Editor und post.h hingefuegt

Der Editor wird im Mud an div. Stellen benutzt und auch das
post.h ist vielfach (indirekt) inkludiert.
diff --git a/mail/nedit.c b/mail/nedit.c
new file mode 100644
index 0000000..61c2be0
--- /dev/null
+++ b/mail/nedit.c
@@ -0,0 +1,545 @@
+#pragma strict_types
+
+/* nedit.c
+   Editor fuer news, mail usw.
+   Version 1 (C) 1993 Loco
+   Version 2 (C) 1995 Wargon
+
+   Verwendung ausserhalb von Morgengrauen ist gestattet unter folgenden
+   Bedingungen:
+   - Benutzung erfolgt auf eigene Gefahr. Jegliche Verantwortung wird
+     abgelehnt.
+   - Auch in veraenderten oder abgeleiteten Objekten muss ein Hinweis auf
+     die Herkunft erhalten bleiben.
+   Ein Update-Service besteht nicht.
+
+   Anwendung:
+    #inherit "/mail/nedit";      (zusaetzlich zu anderen inherits)
+
+     nedit(string funcname);                    oder
+    nedit(string funcname,string pretext);
+    Nach Beendigung des Editors wird die Funktion funcname aufgerufen.
+    Sie bekommt als Argument einen string mit dem fertigen editierten Text
+    uebergeben bzw. 0, wenn der Editor mit ~q abgebrochen wurde.
+    Optionales Argument pretext ist der zu editierende Text. Wenn 0 oder nicht
+    uebergeben, wird ein neuer Text begonnen.
+*/
+
+#include <properties.h>
+#include <wizlevels.h>
+#include <defines.h>
+#include <input_to.h>
+
+#define TP this_player()
+
+#define F_OVR 1  // Overwrite-Modus
+#define F_BLK 2  // Blocksatz
+
+#define MAX_LINES 1000
+
+static mixed nedittext, nexitfunc, editor_used;
+static int bstart, bend;  // Anfang und Ende des Blocks
+static int cur;           // Aktuelle Zeile
+static int len;           // Laenge des Gesamttextes
+static int flags;          // Overwritemodus
+
+static int get_edit_line(string str);
+static int ShowWritten(int f, int l, int num);
+static string killctrl( string str );
+static int ShowHelp();
+static int delLine(int l);
+static void delBlock();
+static int input_func();
+varargs static void moveBlock(int start, int end, int real);
+
+void init_rescue() {
+  add_action("RescueText","~r");
+}
+
+private string nedit_prompt()
+{
+  if (sizeof(nedittext) <= MAX_LINES)
+    return("]");
+  else {
+    nedittext = nedittext[0..MAX_LINES-1];
+    len = MAX_LINES;
+    if (cur >= MAX_LINES)
+      cur = MAX_LINES-1;
+    if (bstart >= MAX_LINES)
+      bstart = MAX_LINES-1;
+    if (bend >= MAX_LINES)
+      bend = MAX_LINES-1;
+    return sprintf("*** Mehr als %d Zeilen! Text wurde abgeschnitten! ***\n]", MAX_LINES);
+  }
+}
+
+static varargs int nedit(string exitfunc,string pretext) {
+  if (editor_used) {
+    write("Offensichtlich schreibt hier schon jemand dran. Sorry.\n"+
+                        "(Falls du es selbst bist, tippe ~r zur Wiederaufnahme einer verlorenen Sitzung)\n");
+    return -1;
+  }
+  if (!pretext) nedittext=({""});
+  else nedittext=explode(pretext,"\n");
+  bstart = 0;
+  bend = cur = len = sizeof(nedittext)-1;
+  nexitfunc=exitfunc;
+  flags = 0;
+  editor_used=(string)TP->query_real_name();
+  if (pretext)
+    get_edit_line("~z");
+  else {
+    //nedit_prompt();
+    input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+  }
+  return 1;
+}
+
+static int get_edit_line(string str) {
+  int err;
+  int spaces;
+  int fflag;
+  int sl;
+
+  if (!str) str="";
+  str=killctrl(str); /* kleiner hack wegen CTRL-chars. */
+  fflag = 0;
+
+  sl = sizeof(str);
+
+  if (str=="**" || str=="~." || str==".") {
+    editor_used=0;
+    str = implode(nedittext, "\n");
+    nedittext = 0;
+    call_other(this_object(),nexitfunc,str);
+    return 1;
+  }
+  if (str[0..0]== "~" && sl >= 2) {
+    if (sl == 2) {
+      switch(str[0..1]) {
+      // Abbruch:
+      case "~q":
+        editor_used = 0;
+        return call_other(this_object(), nexitfunc, 0);
+      // Temporaer rausgehen:
+      case "~!":
+        write("Mit ~r kannst Du weiterschreiben.\n");
+        init_rescue();
+        return 1;
+      // Gesamten Text anzeigen
+      case "~R":
+        fflag = 1;
+      case "~r":
+        return ShowWritten(0, len, fflag);
+      // Ausschnitt um Cursor anzeigen
+      case "~Z":
+        fflag = 1;
+      case "~z":
+        int f = (cur > 5) ? cur-5 : 0;
+        int l = (cur < len-5) ? cur + 5 : len;
+        return ShowWritten(f, l, fflag);
+      // Hilfeseite anzeigen:
+      case "~h":
+        return ShowHelp();
+      // Zeile ueber Cursor loeschen:
+      case "~d":
+        return delLine(cur-1);
+      // Block loeschen:
+      case "~D":
+        delBlock();
+        write( "Block geloescht.\n" );
+        return input_func();
+      // Overwrite-Modus toggeln:
+      case "~v":
+        flags ^= F_OVR;
+        printf("%smodus eingeschaltet.\n",
+              (flags & F_OVR) ? "Ueberschreib" : "Einfuege");
+        return input_func();
+      // Blocksatz toggeln:
+      case "~b":
+        flags ^= F_BLK;
+        printf("%ssatz aktiviert.\n",
+              (flags & F_BLK) ? "Block" : "Flatter");
+        return input_func();
+      // Statusinfo anzeigen:
+      case "~s":
+        printf("Zeile: %d | Laenge: %d | BStart: %d | BEnde: %d | "
+               "Modus: %s/%s.\n",
+                cur, len, bstart, bend, (flags&F_OVR)?"Ueber.":"Einfg.",
+                (flags&F_BLK)?"Blocksatz":"Flattersatz");
+        return input_func();
+      // Block verschieben:
+      case "~m":
+        moveBlock(bstart, bend, 1);
+        return input_func();
+      // Block umformatieren:
+      case "~F":
+        int bs = bstart;
+        str = implode(nedittext[bstart..bend], " ");
+        delBlock();
+        bstart = bend = cur = bs;
+        fflag = -1;
+        write("Block wurde umformatiert.\n");
+        break;
+      // Zeile umformatieren:
+      case "~f":
+        str = nedittext[cur];
+        nedittext = nedittext[0..cur-1] + nedittext[cur+1..];
+        if (cur <= bstart)
+          bstart--;
+        if (cur <= bend)
+          bend--;
+        len --;
+        fflag = -1;
+        write("Zeile wurde umformatiert.\n");
+        break;
+      } // switch
+    } // if (sl == 2)
+    else {
+      // Cursorbewegungen an bestimmte Stellen:
+      if (str[0..1] == "~c" && sl == 3) {
+        fflag = 1;
+        switch(str[2]) {
+          case 'u': spaces = -1;           break;
+          case 'd': spaces = 1;            break;
+          case 't': spaces = -len;         break;
+          case 'b': spaces = len;          break;
+          case 's': spaces = bstart - cur; break;
+          case 'e': spaces = bend - cur;   break;
+          default:  spaces = 0;
+                    fflag = 0;
+                    break;
+        }
+      }
+      // Cursorbewegung mit Zeilennummern:
+      if (spaces || sscanf(str, "~c%d", spaces) == 1) {
+        if (fflag>0 || str[2..2] == "+" || str[2..2] == "-")
+          cur += spaces;
+        else
+          cur = spaces-1;
+
+        if (cur < 0)
+          cur = 0;
+        else if (cur > len)
+          cur = len;
+
+        printf("%s\n",nedittext[cur]);
+        return input_func();
+      }
+      // Blockgrenzen setzen:
+      if ((err = (str[0..2] == "~bs")) || (str[0..2]=="~be")) {
+        string out, p;
+        int pos;
+
+        int valid = -1;
+
+        if (sl == 3)
+          pos = valid = cur;
+        else if (sscanf(str[3..], "%d%s", pos, p) == 2 && p=="")
+          valid = pos--;
+
+        if (valid >= 0) {
+          if (err) {
+            bstart = pos;
+            if (pos > bend)
+              bend = len;
+            out = "Blockanfang";
+          }
+          else {
+            if (pos < bstart)
+              bstart = 0;
+            bend = pos;
+            if (len && bend == len)
+              bend--;
+            out = "Blockende";
+          }
+          printf("%s gesetzt.\n", out);
+          return input_func();
+        }
+      }
+
+      // Ersetzen:
+      if ((sizeof(str) >= 8) && str[0..1] == "~s") {
+        string *s1, *s2;
+        int m;
+
+        m = (str[2] == ' ') ? 3 : 2;
+
+        if (sizeof(s1 = explode(str[m..], str[m..m])) == 4) {
+          s2 = explode(nedittext[cur], s1[1]);
+          if (sizeof(s2) > 1) {
+            s2[1] = s2[0]+s1[2]+s2[1];
+            nedittext[cur] = implode(s2[1..], s1[1]);
+            if (s1[3] == "p")
+              printf("%s\n", nedittext[cur]);
+            else
+              write("OK.\n");
+            //nedit_prompt();
+          }
+          else {
+            printf("\"%s\" nicht gefunden!\n", s1[1]);
+            //nedit_prompt();
+          }
+
+          input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+          return 1;
+        }
+      }
+    } // if (sl > 2)
+  } // if (str[0..0] == "~")
+
+  spaces=(sizeof(str) && (str[0]==' ' || str[0]=='\t'));
+  if (spaces) str="$"+str;  /* Kleiner hack wegen fuehrenden Leerzeichen */
+  str=break_string(str,78,0,(flags&F_BLK) ? BS_BLOCK|BS_NO_PARINDENT : 0);
+  if (spaces) str=str[1..<1];
+  if ( ((str[0..1]=="~r" && sizeof(str)>2) || str[0..1]=="~i") && 
+       IS_LEARNER(TP) ) 
+  {
+    str=str[2..<2];
+    if (str[0..0]==" ") str=str[1..<1];
+    if (!str || catch(err=file_size(str=(string)"/secure/master"->_get_path(str,getuid(TP)))) || err<0) {
+      write("File nicht gefunden.\n");
+      //nedit_prompt();
+      input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+      return 1;
+    }
+    str=read_file(str);
+    if (!str){
+      write("Zu gross!\n");
+      //nedit_prompt();
+      input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+      return 1;
+    }
+    write("Ok.\n");
+  }
+  if (str=="" || !str) str="\n";
+  {
+    string *x;
+    int sx;
+
+    x = explode(str, "\n")[0..<2];
+    sx = sizeof(x);
+
+    if (flags&F_OVR && !fflag) {
+      nedittext = nedittext[0..cur-1] + x + nedittext[cur+1..];
+      sx--;
+    }
+    else
+      nedittext = nedittext[0..cur-1] + x + nedittext[cur..];
+
+    if (cur < bstart)
+      bstart += sx;
+    if (cur <= bend)
+      bend += (sx + fflag);
+    cur += (sx + fflag + ((flags&F_OVR) ? 1:0));
+    len += sx;
+
+    // Kann beim Umformatieren des letzten Abschnitts vorkommen.
+    if (nedittext[len] != "") {
+      nedittext += ({ "" });
+      len++;
+    }
+  }
+  //nedit_prompt();
+  input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+  return 1;
+}
+
+static int delLine(int l)
+{
+  string pr;
+  if (l < 0)
+    pr="Da ist nix mehr zum Loeschen!\n]";
+  else {
+    if (bstart >= l)
+      bstart--;
+    if (bend >= l)
+      bend--;
+    if (cur >= l)
+      cur--;
+    len--;
+    nedittext=(nedittext[0..l-1]+nedittext[l+1..]);
+    write("Vorherige Zeile geloescht.\n");
+    pr=nedit_prompt();
+  }
+  input_to("get_edit_line", INPUT_PROMPT, pr);
+  return 1;
+}
+
+static void delBlock()
+{
+  if (cur > bstart) {
+    if (cur <= bend)
+      cur = bstart;
+    else
+      cur -= (bend - bstart + 1);
+  }
+  if (bend == len)
+    nedittext = nedittext[0..bstart-1];
+  else
+    nedittext = nedittext[0..bstart-1] + nedittext[bend+1..];
+
+  bend = len = sizeof(nedittext)-1;
+  bstart = 0;
+  if (cur > len)
+    cur = len;
+}
+
+varargs static void moveBlock(int start, int end, int real)
+{
+  int blen;
+  string *block;
+
+  if (cur >= start && cur <= end)
+    write("Aber der Cursor steht innerhalb des Blocks!\n");
+  else {
+    block = nedittext[start..end];
+    blen = sizeof(block)-1;
+    delBlock();
+    nedittext = nedittext[0..cur-1] + block + nedittext[cur..];
+    if (real) {
+      bstart = cur;
+      bend = cur + blen;
+    }
+    len += (blen+1);
+    write("OK.\n");
+  }
+}
+
+#define UMLAUT ([ \
+    'ä': "ae", \
+    'ö': "oe", \
+    'ü': "ue", \
+    'Ä': "Ae", \
+    'Ö': "Oe", \
+    'Ü': "Ue", \
+    'ß': "ss"  ])
+
+static string killctrl( string str )
+{
+    int i, j;
+    string tmp;
+
+    tmp = "";
+    
+    for ( j = sizeof(str), i = 0; i < j; i++ )
+        tmp += (UMLAUT[str[i]] || str[i..i]);
+
+    tmp = regreplace( tmp, "[^ -~\t]", "", 1 );
+    
+    if (sizeof(tmp) &&  tmp[0] < 32 )
+        return tmp[1..];
+  
+    return tmp;
+}
+
+mixed RescueText() {
+  if (!nedittext || !editor_used)
+    return notify_fail("Du hast nix angefangen zu schreiben!\n"),0;
+  if (TP->query_real_name()!=editor_used)
+    return notify_fail("Hier schreibt "+capitalize(editor_used)+"!\n"),0;
+  if (query_input_pending(TP))
+    return notify_fail("Du schreibst gerade schon irgendwas. Sorry...\n"),0;
+  return ShowWritten(0, len, 0);
+}
+
+static int ShowWritten(int f, int l, int num) {
+  string s, t, c, p, in;
+  int i;
+
+  if (num) {
+    if (l >= 100) {
+      p = "%3d%s%s";
+      in = " ";
+    }
+    else {
+      p = "%2d%s%s";
+      in = "  ";
+    }
+  }
+  else
+    in = "";
+
+  for (t="", i=l-1; i>=f; i--) {
+    if (i == cur)
+      c = ( ((i == bend) || (i == bstart)) ? "#" : "*");
+    else if (i==bstart || i==bend)
+      c = ">";
+    else c = ":";
+
+    if (num)
+      t = (sprintf(p, i+1, c, nedittext[i])[0..75] + "\n" + t);
+    else
+      t = (c + nedittext[i]+"\n" + t);
+  }
+
+  if (l==len) {
+    if (len == cur)
+      c = ( (len == bend) ? "#" : "*");
+    else if (len==bend)
+      c = ">";
+    else c = " ";
+  }
+  else c= " ";
+
+  s="Das hast Du bisher geschrieben:\n"+in+" \
+--------------------------\n\
+"+t+in+c+"\
+--------------------------";
+  this_player()->More(s,0,symbol_function("input_func",this_object()));
+  return 1;
+}
+
+static int ShowHelp() {
+  this_player()->More("\
+--------------------------\n\
+Der Editor versteht folgende Befehle:\n\
+--- Dateikommandos:\n\
+~h            diese Hilfsseite\n\
+~r / ~R     zeigt an, was Du bisher geschrieben hast\n\
+~z / ~Z     zeigt den Textausschnitt um den Cursor herum\n\
+"+(IS_WIZARD(TP) ? "\
+~i filename fuegt eine Datei in den Text ein (auch ~r filename)\n\
+" : "" )+ "\
+~q            bricht ab\n\
+** oder .   beendet sauber\n\
+!<cmd>            fuehrt <cmd> aus, wie wenn Du gerade nicht schreiben wuerdest\n\
+~!            verlaesst den Editor voruebergehend\n\
+~s            Statusinformationen anzeigen\n\
+~b            Wechselt zwischen Flatter- (default) und Blocksatz\n\
+--- zeilenorientierte Kommandos:\n\
+~d            loescht die letzte Zeile (Text-, nicht Eingabezeile)\n\
+~v            wechselt zwischen Einfuege- (default) und Ueberschreibmodus\n\
+~s !s1!s2!  Ersetzt das erste Vorkommnis des Strings s1 durch den String s2\n\
+            in der aktuellen Zeile.\n\
+            Statt durch ! koennen die Strings auch durch beliebige andere\n\
+            Zeichen getrennt werden, die weder in s1 noch in s2 vorkommen.\n\
+~f            Formatiert die aktuelle Zeile neu\n\
+--- Cursorkommandos:\n\
+~cu / ~cd   Cursor um eine Zeile nach oben/unten bewegen\n\
+~ct / ~cb   Cursor an Anfang/Ende des Textes bewegen\n\
+~cs / ~ce   Cursor an Blockanfang/Blockende bewegen\n\
+~c<nr>            Cursor nach Zeile <nr> bewegen\n\
+~c+<nr>     Cursor um <nr> Zeilen nach unten bewegen\n\
+~c-<nr>     Cursor um <nr> Zeilen nach oben bewegen\n\
+--- blockorientierte Kommandos:\n\
+~bs/~bs<nr> setzt Blockanfang auf Cursorposition bzw. auf Zeile <nr>\n\
+~be/~be<nr> setzt Blockende auf Cursorposition bzw. auf Zeile <nr>\n\
+~F            formatiert den Block neu\n\
+~D            loescht den markierten Block\n\
+~m            verschiebt den markierten Block an die Cursorposition\n\
+---\n\
+Alles andere gilt als Text. Ueberlange Zeilen werden auf eine maximale\n\
+Laenge von 78 Zeichen umgebrochen.\n\
+Nach ~!, oder wenn man waehrend des Schreibens netztot wird, kann man mit\n\
+ ~r wieder in den Editor einsteigen.\n\
+--------------------------\n\
+", 0, symbol_function("input_func", this_object()));
+  return 1;
+}
+
+static int input_func() {
+  //nedit_prompt();
+  input_to("get_edit_line", INPUT_PROMPT, nedit_prompt());
+  return 1;
+}
diff --git a/mail/post.h b/mail/post.h
new file mode 100644
index 0000000..d6ae465
--- /dev/null
+++ b/mail/post.h
@@ -0,0 +1,46 @@
+#ifndef _MAIL_POST_H
+#define _MAIL_POST_H
+
+// Files der Post
+
+#define MAILER "/mail/mailer"
+#define STDPOST "/p/service/loco/std/post"
+#define TESTMAILER "/mail/testmailer"
+#define MAILCABIN "/std/mailcabin"
+#define NEDIT "/mail/nedit"
+#define SAVEFILENAME ("/open/tmp/"+geteuid(this_player())+".mail")
+#define LONGHELP "/p/service/loco/doc/post"
+#define MAILDEMON "/secure/mailer"
+#define ALIASFILE(name) ("/players/"+name+"/.mailrc")
+#define SYSALIAS "/mail/system.mailrc"
+#define FWSERV "/p/service/loco/obj/fwserv"
+#define FWSAVESERV "/p/service/loco/obj/fwsaveserv"
+#define FWSAVEFILE(x) ("/p/service/loco/save/forwards/"+x)
+
+// Konfiguration
+
+#define NRCABINS 2                   // Anzahl Schreibkabinen pro Postamt
+#define MAIL_SUPPORT_BCC             // bcc's in '-name'-Syntax (MG)
+#define MAIL_QUERY_BCC               // bcc's abfragen (NF)
+
+// Files fuer die Paketpost
+
+#define PARCEL "/p/service/loco/obj/parcel"
+#define STAMPSERV "/p/service/loco/lib/stampserv"
+#define STAMP "/p/service/loco/obj/marke"
+#define PARCELSERVER "/p/service/loco/lib/parcelserver"
+#define STAMPSAVEPATH "/p/service/loco/save/stamps/"
+#define COUNTER "/p/service/loco/std/schalter"
+
+// Versendeerlaubnis
+// Fuer Raeume: Darf hierher ein Kurierpaket geschickt werden?
+// Fuer Objekte: Darf es in Paketen verschickt werden?
+// Anwendung: SetProp(P_POST, wert);
+
+#define P_POST             "Post"
+#define PP_FORBIDDEN       -2     // verboten
+#define PP_NO_EXPRESS      -1     // Kurierpaket verboten, postl. nach Default
+#define PP_DEFAULT          0     
+#define PP_NORMAL_ALLOWED   1     // postlagernd erlaubt, Kurierp. nach Default
+#define PP_ALLOWED          2     // Auf jeden Fall erlaubt
+#endif