blob: 6d4679c79608411a0ae8601a22fc43757f9a9c57 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/commands.c -- alias, history and player command handling
4//
5// $Id: command.c 9576 2016-06-18 15:00:01Z Zesstra $
6#pragma strong_types
7#pragma save_types
8//#pragma range_check
9#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020010
11#define NEED_PROTOTYPES
12#include <player/command.h>
13#include <player/comm.h>
14#include <thing/properties.h>
15#include <living/moving.h>
16#include <player.h>
17#undef NEED_PROTOTYPES
18
19#include <properties.h>
20#include <language.h>
21#include <new_skills.h>
22#include <config.h>
23#include <defines.h>
24#include <wizlevels.h>
25#include <logging.h>
26#include <strings.h>
27
28#define CBLOG(x) log_file(SHELLLOG("DISABLECOMMANDS"),x,200000)
Zesstrafb4cc3d2019-05-06 21:16:30 +020029#define FALIASDB "/secure/zweities"
MG Mud User88f12472016-06-24 23:31:02 +020030
31#define HIST_SIZE 40
32#define EPMASTER "/secure/explorationmaster"
33
Zesstrafb4cc3d2019-05-06 21:16:30 +020034// Im Char gespeicherte Aliase
MG Mud User88f12472016-06-24 23:31:02 +020035private mapping aliases;
Zesstrafb4cc3d2019-05-06 21:16:30 +020036// Vereinigte Liste aktiver Aliase aus im Char gespeicherten und
37// Familienaliases. Wird nicht gespeichert, sondern bei Login erzeugt!
38private nosave mapping active_aliases = ([]);
39
MG Mud User88f12472016-06-24 23:31:02 +020040private string *commands;
41private int hist_size, show_processing, histmin;
42private string default_notify_fail;
43private nosave string *history, *unparsed_args, unmodified;
44private nosave int hist_now;
45private nosave object last_command_env;
46private nosave int cmds_per_time, last_chg, max_commands, *cmd_types;
47// Datenstruktur: ({Setzer, Ablaufzeit, String/Closure})
48private nosave mixed disablecommands;
49private nosave object* syntaxdb;
50
51nomask void __set_bb(int flag);
52
53static varargs int __auswerten(string str, string intern);
54varargs int SoulComm(string str, string _verb);
55varargs mixed More(string str, int fflag, string returnto);
MG Mud User88f12472016-06-24 23:31:02 +020056static void reallocate_histbuf();
57
58private void AddHistory(string str)
59{
60 if (!stringp(str) || str=="" || str[0]=='&' || str[0]=='^' ||
61 str=="hist")
62 return;
63 if (!hist_size) return;
64 if (!pointerp(history) || sizeof(history)!=hist_size)
65 reallocate_histbuf();
66 if (sizeof(str)>=histmin && history[(hist_size+hist_now-1)%hist_size]!=str)
67 history[(hist_now++)%hist_size]=str;
68}
69
70static void create()
71{
72 last_chg=0;
73 histmin=hist_now=0;
74 Set(P_LOCALCMDS,({}));
75 Set(P_LOCALCMDS,PROTECTED,F_MODE_AS);
76 Set("_syntaxdb", SECURED|SAVE, F_MODE_AS);
77
78 show_processing=1;
79 unparsed_args=({0,0,0});
80 hist_size=HIST_SIZE;
81}
82
83static int replacedisplay(string str)
84{
85 if (!str || str=="" || !sscanf(str,"%d",show_processing))
86 printf("Unzulaessige Eingabe!\n%s 0|1|2\n",query_verb());
87 printf("Ersetzungsanzeige auf Level %d.\nLevel 0: Nichts anzeigen\n"+
88 "Level 1: Nur History-Ersetzungen anzeigen\n"+
89 "Level 2: History- und Alias-Ersetzungen anzeigen\n",show_processing);
90 if (show_processing>2&&!IS_WIZARD(ME)) show_processing=2;
91 return 1;
92}
93
94static int histmin(string str)
95{
96 int len;
97
98 if (!str||!sscanf(str,"%d",len)||len<0)
99 {
100 write("Benutzung: histmin ZAHL\nLegt die Mindestlaenge fest, die eine \
101Befehlszeile haben muss, um in den\nHistory-Puffer zu gelangen. Derzeit \
102eingestellt auf "+(string)histmin+" Zeichen.\n");
103 return 1;
104 }
105 histmin=len;
106 write("Mindestlaenge auf "+(string)len+" eingestellt.\n");
107 return 1;
108}
109
110static void reallocate_histbuf()
111{
112 int i;
113
114 history=allocate(hist_size);
115 hist_now=0;
116 for (i=0;i<hist_size;i++)
117 if (!stringp(history[i]))
118 history[i]="\n\n";
119}
120
121static int histlen(string str)
122{
123 int d;
124 if (!str||!sscanf(str,"%d",d)||d<0||d>40)
125 {
126 write("Benutzung: histlen ZAHL\nZAHL muss zwischen 0 und 40 liegen.\n");
127 printf("Deine History-Buffer-Laenge liegt bei %d Befehlen.\n",hist_size);
128 return 1;
129 }
130 hist_size=d;
131 printf("Deine History-Buffer-Laenge liegt jetzt bei %d Befehlen.\n",
132 hist_size);
133 reallocate_histbuf();
134 return 1;
135}
136
Zesstra3fe70c62019-05-28 22:46:19 +0200137// Wenn keine bestimmten Aliasnamen angegeben sind, werden alle
138// Familienaliase geholt und mit den Charaliasen vereinigt.
139// Sonst werden nur bestimmte ermittelt und der Liste der aktiven
140// Aliase ersetzt/ergaenzt.
141// Wenn <verbose>, dann wird eine Meldung ausgegeben.
142private void merge_family_aliases(string *to_update, int verbose)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200143{
Zesstra3fe70c62019-05-28 22:46:19 +0200144 mapping family;
145 if (!to_update)
146 {
147 // Char- und Familienaliase addieren und als neues aktives Set
148 // speichern.
149 // Die Aliase des Char haben Prioritaet und ueberdecken die der Familie.
150 family = FALIASDB->QueryFamilyAlias();
151 active_aliases = family + aliases;
152 }
153 else
154 {
155 // Die uebergebene Liste neuholen (alle davon vorhandenen) und
156 // im aktiven Set aktualisieren/eintragen.
157 family = m_allocate(sizeof(to_update));
158 foreach(string key: &to_update)
159 {
160 family += FALIASDB->QueryFamilyAlias(key);
161 }
162 active_aliases = active_aliases + family;
163 }
164 if (verbose && sizeof(family))
165 {
166 write(break_string((
167 "Es wurden folgende Familienaliase aktiviert: "
168 +CountUp(m_indices(family)) + ".\n"),75));
169 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200170}
171
MG Mud User88f12472016-06-24 23:31:02 +0200172static void initialize()
173{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200174 if (!pointerp(history)||sizeof(history)!=hist_size)
175 reallocate_histbuf();
176 add_action("__auswerten","",1);
MG Mud User88f12472016-06-24 23:31:02 +0200177 max_commands = EPMASTER->QueryCommands();
178 cmd_types = EPMASTER->QueryCmdTypes() || ({});
179
180 if ( !mappingp(aliases) )
181 aliases = ([]);
182
Zesstra3fe70c62019-05-28 22:46:19 +0200183 merge_family_aliases(0,0);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200184
MG Mud User88f12472016-06-24 23:31:02 +0200185 if ( !pointerp(commands) )
186 commands = ({});
187
188 if (QueryProp("_syntaxdb"))
189 syntaxdb = ({find_object("/secure/syntaxdb")});
190/* else if (QueryProp(P_TESTPLAYER))
191 {
192 SetProp("_syntaxdb", 1);
193 call_out(#'_notify, 2,
194 "\nDa Du als Testspieler markiert bist, wurde bei Dir "
195 "die Syntaxsammlung eingeschaltet. Du kannst dies "
196 "wieder ausschalten. (hilfe syntaxsammlung) "
197 "Es waere schoen, wenn Du es beim Testen von "
198 "Gebieten einschaltest.", 0);
199 }*/
200}
201
202static mixed _set_default_notify_fail(string s)
203{
204 if (stringp(s)&&s!="")
205 {
206 if (s[<1]!='\n') s+="\n";
207 return default_notify_fail=s;
208 }
209 else if (!s||s=="")
210 return (default_notify_fail=0);
211}
212
213static mixed _query_default_notify_fail()
214{
215 return default_notify_fail;
216}
217
218static int set_errormessage(string s)
219{
220 if (!(s=_unparsed_args()))
221 {
222 _set_default_notify_fail(0);
223 write("Standard-Fehlermeldung auf \"Wie bitte?\" gesetzt.\n");
224 } else
225 {
226 write(break_string(sprintf("Standard-Fehlermeldung auf %s gesetzt.\n",
227 s),78));
228 _set_default_notify_fail(s);
229 }
230 return 1;
231}
232
233void reconnect()
234{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200235 if (!mappingp(aliases))
236 aliases=([]);
237
Zesstra3fe70c62019-05-28 22:46:19 +0200238 merge_family_aliases(0,0);
MG Mud User88f12472016-06-24 23:31:02 +0200239
240 if ( !pointerp(commands) )
241 commands = ({});
242
243 max_commands = EPMASTER->QueryCommands();
244 cmd_types = EPMASTER->QueryCmdTypes() || ({});
245}
246
247static int show_hist()
248{
249 int i;
250 string comm;
251
252 tell_object( ME, "Die History-Liste enthaelt folgende Kommandos:\n" );
253
254 for( i = 0; i < hist_size; i++ )
255 if ((comm=history[(hist_now+i)% hist_size])!= "\n\n")
256 tell_object( ME, " &"+(hist_now+i-hist_size)+"/-"+ (hist_size-i-1)
257 +"\t= "+comm+"\n");
258 return 1;
259}
260
Zesstrafb4cc3d2019-05-06 21:16:30 +0200261static string present_alias(<string|int>* ali)
MG Mud User88f12472016-06-24 23:31:02 +0200262{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200263 int j;
264 <string|int> k;
MG Mud User88f12472016-06-24 23:31:02 +0200265 string s,s2;
266
267 for (s="",j=sizeof(ali)-1;j>=0;j--)
268 if (intp(ali[j]))
269 if ((k=ali[j])<0)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200270 s="$"+(k==-1?"":(string)-k)+"*"+s;
MG Mud User88f12472016-06-24 23:31:02 +0200271 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200272 s="$"+(string)k+s;
MG Mud User88f12472016-06-24 23:31:02 +0200273 else
274 {
275 s2=implode(explode(ali[j],"\\"),"\\\\");
276 s=implode(explode(s2,"$"),"\\$")+s;
277 }
278 return s;
279}
280
281#define ALIFORMAT ({" %s\t= %s", "alias %s %s"})[display_as_aliascommand]
Zesstrafb4cc3d2019-05-06 21:16:30 +0200282#define FALIFORMAT ({" %s\t= %s", "alias -f %s %s"})[display_as_aliascommand]
MG Mud User88f12472016-06-24 23:31:02 +0200283// Ich weiss, den Variablennamen im define zu haben ist unfein, aber das
284// macht es im Code dann angenehm uebersichtlich. -HrT
285
Zesstrafb4cc3d2019-05-06 21:16:30 +0200286static int query_aliases(int display_as_aliascommand, int familymode)
MG Mud User88f12472016-06-24 23:31:02 +0200287{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200288 mapping selected_aliases;
MG Mud User88f12472016-06-24 23:31:02 +0200289
Zesstrafb4cc3d2019-05-06 21:16:30 +0200290 if (familymode)
291 selected_aliases=FALIASDB->QueryFamilyAlias();
292 else
293 selected_aliases = aliases;
294
Bugfix0c5133d2019-05-28 10:38:44 +0200295 string *alis = sort_array(m_indices(selected_aliases),#'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200296
297 if(sizeof(alis))
MG Mud User88f12472016-06-24 23:31:02 +0200298 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200299 foreach(string a : &alis)
300 a = sprintf( (familymode ? FALIFORMAT : ALIFORMAT),
301 a, present_alias(selected_aliases[a]) );
302 More("Du hast folgende "
303 + (familymode ? "Familien-" : "")
Bugfix080e3ff2019-05-28 10:06:47 +0200304 + "Aliase definiert:\n" + CountUp(alis, "\n", "\n"));
MG Mud User88f12472016-06-24 23:31:02 +0200305 }
306 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200307 write("Du hast keine "
308 +(familymode ? "Familien-" : "") + "Aliase definiert.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200309 return 1;
310}
311
MG Mud User88f12472016-06-24 23:31:02 +0200312static int alias(string str)
313{
Zesstraf86ed742019-04-25 18:37:27 +0200314 // unbearbeitetes Kommando ohne Verb ermitteln (auch ohne Trim an Anfang und
315 // Ende)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200316 string um;
Zesstraf86ed742019-04-25 18:37:27 +0200317 if (unmodified && unmodified!="")
MG Mud User88f12472016-06-24 23:31:02 +0200318 um=implode(old_explode(unmodified," ")[1..]," ");
Zesstraf86ed742019-04-25 18:37:27 +0200319
MG Mud User88f12472016-06-24 23:31:02 +0200320 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200321 if( !(str = um||_unparsed_args()) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200322 return query_aliases(0, 0);
MG Mud User88f12472016-06-24 23:31:02 +0200323
Zesstrafb4cc3d2019-05-06 21:16:30 +0200324 // optionen auswerten bis keine mehr kommen, dabei vorne den String
325 // verkuerzen
326 int display_as_aliascommand, familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200327 while(sizeof(str) >= 2 && str[0] == '-')
328 {
329 if (str[1] == 'a')
330 display_as_aliascommand = 1;
331 else if (str[1] == 'f')
332 familymode = 1;
333 else
334 break;
335 // "-? " abschneiden
336 str = trim(str[2..], TRIM_LEFT);
MG Mud User88f12472016-06-24 23:31:02 +0200337 }
Zesstraf332ded2019-04-25 18:40:02 +0200338 if (!sizeof(str) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200339 return query_aliases(display_as_aliascommand, familymode);
MG Mud User88f12472016-06-24 23:31:02 +0200340
Zesstrafb4cc3d2019-05-06 21:16:30 +0200341 int pos=member(str,' ');
Zesstraf86ed742019-04-25 18:37:27 +0200342 if (pos < 0) // Nur 1 Arg, Alias abfragen
MG Mud User88f12472016-06-24 23:31:02 +0200343 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200344 <string|int>* tmp;
345 if (familymode)
Bugfixc487d4c2019-05-28 11:04:29 +0200346 tmp=FALIASDB->QueryFamilyAlias(str)[str];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200347 else
348 tmp=aliases[str];
349
350 if (tmp) // genau eins angegebenen
351 printf((familymode ? FALIFORMAT : ALIFORMAT)
352 +"\n",str,present_alias(tmp));
Zesstraf86ed742019-04-25 18:37:27 +0200353 else if (str[<1]=='*') // * am Ende, alle ausgeben, die passend anfangen
354 {
355 str=str[0..<2];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200356 mapping selected_aliases;
357 if (familymode)
358 selected_aliases=FALIASDB->QueryFamilyAlias();
359 else
360 selected_aliases = aliases;
361 string *hits=filter(m_indices(selected_aliases),
362 function int (string alname, string start)
363 { return strstr(alname, start) == 0; },
364 str);
Zesstraf86ed742019-04-25 18:37:27 +0200365 if (!sizeof(hits))
MG Mud User88f12472016-06-24 23:31:02 +0200366 {
Zesstraf86ed742019-04-25 18:37:27 +0200367 printf("Du hast kein Alias, das mit \"%s\" anfaengt.\n", str);
368 return 1;
MG Mud User88f12472016-06-24 23:31:02 +0200369 }
Zesstraf86ed742019-04-25 18:37:27 +0200370 hits=sort_array(hits, #'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200371 foreach(string hit: &hits)
372 hit = sprintf((familymode ? FALIFORMAT : ALIFORMAT),
373 hit, present_alias(selected_aliases[hit]));
Zesstraf86ed742019-04-25 18:37:27 +0200374 More("Folgende Aliase beginnen mit \""+str+"\":\n"+implode(hits,"\n"));
375 }
376 else // Nix gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200377 printf("Du hast kein Alias \"%s\" definiert.\n",str);
378 return 1;
379 }
Zesstraf86ed742019-04-25 18:37:27 +0200380
MG Mud User88f12472016-06-24 23:31:02 +0200381 if (!pos)
382 {
Zesstraf86ed742019-04-25 18:37:27 +0200383 write("Fehler: Leerzeichen am Alias-Anfang\n");
MG Mud User88f12472016-06-24 23:31:02 +0200384 return 1;
385 }
Zesstraf86ed742019-04-25 18:37:27 +0200386 // Kommandoverb alles bis zum ersten " ".
Zesstrafb4cc3d2019-05-06 21:16:30 +0200387 string commandverb=str[0..pos-1];
Zesstraf86ed742019-04-25 18:37:27 +0200388 if (commandverb=="unalias")
MG Mud User88f12472016-06-24 23:31:02 +0200389 {
390 write
391 ("Es nicht moeglich, den Befehl unalias zu ueberladen (waer dumm :))\n");
392 return 1;
393 }
Zesstraf86ed742019-04-25 18:37:27 +0200394 if (commandverb=="*")
MG Mud User88f12472016-06-24 23:31:02 +0200395 {
396 write
397 ("Es nicht moeglich, den Befehl \"*\" zu ueberladen.\n");
398 return 1;
399 }
400
Zesstrafb4cc3d2019-05-06 21:16:30 +0200401 // ab hier wird der Expansionstext in ein Array von Strings geparst. Alle
402 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
403 // laufender Index im Array. Negative Zahlen stehen fuer $n*, d.h. alle
404 // Argument nach dem genannten.
405 // Bsp: ({"stecke ", 1, " in ", -2 })
406 //TODO: regexplode("teile $1 mit $2* Ich bin jetzt weg, \$ verdienen!","[$][0-9][*]{0,1}",RE_PCRE)
407 str=str[pos+1..];
408 <string|int>* tmp=({}); // Alias-Array
409 int l, num;
MG Mud User88f12472016-06-24 23:31:02 +0200410 while (l=sizeof(str)) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200411 pos=0; // Positionszaehler in str
412 int cont=1; // Statusflag fuer inneres while
413 while (cont)
414 {
415 // innere Schleife: scannt ein Argument und haengt es als Element in
416 // tmp an. Laeuft ueber den String bis Stringende oder & oder $
417 // erreicht wird, dann ist ein Argument vollstaendig und das naechste
418 // faengt an.
419 if (pos<l)
420 {
421 if(str[pos]=='\\') // escapte '\' werden zu einzelnen '\'.
422 {
MG Mud User88f12472016-06-24 23:31:02 +0200423 str=str[0..pos-1]+str[pos+1..];
424 l--;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200425 }
426 else
427 {
428 if (str[pos]=='$' || str[pos]=='&') // & ist historisch...
429 { // Argument-Platzhalter gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200430 cont=0;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200431 if (pos>0) { // vorhergehender Textblock vollstaendig, anhaengen
MG Mud User88f12472016-06-24 23:31:02 +0200432 tmp+=({str[0..pos-1]});
433 }
434 if (pos==l-1) {
435 printf("Fehler: %c am Zeilenende\n",str[pos]);
436 return 1;
437 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200438 // $* oder $n ? Im Falle von $n landet in num der ASCII-Wert des
439 // Zeichens, von welchem der Wert von '0' abgezogen wird -> num
440 // enthaelt danach 0..9, wenn eine Ziffer angegeben wurde.
441 num=str[++pos]; // naechstes Zeichen holen
442 if (num=='*') {
443 // Argument 1 und pos muss wieder eins zurueck.
MG Mud User88f12472016-06-24 23:31:02 +0200444 num=1;
445 pos--;
446 } else {
447 num-='0';
448 }
449 if (num<0 || num>9) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200450 printf("Fehler: Nach %c muss eine Ziffer oder * folgen\n",
MG Mud User88f12472016-06-24 23:31:02 +0200451 str[pos-1]);
452 return 1;
453 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200454 // str nach Argumentkennung weiter verarbeiten.
455 str=str[pos+1..];
456 // Aber fuer den Fall $n* das naechste Zeichen auch untersuchen
457 if (sizeof(str) && str[0]=='*') {
458 str=str[1..]; // auch ueberspringen
459 num = negate(num); // Im Array negiert kodieren
MG Mud User88f12472016-06-24 23:31:02 +0200460 }
461 tmp+=({num});
462 }
463 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200464 ++pos; // naechstes Zeichen im naechste inner while angucken
MG Mud User88f12472016-06-24 23:31:02 +0200465 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200466 // Ende des gesamten Strings erreicht.
467 else
468 {
469 cont=0; // ende inner while
470 // letzten Argumentblock anhaengen
471 if (str!="") tmp+=({str});
472 str=""; // beendet outer while
473 }
474 } // inner while
475 } // outer while
476
477 if (familymode)
478 {
479 int err=FALIASDB->AddOrReplaceFamilyAlias(commandverb, tmp);
480 if (err < 1)
481 {
482 printf("Neues Familienalias konnte nicht definiert werden.\n");
483 if (err==-2)
484 printf("Du hast schon genuegend Aliase definiert!\n");
485 }
486 else
487 {
488 printf("Neues Familienalias: %s\t= %s\n",
489 commandverb, present_alias(tmp));
490 // Alias direkt aktivieren, aber nur falls es keins in diesem Char gibt
491 // (was dann eh schon aktiv ist).
492 if (!member(aliases, commandverb))
493 active_aliases[commandverb] = tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200494 }
495 }
MG Mud User88f12472016-06-24 23:31:02 +0200496 else
497 {
Zesstra1b98da72020-10-19 21:50:22 +0200498 if ((!aliases[commandverb]) && (sizeof(aliases)>1500))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200499 printf("Du hast schon genuegend Aliase definiert!\n");
500 else
501 {
Zesstrac687e292019-05-28 22:43:11 +0200502 if (member(active_aliases, commandverb)
503 && !member(aliases, commandverb))
504 printf("Hinweis: das neue Alias ueberschattet ein Familienalias.\n");
505 aliases[commandverb] = tmp;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200506 active_aliases[commandverb] = tmp;
507 printf("Neues Alias: %s\t= %s\n",commandverb, present_alias(tmp));
Zesstra1b98da72020-10-19 21:50:22 +0200508 if (sizeof(aliases)>1000)
509 {
510 printf("Du hast bereits %d Aliase definiert. Bitte raeume auf!\n");
511 }
512 }
MG Mud User88f12472016-06-24 23:31:02 +0200513 }
514 return 1;
515}
516
517static int unalias(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200518
Zesstrafb4cc3d2019-05-06 21:16:30 +0200519 string um;
MG Mud User88f12472016-06-24 23:31:02 +0200520 if (unmodified&&unmodified!="")
521 um=implode(old_explode(unmodified," ")[1..]," ");
522 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200523 if ( !(str=um || _unparsed_args()))
524 return 0;
525
Zesstrafb4cc3d2019-05-06 21:16:30 +0200526 int familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200527 while(sizeof(str) >= 2 && str[0] == '-')
528 {
529 if (str[1] == 'f')
530 familymode = 1;
531 else
532 break;
533 // "-f " abschneiden
534 str = trim(str[2..], TRIM_LEFT);
535 }
536
MG Mud User88f12472016-06-24 23:31:02 +0200537 if (str == "*.*" || str == "*") {
538 write(break_string(
539 "Versuchs mal mit 'unalias .*', wenn Du wirklich alle Alias entfernen "
540 "willst.",78));
541 return 1;
542 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200543
544 mapping selected_aliases;
545 if (familymode)
546 selected_aliases=FALIASDB->QueryFamilyAlias();
547 else
548 selected_aliases = aliases;
549
550 string *to_delete;
551 // Genau ein Alias gegeben?
552 if (member(selected_aliases,str))
553 to_delete = ({str});
554 else // sonst als RegExp interpretieren
555 to_delete=regexp(m_indices(selected_aliases),("^"+str+"$"));
556
557 if (sizeof(to_delete))
Zesstraf86ed742019-04-25 18:37:27 +0200558 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200559 foreach(string key : to_delete)
Zesstraf86ed742019-04-25 18:37:27 +0200560 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200561 if (familymode)
562 FALIASDB->DeleteFamilyAlias(key);
563 else
564 m_delete(aliases, key);
Arathorn0875e102021-01-20 00:33:17 +0100565
566 if (!familymode || !member(aliases,key))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200567 // auf jeden Fall noch deaktivieren
Arathorn0875e102021-01-20 00:33:17 +0100568 m_delete(active_aliases, key);
MG Mud User88f12472016-06-24 23:31:02 +0200569 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200570 if (sizeof(to_delete) == 1)
571 write("Du entfernst das Alias \""+ to_delete[0] +"\".\n");
572 else
573 write(break_string(("Du entfernst folgende Aliase: "
574 +CountUp(to_delete) + ".\n"),75));
Zesstra3fe70c62019-05-28 22:46:19 +0200575 // Wenn nicht im Familienmodus (d.h. Char-Aliase wurden geloescht), wird
576 // versucht, gleichnamige Familienaliase (sofern vorhanden) zu
577 // aktivieren.
578 if (!familymode)
579 {
580 merge_family_aliases(to_delete, 1);
581 }
MG Mud User88f12472016-06-24 23:31:02 +0200582 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200583 else
584 write("So ein Alias hast Du nicht definiert.\n");
585
MG Mud User88f12472016-06-24 23:31:02 +0200586 return 1;
587}
588
589varargs string _unparsed_args(int level)
590{
591 return unparsed_args[level];
592}
593
594#define ARTIKEL ({"das","der","die","des","dem","den","ein","eine","einer",\
595 "eines"})
596
597#define TRENNER ({"in","aus","ueber","auf","unter","mit","durch","fuer",\
598 "von","vom","im","aufs","ein","weg","zurueck"})
599
600static string _single_spaces(string str)
601{
602 return regreplace(str, " *", " ", 1);
603}
604
605static mixed _return_args(string str)
606{
607 string *t,*t2,verb,s2;
608 int i,l,j,l2;
609
610 t=explode(trim(str,TRIM_BOTH)," ");
611 verb=t[0];
612 t = t[1..];
613 if (!sizeof(t))
614 {
615 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=0;
616 return str=verb;
617 }
618 else
619 str = unparsed_args[0] = implode(t, " ");
620
621 str=unparsed_args[1]=lower_case(_single_spaces(str));
622 t=regexplode(str,"\\<im\\>|\\<ins\\>");
623 for (i=1;i<sizeof(t);i+=2) t[i]="in";
624 t=regexplode(implode(t,""),"[\\,\\!\\:][\\,\\!\\:]*");
625 l=sizeof(t);
626 for(i=1;i<l;i+=2) t[i]="";
627 t=old_explode(implode(t,"")," ")-({""});
628 for (i=sizeof(t)-2;i>=0;i--)
629 {
630 if (member(ARTIKEL,t[i])>=0)
631 t=t[0..i-1]+t[i+1..];
632 }
633 unparsed_args[2]=implode(t," ");
634 t=regexplode((str=implode(t," ")),"[0-9][0-9]*\\.");
635 if ((l=sizeof(t))>2)
636 {
637 i=1;
638 while (i<l-1)
639 {
640 t[i]=" "+t[i][0..<2]+" ";
641 if ((l2=sizeof(t2=old_explode(t[i+1]," ")))<2)
642 t[i+1]+=t[i];
643 else
644 {
645 for (j=1;j<l2;j++)
646 {
647 if (member(TRENNER,t2[j])>=0)
648 {
649 t2[j-1]+=t[i];
650 l2=0;
651 }
652 }
653 if (!l2)
654 t[i+1]=implode(t2," ");
655 else
656 t[i+1]+=t[i];
657 }
658 t[i]="";
659 i+=2;
660 }
661 str=_single_spaces(verb+" "+implode(t," "));
662 if (str[<1]==' ') str=str[0..<2];
663 } else str=verb+(str==""?"":" "+str);
664 if (show_processing>2)
665 printf("-> {%s}\n",str);
666 return str;
667}
668
669static void decay_average()
670{
671 if (absolute_hb_count()-last_chg>14)
672 {
673 last_chg=absolute_hb_count()-last_chg;
674 if (last_chg>3000)
675 last_chg=absolute_hb_count(),cmds_per_time=0;
676 else
677 {
678 while (last_chg>14)
679 cmds_per_time=cmds_per_time*9/10, last_chg-=15;
680 last_chg=absolute_hb_count()-last_chg;
681 }
682 }
683}
684
685private void DelayPreparedSpells() {
686 mixed ps;
687
688 if (pointerp(ps=QueryProp(P_PREPARED_SPELL))
689 && sizeof(ps)>=1 && intp(ps[0])) {
690 ps[0]++;
691 SetProp(P_PREPARED_SPELL,ps);
692 write("Die Ausfuehrung Deines vorbereiteten Spruches wird verzoegert.\n");
693 } else if (ps) {
694 SetProp(P_PREPARED_SPELL,0);
695 }
696}
697
698static mixed bb;
699#ifndef BBMASTER
700#define BBMASTER "/secure/bbmaster"
701#endif
702
703/** Interpretiert Aliase und History-Kommandos
MG Mud User88f12472016-06-24 23:31:02 +0200704 \param[in] str string - Kommando des Spielers
705 \return interpretiertes Alias bzw. korrektes Kommando aus der History
706*/
707private string parsecommand(string str)
708{
709 if (str[0]=='\\')
710 {
711 // Kommando soll nicht interpretiert werden
712 return str[1..];
713 }
714 else if (str[0]=='&')
715 {
716 // Kommando aus der History
717 string cmd = str[1..];
718 int cmd_size = sizeof(cmd);
719 int cmd_found = 0;
720 if (cmd_size)
721 {
722 // Test ob &<text> etwas findet
723 for (int i=0;i<hist_size-1 && !cmd_found;i++)
724 {
725 int idx = (hist_size-i+hist_now-1)%hist_size;
726 if (history[idx][0..cmd_size-1]==cmd)
727 {
728 str = history[idx];
729 cmd_found = 1;
730 }
731 if (cmd_found)
732 {
733 if (show_processing)
734 printf("[%s]\n",str);
735 }
736 }
737 }
738 if (!cmd_found)
739 {
740 // Test, ob &<nr> klappt
741 int nummer;
742 if (str=="&&")
743 str = "&-0";
744 if (sscanf(str,"&%d",nummer))
745 {
746 if (nummer<0 || (!nummer && str[1]=='-'))
747 {
748 if (nummer<-(hist_size-1))
749 nummer=-1;
750 else
751 nummer=(hist_now+nummer-1+hist_size)%hist_size;
752 }
753 else
754 {
755 if (nummer>hist_now || hist_now-nummer>hist_size)
756 nummer=-1;
757 else
758 nummer=nummer%hist_size;
759 }
760 if (nummer<0
761 || ( (cmd=history[nummer]) =="\n\n") )
762 notify_fail("Der Befehl ist nicht in der History!\n");
763 else
764 {
765 str = cmd;
766 if (show_processing)
767 printf("[%s]\n",str);
768 }
769 }
770 }
771 }
772 switch (str)
773 {
774 case "n": return "norden";
775 case "s": return "sueden";
776 case "w": return "westen";
777 case "o": return "osten";
778 case "nw": return "nordwesten";
779 case "sw": return "suedwesten";
780 case "so": return "suedosten";
781 case "no": return "nordosten";
782 case "ob": return "oben";
783 case "u": return "unten";
784 }
785 // Test auf Alias
786 string output = "";
787 string* input = explode(str," ");
788 int input_size = sizeof(input);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200789 mixed alias = active_aliases[input[0]];
MG Mud User88f12472016-06-24 23:31:02 +0200790 if (!alias)
791 return str;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200792 // Das Alias ist in ein Array von Strings gespeichert. Alle
793 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
794 // laufender Index im Array. An der Stelle werden die Argumente vom Alias
795 // eingefuegt, alle anderen Elemente werden in den output kopiert. Negative
796 // Zahlen stehen fuer $n*, d.h. alle Argument nach dem genannten.
797 // Bsp: ({"stecke ", 1, " in ", -2 })
MG Mud User88f12472016-06-24 23:31:02 +0200798 foreach (mixed a:alias)
799 {
800 if (!intp(a))
801 output += a;
802 else
803 {
804 if (a >= 0)
805 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200806 // Einzelnes Argument ($n). Argument anstelle von a einfuegen, falls
807 // genug angegeben wurden
MG Mud User88f12472016-06-24 23:31:02 +0200808 if (input_size > a)
809 output += input[a];
810 }
811 else
812 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200813 // Argumente ab n ($n*). Alle von a bis Ende einfuegen.
MG Mud User88f12472016-06-24 23:31:02 +0200814 a = -a;
815 if (input_size > a)
816 output += implode(input[a..]," ");
817 }
818 }
819 }
820 output = _single_spaces(output);
821 str = trim(output,TRIM_RIGHT);
822 if (show_processing>1)
823 printf("[%s]\n",str);
824 return str;
825}
826
827/** Behandelt alle Sonderfaelle der Eingabe des Spielers
828 Alle Befehle des Spielers, die nicht durch Objekte behandelt
829 werden sollen, werden hier erkannt und ausgefuehrt.
830 Dazu gehoert auch die Interpretation von Aliases und History-
831 befehlen.
832 \param[in] str string: Kommando des Spielers
833 \return auszufuehrendes Kommando
834 oder 0 fuer ein nicht interpretierbares Kommando
835 oder 1 fuer ein bereits durchgefuehrtes Kommando
836*/
837mixed modify_command(string str)
838{
839
840 if (extern_call() && previous_object() &&
841 (previous_object()!=this_object() || process_call()) )
842 {
843 return 0;
844 }
845
846 // Leerzeichen an den Enden abschneiden.
847 str = trim(str, TRIM_BOTH);
848
849 if (bb)
850 BBMASTER->BBWrite(trim(str,TRIM_RIGHT,"\n"), 0);
851
852 decay_average();
853 cmds_per_time+=10000;
854
855 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=unmodified="";
856
857 if (!sizeof(str)) return "";
858
859 // Kommando wird geparst
860 unmodified=parsecommand(str);
861
862 // Environment schonmal merken.
863 last_command_env=environment();
864
865 if (unmodified == "")
866 return "";
867 // Kommando in History merken, auch wenn es im Kommandoblock abgebrochen
868 // wird.
869 AddHistory(unmodified);
870
871 // pruefen, ob Kommandoblock gesetzt ist.
872 // (Fuer Magier mit mschau ein wird das ignoriert.)
873 // BTW: Es wird absichtlich nicht das Ergebnis der Closure zurueckgegeben,
874 // sonst wuerde man beliebigen Objekten nicht nur das Abbrechen, sondern
875 // auch das Aendern von Kommandos ermoeglichen.
876 if (disablecommands && !IS_LEARNING(ME) )
877 {
878 if (disablecommands[B_TIME] >= time()
879 && objectp(disablecommands[B_OBJECT]))
880 {
881 // disablecommands valid
882 // hart-kodierte Ausnameliste pruefen
883 if ( member(({"mrufe","mschau","bug","idee","typo","detail"}),
884 explode(str," ")[0]) == -1)
885 {
886 if (closurep(disablecommands[B_VALUE]))
887 {
888 if (funcall(disablecommands[B_VALUE],_return_args(unmodified)))
889 {
890 // Non-zero Closure-Ergebnis, Abbruch. Die gerufene Funktion ist
891 // fuer eine geeignete Meldung an den Spieler verantwortlich.
892 return 1;
893 }
894 }
895 // wenn Text, dann auch pruefen, ob das Kommandoverb in den Ausnahmen
896 // steht. (query_verb() geht leider hier noch nicht.)
897 else if (stringp(disablecommands[B_VALUE])
898 && member(disablecommands[B_EXCEPTIONS],
899 explode(str," ")[0]) == -1)
900 {
901 // meldung ausgeben...
902 tell_object(PL, disablecommands[B_VALUE]);
903 // und Ende...
904 return 1;
905 }
906 }
907 }
908 else disablecommands=0;
909 }
910
911 // Verfolger direkt ins Env reinholen.
912 if (remove_call_out("TakeFollowers")>=0)
913 catch(TakeFollowers();publish);
914
915 DelayPreparedSpells();
916
917 // Historyeintrag korrigieren
918 if (unmodified[0]=='^')
919 {
920 string *oldnew,pre,post;
921 if (sizeof(oldnew=explode(unmodified,"^"))>2)
922 {
923 int hist_idx = (hist_now-1)%hist_size;
924 sscanf(history[hist_idx],"%s"+oldnew[1]+"%s", pre, post);
925 unmodified = pre+oldnew[2]+post;
926 if (show_processing)
927 write("["+unmodified+"]\n");
928 // korrigiertes Kommando natuerlich auch in die History.
929 AddHistory(unmodified);
930 }
931 }
932
933 if( bb )
934 BBMASTER->BBWrite(" -> " + unmodified, 1);
935
936 if (show_processing>1)
937 printf("[%s]\n",unmodified);
938
939 mixed ret = _return_args(unmodified);
940
941 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
942 // dorthin melden.
943 if (syntaxdb)
944 {
945 if (!objectp(syntaxdb[0]))
946 syntaxdb[0] = find_object("/secure/syntaxdb");
947 if (syntaxdb[0])
948 catch(syntaxdb[0]->start_cmd(unmodified);nolog);
949 }
950 return ret;
951}
952
953static int do_list(string str)
954{
955 string *cmdlist;
956 int i;
957
958 if (!QueryProp(P_WANTS_TO_LEARN))
959 return 0;
960 cmdlist=old_explode(_unparsed_args()||"",";")-({ "" });
961 for (i=0;i<sizeof(cmdlist);i++)
962 {
963 cmdlist[i]=implode(old_explode(cmdlist[i]," ")-({}), " ");
964 if (show_processing)
965 write("["+cmdlist[i]+"]\n");
966 command(cmdlist[i]);
967 }
968 return 1;
969}
970
971//falls die aliasliste kaputt ist ...
972
973int unalias_all()
974{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200975 if (IS_ELDER(this_interactive()))
976 {
977 aliases=([]);
Zesstra3fe70c62019-05-28 22:46:19 +0200978 merge_family_aliases(0,0);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200979 }
MG Mud User88f12472016-06-24 23:31:02 +0200980 return 1;
981}
982
983object _query_last_command_env()
984{
985 return last_command_env;
986}
987
988int _query_show_alias_processing()
989{
990 return show_processing;
991}
992
993int _query_histmin()
994{
995 return histmin;
996}
997
998varargs void AddAction(mixed fun, mixed cmd, int flag, int lvl)
999{
1000 int i;
1001 mixed *cmds;
1002
1003 log_file( "ARCH/ADD_ACTION", sprintf(
1004 "%s:\n TO: %O TP: %O PO: %O\n fun: %O cmd: %O flag: %O lvl: %O",
1005 dtime(time()), this_object(), this_player(), previous_object(),
1006 fun, cmd, flag, lvl));
1007
1008 if (!(cmds=Query(P_LOCALCMDS))) cmds=({});
1009
1010 if (!pointerp(cmd)) cmd=({cmd});
1011
1012 for (i = sizeof(cmd)-1; i>=0; i--)
1013 cmds += ({({ cmd[i] , fun, flag, lvl})});
1014
1015 Set(P_LOCALCMDS, cmds);
1016}
1017
1018static int auswerten(mixed cmd, string str)
1019{
1020 if (closurep(cmd))
1021 return funcall(cmd,str);
1022 if (stringp(cmd))
1023 return call_other(this_object(),cmd,str);
1024 return 0;
1025}
1026
1027static varargs int __auswerten(string str, string intern)
1028{
1029 string verb;
1030 mixed *cmd, cmds;
1031 int i,ret,lvl,l,vl;
1032
1033 if (!intern)
1034 verb=query_verb();
1035 else
1036 verb=intern;
1037 lvl=query_wiz_level(ME);
1038 vl=sizeof(verb);
1039 cmds=QueryProp(P_LOCALCMDS);
1040
1041 for(i=sizeof(cmds)-1;i>=0;i--)
1042 {
1043 cmd=cmds[i],l=sizeof(cmd[0]);
1044 if (cmd[0]==verb[0..l-1] && cmd[3]<=lvl && (cmd[2]||vl==l) &&
1045 (ret=auswerten(cmd[1],str)))
1046 return ret;
1047 }
1048 // An dieser Stelle gibt es hier und vermutlich nirgendwo anders etwas, was
1049 // dieses Kommando als gueltig betrachtet. Wir informieren ggf. die
1050 // Syntax-DB. (Achtung: wenn jemand ne add_action() im Spielerobjekt
1051 // einbaut, die vor dieser eingetragen wird, ist die Annahme ggf. falsch.)
1052 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1053 // dorthin melden.
1054 if (syntaxdb)
1055 {
1056 if (!objectp(syntaxdb[0]))
1057 syntaxdb[0] = find_object("/secure/syntaxdb");
1058 if (syntaxdb[0])
1059 catch(syntaxdb[0]->cmd_unsuccessful();nolog);
1060 }
1061
1062 return 0;
1063}
1064
1065public void syntax_log_ep(int type)
1066{
1067 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1068 // dorthin melden.
1069 if (syntaxdb && syntaxdb[0])
1070 {
1071 catch(syntaxdb[0]->LogEP(type);nolog);
1072 }
1073}
1074
1075static mixed _query_localcmds()
1076{
1077 mixed *l;
1078
1079 l=Query(P_LOCALCMDS);
1080 if (!pointerp(l))
1081 l=({});
1082 return ({
1083 ({"ali","alias",0,0}),
1084 ({"alias","alias",0,0}),
1085 ({"unali","unalias",1,0}),
1086 ({"histmin","histmin",0,0}),
1087 ({"histlen","histlen",0,0}),
1088 ({"hist","show_hist",0,0}),
1089 ({"history","show_hist",0,0}),
1090 ({"do","do_list",0,LEARNER_LVL}),
1091 ({"ersetzungsanzeige","replacedisplay",0,0}),
1092 ({"syntaxsammlung","collect_cmds",0,0}),
1093 ({"fehlermeldung","set_errormessage",0,SEER_LVL}),
1094 })+l;
1095}
1096
1097static int collect_cmds(string cmd)
1098{
1099 if (!stringp(cmd))
1100 {
1101 _notify("Mit diesem Befehl kannst Du mithelfen, Syntaxen im MG zu "
1102 "verbessern. Wenn Du einverstanden bist, speichern wir "
1103 "anonym (d.h. ohne Deinen Charnamen), welche Deiner Befehle "
1104 "erfolgreich und nicht erfolgreich waren. Uebliche "
1105 "Kommunikationsbefehle werden dabei nicht gespeichert.",
1106 0);
1107 _notify("Mit 'syntaxsammlung ja' kannst Du die Speicherung einschalten, "
1108 "mit 'syntaxsammlung nein' kannst Du sie ausschalten.",0);
1109 _notify("Deine Befehle werden zur Zeit"
1110 + (QueryProp("_syntaxdb") ? " " : " NICHT ")
1111 + "gespeichert.", 0);
1112 }
1113 else if (cmd == "ja")
1114 {
1115 SetProp("_syntaxdb", 1);
1116 _notify("Ab jetzt werden Deine Befehle gespeichert. Vielen Dank!", 0);
1117 }
1118 else
1119 {
1120 SetProp("_syntaxdb", 0);
1121 _notify("Ab jetzt werden Deine Befehle NICHT gespeichert.", 0);
1122 }
1123 return 1;
1124}
1125
1126int _query_command_average()
1127{
1128 decay_average();
1129 return cmds_per_time;
1130}
1131
1132nomask void __set_bb(int flag) {
1133 if( previous_object()!=find_object(BBMASTER) || process_call() )
1134 return;
1135 bb=flag;
1136}
1137
1138
1139nomask public void countCmds( int type, string key )
1140{
1141 string tmp;
1142
1143 if ( this_player() != this_interactive()
1144 || this_interactive() != this_object()
1145 || member( cmd_types, type ) < 0 )
1146 return;
1147
1148 tmp = sprintf( "%d\n%s", type, key );
1149
1150 commands -= ({ tmp });
1151 commands += ({ tmp });
1152 commands = commands[0..max_commands-1];
1153}
1154
1155
1156nomask public string *getCmds()
1157{
1158 string *tmp;
1159
1160 if ( previous_object() != find_object(BBMASTER) )
1161 return ({});
1162
1163 tmp = commands;
1164 commands = ({});
1165
1166 return tmp;
1167}
1168
1169/*
1170 * Force the monster to do a command. The force_us() function isn't
1171 * always good, because it checks the level of the caller, and this function
1172 * can be called by a room.
1173 */
1174int command_me(string cmd)
1175{
1176 if (IS_LEARNER(ME))
1177 {
1178 if (!this_interactive() || !previous_object())
1179 return 0;
1180 if( geteuid(ME)!=geteuid(this_interactive())
1181 || geteuid(ME)!=geteuid(previous_object()) )
1182 {
1183 if( query_wiz_level(ME)<query_wiz_level(previous_object()))
1184 tell_object(ME,previous_object()->name()+" zwingt Dich zu: "
1185 + cmd + ".\n");
1186 else
1187 {
1188 tell_object(ME,previous_object()->name()
1189 + " versucht, Dich zu " + cmd + " zu zwingen.\n" );
1190 return 0;
1191 }
1192 }
1193 }
1194 return command(cmd);
1195}
1196
1197
1198static mixed _query_p_lib_disablecommands() {
1199 // abgelaufen oder Objekt zerstoert? Weg damit.
1200 if (pointerp(disablecommands)
1201 && (disablecommands[B_TIME] < time()
1202 || !objectp(disablecommands[B_OBJECT])) )
1203 return(disablecommands = 0);
1204
1205 // sonst Kopie zurueck (copy(0) geht)
1206 return(copy(disablecommands));
1207}
1208
1209static mixed _set_p_lib_disablecommands(mixed data) {
1210
1211 // setzendes Objekt ermitteln, da diese Funktion nur per SetProp() gerufen
1212 // werden sollte (!), ist das PO(1);
1213 object origin = previous_object(1);
1214 // wenn nicht existent, direkt abbruch
1215 if (!objectp(origin))
1216 return _query_p_lib_disablecommands();
1217
1218 // Prop loeschen? Explizit loeschen darf jeder, allerdings nicht direkt
1219 // ungeprueft ueberschreiben.
1220 if (!data) {
1221 return (disablecommands = 0 );
1222 }
1223 // mal direkt buggen bei falschen Datentyp, damits auffaellt.
1224 if (!pointerp(data) || sizeof(data) < 2 || !intp(data[0])
1225 || (!stringp(data[1]) && !closurep(data[1]))
1226 || (sizeof(data) >= 3 && !pointerp(data[2])) )
1227 raise_error(sprintf(
1228 "Wrong data type for P_DISABLE_COMMANDS. Expected Array with "
1229 "2 or 3 elements (int, string|closure, [string*]), got %.25O\n",
1230 data));
1231
1232 // Wenn abgelaufen oder gleiches Objekt wie letztes Mal: eintragen.
1233 if (!disablecommands || (disablecommands[B_TIME] < time()
1234 || !objectp(disablecommands[B_OBJECT])
1235 || disablecommands[B_OBJECT] == origin) ) {
1236 // Loggen nur, wenn eine Closure eingetragen wird. Reduziert den
1237 // Logscroll und Strings haben deutlich weniger Missbrauchspotential.
1238 if (closurep(data[1])) {
1239 CBLOG(sprintf("[%s] CB gesetzt von %O, gueltig bis %s, Daten: %O\n",
1240 strftime("%Y%m%d-%H:%M:%S"),origin,
1241 strftime("%Y%m%d-%H:%M:%S",data[0]),
1242 (stringp(data[1]) ? regreplace(data[1],"\n","\\n",0)
1243 : data[1])));
1244 }
1245 if (sizeof(data)+1 <= B_EXCEPTIONS)
1246 disablecommands = ({ origin, data[0], data[1], ({}) });
1247 else
1248 disablecommands = ({ origin, data[0], data[1], data[2] });
1249 return(copy(disablecommands));
1250 }
1251
1252 return(_query_p_lib_disablecommands());
1253}
1254
1255static mixed _set__syntaxdb(mixed v)
1256{
1257 Set("_syntaxdb", v, F_VALUE);
1258 if (v)
1259 syntaxdb = ({find_object("/secure/syntaxdb")});
1260 else
1261 syntaxdb = 0;
1262 return QueryProp("_syntaxdb");
1263}
1264