Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/secure/telnetneg.c b/secure/telnetneg.c
new file mode 100644
index 0000000..341e1a0
--- /dev/null
+++ b/secure/telnetneg.c
@@ -0,0 +1,863 @@
+// MorgenGrauen MUDlib
+//
+// telnetneg.c -- Verwaltung von Telnet-Negotiations
+//
+// $Id$
+
+/* Das Original wurde von Marcus@Tapp zur Verfuegung gestellt. */
+/* Angepasst fuer die MG-Mudlib von Ringor@MG */
+/* Weitgehend ueberarbeitet von Zesstra@MG */
+
+#pragma strict_types,save_types
+#pragma range_check
+#pragma no_clone
+#pragma no_shadow
+#pragma pedantic
+
+inherit "/secure/telnetneg-structs.c";
+
+#define NEED_PROTOTYPES
+#include "/secure/telnetneg.h"
+#undef NEED_PROTOTYPES
+
+// unterstuetzte Optionen:
+// TELOPT_EOR, TELOPT_NAWS, TELOPT_LINEMODE, TELOPT_TTYPE
+
+//#define __DEBUG__ 1
+
+#ifdef __DEBUG__
+#define DEBUG(x)        if (interactive(this_object()))\
+          tell_object(this_object(),"TN: " + x + "\n")
+#define DTN(x,y) _debug_print(x,y)
+#else
+# define DEBUG(x)
+# define DTN(x,y)
+#endif
+
+
+
+// Aus mini_props.c:
+public varargs mixed Query( string str, int type );
+public varargs mixed Set( string str, mixed value, int type );
+
+private nosave mapping TN = ([]);
+nosave string *Terminals;
+
+// Prototypen
+private void eval_naws(int *optargs);
+
+#ifdef __DEBUG__
+// Gibts einige Konstanten mit sym. Namen aus.
+private string dtranslate(int i) {
+  switch(i) {
+    case IAC: return "IAC";
+    case DONT: return "DONT";
+    case DO: return "DO";
+    case WONT: return "WONT";
+    case WILL: return "WILL";
+    case SB: return "SB";
+    case SE: return "SE";
+    case EOR: return "EOR";
+    case TELOPT_LINEMODE: return "TELOPT_LINEMODE";
+    case TELOPT_XDISPLOC: return "TELOPT_XDISPLOC";
+    case TELOPT_ENVIRON: return "TELOPT_ENVIRON";
+    case TELOPT_NEWENV: return "TELOPT_NEWENV";
+    case TELOPT_EOR: return "TELOPT_EOR";
+    case TELOPT_NAWS: return "TELOPT_NAWS";
+    case TELOPT_TSPEED: return "TELOPT_TSPEED";
+    case TELOPT_TTYPE: return "TELOPT_TTYPE";
+    case TELOPT_ECHO: return "TELOPT_ECHO";
+    case TELOPT_SGA: return "TELOPT_SGA";
+    case TELOPT_NAMS: return "TELOPT_NAMS";
+    case TELOPT_STATUS: return "TELOPT_STATUS";
+    case TELOPT_TM: return "TELOPT_TM";
+
+    case TELOPT_MSDP: return "TELOPT_MSDP";
+    case TELOPT_COMPRESS2: return "TELOPT_COMPRESS2";
+    case TELOPT_MSP: return "TELOPT_MSP";
+    case TELOPT_MXP: return "TELOPT_MXP";
+    case TELOPT_ATCP: return "TELOPT_ATCP";
+    case TELOPT_GMCP: return "TELOPT_GMCP";
+    case TELOPT_MSSP: return "TELOPT_MSSP";
+  }
+  return to_string(i);
+}
+
+// Gibt <arr> halbwegs lesbar an this_object() aus.
+private void _debug_print(string x, int *arr) {
+  if (arr[1] == SB && arr[<1] != SE)
+    arr += ({IAC, SE});
+  closure map_int = function string (int i)
+    { if (i >= 32 && i <= 126) return sprintf("%c",i);
+      return "["+to_string(i)+"]";
+    };
+  if (sizeof(arr)<=5) {
+    foreach(int c : arr)
+      x += " " + dtranslate(c);
+  }
+  else {
+      x += dtranslate(arr[0]) + " " + dtranslate(arr[1]) + " "
+           + dtranslate(arr[2]) + " "
+           + implode(map(arr[3..<3], map_int)," ")
+           + " " + dtranslate(arr[<2]) + " " + dtranslate(arr[<1]);
+  }
+  DEBUG(x);
+}
+#endif
+
+protected varargs int send_telnet_neg(int *arr, int bm_flags)
+{
+    if ( sizeof(arr) < 2 )
+        return efun::binary_message(arr,bm_flags);
+
+    struct telopt_s opt = TN[arr[1]];
+
+    switch (arr[0]){
+    case DO:
+    case DONT:
+        (opt->lo_wishes)->remoteside = arr[0];
+        arr = ({IAC}) + arr;
+        break;
+    case WILL:
+    case WONT:
+        (opt->lo_wishes)->localside = arr[0];
+        arr = ({IAC}) + arr;
+        break;
+    case SB:
+        (opt->lo_wishes)->sbdata = arr[0..];
+        arr = ({IAC}) + arr + ({IAC, SE});
+        break;
+    default:
+        break;
+    }
+    DTN("send_tn: ",arr);
+    return efun::binary_message(arr, bm_flags);
+}
+
+protected varargs int send_telnet_neg_str(string str, int bm_flags) {
+#ifdef __DEBUG__
+    // Debugausgaben zur Zeit nur fuer arraybasierte Variante
+    return send_telnet_neg(to_array(str), bm_flags);
+#else
+    if ( sizeof(str) < 2 )
+        return efun::binary_message(str, bm_flags);
+
+    struct telopt_s opt = TN[str[1]];
+
+    switch (str[0]) {
+    case DO:
+    case DONT:
+        (opt->lo_wishes)->remoteside = str[0];
+        str=sprintf("%c%s",IAC,str);
+        break;
+    case WILL:
+    case WONT:
+        (opt->lo_wishes)->localside = str[0];
+        str=sprintf("%c%s",IAC,str);
+        break;
+    case SB:
+        (opt->lo_wishes)->sbdata = map(explode(str[0..],""),#'to_int);
+        str=sprintf("%c%s%c%c", IAC, str, IAC, SE);
+        break;
+    default:
+        break;
+    }
+
+    return efun::binary_message(str, bm_flags);
+#endif // __DEBUG__
+}
+
+// Startet eine Verhandlung, um den Status einer Option zu aendern.
+// Wenn bereits eine Verhandlung laeuft, wird nichts gemacht und -1
+// zurueckgeben.
+// Wenn die Verhandlung keine Aenderung vom Status quo zum Ziel hat, wird
+// nichts gemacht und -2 zurueckgegeben.
+// Ansonsten ist die Rueckgabe die Anzahl der uebermittelten Zeichen.
+// <action>: WILL: Option soll auf dieser Seite eingeschaltet werden.
+//           WONT: Option soll auf dieser Seite ausgeschaltet werden.
+//           DO  : Option soll auf der anderen Seite eingeschaltet werden.
+//           DONT: Option soll auf der anderen Seite ausgeschaltet werden.
+protected int do_telnet_neg(int option, int action) {
+  struct telopt_s opt = TN[option];
+  if (!structp(opt))
+  {
+    opt = (<telopt_s> option: option,
+                      re_wishes: (<to_state_s>),
+                      lo_wishes: (<to_state_s>),
+                      state: (<to_state_s>)
+          );
+    TN[option] = opt;
+  }
+  // es wird nur geprueft, ob wir bereits eine Verhandlung begonnen haben
+  // (lo_wishes), weil reinkommende remote Wuensche letztendlich sofort durch
+  // unsere Antwort erledigt sind.
+  switch(action)
+  {
+    case WILL:
+      if (opt->lo_wishes->localside != 0)
+        return -1;
+      if (opt->state->localside)
+        return -2;
+      return send_telnet_neg( ({ WILL, option }) );
+      break;
+    case WONT:
+      if (opt->lo_wishes->localside != 0)
+        return -1;
+      if (!opt->state->localside)
+        return -2;
+      return send_telnet_neg( ({ WONT, option }) );
+      break;
+    case DO:
+      if (opt->lo_wishes->remoteside != 0)
+        return -1;
+      if (opt->state->remoteside)
+        return -2;
+      return send_telnet_neg( ({ DO, option }) );
+      break;
+    case DONT:
+      if (opt->lo_wishes->remoteside != 0)
+        return -1;
+      if (!opt->state->remoteside)
+        return -2;
+      return send_telnet_neg( ({ DONT, option }) );
+      break;
+  }
+  raise_error(sprintf("Unsupported telnet negotation action in "
+      "do_telnet_neg(): %d\n",action));
+}
+
+// LOCAL Standard Handlers //
+private void _std_lo_handler_eor(struct telopt_s opt, int action) {
+  // tatsaechlich nix zu tun. Handler ist nur da, damit die Option auf dieser
+  // Seite aktiviert wird. Die Arbeit erledigt print_prompt.
+  return;
+}
+
+private void _std_lo_handler_mssp(struct telopt_s opt, int action) {
+  // nur einschalten ist interessant.
+  if (action != LOCALON)
+    return;
+  // Krams senden, wenn Objekt geladen. Sonst wieder abschalten (kommt
+  // hoffentlich nicht vor)...
+  object mssp = find_object("/secure/misc/mssp");
+  if (!mssp)
+    send_telnet_neg( ({WONT, TELOPT_MSSP }) );
+  else
+  {
+    send_telnet_neg_str(sprintf("%c%c%s",
+          SB, TELOPT_MSSP, mssp->get_telnegs_str()));
+    // die Daten brauchen wir nicht mehr
+    opt->lo_wishes->sbdata = 0;
+  }
+}
+
+
+// REMOTE Standard Handlers //
+private void _std_re_handler_tm(struct telopt_s opt, int action,
+                                int *data)
+{
+  // egal, was geantwortet wurde, es gibt nen Hinweis auf die round-trip-time.
+  // Wenn ein Array in opt->data[1] steht, rechnen wir das aus und schreiben es
+  // in opt->data[0] als Ergebnis rein.
+  if (pointerp(opt->data) && pointerp(opt->data[1]))
+  {
+    int *ut = utime();
+    int *start = opt->data[1];
+    int res = (ut[0] - start[0]) * 1000000;
+    res += ut[1] - start[1];
+    opt->data[0] = res;
+    opt->data[1] = 0;
+    DEBUG("RTT: "+res);
+  }
+  return;
+}
+
+private void _std_re_handler_naws(struct telopt_s opt, int action,
+                                  int *data)
+{
+  if (action == SB)
+  {
+    eval_naws(data);
+  }
+}
+
+private void _std_re_handler_linemode(struct telopt_s opt, int action,
+                                      int *data)
+{
+  if (action == REMOTEON)
+  {
+    // see /doc/concepts/negotiations. We use only the minimum
+    // needed for linemode: switching on local commandline-editing
+    // for the client.
+    send_telnet_neg(({ SB, TELOPT_LINEMODE, LM_MODE, MODE_EDIT }));
+    // flush on 0d and 0a...
+    // TODO: what does this exactly do?
+    send_telnet_neg(({ SB, TELOPT_LINEMODE, DO, LM_FORWARDMASK, 0,
+                          0x40|0x08 }));
+    //Gna...
+    opt->lo_wishes->sbdata = ({MODE_EDIT});
+  }
+}
+
+private void _std_re_handler_ttype(struct telopt_s opt, int action,
+                                   int *data)
+{
+  if (action == SB)
+  {
+    //TODO: get rid of this hysterical stuff...
+    //NOTE: We do not do multiple SB SENDs due to some weird
+    //bugs in IBM3270 emulating telnets which crash if we
+    //do that.
+    if ( sizeof(data) < 1 )
+        return;
+
+    if ( data[0] != TELQUAL_IS )
+        return;
+
+    string tmpterminal = lower_case( to_string(data[1..]) );
+    if ( !Terminals )
+        Terminals = ({ tmpterminal });
+    else
+        Terminals += ({ tmpterminal });
+
+    if ( Query(P_TTY_TYPE) )
+          Set( P_TTY_TYPE, Terminals[0] );
+  }
+  else if (action == REMOTEON)
+  {
+    send_telnet_neg(({ SB, TELOPT_TTYPE, TELQUAL_SEND }));
+  }
+}
+
+// Bindet/registriert Handler fuer die jew. Telnet Option. (Oder loescht sie
+// auch wieder.) Je nach <initneg> wird versucht, die Option neu zu
+// verhandeln.
+protected int bind_telneg_handler(int option, closure re, closure lo,
+                                  int initneg)
+{
+  struct telopt_s opt = TN[option];
+  if (!structp(opt))
+  {
+    opt = (<telopt_s> option: option,
+                      re_wishes: (<to_state_s>),
+                      lo_wishes: (<to_state_s>),
+                      state: (<to_state_s>)
+          );
+    TN[option] = opt;
+  }
+
+  opt->remotehandler = re;
+  if (initneg)
+  {
+    if (re)
+      do_telnet_neg(option, DO);
+    else
+      do_telnet_neg(option, DONT );
+  }
+
+  opt->localhandler = lo;
+  if (initneg)
+  {
+    if (lo)
+      do_telnet_neg(option, WILL);
+    else
+      do_telnet_neg(option, WONT);
+  }
+  return 1;
+}
+
+
+// Mal unsere Wuensche an den Client schicken und die Standardhandler
+// registrieren. Hierbei bei Bedarf neue Verhandlungen starten.
+// Gerufen aus login.c nach Verbindungsaufbau.
+// Bemerkung: das Spielerobjekt bietet evt. noch zusaetzliche Telnetoptionen
+//            an, die dann ueber startup_telnet_negs() (im Spielerobjekt)
+//            laufen.
+protected void SendTelopts()
+{
+  bind_telneg_handler(TELOPT_EOR, 0, #'_std_lo_handler_eor, 1);
+  if (find_object("/secure/misc/mssp"))
+    bind_telneg_handler(TELOPT_MSSP, 0, #'_std_lo_handler_mssp, 1);
+
+  bind_telneg_handler(TELOPT_NAWS, #'_std_re_handler_naws, 0, 1);
+  bind_telneg_handler(TELOPT_LINEMODE, #'_std_re_handler_linemode, 0, 1);
+  bind_telneg_handler(TELOPT_TTYPE, #'_std_re_handler_ttype, 0, 1);
+  // fuer TELOPT_TM jetzt keine Verhandlung anstossen.
+  bind_telneg_handler(TELOPT_TM, #'_std_re_handler_tm, 0, 0);
+}
+
+
+// Bindet die Standardhandler _aus diesem_ Programm (und ueberschreibt dabei
+// ggf. andere). Hierbei werden nur die Handler neu gebunden, keine neuen
+// Verhandlungen initiiert.
+// gerufen aus base.c indirekt via startup_telnet_negs().
+protected void _bind_telneg_std_handlers() {
+  bind_telneg_handler(TELOPT_EOR, 0, #'_std_lo_handler_eor, 0);
+  // Besondere Situation: MSSP ist nach Spielerlogin eigentlich uninteressant.
+  // Daher sparen wir uns das im Kontext des Spielerobjekts und schalten es
+  // einfach wieder aus.
+  bind_telneg_handler(TELOPT_MSSP, 0, 0, 0);
+
+  bind_telneg_handler(TELOPT_NAWS, #'_std_re_handler_naws, 0, 0);
+  bind_telneg_handler(TELOPT_LINEMODE, #'_std_re_handler_linemode, 0, 0);
+  bind_telneg_handler(TELOPT_TTYPE, #'_std_re_handler_ttype, 0, 0);
+  bind_telneg_handler(TELOPT_TM, #'_std_re_handler_tm, 0, 0);
+}
+
+
+// Ruft die entsprechenden handler von der Telnet Option.
+// Wenn es keinen handler (mehr) gibt, wird die Option auch auf der jeweiligen
+// Seite ausgeschaltet. Deshalb MUSS lo_wishes und re_wishes vom Aufrufer VOR
+// DEM AUFRUF zurueckgesetzt worden sein!
+// <action>: 'LOCALON':   Option wurde auf unserer Seite eingeschaltet
+//           'LOCALOFF':  Option wurde auf unserer Seite ausgeschaltet
+//           'REMOTEON':  Option wurde auf Clientseite eingeschaltet
+//           'REMOTEOFF': Option wurde auf Clientseite ausgeschaltet
+//           'SB':        Suboption negotiation Daten wurden empfangen
+// <data>: die per SB empfangenen Daten (unverarbeitet)
+private void _call_handler(struct telopt_s opt, int action, int *data) {
+  switch(action)
+  {
+    case REMOTEON:
+    case REMOTEOFF:
+    case SB:
+      if (opt->remotehandler)
+      {
+        funcall(opt->remotehandler, opt, action, data);
+      }
+      else
+      {
+        // ok, geht nicht. Ggf. Abschalten (do_telnet_neg passt auf,
+        // dass nur verhandelt wird, wenn die Option an ist.)
+        do_telnet_neg( opt->option, DONT );
+      }
+      break;
+    case LOCALON:
+    case LOCALOFF:
+      if (opt->localhandler)
+      {
+        funcall(opt->localhandler, opt, action);
+      }
+      else
+      {
+      // ok, geht nicht. Ggf. Abschalten (do_telnet_neg passt auf,
+      // dass nur verhandelt wird, wenn die Option an ist.)
+        do_telnet_neg( opt->option, WONT );
+      }
+      break;
+  }
+}
+
+// Gerufen vom Driver, wenn neue telnet options reinkommen.
+void
+telnet_neg(int command, int option, int *optargs)
+{
+    DTN("recv_tn: ", ({IAC, command, option}) + (optargs||({})));
+
+    struct telopt_s opt = TN[option];
+    if (!structp(opt))
+    {
+      opt = (<telopt_s> option: option,
+                        re_wishes: (<to_state_s>),
+                        lo_wishes: (<to_state_s>),
+                        state: (<to_state_s>)
+            );
+      TN[option] = opt;
+    }
+
+    // Was will der Client tun?
+    if (command == WONT)
+    {
+        // Client will die Option auf seiner Seite abschalten. Wir MUESSEN das
+        // akzeptieren.
+        // Wir muessen das allerdings ignorieren, wenn die Option bereits aus
+        // ist.
+        if (opt->state->remoteside==0)
+        {
+          // Ausnahme fuer TELOPT_TM, da das kaum ein Client kann und fuer RTT
+          // es eigentlich auch egal ist, was zurueck kommt: der handler wird
+          // zumindest doch gerufen zum Ausrechnen der RTT
+          if (option == TELOPT_TM)
+            _call_handler(opt, REMOTEOFF, 0);
+          // ansonsten aber wirklich ignorieren. ;)
+          return;
+        }
+        opt->re_wishes->remoteside = command;
+        // Bestaetigung auf ein WONT senden, wenn wir nicht selber schon ein
+        // DONT geschickt hatten.
+        if (opt->lo_wishes->remoteside != DONT) {
+          send_telnet_neg( ({DONT, option}) );
+        }
+        // Wir haben jetzt auf jeden Fall ein DONT gesendet und ein WONT
+        // erhalten. Damit ist die Option jetzt auf der clientseite aus.
+        // Ausserdem setzen wir die Wishes zurueck.
+        opt->re_wishes->remoteside = 0;
+        opt->lo_wishes->remoteside = 0;
+        if (opt->state->remoteside != 0)
+        {
+            opt->state->remoteside = 0;
+            _call_handler(opt, REMOTEOFF, 0);
+        }
+    } // WONT vom Client verarbeitet
+    else if ( command == WILL)
+    {
+        // Wenn die Option bereits an ist, muessen wir dies ignorieren.
+        if (opt->state->remoteside == 1)
+        {
+          // Ausnahme fuer TELOPT_TM, der handler wird zumindest doch gerufen
+          // zum Ausrechnen der RTT. Diese Option laesst sich ohnehin
+          // aktivieren, auch wenn sie schon an ist.
+          if (option == TELOPT_TM)
+            _call_handler(opt, REMOTEON, 0);
+          // sonst aber wirklich ignorieren. ;-)
+          return;
+        }
+        opt->re_wishes->remoteside = command;
+        if ( opt->lo_wishes->remoteside == 0 )
+        {
+            // Der Client will, wir haben noch nix dazu gesagt. (Mit unserer
+            // Antwort ist die Verhandlung uebrigens beendet.)
+            // Wenn es einen remotehandler fuer die Option gibt, schalten wir
+            // sie ein...
+            if (opt->remotehandler)
+            {
+                send_telnet_neg(({DO, option}));
+                // Option jetzt an der Clientseite an.
+                opt->re_wishes->remoteside = 0;
+                opt->lo_wishes->remoteside = 0;
+                if (opt->state->remoteside != 1)
+                {
+                    opt->state->remoteside = 1;
+                    _call_handler(opt, REMOTEON, 0);
+                }
+            }
+            else
+            {
+              // sonst verweigern wir das einschalten (die meisten Optionen
+              // auf Clientseite sind fuer uns eh egal).
+              send_telnet_neg(({DONT, option}));
+              // Option jetzt an der Clientseite aus.
+              opt->re_wishes->remoteside = 0;
+              opt->lo_wishes->remoteside = 0;
+              if (opt->state->remoteside != 0)
+              {
+                  opt->state->remoteside = 0;
+                  _call_handler(opt, REMOTEOFF, 0);
+              }
+            }
+        }
+        else if ( opt->lo_wishes->remoteside == DO)
+        {
+            // Wir haben haben bereits per DO angefordert, d.h. das ist die
+            // Clientbestaetigung - wir duerfen nicht bestaetigen und die
+            // Option ist jetzt clientseitig aktiv. Verhandlung beendet.
+            opt->re_wishes->remoteside = 0;
+            opt->lo_wishes->remoteside = 0;
+            if (opt->state->remoteside != 1)
+            {
+                opt->state->remoteside = 1;
+                _call_handler(opt, REMOTEON, 0);
+            }
+        } // if (DO)
+        else {
+          // Mhmm. Wir hatten ein DONT gesendet, aber der Client hat mit WILL
+          // geantwortet. Das darf er eigentlich gar nicht.
+          //TODO: was sollte man jetzt eigentlich tun? Erstmal wiederholen wir
+          //das DONT...
+          send_telnet_neg( ({DONT, option}) );
+        }
+
+        return;
+    } // WILL vom Client verarbeitet
+    // Was sollen wir (nicht) fuer den Client tun?
+    else if ( command == DONT)
+    {
+        // Client will, dass wir etwas nicht tun. Wir MUESSEN das akzeptieren.
+        // wenn die Option auf unserer Seite aber schon aus ist, muessen wir
+        // dies ignorieren.
+        if (opt->state->localside == 0)
+          return;
+
+        opt->re_wishes->localside = command;
+        // Wenn wir noch kein WONT gesendet haben, senden wir das jetzt als
+        // Bestaetigung.
+        if (opt->lo_wishes->localside = WONT)
+            send_telnet_neg( ({WONT, option}) );
+        // Verhandlung beendet, Option is auf unserer Seite jetzt aus.
+        // Wuensche auch wieder zuruecksetzen.
+        opt->re_wishes->localside = 0;
+        opt->lo_wishes->localside = 0;
+        if (opt->state->localside != 0)
+        {
+          opt->state->localside = 0;
+          _call_handler(opt, LOCALOFF, 0);
+        }
+    }
+    else if ( command == DO )
+    {
+        // Client will, dass wir option tun. Mal schauen, wie wir dazu stehen.
+        // wenn die Option auf unserer Seite aber schon an ist, muessen wir
+        // dies ignorieren.
+        if (opt->state->localside == 1)
+          return;
+
+        opt->re_wishes->localside = command;
+
+        if ( opt->lo_wishes->localside == 0 ) {
+            // wir haben unsere Wuensche noch nicht geaeussert. Sobald wir
+            // bestaetigen, ist die Option auf unserer Seite an/aus und die
+            // Verhandlungen beendet.
+            // in jedem Fall die Wuensche zuruecksetzen
+            opt->re_wishes->localside = 0;
+            opt->lo_wishes->localside = 0;
+            if (opt->localhandler)
+            {
+                send_telnet_neg(({WILL, option}));
+                opt->state->localside = 1;
+                _call_handler(opt, LOCALON, 0);
+            }
+            else
+            {
+                send_telnet_neg(({WONT, option}));
+                opt->state->localside = 0;
+                _call_handler(opt, LOCALOFF, 0);
+            }
+        }
+        else if (opt->lo_wishes->localside == WILL ) {
+            // wir haben schon WILL gesendet, welches der Client jetzt
+            // bestaetigt hat (d.h. die Option ist jetzt auf dieser Seite an),
+            // wir bestaetigen das aber nicht (nochmal).
+            opt->re_wishes->localside = 0;
+            opt->lo_wishes->localside = 0;
+            if (opt->state->localside != 1)
+            {
+              opt->state->localside = 1;
+              _call_handler(opt, LOCALON, 0);
+            }
+        }
+        else {
+            // Mhmm. Wir haben ein WONT gesendet, der Client hat mit DO
+            // geantwortet. Das darf er eigentlich nicht.
+            // TODO: Was tun?
+            send_telnet_neg ( ({WONT, option}) );
+        }
+        // fertig mit DO
+        return;
+    }
+    // bleibt noch SB ueber
+    else if ( command == SB )
+    {
+        opt->re_wishes->sbdata = optargs;
+        _call_handler(opt, SB, optargs);
+        return;
+    } // if ( command == SB )
+}
+
+// wird nur in base.c gerufen, wenn die Verbindung an das Spielerobjekt
+// uebergeben wurde.
+// es uebertraegt unter anderem den Telnet Option Zustand aus login.c (das ist
+// dann previous_object()) in das Spielerobjekt (welches dann this_object())
+// ist!
+protected void
+startup_telnet_negs()
+{
+  int* optargs;
+
+  Set( P_TTY_TYPE, 0 );  //avoid ANY mistakes... Wird unten neu gesetzt.
+  // Daten aus dem Loginobjekt uebertragen. Das ist wichtig! (Dabei wird dann
+  // auch der Status von der letzten Session ueberschrieben.)
+  TN = (mapping) previous_object()->query_telnet_neg();
+  // bevor irgendwas anderes gemacht wird, werden erstmal die Standardhandler
+  // gesetzt. Die sind naemlich in diesem Objekt jetzt erstmal kaputt, weil
+  // sie im Loginobjekt gerufen werden.
+  _bind_telneg_std_handlers();
+  // dann restliche Daten aus dem Loginobjekt holen.
+  Terminals = (string *) previous_object()->query_terminals();
+  Set( P_TTY_COLS, previous_object()->Query(P_TTY_COLS) );
+  Set( P_TTY_ROWS, previous_object()->Query(P_TTY_ROWS) );
+
+  struct telopt_s opt = TN[TELOPT_NAWS];
+  if (optargs = (opt->re_wishes)->sbdata) {
+      eval_naws(optargs);
+  }
+
+  if ( pointerp(Terminals) && sizeof(Terminals)) {
+      if ( Terminals[0][0..3] == "dec-" )
+          Terminals[0] = Terminals[0][4..];
+
+      if ( Terminals[0] == "linux" )
+          Terminals[0] = "vt100";
+
+      Set( P_TTY_TYPE, Terminals[0] );
+  }
+}
+
+// somehow completely out of the ordinary options processing/negotiation. But
+// the only purpose is to transmit something over the wire which is not shown,
+// but (likely) answered by the other device.
+protected void send_telnet_timing_mark() {
+  struct telopt_s opt = TN[TELOPT_TM];
+  if (pointerp(opt->data))
+    opt->data[1] = utime();
+  else
+    opt->data = ({ 0, utime() });
+  // absichtlich nicht do_telnet_ne() verwendet, da dies nicht senden wuerde,
+  // haette der Client schonmal mit WILL geantwortet. TELOPT_TM ist aber eine
+  // Option, bei der man das darf...
+  send_telnet_neg( ({DO, TELOPT_TM}) );
+}
+
+/* Is called from the H_PRINT_PROMPT driver hook and appends the IAC EOR if
+ * the client supports it.
+ */
+void print_prompt(string prompt) {
+//    if (extern_call() && previous_object()!=this_object())
+//        return;
+
+    // ggf. Uhrzeit in den prompt reinschreiben.
+    prompt = regreplace(prompt,"\\t",strftime("%H:%M"),0);
+    // Prompt senden
+    tell_object(this_object(), prompt);
+    // Und EOR senden, falls vom Client gewuenscht.
+    struct telopt_s opt = TN[TELOPT_EOR];
+    if (opt->state->localside == 1)
+    {
+        binary_message(({IAC, EOR}), 1);
+        DTN("tn_eor ",({IAC,EOR}));
+    }
+}
+
+// Helper
+private void eval_naws(int *optargs) {
+  int l, c;
+
+  if ( sizeof(optargs) != 4 )
+  {
+      tell_object(this_object(),
+          break_string( sprintf("Dein Client hat einen Fehler beim"
+                            +"Aushandeln der TELOPT_NAWS - er hat"
+                            +"IAC SB %O IAC SE gesendet!\n",
+                            optargs), 78,
+                    "Der GameDriver teilt Dir mit: " ));
+      // und dem Client sagen, dass er den Schrott nicht mehr uebertragen
+      // soll (falls wir das nicht schon gemacht haben).
+      struct telopt_s opt = TN[TELOPT_NAWS];
+      if (opt->state->remoteside == WILL
+          && opt->lo_wishes->remoteside != DONT)
+        send_telnet_neg(( {DONT, TELOPT_NAWS}) );
+      return;
+  }
+
+  if ( interactive(this_object()) ){
+      if ( !optargs[1] )
+          c = optargs[0];
+      else
+          c = optargs[1] + optargs[0] * 256;
+
+      if ( c < 35 ){
+          if (Query(P_TTY_SHOW))
+              tell_object( this_object(),
+                       break_string("Dein Fenster ist schmaler als"
+                                    +" 35 Zeichen? Du scherzt. ;-)"
+                                    +" Ich benutze den Standardwert"
+                                    +" von 80 Zeichen.\n", 78,
+                                    "Der GameDriver teilt Dir mit: ")
+                       );
+          c = 80;
+      }
+
+      if ( !optargs[3] )
+          l = optargs[2];
+      else
+          l = 256 * optargs[2] + optargs[3];
+
+      if ( l > 100 ){
+          //TODO: remove
+          l = 100;
+          if (Query(P_TTY_SHOW))
+              tell_object( this_object(),
+                       break_string("Tut mir leid, aber ich kann"
+                                    +" nur bis zu 100 Zeilen"
+                                    +" verwalten.\n", (c ? c-2 : 78),
+                                    "Der GameDriver teilt Dir mit: " )
+                       );
+      }
+
+      if ( l < 3 ){
+          if (Query(P_TTY_SHOW))
+              tell_object( this_object(),
+                       break_string("Du willst weniger als drei"
+                                    +" Zeilen benutzen? Glaub ich"
+                                    +" Dir nicht - ich benutze den"
+                                    +" Standardwert von 24"
+                                    +" Zeilen.\n", (c ? c-2 : 78),
+                                    "Der GameDriver teilt Dir mit: " )
+                       );
+          l = 24;
+      }
+
+      if ( ((int) Query(P_TTY_ROWS) != l) ||
+           ((int) Query(P_TTY_COLS) != c) ){
+          Set( P_TTY_ROWS, l );
+          Set( P_TTY_COLS, c );
+
+          if (Query(P_TTY_SHOW))
+              tell_object( this_object(),
+                       break_string("Du hast Deine Fenstergroesse auf"
+                                    +" "+l+" Zeilen und "+c+
+                                    " Spalten geaendert.\n", c-2,
+                                    "Der GameDriver teilt Dir mit: ")
+                       );
+      }
+  }
+}
+
+private void _call_old_SendTelOpts(object po) {
+  if (!objectp(po) || !interactive(po)) return;
+/*
+  closure cl=unbound_lambda( ({}),
+               ({ #'funcall, ({#'symbol_function, "SendTelopts"}) }) );
+
+  funcall(bind_lambda(cl, po));
+*/  
+  // Bloody temporary Hack until next reboot...
+
+  funcall( bind_lambda( #'efun::binary_message, po ),
+           ({ IAC, WILL, TELOPT_EOR,
+              IAC, DO, TELOPT_TTYPE,
+              IAC, DO, TELOPT_NAWS,
+              IAC, DO, TELOPT_LINEMODE,
+           }), 0x1 );
+}
+
+// Query-/Set-Methoden
+// Und wenn hier einer von aussen dran rumpfuscht, werde ich sauer.
+mapping
+query_telnet_neg()
+{
+   if (interactive(previous_object())
+      && program_time(previous_object()) < 1359926079
+      && load_name(this_object()) == "/secure/login" )
+    {
+      call_out(#'_call_old_SendTelOpts, 0, previous_object());
+      // alte Datenstruktur zurueckgeben... Leider leer...
+      return (["sent": m_allocate(3,3), "received": m_allocate(3,3) ]);
+    }
+
+    return TN;
+}
+
+// siehe oben
+string *
+query_terminals() {
+    return Terminals;
+}
+
+public int _query_p_lib_telnet_rttime()
+{
+  struct telopt_s opt = TN[TELOPT_TM];
+  if (opt && pointerp(opt->data))
+    return (opt->data)[0];
+  return 0;
+}
+