blob: ae71713f9f480136eb3e0e151f8cf5ae076dbfe5 [file] [log] [blame]
/* /std/channel_supervisor.c
//
// Der Standard-Supervisor fuer Ebenen. Sollte von allen Objekten geerbt
// werden, die Zugriffsrechte fuer Ebenen verwalten ("das Sagen" auf der Ebene
// haben).
// Das Objekt braucht ggf. eine eUID zum Dateizugriff. Zum Setzen dieser ist
// der Erbende verantwortlich.
// Standardmaessig wird /p/daemon/channeld.init[.testmud] eingelesen.
// Erbende koennen ihre Daten auch voellig anderweitig einlesen/ermitteln und
// Rechte voellig anders pruefen statt gegen ein Level zu pruefen.
// Das einzig wichtige fuer die Rechtepruefung ist die Funktion
// ch_check_access(), die vom CHANNELD gerufen wird. Sie muss 1 zurueckgeben,
// falls die Aktion erlaubt wird und 0 anderenfalls.
//
// Benutzung fuer Standardebenen:
// Dieses Objekt erben, ggf. eine eUID setzen und ch_read_init_file()
// rufen.
// Zusaetzlich sollte dieses Objekt aber auch ein Namen haben, weil es
// damit auf den Ebenen angezeigt wird. (D.h. minimal name() und Name()
// sollten implementiert/geerbt sein.)
*/
#pragma strict_types, rtt_checks
#pragma no_shadow, no_clone
#include <wizlevels.h>
#include <regexp.h>
#include "/p/daemon/channel.h"
#include <living/description.h>
/* Speichert Sende- und Empfangslevel sowie Flags zu den einzelnen Channeln.
mapping ch_access_data = ([ string channel_name : (<ch_access>) ]) */
struct ch_access {
int recv;
int send;
int flags;
};
// nicht nosave hier, damit man es zwar nosave erben kann, aber ggf. auch
// speichern kann
protected mapping ch_access_data = m_allocate(0, 1);
// oeffentlicher Name des Supervisors
protected string ch_sv_name = "Generischer SV";
protected void ch_set_sv_name(string newname)
{
ch_sv_name = newname;
}
public varargs string name(int casus,int demon)
{
return ch_sv_name;
}
public varargs string Name(int casus, int demon)
{
return capitalize(name( casus, demon )||"");
}
// ch_check_access() prueft die Zugriffsberechtigungen auf Ebenen.
//
// Wird vom CHANNELD gerufen.
// Gibt 1 zurueck, wenn Aktion erlaubt, 0 sonst.
//
// Verlassen (C_LEAVE) ist immer erlaubt. Die anderen Aktionen sind in zwei
// Gruppen eingeteilt:
// 1) RECV. Die Aktionen dieser Gruppe sind Suchen (C_FIND), Auflisten
// (C_LIST) und Betreten (C_JOIN).
// 2) SEND. Die Aktion dieser Gruppe ist zur Zeit nur Senden (C_SEND).
//
// Aktionen werden zugelassen, wenn Spieler/MagierLevel groesser ist als die
// fuer die jeweilige Aktionsgruppe RECV oder SEND festgelegte Stufe.
// Handelt es sich um eine Magierebene (<accessflags> enthaelt das Flag
// CH_ACCESS_WIZARD), muss die Magierstufe des Spielers groesser sein als die
// Mindeststufe der Ebene. Ansonsten wird gegen den Spielerlevel geprueft.
// Enthaelt <accessflags> das Flag CH_ACCESS_NOGUEST, darf die Ebene nicht von
// Gaesten benutzt werden.
//
// Wenn RECV_LVL oder SEND_LVL auf -1 gesetzt ist, sind die Aktionen der
// jeweiligen Gruppen komplett geblockt.
public int ch_check_access(string ch, object user, string cmd)
{
struct ch_access access = ch_access_data[ch];
// Wenn keine Information verfuegbar, ist der SV zwar als SV eingetragen,
// hat aber keine Daten. In dem Fall ist alles erlaubt. Das kann z.B.
// passieren, wenn der im .init angegeben SV nicht ladbar ist beim Laden des
// Channeld oder wenn beim Erstellen der Ebene explizit ein SV angegeben
// wird, der nix weiss.
if (!access)
return 1;
// <user> ist Gast, es sind aber keine Gaeste zugelassen? Koennen wir
// direkt ablehnen.
if ((access.flags & CH_ACCESS_NOGUEST) && ({int})user->QueryGuest())
return 0;
// Ebenso auf Magier- oder Seherebenen, wenn ein Spieler anfragt, der
// noch kein Seher ist.
if ((access.flags & CH_ACCESS_WIZARD) && query_wiz_level(user) < SEER_LVL)
return 0;
// Ebene ist Magierebene? Dann werden alle Stufenlimits gegen Magierlevel
// geprueft, ansonsten gegen Spielerlevel.
int level = (access.flags & CH_ACCESS_WIZARD
? query_wiz_level(user)
: ({int})user->QueryProp(P_LEVEL));
switch (cmd)
{
case C_FIND:
case C_LIST:
case C_JOIN:
if (access.recv == -1)
return 0;
if (access.recv <= level)
return 1;
break;
case C_SEND:
if (access.send == -1)
return 0;
if (access.send <= level)
return 1;
break;
// Verlassen ist immer erlaubt
case C_LEAVE:
return 1;
}
return 0;
}
// ch_store_access() - Angaben zu Zugriffsrechten fuer eine Ebene merken
// Angaben kommen in folgender Reihenfolge:
// string* chinfo = ({ channel_name, receive_level, send_level,
// adminflags, channelflags, description,
// supervisor })
// mapping &data ist im Regelfall das <ch_access_data>, was per
// Referenz uebergeben wird (auch wenn das nicht noetig ist,
// macht es klar, was beabsichtigt ist).
protected void ch_store_access(string* chinfo, mapping data)
{
object supervisor;
// Nur die Angabe des SV (Index 6) im initfile ist optional, alle Elemente
// davor muessen da sein. Wenn kein Supervisor angegeben ist, wird der
// Default-SV angenommen.
if (sizeof(chinfo) >= 7)
{
if (stringp(chinfo[6]) && sizeof(chinfo[6]))
supervisor = find_object(chinfo[6]);
}
else if (sizeof(chinfo) == 6)
supervisor = find_object(DEFAULTSV);
else
return;
// Nur Daten merken, wenn wir auch der Supervisor fuer die Ebene sein
// sollen.
if (supervisor != this_object())
return;
struct ch_access access = (<ch_access>
recv: to_int(chinfo[1]),
send: to_int(chinfo[2]),
flags: to_int(chinfo[3])
);
data[lower_case(chinfo[0])] = access;
// Rest der Ebenendaten interessiert uns nicht.
}
// Liest ein channeld.init file ein. Wenn keines angegeben wird, wird der
// das Standardfile fuers Mud eingelesen. Die Angaben werden in das Mapping
// <ch_access_data> uebernommen, dieses vorher aber nicht geloescht.
// Der Rueckgabewert ist < 0 fuer Fehler, ansonsten die Groesse von
// <ch_access_data> nach Einlesen des Files.
protected varargs int ch_read_init_file(string fname)
{
string ch_list;
if (!fname)
{
#if !defined(__TESTMUD__) && MUDNAME=="MorgenGrauen"
fname = CHMASTER ".init";
#else
fname = CHMASTER ".init.testmud";
#endif
}
ch_list = read_file(fname);
if (!stringp(ch_list))
return -1;
// Channeldatensaetze erzeugen, dazu zuerst Datenfile in Zeilen zerlegen
// "Allgemein: 0: 0: 0: 0: Allgemeine Unterhaltungsebene"
// Danach drueberlaufen und in Einzelfelder splitten, dabei gleich die
// Trennzeichen (Doppelpunkt, Tab und Space) rausfiltern.
foreach(string ch : old_explode(ch_list, "\n"))
{
if (ch[0]=='#')
continue;
ch_store_access(regexplode(ch, ":[ \t]*", RE_OMIT_DELIM),
&ch_access_data);
}
return sizeof(ch_access_data);
}
// Nur falls es mal gebraucht wird und damit es schon jetzt alle rufen
// koennen.
protected void create()
{
}
public varargs int remove(int silent)
{
destruct(this_object());
return 1;
}