blob: f9f40a13c95bc3935edffdaeb9758f5fbb58e7f8 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// master.c -- master object
4//
5// $Id: master.c 9530 2016-03-17 19:59:01Z Zesstra $
Zesstra9dd50132019-11-28 21:42:14 +01006#pragma strict_types
7#pragma no_clone
8#pragma no_shadow
9#pragma no_inherit
10#pragma verbose_errors
11#pragma combine_strings
12//#pragma pedantic
MG Mud User88f12472016-06-24 23:31:02 +020013#pragma range_check
14#pragma warn_deprecated
15
16#include "/sys/files.h"
17#include "/sys/interactive_info.h"
18#include "/sys/driver_info.h"
19
MG Mud User88f12472016-06-24 23:31:02 +020020//for limited, set_limit(), etc. Abs. Pfad noetig, da noch kein Include-Hook
21#include "/sys/rtlimits.h"
22#include "/sys/debug_info.h"
MG Mud User88f12472016-06-24 23:31:02 +020023#include "/sys/configuration.h"
Zesstraa6068542019-09-30 23:21:45 +020024#include "/sys/driver_hook.h"
MG Mud User88f12472016-06-24 23:31:02 +020025#include "/sys/regexp.h"
26
Zesstra9dd50132019-11-28 21:42:14 +010027#include "/secure/master.h"
28#include "/secure/config.h"
MG Mud User88f12472016-06-24 23:31:02 +020029// Module des Master einfuegen. Per #include, damits geringfuegig schneller.
30// Da die Module ja nirgendwo sonst geerbt werden koennten, ist dies
31// ausnahmsweise OK. ;)
32#include "/secure/master/destruct.c"
Zesstra9dd50132019-11-28 21:42:14 +010033#include "/secure/master/userinfo.c"
34#include "/secure/master/file_access.c"
35#include "/secure/master/misc.c"
36#include "/secure/master/players_deny.c"
MG Mud User88f12472016-06-24 23:31:02 +020037#include "/secure/master/autoinclude.c"
Zesstra9dd50132019-11-28 21:42:14 +010038#include "/secure/master/network.c"
39#include "/secure/master/domain.c"
40#include "/secure/master/guild.c"
41
MG Mud User88f12472016-06-24 23:31:02 +020042
43// Fuer Logfile(-Rotation)
44#define RESETINT 3600 // jede Stunde
45#define LOGROTATE (24*2) // alle 48h
46#define LOGFILEAGE (RESETINT*LOGROTATE) // alle 2 tage wechseln
47#define LOGNUM 3 // Anzahl der Logfiles
48
49private nosave int logrotate_counter; //READ_FILE alle LOGROTATE Resets rotieren
50// Wird gerade versucht, die simul_efuns zu laden? Wenn ja, duerfen keine
51// sefuns gerufen werden.
52private nosave int loading_simul_efuns;
53// wird gerade ein Fehler bearbeitet? Dient zur Erkennung von Rekursionen in
54// der Fehlerbehandlung
55private nosave int handling_error;
56
57// #####################
58//######################## Start des Masters ############################
59// #####################
60
61// Initialisierung des Masters
62//arg==0: Mud startet gerade, arg==1: Master wurde reaktiviert,
63//arg==2: Master reaktiviert (Variablen weg), arg==3: Master wurde
64//neugeladen.
65protected void inaugurate_master(int arg) {
66
67 set_driver_hook(H_REGEXP_PACKAGE, RE_TRADITIONAL);
Bugfix05c09d72017-02-14 21:26:20 +010068
Zesstra86607bb2017-06-17 19:02:40 +020069 efun::configure_object(this_object(), OC_EUID, ROOTID);
Bugfix05c09d72017-02-14 21:26:20 +010070
71 // Bei Neustart wizinfo initialisieren und ggf. Ordner in /data erstellen.
72 if (!arg)
73 {
74 set_extra_wizinfo(0, allocate(BACKBONE_WIZINFO_SIZE));
75 CreateDataDirectories();
76 }
77
Zesstra9dd50132019-11-28 21:42:14 +010078 userinfo_init();
MG Mud User88f12472016-06-24 23:31:02 +020079 LoadPLDenylists();
80
81 // Was soll vor jede Datei geschrieben werden?
82 set_driver_hook(H_AUTO_INCLUDE, #'autoincludehook);
83
84 //div. Listen einlesen
85 ReloadBanishFile();
86 ReloadDeputyFile();
87 ReloadInsecureFile();
Bugfix05c09d72017-02-14 21:26:20 +010088
MG Mud User88f12472016-06-24 23:31:02 +020089 //simul_efun.c nach inaugurate_master() starten und initialisieren,
90 //(so richtig seh ich den Sinn hier momentan nicht ein...
91 //call_out("start_simul_efun",0);
92
93 // Reset festsetzen (1h)
94 set_next_reset(RESETINT);
95
96 // Driver konfigurieren
97 // Lagerkennung erst ne Minute spaeter, waehrend preload darfs momentan
98 // ruhig laggen (Zeit: vorlaeufig 1min)
Zesstra92bb2dd2019-11-28 21:45:19 +010099 call_out(#'configure_driver, 60, DC_LONG_EXEC_TIME, 200000);
Zesstra879e6e12019-09-27 16:23:49 +0200100
MG Mud User88f12472016-06-24 23:31:02 +0200101 // Hooks setzen
Zesstra879e6e12019-09-27 16:23:49 +0200102
103 // Standard-Encoding fuer Dateien
104 set_driver_hook(H_FILE_ENCODING, "UTF-8");
105 // Und Encoding fuer Dateinamen im Filesystem
106 configure_driver(DC_FILESYSTEM_ENCODING, "UTF-8");
Zesstraa1701ed2020-01-16 23:06:09 +0100107 // Standard-Encoding fuer Interactives
Zesstra0ebec872020-01-17 00:24:57 +0100108 configure_interactive(0, IC_ENCODING, "ASCII//TRANSLIT");
Zesstra879e6e12019-09-27 16:23:49 +0200109
MG Mud User88f12472016-06-24 23:31:02 +0200110 // Standardincludeverzeichnisse fuer #include <>
111 set_driver_hook(H_INCLUDE_DIRS, ({"/secure/","/sys/"}) );
Zesstra879e6e12019-09-27 16:23:49 +0200112
MG Mud User88f12472016-06-24 23:31:02 +0200113 //Nach dem Laden/Clonen create() im Objekt rufen
114 set_driver_hook(H_CREATE_CLONE, "create");
115 set_driver_hook(H_CREATE_OB, "create");
116 set_driver_hook(H_CREATE_SUPER, "create_super");
117
118 // Bei Reset reset() im Objekt aufrufen
119 set_driver_hook(H_RESET, "reset");
Zesstra879e6e12019-09-27 16:23:49 +0200120
MG Mud User88f12472016-06-24 23:31:02 +0200121 // Zum Aufraeumen clean_up() im Objekt aufrufen
122 set_driver_hook(H_CLEAN_UP, "clean_up");
123
124 // Jede Eingabe wird ueber modify_command gelenkt
125 set_driver_hook(H_MODIFY_COMMAND, "modify_command");
126 // Dieser Hook ist mandatory, aber wird nur benutzt, wenn via
127 // set_modify_command() aktiviert - was wir nicht (mehr) tun. Insofern ist
128 // das Relikt aus alten Zeiten.
129 //set_driver_hook(H_MODIFY_COMMAND_FNAME, "modify_command");
130
131 // Standard-Fehlermeldung
132 //set_driver_hook(H_NOTIFY_FAIL, "Wie bitte?\n");
133 set_driver_hook(H_NOTIFY_FAIL, function string (string cmd, object tp)
Zesstrad872d182019-11-28 20:13:02 +0100134 {if (tp && stringp(cmd=({string})tp->QueryProp(P_DEFAULT_NOTIFY_FAIL)))
MG Mud User88f12472016-06-24 23:31:02 +0200135 return(cmd);
136 return("Wie bitte?\n");});
137
138 // Was machen bei telnet_neg
139 set_driver_hook(H_TELNET_NEG,"telnet_neg");
MG Mud User88f12472016-06-24 23:31:02 +0200140
141 // Promptbehandlung: Defaultprompt setzen und dafuer sorgen, dass alle
142 // Promptausgaben durch print_prompt im Interactive laufen, damit das EOR
143 // angehaengt wird.
144 set_driver_hook(H_PRINT_PROMPT, "print_prompt");
145 set_driver_hook(H_DEFAULT_PROMPT, "> ");
146
147 // EUID und UID muessen neue Objekte auch noch kriegen, Hooks dafuer setzen
148 set_driver_hook(H_LOAD_UIDS, #'load_uid_hook);
149 set_driver_hook(H_CLONE_UIDS, #'clone_uid_hook);
150
151 // Meldung bei vollem Mud
152 set_driver_hook(H_NO_IPC_SLOT, "Momentan sind leider zuviele Spieler im "
153 +MUDNAME+" eingeloggt.\nBitte komm doch etwas spaeter nochmal "
154 "vorbei!\n");
155
156 // Nun der beruechtigte Move-Hook ...
157 // (bewegt objekt und ruft alle notwendigen inits auf)
158 // Hier wird H_MOVE_OBJECT0 benutzt, d.h. die lambda wird an das aktuelle
159 // Objekt vor Ausfuehrung gebunden, nicht an 'item', was move_objet()
160 // uebergeben wurde.
161 set_driver_hook(H_MOVE_OBJECT0,
162 unbound_lambda(({'item,'dest}),
163 ({#',, // item!=this_object?
164 ({#'?,({#'!=,'item,({#'this_object})}),
165 ({#'raise_error, // ->Fehler!
166 "Illegal to move other object than this_object()\n"}) }),
Zesstra1b809c72018-03-02 00:31:58 +0100167 ({#'=,'oldenv,({#'environment,'item}) }), // altes Env merken
MG Mud User88f12472016-06-24 23:31:02 +0200168 ({#'efun::set_environment,'item,'dest}), // item nach dest bewegen
169 ({#'?,
170 ({#'living,'item}), // living(item)?
171 ({#',,
172 ({#'efun::set_this_player,'item}), // set_this_player(item)
Zesstra1b809c72018-03-02 00:31:58 +0100173 ({#'call_other,'dest,"init",'oldenv}),// dest->init(oldenv)
MG Mud User88f12472016-06-24 23:31:02 +0200174 ({#'?!,
175 ({#'&&, // !objectp(item)||
176 ({#'objectp, 'item}), // env(item)!=dest?
177 ({#'==,({#'environment, 'item}),'dest})}),
178 ({#'return})})})}), // -> fertig
179 ({#'=,'others,({#'-,({#'all_inventory,'dest}),({#'({,'item})})}),
180#ifdef EMACS_NERV
181 }) // Emacs kann ({#'({ nicht parsen // others=all_inv(dest)-
182#endif // ({item})
Zesstra1b809c72018-03-02 00:31:58 +0100183 ({#'filter,'others,lambda(({'ob,'item,'lastenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200184 ({#'?,
185 ({#'&&,
186 ({#'objectp,'item}), // objectp(item)&&
187 ({#'living,'ob}), // living(ob)&&
188 ({#'==,({#'environment,'item}),({#'environment,'ob})})}),
189 ({#',, // env(item)==env(ob)?
190 ({#'efun::set_this_player, 'ob}), // set_this_player(ob)
Zesstra1b809c72018-03-02 00:31:58 +0100191 ({#'call_other,'item, "init",'lastenv}) // item->init(lastenv)
192 })})),'item,'oldenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200193 ({#'?,
194 ({#'living,'item}), // living(item)?
195 ({#',,
196 ({#'efun::set_this_player,'item}), // set_this_player(item)
Zesstra1b809c72018-03-02 00:31:58 +0100197 ({#'filter,'others,lambda(({'ob,'item,'lastenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200198 ({#'?,
199 ({#'&&,
200 ({#'objectp,'item}), // objectp(item)&&
201 ({#'objectp,'ob}), // objectp(ob)&&
202 ({#'==,({#'environment,'item}),({#'environment,'ob})})
203 }), // env(item)==env(ob)?
Zesstra1b809c72018-03-02 00:31:58 +0100204 ({#'call_other,'ob,"init",'lastenv}) // ob->init(lastenv)
205 })),'item, 'oldenv})})}),
MG Mud User88f12472016-06-24 23:31:02 +0200206 ({#'?,
207 ({#'&&,
208 ({#'objectp,'item}), // objectp(item)&&
209 ({#'living,'dest}), // living(dest)&&
210 ({#'==,({#'environment,'item}),'dest})// env(item)==dest?
211 }),
212 ({#',,
213 ({#'efun::set_this_player,'dest}), // set_this_player(dest)
Zesstra1b809c72018-03-02 00:31:58 +0100214 ({#'call_other,'item,"init",'oldenv})})})}))); //item->init(oldenv)
MG Mud User88f12472016-06-24 23:31:02 +0200215 DEBUG("Master inaugurated");
216 return;
217}
218
219// epilog() gibt die Dateien zurueck, die vorgeladen werden muessen
220protected string *epilog(int eflag) {
221 string *files, *domains;
222 int i;
223
Zesstra86607bb2017-06-17 19:02:40 +0200224 efun::configure_object(this_object(), OC_EUID, ROOTID);
MG Mud User88f12472016-06-24 23:31:02 +0200225 ReloadBanishFile();
226 ReloadDeputyFile();
227 ReloadInsecureFile();
228
229 if (eflag) {
Zesstrad77ab422019-09-27 17:39:27 +0200230 debug_message(
231 "epilog(): -e angegeben -> Preloading unterdrueckt ...\n",
232 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200233 return 0;
234 }
235
Zesstrad77ab422019-09-27 17:39:27 +0200236 debug_message("Preloading gestartet.\n", DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200237
238 //Files fuers Preloading und Regionen holen
239 files=explode_files("/std/preload_file") + explode_files("/d/preload_file");
240 domains=get_domains() + ({"erzmagier"}); // EM haben auch ein Preload File
241
242 for (i=sizeof(domains);i--;)
243 files+=explode_files("/d/"+domains[i]+"/preload_file");
Zesstrad77ab422019-09-27 17:39:27 +0200244
MG Mud User88f12472016-06-24 23:31:02 +0200245 return files;
246}
247
248// preload() wird fuer jeder Datei im Preload einmal durchlaufen
249protected void preload(string file) {
250 string err;
251 string name;
252 int *res, zeit;
253
254 // Kein richtiger Dateiname: fertig
255 if(!file || !file[0] || file[0] == ';' || file_size(file+".c") < 0) return;
256
257 // Kein Besitzer -> Meldung ausgeben, fertig
258 if (!(name=creator_file(file)))
259 {
Zesstrad77ab422019-09-27 17:39:27 +0200260 debug_message(
261 sprintf("preload: Kein Besitzer gefunden fuer Datei %s.\n",file),
262 DMSG_STDOUT|DMSG_STDERR);
MG Mud User88f12472016-06-24 23:31:02 +0200263 return;
264 }
265
Zesstra86607bb2017-06-17 19:02:40 +0200266 efun::configure_object(this_object(), OC_EUID, name);
MG Mud User88f12472016-06-24 23:31:02 +0200267
268 // Dann mal laden .. dabei Zeit messen
269 zeit = apply(#'+,rusage()[0..1]);
270
271 // Waehrend des Preloads sind 1.5MTicks leider nicht soviel, insb. wenn
272 // sowas wie der channeld jede menge Objekte laden muss, die wiederum erst
273 // das ganze Geraffel aus /std/ laden. Daher hier einfach mal fuers Preload
274 // die Grenze hoch.
275 err = catch(limited(#'load_object,({5000000}),file));
276
277 if (err != 0)
Zesstrad77ab422019-09-27 17:39:27 +0200278 debug_message(sprintf("\nFehler beim Laden von %s:\n%s\n",file,err),
279 DMSG_STDOUT|DMSG_STDERR);
MG Mud User88f12472016-06-24 23:31:02 +0200280 else
281 {
Zesstrad77ab422019-09-27 17:39:27 +0200282 // Datei, Besitzer und Ladezeit ausgeben
MG Mud User88f12472016-06-24 23:31:02 +0200283 zeit=apply(#'+,rusage()[0..1])-zeit;
Zesstrad77ab422019-09-27 17:39:27 +0200284 debug_message(sprintf("%-50s%-15s (%2d.%:02d s)\n",
285 file, name, zeit/1000,zeit%1000));
MG Mud User88f12472016-06-24 23:31:02 +0200286 }
287
288 // Noch EUID zuruecksetzen
Zesstra86607bb2017-06-17 19:02:40 +0200289 efun::configure_object(this_object(), OC_EUID, ROOTID);
MG Mud User88f12472016-06-24 23:31:02 +0200290
291 return;
292}
293
294//simul_efun.c laden oder die spare_simul_efun.c als Fallback
295//es ist moeglich, hier ein Array von strings zurueckzugeben. Die
296//nachfolgenden gelten als Backup-Objekte, falls eine sefun im Hauptobjekt
297//nicht gefunden wird.
298protected string *get_simul_efun() {
299 string err;
300
301 ++loading_simul_efuns;
302
bugfixd94d0932020-04-08 11:27:13 +0200303 if (!(err=catch(({void})SIMUL_EFUN_FILE->start_simul_efun())) ) {
MG Mud User88f12472016-06-24 23:31:02 +0200304 --loading_simul_efuns;
305 return ({SIMUL_EFUN_FILE});
306 }
Zesstrad77ab422019-09-27 17:39:27 +0200307
MG Mud User88f12472016-06-24 23:31:02 +0200308 debug_message("Failed to load simul efun " + SIMUL_EFUN_FILE +
Zesstrad77ab422019-09-27 17:39:27 +0200309 " " + err, DMSG_STDOUT | DMSG_LOGFILE | DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200310
bugfixd94d0932020-04-08 11:27:13 +0200311 if (!(err=catch(({void})SPARE_SIMUL_EFUN_FILE->start_simul_efun())) ) {
MG Mud User88f12472016-06-24 23:31:02 +0200312 --loading_simul_efuns;
313 return ({SPARE_SIMUL_EFUN_FILE});
314 }
MG Mud User88f12472016-06-24 23:31:02 +0200315
Zesstrad77ab422019-09-27 17:39:27 +0200316 debug_message("Failed to load spare simul efun " + SPARE_SIMUL_EFUN_FILE +
317 " " + err, DMSG_STDOUT | DMSG_LOGFILE | DMSG_STAMP);
318
319
MG Mud User88f12472016-06-24 23:31:02 +0200320 efun::shutdown();
Zesstrad77ab422019-09-27 17:39:27 +0200321
MG Mud User88f12472016-06-24 23:31:02 +0200322 return 0;
323}
324
325protected mixed call_sefun(string sefun, varargs mixed args) {
326 if (!loading_simul_efuns)
327 return apply(symbol_function(sefun), args);
328 else {
329 switch(sefun) {
330 case "log_file":
331 case "secure_level":
332 case "secure_euid":
333 case "find_player":
334 case "find_netdead":
335 case "find_living":
336 case "process_call":
337 case "replace_personal":
338 case "file_time":
339 return 0;
340 case "dtime":
341 if (pointerp(args) && sizeof(args))
342 return strftime("%a %d. %b %Y, %H:%M:%S",args[0]);
343 else
344 return strftime("%a %d. %b %Y, %H:%M:%S");
345 case "uptime":
346 return to_string(time()-__BOOT_TIME__) + " Sekunden";
347 }
348 }
349 return 0;
350}
351
352
353// Preload manuell wiederholen; Keine GD-Funktion
354void redo_preload()
355{
356 string *to_preload;
357 int i,j;
358
359 to_preload=epilog(0);
360 j=sizeof(to_preload);
361 for (i=0;i<j;i++)
362 catch(preload(to_preload[i]));
363 return;
364}
365
366// ##################
367//########################## Standard-Lfuns #############################
368// ##################
369
370// Keine GD-Funktion, aber sinnvoll.
371public varargs int remove(int silent)
372{
373 write("Der Master will aber nicht zerstoert werden!\n");
374 return 0;
375}
376
377// Einige repetitiven Taetigkeiten kann der Reset erledigen
378protected void reset()
379{
380 int i, *date;
381 mixed *wl;
382
383 //Darf nicht von Hand aufgerufen werden!
384 if (TI||TP) return;
385
386 // Naechsten Reset setzen
387 set_next_reset(RESETINT);
388
389 // Userinfo aufraeumen
390 _cleanup_uinfo();
391
392 // Projekt-Cache loeschen
393 _cleanup_projects();
394
395 // Wenn Zeit abgelaufen, dann READ_FILE-Log rotieren
396 if (!logrotate_counter--)
397 {
398 i=time()/LOGFILEAGE;
399 date=get_dir(sprintf("%s.%d", READ_FILE,i%LOGNUM), GETDIR_DATES);
400 if (pointerp(date)&&sizeof(date)&&
401 (date[0]/LOGFILEAGE)==i) return;
402 if (file_size(READ_FILE)>0)
403 rename(READ_FILE, sprintf("%s.%d", READ_FILE,i%LOGNUM));
404 logrotate_counter=LOGROTATE;
405 }
406 // einmal am Tag die UIDAliase resetten. Hierzu wird der logrotate_counter
407 // missbraucht.
408 if (!(logrotate_counter%24)) {
409 ResetUIDAliase();
410#ifdef _PUREFTPD_
411 expire_ftp_user();
412#endif
413 }
414
415 // Wizlist altert
416 wl = wizlist_info();
417 for (i=sizeof(wl); i--; )
418 set_extra_wizinfo(wl[i][WL_NAME], wl[i][WL_EXTRA] * 99 / 100);
419
MG Mud User88f12472016-06-24 23:31:02 +0200420 return;
421}
422
423
424// #################
425//########################## ID-Management ##############################
426// #################
427
428// Magier-ID fuer Datei str (als Objekt oder als String) ermitteln
429string creator_file(mixed str) {
430 string *strs,tmp;
431 int s;
432
Zesstraa43be352018-11-06 22:40:32 +0100433 // path_array nach strs
MG Mud User88f12472016-06-24 23:31:02 +0200434 // TODO: was ist mit clones?
435 if(objectp(str))
Zesstraccc58df2018-11-07 23:25:20 +0100436 strs=path_array(object_name(str));
MG Mud User88f12472016-06-24 23:31:02 +0200437 else if(stringp(str))
Zesstraccc58df2018-11-07 23:25:20 +0100438 strs=path_array(str);
MG Mud User88f12472016-06-24 23:31:02 +0200439 else return NOBODY;
440
441 // absolute Pfade interessieren hier gerade nicht.
442 strs -= ({""});
443
444 s=sizeof(strs);
445 if(s<2) return NOBODY;
446
447 switch(strs[0]) {
448 case DOMAINDIR:
449 // Fuer Nicht-Magier bzw. "Pseudo-"Magier die Regionskennung
450 if( s==2 || WIZLVLS[strs[2]] || !IS_LEARNER(strs[2]) )
451 return strs[1];
452
453 // in /d/erzmagier gibt es Magier-IDs
454 if (strs[1]=="erzmagier") return strs[2];
455
456 // Ansonsten d.region.magiername
457 return sprintf("d.%s.%s", strs[1], strs[2]);
458
459 case PROJECTDIR:
460 // In p.service gibt es ids mit uid
461 if (s>2 && strs[1]=="service") return "p.service."+strs[2];
462
463 // Ansonsten nur p.projekt (p.service ist auch hier drin)
464 return "p."+strs[1];
465
466 case WIZARDDIR:
467 if (s>2)
468 return strs[1];
469 if (s==2 && file_size(strs[0]+"/"+strs[1])==FSIZE_DIR)
470 return strs[1];
471 return NOBODY;
472
473 case SECUREDIR:
474 return ROOTID;
475
476 case GUILDDIR:
477 case SPELLBOOKDIR:
478 tmp=strs[1];
479 if (tmp[<2..<2]==".") tmp=tmp[0..<3];
480 if ((s=member(tmp,'.'))>0) tmp=tmp[s+1..];
481 return "GUILD."+tmp;
482
483 case LIBROOMDIR:
484 return ROOMID;
485
486 case STDDIR:
487 case LIBOBJDIR:
488 return BACKBONEID;
489
490 case DOCDIR:
491 return DOCID;
492
493 case MAILDIR:
494 return MAILID;
495 case NEWSDIR:
496 return NEWSID;
497
498 case LIBITEMDIR:
499 return ITEMID;
500
501 /* Fall-Through */
502 default:
503 return NOBODY;
504
505 }
506 return NOBODY; //should never be reached.
507}
508
509// UID und EUID an Objekt geben (oder eben nicht)
510// Keine GD-Funktion, aber von Hooks aufgerufen
Zesstraaed340b2019-11-28 21:26:49 +0100511protected mixed give_uid_to_object(string datei, object po)
MG Mud User88f12472016-06-24 23:31:02 +0200512{
513 string creator,pouid;
514
515 // Parameter testen
516 if (!stringp(datei)||!objectp(po)) return 1;
517
518 // Keine Objekte in /log, /open oder /data
519 if (strstr(datei, "/"LIBDATADIR"/") == 0
520 || strstr(datei, "/"LIBLOGDIR"/") == 0
521 || strstr(datei, "/"FTPDIR"/") == 0
522 )
523 return 1;
524
525 // Datei muss Besitzer haben
526 if (!(creator=creator_file(datei))) return 1;
527
528 // Hack, damit simul_efun geladen werden kann
529 if (creator==ROOTID && po==TO) return ROOTID;
530
531 // Keine euid, kein Laden ...
532 if (!(pouid=geteuid(po))) return 1; // Disallow if no euid in po
533
Zesstraf626b012020-01-05 20:43:03 +0100534 // Root soll keine Root-Objekte via den BACKBONEID-Mechanismus weiter
535 // unten generieren.
536 // Ausserdem nur UID setzen, keine eUID.
MG Mud User88f12472016-06-24 23:31:02 +0200537 if (pouid==ROOTID)
538 return ({creator,NOBODY}); // root does not create root objects!
539
Zesstraf626b012020-01-05 20:43:03 +0100540 // EUID mitsetzen, wenn PO und creator dieselbe UID sind.
541 // Wenn creator die BACKBONEID ist (im allg. liegt das Objekt dann in
542 // LIBOBJDIR), bekommt das Objekt nicht die BACKBONEID, sondern die UID des
543 // Erzeguers. Auch hier wird die eUID mitgesetzt.
MG Mud User88f12472016-06-24 23:31:02 +0200544 if (creator==pouid || creator==BACKBONEID)
545 return pouid;
546
547 return ({creator,NOBODY});
548}
549
550// Die System-IDs muessen bekannt sein
551string get_master_uid() { return ROOTID;}
552string get_bb_uid() { return BACKBONEID; }
MG Mud User88f12472016-06-24 23:31:02 +0200553
554// ##########################
555//###################### Sonstige GD-Funktionen #########################
556// ##########################
557
558// Spieler hat sich eingeloggt
559protected object connect()
560{
561 string err;
562 int errno;
563 object ob,bp;
564
565#if defined(SSLPORT) && __EFUN_DEFINED__(tls_available)
566 if (efun::interactive_info(this_player(), II_MUD_PORT) == SSLPORT) {
567 // reject connection of TLS is not available
568 if (!tls_available())
569 return 0;
570 // establish TLS
571 errno=tls_init_connection();
572 if (errno < 0) {
573 // Fehler im Vebindungsaufbau
574 printf("Can't establish a TLS/SSL encrypted connection: %s\n",
575 tls_error(errno));
576 return 0; // this will close the connection to the client.
577 }
578 }
579#endif
580
581 // Blueprint im Environment? Das geht nun wirklich nicht ...
582 if ((bp=find_object("/secure/login")) && environment(bp))
583 catch(destruct(bp);publish);
584
585 // Login-Shell clonen
586 err = catch(ob = clone_object("secure/login"); publish);
587
588 if (errno == 0 && err)
589 write("Fehler beim Laden von /secure/login.c\n"+err+"\n");
590
591 return ob;
592}
593
594// Was machen bei disconnect?
595protected void disconnect(object who, string remaining) {
Zesstrabfdcd9d2020-09-21 19:19:35 +0200596#if (__VERSION_MICRO__*100 + __VERSION_MINOR__ *10000 + __VERSION_MAJOR__ \
597 * 1000000) <= 3060300
598 // Workaround fuer Driver-Speicherleck in 3.6.2 und 3.6.3: vor dem
599 // Disconnect das Encoding wechseln, damit der driver das Handle auf iconv
600 // schliesst.
601 configure_interactive(who, IC_ENCODING, "UTF-8");
602#endif
603 ({void})who->NetDead();
604 return;
MG Mud User88f12472016-06-24 23:31:02 +0200605}
606
607// Es gibt kein File 'filename'. VC aktivieren so vorhanden ...
608protected object compile_object(string filename)
609{
610 object ret;
611 string *str;
612 string compiler;
613
614 if (!sizeof(filename)) return 0;
615 str=efun::explode(filename,"/");
616
617 if(sizeof(str)<2) return 0;
618 compiler=implode(str[0..<2],"/")+"/virtual_compiler";
619
620 if (find_object(compiler)
621 || file_size(compiler+".c")>0)
622 {
623 if(catch(
Zesstrad872d182019-11-28 20:13:02 +0100624 ret=({object})call_other(compiler,"compile_object",str[<1]); publish))
MG Mud User88f12472016-06-24 23:31:02 +0200625 return 0;
626 }
627 else
628 return(0);
629
630 if ( objectp(ret) && efun::explode(creator_file(filename), ".")[<1] !=
631 REAL_EUID(ret) ){
632 funcall( symbol_function('log_file/*'*/), "ARCH/VC_MISSBRAUCH",
633 sprintf( "%s: %s versucht per VC %s zu %s umzubenennen!\n",
634 funcall( symbol_function('dtime/*'*/), time() ),
635 (this_interactive() ? getuid(this_interactive()):
636 object_name(previous_object())), object_name(ret),
637 filename) );
638
639 return 0;
640 }
641 return ret;
642}
643
644// ############
645//############################ Shutdown #################################
646// ############
647
648// Spieler bei Shutdown entfernen
649protected void remove_player(object victim)
650{
bugfixd94d0932020-04-08 11:27:13 +0200651 catch(({int})victim->quit());
652 if (victim) catch(({int})victim->remove());
MG Mud User88f12472016-06-24 23:31:02 +0200653 if (victim) destruct(victim);
654 return;
655}
656
657// Langsamer Shutdown
658protected void slow_shut_down(int minutes)
659{
660 //sollte nur vom GD gerufen werden. Oder allenfalls Master selbst
661 filter(users(),#'tell_object,
662 "Der Gamedriver ruft: Der Speicher wird knapp ! Bereitet euch auf das Ende vor !\n");
bugfixd94d0932020-04-08 11:27:13 +0200663 ({int})"/obj/shut"->shut(minutes);
MG Mud User88f12472016-06-24 23:31:02 +0200664 return;
665}
666
667
668// In LD varargs void notify_shutdown(string crash_reason)
669protected varargs void notify_shutdown (string crash_reason) {
670
671 if (PO && PO != TO)
672 return;
673 if (crash_reason) {
674 //Uhoh... Verdammter Crash. :-( Zumindest mal mitloggen,
675 //was der Driver sagt...
676 write_file(CRASH_LOG,sprintf(
677 "\n%s: The driver crashed! Reason: %s\n",
678 ctime(time()),crash_reason));
679 }
680
681 filter(users(), #'tell_object,
682 "Game driver shouts: LDmud shutting down immediately.\n");
683 save_wiz_file();
684 return;
685}
686
687// ##################
688//########################## Berechtigungen #############################
689// ##################
690
691// Darf Verbindung durch name von obfrom nach ob gelegt werden?
692
693//int valid_exec(string name) {return 1;}
694
695int valid_exec(string name, object ob, object obfrom)
696{
697 // Ungueltige Parameter oder Aufruf durch process_string -> Abbruch
698 if (!objectp(ob) || !objectp(obfrom)
699 || !stringp(name) || !sizeof(name)
700 || funcall(symbol_function('process_call)) )
701 return 0;
702
703 // renew_player_object() darf ...
Zesstrae51f0602019-12-17 22:43:37 +0100704 if (name=="secure/master.c" || name=="/secure/master.c")
MG Mud User88f12472016-06-24 23:31:02 +0200705 return 1;
706
707 // Ansonsten darf sich nur die Shell selber aendern ...
708 if (previous_object() != obfrom) return 0;
709
710 // Die Login-Shell zu jedem Objekt ...
711 if (name=="/secure/login.c"
712 || name=="secure/login.c")
713 return 1;
714
715 // Magier per exec nur, wenn sie damit keine Fremde uid/euid bekommen
716 if (this_interactive() == obfrom && getuid(obfrom) == getuid(ob)
717 && geteuid(obfrom) == geteuid(ob))
718 return 1;
719
720 // Sonst darf niemand was
721 return 0;
722}
723
724
725// Darf me you snoopen?
726int valid_snoop(object me, object you) {
727 return getuid(PO) == ROOTID;
728}
729
730// Darf wiz wissen, ob er gesnoopt wird?
731int valid_query_snoop(object wiz) {
732 return getuid(PO) == ROOTID;
733}
734
735// Darf ob seine EUID auf neweuid setzen?
736int valid_seteuid(object ob, string neweuid)
737{
738 return (ob==this_object() ||
739 getuid(ob) == ROOTID ||
740 getuid(ob) == neweuid ||
741 creator_file(object_name(ob)) == neweuid);
742}
743
744// Darf getraced werden?
745int valid_trace(string what, mixed arg) {
746 return IS_ARCH(TI);
747}
748
749
750// valid_write() und
751// valid_read() befinden sich in file_access.c
752
753
754// Darf PO ob shadowen?
755int query_allow_shadow(object ob)
756{
757 // ROOT darf nicht geshadowed werden
758 if(getuid(ob) == ROOTID)
759 return 0;
760
761 // Access-Rights auch nicht
762 if (efun::explode(object_name(ob),"#")[0][<14..]=="/access_rights")
763 return 0;
764
765 // Ansonsten query_prevent_shadow fragen ...
Zesstrad872d182019-11-28 20:13:02 +0100766 return !({int})ob->query_prevent_shadow(PO);
MG Mud User88f12472016-06-24 23:31:02 +0200767}
768
769
770/* privilege_violation is called when objects try to do illegal things,
771 * or files being compiled request a privileged efun.
772 *
773 * return values:
774 * 1: The caller/file is allowed to use the privilege.
775 * 0: The caller was probably misleaded; try to fix the error.
776 * -1: A real privilege violation. Handle it as error.
777 */
Zesstraac4e6a82020-01-16 22:59:28 +0100778int privilege_violation(string op, mixed who, mixed arg1, mixed arg2,
779 mixed arg3)
MG Mud User88f12472016-06-24 23:31:02 +0200780{
781
782 if (objectp(who) &&
783 (who==this_object() || geteuid(who)==ROOTID))
784 return 1;
785
786 switch(op)
787 {
788 case "call_out_info":
789 return -1;
790 case "send_udp":
791 return 1;
792
793 case "nomask simul_efun":
794 // <who> ist in diesem Fall ein string (Filename) und damit von dem
795 // Check da oben nicht abgedeckt. Daher explizite Behandlung hier.
796 // Ausserdem hat der Pfad (zur Zeit noch) keinen fuehrenden '/'.
797 // Falls das jemand einschraenken will: der Kram fuer die simul_efuns
798 // muss das duerfen!
799 if (stringp(who)
800 && strstr(who,"secure/") == 0)
801 return 1;
802 return 0; // alle andere nicht.
803
804 case "get_extra_wizinfo":
805 // benutzt von /secure/memory.c und /secure/simul_efun.c
806 case "set_extra_wizinfo":
807 // wird benutzt von simul_efun.c, welche aber als ROOT-Objekt implizit
808 // erlaubt ist (s.o.)
809 return -1; // fuer allen nicht erlaubt.
810
811 case "rename_object":
812 if (object_name(who)=="/secure/impfetch" ||
813 BLUE_NAME(who)=="/secure/login")
814 return 1;
815 return(-1);
816
817 case "configure_driver":
818 return call_sefun("secure_level") >= ARCH_LVL;
819
820 case "limited":
821 // Spielershells duerfen sich zusaetzliche Ticks fuer den Aufruf von
822 // ::die() beschaffen, damit der Tod nicht wegen wenig Ticks buggt.
823 if (strstr(load_name(who), "/std/shells/") == 0
824 && get_type_info(arg1, 2) == who
825 && get_type_info(arg1, 3) == "/std/living/life"
826// && get_type_info(arg1, 4) == "die"
827 && arg2[LIMIT_EVAL] <= 10000000 ) {
828 return 1;
829 }
830 //DEBUG(sprintf("%O, %O, %O", who, arg1, arg2));
831 int *limits=efun::driver_info(DI_CURRENT_RUNTIME_LIMITS);
832 // LIMIT_EVAL darf verringert werden. Alle anderen Limits duerfen nicht
833 // geaendert werden. Achja, LIMIT_EVAL darf nicht 0 (LIMIT_UNLIMITED)
834 // sein. *g*
835 // LIMIT_COST darf entweder 0 oder -100 sein.
836 if (arg2[LIMIT_EVAL]>1000 && (arg2[LIMIT_EVAL] < get_eval_cost())-500
837 && arg2[LIMIT_ARRAY] == limits[LIMIT_ARRAY]
838 && arg2[LIMIT_MAPPING_KEYS] == limits[LIMIT_MAPPING_KEYS]
839 && arg2[LIMIT_MAPPING_SIZE] == limits[LIMIT_MAPPING_SIZE]
840 && arg2[LIMIT_BYTE] == limits[LIMIT_BYTE]
841 && arg2[LIMIT_FILE] == limits[LIMIT_FILE]
842 && arg2[LIMIT_CALLOUTS] == limits[LIMIT_CALLOUTS]
843 && (arg2[LIMIT_COST] == 0 || arg2[LIMIT_COST] == -100) )
844 return(1);
845 //sonst verweigern.
846 return(-1);
847
848 case "sqlite_pragma":
849 return 1;
850 case "attach_erq_demon":
851 case "bind_lambda":
852 case "configure_interactive":
853 case "configure_object":
854 case "execute_command":
855 case "erq":
856 case "input_to":
857 case "mysql":
858 case "net_connect":
859 case "pgsql":
860 case "set_driver_hook":
861 case "set_this_object":
862 case "shadow_add_action":
863 case "symbol_variable":
864 case "variable_list":
865 case "wizlist_info":
866 default:
867 return(-1);
868 }
869 return -1;
870}
871
872// ####################
873//######################## Fehlerbehandlung #############################
874// ####################
875
876// Behandlung von Fehler im Heart_Beat
877protected int heart_beat_error( object culprit, string error, string program,
878 string current_object, int line, int caught)
879{
880 if (!objectp(culprit)) return 0;
881 if (interactive(culprit))
882 {
883 tell_object(culprit,"Der GameDriver teilt Dir mit: "
884 "Dein Herzschlag hat ausgesetzt!\n");
885 if (IS_LEARNER(culprit))
886 tell_object(culprit,
887 sprintf("Fehler: %sProgamm: %s, CurrObj: %s, Zeile: %d, "
888 "the error was %scaught at higher level.\n",
889 error,program,current_object,line,
890 caught ? "" : "not"));
891 }
892
893 if (efun::object_info(culprit, OI_ONCE_INTERACTIVE))
894 call_out("restart_heart_beat", 5, culprit);
895 else
bugfixd94d0932020-04-08 11:27:13 +0200896 catch(({void})culprit->make_immortal(); publish);
MG Mud User88f12472016-06-24 23:31:02 +0200897 return 0;
898}
899
900// Ausgabe einer Meldung an Spieler mit Level >= minlevel. Wird genutzt, um
901// Magier ueber Fehler zu informieren, die nicht normal behandelt werden
902// (z.B. rekursive Fehler, d.h. Fehler in der Fehlerbehandlung)
903private void tell_players(string msg, int minlevel) {
904 msg = efun::sprintf("%=-78s","Master: " + msg); // umbrechen
905 efun::filter(efun::users(), function int (object pl)
906 {
907 if (query_wiz_level(pl) >= minlevel)
908 efun::tell_object(pl, msg);
909 return 0;
910 } );
911}
912
913/**
914 * \brief Error handling fuer Fehler beim Compilieren.
915 *
916 * log_error() wird vom GameDriver aufgerufen, wenn zur Compile-Zeit ein
917 * Fehler auftrat. Die Fehlermeldung wird unter /log/error geloggt.
918 * Falls this_interactive() ein Magier ist, bekommt er die Fehlermeldung
919 * direkt angezeigt.
920 * Sollte das Logfile 50kB ueberschreiten, wird es rotiert. Auf [Entwicklung]
921 * wird dann eine Fehlermeldung abgesetzt.
922 *
923 * @param file Die Datei, in der der Fehler auftrat.
924 * @param message Die Fehlermeldung.
925 * @param warn Warnung (warn!=0) oder Fehler (warn==0)?
926 * */
927
928protected void log_error(string file, string message, int warn) {
929 string lfile;
930 string cr;
931 mixed *lfile_size;
932
933 if (handling_error == efun::time()) {
934 // Fehler im Verlauf einer Fehlerbehandlung: Fehlerbehandlung minimieren,
935 // nur Meldung an eingeloggte Erzmagier.
936 tell_players("log_error(): Rekursiver Fehler in Fehlerbehandlung. "
937 "Bitte Debuglog beachten. Aktueller Fehler in " + file + ": "
938 + message, ARCH_LVL);
939 return;
940 }
941 handling_error = efun::time();
942
943 //Fehlerdaten an den Errord zur Speicherung weitergeben, falls wir sowas
944 //haben.
945#ifdef ERRORD
946 // Only call the errord if we are _not_ compiling the sefuns. It uses sefuns
947 // and it will cause a recursing call to get_simul_efuns() which is bound to
948 // fail.
949 if (!loading_simul_efuns) {
950 catch(limited(#'call_other,({200000}),ERRORD,"LogCompileProblem",
951 file,message,warn);publish );
952 }
953#endif // ERRORD
954
955 // Logfile bestimmen
956 cr=creator_file(file);
957 if (!cr) lfile="NOBODY.err";
958 else if (cr==ROOTID) lfile="ROOT";
959 else if (efun::member(cr,' ')!=-1) lfile="STD";
960 else lfile=cr;
961 //je nach Warnung oder Fehler Verzeichnis und Suffix bestimmen
962 if (warn) {
963 lfile="/log/warning/" + lfile + ".warn";
964 }
965 else {
966 lfile="/log/error/" + lfile + ".err";
967 }
968
969 // Bei Bedarf Rotieren des Logfiles
970 if ( !loading_simul_efuns
971 && sizeof(lfile_size = get_dir(lfile,2))
972 && lfile_size[0] >= MAX_ERRLOG_SIZE )
973 {
974 catch(rename(lfile, lfile + ".old"); publish); /* No panic if failure */
975 if (!loading_simul_efuns)
976 {
977 catch(send_channel_msg("Entwicklung","<MasteR>",
978 "Logfile rotiert: "+lfile+"."));
979 }
980 }
981
982 efun::write_file(lfile,message);
983
984 // Magier bekommen die Fehlermeldung angezeigt
985 if (IS_LEARNER(TI)) efun::tell_object(TI, message);
986
987 handling_error = 0;
988}
989
990/* Gegenmassnahme gegen 'too long eval' im Handler vom runtime error:
991 Aufsplitten des Handlers und Nutzung von limited() */
992//keine GD-Funktion
993private void handle_runtime_error(string err, string prg, string curobj,
994 int line, mixed culprit, int caught, object po, int issueid)
995{
996 string code;
997 string debug_txt;
998 object ob, titp;
999
1000 //DEBUG(sprintf("Callerstack: (handle_runtime_error()): %O\n",
1001 // caller_stack(1)));
1002 // Fehlermeldung bauen
1003 if (!stringp(err)) err="<NULL>";
1004 if (!stringp(prg)) prg="<NULL>";
1005 if (!stringp(curobj)) curobj="<NULL>";
1006 debug_txt=efun::sprintf("Fehler: %O, Objekt: %s, Programm: %O, Zeile %O (%s), "
1007 "ID: %d",
1008 err[0..<2], curobj, (prg[0]!='<'?"/":"")+prg, line,
1009 (TI?efun::capitalize(efun::getuid(TI)):"<Unbekannt>"),
1010 issueid);
1011
1012 titp = TI || TP;
1013 // Fehlermeldung an Kanaele schicken, aber nur wenn der aktuelle Fehler
1014 // nicht waehrend des ladens der simulefuns auftrat, bei der Ausgabe der
1015 // Meldung ueber die Kaenaele wieder sefuns genutzt werden.
1016 if (!loading_simul_efuns) {
bugfixd94d0932020-04-08 11:27:13 +02001017 if (titp && (IS_LEARNER(titp) || (({int|string})titp->QueryProp(P_TESTPLAYER))))
MG Mud User88f12472016-06-24 23:31:02 +02001018 {
1019 catch(send_channel_msg("Entwicklung",
1020 capitalize(objectp(po) ? REAL_UID(po) : ""),
1021 debug_txt));
1022 }
1023 else
1024 {
1025 catch(send_channel_msg("Debug",
1026 capitalize(objectp(po) ? REAL_UID(po) : ""),
1027 debug_txt));
1028 }
1029 }
1030
1031 if (!titp) return;
1032
1033 // Fehlermeldung an Benutzer
1034 if (IS_LEARNER(titp))
1035 efun::tell_object(titp,
1036 efun::sprintf("%'-'78.78s\nfile: %s line: %d object: %s\n" +
1037 "%serror: %s%'-'78.78s\n","",prg,line,curobj,
1038 (prg&&(code=efun::read_file("/"+prg,line,1))?
1039 "\n"+code+"\n":""),err,""));
1040 else
1041 efun::tell_object(titp, "Du siehst einen Fehler im Raum-Zeit-Gefuege.\n");
1042}
1043
1044//Keine GD-Funktion, limitiert die Kosten fuer den handler
1045private void call_runtime_error(string err, string prg, string curobj,
1046 int line, mixed culprit, int caught, object po)
1047{
1048 if (handling_error == efun::time())
1049 {
1050 // Fehler im Verlauf einer Fehlerbehandlung: Fehlerbehandlung minimieren,
1051 // nur Meldung an eingeloggte Regionsmagier.
1052 tell_players("call_runtime_error(): Rekursiver Fehler in "
1053 "Fehlerbehandlung. Bitte Debuglog beachten. Aktueller Fehler in "
1054 + curobj + ": " + err, LORD_LVL);
1055 return;
1056 }
1057 handling_error = efun::time();
1058
1059 //Fehlerdaten an den Errord zur Speicherung weitergeben, falls wir sowas
1060 //haben.
MG Mud User88f12472016-06-24 23:31:02 +02001061 int issueid;
Christian Georg Beckerd66c9602017-01-09 10:37:51 +02001062#ifdef ERRORD
MG Mud User88f12472016-06-24 23:31:02 +02001063 // Wenn die sefuns gerade geladen werden, erfolgt keine Weitergabe an den
1064 // ErrorD, da dabei wieder sefuns gerufen werden, was zu einer Rekursion
1065 // fuehrt.
1066 if (!loading_simul_efuns) {
1067 catch(issueid=efun::limited(#'call_other,({200000}),ERRORD,"LogError",
1068 err,prg,curobj,line,culprit,caught);publish);
1069 }
1070#endif // ERRORD
1071
1072 //eigenen Errorhandler laufzeitbegrenzt rufen
1073 efun::limited(#'handle_runtime_error, ({ 200000 }), err, prg, curobj,
1074 line,culprit,caught, po, issueid);
1075
1076 handling_error = 0;
1077}
1078
1079// Laufzeitfehlerbehandlung, hebt Evalcost-Beschraenkung auf und reicht weiter
1080// an call_runtime_error, die die Grenze wieder auf einen bestimmten Wert
1081// festlegt.
1082protected void runtime_error(string err ,string prg, string curobj, int line,
1083 mixed culprit, int caught) {
1084
1085 //DEBUG(sprintf("Callerstack: (runtime_error()): %O\nPO: %O\nPO(0): %O\n",
1086 // caller_stack(1),previous_object(),previous_object(0)));
1087
1088 limited(#'call_runtime_error, ({ LIMIT_UNLIMITED }),
1089 err,prg,curobj,line,culprit,caught,previous_object());
1090}
1091
1092//Warnungen mitloggen
1093protected void runtime_warning( string msg, string curobj, string prog, int line,
1094 int inside_catch)
1095{
1096 string code;
1097 string debug_txt;
1098 object titp;
1099
1100 //DEBUG(sprintf("Callerstack: in runtime_warning(): %O\nPO(0): %O\n",
1101 // caller_stack(1),previous_object(0)));
1102
1103 //Daten der Warnung an den Errord zur Speicherung weitergeben, falls wir
1104 //sowas haben.
1105 int issueid;
1106#ifdef ERRORD
1107 catch(issueid=limited(#'call_other,({200000}),ERRORD,"LogWarning",
1108 msg,prog,curobj,line,inside_catch); publish);
1109#endif // ERRORD
1110
1111 // Fehlermeldung bauen
1112 if (!stringp(msg)) msg="<NULL>";
1113 if (!stringp(prog)) prog="<NULL>";
1114 if (!stringp(curobj)) curobj="<NULL>";
1115 debug_txt=sprintf("Warnung: %O, Objekt: %s, Programm: %O, Zeile %O (%s) "
1116 "ID: %d",
1117 msg[0..<2], curobj, (prog[0]!='<'?"/":"")+prog, line,
1118 (TI?capitalize(getuid(TI)):"<Unbekannt>"),
1119 issueid);
1120
1121 //Fehlermeldungen an -warnungen schicken
1122 catch(send_channel_msg("Warnungen",
1123 capitalize(objectp(previous_object()) ?
1124 REAL_UID(previous_object()) : ""),
1125 debug_txt));
1126
1127 titp = TI || TP;
1128
1129 if (!titp) return;
1130
1131 // Fehlermeldung an Benutzer
1132 if (IS_LEARNER(titp))
1133 tell_object(titp,
1134 sprintf("%'-'78.78s\nfile: %s line: %d object: %s\n" +
1135 "%sWarnung: %s%'-'78.78s\n","",prog,line,curobj,
1136 (prog&&(code=read_file("/"+prog,line,1))?
1137 "\n"+code+"\n":""),msg,""));
1138 return;
1139}
1140
1141
1142// #####################
1143//######################## Einrichten des ED ############################
1144// #####################
1145
1146// Setup speichern
1147protected int save_ed_setup(object who, int code)
1148{
1149 string file;
1150
1151 if (!intp(code)) return 0;
1152 file = sprintf("/players/%s/.edrc",geteuid(who));
1153 rm(file);
1154 return write_file(file,(string)code);
1155}
1156
1157// Setup einladen
1158protected int retrieve_ed_setup(object who)
1159{
1160 string file;
1161
1162 file = sprintf("/players/%s/.edrc",getuid(who));
1163 if (file_size(file)<1) return 0;
1164 return (int)read_file(file);
1165}
1166
1167// Wo werden Dateien gespeichert?
1168string get_ed_buffer_save_file_name(string file)
1169{
1170 return sprintf("/players/%s/.dead_ed_files/%s",
1171 getuid(this_player()),efun::explode(file, "/")[<1]);
1172}
1173
1174// ################################
1175//################### Ungenutzte Pflichtfunktionen ######################
1176// ################################
1177
1178// Nichts zu tun beim Master-Neustart
1179protected void external_master_reload() { return; }
1180
1181// Keine externen Master-Flags
1182protected void flag(string str) { return; }
1183
1184// Wird benoetigt, falls ERQ angeschlossen ist
1185protected void stale_erq(closure callback) { return; }
1186
1187// Zerstoerten Master wiederbeleben ...
1188// nicht viel zu tun, wenn flag gesetzt ist. Wenn aber nicht, sind alle
1189// Variablen auf 0. Nach dieser Funktion wird wieder inaugurate_master()
1190// gerufen.
1191protected void reactivate_destructed_master(int flag) {
1192 if (flag) {
1193 //re-init
1194 //was machen? TODO
1195 }
1196 return;
1197}
1198
1199// Kein Quota-Demon (potentielles TODO)
1200//Handle quotas in times of memory shortage.
1201//is called during the final phase of a garbage collection, if the user
1202//reserve could not be re-allocated. Last (!) Chance to free (active) objects
1203//from the system and prevent call to slow_shut_down()!
1204protected void quota_demon() {
1205 //was kann man machen?
1206 //uebervolle Seherhaeuser leeren?
1207 return;
1208}
1209
1210// Keine Prepositionen in parse_command
1211//string *parse_command_prepos_list() { return ({}); }
1212
1213// Wie lautet das Wort fuer 'alle' ?
1214//string *parse_command_all_word() { return ({}); }
1215
1216
1217// Keine Besonderen Objektnamen
1218string printf_obj_name(object ob) { return 0; }
1219
1220// ###################
1221//######################### Sonstiges/Hooks #############################
1222// ###################
1223
1224//TODO: save_wiz_file in shutdown() integrieren?
1225// Wizliste speichern: Zeile generieren
1226static string _save_wiz_file_loop(mixed *a)
1227{
1228 return sprintf("%s %d %d\n",a[WL_NAME],a[WL_COMMANDS],a[WL_EXTRA]);
1229}
1230
1231// Wizliste speichern
1232protected void save_wiz_file()
1233{
1234 rm("/WIZLIST");
1235 write_file("/WIZLIST",implode(
1236 map(wizlist_info(),#'_save_wiz_file_loop),""));
1237}
1238
MG Mud User88f12472016-06-24 23:31:02 +02001239// EUID und UID werden von give_uid_to_object() vergeben, diese sind in
1240// inaugurate_master() als driver hooks angemeldet.
1241
MG Mud User88f12472016-06-24 23:31:02 +02001242protected mixed load_uid_hook(string datei) {
Zesstraaed340b2019-11-28 21:26:49 +01001243 return(give_uid_to_object(datei, previous_object()));
MG Mud User88f12472016-06-24 23:31:02 +02001244}
1245
Zesstraaed340b2019-11-28 21:26:49 +01001246protected mixed clone_uid_hook(object blueprint, string new_name) {
1247 return(give_uid_to_object(new_name, previous_object()));
MG Mud User88f12472016-06-24 23:31:02 +02001248}
1249