Merge branch 'master' of ssh://mgg/mudlib-public
diff --git a/doc/pcmd/telnet b/doc/pcmd/telnet
index 029317f..489708f 100644
--- a/doc/pcmd/telnet
+++ b/doc/pcmd/telnet
@@ -32,6 +32,7 @@
 
  SIEHE AUCH:
     telnegs, telnet keepalive, telnet gmcp
+    P_TELNET_KEEPALIVE_DELAY
 
  LETZTE AeNDERUNG:
-    15.01.2018, Zesstra
+    26.07.2019, Zesstra
diff --git a/doc/pcmd/telnet_keepalive b/doc/pcmd/telnet_keepalive
index eecbfd7..770ceba 100644
--- a/doc/pcmd/telnet_keepalive
+++ b/doc/pcmd/telnet_keepalive
@@ -19,11 +19,11 @@
     Verbindung terminiert wird. Daher besitzen die Spielershells ein
     einschaltbares 'Telnet-Keep-Alive'.
 
-    Diese Funktion schickt alle 4 min Daten an eure Clients, die diese
-    nicht anzeigen, aber ihrerseits beantworten/bestaetigen (sofern der Client
-    dies unterstuetzt). So gibt es in der Verbindung zum Mud min. alle 4 min
-    Datenverkehr. Das sollte Verbindungsabbruechen durch Inaktivitaet
-    vorbeugen.
+    Diese Funktion schickt regelmaessig (Standardeinstellung: alle 4 min)
+    Daten an eure Clients, die diese nicht anzeigen, aber ihrerseits
+    beantworten/bestaetigen (sofern der Client dies unterstuetzt). So gibt
+    es in der Verbindung zum Mud regelmaessig Datenverkehr. Das sollte
+    Verbindungsabbruechen durch Inaktivitaet vorbeugen.
 
     Bitte schaltet diese Funktion aber nur ein, wenn ihr sie braucht, d.h.
     ohne sie Probleme mit Verbindungsabbruechen beim Ideln habt.
@@ -32,11 +32,9 @@
 
     Ohne Argumente wird der aktuelle Zustand angezeigt.
 
-    Hinweis fuer Magier: Magier im Magiermodus (mschau ein) kommen leider
-    nicht in den Genuss dieses Features, weil sie keinen Heartbeat haben.
-
  SIEHE AUCH:
-    telnegs, telnet gmcp
+    telnegs, telnet gmcp,
+    P_TELNET_KEEPALIVE_DELAY
 
  LETZTE AeNDERUNG:
-    08.12.2015, Zesstra
+    26.07.2019, Zesstra
diff --git a/doc/sphinx/props/P_TELNET_KEEPALIVE_DELAY.rst b/doc/sphinx/props/P_TELNET_KEEPALIVE_DELAY.rst
new file mode 100644
index 0000000..d50b4cb
--- /dev/null
+++ b/doc/sphinx/props/P_TELNET_KEEPALIVE_DELAY.rst
@@ -0,0 +1,39 @@
+P_TELNET_KEEPALIVE_DELAY
+========================
+
+NAME
+----
+
+     P_TELNET_KEEPALIVE_DELAY "p_lib_telnet_alive_delay"
+
+DEFINIERT IN
+------------
+
+     <player/telnetneg.h>
+
+BESCHREIBUNG
+------------
+
+     In dieser Property kann der zeitliche Abstand zwischen zwei Aussendungen
+     der "Telnet Timing Mark", welche fuer das Telnet keep-alive benutzt wird,
+     bestimmt werden. Die Angabe ist in Heartbeats.
+     Eine 0 fuehrt zu einer Standardverzoegerung (zur Zeit 240 s).
+
+     Wenn diese Property in einem Magier (oder Spieler) gesetzt wird, sollte
+     experimentell ermittelt werden, welcher Wert sinnvoll ist. Dies kann z.B.
+     dadurch erfolgen, dass von 120 (Heartbeats) eine stufenweise Reduktion
+     erfolgt, bis kein Disconnect mehr erfolgt. Helfen sehr niedrige Werte
+     nicht, sollte die Verzoegerung wieder erhoeht werden bzw. das Keepalive
+     ganz abgeschaltet werden.
+
+BEMERKUNGEN
+-----------
+
+     Die Property sollte nicht auf weniger als 30 gesetzt werden.
+
+SIEHE AUCH
+----------
+
+     :doc:`../pcmd/telnet`
+
+25.07.2019, Zesstra
diff --git a/std/player/base.c b/std/player/base.c
index e83930e..56102b1 100644
--- a/std/player/base.c
+++ b/std/player/base.c
@@ -73,6 +73,7 @@
 #include "/secure/questmaster.h"
 #include "/secure/lepmaster.h"
 #include <events.h>
+#include <player/telnetneg.h>
 
 #undef NAME /* DEFINED BY UDP.H; BAD NAME CLASH :( */
 #define NAME(who) capitalize(getuid(who))
@@ -84,9 +85,6 @@
 private nosave string  *autoload_error;
 private nosave string realip; 
 
-private nosave string passw;        /* temporarily for password change */
-private nosave string passwold;     /* temporarily for password change */
-
 // HB-Zaehler. Wenn 0 erreicht wird, wird  ein Telnet TM Paket als Keep-Alive
 // an den Client gesendet und der Counter wieder auf hochgesetzt. 
 // Wenn == 0, ist das Keep-Alive abgeschaltet.
@@ -742,7 +740,7 @@
   * @return 1, falls der Spieler Keep-Alive Paket wuenscht, sonst 0. 
   * @see heart_beat()
 */
-protected int CheckTelnetKeepAlive() {
+protected int CheckTelnetKeepAlive(int delay) {
   if (telnet_tm_counter > 0) {
     // Spieler hat offenbar ein Keep-Alive konfiguriert ...
     if (!(--telnet_tm_counter)) {
@@ -753,7 +751,7 @@
       // alle 120 HBs (240s, 4min).
       // sollte eigentlich 240 / __HEART_BEAT_INTERVAL__ sein. Aber spart
       // eine Operation im HB. ;-)
-      telnet_tm_counter = 120;
+      telnet_tm_counter = delay || 120;
     }
     return 1; // Keep-Alive ist eingeschaltet
   }
@@ -809,7 +807,7 @@
   if (CheckDailyPlaytime())
     return;
 
-  CheckTelnetKeepAlive();
+  CheckTelnetKeepAlive(QueryProp(P_TELNET_KEEPALIVE_DELAY));
 
   life::heart_beat();
   combat::heart_beat();
@@ -1203,9 +1201,8 @@
     write("Falsches Passwort!\n");
     return 1;
   }
-  passwold = str;
   input_to("change_password3",INPUT_NOECHO|INPUT_PROMPT,
-      "Bitte das NEUE Passwort eingeben: ");
+      "Bitte das NEUE Passwort eingeben: ", str);
   return 1;
 }
 
@@ -1216,32 +1213,32 @@
   * \return 1 bei Erfolg, 0 sonst.
   * \sa change_password(), change_password2(), change_password4()
   */
-static int change_password3( string str )
+static int change_password3( string str, string passwold )
 {
     write( "\n" );
 
     if ( !str || str == "" ){
         write( "Abgebrochen !\n" );
-        passwold = passw = 0;
         return 1;
     }
 
     if ( passwold == str ){
         write( "Das war Dein altes Passwort.\n" );
         input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
-            "Bitte das NEUE Passwort eingeben (zum Abbruch Return druecken): ");
+            "Bitte das NEUE Passwort eingeben (zum Abbruch Return "
+            "druecken): ", passwold);
         return 1;
     }
 
     if ( !MASTER->good_password( str, getuid(ME) ) ){
         input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
-            "Bitte das NEUE Passwort eingeben: ");
+            "Bitte das NEUE Passwort eingeben: ", passwold);
         return 1;
     }
 
     passw = str;
     input_to( "change_password4", INPUT_NOECHO|INPUT_PROMPT,
-        "Bitte nochmal: ");
+        "Bitte nochmal: ", passwold, str);
     return 1;
 }
 
@@ -1251,22 +1248,20 @@
   * \return 1 bei Erfolg, 0 sonst.
   * \sa change_password(), change_password2(), change_password3()
   */
-static int change_password4( string str )
+static int change_password4( string str, string passwold, string passwnew )
 {
     write( "\n" );
 
-    if ( !str || str != passw ){
+    if ( !str || str != passwnew ){
         write( "Das war verschieden! Passwort NICHT geaendert.\n" );
-        passwold = passw = 0;
         return 1;
     }
 
-    if ( MASTER->update_password( passwold, passw ) )
+    if ( MASTER->update_password( passwold, passwnew ) )
         write( "Passwort geaendert.\n" );
     else
         write( "Hat nicht geklappt!\n" );
 
-    passwold = passw = 0;
     return 1;
 }
 
@@ -4213,11 +4208,16 @@
 
 private int set_keep_alive(string str) {
   if (str == "ein") {
-    telnet_tm_counter = 240 / __HEART_BEAT_INTERVAL__;
-    tell_object(this_object(), break_string(
-        "An Deinen Client werden jetzt alle 4 Minuten unsichtbare Daten "
+    telnet_tm_counter = QueryProp(P_TELNET_KEEPALIVE_DELAY) || (240 / __HEART_BEAT_INTERVAL__);
+    tell_object(this_object(), break_string( sprintf(
+        "An Deinen Client werden jetzt alle %i Sekunden unsichtbare Daten "
         "geschickt, um zu verhindern, dass Deine Verbindung zum "MUDNAME
-        " beendet wird.", 78));
+        " beendet wird.",
+        telnet_tm_counter*__HEART_BEAT_INTERVAL__), 78));
+    // Bei Magiern ist der HB evtl. ausgeschaltet und muss eingeschaltet
+    // werden.
+    if (!object_info(this_object(), OC_HEART_BEAT))
+      configure_object(this_object(), OC_HEART_BEAT, 1);
   }
   else if (str == "aus") {
     telnet_tm_counter = 0;
diff --git a/std/shells/magier.c b/std/shells/magier.c
index 90da043..efde69f 100644
--- a/std/shells/magier.c
+++ b/std/shells/magier.c
@@ -40,6 +40,7 @@
 #include <properties.h>
 #include <new_skills.h>
 #include <config.h>
+#include <player/telnetneg.h>
 
 protected void create()
 {
@@ -76,7 +77,8 @@
 
   if (!QueryProp(P_WANTS_TO_LEARN)||((en=QueryEnemies())&&sizeof(en[0])))
     base::heart_beat();
-  else if (!CheckTelnetKeepAlive()) {
+  else if (!CheckTelnetKeepAlive(QueryProp(P_TELNET_KEEPALIVE_DELAY)))
+  {
     // Wenn der Magier kein Telnet Keep-Alive wuenscht, kann der HB ganz
     // abgeschaltet werden. Sonst muss er aber weiterlaufen, damit
     // CheckTelnetKeepAlive() regelmaessig gerufen wird.
diff --git a/sys/player/telnetneg.h b/sys/player/telnetneg.h
index 415ed90..6a5f1ca 100644
--- a/sys/player/telnetneg.h
+++ b/sys/player/telnetneg.h
@@ -9,6 +9,7 @@
 #ifndef _TELNETNEG_H_
 #define _TELNETNEG_H_
 
+#define P_TELNET_KEEPALIVE_DELAY "p_lib_telnet_alive_delay"
 #endif
 
 #ifdef NEED_PROTOTYPES