Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/player/channel.c b/std/player/channel.c
new file mode 100644
index 0000000..9f8512a
--- /dev/null
+++ b/std/player/channel.c
@@ -0,0 +1,579 @@
+// MorgenGrauen MUDlib
+//
+// channel.c -- channel client
+//
+// $Id: channel.c 9404 2015-12-13 00:21:44Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <util.h>
+#include <thing/properties.h>
+#include <living/comm.h>
+#include <player.h>
+#include <player/comm.h>
+#include <daemon.h>
+#include <player/gmcp.h>
+#undef NEED_PROTOTYPES
+
+#include <wizlevels.h>
+#include <defines.h>
+#include <properties.h>
+#include <sys_debug.h>
+#include <regexp.h>
+
+#define P_SWAP_CHANNELS  "swap_channels"
+#define P_CHANNEL_SHORT  "short_channels"
+
+#define CHANNELCMDS      "[#@%$&()<>a-zA-Z0-9\\-]"
+
+#define DEFAULT_CHANNELS ({"Abenteuer", "Anfaenger","Grats","Tod", "ZT"})
+#define DEFAULT_SHORTCUTS \
+([                     \
+ "b":"Abenteuer",      \
+ "a":"Allgemein",      \
+ "B":"Beileid",        \
+ "q":"D-chat",         \
+ "G":"Grats",          \
+ "M":"Moerder",        \
+ "h":"Seher",          \
+ "T":"Tod",            \
+])
+
+#define WIZARD_SHORTCUTS \
+([                     \
+ "P":"D-code",         \
+ "D":"Debug",          \
+ "O":"Intercode",      \
+ "I":"Intermud",       \
+ "m":"Magier",         \
+])
+
+
+private nosave mapping shortcut;
+private nosave int c_status;
+
+void create()
+{
+  Set(P_CHANNELS, SAVE, F_MODE);
+  Set(P_CHANNELS, DEFAULT_CHANNELS);
+  Set(P_SWAP_CHANNELS, SAVE, F_MODE);
+  Set(P_STD_CHANNEL, "Allgemein");
+  Set(P_STD_CHANNEL, SAVE, F_MODE);
+  Set(P_CHANNEL_SHORT, SAVE, F_MODE);
+  Set(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
+      + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
+}
+
+static mixed _query_localcmds()
+{
+  return ({({"-","ChannelParser", 1, 0}),
+           ({"ebene", "ChannelAdmin", 0, 0}),
+           ({"ebenen", "ChannelAdmin", 1, 0}),
+         });
+}
+
+mixed RegisterChannels()
+{
+  mixed err;
+  if(extern_call() &&
+     previous_object() != find_object(CHMASTER)) return;
+  c_status = 0;
+  shortcut = QueryProp(P_CHANNEL_SHORT);
+  SetProp(P_CHANNELS, map(QueryProp(P_CHANNELS) || ({}),
+	#'lower_case));
+  err = filter(QueryProp(P_CHANNELS),
+         symbol_function("join", CHMASTER),
+         this_object());
+  if(QueryProp(P_LEVEL) < 5) return err;
+  while(sizeof(err)) {
+    CHMASTER->new(err[0], this_object());
+    err[0..0] = ({});
+  }
+  return err;
+}
+
+mixed RemoveChannels()
+{
+  closure cl;
+  mixed err=({});
+  if(extern_call() &&
+     previous_object() != find_object(CHMASTER)) return;
+  if(!c_status) c_status = 1;
+  else return ({});
+  cl=symbol_function("leave", CHMASTER);
+  if (closurep(cl)) {
+      err = filter(QueryProp(P_CHANNELS), cl, this_object());
+      SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - err);
+  }
+  return err;
+}
+
+varargs private string getName(mixed x, int fall) {
+  
+  mixed o = closurep(x) ? query_closure_object(x) : x;
+  if(stringp(o) && sizeof(o) && (x = find_object(o))) 
+    o = x;
+  
+  // Objekte
+  if (objectp(o)) {
+    // Magier sehen unsichtbare nicht nur als "Jemand"
+    if (o->QueryProp(P_INVIS) && IS_LEARNING(this_object()))
+      return "("+capitalize(getuid(o))+")";
+    // Froesche mit Namen versorgen.
+    if (o->QueryProp(P_FROG))
+      return "Frosch "+capitalize(getuid(o));
+    // Default (Unsichtbare als "Jemand" (s. Name()))
+    return o->Name(fall, 2)||"<Unbekannt>";
+  }
+  // Strings
+  else if (stringp(o) && sizeof(o)) {
+    if (o[0] == '/') {
+      // unsichtbare Objekte...
+      int p = strstr(o, "$");
+      if (p != -1) {
+	// Magier im Magiermodus kriegen den Realnamen, andere nicht.
+	if (IS_LEARNING(this_object()))
+	  return o[1..p-1];
+	else
+	  return o[p+1..];
+      }
+      else
+	// doch nicht unsichtbar
+	return (fall == WESSEN ? o+"s" : o);
+    }
+    else
+      // nicht unsichtbar
+      return (fall == WESSEN ? o+"s" : o);
+  }
+  // Fall-through
+  return "<Unbekannt>";
+}
+
+// <nonint> unterdrueckt die AUsgabe an den Spieler und liefert den Text
+// zurueck. Wird nur fuer die Ebenenhistory benutzt. 
+string ChannelMessage(mixed* msg, int nonint)
+{
+  string channel_message;
+  string channel=msg[0];
+  object sender=msg[1];
+  string message=msg[2];
+  int msg_type = msg[3];
+
+  if ( previous_object() != find_object(CHMASTER) &&
+       previous_object() != ME )
+      return 0;
+
+  string sender_name = getName(sender, msg_type == MSG_GEMOTE ? WESSEN : WER);
+  int prepend_indent_flag=QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0;
+  switch(msg_type) {
+  case MSG_EMPTY:
+    channel_message= message+"\n";
+    break;
+  case MSG_GEMOTE:
+  case MSG_EMOTE:
+    channel_message = break_string(sender_name + " "+ message+"]",
+                   78, sprintf("[%s:", channel),
+                   BS_INDENT_ONCE|prepend_indent_flag);
+    break;
+  case MSG_SAY:
+  default:
+    string presay=sprintf("[%s:%s] ", channel, sender_name);
+    channel_message = break_string(message, max(78,sizeof(presay)+10),
+                   presay, prepend_indent_flag);
+    break;
+  }
+  if(nonint)
+    return channel_message;
+
+  // Wenn GMCP sich um Uebertragung der Nachricht kuemmert, wird ReceiveMsg()
+  // nicht mehr aufgerufen.
+  if (GMCP_Channel(channel_message, channel, sender_name) != 1)
+  {
+    // Der Ebenenname muss in Kleinbuchstaben uebergeben werden, damit die
+    // Ignorierepruefung funktioniert. Die ignorierestrings sind naemlich alle
+    // kleingeschrieben.
+    ReceiveMsg(channel_message, 
+               MT_COMM|MT_FAR|MSG_DONT_STORE|MSG_DONT_WRAP,
+               MA_CHANNEL"." + lower_case(channel), 0, sender);
+  }
+  return 0;
+}
+
+private void createList(string n, mixed a, mixed m, mixed l)
+{
+  int pos; string sh, *mem;
+  if((pos = member(map(m_values(shortcut), #'lower_case/*'*/), n)) != -1)
+    sh = m_indices(shortcut)[pos];
+  else sh = "";
+  mem=map(a[I_MEMBER],#'getName/*'*/, WER);
+  mem-=({"<MasteR>"});
+  l += ({ sprintf("%-12.12'.'s %c[%-1.1s] %|12.12' 's (%-|3' 'd) %-42.42s\n",
+                  a[I_NAME], (member(m, n) != -1 ? '*' : ' '), sh,
+                  a[I_MASTER] ?
+                  getName(a[I_MASTER]) : getName(a[I_ACCESS]),
+                  sizeof(mem),
+            (closurep(a[I_INFO]) && objectp(query_closure_object(a[I_INFO]))) ?
+                  funcall(a[I_INFO]) || "- Keine Beschreibung -" :
+                  (stringp(a[I_INFO]) ? a[I_INFO] : "- Keine Beschreibung -")
+        ) });
+}
+
+private mixed getChannel(string ch)
+{
+  mixed ff;
+  if(!sizeof(ch)) ch = QueryProp(P_STD_CHANNEL);
+  if(shortcut && shortcut[ch]) ch = shortcut[ch];
+  return CHMASTER->find(ch, this_object());
+}
+
+#ifndef DEBUG
+#define DEBUG(x)        if (funcall(symbol_function('find_player),"zesstra"))\
+          tell_object(funcall(symbol_function('find_player),"zesstra"),\
+	              "MDBG: "+x+"\n")
+#endif
+int ChannelParser(string args)
+{
+  mixed ch, cmd, tmp;
+  int pos, type, err;
+  string txt;
+  cmd = query_verb();
+  args = _unparsed_args();
+  notify_fail("Benutzung: -<Ebene>[ ]['|:|;]<Text>\n"
+              "           -<Ebene>[+|-|?|!|*]\n"
+              "           -?\n");
+  if(!cmd && !args) return 0;
+  if(!args) args = "";
+  cmd = cmd[1..];
+  if(sizeof(cmd = regexplode(cmd,
+                             "^" CHANNELCMDS "*"
+                             "([+-]|\\!|\\?|\\*)*")) > 1)
+  {
+    //z.B. cmd= ({"","allgemein",":testet"})
+    if(sizeof(cmd[1]) > 1 &&
+       strstr("+-?!*", cmd[1][<1..<1]) > -1)
+      tmp = cmd[1][0..<2];
+    else
+      tmp = cmd[1];
+    if(cmd[1] != "?" && cmd[1] != "!")
+      if(pointerp(ch = getChannel(tmp)))
+      {
+        notify_fail("Diese Angabe war nicht eindeutig! "
+                    "Folgende Ebenen passen:\n"
+                    +implode(ch, ", ")+"\n");
+        return 0;
+      }
+      else if(!ch) return (notify_fail("Die Ebene '"+tmp
+                                       +"' gibt es nicht!\n"), 0);
+    //DEBUG(sprintf("ChanCmd: %O\n",cmd));
+    if (sizeof(cmd[1])) {
+      switch(cmd[1][<1]) {
+    case '+':
+      switch(CHMASTER->join(ch, this_object()))
+      {
+      case E_ACCESS_DENIED:
+        notify_fail("Du darfst an die Ebene '"+ch+"' nicht heran.\n");
+        return 0;
+      case E_ALREADY_JOINED:
+        notify_fail("Du hast diese Ebene schon betreten!\n");
+        return 0;
+      default: break;
+      }
+      write("Du betrittst die Ebene '"+ch+"'.\n");
+      if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
+        SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
+      return 1;
+    case '-':
+      switch(CHMASTER->leave(ch, this_object()))
+      {
+      case E_ACCESS_DENIED:
+        write("Du kannst die Ebene '"+ch+"' nicht verlassen.\n");
+        break;
+      case E_NOT_MEMBER:
+        write("Wie willst Du eine Ebene verlassen, welche Du nicht "
+              "betreten hast?\n");
+        break;
+      default:
+        write("Du verlaesst die Ebene '"+ch+"'.\n");
+        SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - ({ lower_case(ch), ch }));
+        break;
+      }
+      return 1;
+    case '!':
+    case '?':
+    {
+      mapping l;
+      if(mappingp(l = CHMASTER->list(this_object())))
+        if(stringp(ch) && sizeof(ch) && pointerp(l[ch = lower_case(ch)]))
+        {
+          int c; object o; string n; string *m;
+          m=sort_array(map(l[ch][I_MEMBER],#'getName/*'*/, WER),#'>/*'*/);
+          m-=({"<MasteR>"});
+          write(l[ch][I_NAME]+", "+funcall(l[ch][I_INFO])+".\n");
+          write("Du siehst "+((c = sizeof(m)) > 0
+                              ? (c == 1 ? "ein Gesicht" : c+" Gesichter")
+                              : "niemanden")+" auf der Ebene '"
+                                +l[ch][I_NAME]+"':\n");
+          write(break_string(implode(m,", "), 78));
+          write((l[ch][I_MASTER] ?
+                 getName(l[ch][I_MASTER]) : getName(l[ch][I_ACCESS], WER))
+                +" hat das Sagen auf dieser Ebene.\n");
+        }
+        else
+        {
+          mixed list; list = ({});
+          if(cmd[1][<1] == '!')
+            l -= mkmapping(m_indices(l) - QueryProp(P_CHANNELS));
+          walk_mapping(l, #'createList/*'*/, QueryProp(P_CHANNELS), &list);
+          list = sort_array(list, #'>/*'*/);
+          txt = sprintf("%-12.12' 's  [A] %|12' 's (%-3' 's) %-42.42s\n",
+                        "Name", "Eigner", "Sp", "Beschreibung")
+              + "-------------------------------------------------------"
+              + "-----------------------\n"
+              + implode(list, "");
+          More(txt);
+        }
+      return 1;
+    }
+    case '*':
+    {
+      mixed hist; int amount;
+      if(!pointerp(hist = CHMASTER->history(ch, this_object())) 
+		      || !sizeof(hist))
+      {
+        write("Es ist keine Geschichte fuer '"+ch+"' verfuegbar.\n");
+        return 1;
+      }
+      
+      //(Zesstra) cmd hat offenbar immer 3 Elemente...
+      //bei -all* ({"","all*",""})
+      //bei -all*10 ({"","all*,"10"})
+      //also ist bei -all* amount immer == 0 und es funktioniert eher zufaellig.
+      /*if(sizeof(cmd) > 2) 
+        amount = to_int(cmd[2]);
+      else 
+        amount=sizeof(hist);*/
+      amount=to_int(cmd[2]);
+      if (amount <= 0 || amount >= sizeof(hist))
+        amount=sizeof(hist);
+
+      txt = "Folgendes ist auf '"+ch+"' passiert:\n"
+          + implode(map(hist[<amount..], #'ChannelMessage/*'*/, 1), "");
+      More(txt);
+      return 1;
+    }
+    default:
+      break;
+    }
+    }
+  }
+  if(sizeof(cmd = implode(cmd[2..], "")))
+     args = cmd + (sizeof(args) ? " " : "") + args;
+
+  // KOntrollchars ausfiltern.
+  args = regreplace(args,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
+  if(!sizeof(args)) return 0;
+
+  //Wenn cmd leer ist: MSG_SAY
+  if (!sizeof(cmd)) type=MSG_SAY;
+  else {
+    switch(cmd[0])
+    {
+    case ':' :
+      type = MSG_EMOTE;
+      args = args[1..];
+      break;
+    case ';' :
+      type = MSG_GEMOTE;
+      args = args[1..];
+      break;
+    case '\'':
+      args = args[1..];
+    default  : type = MSG_SAY; break;
+    }
+  }
+  if(!ch || !sizeof(ch)) ch = QueryProp(P_STD_CHANNEL);
+  if((err = CHMASTER->send(ch, this_object(), args, type)) < 0)
+    if(!(err = CHMASTER->join(ch, this_object())))
+    {
+      if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
+        SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
+      err = CHMASTER->send(ch, this_object(), args, type);
+    }
+
+  switch(err)
+  {
+  case E_ACCESS_DENIED:
+    notify_fail("Auf der Ebene '"+ch+"' darfst Du nichts sagen.\n");
+    return 0;
+  case E_NOT_MEMBER:
+    notify_fail("Du hast die Ebene '"+ch+"' nicht betreten!\n");
+    return 0;
+  }
+  return 1;
+}
+
+int ChannelAdmin(string args)
+{
+  string n, descr, sh, cn;
+  mixed pa, tmp;
+  args = _unparsed_args();
+  notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
+              "           ebene <Abkuerzung>=\n"
+              "           ebene abkuerzungen [standard]\n"
+              "           ebene standard <Ebene>\n"
+              "           ebene an|ein|aus\n"
+              +(QueryProp(P_LEVEL) >= 5 ?
+                "           ebene neu <Name> <Bezeichnung>\n"
+    "           ebene beschreibung <Name> <Beschreibung>\n" : "")
+        +(IS_ARCH(this_object()) ?
+          "           ebene kill <Name>\n"
+	  "           ebene clear <Name>\n": ""));
+  if(!args || !sizeof(args)) return 0;
+  if(sscanf(args, "kill %s", n) && IS_ARCH(this_object()))
+  {
+    if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
+    switch(CHMASTER->remove(cn, this_object()))
+    {
+    case E_ACCESS_DENIED:
+     notify_fail("Die Ebene '"+cn+"' lies sich nicht entfernen!\n");
+     return 0;
+    }
+    write("Du entfernst die Ebene '"+cn+"'.\n");
+    return 1;
+  }
+  if(sscanf(args, "clear %s", n) && IS_ARCH(this_object()))
+  {
+    if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
+    switch(CHMASTER->clear_history(cn, this_object()))
+    {
+    case E_ACCESS_DENIED:
+     notify_fail("Der Verlauf zur Ebene '"+cn+"' lies sich nicht entfernen!\n");
+     return 0;
+    }
+    write("Du entfernst den Verlauf zur Ebene '"+cn+"'.\n");
+    return 1;
+  }
+  if(sscanf(args, "neu %s %s", n, descr) == 2)
+  {
+    mixed x;
+    if(QueryProp(P_LEVEL) < 5)
+      return (notify_fail("Neue Ebenen zu erstellen ist dir verwehrt.\n"), 0);
+    if(!sizeof(regexp(({ n }), "^" CHANNELCMDS CHANNELCMDS "*")))
+      return (notify_fail("Der Name '"+n+"' ist nicht konform!\n"), 0);
+    if (sizeof(n) > 20 )
+      return(notify_fail("Der Name '"+n+"' ist zu lang.\n"), 0);
+    switch(x = CHMASTER->new(n, this_object(), descr))
+    {
+    case E_ACCESS_DENIED:
+      notify_fail("Diese Ebene darfst du nicht erschaffen!\n"); break;
+    default:
+      write("Du erschaffst die Ebene '"+n+"'.\n");
+      SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ lower_case(n) }));
+      return 1;
+    }
+  }
+  if(sscanf(args, "beschreibung %s %s", n, descr) == 2)
+  {
+    mixed ch;
+    cn = CHMASTER->find(n, this_object());
+    if(!cn || pointerp(cn))
+      return (notify_fail("Die Ebene '"+n+"' existiert nicht oder die Angabe "
+        "war nicht eindeutig.\n"), 0);
+    ch = CHMASTER->list(this_object());
+    if(ch[lower_case(cn)][I_MASTER] != this_object())
+      return (notify_fail("Du bist nicht berechtigt die Beschreibung der Ebene"
+        " '"+cn+"' zu aendern.\n"), 0);
+    ch[lower_case(cn)][I_INFO] = descr;
+    write("Die Ebene '"+cn+"' hat ab sofort die Beschreibung:\n"+descr+"\n");
+    return 1;
+  }
+  if(sscanf(args, "%s=%s", sh, n) == 2 && sizeof(n))
+  {
+    mapping sc;
+    if(pointerp(tmp = CHMASTER->find(n, this_object())) || !tmp)
+      return (notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
+                          +(pointerp(tmp) ? implode(tmp, ", ") + "\n" :
+                            "Ebene '"+n+"' nicht gefunden!\n")), 0);
+    sc = QueryProp(P_CHANNEL_SHORT);
+    if(!sc) sc = ([]);
+    sc[sh] = tmp;
+    SetProp(P_CHANNEL_SHORT, sc);
+    shortcut = QueryProp(P_CHANNEL_SHORT);
+    write("'"+sh+"' wird jetzt als Abkuerzung fuer '"+tmp+"' anerkannt.\n");
+    return 1;
+  }
+  if(sscanf(args, "%s=", sh))
+  {
+    SetProp(P_CHANNEL_SHORT, m_copy_delete(QueryProp(P_CHANNEL_SHORT) || ([]), sh));
+    shortcut = QueryProp(P_CHANNEL_SHORT);
+    write("Du loeschst die Abkuerzung '"+sh+"'.\n");
+    return 1;
+  }
+  if(args == "an" || args == "ein")
+  {
+    mixed excl;
+    if(pointerp(QueryProp(P_SWAP_CHANNELS)))
+      SetProp(P_CHANNELS, QueryProp(P_SWAP_CHANNELS));
+    else
+      SetProp(P_CHANNELS, m_indices(CHMASTER->list(this_object())));
+    excl = RegisterChannels();
+    write("Du schaltest folgende Ebenen ein:\n"
+          +break_string(implode(QueryProp(P_CHANNELS) - excl, ", "), 78));
+    SetProp(P_SWAP_CHANNELS, 0);
+    return 1;
+  }
+  if(args == "aus")
+  {
+    SetProp(P_SWAP_CHANNELS, QueryProp(P_CHANNELS));
+    RemoveChannels();
+    SetProp(P_CHANNELS, ({}));
+    write("Du stellst die Ebenen ab.\n");
+    return 1;
+  }
+  pa = old_explode(args, " ");
+  if(!strstr("abkuerzungen", pa[0]))
+  {
+    string txt; txt = "";
+    if(sizeof(pa) > 1 && !strstr("standard", pa[1]))
+    {
+      write("Die Standard Abkuerzungen werden gesetzt.\n");
+      SetProp(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
+              + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
+    }
+    walk_mapping(QueryProp(P_CHANNEL_SHORT),
+                 lambda(({'i/*'*/, 'c, 'r}),
+                        ({#'+=, 'r/*'*/,
+                          ({#'sprintf/*'*/, "%5.5s = %s\n", 'i, 'c})})),
+                 &txt);
+    txt = sprintf("Folgende Abkuerzungen sind definiert:\n%-78#s\n",
+                  implode(sort_array(old_explode(txt, "\n"), #'>/*'*/), "\n"));
+    More(txt);
+    return 1;
+  }
+  if(!strstr("standard", pa[0]))
+    if(sizeof(pa) < 2)
+      return (notify_fail("Benutzung: ebene standard <Ebene>\n"
+                          +(QueryProp(P_STD_CHANNEL)
+                            ? "Momentan ist '"+QueryProp(P_STD_CHANNEL)
+                            +"' eingestellt.\n"
+                            : "Es ist keine Standardebene eingestellt.\n")),0);
+    else
+      if(pointerp(tmp = CHMASTER->find(pa[1], this_object())))
+        return (notify_fail("Das war keine eindeutige Angabe! "
+                            "Folgende Ebenen passen:\n"
+                            +break_string(implode(tmp, ", "), 78)), 0);
+      else
+        if(!tmp) return (notify_fail("Ebene '"+pa[1]+"' nicht gefunden!\n"),0);
+        else
+        {
+          write("'"+tmp+"' ist jetzt die Standardebene.\n");
+          SetProp(P_STD_CHANNEL, tmp);
+          return 1;
+        }
+  return(0);
+}
+