#!/usr/bin/tclsh
#
# OpenVerse Rapid Transit server object (ORT).
# 
# This server object will turn your server into an ORT allowing other
# servers to register with you. Your server will "travel" to other servers
# which register with your ORT. You should probably notify the terminus to
# have your ORT registerd there. See the web page for more information
# http://openverse.org/
#
# Module Name		- OpenVerse Rapid Transit server object (ORT)
# Current Maintainter 	- Cruise <cruise@openverse.org>
# Sourced By		- server.tcl
#
# Copyright (C) 1999 David Gale <cruise@openverse.org>
# For more information visit http://OpenVerse.org/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
# USA.

global ORT

#----------------------------------------------------------------
# User Configuration Section.
#----------------------------------------------------------------

set ORT(port) 4200;				# Port to accept registrations on
set ORT(image) "$MVS(homedir)/images/train.gif"; # Your image name
set ORT(time) 30;				# Time between stops
set ORT(name) "ORT Number 1";			# Name Your ORT!
set ORT(myip) "207.0.217.22";			# Your IP Address
#set ORT(myip) "192.168.0.99";			# Your IP Address
set ORT(webpage_dir) "/html/openverse.org/ORT"; # Generates a web page of
						# the active servers in
						# the ort's stop list!
set ORT(virtual_web_dir) "/ORT";		# The above dir in
						# relation to your root
						# web dir. 
set ORT(warp_timeout) 5;			# Seconds to allow remote site to respond to a connection.
#----------------------------------------------------------------
# End User Configuration Section
#----------------------------------------------------------------
#
# You should not need to edit anything past this point. If you do edit
# anything past this point, to fix a bug or to improve on a feature,
# please send diffs to me, i'll probably incorporate the change.
#
# I'm thinking I want to move this information into a seperate log file
# I've made it possible by using this function whenever possible.
# Someday, i'll seperate the information, for now we just pass it on to
# the server's main logging facility.
#
proc OrtLog {what} {
	global ORT

	LogIt "(ORT) - $what"
}

#
# This function reads input from the connecting 
#
#

proc ORT_ReadFrom {sck} {
	global ORT MVS

	set input ""
	catch {gets $sck input}
	if {[eof $sck] == 1} {
		DisconnectRegister $sck 1
                unset input sck
                return
        }
	OrtLog "<- (ORT $sck) $input"
	set parms [split $input " "]
	set rest [string range $input [expr [string first " " $input] +1] end]
	if {[string compare [lindex $parms 0] "TRANS_REG"] && !$ORT($sck.begin)} {
		DisconnectRegister $sck 1
		unset input sck parms rest
		return
	}
	switch -- [lindex $parms 0] {
		"TRANS_REG" {
			set ORT($sck.begin) 1
			set ORT($sck.port) "blah"
			set ORT($sck.rating) "blah"
			set ORT($sck.image) "blah"
			set ORT($sck.size) 0
			set ORT($sck.login) "blah"
			set ORT($sck.password) "blah"
			set ORT($sck.description) "blah"
			set ORT($sck.state) "blah"
			set ORT($sck.country) "blah"
			set ORT($sck.admin) "blah"
			set ORT($sck.email) "blah"
			set ORT($sck.website) "blah"
			set ORT($sck.name) "blah"
			set ORT($sck.age) [clock seconds]
			SendToUser $sck "OK"
		}
		"IMAGE" {
			set ORT($sck.image) [lindex $parms 1]
			set ORT($sck.size) [lindex $parms 2]
			if {![file exists "$MVS(homedir)/images/[lindex $parms 1]"]} {
				SendToUser $sck "DCCSENDAV [lindex $parms 1]"
				SendToUser $sck "OK"
			} elseif {[file size "$MVS(homedir)/images/[lindex $parms 1]"] != [lindex $parms 2]} {
				#
				# Should we accept this blindly? I think
				# perhaps that we should send a reject message.
				#
				SendToUser $sck "OK"
			} else {
				SendToUser $sck "OK"
			}
		}
		"PORT" {
			set ORT($sck.port) [lindex $parms 1]
			SendToUser $sck "OK"
		}
		"RATING" {
			set ORT($sck.rating) $rest
			SendToUser $sck "OK"
		}
		"LOGIN" {
			set ORT($sck.login) [lindex $parms 1]
			SendToUser $sck "OK"
		}
		"PASSWORD" {
			set ORT($sck.password) [lindex $parms 1]
			SendToUser $sck "OK"
		}
		"DESCRIPTION" {
			set ORT($sck.description) $rest
			SendToUser $sck "OK"
		}
		"STATE" {
			set ORT($sck.state) $rest
			SendToUser $sck "OK"
		}
		"COUNTRY" {
			set ORT($sck.country) $rest
			SendToUser $sck "OK"
		}
		"ADMIN" {
			set ORT($sck.admin) $rest
			SendToUser $sck "OK"
		}
		"ADMINEMAIL" {
			set ORT($sck.email) $rest
			SendToUser $sck "OK"
		}
		"WEBSITE" {
			set ORT($sck.website) $rest
			SendToUser $sck "OK"
		}
		"NAME" {
			set ORT($sck.name) $rest
			SendToUser $sck "OK"
		}
		"END" {
			set ORT($sck.end) 1
			RegisterStop $sck
			OrtLog "$ORT($sck.address) is registered"
			DisconnectRegister $sck 2
		}
		"DCCGETAV" {
			# Incoming stop image!
			if ![SanityCheck [lindex $parms 2]] {return}
			ORT_DCCGet $ORT($sck.address) [lindex $parms 1] [lindex $parms 2] [lindex $parms 3]
		}
		default {
			if {$ORT($sck.end)} {
				DisconnectRegister $sck 0
			} else {
				DisconnectRegister $sck 3
			}
		}
	}
	unset input sck parms rest
}

proc ORT_DCCGet {host port file size} {
	global ORT MVS

	if ![SanityCheck "$file"] {
		OrtLog "(!) $file fails SanityCheck"
		return
	}

	set dldir "$MVS(homedir)/images"
	set sock [socket -async $host $port]
	fconfigure $sock -blocking 1

	set idx [incr MVS(dcc_num)]	
	set MVS(DCC.$idx.sender) "ORT_Stop"
	set MVS(DCC.$idx.file) "$dldir/$file"
	set MVS(DCC.$idx.size) $size
	set MVS(DCC.$idx.type) "ORT"
	set MVS(DCC.$idx.posn) 0
	set MVS(DCC.$idx.server) -1
	set MVS(DCC.$idx.sock) $sock
	set MVS(DCC.$idx.time) [clock seconds]
	lappend MVS(dcc_list) $idx
	fileevent $sock writable "ORT_startGet $idx"
}

proc ORT_startGet {index} {
	global ORT MVS

    set file $MVS(DCC.$index.file)
    set posn $MVS(DCC.$index.posn)
    fileevent $MVS(DCC.$index.sock) writable {}
    fconfigure $MVS(DCC.$index.sock) -buffering none -blocking 0 -translation binary -buffersize 4096
    set flags [list WRONLY CREAT]
    if {$posn == 0} { lappend flags TRUNC }
    if {![catch {open $file $flags 0600} outfile]} {
	if {$posn != 0} {
	    if {[catch {seek $outfile $posn start} msg]} {
	    	close $outfile
	    	endDCC Get $index 0 "Cannot seek on $file : $msg"
		return 0
	    }
		incr MVS(DCC.$index.size) -$posn
	}
	uplevel #0 set tl($MVS(DCC.$index.sock)) 0
	fconfigure $outfile -translation binary 
	fileevent $MVS(DCC.$index.sock) readable "Serv_dccgevent $index [clock seconds] $outfile"
    } {
	Serv_endDCC Get $index 0 "Cannot write $file : $outfile"
        return
    }
    return
}

# Accept Registration Connections.
#
proc RegistryConnect {sck address port} {
	global ORT
	
	if {[lsearch $ORT(connections) $sck] == -1} {
		lappend ORT(connections) $sck
	} else {
		close $sck
		unset sck address port
		return
	}
	set ORT($sck.address) $address
	set ORT($sck.port) $port
	set ORT($sck.begin) 0
	set ORT($sck.end) 0
	set ORT($sck.age) [clock seconds]
	fconfigure $sck -blocking 0 -buffering line
	fileevent $sck readable "ORT_ReadFrom $sck"
	unset sck address port
}

proc DisconnectRegister {sck kill} {
	global ORT

	switch -- $kill {
		1 {
			set idx [lsearch $ORT(connections) $sck]
			set ORT(connections) [lreplace $ORT(connections) $idx $idx]
			unset idx
			unset ORT($sck.address)
			unset ORT($sck.port)
			unset ORT($sck.begin)
			unset ORT($sck.end)
		}
		2 {
			set idx [lsearch $ORT(connections) $sck]
			set ORT(connections) [lreplace $ORT(connections) $idx $idx]
			unset idx
			unset ORT($sck.address)
			unset ORT($sck.port)
			unset ORT($sck.rating)
			unset ORT($sck.image)
			unset ORT($sck.size)
			unset ORT($sck.login)
			unset ORT($sck.password)
			unset ORT($sck.description)
			unset ORT($sck.state)
			unset ORT($sck.country)
			unset ORT($sck.admin)
			unset ORT($sck.email)
			unset ORT($sck.website)
			unset ORT($sck.name)
			unset ORT($sck.begin)
			unset ORT($sck.end)
			unset ORT($sck.age)
		}
		3 {
			set idx [lsearch $ORT(connections) $sck]
			set ORT(connections) [lreplace $ORT(connections) $idx $idx]
			unset idx
			unset ORT($sck.address)
			unset ORT($sck.port)
			unset ORT($sck.rating)
			unset ORT($sck.image)
			unset ORT($sck.size)
			unset ORT($sck.login)
			unset ORT($sck.password)
			unset ORT($sck.description)
			unset ORT($sck.state)
			unset ORT($sck.country)
			unset ORT($sck.admin)
			unset ORT($sck.email)
			unset ORT($sck.website)
			unset ORT($sck.name)
			unset ORT($sck.begin)
			unset ORT($sck.end)
			unset ORT($sck.age)
		}
	}
	SendToUser $sck "GOODBYE"
	catch {close $sck}
}

proc RegisterStop {sck} {
	global ORT MVS

	# Do we have this stop?
	set stopper 1
	set pagegen 0
	foreach stop $ORT(stops) {
		if {![string compare $ORT(stop.$stop.address) $ORT($sck.address)] && $ORT(stop.$stop.port) == $ORT($sck.port)} {
			OrtLog "Registration is an UPDATE"
			set stop $stop
			set stopper 0
			break
		}
	}
	if {$stopper} {
		OrtLog "Registration is NEW"
		incr ORT(NewStop)
		set stop $ORT(NewStop)
		lappend ORT(stops) $ORT(NewStop)
		OrtLog "NEW Site is #$stop"
		set pagegen 1
	}
	set ORT(stop.$stop.address)		$ORT($sck.address)
	set ORT(stop.$stop.port)		$ORT($sck.port)
	set ORT(stop.$stop.rating)		$ORT($sck.rating)
	set ORT(stop.$stop.image)		$ORT($sck.image)
	set ORT(stop.$stop.size)		$ORT($sck.size)
	set ORT(stop.$stop.description)		$ORT($sck.description)
	set ORT(stop.$stop.state)		$ORT($sck.state)
	set ORT(stop.$stop.country)		$ORT($sck.country)
	set ORT(stop.$stop.admin)		$ORT($sck.admin)
	set ORT(stop.$stop.email)		$ORT($sck.email)
	set ORT(stop.$stop.website)		$ORT($sck.website)
	set ORT(stop.$stop.name)		$ORT($sck.name)
	set ORT(stop.$stop.age)			[clock seconds]
	set ORT(stop.$stop.login)		$ORT($sck.login)
	set ORT(stop.$stop.password)		$ORT($sck.password)
	if {$pagegen || $ORT(pagegen)} {
		#
		# Generate a new web page.
		#
		if {![file exists "$ORT(webpage_dir)/images"]} {
			file mkdir "$ORT(webpage_dir)/images"
		}
		if {![file exists "$ORT(webpage_dir)/links"]} {
			file mkdir "$ORT(webpage_dir)/links"
		}
		file copy -force "$MVS(homedir)/images/$ORT(stop.$stop.image)" "$ORT(webpage_dir)/images"
		set outfile [open "$ORT(webpage_dir)/index.php3" w]
		puts $outfile "\
		<? include(\"../header.php3\") ?>
		ORT Registered Servers
		<? include(\"../header2.php3\") ?>
		What you will find here is a listing of all of the servers
		which have registered with the ORT (OpenVerse Rapid
		Transit). This list is generated automatically by the
		main ORT train run on <a
		href=\"http://OpenVerse.Org\">OpenVerse.Org</a> each time
		a new server registers.
		<P>
		All you have to do to be on this list is edit your
		server's config file to register your server with the
		ORT. See the server.cfg for instructions on doing this. If
		you need help, email <a href=\"mailto:cruise@openverse.org\">cruise@openverse.org</a>
		<P>
		This Server's registration information is....
		<UL>
		<LI> <b>Name</b> $ORT(name)
		<LI> <b>IP Address</b> $ORT(myip)
		<LI> <b>Registration Port</b> $ORT(port)
		</UL>
		<hr>
		<UL>
		"
		foreach stop $ORT(stops) {
			set of [open "$ORT(webpage_dir)/links/$ORT(stop.$stop.address)_$ORT(stop.$stop.port).ovl" w]
			puts $of "$ORT(stop.$stop.address):$ORT(stop.$stop.port)"
			close $of
			puts $outfile "
			<LI> <a href=\"$ORT(virtual_web_dir)/links/$ORT(stop.$stop.address)_$ORT(stop.$stop.port).ovl\"><img src=\"$ORT(virtual_web_dir)/images/$ORT(stop.$stop.image)\"></a>
			<UL>
			<LI> <b>$ORT(stop.$stop.name)</b>
			<LI> <b>Admin</b> $ORT(stop.$stop.admin) <a href=\"mailto:$ORT(stop.$stop.email)\">$ORT(stop.$stop.email)</a>
			<LI> <b>Website</b> <a href=\"$ORT(stop.$stop.website)\">$ORT(stop.$stop.website)</a>
			<LI> <b>Hostname</b> $ORT(stop.$stop.address)
			<LI> <b>Port</b> $ORT(stop.$stop.port)
			<LI> <b>Location</b> $ORT(stop.$stop.state) - $ORT(stop.$stop.country)
			<LI> <b>Content Rating</b> $ORT(stop.$stop.rating)
			<LI> <b>Description</b> $ORT(stop.$stop.description)
			</UL>
			"
		}
		puts $outfile "
		</UL>
		<hr>
		<i>Page generated automagically at [clock format [clock seconds]]</i>
		<? include(\"../footer.php3\") ?>
		"
		close $outfile
		set ORT(pagegen) 0
	}
	unset stop pagegen
}

#
# Updates our stops and closes old sockets.
#
proc UpdateStops {} {
	global ORT 

	set tme [clock seconds]

	#
	# Check the age of each of the stops on our schedule.
	#
	foreach stop $ORT(stops) {
		if {[expr $tme - $ORT(stop.$stop.age)] > 350} {
			if {$ORT(current_stop) != $stop} {
				OrtLog "Stop #$stop timed out"
				set idx [lsearch $ORT(stops) $stop]
				set ORT(stops) [lreplace $ORT(stops) $idx $idx]
				unset idx
				set ORT(pagegen) 1
			}
		}
	}

	#
	# Check our open sockets TO servers.
	#
	foreach sock $ORT(socks) {
		if {[expr $tme - $ORT(sock.$sock.age)] > 60} {
			OrtLog "-> (ORT $sock) Socket has timed out"
			catch {close $sock}
			set idx [lsearch $ORT(socks) $sock]
			set ORT(socks) [lreplace $ORT(socks) $idx $idx]
			unset idx
		}
	}

	#
	# Check our connections FROM servers
	#
	foreach sock $ORT(connections) {
		if {[expr $tme - $ORT($sock.age)] > 60} {
			OrtLog "<- (ORT $sock) Connection has timed out"
			catch {close $sock}
			set idx [lsearch $ORT(connections) $sock]
			set ORT(connections) [lreplace $ORT(connections) $idx $idx]
			unset idx
		}
	}

	unset tme
	after 10000 UpdateStops
}

proc OBJ_DCCSendAv {host port what} {
        global ORT MVS

        set file "$MVS(homedir)/images/$what"

        if {[file exists $file]} {
                if {![file readable $file]} {
                        OrtLog "(ORT) (DCCSend) Cannot read file $file."
                        return
                }
                set size [file size $file]
                set idx [incr MVS(dcc_num)]
                set sock [socket -async $host $port]
                fconfigure $sock -blocking 1

                set MVS(DCC.$idx.sender) "*"
                set MVS(DCC.$idx.file) "$file"
                set MVS(DCC.$idx.size) $size
                set MVS(DCC.$idx.posn) 0
                set MVS(DCC.$idx.time) [clock seconds]
                set MVS(DCC.$idx.server) -1
                set MVS(DCC.$idx.sock) $sock
                set MVS(DCC.$idx.port) $port
                set MVS(DCC.$idx.time) [clock seconds]
                fileevent $sock writable "ORT_acceptSend $idx"
        } else {
                OrtLog "(ORT) (DCCSendAv) File $file does not exist."
        }
}

proc ORT_acceptSend {index} {
	global MVS

	fileevent $MVS(DCC.$index.sock) writable {}
	set chan $MVS(DCC.$index.sock)
        
        if {[ catch {open $MVS(DCC.$index.file) RDONLY} infile]} {
                endDCC Send $index 0 "Cannot read $MVS(DCC.$index.file) :$infile"
                return 0
        }

        if {[set posn $MVS(DCC.$index.posn)] != {} && $posn > 0} {
                if {[catch {seek $infile $posn start} msg]} {
                        endDCC Send $index 0 "Cannot seek $MVS(DCC.$index.file) :$msg"
                        close $infile
                        return 0
                }
                incr MVS(DCC.$index.size) -$posn
        } 

        if {$MVS(DCC.$index.size) == 0} {
                close $infile
                endDCC Send $index 1 "Transfer completed."
                return 1
        }

	set st [clock seconds]
        fconfigure $infile -translation binary

        if {[catch {set buffer [read $infile $MVS(sendbuffer)]} msg]} {
                endDCC Send $index 0 "Error reading $file : $msg"
                close $infile
                return 0
        }

        global tl
        set tl($chan) [string length $buffer]
        fconfigure $chan -blocking 0 -buffering none -translation binary
        if {[catch {puts -nonewline $chan $buffer} msg]} {
                endDCC Send $index 0 "Write error : $msg"
                close $infile
                return 0
        }
        flush $chan
        OrtLog "($MVS(DCC.$index.sender)) -- Accepted DCCSend"
        fileevent $chan readable "Serv_dccSendEvent $index $st $infile"

}

#
# ConnectToStop
#
# This function will connect us to the remote server and send our
# authentication information and image information for this ORT.
# It's a fairly cut and dry process. This function is called by the main
# timer loop.
# 
proc ConnectToStop {} {
	global ORT errorInfo MVS

	if {$ORT(current_stop) < 0} {return 0}
	OrtLog "Connecting to Stop No. $ORT(current_stop) ($ORT(stop.$ORT(current_stop).address):$ORT(stop.$ORT(current_stop).port))"
	if {[catch {
		set ORT(sock) [socket -myaddr $ORT(myip) $ORT(stop.$ORT(current_stop).address) $ORT(stop.$ORT(current_stop).port)]
		fconfigure $ORT(sock) -blocking 0 -buffering line
		lappend ORT(socks) $ORT(sock)
		set ORT(sock.$ORT(sock).age) [clock seconds]
		fileevent $ORT(sock) readable "ReadFromStop $ORT(sock)"
		SendToUser $ORT(sock) "TRANS $ORT(stop.$ORT(current_stop).login) $ORT(stop.$ORT(current_stop).password) [file tail $ORT(image)] [file size "$ORT(image)"] $ORT(time) $MVS(port) |$ORT(name)"
	}]} {
		OrtLog "Unable To Connect!"
		OrtLog "$errorInfo"
		catch {close $ORT(sock)}
		return 0	
	}
	OrtLog "Connected!"
	return 1
}

proc ReadFromStop {sck} {
	global ORT

	set input ""
	catch {gets $sck input}
	if {[eof $sck] == 1} {
		catch {close $sck}
		set idx [lsearch $ORT(socks) $sck]
		set ORT(socks) [lreplace $ORT(socks) $idx $idx]
                unset input sck
                return
        }
	OrtLog "(ORT $sck)<- $input"
	set parms [split $input " "]
	set rest [string range $input [expr [string first " " $input] +1] end]
	switch -- [lindex $parms 0] {
		"DCCSENDAV" {
			OBJ_DCCSendAv $ORT(stop.$ORT(current_stop).address) [lindex $parms 1] [lindex $parms 2]
		}
		"AUTH_REQD" {
			# Crap, skip this one.
			set idx [lsearch $ORT(socks) $sck]
			set ORT(socks) [lreplace $ORT(socks) $idx $idx]
			catch {close $sck}
		}
		"USERS" {
			set ORT(stop.$ORT(current_stop).users) [lindex $parms 1]
		}
		"REGISTERED" {
			catch {close $sck}
			set idx [lsearch $ORT(socks) $sck]
			set ORT(socks) [lreplace $ORT(socks) $idx $idx]
			set ORT(state) "STOP"
			set ORT(moving_in_time) 0
		}
	}
}

proc UpdateStopTimer {} {
	global ORT MVS

	switch $ORT(state) {
		"STOP"	{
			if {!$ORT(moving_in_time)} {
				SendToAllUsers "TEXT tram_info_next_time 250 36 green 4 0 |STOPPED"
				if {$ORT(current_stop) != -1} {
					SendToAllUsers "TEXT tram_info_users 114 95 yellow 3 0 |Users $ORT(stop.$ORT(current_stop).users)"
				}
				incr ORT(moving_in_time)
			} else {
				incr ORT(moving_in_time)
				SendToAllUsers "TEXT tram_info_next_time 250 36 green 4 0 |[clock format [expr $ORT(time) - $ORT(moving_in_time)] -format "00:%M:%S"]"
				if {$ORT(moving_in_time) >= $ORT(time)} {
					set ORT(state) "MOVING"
					set ORT(moving_in_time) 0
				}
			}
		}
		"WARP" {
			#
			# Allow the stop some time to respond. 1 second is not enough. (warp_timeout)
			# CRUISE - 10/23/2001
			#
			incr ORT(warp_time)
			OrtLog "STILL WAITING FOR RESPONSE - Waited $ORT(warp_time) for response from this stop."
			if {$ORT(warp_time) > $ORT(warp_timeout)} {
				#
				# WARP Timed out, move on to the next stop.
				#
				OrtLog "STOP TIMEOUT - Waited $ORT(warp_time) SECONDS"
				set ORT(state) "MOVING"
			}
		}
		"MOVING" {
			SendToAllUsers "TEXT tram_info_next_time 250 36 green 4 0 |WARP"
			#
			# If we have no stops... well, just display the main link.
			# Otherwise, process this stop.
			if {$ORT(current_stop) == -1} {
				if {[llength $ORT(stops)] > 0}  {
					set ORT(current_stop) [lindex $ORT(stops) 0]
				} else {
					set ORT(state) "STOP"
					SendToAllUsers "TEXT tram_info_next_time 250 36 green 4 0 |STOPPED"
					incr ORT(moving_in_time)
				}
			} else {
				set idx [lsearch $ORT(stops) $ORT(current_stop)]
				incr idx
				if {$idx > [llength $ORT(stops)]} {
					set idx 0
				}
				set ORT(current_stop) [lindex $ORT(stops) $idx]
				set ORT(stop.$ORT(current_stop).users) 0
				if {[ConnectToStop]} {
					#
					# Being in WARP mode allows the server a few seconds to respond.
					#
					set ORT(state) "WARP"
					set ORT(warp_time) 0
					foreach who $MVS(socks) {
						ShowStop $who 0
					}
				}
			}
		}
	}
	after 1000 UpdateStopTimer

}

#
# If this is our first time through, then initialize the object.
#
if {![info exists ORT(running_flag)]} {
	set ORT(NewStop) 0
	set ORT(running_flag) 1
	set ORT(pagegen) 0
	set ORT(state) "STOP"
	set ORT(moving_in_time) 0
	set ORT(stopping_in_time) 0
	set ORT(stops) {}
	set ORT(socks) {}
	set ORT(current_stop) -1
	set ORT(connections) {}
	set ORT(server_sock) [socket -server RegistryConnect $ORT(port)]
	lappend MVS(tell_registry) "tram_more_info tram_more_info"
	lappend MVS(tell_registry) "tram_more_info_tell_close tram_more_info_tell_close"
	after 60000 UpdateStops
	after 1000 UpdateStopTimer
}

#
# Shows the user more information about the current stop.
#
proc tram_more_info {who} {
	global ORT MVS
	if {[llength $ORT(stops)] <= 0 || $ORT(current_stop) == -1 || $ORT(current_stop) == ""} {return}
	set timeleft [expr ($ORT(time) - $ORT(moving_in_time)) * 1000]
	switch $ORT(stop.$ORT(current_stop).rating) {
		"G" {set color "green"}
		"PG" {set color "yellow"}
		"R" {set color "red"}
		"X" {set color "red"}
		"XXX" {set color "red"}
		default {set color "red"}
	}
	SendToUser $who "BOX tram_more_info_box 74 172 300 333 black red $timeleft"
	SendToUser $who "TELL tram_more_info_nomove_zone 74 172 300 333 $timeleft"
	SendToUser $who "MOUSEOVER tram_more_info_close 292 181 ORT_Close_More_on.gif [file size "$MVS(images)/ORT_Close_More_on.gif"] ORT_Close_More_off.gif [file size "$MVS(images)/ORT_Close_More_off.gif"] $timeleft"
	SendToUser $who "TELL tram_more_info_tell_close 283 174 301 188 $timeleft"
	SendToUser $who "TEXT tram_more_info_rating 94 193 $color 2 $timeleft |($ORT(stop.$ORT(current_stop).rating))"
	SendToUser $who "TEXT tram_more_info_admin 130 193 yellow 3 $timeleft |Admin"
	SendToUser $who "TEXT tram_more_info_admin_value 223 193 green 3 $timeleft |$ORT(stop.$ORT(current_stop).admin)"
	SendToUser $who "LINK tram_more_info_admin_link 74 189 300 198 $timeleft mailto:$ORT(stop.$ORT(current_stop).email)"
	SendToUser $who "TEXT tram_more_info_website 181 214 yellow 3 $timeleft | (Click here to go to the website)"
	SendToUser $who "LINK tram_more_info_website_link 74 200 300 223 $timeleft $ORT(stop.$ORT(current_stop).website)"
	SendToUser $who "TEXT tram_more_info_location 181 235 yellow 3 $timeleft |$ORT(stop.$ORT(current_stop).state) - $ORT(stop.$ORT(current_stop).country)"
	SendToUser $who "WTEXT tram_more_info_description 185 282 white 2 $timeleft 225 |$ORT(stop.$ORT(current_stop).description)"
}

#
# Closes the more info window.
#
proc tram_more_info_tell_close {who} {
	global ORT MVS
	set timeleft 1
	set color "black"
	SendToUser $who "BOX tram_more_info_box 74 172 300 333 black red $timeleft"
	SendToUser $who "TELL tram_more_info_nomove_zone 74 172 300 333 $timeleft"
	SendToUser $who "MOUSEOVER tram_more_info_close 292 181 ORT_Close_More_on.gif [file size "$MVS(images)/ORT_Close_More_on.gif"] ORT_Close_More_off.gif [file size "$MVS(images)/ORT_Close_More_off.gif"] $timeleft"
	SendToUser $who "TELL tram_more_info_tell_close 283 174 301 188 $timeleft"
	SendToUser $who "TEXT tram_more_info_rating 94 193 $color 2 $timeleft | "
	SendToUser $who "TEXT tram_more_info_admin 130 193 yellow 3 $timeleft | "
	SendToUser $who "TEXT tram_more_info_admin_value 223 193 green 3 $timeleft | "
	SendToUser $who "LINK tram_more_info_admin_link 74 189 300 198 $timeleft mailto:cruise@openverse.org"
	SendToUser $who "TEXT tram_more_info_website 181 214 yellow 3 $timeleft | "
	SendToUser $who "LINK tram_more_info_website_link 74 200 300 223 $timeleft http://openverse.org/"
	SendToUser $who "TEXT tram_more_info_location 181 235 yellow 3 $timeleft | "
	SendToUser $who "WTEXT tram_more_info_description 185 282 white 2 $timeleft 225 | "
}

#
# ShowStop who initalize_flag
#
# This function will show the current_stop information to the user. If the
# user is just logging in, the initalize_flag should be set to one so that
# backgound setup information can be displayed to the user.
#
proc ShowStop {who init} {
	global ORT MVS

	if {$init} {
		SendToUser $who "BOX tram_info 74 11 300 171 black red 0"
		SendToUser $who "TELL tram_nomove_zone 74 11 300 104 0"
		SendToUser $who "TEXT tram_info_next 136 36 yellow 4 0 |New Stop In"
		SendToUser $who "MOUSEOVER tram_info_more 260 95 ov_more_info.gif [file size "$MVS(homedir)/images/ov_more_info.gif"] ov_more_info_on.gif [file size "$MVS(homedir)/images/ov_more_info_on.gif"] 0"
		SendToUser $who "TELL tram_more_info 233 86 287 103 0"
		if {[llength $ORT(stops)] > 0 && $ORT(current_stop) >= 0} {
			SendToUser $who "TEXT tram_info_users 114 95 yellow 3 0 |Users $ORT(stop.$ORT(current_stop).users)"
		}
	}
	if {[llength $ORT(stops)] > 0 && $ORT(current_stop) >= 0} {
		SendToUser $who "TEXT tram_info_stop_name 186 67 red 3 0 |$ORT(stop.$ORT(current_stop).name)"
		SendToUser $who "EXIT_OBJ tram_server_exit 74 101 300 171 0 $ORT(stop.$ORT(current_stop).address) $ORT(stop.$ORT(current_stop).port)"
		SendToUser $who "IMAGE tram_info_image 186 136 $ORT(stop.$ORT(current_stop).image) [file size "$MVS(homedir)/images/$ORT(stop.$ORT(current_stop).image)"] 0"
	} else {
		SendToUser $who "IMAGE tram_info_image 186 136 ov_tram_logo.gif [file size "$MVS(homedir)/images/ov_tram_logo.gif"] 0"
	}
}

#
# Set up the user's screen now.
#

ShowStop $who 1

