1 #pragma strong_types
2 #pragma save_types
3 
4 /* obj/simul_efun.c
5  *
6  * The simul-efun object provides functions which can be accessed as
7  * if they were true efuns. This is most useful to protect sensitive
8  * efuns from clumsy fingers, but is also used to simulate functions
9  * which formerly were implemented by the driver.
10  */
11 
12 #define MAX_LOG_SIZE 50000
13 
14 #define BACKBONE_WIZINFO_SIZE 5
15 
16 #define LIVING_NAME 3
17 #define NAME_LIVING 4
18 
19 #include "/sys/wizlist.h"
20 #include "/sys/erq.h"
21 #include "/sys/files.h"
22 
23 mapping living_name_m, name_living_m;
24   /* Living -> Name and Name -> Living mappings.
25    */
26 
27 //---------------------------------------------------------------------------
start_simul_efun()28 void start_simul_efun()
29 
30 /* Activate the simul-efun object.
31  */
32 
33 {
34     mixed *info;
35 
36     if ( !(info = get_extra_wizinfo(0)) )
37 	set_extra_wizinfo(0, info = allocate(BACKBONE_WIZINFO_SIZE));
38     if (!(living_name_m = info[LIVING_NAME]))
39 	living_name_m = info[LIVING_NAME] = m_allocate(0, 1);
40     if (!(name_living_m = info[NAME_LIVING]))
41 	name_living_m = info[NAME_LIVING] = m_allocate(0, 1);
42 }
43 
44 //---------------------------------------------------------------------------
ls(string path)45 void ls (string path)
46 
47 /* Print the directory listing of <path>, like the unix command.
48  */
49 
50 {
51     int max, i, len, tmp;
52     status trunc_flag;
53     mixed *dir;
54     set_this_object(previous_object());
55     dir = get_dir (path, GETDIR_NAMES|GETDIR_SIZES);
56     if (path != "/")
57 	path += "/";
58     if (!dir) {
59         write("No such directory.\n");
60         return;
61     }
62     if (sizeof(dir) > 999)
63     {
64         dir = dir[0..998];
65         trunc_flag = 1;
66     }
67     for(i = sizeof(dir); i--; ) {
68         if(dir[i--] == -2)
69             dir[i]+="/";
70         len = strlen(dir[i]);
71         if (len > max)
72             max = len;
73     }
74     ++max;
75     if (max > 79)
76         max = 79;
77     for (i=0; i < sizeof(dir); i+=2) {
78 	string name;
79             name = dir[i];
80 	tmp = strlen(name);
81 	if (len + tmp > 79) {
82 	    len = 0;
83 	    write("\n");
84 	}
85 	write(name);
86         if (len + max > 79) {
87             write("\n");
88             len = 0;
89         } else {
90             write("                                                                                "[80-max+tmp..]);
91             len += max;
92         }
93     }
94     write("\n");
95     if (trunc_flag) write("***TRUNCATED***\n");
96 }
97 
98 //---------------------------------------------------------------------------
create_wizard(string owner,string domain)99 string create_wizard(string owner, string domain)
100 {
101     mixed result;
102 
103     set_this_object(previous_object());
104     result =
105       (mixed)__MASTER_OBJECT__->master_create_wizard(owner, domain, previous_object());
106     if (stringp(result)) return result;
107     return 0;
108 }
109 
110 //---------------------------------------------------------------------------
log_file(string file,string str)111 void log_file(string file,string str)
112 {
113     string file_name;
114     int *st;
115 
116     file_name = "/log/" + file;
117 #ifdef COMPAT_FLAG
118     if (sizeof(regexp(({file}), "/")) || file[0] == '.' || strlen(file) > 30 )
119     {
120         write("Illegal file name to log_file("+file+")\n");
121         return;
122     }
123 #endif
124     if ( sizeof(st = get_dir(file_name,2) ) && st[0] > MAX_LOG_SIZE) {
125 	catch(rename(file_name, file_name + ".old")); /* No panic if failure */
126     }
127     set_this_object(previous_object());
128     write_file(file_name, str);
129 }
130 
131 //---------------------------------------------------------------------------
localcmd()132 void localcmd()
133 {
134     string *verbs;
135     int i,j;
136 
137     verbs = query_actions(this_player());
138     for (i=0, j = sizeof(verbs); --j >= 0; i++) {
139 	write(verbs[i]+" ");
140     }
141     write("\n");
142 }
143 
144 //---------------------------------------------------------------------------
unique_array(mixed * arr,string func,mixed skipnum)145 mixed *unique_array(mixed *arr,string func,mixed skipnum)
146 {
147     mixed *al, last;
148     mapping m;
149     int i, j, k, *ordinals;
150 
151     if (sizeof(arr) < 32)
152         return efun::unique_array(arr, func, skipnum);
153     for (ordinals = allocate(i = sizeof(arr)); i--; )
154 	    ordinals[i] = i;
155     m = mkmapping(map_objects(arr, func), ordinals, arr);
156     al = m_indices(m);
157     ordinals = m_values(m, 0);
158     arr = m_values(m, 1);
159     if (k = i = sizeof(al)) {
160         for (last = al[j = --i]; i--; ) {
161             if (al[i] != last) {
162                 if (last != skipnum) {
163                     arr[--k] = arr[i+1..j];
164                     ordinals[k] = ordinals[j];
165                 }
166                 last = al[j = i];
167             }
168         }
169         if (last != skipnum) {
170             arr[--k] = arr[0..j];
171             ordinals[k] = ordinals[j];
172         }
173     }
174     return m_values(mkmapping(ordinals[k..], arr[k..]),0);
175 }
176 
177 //---------------------------------------------------------------------------
snoop(mixed snoopee)178 varargs mixed snoop(mixed snoopee)
179 {
180     int result;
181 
182     if (snoopee && query_snoop(snoopee)) {
183         write("Busy.\n");
184         return 0;
185     }
186     result = snoopee ? efun::snoop(this_player(), snoopee)
187                      : efun::snoop(this_player());
188     switch (result) {
189 	case -1:
190 	    write("Busy.\n");
191 	    break;
192 	case  0:
193 	    write("Failed.\n");
194 	    break;
195 	case  1:
196 	    write("Ok.\n");
197 	    break;
198     }
199     if (result > 0) return snoopee;
200 }
201 
202 //---------------------------------------------------------------------------
notify_fail(mixed message)203 void notify_fail(mixed message)
204 {
205     if ( !(stringp(message) && strstr(message, "@@") < 0) ) {
206 	efun::notify_fail(message);
207 	return;
208     }
209     efun::notify_fail(
210       funcall(
211         bind_lambda(#'lambda, previous_object()),
212         0, ({#'process_string, message})
213       )
214     );
215 }
216 
217 //---------------------------------------------------------------------------
218 string version() {
219     return __VERSION__;
220 }
221 
222 //---------------------------------------------------------------------------
223 string query_host_name() {
224     return __HOST_NAME__;
225 }
226 
227 //---------------------------------------------------------------------------
228 nomask void set_environment() {}
229 
230 nomask void set_this_player() {}
231 
232 //---------------------------------------------------------------------------
233 varargs void add_worth(int value, object ob)
234 {
235     mixed old;
236 #ifdef __COMPAT_MODE__
237     switch (explode(object_name(previous_object()), "/")[0]) {
238 #else
239     switch (explode(object_name(previous_object()), "/")[1]) {
240 #endif
241       default:
242 	raise_error("Illegal call of add_worth.\n");
243       case "obj":
244       case "std":
245       case "room":
246     }
247     if (!ob) {
248 	if ( !(ob = previous_object(1)) )
249 	    return;
250     }
251     if (intp(old = get_extra_wizinfo(ob)))
252         set_extra_wizinfo(ob, old + value);
253 }
254 
255 //---------------------------------------------------------------------------
256 varargs void wizlist(string name)
257 {
258     int i, pos, total_cmd;
259     int *cmds;
260     mixed *a;
261     mixed *b;
262 
263     if (!name) {
264         name = this_player()->query_real_name();
265         if (!name)
266         {
267             write("Need to provide a name or 'ALL' to the wizlist function.\n");
268             return;
269         }
270     }
271     a = transpose_array(wizlist_info());
272     cmds = a[WL_COMMANDS];
273     a[WL_COMMANDS] = a[0];
274     a[0] = cmds;
275 
276     a = unmkmapping(apply(#'mkmapping, a));
277     cmds = a[0];
278     a[0] = a[WL_COMMANDS];
279     a[WL_COMMANDS] = cmds;
280 
281     if ((pos = member(a[WL_NAME], name)) < 0 && name != "ALL")
282     {
283         write("No wizlist info for '"+name+"' found.\n");
284         return;
285     }
286     b = allocate(sizeof(cmds));
287     for (i = sizeof(cmds); i;) {
288         b[<i] = i;
289         total_cmd += cmds[--i];
290     }
291     a = transpose_array(a + ({b}) );
292     if (name != "ALL") {
293         if (pos + 18 < sizeof(cmds)) {
294             a = a[pos-2..pos+2]+a[<15..];
295         } else if (pos < sizeof(cmds) - 13) {
296             a = a[pos-2..];
297         } else {
298             a = a[<15..];
299         }
300     }
301     write("\nWizard top score list\n\n");
302     if (total_cmd == 0)
303         total_cmd = 1;
304     for (i = sizeof(a); i; ) {
305         b = a[<i--];
306         if (b[WL_GIGACOST] > 1000)
307             printf("%-15s %5d %2d%% (%d)\t[%d%4dk,%5d] %6d %d\n",
308               b[WL_NAME], b[WL_COMMANDS],
309               b[WL_COMMANDS] * 100 / total_cmd, b[<1],
310               b[WL_GIGACOST] / 1000,
311               b[WL_COST] / 1000 + (b[WL_GIGACOST] % 1000) * 1000000000,
312               b[WL_HEART_BEATS], b[WL_EXTRA], b[WL_ARRAY_TOTAL]
313             );
314         else
315             printf("%-15s %5d %2d%% (%d)\t[%4dk,%5d] %6d %d\n",
316               b[WL_NAME], b[WL_COMMANDS],
317               b[WL_COMMANDS] * 100 / total_cmd, b[<1],
318               b[WL_COST] / 1000 + (b[WL_GIGACOST] % 1000) * 1000000000,
319               b[WL_HEART_BEATS], b[WL_EXTRA], b[WL_ARRAY_TOTAL]
320             );
321     }
322     printf("\nTotal         %7d     (%d)\n\n", total_cmd, sizeof(cmds));
323 }
324 
325 //---------------------------------------------------------------------------
326 void shout(string s)
327 {
328     filter(users(), lambda(({'u}),({#'&&,
329       ({#'environment, 'u}),
330       ({#'!=, 'u, ({#'this_player})}),
331       ({#'tell_object, 'u, to_string(s)})
332     })));
333 }
334 
335 //---------------------------------------------------------------------------
336 void set_living_name(string name)
337 {
338     string old;
339     mixed a;
340     int i;
341 
342     if (old = living_name_m[previous_object()]) {
343 	if (pointerp(a = name_living_m[old])) {
344 	    a[member(a, previous_object())] = 0;
345 	} else {
346 	    efun::m_delete(name_living_m, old);
347 	}
348     }
349     living_name_m[previous_object()] = name;
350     if (a = name_living_m[name]) {
351 	if (!pointerp(a)) {
352 	    name_living_m[name] = ({a, previous_object()});
353 	    return;
354 	}
355 	/* Try to reallocate entry from destructed object */
356 	if ((i = member(a, 0)) >= 0) {
357 	    a[i] = previous_object();
358 	    return;
359 	}
360 	name_living_m[name] = a + ({previous_object()});
361 	return;
362     }
363     name_living_m[name] = previous_object();
364 }
365 
366 //---------------------------------------------------------------------------
367 object find_living(string name)
368 {
369     mixed *a, r;
370     int i;
371 
372     if (pointerp(r = name_living_m[name])) {
373 	if ( !living(r = (a = r)[0])) {
374 	    for (i = sizeof(a); --i;) {
375 		if (living(a[<i])) {
376 		    r = a[<i];
377 		    a[<i] = a[0];
378 		    return a[0] = r;
379 		}
380 	    }
381 	}
382 	return r;
383     }
384     return living(r) && r;
385 }
386 
387 //---------------------------------------------------------------------------
388 object find_player(string name)
389 {
390     mixed *a, r;
391     int i;
392 
393     if (pointerp(r = name_living_m[name])) {
394 	if ( !(r = (a = r)[0]) || !query_once_interactive(r)) {
395 	    for (i = sizeof(a); --i;) {
396 		if (a[<i] && query_once_interactive(a[<i])) {
397 		    r = a[<i];
398 		    a[<i] = a[0];
399 		    return a[0] = r;
400 		}
401 	    }
402 	    return 0;
403 	}
404 	return r;
405     }
406     return r && query_once_interactive(r) && r;
407 }
408 
409 /*===========================================================================
410  * The following functions provide the necessary compatibility of this
411  * compat-mode mudlib with a plain driver.
412  * Just the parse_command() efun is not simulated.
413  */
414 
415 #ifndef __COMPAT_MODE__
416 //---------------------------------------------------------------------------
417 string function_exists (string str, object ob)
418 {
419     string rc;
420 
421     rc = efun::function_exists(str, ob);
422     return stringp(rc) ? rc[1..] : 0;
423 }
424 
425 //---------------------------------------------------------------------------
426 string object_name(object ob)
427 {
428     string rc;
429 
430     rc = efun::object_name(ob);
431     return stringp(rc) ? rc[1..] : 0;
432 }
433 
434 //---------------------------------------------------------------------------
435 string program_name(object ob)
436 {
437     string rc;
438 
439     rc = efun::program_name(ob);
440     return stringp(rc) ? rc[1..] : 0;
441 }
442 
443 //---------------------------------------------------------------------------
444 string* inherit_list(object ob)
445 {
446     string *rc;
447     int i;
448 
449     rc = efun::inherit_list(ob);
450     for (i = sizeof(rc); i-- > 0; )
451         rc[i] = rc[i][1..];
452     return rc;
453 }
454 
455 //---------------------------------------------------------------------------
456 string to_string(mixed arg)
457 {
458     string rc;
459 
460     rc = efun::to_string(arg);
461     return objectp(arg) ? rc[1..] : rc;
462 }
463 
464 //---------------------------------------------------------------------------
465 string creator(object ob)
466 {
467     return getuid(ob);
468 }
469 
470 //---------------------------------------------------------------------------
471 varargs void add_action(string fun, string cmd, int flag)
472 {
473     if (fun == "exit")
474         raise_error("Illegal to define a command to the exit() function.\n");
475 
476     efun::set_this_object(previous_object());
477     if (cmd)
478         efun::add_action(fun, cmd, flag);
479 }
480 
481 //---------------------------------------------------------------------------
482 object present_clone (mixed obj, object env)
483 {
484   if (stringp(obj) && '/' != obj[0])
485       obj = "/"+obj;
486   return efun::present_clone(obj, env);
487 }
488 
489 //---------------------------------------------------------------------------
490 #endif /* __COMPAT_MODE__ */
491 
492 #if !__EFUN_DEFINED__(present)
493 //---------------------------------------------------------------------------
494 varargs object present(mixed ob, object env)
495 {
496     int specific, num, i;
497     object found;
498     string str;
499 
500     if (!env)
501     {
502         env = previous_object();
503         specific = 0;
504     }
505     else
506         specific = 1;
507 
508     if (objectp(ob))
509     {
510         /* Quick check: is ob there or not? */
511 
512         if (specific)
513             return environment(ob) == env ? ob : 0;
514         if (environment(ob) == env
515          || (environment(env) && environment(ob) == environment(env))
516            )
517             return ob;
518         return 0;
519     }
520 
521     /* Search by name. Prepare the search parameters */
522     if (2 != sscanf(ob, "%s %d", str, num))
523     {
524         num = 1;
525         str = ob;
526     }
527 
528     /* First, search in env by name */
529     for (found = first_inventory(env), i = 0
530         ; found
531         ; found = next_inventory(env))
532     {
533         if (found->id(str) && ++i == num)
534             break;
535         if (!found)  /* may happen */
536             break;
537     }
538 
539     if (found || specific)
540         return found;
541 
542     /* If not found, search in environment(env) by name */
543     env = environment(env);
544     if (!env)
545         return 0;
546     if (env->id(ob))
547         return env;
548     if (!env) /* the id() may have destructed env */
549         return 0;
550 
551     for (found = first_inventory(env), i = 0
552         ; found
553         ; found = next_inventory(env))
554     {
555         if (found->id(str) && ++i == num)
556             break;
557         if (!found)  /* may happen */
558             break;
559     }
560 
561     return found;
562 }
563 
564 #endif /* !efun_defined(present) */
565 
566 #if !__EFUN_DEFINED__(transfer)
567 //---------------------------------------------------------------------------
568 /*
569  * Transfer an object from an object to an object.
570  * Call add_weight(), drop(), get(), prevent_insert(), add_weight(),
571  * and can_put_and_get() where needed.
572  * Return 0 on success, and special code on failure:
573  *
574  * 1: To heavy for destination.
575  * 2: Can't be dropped.
576  * 3: Can't take it out of it's container.
577  * 4: The object can't be inserted into bags etc.
578  * 5: The destination doesn't allow insertions of objects.
579  * 6: The object can't be picked up.
580  */
581 int transfer(object item, object dest)
582 {
583     int weight;
584     object from;
585 
586     efun::set_this_object(previous_object());
587 
588     weight = item->query_weight();
589     if (!item)
590         return 3;
591 
592     from = environment(item);
593     if (from)
594     {
595         /*
596          * If the original place of the object is a living object,
597          * then we must call drop() to check that the object can be dropped.
598          */
599         if (living(from))
600         {
601             if (item->drop() || !item)
602                 return 2;
603         }
604         /*
605          * If 'from' is not a room and not a player, check that we may
606          * remove things out of it.
607          */
608         else if (environment(from))
609         {
610             if (!from->can_put_and_get() || !from)
611                 return 3;
612         }
613     }
614 
615     /*
616      * If the destination is not a room, and not a player,
617      * Then we must test 'prevent_insert', and 'can_put_and_get'.
618      */
619     if (environment(dest) && !living(dest))
620     {
621         if (item->prevent_insert())
622             return 4;
623         if (!dest->can_put_and_get() || !dest)
624             return 5;
625     }
626 
627     if (living(dest))
628     {
629         if (!item->get() || !item)
630             return 6;
631     }
632 
633     /*
634      * If it is not a room, correct the total weight in the destination.
635      */
636     if (environment(dest) && weight)
637     {
638         if (!dest->add_weight(weight) || !dest)
639             return 1;
640     }
641 
642     /*
643      * If it is not a room, correct the weight in the 'from' object.
644      */
645     if (from && environment(from) && weight)
646     {
647         from->add_weight(-weight);
648     }
649 
650     move_object(item, dest);
651 
652     return 0;
653 }
654 
655 #endif /* !efun_define(transfer) */
656 
657 #if !__EFUN_DEFINED__(extract)
658 //---------------------------------------------------------------------------
659 mixed extract (mixed data, varargs mixed*from_to)
660 
661 {
662     int from, to;
663 
664     if (!stringp(data) && !pointerp(data))
665     {
666         raise_error("Illegal type for extract(): must be string or array.\n");
667         return 0;
668     }
669 
670     switch(sizeof(from_to))
671     {
672     case 0: return data;
673     case 1:
674         if (!intp(from_to[0]))
675         {
676             raise_error("Illegal 'from' index for extract(): must be a number.\n");
677             return 0;
678         }
679         from = from_to[0];
680         if (from >= 0)
681             return data[from..];
682         return data[<-from..];
683     case 2:
684         if (!intp(from_to[0]) || !intp(from_to[1]))
685         {
686             raise_error("Illegal index for extract(): must be a number.\n");
687             return 0;
688         }
689         from = from_to[0];
690         to = from_to[1];
691         if (from >= 0)
692         {
693             if (to >= 0)
694                 return data[from..to];
695             return data[<from..<-to];
696         }
697         if (to >= 0)
698             return data[<-from..to];
699         return data[<from..<-to];
700     }
701 
702     raise_error("Illegal number of arguments for extract().\n");
703     return 0;
704 }
705 
706 #endif /* !efun_defined(extract) */
707 
708 /*************************************************************************/
709