#!/usr/bin/wishx
#######################################################################
#
# hlgui
#
# Half-Life dedicated server administration/monitoring GUI client
# Copyright (C) 2000 Rob Abbott
#
#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Comments, bug reports, etc to linuxhlds@halflife.org
#
# Maintained by
# Rob Abbott    <linuxhlds@halflife.org>           rabbott 
# Frank Odignal <odignal@stud.fbi.fh-darmstadt.de> ogdinal
# Uli Staerk <uli@spielviel.de> staerk
#
#   rabbott 2000-07-28 - More changes from Uli - map name and time rem fix
#
#   rabbott 2000-07-26 - Merge in Uli's changes (buttons now appear on Linux)
#
#   staerk  2001-07-04 - Fixed some problems with special German characters
#		       - Added optional admin-mod buttons
#
#   rabbott 2000-11-14 - Fix "sticky" option to stop M$ from complaining :(
#
#   rabbott 2000-10-28 - Added optional 'team' column
#
#   rabbott 2000-10-29 - Release 1.28b2
#
#   rabbott 2000-10-28 - Added optional 'model' column
#
#   rabbott 2000-10-06 - Fix to accomodate Tcl 8.3
#                        (argv now includes executable)
#
#   rabbott 2000-09-18 - Merge in Richard Pennington's resize code :)
#                      - <rich@introl.com>
#
#   rabbott 2000-08-26 - Release 1.21
#                      - Fixed problem that prevented banning
#                      - (Thanks Cory Van Allen)
#
#   rabbott 2000-08-05 - Color-code ADMIN messages
#                      - exec 'banned.cfg' before writeid
#
#   rabbott 2000-07-07 - Menu and Button help menus fixed
#
#   rabbott 2000-06-29 - Release 1.10
#                      - Added macro functionality
#
#   ogdinal 2000/05/10 - log text scrolls only if scrollbar is at bottomost position.
#                        This enables back scrolling/reading w/o intervention of
#                        new log text appearing in the window, scrolling down.
#   ogdinal 2000/05/10 - added coloring of log lines, configurable in initvars
#   ogdinal 2000/05/10 - log window now uses last line (disabled for now, as it
#                        makes problems with tag coloring)
#
#######################################################################
# About - just an info box 
#
proc aboutGui {} {
	global vers vnum font

	helpBox ueber \
"
Dies ist ein GUI-basiertes Half-Life Serveradministrationstool fuer Linux

Falls ein Problem auftritt oder Sie irgendwelche Kommentare haben,
schreiben Sie bitte an
linuxhlds@halflife.org

Visit Maelstrom's Brewpub (TFC/Linux)
63.68.143.63:27015

Visit www.spielviel.de

$vers, Copyright (C) 2000 Rob Abbott <linuxhlds@halflife.org>
Uebersetzung von Uli Staerk <uli@spielviel.de>

$vers wird mit ABSOLUT KEINER GARANTIE geliefert; Hilfe->Garantie fuer Details.

Dies ist kostenlose Software. Sie duerfen Sie unter bestimmten
Bedingungen weiterverbreiten; Hilfe->Bedingungen fuer Details.

\"Relax, don't worry, have a homebrew\"
   -- Charlie Papazian
"
}

proc warranty {} {

	helpBox garantie \
"
	KEINE GEWAEHRLEISTUNG

Paragraph 11. Da das Programm ohne jegliche Kosten lizenziert wird, besteht keinerlei Gewaehrleistung
fuer das Programm, soweit dies gesetzlich zulaessig ist. Sofern nicht anderweitig schriftlich bestaetigt,
stellen die Copyright-Inhaber und/oder Dritte das Programm so zur Verfuegung, \"wie es ist\", ohne
irgendeine Gewaehrleistung, weder ausdruecklich noch implizit, einschliesslich - aber nicht begrenzt auf -
Marktreife oder Verwendbarkeit fuer einen bestimmten Zweck. Das volle Risiko bezueglich Qualitaet und
Leistungsfaehigkeit des Programms liegt bei Ihnen. Sollte sich das Programm als fehlerhaft
herausstellen, liegen die Kosten fuer notwendigen Service, Reparatur oder Korrektur bei Ihnen.
Paragraph 12. In keinem Fall, ausser wenn durch geltendes Recht gefordert oder schriftlich zugesichert,
ist irgendein Copyright-Inhaber oder irgendein Dritter, der das Programm wie oben erlaubt modifiziert
oder verbreitet hat, Ihnen gegenueber fuer irgendwelche Schaeden haftbar, einschliesslich jeglicher
allgemeiner oder spezieller Schaeden, Schaeden durch Seiteneffekte (Nebenwirkungen) oder
Folgeschaeden, die aus der Benutzung des Programms oder der Unbenutzbarkeit des Programms
folgen (einschliesslich - aber nicht beschraenkt auf - Datenverluste, fehlerhafte Verarbeitung von
Daten, Verluste, die von Ihnen oder anderen getragen werden muessen, oder dem Unvermoegen
des Programms, mit irgendeinem anderen Programm zusammenzuarbeiten), selbst wenn ein
Copyright-Inhaber oder Dritter ueber die Moeglichkeit solcher Schaeden unterrichtet worden war.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
"
}

proc helpBox { wn text } {
	global vers font

	toplevel .$wn
	frame .$wn.log
	text .$wn.log.text -height 20 -state normal -fg yellow -bg black \
		-yscroll ".$wn.log.sy set" -font $font(norm)
	scrollbar .$wn.log.sy -command ".$wn.log.text yview"
	.$wn.log.text insert end $text

	.$wn.log.text configure -state disabled
	grid .$wn.log.text -in .$wn.log -row 0 -column 1 -sticky nsew
	grid .$wn.log.sy -in .$wn.log -row 0 -column 0 -sticky ns 
	grid rowconfigure .$wn.log 0 -weight 1
	grid columnconfigure .$wn.log 1 -weight 1
	frame .$wn.b
   	button .$wn.b.b1 -text "Fertig" -command "destroy .$wn" -font $font(norm)
	grid .$wn.b.b1 -in .$wn.b -row 0 -column 0
	grid .$wn.b -in .$wn -row 1 -column 0
	grid .$wn.log -in .$wn -row 0 -column 0 -sticky nsew
	grid rowconfigure .$wn 0 -weight 1
	grid columnconfigure .$wn 0 -weight 1

	centerWindow .$wn .
}

proc cdm {} {
	global vers

	helpBox bedingungen \
"
Diese Uebersetzung ist kein rechtskraeftiger Ersatz fuer die englischsprachige Originalversion!

		GNU GENERAL PUBLIC LICENSE
Bedingungen fuer die Vervielfaeltigung, Verbreitung und Bearbeitung

Paragraph 0. Diese Lizenz gilt fuer jedes Programm und jedes andere Werk,
in dem ein entsprechender Vermerk des Copyright-Inhabers darauf hinweist,
dass das Werk unter den Bestimmungen dieser General Public License verbreitet
werden darf. Im folgenden wird jedes derartige Programm oder Werk als
\"das Programm\" bezeichnet; die Formulierung \"auf dem Programm
basierendes Werk\" bezeichnet das Programm sowie jegliche Bearbeitung
des Programms im urheberrechtlichen Sinne, also ein Werk, welches das
Programm, auch auszugsweise, sei es unveraendert oder veraendert und/oder
in eine andere Sprache uebersetzt, enthaelt. (Im folgenden wird die Uebersetzung
ohne Einschraenkung als \"Bearbeitung\" eingestuft.) Jeder Lizenznehmer
wird im folgenden als \"Sie\" angesprochen.
Andere Handlungen als Vervielfaeltigung, Verbreitung und Bearbeitung werden
von dieser Lizenz nicht beruehrt; sie fallen nicht in ihren Anwendungsbereich.
Der Vorgang der Ausfuehrung des Programms wird nicht eingeschraenkt, und
die Ausgaben des Programms unterliegen dieser Lizenz nur, wenn der Inhalt
ein auf dem Programm basierendes Werk darstellt (unabhaengig davon, dass die
Ausgabe durch die Ausfuehrung des Programmes erfolgte). Ob dies zutrifft,
haengt von den Funktionen des Programms ab.
Paragraph 1. Sie duerfen auf beliebigen Medien unveraenderte Kopien des
Quelltextes des Programms, wie sie ihn erhalten haben, anfertigen und verbreiten.
Voraussetzung hierfuer ist, dass Sie mit jeder Kopie einen entsprechenden
Copyright-Vermerk sowie einen Haftungsausschluss veroeffentlichen, alle
Vermerke, die sich auf diese Lizenz und das Fehlen einer Garantie beziehen,
unveraendert lassen und desweiteren allen anderen Empfaengern des
Programms zusammen mit dem Programm eine Kopie dieser Lizenz zukommen lassen.
Sie duerfen fuer den eigentlichen Kopiervorgang eine Gebuehr verlangen.
Wenn Sie es wuenschen, duerfen Sie auch gegen Entgelt eine Garantie fuer das
Programm anbieten.
Paragraph 2. Sie duerfen Ihre Kopie(n) des Programms oder eines Teils davon
veraendern, wodurch ein auf dem Programm basierendes Werk entsteht; Sie
duerfen derartige Bearbeitungen unter den Bestimmungen von Paragraph 1
vervielfaeltigen und verbreiten, vorausgesetzt, dass zusaetzlich alle folgenden
Bedingungen erfuellt werden:
(a) 
Sie muessen die veraenderten Dateien mit einem auffaelligen Vermerk
versehen, der auf die von Ihnen vorgenommene Modifizierung und
das Datum jeder Aenderung hinweist.
(b) 
Sie muessen dafuer sorgen, dass jede von Ihnen verbreitete oder
veroeffentlichte Arbeit, die ganz oder teilweise von dem Programm
oder Teilen davon abgeleitet ist, Dritten gegenueber als Ganzes unter
den Bedingungen dieser Lizenz ohne Lizenzgebuehren zur Verfuegung
gestellt wird.
(c) 
Wenn das veraenderte Programm normalerweise bei der Ausfuehrung
interaktiv Kommandos einliest, muessen Sie dafuer sorgen, dass es, wenn
es auf dem ueblichsten Wege fuer solche interaktive Nutzung gestartet
wird, eine Meldung ausgibt oder ausdruckt, die einen geeigneten
Copyright-Vermerk enthaelt sowie einen Hinweis, dass es keine
Gewaehrleistung gibt (oder anderenfalls, dass Sie Garantie leisten), und
dass die Benutzer das Programm unter diesen Bedingungen weiter
verbreiten duerfen. Auch muss der Benutzer darauf hingewiesen werden,
wie er eine Kopie dieser Lizenz ansehen kann. (Ausnahme: Wenn das
Programm selbst interaktiv arbeitet, aber normalerweise keine derartige
Meldung ausgibt, muss Ihr auf dem Programm basierendes Werk auch
keine solche Meldung ausgeben).
        Diese Anforderungen betreffen das veraenderte Werk als Ganzes. Wenn
        identifizierbare Abschnitte des Werkes nicht von dem Programm abgeleitet
       sind und vernuenftigerweise selbst als unabhaengige und eigenstaendige
       Werke betrachtet werden koennen, dann erstrecken sich diese Lizenz und
       ihre Bedingungen nicht auf diese Abschnitte, wenn sie als eigenstaendige
       Werke verbreitet werden. Wenn Sie jedoch dieselben Abschnitte als Teil
       eines Ganzen verbreiten, das ein auf dem Programm basierendes Werk
       darstellt, dann muss die Verbreitung des Ganzen nach den Bedingungen
       dieser Lizenz erfolgen, deren Bedingungen fuer weitere Lizenznehmer somit
       auf die Gesamtheit ausgedehnt werden - und damit auf jeden einzelnen Teil,
       unabhaengig vom jeweiligen Autor.
       Somit ist es nicht die Absicht dieses Abschnittes, Rechte fuer Werke in
      Anspruch zu nehmen oder zu beschneiden, die komplett von Ihnen
      geschrieben wurden; vielmehr ist es die Absicht, die Rechte zur Kontrolle der
      Verbreitung von Werken, die auf dem Programm basieren oder unter seiner
      auszugsweisen Verwendung zusammengestellt worden sind, auszuueben.
      Ferner bringt ein einfaches Zusammenstellen eines anderen Werkes, das
      nicht auf dem Programm basiert, zusammen mit dem Programm oder einem
      auf dem Programm basierenden Werk auf ein- und demselben Speicher- oder
      Vertriebsmedium das andere Werk nicht in den Anwendungsbereich dieser Lizenz.
      Paragraph 3. Sie duerfen das Programm (oder ein darauf basierendes Werk
      gemaess Paragraph 2) als Objectcode oder in ausfuehrbarer Form unter den
      Bedingungen von Paragraph 1 und 2 vervielfaeltigen und verbreiten - 
      vorausgesetzt, dass Sie ausserdem eine der folgenden Leistungen erbringen:
	(a) 
		Liefern Sie das Programm zusammen mit dem vollstaendigen
		zugehoerigen maschinenlesbaren Quelltext auf einem fuer den
		Datenaustausch ueblichen Medium aus, wobei die Verteilung
		unter den Bedingungen der Paragraphen 1 und 2 erfolgen muss.
		Oder:
	(b) 
		Liefern Sie das Programm zusammen mit einem mindestens
		drei Jahre lang gueltigen schriftlichen Angebot aus, jedem
		Dritten eine vollstaendige maschinenlesbare Kopie des
		Quelltextes zur Verfuegung zu stellen - zu nicht hoeheren Kosten
		als denen, die durch den physikalischen Kopiervorgang
		anfallen -, wobei der Quelltext unter den Bedingungen der
		Paragraphen 1 und 2 auf einem fuer den Datenaustausch
		ueblichen Medium weitergegeben wird. Oder:
	(c) 
		Liefern Sie das Programm zusammen mit dem schriftlichen
		Angebot der Zurverfuegungstellung des Quelltextes aus, das
		Sie selbst erhalten haben. (Diese Alternative ist nur fuer
		nicht-kommerzielle Verbreitung zulaessig und nur, wenn Sie
		das Programm als Objectcode oder in ausfuehrbarer Form mit
		einem entsprechenden Angebot gemaess Absatz b erhalten haben.)

Unter dem Quelltext eines Werkes wird diejenige Form des Werkes verstanden,
die fuer Bearbeitungen vorzugsweise verwendet wird. Fuer ein ausfuehrbares
Programm bedeutet \"der komplette Quelltext\": Der Quelltext aller im Programm
enthaltenen Module einschliesslich aller zugehoerigen Modulschnittstellen-
Definitionsdateien sowie der zur Compilation und Installation verwendeten Skripte.
Als besondere Ausnahme jedoch braucht der verteilte Quelltext nichts von dem zu
enthalten, was ueblicherweise (entweder als Quelltext oder in binaerer Form) zusammen
mit den Hauptkomponenten des Betriebssystems (Kernel, Compiler usw.) geliefert
wird, unter dem das Programm laeuft - es sei denn, diese Komponente selbst gehoert
zum ausfuehrbaren Programm.
Wenn die Verbreitung eines ausfuehrbaren Programms oder des Objectcodes dadurch
erfolgt, dass der Kopierzugriff auf eine dafuer vorgesehene Stelle gewaehrt wird, so gilt
die Gewaehrung eines gleichwertigen Zugriffs auf den Quelltext als Verbreitung des
Quelltextes, auch wenn Dritte nicht dazu gezwungen sind, den Quelltext zusammen
mit dem Objectcode zu kopieren.
Paragraph 4. Sie duerfen das Programm nicht vervielfaeltigen, veraendern, weiter lizenzieren
oder verbreiten, sofern es nicht durch diese Lizenz ausdruecklich gestattet ist. Jeder
anderweitige Versuch der Vervielfaeltigung, Modifizierung, Weiterlizenzierung und
Verbreitung ist nichtig und beendet automatisch Ihre Rechte unter dieser Lizenz.
Jedoch werden die Lizenzen Dritter, die von Ihnen Kopien oder Rechte unter dieser
Lizenz erhalten haben, nicht beendet, solange diese die Lizenz voll anerkennen und befolgen.
Paragraph 5. Sie sind nicht verpflichtet, diese Lizenz anzunehmen, da Sie sie nicht
unterzeichnet haben. Jedoch gibt Ihnen nichts anderes die Erlaubnis, das Programm
oder von ihm abgeleitete Werke zu veraendern oder zu verbreiten. Diese Handlungen
sind gesetzlich verboten, wenn Sie diese Lizenz nicht anerkennen. Indem Sie das
Programm (oder ein darauf basierendes Werk) veraendern oder verbreiten, erklaeren Sie
Ihr Einverstaendnis mit dieser Lizenz und mit allen ihren Bedingungen bezueglich der
Vervielfaeltigung, Verbreitung und Veraenderung des Programms oder eines darauf
basierenden Werkes.
Paragraph 6. Jedesmal, wenn Sie das Programm (oder ein auf dem Programm basierendes
Werk) weitergeben, erhaelt der Empfaenger automatisch vom urspruenglichen Lizenzgeber
die Lizenz, das Programm entsprechend den hier festgelegten Bestimmungen zu
vervielfaeltigen, zu verbreiten und zu veraendern. Sie duerfen keine weiteren
Einschraenkungen der Durchsetzung der hierin zugestandenen Rechte des Empfaengers
vornehmen. Sie sind nicht dafuer verantwortlich, die Einhaltung dieser Lizenz durch
Dritte durchzusetzen.
Paragraph 7. Sollten Ihnen infolge eines Gerichtsurteils, des Vorwurfs einer
Patentverletzung oder aus einem anderen Grunde (nicht auf Patentfragen begrenzt)
Bedingungen (durch Gerichtsbeschluss, Vergleich oder anderweitig) auferlegt werden,
die den Bedingungen dieser Lizenz widersprechen, so befreien Sie diese Umstaende nicht
von den Bestimmungen dieser Lizenz. Wenn es Ihnen nicht moeglich ist, das Programm
unter gleichzeitiger Beachtung der Bedingungen in dieser Lizenz und Ihrer
anderweitigen Verpflichtungen zu verbreiten, dann duerfen Sie als Folge das
Programm ueberhaupt nicht verbreiten. Wenn zum Beispiel ein Patent nicht
die gebuehrenfreie Weiterverbreitung des Programms durch diejenigen
erlaubt, die das Programm direkt oder indirekt von Ihnen erhalten haben,
dann besteht der einzige Weg, sowohl das Patentrecht als auch diese
Lizenz zu befolgen, darin, ganz auf die Verbreitung des Programms zu
verzichten.
Sollte sich ein Teil dieses Paragraphen als ungueltig oder unter bestimmten
Umstaenden nicht durchsetzbar erweisen, so soll dieser Paragraph seinem
Sinne nach angewandt werden; im uebrigen soll dieser Paragraph als Ganzes gelten.
Zweck dieses Paragraphen ist nicht, Sie dazu zu bringen, irgendwelche Patente
oder andere Eigentumsansprueche zu verletzen oder die Gueltigkeit solcher
Ansprueche zu bestreiten; dieser Paragraph hat einzig den Zweck, die Integritaet
des Verbreitungssystems der freien Software zu schuetzen, das durch die Praxis
oeffentlicher Lizenzen verwirklicht wird. Viele Leute haben grosszuegige Beitraege 
zu dem grossen Angebot der mit diesem System verbreiteten Software im
Vertrauen auf die konsistente Anwendung dieses Systems geleistet; es
liegt am Autor/Geber, zu entscheiden, ob er die Software mittels irgendeines
anderen Systems verbreiten will; ein Lizenznehmer hat auf diese Entscheidung
keinen Einfluss.
Dieser Paragraph ist dazu gedacht, deutlich klarzustellen, was als Konsequenz
aus dem Rest dieser Lizenz betrachtet wird.
Paragraph 8. Wenn die Verbreitung und/oder die Benutzung des Programms
in bestimmten Staaten entweder durch Patente oder durch urheberrechtlich
geschuetzte Schnittstellen eingeschraenkt ist, kann der Urheberrechtsinhaber,
der das Programm unter diese Lizenz gestellt hat, eine explizite geographische
Begrenzung der Verbreitung angeben, in der diese Staaten ausgeschlossen
werden, so dass die Verbreitung nur innerhalb und zwischen den Staaten
erlaubt ist, die nicht ausgeschlossen sind. In einem solchen Fall beinhaltet
diese Lizenz die Beschraenkung, als waere sie in diesem Text niedergeschrieben.
Paragraph 9. Die Free Software Foundation kann von Zeit zu Zeit ueberarbeitete
und/oder neue Versionen der General Public License veroeffentlichen. Solche
neuen Versionen werden vom Grundprinzip her der gegenwaertigen entsprechen,
koennen aber im Detail abweichen, um neuen Problemen und Anforderungen
gerecht zu werden.
Jede Version dieser Lizenz hat eine eindeutige Versionsnummer. Wenn in
einem Programm angegeben wird, dass es dieser Lizenz in einer bestimmten
Versionsnummer oder \"jeder spaeteren Version\" (\"any later version\")
unterliegt, so haben Sie die Wahl, entweder den Bestimmungen der
genannten Version zu folgen oder denen jeder beliebigen spaeteren
Version, die von der Free Software Foundation veroeffentlicht wurde.
Wenn das Programm keine Versionsnummer angibt, koennen Sie eine
beliebige Version waehlen, die je von der Free Software Foundation
veroeffentlicht wurde.
Paragraph 10. Wenn Sie den Wunsch haben, Teile des Programms in
anderen freien Programmen zu verwenden, deren Bedingungen fuer die
Verbreitung anders sind, schreiben Sie an den Autor, um ihn um die
Erlaubnis zu bitten. Fuer Software, die unter dem Copyright der
Free Software Foundation steht, schreiben Sie an die Free Software Foundation;
wir machen zu diesem Zweck gelegentlich Ausnahmen. Unsere Entscheidung
wird von den beiden Zielen geleitet werden, zum einen den freien Status aller
von unserer freien Software abgeleiteten Werke zu erhalten und zum anderen
das gemeinschaftliche Nutzen und Wiederverwenden von Software im
allgemeinen zu foerdern.


    
		GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The \"Program\", below,
refers to any such program or work, and a \"work based on the Program\"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term \"modification\".)  Each licensee is addressed as \"you\".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)
 
These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
 
  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
 
  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and \"any
later version\", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
"
}

proc menuHelp {} {
	global vers

	helpBox menue-hilfe \
"$vers

==============================================================================

Datei-Menue
   Verbinden  : Verbindet mit halfd auf der Adresse und Port die unter
                Optionen angegeben sind.  Sobald Sie verbunden sind wird Ihr
                Passwort uebermittelt und Sie sollten Informationen sehen.

   Trennen     : Trennt Ihre Verbindung zu halfd.  Dies hat KEINEN Einfluss
                auf irgendwelche laufenden hlds_l Server.

  Passwort eingeben : Hier koennen Sie Ihr Passwort eingeben, das Sie beim
                          Start des GUI eingegeben haben.

   -----------------------------------------------------------------

   HL Server starten: Startet den HL Server, der von dem halfd, zu dem Sie
                      verbunden sind, verwaltet wird.
                      Nur User, die mit dem Administratoren-Passwort angemeldet sind,
                      koennen dies tun.

   Server anhalten: Haelt den HL Server an, der von dem halfd, zu dem Sie
                      verbunden sind, verwaltet wird.
                      Nur User, die mit dem Administratoren-Passwort angemeldet sind,
                      koennen dies tun.


   -----------------------------------------------------------------

   Beenden          : Trennt Sie vom halfd und beendet das GUI.


==============================================================================

Optionen-Menue
   Client Optionen

      Server Port : Der TCP Port, auf dem halfd laeuft.  Ihr Server-
                    administrator kann Ihnen diese Information geben.
	
      Server Addr : Die IP-Adresse des Servers.  
                    Ihr Serveradministrator kann Ihnen diese Informtaion geben.
                    Dies ist wahrscheinlich die gleiche Adresse, zu der Sie auch
                    im Spiel verbinden.

      Log History : Anzahl der Zeilen, die im Ausgabefenster im unteren Teil
                    des GUI gespeichert werden sollen.

      Log Hoehe  : Anzahl der Zeilen, die im Audagabefenster im unteren Teil
                    des GUI sichtbar sein sollen.
                    Bei einem groesseren Fenster koennen auch mehr Zeilen angezeigt
                    werden.

      Tabellenhoehe  : Anzahl der Zeilen, die in der User/Ping/etc. Tabelle des GUI
                    angezeigt werden sollen.
                    Bei einem groesseren Fenster koennen auch mehr Zeilen angezeigt
                    werden.

      WONid anzeigen  : Wenn aktibiert, erscheint die WONid des Users in der
                    Tabelle.

      Modelle anzeigen  : Wenn aktiviert, erscheint das vom User benutzte Modell
                    in der Tabelle.
                    Der Server muss \"getmodels\" aktiviert haben, ansonsten erscheint nur
                    ein \"-\" in der Tabelle.

      Teams anzeigen   : Wenn aktiviert, erscheint die Nummer des Teams des
                    Users in der Tabelle.
                    Dies funktioniert nur fuer Counter-Strike und TFC.

      Chat Modus   : Dies hat nur Bedeutung, wenn sie \"Text empfangen\" aktiviert
                    haben.
                    Im \"Chat Modus\" bekommen Sie nur das, was die User sagen,
                    angezeigt. Status- und Server-Meldungen werden herausgefiltert.

   ---------------------------------------------------------------

  Makros konfigurieren

      Oeffnet ein Fenster, wo Sie Makros definieren koennen, die dann ueber den
                  \"Makros\" Knopf im GUI abgerufen werden koennen.

	  Hierbei handelt es sich um Kommandos, die direkt zum Server gesandt
                  werden.

  ---------------------------------------------------------------
	
   Alarm zuruecksetzen

	 Sollte ein Alarm vorhanden sein, wird dieser wieder auf  \"gruen\"
                 zurueckgesetzt.

   ---------------------------------------------------------------

   Folgende Optionen sind nur fuer Administratoren verfuegbar:

   Voting-Session beginnen : Wenn Voting eingeschaltet ist, oeffnet das sofort
                    eine neue Voting-Session.

   Voting abschalten : Schaltet das Voting komplett ab, z.B. fuer Clan-Matches
                    ratsam.

   Voting einschalten : Schaltet das Voting ein, falls es abgeschaltet wurde.
"
}

proc buttonHelp {} {
	global vers

	helpBox knopf-hilfe \
"$vers

==============================================================================

User kicken/bannen       
   Kicked den gewaehlten Users; es oeffnet sich ein weiters Fenster, wo man
   optional Ban-Details einstellen kann.
   Nur Administratoren koennen dies benutzen.

-----------------------------------------------------------------

Map wechseln       
   Es oeffnet sich eine Liste mit allen verfuegbaren Maps.
   Das \"changelevel\" Kommand wird zum Server gesandt, wenn eine Map
   gewaehlt wurde und auf \"bernehmen\" gedrueckt wurde.
   Dieser Knopf erscheint nur, wenn man als Administrator eingewaehlt ist.

Maps anzeigen
   Es oeffnet sich eine Liste mit allen verfuegbaren Maps.
   \"Uebernehmen\" oder \"Abbrechen\" schliesst die Liste.
   Dieser Knopf erscheint nur, wenn man als User eingewaehlt ist.

-----------------------------------------------------------------

Text empfangen
                Schaltet Textnachtichten, die Sie im unteren Ausgabefenster erhalten,
               ein.
               Standardmaessig ist dies nicht aktiviert, da es Bandbreite verbraucht.

Text anhalten
	Wenn Sie Textnachrichten erhalten, schalten Sie diese hiermit ab.
                Ratsam, wenn Sie fuer laengere Zeit nicht am PC sind.

-----------------------------------------------------------------

nslookup
	Zeigt den Hostname zu der IP des gewaehlten User an.

-----------------------------------------------------------------

Aktualisieren
   Aktualisiert alle Informationen sofort.
   Diese Option ist nur fuer Administratoren verfuegbar.
   Die Statistiken aktualisieren sich zusaetzlich in bestimmten Intervalen und
   wenn bestimmte Dinge auf dem Server eintreten (z.B. Map Wechsel).

-----------------------------------------------------------------

Makros
   
   Erlaubt Ihnen ein \"Makro\" auszufuehren, das Sie vorher im
   \"Makros konfigurieren\" Menue erstellt haben.
   Nur Administratoren koennen dies benutzen.

==============================================================================

Server-Kommando
   Alles was Sie hier eingeben wird vom Server ausgefuehrt.
   Nur Administratoren koennen dies benutzen.

-----------------------------------------------------------------

Mitteilen
   Alles was Sie hier eingeben wird allen Usern mitgeteilt.
   Nur Administratoren koennen dies benutzen.
"
}

######################################################################
# start of net code
proc connectToServer {} {
	global after sockFd gotInit connected clientOpts tcl_platform

	set gotInit 0

	catch { after cancel $after(connect) }

	set plat $tcl_platform(platform)

	set needResched 0

	if !$connected {
		set addr $clientOpts(addr)
		set port $clientOpts(port)

		statusBar "Verbinde zu $addr:$port ... "
		update idletasks

		if [cequal $plat unix] {

		# Use asynchronous connections.  Very cool.
		if [ catch {socket -async $addr $port} sockFd] {
			statusBar "Fehler beim Verbinden zu $addr:$port : $sockFd"
			set needResched 1
		} else {
			# We need to be non-blocking until we're connected.
			fconfigure $sockFd -blocking 0

			# Now wait for it to connect
			fileevent $sockFd writable sockConnected
		}

		} else {

		# We're on windoze.  Use a blocking connection.  Gross.
		if [ catch { socket $addr $port} sockFd] {
			statusBar "Fehler beim Verbinden zu $addr:$port : $sockFd"
			set needResched 1
		} else {
			# We're connected.
			set connected 1
			gotConnection
		}
		}
	}

	if $needResched {
		statusBar "Versuche erneuten Verbindungsaufbau in 30 sek...."
		set after(connect) [after 30000 connectToServer]
	}
}

proc sockConnected {} {
	global sockFd clientOpts connected

	set addr $clientOpts(addr)
	set port $clientOpts(port)

	# Delete the event
	fileevent $sockFd writable {}
	
	# Make sure we *really* connected
	if [catch { gets $sockFd } err] {
		statusBar "Fehler beim Verbinden zu $addr:$port : $err"
		statusBar "Versuche erneuten Verbindungsaufbau in 30 sek...."
		set after(connect) [after 30000 connectToServer]
	} else {
		# Now we want to block
		fconfigure $sockFd -blocking 1
		set connected 1
		gotConnection
	}
}

proc writeClientSock { data } {
	global sockFd clientOpts connected
	if !$connected return

hlDebug "[clock format [clock seconds] -format %T] wrote '$data'"

	if [catch {
		flush $sockFd
		puts $sockFd $data
		flush $sockFd
	} err ] {
		statusBar "Fehler beim Schreiben auf socket: '$err'.\nVerbindungsabbau."
		closeClientSock
	}
}

proc closeClientSock {} {
	global sockFd connected

	set connected 0

	catch { close $sockFd }

	statusBar "Verbindung zu halfd geschlossen."
	lostConnection
}

proc readClientSock {} {
	global sockFd

	if [catch { eof $sockFd } eof] {
		statusBar "Fehler beim Lesen von socket: $eof"
		closeClientSock
		return
	}

	if $eof {
		statusBar "halfd hat die Verbindung abgebaut!"
		closeClientSock
	} else {
		if [catch {gets $sockFd} data] {
			statusBar "Fehler beim Lesen von socket: $data"
			closeClientSock
		} else {
			# statusBar "[clength $data] bytes erhalten" 0
			processServerData $data $sockFd
		}
	}
}


# end of net code
######################################################################

proc setClientOpts {} {
	global clientOpts adminOpts font

	set f [toplevel .client]

	wm title $f "Client Optionen"
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .
	grab set $f 

	frame $f.port
	label $f.port.l -text "Server Port: " -width 25 -font $font(bold)
	entry $f.port.e -textvariable port -width 40 -font $font(norm)
	$f.port.e delete 0 end
	$f.port.e insert 0 $clientOpts(port)

	frame $f.addr
	label $f.addr.l -text "Server Addr: " -width 25 -font $font(bold)
	entry $f.addr.e -textvariable addr -width 40 -font $font(norm)
	$f.addr.e delete 0 end
	$f.addr.e insert 0 $clientOpts(addr)

	frame $f.info
	label $f.info.l -text "Folgende Optionen erfordern einen Neustart des GUI bevor sie in Kraft treten." -font $font(bold)
	
	frame $f.loghist
	label $f.loghist.l -text "Log History: " -width 25 -font $font(bold)
	entry $f.loghist.e -textvariable loghist -width 40 -font $font(norm)
	$f.loghist.e delete 0 end
	$f.loghist.e insert 0 $adminOpts(loghist)

	frame $f.logheight
	label $f.logheight.l -text "Log Hoehe: " -width 25 -font $font(bold)
	entry $f.logheight.e -textvariable logheight -width 40 -font $font(norm)
	$f.logheight.e delete 0 end
	$f.logheight.e insert 0 $adminOpts(logheight)

	frame $f.lbxheight
	label $f.lbxheight.l -text "Tabellenhoehe: " -width 25 -font $font(bold)
	entry $f.lbxheight.e -textvariable lbxheight -width 40 -font $font(norm)
	$f.lbxheight.e delete 0 end
	$f.lbxheight.e insert 0 $adminOpts(lbxheight)

	frame $f.fontsize
	label $f.fontsize.l -text "Schriftgrad: " -width 25 -font $font(bold)
	entry $f.fontsize.e -textvariable fontsize -width 40 -font $font(norm)
	$f.fontsize.e delete 0 end
	$f.fontsize.e insert 0 $font(size)

	foreach id "port addr info loghist logheight lbxheight fontsize" {
		pack $f.$id.l -side left
		catch { pack $f.$id.e -side left -expand y -fill x }
		pack $f.$id -expand y
	}

	frame  $f.wonid
	label  $f.wonid.l -text "WONid anzeigen " -width 25 -font $font(bold)
	checkbutton $f.wonid.b -variable chkWonId
	set de de
	if $adminOpts(wonid) { set de "" }
	$f.wonid.b ${de}select
	pack $f.wonid.l -side left
	pack $f.wonid.b -side left
	pack $f.wonid

	frame  $f.model
	label  $f.model.l -text "Modelle anzeigen " -width 25 -font $font(bold)
	checkbutton $f.model.b -variable chkModels
	set de de
	if $adminOpts(model) { set de "" }
	$f.model.b ${de}select
	pack $f.model.l -side left
	pack $f.model.b -side left
	pack $f.model

	frame  $f.team
	label  $f.team.l -text "Teams anzeigen " -width 25 -font $font(bold)
	checkbutton $f.team.b -variable chkTeam
	set de de
	if $adminOpts(team) { set de "" }
	$f.team.b ${de}select
	pack $f.team.l -side left
	pack $f.team.b -side left
	pack $f.team

	frame  $f.chat
	label  $f.chat.l -text "Chat-Modus " -width 25 -font $font(bold)
	checkbutton $f.chat.b -variable chkChat
	set de de
	if $adminOpts(chatmode) { set de "" }
	$f.chat.b ${de}select
	pack $f.chat.l -side left
	pack $f.chat.b -side left
	pack $f.chat

	#Admin-mod checkbox by Uli
	frame  $f.adminmod
	label  $f.adminmod.l -text "admin-mod " -width 25 -font $font(bold)
	checkbutton $f.adminmod.b -variable chkAdmin
	set de de
	if $adminOpts(adminmod) { set de "" }
	$f.adminmod.b ${de}select
	pack $f.adminmod.l -side left
	pack $f.adminmod.b -side left
	pack $f.adminmod

	frame $f.buts
	button $f.buts.a -text "Speichern" -command {

		foreach id "port addr" {
			set clientOpts($id) [.client.$id.e get]
		}

		foreach id "loghist logheight lbxheight" {
			set adminOpts($id) [.client.$id.e get]
		}

		set font(size) $fontsize
		set adminOpts(wonid)    $chkWonId
		set adminOpts(model)   $chkModels
		set adminOpts(team)    $chkTeam
		set adminOpts(chatmode) $chkChat
		#admin-mod check
		set adminOpts(adminmod) $chkAdmin

		writeConfig
		destroy .client
	}

	button $f.buts.c -text "Abbrechen" -command {
		destroy .client
	}

	label $f.buts.l -text "" -width 5 -font $font(bold)

	pack $f.buts.a -side left 
	pack $f.buts.l -side left 
	pack $f.buts.c -side right
	pack $f.buts

	centerWindow $f .

	update idletasks
}

proc execMacro {} {
	global macros

	set macs ""
	loop i 0 11 {
		if ![cequal $macros($i) ""] { lappend macs $macros($i) }
	}

	if [lempty $macs] {
		statusBar "Keine Makros definiert!" 0
	} else {
		popupListBox "Bitte Makro waehlen" 10 $macs execCmd
	}
}
	

proc createMacroMenu {} {
	global macros

	loop i 0 11 {
		catch { .menubar.macros.menu delete $i }
	}


   loop i 0 11 {
   		if [cequal $macros($i) ""] {
			set macLabel "<no macro>"
		} else {
			set macLabel $macros($i)
		}

   		.menubar.macros.menu add command -activeforeground blue -label $macLabel -command {
			# FOR SOME REASON THIS DOESN'T RETURN THE ACTIVE
			# SELECTION IN WINDOZE... :( !!!
			set idx [.menubar.macros.menu index active]
			if ![cequal $idx none] {
				set macCmd $macros($idx)
				if ![cequal $macCmd ""] {
					execCmd $macCmd
				}
			}
		}
   }
}
	

proc setMacros {} {
	global clientOpts adminOpts font macros

	set f [toplevel .macros]

	wm title $f "Makros"
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .
	grab set $f 

	loop i 0 11 {
		frame $f.macro$i
		label $f.macro$i.l -text "Makro # $i: " -width 25 -font $font(bold)
		entry $f.macro$i.e -textvariable macro$i -width 40 -font $font(norm)
		$f.macro$i.e delete 0 end
		$f.macro$i.e insert 0 $macros($i)

		pack $f.macro$i.l -side left
		pack $f.macro$i.e -side left -expand y -fill x
		pack $f.macro$i -expand y
	}

	frame $f.buts
	button $f.buts.a -text "Speichern" -command {

		loop i 0 11 {
			set macros($i) [string trim [.macros.macro$i.e get]]
		}

#		createMacroMenu

		writeConfig
		destroy .macros
	}

	button $f.buts.c -text "Abbrechen" -command {
		destroy .macros
	}

	label $f.buts.l -text "" -width 5 -font $font(bold)

	pack $f.buts.a -side left 
	pack $f.buts.l -side left 
	pack $f.buts.c -side right
	pack $f.buts

	centerWindow $f .

	update idletasks
}


proc setAuthState {} {
	global connected serverUp authLevel

	if ![info exists connected] { set connected 0 }
	if ![info exists authLevel] { set authLevel 0 }

	set authState normal

	# If not connected, disable everything except connect, exit, options, help
	# reset
	if !$connected {
		set authState disabled
		set svrStart disabled
		set svrStop  disabled
	} elseif $serverUp {
		set svrStart disabled
		set svrStop  normal
	} else {
		set svrStart normal
		set svrStop  disabled
	}

	# text, nslookup, refresh, changelevel
	.buts.tx configure -state $authState
	.buts.nl configure -state $authState
	.buts.refresh configure -state $authState
	.buts.cl configure -state $authState
	.buts.mac configure -state $authState

	if { $authLevel < 2 || !$connected } {
		set authState disabled
		set authColor grey
		set svrStart disabled
		set svrStop  disabled
	} else {
		set authState normal
		set authColor black
	}

	# Start and stop server
	.menubar.file.menu entryconfigure 4 -state $svrStart
	.menubar.file.menu entryconfigure 5 -state $svrStop

	# If not authorized, disable kick, start/stop server
	# open voting, enable voting, disable voting and refresh
	# Disable voting under 'options'
	foreach entry "4 5 6" {
		.menubar.options.menu entryconfigure $entry -state $authState
	}

	# Disable/enable macros
	loop i 0 11 {
		catch { .menu.macros.$i entryconfigure $entry -state $authState }
	}


	# Kick , changelevel, macros
	.buts.kick    configure -state $authState
	.buts.refresh configure -state $authState
	.buts.mac     configure -state $authState

	#admin-mod slap, slay, bury, unbury
	.buts2.slap    configure -state $authState
	.buts2.slay    configure -state $authState
	.buts2.bury    configure -state $authState
	.buts2.unbury  configure -state $authState

	# Change Map <-> View Maps
	if { $authLevel < 2 } {
		.buts.cl configure -text "Maps anzeigen"
	} else {
		.buts.cl configure -text "Map wechseln"
	}

	# Command, broadcast
	.cmd.e configure -state $authState
	.cmd.l configure -fg $authColor
	.say.e configure -state $authState
	.say.l configure -fg $authColor
	.normsay.e configure -state $authState
	.normsay.l configure -fg $authColor
	

	update idletasks

	return
}

proc processServerData { data fd } {
	global gotInit serverUp authLevel mapList svrInfo userInfo adminOpts

	if [cequal $data ""] return

	if [catch { keylget data type } type] {
		statusBar "Protokollfehler: $type"
		statusBar "Ungueltige Daten von halfd: $data"
		closeClientSock
		return
	}

	keylget data up up

	if { !$up && $serverUp } {
		serverDown
	} elseif { $up && !$serverUp } {
		serverUp
	}
		
	if ![catch {keylget data time} time] {
		set svrInfo(timeleft) $time
		updateTimer
	}

	if { [cequal $type INIT] } {
		set gotInit 1

		keylget data auth authLevel 

		switch -exact -- $authLevel {
			0 { statusBar "Keine Zugangsberechtigung!" }
			1 { statusBar "Als USER angemeldet." }
			2 { statusBar "Als ADMINISTRATOR angemeldet." }
			default {
				set err "[now] Unknown authLevel received: $authLevel"
				.alert.text configure -text $err -bg red
				statusBar $err
			}
		}

		setAuthState

		if $serverUp {
			keylget data name svrInfo(name)
			keylget data ip   svrInfo(ip)
			keylget data max  svrInfo(max)
			keylget data port svrInfo(port)
			serverUp
			return
		}
	} elseif !$gotInit {
		statusBar "Didn't get INIT message from server!"
		closeClientSock
		return
	}

	switch -exact -- $type {
		UPDATE {
			foreach id "users pings frags times ips wonid userid model team" {
				set userInfo($id) ""
			}

			foreach id "users pings frags times ips userid wonid model team" {
				keylget data data.$id userInfo($id)
			}

			keylget data data.map  svrInfo(map)
			keylget data data.cnt  svrInfo(player)
			keylget data data.vote svrInfo(vote)

			Bind_Display
			statusBar "Statistik aktualisiert: [now]" 0
		}

		TEXT {
			keylget data data text
			logText $text
		}

		SB     {
			keylget data data.sb sb
			keylget data data.text text
			if !$sb { set sb 2 }
			statusBar $text $sb
		}

		STATUS {}

		ERR {
			keylget data data err
			.alert.text configure -text $err -bg red
		}

		MAPLIST {
			keylget data data mapList
		}
	}
}

proc updateTimer {} {
	global svrInfo

	if [cequal $svrInfo(timeleft) 0] {
		set maprem ??:??
	} elseif ![ctype digit $svrInfo(timeleft)] {
		set maprem $svrInfo(timeleft)
	} else {
		set maprem ""
		set mapsec $svrInfo(timeleft)
		set maphr  [expr $mapsec / 3600]
		if $maphr { set maprem "$maphr:" }

		set mapmin [expr [expr $mapsec / 60] % 60]
		set mapsec [format %02d [expr $mapsec % 60]]

		append maprem $mapmin:$mapsec
	}

	.map.tl configure -text "Verbleibende Zeit: $maprem"
}

proc lostConnection {} {
	global gotInit gettingText authLevel svrInfo userInfo

	toggleText 1

	if !$gotInit {
		statusBar "Falsches Passwort."
		logText   "Oder Versuch zum falschen Server zu verbinden."
		logText   "Der Server kann unter dem Menue Optionen->Client Optionen geaendert werden."
	} else {
		set gotInit 0
	}

	.status.halfd configure -text "<Nicht verbunden.>"  -bg red
	.status.hlds_l  configure -text "<Status unbekannt.>" -bg red
	.menubar.file.menu entryconfigure 0 -state normal
	.menubar.file.menu entryconfigure 1 -state disabled

	set svrInfo(map)    ""
	set svrInfo(player) 0
	set svrInfo(vote) 3

	foreach id "users pings frags times ips wonid userid model team" {
		set userInfo($id) ""
	}
	Bind_Display

	set authLevel 0
	setAuthState
}

proc gotConnection {} {
	global sockFd authString clientOpts

	statusBar \
	"Verbunden mit halfd auf dem Server $clientOpts(addr):$clientOpts(port)"
	if ![info exists authString] getAuth
	writeClientSock $authString
	fileevent $sockFd readable readClientSock

	.status.halfd configure -text "Verbunden mit halfd"  -bg green

	.menubar.file.menu entryconfigure 0 -state disabled
	.menubar.file.menu entryconfigure 1 -state normal
}

proc toggleText {{stop 0}} {
	global gettingText adminOpts

	if $stop { set gettingText 1 }

	if $gettingText {
		writeClientSock NOTEXT
		set gettingText 0
		set mode empfangen
	} else {
		if $adminOpts(chatmode) {
			writeClientSock "CHAT"
		} else {
			writeClientSock "TEXT"
		}
		set gettingText 1
		set mode anhalten
	}

	.buts.tx configure -text "Text $mode"
}


proc logText { text } {
	global adminOpts userInfo expr tagbg tagfg logbg logfg

	.info.text configure -state normal
	.info.text insert end "$text\n" 
	set lines [.info.text index end]
	if { [lindex [.info.sy get] 1] == 1 } {
		.info.text see end 
	}

	if { $lines > $adminOpts(loghist) } {
		set cnt [expr int($lines) - $adminOpts(loghist) - 1]
		.info.text delete 0.0 $cnt.0
	}
	# highlight chat msgs
	set lines [.info.text index end]
	foreach user $userInfo(users) {
		set linenumber [expr [lindex [split $lines .] 0] - 2]
		set tagstart $linenumber.0
		set tagend [expr $linenumber + 1].0
		if { [cequal [string first $user $text] 0] || [regexp -- $expr(team) $text] } {
			.info.text tag add chat $tagstart $tagend
			.info.text tag configure chat -background $tagbg(chat) -foreground $tagfg(chat)
		} elseif { [regexp -- $expr(dead) $text] } {
			.info.text tag add dead $tagstart $tagend
			.info.text tag configure dead -background $tagbg(dead) -foreground $tagfg(dead)
		} elseif { [regexp -- $expr(terrorist) $text] } {
			.info.text tag add terrorist $tagstart $tagend
			.info.text tag configure terrorist -background $tagbg(terrorist) -foreground $tagfg(terrorist)
		} elseif { [regexp -- $expr(counter-terrorist) $text] } {
			.info.text tag add counter-terrorist $tagstart $tagend
			.info.text tag configure counter-terrorist -background $tagbg(counter-terrorist) -foreground $tagfg(counter-terrorist)
		} elseif { [regexp -- $expr(server) $text] } {
			.info.text tag add server $tagstart $tagend
			.info.text tag configure server -background $tagbg(server) -foreground $tagfg(server)
		} else {
			#.info.text tag add log $tagstart $tagend
			#.info.text tag configure log -background $logbg -foreground $logfg
			#.info.text tag raise log
		}
	}
	.info.text configure -state disabled
}

#######################################################################
# tkerror - supress any gui error msgs; server *may* continue to run...?
#
#proc tkerror {errmsg} {
#     puts stderr "An error has occurred.  If you can reliably reproduce it,"
#     puts stderr "please contact the author!   See Help->About."
#     puts stderr $errmsg
#}


######################################################################
# centerWindow - center a window on the display or relative to a 
#                   parent window
#
# Args:
#        window  - window to be centered
#        parent  - (optional) parent window in which 'window'
#                  should be centered. If empty, 'window' is
#                  centered on the display
#
# Notes:
#
# This really only works if the size of the window has already been
# established.  For example, if a window hasn't been mapped yet it's
# width and height may very will be 1x1. Grep for examples of how to
# work around this
#
# PACKAGE-EXPORT centerWindow
#
proc centerWindow {window {parent {}}} {

    set centerDisp 1
    if {$parent != {}} {
	if {[winfo viewable $parent]} {
	    set centerDisp 0
	} 
    } 

    if {$centerDisp} {
	set pw [winfo screenwidth $window]
	set ph [winfo screenheight $window]
    } else {
	set pw [winfo width $parent]
	set ph [winfo height $parent]
    }

    set width [expr [winfo reqwidth $window] + 10]
    set height [expr [winfo reqheight $window] + 10]

    if {$centerDisp} {
	set xo 0
	set yo 0
    } else {
	set xo [winfo x $parent]
	set yo [winfo y $parent]
    }

    set x [expr ($pw / 2) - ($width / 2) + $xo]
    set y [expr ($ph / 2) - ($height / 2) + $yo]

    set screen $parent
    if {$parent == {}} {set screen .}
    set maxX [expr [winfo screenwidth $screen] - $width]
    set maxY [expr [winfo screenheight $screen] - $height]
    set x [min [max $x 0] $maxX]
    set y [min [max $y 0] $maxY]

    wm geometry $window "+$x+$y"
}

proc statusBar { text {log 1} } {
	global adminOpts

	catch {

	if { $log < 2 } {
		.statusbar configure -text $text
	}

	if $log {
		logText $text
	}

	update idletasks

	}
}

proc changeLevel { map } {
	global fds adminOpts authLevel

	if { $authLevel > 1 } {
		writeClientSock "changelevel $map"
		statusBar "Zur Map '$map' gewechselt."
	}
}

proc serverUp {} {
	global fds serverUp svrInfo
	set serverUp 1

	# .status.hlds_l configure -text "$svrInfo(name) -- $svrInfo(ip)" -bg green
	.status.hlds_l configure -text $svrInfo(name) -bg green

	.menubar.file.menu entryconfigure 4 -state disabled
	.menubar.file.menu entryconfigure 5 -state normal

	setAuthState
}

proc nsLookup {} {
	global userInfo

	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte eine IP-Addresse zum Aufloesen auswaehlen..." 0
		sleep 1
		return
	}

	set ip [lindex $userInfo(ips) $idx]
	if [cequal $ip CONNECTING] {
		statusBar "Bitte warten bis der Benutzer verbunden hat!" 0
		return
	}

	statusBar "Nameserver-Aufloesung von $ip im Gange..."
	update idletasks

	if [catch { host_info official_name $ip } data] {
		statusBar "Error on nslookup: $data"
	} else {
		set user [lindex $userInfo(users) $idx]
		statusBar "$user - $ip loest nach [string trim $data] auf"
	}
}

proc popupListBox { title height list okcmd } {
	global lbcmd font

	set lbcmd $okcmd
	set f [toplevel .listBox]

	wm title $f $title
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .
	grab set $f 

	frame $f.lb
	scrollbar $f.lb.sb -orient vertical -command [list $f.lb.lb yview]

	listbox $f.lb.lb -height $height -yscrollcommand [list $f.lb.sb set] -font $font(norm)
	pack $f.lb.sb -side left -fill y -expand y
	pack $f.lb.lb -side right
	pack $f.lb
	foreach item $list {
		$f.lb.lb insert 0 $item
	}

	frame $f.buts
	button $f.buts.a -text "Uebernehmen" -command {
		catch {
		[$lbcmd [.listBox.lb.lb get [.listBox.lb.lb curselection]]]
		}
		destroy .listBox
	} -font $font(norm)

	button $f.buts.c -text "Abbrechen" -command {
		destroy .listBox
	} -font $font(norm)
	pack $f.buts.a -side left 
	pack $f.buts.c -side right
	pack $f.buts

	centerWindow $f .

	tkwait window $f
}

proc popupError { error } {
	global vers errText font
	set f .error

	set errText $error

	toplevel $f

	wm title $f "$vers Error"
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .
	grab set $f 

	frame $f.f
	message $f.f.t -fg red -bg black -text $errText -justify left 
	pack $f.f.t

	frame $f.buts
	button $f.buts.d -text "Verwerfen" -command {destroy .error}
	pack $f.buts.d -side bottom
	button $f.buts.s -text "Fehlermeldung speichern" -command {
		set fd [open hlgui.err a]
		puts $fd [replicate = 70]
		puts $fd "Error occurred [now]"
		puts $fd ""
		puts $fd $errText
		puts $fd ""
		close $fd
		.error.sb.l configure -text "Meldung gespeichert in [pwd]/hlgui.err"
	}
	pack $f.buts.d -side left
	pack $f.buts.s -side right
	pack $f.buts -side bottom -fill x -expand 1

	frame $f.sb -relief raised -bd 3
	label $f.sb.l -text "Willkommen bei hlgui!" -font $font(bold)
	pack $f.sb.l
	pack $f.sb -side bottom -fill x -expand 1

	pack $f.f

	centerWindow $f .

	update idletasks
	tkwait window $f
}

proc serverDown {} {
	global serverUp
	set serverUp 0

	.status.hlds_l configure -text "<Server Down>" -bg red

	.stats.tul configure -text "Verb / Aktiv / Max:  0 / 0 / 0"
	.stats.apl configure -text "Durchschnitts-Ping:  0"
	.stats.vote configure -text "Voting: <unbekannt>"

	.map.t  configure -text "Map : <keine>"
	.map.tl configure -text "Verbleibende Zeit: ??:??"

	setAuthState
}

proc Bind_Display {} {
	global lbxs userInfo adminOpts svrInfo font

	# Get the current selection, if any
	set idx [.table.user.l curselection]
	set oldId "xxx"
	if ![cequal $idx ""] {
		set user [.table.user.l get $idx]
		set ip   [.table.ip.l get $idx]
		set oldId "$user^$ip"

		foreach id "user ping frag time ip" {
			.table.$id.l selection clear $idx
		}

		if { $adminOpts(wonid) && $adminOpts(packedwonid) } {
			.table.wonid.l selection clear $idx
		}

		if { $adminOpts(model) && $adminOpts(packedmodel) } {
			.table.model.l selection clear $idx
		}

		if { $adminOpts(team) && $adminOpts(packedteam) } {
			.table.team.l selection clear $idx
		}
	}

	set con 0
	set act 0
	foreach ip $userInfo(ips) {
		if [cequal $ip CONNECTING] {
			incr con
		} else {
			incr act
		}
	}

	.stats.tul configure -text "Verb / Aktiv / Max:   $con / $act / $svrInfo(max)"

	set avgping 0
	if { $svrInfo(player) > 0 } {
		set tot 0
		set cnt $svrInfo(player)
		foreach ping $userInfo(pings) {
			# Toss the '9999' pings
			if [cequal $ping 9999] {
				incr cnt -1
			} else {
				incr tot $ping
			}
		}

		#set cnt $svrInfo(player)
		#set high 0
		#set low  9999
		#if { $svrInfo(player) > 3 } {
		#	# Toss the 9999 pings
		#	incr tot -$high
		#	incr tot -$low
		#	incr cnt -2
		#}

		if $cnt { set avgping [expr $tot / $cnt] }
	}
	.stats.apl configure -text "Durchschnitts-Ping:   $avgping"

	switch $svrInfo(vote) {
		0 { set vote Ausgeschaltet  }
		1 { set vote Eingeschaltet  }
		2 { set vote "Grade dabei..." }
		default { set vote <unbekannt> }
	}
	.stats.vote configure -text "Voting: $vote"

	.map.t configure -text "Map : $svrInfo(map)"
	updateTimer

	# Do the table
	foreach lbx $lbxs {
		$lbx delete 0 end
	}

	set i 0
	foreach user $userInfo(users) {
		.table.user.l  insert end $user
		.table.ping.l  insert end [lindex $userInfo(pings) $i]
		.table.frag.l  insert end [lindex $userInfo(frags) $i]
		.table.time.l  insert end [lindex $userInfo(times) $i]

		set ip [lindex $userInfo(ips) $i]
		.table.ip.l    insert end $ip

		# Put the selection back if that user is still around
		if [cequal "$user^$ip" $oldId] {
			foreach id "user ping frag time ip" {
				.table.$id.l selection set $i
			}
		}

		if { $adminOpts(wonid) && $adminOpts(packedwonid) } {
			.table.wonid.l insert end [lindex $userInfo(wonid) $i]
			if [cequal "$user^$ip" $oldId] {
				.table.wonid.l selection set $i
			}
		}

		if { $adminOpts(model) && $adminOpts(packedmodel) } {
			.table.model.l insert end [lindex $userInfo(model) $i]
			if [cequal "$user^$ip" $oldId] {
				.table.model.l selection set $i
			}
		}

		if { $adminOpts(team) && $adminOpts(packedteam) } {
			.table.team.l insert end [lindex $userInfo(team) $i]
			if [cequal "$user^$ip" $oldId] {
				.table.team.l selection set $i
			}
		}

		incr i
	}

}

proc BindDragto { x y args } {
        foreach w [lindex $args 0] {
                $w scan dragto $x $y
        }
}

proc BindMark { x y args } {
        foreach w $args {
                $w scan mark $x $y
        }
}

proc BindYview { lists args } {
        foreach l $lists {
                eval {$l yview} $args
        }
}

proc BindSelect { y args } {
        foreach w [lindex $args 0] {
                $w select clear 0 end
                $w select anchor [$w nearest $y]
                $w select set anchor [$w nearest $y]
        }
}

proc writeConfig {} {
	global clientOpts adminOpts gameId kl font macros

	if [catch {open halfd_client.cfg w} fd] {
		popupError "Fehler beim ffnen der Konfigurationsdatei: $fd"
		exit 1
	}


	keylset kl CLIENT.chatmode  $adminOpts(chatmode)
	keylset kl CLIENT.loghist   $adminOpts(loghist)
	keylset kl CLIENT.logheight $adminOpts(logheight)
	keylset kl CLIENT.lbxheight $adminOpts(lbxheight)
	keylset kl CLIENT.adminmod  $adminOpts(adminmod)
	keylset kl CLIENT.wonid     $adminOpts(wonid)
	keylset kl CLIENT.model     $adminOpts(model)
	keylset kl CLIENT.team      $adminOpts(team)
	keylset kl CLIENT.fontsize  $font(size)

	loop i 0 11 {
		keylset kl MACRO.$i $macros($i)
	}

	keylset kl SERVER.port $clientOpts(port)
	keylset kl SERVER.addr $clientOpts(addr)

	puts $fd [replicate # 78]
	puts $fd "# halfd Client Configuration File"

	if [catch {
		puts $fd "# Updated [now], [id user]"
	} err] {
		puts $fd "# Updated [now]"
	}

	puts $fd [replicate # 78]
	puts $fd "#"
	puts $fd ""
	foreach item $kl {
		puts $fd [list $item]
	}

	close $fd
}

proc readConfig {} {
	global clientOpts adminOpts gameId kl font macros env

	if [info exists env(HLDIR)] {
		cd $env(HLDIR)
	}

	if ![file exists halfd_client.cfg] {
		popupError "
Can't find 'halfd_client.cfg' configuration file!
Please start this GUI from the directory that
contains the halfd_client.cfg file, or
set the environment variable HLDIR to point
to the proper directory."
		exit 1
	}

	if [catch {open halfd_client.cfg r} fd] {
		popupError "Fehler beim Oeffnen der Konfigurationsdatei: $fd"
		exit 1
	}

	set kl ""
	while 1 {
		set line [gets $fd]
		if [eof $fd] break
		if {[cequal [string trim $line] ""] || \
			[cequal [csubstr [string trim $line] 0 1] "#"]} continue
		append kl " $line"
	}

	set adminOpts(lbxheight) 10
	set adminOpts(logheight) 10
	set adminOpts(loghist)   300
	set adminOpts(wonid)     0
	set adminOpts(model)     0
	set adminOpts(team)      0
	set adminOpts(chatmode)  0
	set adminOpts(adminmod)  0

	set font(size) 14

	set clientOpts(port) 3000
	set clientOpts(addr) 63.68.143.63

	loop i 0 11 { set macros($i) "" }

	keylget kl CLIENT.chatmode  adminOpts(chatmode)
	keylget kl CLIENT.adminmod  adminOpts(adminmod)
	keylget kl CLIENT.loghist   adminOpts(loghist)
	keylget kl CLIENT.logheight adminOpts(logheight)
	keylget kl CLIENT.lbxheight adminOpts(lbxheight)
	keylget kl CLIENT.wonid     adminOpts(wonid)
	keylget kl CLIENT.model     adminOpts(model)
	keylget kl CLIENT.team      adminOpts(team)
	keylget kl CLIENT.fontsize  font(size)

	loop i 0 11 {
		keylget kl MACRO.$i macros($i)
	}

	keylget kl SERVER.port clientOpts(port)
	keylget kl SERVER.addr clientOpts(addr)
}

proc buildTable {} {
	global lbxs adminOpts font

	set lbxfs [list .table.user .table.ping .table.frag \
		.table.time .table.ip]

	if $adminOpts(wonid) { 
		lappend lbxfs .table.wonid
		set adminOpts(packedwonid) 1
	} else {
		set adminOpts(packedwonid) 0
	}

	if $adminOpts(model) { 
		lappend lbxfs .table.model
		set adminOpts(packedmodel) 1
	} else {
		set adminOpts(packedmodel) 0
	}

	if $adminOpts(team) { 
		lappend lbxfs .table.team
		set adminOpts(packedteam) 1
	} else {
		set adminOpts(packedteam) 0
	}

	foreach lbxf $lbxfs {
		lappend lbxs ${lbxf}.l
	}
   #
   # User, ping, frags, time, ip , (and optionally) wonid, model, team table
   #

	frame .table
	set frame .table
	grid rowconfigure $frame 0 -weight 1

	set widths [list 30 7 7 10 18]
	set hdrs [list User Ping Frags Zeit "IP-Addresse"]
	if $adminOpts(wonid) {
		lappend widths 10
		lappend hdrs   WONid
	}

	if $adminOpts(model) {
		lappend widths 12
		lappend hdrs   Modell
	}

	if $adminOpts(team) {
		lappend widths 6
		lappend hdrs   Team
	}

	# Five listboxes and a scrollbar
	set i 0
	foreach lbxf $lbxfs {
		frame $lbxf
		if !$i {
			set sf $frame.sy
			scrollbar $sf -orient vertical \
				-command [list BindYview $lbxs]
		}
		label $lbxf.t -text [lindex $hdrs $i] -font $font(bold)
		set lbx $lbxf.l
			
		set export "false"
		if !$i {set export "true"}
		listbox $lbxf.l \
			-yscrollcommand [list $sf set] \
			-exportselection $export \
			-bg black -fg green \
			-width [lindex $widths $i] \
			-font $font(norm)

			# -height $adminOpts(lbxheight) \

		incr i
	}

	grid $sf -in $frame -row 0 -column 0 -sticky ns

	set i 1
	foreach lbx $lbxfs {
		grid $lbx.t -in $lbx -row 0 -column 0 -sticky ew
		grid $lbx.l -in $lbx -row 1 -column 0 -sticky nsew
		grid rowconfigure $lbx 1 -weight 1
		grid $lbx -in $frame -row 0 -column $i -sticky nsew
		incr i
	}

	# expand the next (unfilled) column
        grid columnconfigure $frame $i -weight 1

	foreach lbx $lbxs {
		bind $lbx <ButtonPress> \
			[list BindSelect %y $lbxs]
		bind $lbx <ButtonRelease> \
			[list BindSelect %y $lbxs]
		bind $lbx <Button> \
			[list BindSelect %y $lbxs]
		bind $lbx <B1-Motion> \
			[list BindDragto %x %y $lbxs]
		bind $lbx <B2-Motion> \
			[list BindDragto %x %y $lbxs]
	}

        return $frame
}

proc launchServer {} {
	statusBar "Starte den Server.  Bitte warten..."
	writeClientSock start
}

#this one uses admin-mod's admin_tsay feature
proc say { { text "" } } {
	
	if [cequal $text ""] {
		set text [.say.e get]
		.say.e delete 0 end
	}

        writeClientSock "admin_command admin_tsay red $text"
	
	statusBar "Habe '$text' mitgeteilt..."
}

#this is the normal saying
proc normsay { { text "" } } {

	if [cequal $text ""] {
		set text [.normsay.e get]
		.normsay.e delete 0 end
	}

	writeClientSock "say $text"
                	
	statusBar "Habe '$text' mitgeteilt..."
}


proc execCmd {{cmd ""}} {
	global fds 

	if [cequal $cmd ""] {
		set cmd [.cmd.e get]
		.cmd.e delete 0 end
	}
	if [cequal $cmd ""] return

	statusBar "Habe  '$cmd' zum Server gesandt..."
	writeClientSock $cmd
}

#several procs to make use of some admin-mod features
proc slapUser {} {
	global font userInfo
	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte User zum schlagen whlen..." 0
		sleep 1
		return
	}

	set usertoslap  [lindex $userInfo(users)  $idx]
	execCmd "admin_command admin_slap $usertoslap"
}

proc buryUser {} {
	global font userInfo
	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte User zum begraben whlen..." 0
		sleep 1
		return
	}

	set usertoslap  [lindex $userInfo(users)  $idx]
	execCmd "admin_command admin_bury $usertoslap"
}

proc unburyUser {} {
	global font userInfo
	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte User zum ausgraben whlen..." 0
		sleep 1
		return
	}

	set usertoslap  [lindex $userInfo(users)  $idx]
	execCmd "admin_command admin_unbury $usertoslap"
}

proc slayUser {} {
	global font userInfo
	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte User zum schlachten whlen..." 0
		sleep 1
		return
	}

	set usertoslap  [lindex $userInfo(users)  $idx]
	execCmd "admin_command admin_slay $usertoslap"
}

proc kickBanUser {} {
	global font

	proc banButton {} {
		global ban

		set state disabled
		set fg grey

		if $ban {
			set state normal
			set fg black
		}

		.kick.bt.l configure -fg $fg
		.kick.bt.e configure -state $state
		.kick.dl.l configure -fg $fg
	}

	global fds userInfo ban banuser banuid banwonid

	set idx [.table.user.l curselection]
	if [cequal $idx ""] {
		statusBar "Bitte User zum kicken/bannen waehlen..." 0
		sleep 1
		return
	}

	set banuid   [lindex $userInfo(userid) $idx]
	set banuser  [lindex $userInfo(users)  $idx]
	set banwonid [lindex $userInfo(wonid) $idx]

	set ban 0

	set f [toplevel .kick]

	wm title $f "Kick / Ban $banuser"
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .
	grab set $f 

	frame $f.ban
	label $f.ban.l -text "Ban User: " -width 25 -font $font(bold)
	checkbutton $f.ban.b -command banButton -variable ban
	set de "de"
	if $ban { set de "" }
	$f.ban.b ${de}select
	pack $f.ban.l -side left
	pack $f.ban.b -side left -expand y
	pack $f.ban

	frame $f.bt
	label $f.bt.l -text "Ban-Zeit: " -width 20 -font $font(bold)
	entry $f.bt.e -width 5 -font $font(norm)
	$f.bt.e delete 0 end
	$f.bt.e insert 0 0
	pack $f.bt.l -side left
	pack $f.bt.e -side left -expand y -fill x
	pack $f.bt -expand y

	frame $f.dl
	label $f.dl.l -text "Zeit in Minuten.  0 = fuer immer" -font $font(bold)
	pack $f.dl.l -side left
	pack $f.dl -expand y

	banButton

	frame $f.buts
	button $f.buts.a -text "Uebernehmen" -command {
		if !$ban {
			execCmd "kick # $banuid"
		} else {
			set bantime [.kick.bt.e get]
			if !$bantime { execCmd "exec banned.cfg" }
			   execCmd "banid $bantime $banwonid kick"
			if !$bantime { execCmd "writeid" }
		}

		destroy .kick

		if !$ban {
			statusBar "Habe $banuser gekicked!"
		} else {
			if !$bantime {
				statusBar "Habe User $banwonid in die banned.cfg geschrieben."
			}
			statusBar "Habe $banuser gekicked und fuer $bantime Minuten gebanned!"
		}
	}

	button $f.buts.c -text "Abbrechen" -command {
		destroy .kick
	}

	label $f.buts.l -text "" -width 5 -font $font(bold)

	pack $f.buts.a -side left 
	pack $f.buts.l -side left
	pack $f.buts.c -side right 
	pack $f.buts

	centerWindow $f .

	tkwait window $f
}

proc stopServer {} {
	writeClientSock quit
}

proc now {} {
	return [clock format [clock seconds]]
}

proc getMaps {} {
	global mapList

	if ![info exists mapList] {
		writeClientSock MAPLIST
		vwait mapList
	}

	return $mapList
}
	
proc getAuth {} {
	global authString font

	set authString ""

	set f [toplevel .auth]

	wm title $f "Passwort eingeben"
	wm resizable $f 0 0
	wm group $f .
	wm transient $f .


	frame $f.entry
	entry $f.entry.e -textvariable authString -width 40 -show * -font $font(norm)
	$f.entry.e delete 0 end
	$f.entry.e insert 0 $authString
	bind $f.entry.e <Return> {
		set authString [.auth.entry.e get]
		destroy .auth
	}

	pack $f.entry
	pack $f.entry.e

	centerWindow $f .

	grab set $f 
	focus $f.entry.e

	tkwait window $f
}

proc setFont { } {
	global font

	set size $font(size)
	set font(bold) "-*-helvetica-bold-r-normal-*-$font(size)-*-*-*-*-*-*-*"
	set font(norm) "-*-helvetica-medium-r-normal-*-$font(size)-*-*-*-*-*-*-*"
}


proc hlDebug { msg } {
	global debugFlag

	if $debugFlag {
		set fd [open hlgui.debug a]
		puts $fd $msg
		close $fd
	}
}

proc usage {} {
	popupError "
Usage: hlgui \[port \[addr\]\]

Where: 

port = The TCP port to use to connect to halfd.  This will override the port set in your configuration file.

addr = The IP address to use to connect to halfd.  This will override the port set in your configuration file.
"
	exit 1
}

#######################################################################
# MAIN - the main gui program.
#
proc main { argc argv } {
   global lbxs adminOpts clientOpts gameId env fds vers sockFd authString
   global font logbg logfg macros env 

   frame .menubar -relief raised -borderwidth 3
   
   readConfig
   setFont

	if { $argc < 5 && $argc > 0 } {
		lassign $argv port addr junk argAuth
		if ![cequal [string first hlgui $port] -1] {
			lassign $argv foo port addr junk argAuth
		}
		if { ![ctype digit $port] && ![cequal port ""] } { usage }
		# Only arg is port
		set clientOpts(port) $port
		if ![cequal $addr ""] { set clientOpts(addr) $addr }
	} elseif { $argc > 0 } {
		usage
	}

   # 
   # Menubar
   # 
   menubutton .menubar.file -text "Datei" -menu .menubar.file.menu -font $font(bold)
   # keep a column counter for more menus
   set column 0
   grid .menubar.file -in .menubar -row 0 -column $column
   incr column
   menu .menubar.file.menu -tearoff 0
   .menubar.file.menu add command -label "Verbinden" -command { connectToServer } -font $font(bold)
   .menubar.file.menu add command -label "Trennen" -command { closeClientSock } -font $font(bold)
   .menubar.file.menu add command -label "Passwort eingeben" -command {
	getAuth
	if $connected {
		closeClientSock
		statusBar "Neuverbinden..." 0
		update idletasks
		sleep 2
		update idletasks
		connectToServer
	}
	} -font $font(bold)
   .menubar.file.menu add separator
   .menubar.file.menu add command -label "HL Server starten" -command {launchServer} \
 	-font $font(bold)
   .menubar.file.menu add command -label "HL Server anhalten" -command {stopServer} \
	-font $font(bold)
   .menubar.file.menu add separator
   .menubar.file.menu add command -label "Beenden" -command {destroy .} -font $font(bold)

   menubutton .menubar.options -text "Optionen" -menu .menubar.options.menu \
	-font $font(bold)
   grid .menubar.options -in .menubar -row 0 -column $column
   incr column
   menu .menubar.options.menu -tearoff 0
   .menubar.options.menu add command -label "Client Optionen" \
	-command setClientOpts -font $font(bold)
   .menubar.options.menu add command -label "Makros konfigurieren" \
	-command setMacros -font $font(bold)
   .menubar.options.menu add command -label "Alarm zuruecksetzen" \
	-command {
		.alert.text configure -text "<keine Alarme>" -bg green
	} -font $font(bold)
   .menubar.options.menu add separator
   .menubar.options.menu add command -label "Voting-Session beginnen" \
	-command {
		writeClientSock STARTVOTE
	} -font $font(bold)
   .menubar.options.menu add command -label "Voting abschalten" \
	-command {
		writeClientSock VOTEOFF
	} -font $font(bold)
   .menubar.options.menu add command -label "Voting einschalten" \
	-command {
		writeClientSock VOTEON
	} -font $font(bold)

#   menubutton .menubar.macros -text "Makros" -menu .menubar.macros.menu \
#	-font $font(bold)
#   pack .menubar.macros -side left
#   menu .menubar.macros.menu -tearoff 0

#	createMacroMenu


   # create an empty, expanding column
   grid columnconfigure .menubar $column -weight 1
   incr column
   menubutton .menubar.help -text "Hilfe" -menu .menubar.help.menu -font $font(bold)

   grid .menubar.help -in .menubar -row 0 -column $column
   menu .menubar.help.menu -tearoff 0
   .menubar.help.menu add command -label "Ueber" -command aboutGui -font $font(bold)
   .menubar.help.menu add separator
   .menubar.help.menu add command -label "Menueleiste" -command menuHelp -font $font(bold)
   .menubar.help.menu add command -label "Knoepfe" -command buttonHelp -font $font(bold)
   .menubar.help.menu add separator
   .menubar.help.menu add command -label "Bedingungen" -command cdm -font $font(bold)
   .menubar.help.menu add command -label "Garantie" -command warranty -font $font(bold)

#we use the $k variable to determine the current row
set k 0
   grid .menubar -in . -row 0 -column 0 -sticky ew
   grid columnconfigure . 0 -weight 1
   incr k

	# Server title
	frame .status
	label .status.halfd -text "<nicht verbunden>" -bg red -font $font(bold) \
		-anchor center
	label .status.hlds_l  -text "<status unbekannt>" -bg red -font $font(bold) \
		-anchor center
	grid .status.halfd -in .status -row 0 -column 0 -sticky ew
	grid .status.hlds_l -in .status -row 0 -column 1 -sticky ew
	grid columnconfigure .status 0 -weight 1
	grid columnconfigure .status 1 -weight 1
	grid .status -in . -row $k -column 0 -sticky ew
	incr k

	# Alert frame
	frame .alert
	label .alert.text -text "<keine Alarme>" -bg green  -font $font(bold) \
		-anchor center
	grid .alert.text -in .alert -row 0 -column 0 -sticky ew
	grid columnconfigure .alert 0 -weight 1
	grid .alert -in . -row $k -column 0 -sticky ew
	incr k

	# Statistics
	frame .stats
	label .stats.tul -text "Verb / Aktiv / Max:  0 / 0 / 0" -font $font(bold)
	label .stats.apl -text "Durchschnitts-Ping: 0" -font $font(bold)
	label .stats.vote -text "Voting: <unbekannt>" -font $font(bold)
	grid .stats.tul -in .stats -row 0 -column 0 -sticky ew
	grid columnconfigure .stats 0 -weight 1
	grid .stats.apl -in .stats -row 0 -column 1 -sticky ew
	grid columnconfigure .stats 1 -weight 1
	grid .stats.vote -in .stats -row 0 -column 2 -sticky ew
	grid columnconfigure .stats 2 -weight 1
	grid .stats -in . -row $k -column 0 -sticky ew
	incr k

	#frame .map -relief raised -bd 5
	frame .map -relief raised -bd 3
	label .map.t  -text "Map: <unbekannt>"  -font $font(bold)
	label .map.tl -text "Verbleibende Zeit: ??:??" -font $font(bold)
	foreach id "t tl" column "0 1" {
		grid .map.$id -in .map -row 0 -column $column
	}
	grid .map -in . -row $k -column 0 -sticky ew
	incr k

	set table [buildTable]
	grid $table -in . -row $k -column 0 -sticky nsew
	grid rowconfigure . $k -weight 1
	incr k

	# Buttons
	frame .buts
	set t .buts
	button $t.kick -text "User kicken/bannen" -command kickBanUser -font $font(norm)
	button $t.cl -text "Map wechseln" -command {
		popupListBox "Map whlen" \
		15 [getMaps] changeLevel
	} -font $font(norm)
	button $t.tx -text "Text empfangen" -command { toggleText } -font $font(norm)
	button $t.nl -text "nslookup" -command { nsLookup } -font $font(norm)
	button $t.mac -text "Makros" -command { execMacro } -font $font(norm)
	button $t.refresh -text "Aktualisieren" -command { writeClientSock REFRESH } -font $font(norm)
	#admin-mod buttons
	frame .buts2
	set s .buts2
	button $s.slap -text "Slap" -command { slapUser } -font $font(norm)
	button $s.bury -text "Bury" -command { buryUser } -font $font(norm)
	button $s.unbury -text "Un-Bury" -command { unburyUser } -font $font(norm)
	button $s.slay -text "Slay" -command { slayUser } -font $font(norm)

        set i 0
	foreach button "$t.kick $t.cl $t.tx $t.nl $t.mac $t.refresh" {
	    grid $button -in $t -row 0 -column $i -sticky ew
	    grid columnconfigure $t $i -weight 1
	    incr i
	}
	
	grid $t -in . -row $k -column 0 -sticky ew
	incr k

	#admin-mod buttons
	set j 0
	    foreach button "$s.slap $s.bury $s.unbury $s.slay" {
	    grid $button -in $s -row 0 -column $j -sticky ew
	    grid columnconfigure $s $j -weight 1
	    incr j
	}
	
	grid $t -in . -row $k -column 0 -sticky ew
	incr k
	
	#checks wether the admin-mod checkbox is checked or not and when it is adds the admin-mod buttons
	if $adminOpts(adminmod) {
		grid $s -in . -row $k -column 0 -sticky ew
		incr k
	}

	# Command entry
	frame .cmd
	label .cmd.l -text "Server-Kommando: " -width 17 -font $font(bold)
	entry .cmd.e -font $font(norm)
	grid .cmd.l -in .cmd -row 0 -column 0
	grid .cmd.e -in .cmd -row 0 -column 1 -sticky ew
	grid columnconfigure .cmd 1 -weight 1
	grid .cmd -in . -row $k -column 0 -sticky ew
	incr k
	bind .cmd.e <Return> execCmd

	# Say (admin-mod's tsay)
	frame .say
	label .say.l -text "Mitteilen (tsay):    " -width 17 -font $font(bold)
	entry .say.e -font $font(norm)
	grid .say.l -in .say -row 0 -column 0
	grid .say.e -in .say -row 0 -column 1 -sticky ew
	grid columnconfigure .say 1 -weight 1
	if $adminOpts(adminmod) {
		grid .say -in . -row $k -column 0 -sticky ew
		incr k
	}
	bind .say.e <Return> say

	# Say (normal)
	frame .normsay
	label .normsay.l -text "Mitteilen (normal):    " -width 17 -font $font(bold)
	entry .normsay.e -font $font(norm)
	grid .normsay.l -in .normsay -row 0 -column 0
	grid .normsay.e -in .normsay -row 0 -column 1 -sticky ew
	grid columnconfigure .normsay 1 -weight 1
	grid .normsay -in . -row $k -column 0 -sticky ew
	incr k
	bind .normsay.e <Return> normsay

	# Statusbar
	label .statusbar -relief raised -text "[now] Willkommen zu hlgui!" \
		-font $font(bold) -anchor center -bd 3
	grid .statusbar -in . -row $k -column 0 -sticky ew
	incr k


	# Logging area
	frame .info
	text .info.text -height $adminOpts(logheight) -state normal \
		-yscroll ".info.sy set" -font $font(norm)
	scrollbar .info.sy -command ".info.text yview" -width 15
	.info.text configure -background $logbg
	.info.text configure -foreground $logfg
	.info.text configure -state disabled
	grid .info.sy -in .info -row 0 -column 0 -sticky ns
	grid .info.text -in .info -row 0 -column 1 -sticky nsew
	grid columnconfigure .info 1 -weight 1
	grid rowconfigure .info 0 -weight 1
	grid .info -in . -row $k -column 0 -sticky nsew
	grid rowconfigure . $k -weight 1
	incr k

	serverDown

	# Resize foo
	#	wm resizable . 0 1
	#	grid .t  -sticky ns
	#	grid rowconfigure .t 0 -weight 2 -minsize 3
	#	grid rowconfigure . 0 -weight 1 
	#	wm resizable . 0 0

	wm title . $vers

	logText "[now] Willkommen zu hlgui!"
	logText "Bitte Hilfe->Ueber fuer Details zu Lizenzierung und Copyright."

	update idletasks

	if [cequal $argc 4] {
		set authString $argAuth
	} else {
		getAuth
	}

	catch { connectToServer }
}

proc bgerror { error } {
    global errorCode errorInfo font

	popupError "
An error occurred.  If you can reliably reproduce this, please send the
error to linuxhlds@halflife.org, along with a description of the steps
you took to reproduce the issue.  Thanks!

($errorCode) : $errorInfo
"
}

#
# Initialize configurabel options
#
proc initvars {} {
	global expr tagbg tagfg logbg logfg

        set expr(dead) "^\\*DEAD\\*"
        set expr(terrorist) "^\\(Terrorist\\)"
        set expr(counter-terrorist) "^\\(Counter-Terrorist\\)"
        set expr(server) "^<|\\[format %c 0x5b]ADMIN"
        set expr(team) "^\\(TEAM\\)"

        set tagbg(chat) #FFFFFF
        set tagfg(chat) #000000
        set tagbg(dead) #000000
        set tagfg(dead) #DDDDDD
        set tagbg(terrorist) #883333
        set tagfg(terrorist) #FFFFFF
        set tagbg(counter-terrorist) #338833
        set tagfg(counter-terrorist) #FFFFFF
        set tagbg(server) #333388
        set tagfg(server) #DDDDDD                                                                                                             
	set logbg #666666
	set logfg #000000
}

proc checkForExtendedTcl {} {
	if { [string length [info commands cequal]] > 0 } { return }

	puts stderr "The Tk interpeter you are running is NOT an Extended Tk"
	puts stderr "(TkX) interpreter."
	puts stderr "hlgui requires TkX.  Please install TkX and try again."

	exit 1
}

#######################################################################
# set some variables for use in the procs and call MAIN
#
checkForExtendedTcl

set lastMap ""
set font(size) 12
setFont

set svrInfo(name)    ""
set svrInfo(logFile) ""
set svrInfo(reconnect) 0
set svrInfo(kills) 0
set svrInfo(max) 0
set svrInfo(timeleft) 0
set svrInfo(player) 0
set svrInfo(vote) 0

set userInfo(users) ""

set vnum 2.03

set vers "hlgui $vnum"
set notIdle 1

set gettingText 0

initvars

# Close the Tk security hole
if [cequal [info commands send] send] {
	catch { rename send {} }
}
# tk appname hlgui ;# Debug only!

set debugFlag 0

#set dfd [open dbg w]
#cmdtrace on $dfd

main [llength $argv] $argv
