blob: ae71713f9f480136eb3e0e151f8cf5ae076dbfe5 [file] [log] [blame]
Zesstra10341b82020-09-12 13:02:54 +02001/* /std/channel_supervisor.c
Zesstra0caa8e42020-08-11 22:51:59 +02002//
Zesstra10341b82020-09-12 13:02:54 +02003// Der Standard-Supervisor fuer Ebenen. Sollte von allen Objekten geerbt
4// werden, die Zugriffsrechte fuer Ebenen verwalten ("das Sagen" auf der Ebene
5// haben).
6// Das Objekt braucht ggf. eine eUID zum Dateizugriff. Zum Setzen dieser ist
7// der Erbende verantwortlich.
8// Standardmaessig wird /p/daemon/channeld.init[.testmud] eingelesen.
9// Erbende koennen ihre Daten auch voellig anderweitig einlesen/ermitteln und
10// Rechte voellig anders pruefen statt gegen ein Level zu pruefen.
11// Das einzig wichtige fuer die Rechtepruefung ist die Funktion
12// ch_check_access(), die vom CHANNELD gerufen wird. Sie muss 1 zurueckgeben,
13// falls die Aktion erlaubt wird und 0 anderenfalls.
14//
15// Benutzung fuer Standardebenen:
16// Dieses Objekt erben, ggf. eine eUID setzen und ch_read_init_file()
17// rufen.
18// Zusaetzlich sollte dieses Objekt aber auch ein Namen haben, weil es
19// damit auf den Ebenen angezeigt wird. (D.h. minimal name() und Name()
20// sollten implementiert/geerbt sein.)
21*/
Zesstra0caa8e42020-08-11 22:51:59 +020022
Zesstra10341b82020-09-12 13:02:54 +020023#pragma strict_types, rtt_checks
Zesstra0caa8e42020-08-11 22:51:59 +020024#pragma no_shadow, no_clone
25
26#include <wizlevels.h>
Zesstra10341b82020-09-12 13:02:54 +020027#include <regexp.h>
Zesstra0caa8e42020-08-11 22:51:59 +020028#include "/p/daemon/channel.h"
29#include <living/description.h>
30
Zesstra0caa8e42020-08-11 22:51:59 +020031/* Speichert Sende- und Empfangslevel sowie Flags zu den einzelnen Channeln.
Zesstra10341b82020-09-12 13:02:54 +020032 mapping ch_access_data = ([ string channel_name : (<ch_access>) ]) */
33struct ch_access {
34 int recv;
35 int send;
36 int flags;
37};
38// nicht nosave hier, damit man es zwar nosave erben kann, aber ggf. auch
39// speichern kann
40protected mapping ch_access_data = m_allocate(0, 1);
Zesstra0caa8e42020-08-11 22:51:59 +020041
Zesstra10341b82020-09-12 13:02:54 +020042// oeffentlicher Name des Supervisors
43protected string ch_sv_name = "Generischer SV";
44
45protected void ch_set_sv_name(string newname)
46{
47 ch_sv_name = newname;
48}
49
50public varargs string name(int casus,int demon)
51{
52 return ch_sv_name;
53}
54
55public varargs string Name(int casus, int demon)
56{
57 return capitalize(name( casus, demon )||"");
58}
59
60// ch_check_access() prueft die Zugriffsberechtigungen auf Ebenen.
Zesstra0caa8e42020-08-11 22:51:59 +020061//
Zesstra10341b82020-09-12 13:02:54 +020062// Wird vom CHANNELD gerufen.
Zesstra0caa8e42020-08-11 22:51:59 +020063// Gibt 1 zurueck, wenn Aktion erlaubt, 0 sonst.
Zesstra0caa8e42020-08-11 22:51:59 +020064//
65// Verlassen (C_LEAVE) ist immer erlaubt. Die anderen Aktionen sind in zwei
66// Gruppen eingeteilt:
67// 1) RECV. Die Aktionen dieser Gruppe sind Suchen (C_FIND), Auflisten
68// (C_LIST) und Betreten (C_JOIN).
69// 2) SEND. Die Aktion dieser Gruppe ist zur Zeit nur Senden (C_SEND).
70//
71// Aktionen werden zugelassen, wenn Spieler/MagierLevel groesser ist als die
72// fuer die jeweilige Aktionsgruppe RECV oder SEND festgelegte Stufe.
Zesstra10341b82020-09-12 13:02:54 +020073// Handelt es sich um eine Magierebene (<accessflags> enthaelt das Flag
74// CH_ACCESS_WIZARD), muss die Magierstufe des Spielers groesser sein als die
75// Mindeststufe der Ebene. Ansonsten wird gegen den Spielerlevel geprueft.
76// Enthaelt <accessflags> das Flag CH_ACCESS_NOGUEST, darf die Ebene nicht von
77// Gaesten benutzt werden.
Zesstra0caa8e42020-08-11 22:51:59 +020078//
79// Wenn RECV_LVL oder SEND_LVL auf -1 gesetzt ist, sind die Aktionen der
80// jeweiligen Gruppen komplett geblockt.
81
Zesstra10341b82020-09-12 13:02:54 +020082public int ch_check_access(string ch, object user, string cmd)
Zesstra0caa8e42020-08-11 22:51:59 +020083{
Zesstra10341b82020-09-12 13:02:54 +020084 struct ch_access access = ch_access_data[ch];
Zesstraf828c3b2020-09-28 22:11:04 +020085 // Wenn keine Information verfuegbar, ist der SV zwar als SV eingetragen,
86 // hat aber keine Daten. In dem Fall ist alles erlaubt. Das kann z.B.
87 // passieren, wenn der im .init angegeben SV nicht ladbar ist beim Laden des
88 // Channeld oder wenn beim Erstellen der Ebene explizit ein SV angegeben
89 // wird, der nix weiss.
90 if (!access)
91 return 1;
Zesstra10341b82020-09-12 13:02:54 +020092 // <user> ist Gast, es sind aber keine Gaeste zugelassen? Koennen wir
Zesstra0caa8e42020-08-11 22:51:59 +020093 // direkt ablehnen.
Zesstra10341b82020-09-12 13:02:54 +020094 if ((access.flags & CH_ACCESS_NOGUEST) && ({int})user->QueryGuest())
Zesstra0caa8e42020-08-11 22:51:59 +020095 return 0;
96
97 // Ebenso auf Magier- oder Seherebenen, wenn ein Spieler anfragt, der
98 // noch kein Seher ist.
Zesstra10341b82020-09-12 13:02:54 +020099 if ((access.flags & CH_ACCESS_WIZARD) && query_wiz_level(user) < SEER_LVL)
Zesstra0caa8e42020-08-11 22:51:59 +0200100 return 0;
101
102 // Ebene ist Magierebene? Dann werden alle Stufenlimits gegen Magierlevel
103 // geprueft, ansonsten gegen Spielerlevel.
Zesstra10341b82020-09-12 13:02:54 +0200104 int level = (access.flags & CH_ACCESS_WIZARD
105 ? query_wiz_level(user)
106 : ({int})user->QueryProp(P_LEVEL));
Zesstra0caa8e42020-08-11 22:51:59 +0200107
108 switch (cmd)
109 {
110 case C_FIND:
111 case C_LIST:
112 case C_JOIN:
Zesstra10341b82020-09-12 13:02:54 +0200113 if (access.recv == -1)
Zesstra0caa8e42020-08-11 22:51:59 +0200114 return 0;
Zesstra10341b82020-09-12 13:02:54 +0200115 if (access.recv <= level)
Zesstra0caa8e42020-08-11 22:51:59 +0200116 return 1;
117 break;
118
119 case C_SEND:
Zesstra10341b82020-09-12 13:02:54 +0200120 if (access.send == -1)
Zesstra0caa8e42020-08-11 22:51:59 +0200121 return 0;
Zesstra10341b82020-09-12 13:02:54 +0200122 if (access.send <= level)
Zesstra0caa8e42020-08-11 22:51:59 +0200123 return 1;
124 break;
125
126 // Verlassen ist immer erlaubt
127 case C_LEAVE:
128 return 1;
Zesstra0caa8e42020-08-11 22:51:59 +0200129 }
130 return 0;
131}
132
Zesstra10341b82020-09-12 13:02:54 +0200133// ch_store_access() - Angaben zu Zugriffsrechten fuer eine Ebene merken
134// Angaben kommen in folgender Reihenfolge:
135// string* chinfo = ({ channel_name, receive_level, send_level,
136// adminflags, channelflags, description,
137// supervisor })
138// mapping &data ist im Regelfall das <ch_access_data>, was per
139// Referenz uebergeben wird (auch wenn das nicht noetig ist,
140// macht es klar, was beabsichtigt ist).
141protected void ch_store_access(string* chinfo, mapping data)
Zesstra0caa8e42020-08-11 22:51:59 +0200142{
Zesstra10341b82020-09-12 13:02:54 +0200143 object supervisor;
Zesstra0caa8e42020-08-11 22:51:59 +0200144
Zesstra10341b82020-09-12 13:02:54 +0200145 // Nur die Angabe des SV (Index 6) im initfile ist optional, alle Elemente
146 // davor muessen da sein. Wenn kein Supervisor angegeben ist, wird der
147 // Default-SV angenommen.
148
149 if (sizeof(chinfo) >= 7)
Zesstra0caa8e42020-08-11 22:51:59 +0200150 {
Zesstra10341b82020-09-12 13:02:54 +0200151 if (stringp(chinfo[6]) && sizeof(chinfo[6]))
152 supervisor = find_object(chinfo[6]);
Zesstra0caa8e42020-08-11 22:51:59 +0200153 }
Zesstra10341b82020-09-12 13:02:54 +0200154 else if (sizeof(chinfo) == 6)
155 supervisor = find_object(DEFAULTSV);
156 else
157 return;
158
159 // Nur Daten merken, wenn wir auch der Supervisor fuer die Ebene sein
160 // sollen.
161 if (supervisor != this_object())
162 return;
163
164 struct ch_access access = (<ch_access>
165 recv: to_int(chinfo[1]),
166 send: to_int(chinfo[2]),
167 flags: to_int(chinfo[3])
168 );
169
170 data[lower_case(chinfo[0])] = access;
171 // Rest der Ebenendaten interessiert uns nicht.
172}
173
174// Liest ein channeld.init file ein. Wenn keines angegeben wird, wird der
175// das Standardfile fuers Mud eingelesen. Die Angaben werden in das Mapping
176// <ch_access_data> uebernommen, dieses vorher aber nicht geloescht.
177// Der Rueckgabewert ist < 0 fuer Fehler, ansonsten die Groesse von
178// <ch_access_data> nach Einlesen des Files.
179protected varargs int ch_read_init_file(string fname)
180{
181 string ch_list;
182 if (!fname)
183 {
184#if !defined(__TESTMUD__) && MUDNAME=="MorgenGrauen"
185 fname = CHMASTER ".init";
186#else
187 fname = CHMASTER ".init.testmud";
188#endif
189 }
190
191 ch_list = read_file(fname);
192 if (!stringp(ch_list))
193 return -1;
194
195 // Channeldatensaetze erzeugen, dazu zuerst Datenfile in Zeilen zerlegen
196 // "Allgemein: 0: 0: 0: 0: Allgemeine Unterhaltungsebene"
197 // Danach drueberlaufen und in Einzelfelder splitten, dabei gleich die
198 // Trennzeichen (Doppelpunkt, Tab und Space) rausfiltern.
199 foreach(string ch : old_explode(ch_list, "\n"))
200 {
201 if (ch[0]=='#')
202 continue;
203 ch_store_access(regexplode(ch, ":[ \t]*", RE_OMIT_DELIM),
204 &ch_access_data);
205 }
206 return sizeof(ch_access_data);
207}
208
209// Nur falls es mal gebraucht wird und damit es schon jetzt alle rufen
210// koennen.
211protected void create()
212{
213}
214
215public varargs int remove(int silent)
216{
217 destruct(this_object());
218 return 1;
Zesstra0caa8e42020-08-11 22:51:59 +0200219}
220