Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/secure/bbmaster.c b/secure/bbmaster.c
new file mode 100644
index 0000000..9677f7f
--- /dev/null
+++ b/secure/bbmaster.c
@@ -0,0 +1,393 @@
+#pragma strict_types
+#pragma no_clone
+#pragma no_shadow
+#pragma no_inherit
+//#pragma pedantic
+//#pragma range_check
+#pragma warn_deprecated
+
+#include <wizlevels.h>
+#include <daemon.h>
+#include <events.h>
+#include <strings.h>
+#include <files.h>
+
+#define FTPSAVE "/secure/ARCH/ftpd"
+
+#define MAXLOGSIZE 2000000
+#define SMALLLOGSIZE 200000
+#define LOGTIME 120
+#define MAXBUFFSIZE 2000
+
+#define DEBUG(x) if (find_player("zesstra"))\
+ tell_object(find_player("zesstra"),\
+ "EDBG: "+x+"\n")
+
+// fuer FTP.
+private mapping monitored;
+
+
+#define D_LOGTIME 0 // Logendezeit, <int>
+#define D_FLAGS 1 // Flags
+#define D_ERSTIE 2 // Name des Ersties.
+#define D_IPSTRING 3
+#define D_INDEX 4 // Index fuer D_LOG, naechster freier index.
+#define D_LOG 5 // Logdaten, <mixed> (Array)
+/* Datenstruktur von D_LOG:
+ ({ ({<zeit>, <kommando>, <environment>}), .... })
+ */
+#define DL_TIME 0 // int
+#define DL_CMD 1 // string
+#define DL_ENV 2 // string
+private nosave mapping ldata = m_allocate(0,D_LOG);
+
+// Flags:
+#define FL_PERMANENT 1 // 'permanent', d.h. nicht nur kurz nach Einloggen
+#define FL_SYNC 2 // nicht puffern, synchron auf Platte schreiben.
+
+// Ja. Macht das bloss nicht nach.
+#define P_SECOND "second"
+
+public int query_bb();
+public void writebb( string msg );
+public varargs void BBWrite(string msg, int catmode);
+
+public int add( string user, int timeout );
+public int sub( string user );
+public void ftpbb( string user, string msg );
+
+private void scan_bb_opfer();
+private void DumpData(string uid, string erstie, string ip, int flags, mixed logdata);
+private void ProcessBuffer(string uid);
+private void RemoveTemporaryPlayer(string uid);
+
+public void create()
+{
+ seteuid( getuid(this_object()) );
+ restore_object( FTPSAVE );
+ scan_bb_opfer();
+ EVENTD->RegisterEvent(EVT_LIB_LOGIN, "Eventhandler", this_object());
+ EVENTD->RegisterEvent(EVT_LIB_LOGOUT, "Eventhandler", this_object());
+ log_file("ARCH/bbmaster.log", strftime("%c: bbmaster wurde geladen.\n"));
+}
+
+// Auf den asynchronen Logout-event zu warten ermoeglicht es theoretisch, 1-2s
+// das Log zu umgehen. Andererseits geht das ohnehin nur dann, wenn die
+// Logzeit eh abgelaufen ist.
+public void Eventhandler(string eid, object trigob, mixed data) {
+ if (previous_object() == find_object(EVENTD)) {
+ string uid;
+ if (objectp(trigob)
+ && strstr(load_name(trigob),"/std/shells/") == 0
+ && !trigob->QueryGuest()) {
+ // Bei Login und Logout den BBMode einschalten (weil der Loginevent ja
+ // erst 1-2s nach Einloggen abgearbeitet wird.
+ trigob->__set_bb(1);
+ uid=getuid(trigob);
+ }
+ else {
+ // kein Objekt mehr da. Vermutlich hat ein Spieler 'ende' gemacht, aber
+ // es koennte auch sein, dass jemand mit nem Selbstzerstoerer den Event
+ // gefakt hat. Aber selbst wenn, viel kann man damit nicht erreichen.
+ uid = data[E_PLNAME];
+ if (!stringp(uid)) return;
+ // Pruefung auf nicht-Anwesenheit von uid waere noch moeglich, hat aber
+ // Probleme, wenn ein Spieler sehr schnell wieder einloggt.
+ }
+
+ if (eid == EVT_LIB_LOGOUT && member(ldata,uid)) {
+ // Wenn Logout und es gibt Daten im Puffer, koennte man die evtl.
+ // wegschreiben oder loeschen.
+ ProcessBuffer(uid);
+ // auf jeden Fall temporaere Spieler entfernen. (Wichtig!)
+ RemoveTemporaryPlayer(uid);
+ }
+ }
+}
+
+// schreibt alle Puffer synchron, ohne Callout... Kann laggen.
+public int ProcessAllBuffers() {
+
+ if (extern_call() && !ARCH_SECURITY)
+ return -1;
+
+ foreach(string uid, int logtime, int flags, string erstie, string ip,
+ int index, mixed data: ldata) {
+ if (index) {
+ DumpData(uid, erstie, ip, flags, data);
+ ldata[uid,D_LOG]=({});
+ ldata[uid,D_INDEX]=0;
+ }
+ }
+ return 1;
+}
+
+private void ProcessBuffer(string uid) {
+
+ if (time() <= ldata[uid,D_LOGTIME]
+ && ldata[uid,D_INDEX]) {
+ // Daten wegschreiben, wenn Logzeit nicht abgelaufen. Sonst nicht.
+ call_out(#'DumpData, 2, uid, ldata[uid,D_ERSTIE], ldata[uid,D_IPSTRING],
+ ldata[uid,D_FLAGS], ldata[uid,D_LOG]);
+ }
+ ldata[uid,D_LOG] = ({});
+ ldata[uid,D_INDEX] = 0;
+}
+
+private void DumpData(string uid, string erstie, string ip, int flags, mixed logdata) {
+ string res = sprintf("\n%s%s, IP: %s\n", capitalize(uid),
+ (stringp(erstie) ? " ("+capitalize(erstie)+")" : ""),
+ (stringp(ip) ? ip : "Unbekannt"));
+ logdata-=({0});
+ foreach(mixed arr : logdata) {
+ res+=sprintf("%O: %O [%s]\n",
+ strftime("%y%m%d-%H%M%S",arr[DL_TIME]),
+ arr[DL_CMD], arr[DL_ENV] || "<unbekannt>");
+ }
+
+ //DEBUG("DumpData: "+res);
+ if (flags & FL_PERMANENT)
+ catch(log_file("ARCH/bb."+uid, res, MAXLOGSIZE));
+ else if (file_size(LIBLOGDIR"/ARCH/bbmaster") == FSIZE_DIR)
+ catch(log_file("ARCH/bbmaster/"+uid, res, SMALLLOGSIZE));
+ // kein else, in anderen Faellen werden die Daten verworfen.
+}
+
+private void AddTemporaryPlayer(string uid) {
+ // natuerlich nur, wenn noch nix eingetragen.
+ if (!member(ldata, uid)) {
+ object ob = find_player(uid) || find_netdead(uid);
+
+ mixed erstie;
+ if (ob)
+ erstie = (string)ob->QueryProp(P_SECOND);
+
+ ldata += ([uid: time() + LOGTIME + random(LOGTIME/2);
+ 0;
+ (stringp(erstie) ? erstie : 0);
+ query_ip_number(ob);
+ 0; ({})
+ ]);
+ }
+}
+
+private void RemoveTemporaryPlayer(string uid) {
+ if (!(ldata[uid,D_FLAGS] & FL_PERMANENT)) {
+ m_delete(ldata, uid);
+ }
+}
+
+
+// Vom Spielererobjekt bei Erschaffung in InitPlayer() gerufen.
+public int query_bb()
+{
+
+ if (load_name(previous_object())[0..11] != "/std/shells/")
+ return 0;
+
+ // in jedem Fall wird nun (temporaer) der BB-Modus aktiviert.
+ if (!previous_object()->QueryGuest())
+ previous_object()->__set_bb(1);
+
+ // nur fuer 'permanente' auch 1 zurueckgeben.
+ return ldata[getuid(previous_object()),D_FLAGS] & FL_PERMANENT;
+}
+
+
+
+// neue Funktion. Kriegt nur Kommandosstring uebergegen, werden ggf. gepuffert
+// und dann weggeschrieben.
+public varargs void BBWrite(string msg, int catmode) {
+
+ if ( !this_interactive() ||
+ (extern_call() &&
+ strstr(load_name(previous_object()), "/std/shells/") != 0 ) )
+ return;
+
+ string uid = getuid(this_interactive());
+
+ if (!member(ldata, uid))
+ AddTemporaryPlayer(uid);
+ else if (ldata[uid,D_LOGTIME] < time()) {
+ // Logzeit abgelaufen. -> ENDE.
+ if (ldata[uid,D_INDEX]) {
+ this_interactive()->__set_bb(0);
+ // es kann vorkommen, dass hier nen ProcessBuffer mit anderer uid
+ // drinhaengt. Ist aber egal, dann wird der Puffer halt naechstesmal
+ // geschrieben.
+ if (find_call_out(#'ProcessBuffer) == -1)
+ call_out(#'ProcessBuffer, 2, uid);
+ }
+ return;
+ }
+
+ // im synchronen Modus direkt auf Platte schreiben.
+ //DEBUG("BBWrite: Flags von +"+uid+": "+to_string(ldata[uid,D_FLAGS])
+ // +"\n");
+ if (ldata[uid,D_FLAGS] & FL_SYNC) {
+ //DEBUG("BBWrite: Syncmodus\n");
+ if (!catmode) {
+ msg = sprintf("%s: %s [%O]\n", strftime("%y%m%d-%H%M%S"),
+ msg, environment(this_interactive()));
+ }
+ else
+ msg = msg + "\n";
+ log_file( "ARCH/bb."+uid, msg, MAXLOGSIZE );
+ return;
+ }
+
+ // alle anderen werden erstmal gepuffert.
+
+ // wenn catmode und nen Index > 0 wird der Kram an den vorherigen Eintragen
+ // angehaengt.
+ int index = ldata[uid,D_INDEX];
+ if (catmode && index > 0) {
+ --index;
+ ldata[uid,D_LOG][index][DL_CMD] += msg;
+ }
+ else {
+ // Puffer vergroessern?
+ if (index >= sizeof(ldata[uid,D_LOG]))
+ ldata[uid,D_LOG]+=allocate(100);
+ ldata[uid,D_LOG][index] = ({ time(), msg,
+ object_name(environment(this_interactive()))
+ });
+ ldata[uid,D_INDEX]++;
+ // es kann vorkommen, dass hier nen ProcessBuffer mit anderer uid
+ // drinhaengt. Ist aber egal, dann wird der Puffer halt naechstesmal
+ // geschrieben.
+ if (index > MAXBUFFSIZE
+ && find_call_out(#'ProcessBuffer) == -1)
+ call_out(#'ProcessBuffer, 2, uid);
+ }
+}
+
+// Alte Funktion, kriegt Strings, teilweise mit Datum, teilweise ohne,
+// schrieb frueher nur weg. msg faengt entweder mit einem Datum/Zeit-String
+// oder mit einem "->" an.
+public void writebb( string msg )
+{
+ int catmode;
+
+ if ( !this_interactive() ||
+ (extern_call() &&
+ strstr(load_name(previous_object()), "/std/shells/") != 0 ) )
+ return;
+
+ // erstmal String bereinigen.
+ msg = trim(msg,TRIM_RIGHT,"\n");
+ if (strstr(msg,"->") == 0) {
+ catmode=1;
+ msg= " -> " + msg[2..];
+ }
+ else {
+ // faengt mit Datumsstring an, erstes Leerzeichen ab dem zehnten Zeichen
+ // suchen und von dort abschneiden.
+ msg = msg[strstr(msg," ",10)+1 ..];
+ }
+
+ // Dann weitergeben
+ BBWrite(msg, catmode);
+}
+
+private void scan_bb_opfer()
+{
+ string* lines;
+ object pl;
+ string uid;
+
+ // diese user werden 'permanent' ueberwacht, nicht nur direkt nach dem
+ // Einloggen.
+ lines = explode( lower_case( read_file("/secure/ARCH/BB_OPFER.dump")
+ || "" ), "\n" )[2..];
+
+ foreach(string line : lines) {
+ if( sizeof(line) && line[0] != '#' ) {
+ uid=line[0 .. member(line,' ')-1];
+ AddTemporaryPlayer(uid);
+ ldata[uid,D_LOGTIME] = __INT_MAX__;
+ ldata[uid,D_FLAGS] = FL_PERMANENT;
+ pl = find_player(uid) || find_netdead(uid);
+ if (pl)
+ pl->__set_bb(1);
+ }
+ }
+}
+
+// Neuladen ist kein grosses Problem, weil der bbmaster ja automatisch
+// neugeladen wird. Nebeneffekt ist lediglich, dass fuer alle laufenden Logs
+// die Logzeit wieder von vorne anfaengt. Da das Schreiben der Puffer aber Lag
+// verursachen kann, duerfen es nur EM+.
+public varargs int remove(int silent) {
+
+ if (!ARCH_SECURITY)
+ return 0;
+
+ log_file("ARCH/bbmaster.log", strftime("%c: remove() called.\n"));
+
+ // alle Puffer leeren...
+ // ProcessAllBuffers() wird hierbei _ohne_ Limits aufgerufen! Kann fieses
+ // Lag erzeugen, aber sonst wurde der Kram evtl. nicht ordentlich
+ // geschrieben.
+ limited(#'ProcessAllBuffers);
+ destruct(this_object());
+ return 1;
+}
+
+
+// Alles ab hier nur zum Ueberwachen von FTP-Aktivitaeten.
+private int player_exists( string user )
+{
+ if ( !stringp( user ) || sizeof( user ) < 2 )
+ return 0;
+
+ return file_size( "/save/" + user[0..0] + "/" + user + ".o" ) > 0;
+}
+
+public int add( string user, int timeout )
+{
+ if ( !ARCH_SECURITY || process_call() )
+ return -1;
+
+ if( !stringp(user) || !player_exists(lower_case(user)) || !intp(timeout) ||
+ !timeout )
+ return -2;
+
+ monitored[lower_case(user)] = timeout;
+ save_object( FTPSAVE );
+
+ return 1;
+}
+
+
+public int sub( string user )
+{
+ if ( !ARCH_SECURITY || process_call() )
+ return -1;
+
+ if( !stringp(user) || !member( monitored, lower_case(user) ) )
+ return -2;
+
+ m_delete( monitored, lower_case(user) );
+ save_object( FTPSAVE );
+
+ return 1;
+}
+
+
+public void ftpbb( string user, string msg )
+{
+ if( getuid(previous_object()) != ROOTID )
+ return;
+
+ if ( ldata[user,D_FLAGS] & FL_PERMANENT )
+ log_file( "ARCH/bb."+user, msg, 2000000 );
+
+ if ( monitored[user] ){
+ if ( monitored[user] > 0 && monitored[user] < time() )
+ sub( user );
+ else
+ CHMASTER->send( "FTP", capitalize(user), msg );
+ }
+}
+