xml_converter._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * $Id: xml_converter.pike,v 1.3 2009/08/07 16:14:56 nicke Exp $
18  */
19 inherit "/kernel/module";
20 inherit "/base/xml_data";
21 #include <macros.h>
22 #include <database.h>
23 #include <attributes.h>
24 #include <classes.h>
25 #include <types.h>
26 #include <access.h>
27 #include <events.h>
28 #include <client.h>
29 #include <config.h>
30 class xml_converter : public module,xml_data{
31 public:
32 
33 
34 /************** deprecated module *****************/
35 
36 
37 
38 import XMLCodegen;
39 import httplib;
40 
41 
42 
43 
44 //#define XML_DEBUG
45 
46 #ifdef XML_DEBUG
47 #define DEBUG_XML(s) werror(s+"\n")
48 #else
49 #define DEBUG_XML(s)
50 #endif
51 
52 #define ID_OBJECT 0
53 #define ID_FUNC 1
54 #define ID_PARAMS 2
55 #define ID_CONV 3
56 
57 #define ID_THIS 1
58 #define ID_THIS_USER 2
59 
60 #ifdef RESTRICTED_NAMES
61 #define OBJ_DESC_OR_NAME OBJ_DESC
62 #else
63 #define OBJ_DESC_OR_NAME OBJ_NAME
64 #endif
65 
66 class OBJECT {
67 public:
68  int id;
69  object obj;
70  mapping vars;
71  void create(int i, void|object o) { id = i; obj = o; }
72  string get_identifier() { return obj->get_identifier(); }
73  function find_function(string f) { return obj->find_function(f); }
74 };
75 
76 class Param {
77 public:
78  mixed val;
79  mixed def; // the default value
80  string name;
81 
82  mixed cast(string castto) {
83  switch(castto) {
84  case "int":
85  return (int)val;
86  case "string":
87  return (string)val;
88  default:
89  return val;
90  }
91  }
92 };
93 
94 OBJECT THIS = OBJECT(ID_THIS);
95 OBJECT THIS_USER = OBJECT(ID_THIS_USER);
96 OBJECT CONV = OBJECT(0);
97 OBJECT LAST = OBJECT(0);
98 OBJECT ACTIVE = OBJECT(0);
99 OBJECT XSL = OBJECT(0);
100 OBJECT ENV = OBJECT(0);
101 
102 class KEYVALUE {
103 public:
104  mixed key;
105  mixed val;
106 };
107 
108  mapping activeThreadMap = ([ ]);
109  mapping params = ([ ]);
110 
111 KEYVALUE ENTRY = KEYVALUE();
112 
113 
114 mapping objXML = ([ CLASS_OBJECT: ([
115  "name": ({ THIS, "query_attribute", ({ OBJ_NAME }), show }),
116  "icon": ({ THIS, "get_icon", ({ }), show_object_ext }),
117  "environment": ({ THIS, "get_environment", ({ }), show }),
118  "id": ({ THIS, "get_object_id", ({ }), show }),
119  "last-modified": ({ CONV, "get_last_modified", ({ THIS, }), get_time }),
120  "modified-by": ({ THIS, "query_attribute", ({DOC_USER_MODIFIED }),show}),
121  "created": ({ THIS, "query_attribute",
122  ({OBJ_CREATION_TIME }), get_time }),
123  "owner": ({ THIS, "get_creator", ({ }), show }),
124  "URL": ({ THIS, "get_identifier", ({ }), no_uml }),
125  "content": ({ CONV, "show_content", ({ THIS }), 0 }),
126  "annotated": ({ CONV, "show_annotations_size", ({ THIS }), 0 }),
127  ]),
128 ]);
129 
130 mapping annotationXML = ([ CLASS_OBJECT: objXML[CLASS_OBJECT] +
131 ([ "mime-headers": ({ THIS, "query_attribute", ({ MAIL_MIMEHEADERS }),
132  show_mapping }),
133  "description": ({ THIS, "query_attribute", ({OBJ_DESC_OR_NAME}), show })
134 ]), ]);
135 
136 mapping linkXML = ([ CLASS_LINK: ([
137  "link": ({ THIS, "get_link_object", ({ }), show_object_ext }),
138  "action": ({ THIS, "get_link_action", ({ }), show }),
139  ]), ]);
140 
141 mapping exitXML = ([ CLASS_EXIT: ([
142  "exit": ({ THIS, "get_exit", ({ }), show_exit }),
143  ]), ]);
144 
145 
146 mapping userXML = ([ CLASS_USER: ([
147  "email": ({ THIS, "query_attribute", ({ USER_EMAIL }), show }),
148  "inventory": ({ THIS, "get_inventory", ({ }), show_size}),
149  "mailbox-size": ({ THIS, "get_annotations", ({ }), show_mailbox_size }),
150  "trail": ({ THIS, "query_attribute", ({ "trail" }), show_trail }),
151  "id": ({ THIS, "get_object_id", ({ }), show }),
152  "fullname": ({ THIS, "query_attribute", ({USER_FULLNAME}),show}),
153  "firstname": ({ THIS, "query_attribute", ({USER_FIRSTNAME}), show}),
154  "name": ({ THIS, "query_attribute", ({ OBJ_NAME }), 0 }),
155  "identifier": ({ THIS, "get_user_name", ({ }), show }),
156  "icon": ({ THIS, "query_attribute", ({ OBJ_ICON }), show }),
157  "environment": ({ THIS, "get_environment", ({ }), show }),
158  "description": ({ THIS, "query_attribute", ({ OBJ_DESC }), show }),
159  "carry": ({ CONV, "show_carry", ({ }), 0 }),
160  "admin": ({ (MODULE_GROUPS ? MODULE_GROUPS->lookup("admin") : 0),"is_member", ({ THIS }), show_truefalse }),
161  "active-group": ({ THIS, "get_active_group", ({ }), show }),
162  "status": ({ THIS, "get_status", ({ }), show_status }),
163  "language": ({ THIS, "query_attribute", ({ USER_LANGUAGE }), show }),
164  ]), ]);
165 
166 mapping userInvXML = ([ CLASS_USER: ([
167  "id": ({ THIS, "get_object_id", ({ }), show }),
168  "name": ({ THIS, "query_attribute", ({ OBJ_NAME }), 0 }),
169  "icon": ({ THIS, "query_attribute", ({ OBJ_ICON }), show }),
170  "status": ({ THIS, "get_status", ({ }), show_status }),
171  ]), ]);
172 
173 
174 mapping annotationsXML = ([ CLASS_OBJECT: ([
175  "annotations": ({ THIS, "get_annotations_for", ({ THIS_USER }),
176  show_annotations }),
177  "active-content": ({ ACTIVE, "get_content", ({ }), show }),
178  ]), ]);
179 
180 mapping userDetailsXML = ([ CLASS_USER: ([
181  "groups": ({ THIS, "get_groups", ({ }), show }),
182  "access": ({ CONV, "get_basic_access", ({ THIS }), 0 }),
183  "user": ({ 0, this_user, ({ }), userXML }),
184  "attributes": ({ THIS, "get_attributes", ({ }), ([
185  "attribute": ({ CONV, "show_attribute", ({ ENTRY }),0})
186  ]), })
187  ]) + userXML[CLASS_USER], ]);
188 
189 
190 mapping containerXML = ([
191  CLASS_CONTAINER: ([
192  "description": ({ THIS, "query_attribute", ({ OBJ_DESC }), show }),
193  "inventory": ({ THIS, "get_inventory", ({ }), show_size }),
194  ]),
195  ]);
196 
197 
198 mapping mailboxXML = ([
199  CLASS_OBJECT:
200  ([
201  "path": ({ CONV, "get_path", ({ THIS }), 0 }),
202  "user": ({ 0, this_user, ({ }), userXML }),
203  ])+objXML[CLASS_OBJECT],
204  CLASS_CONTAINER:
205  ([
206  "inventory": ({ THIS, "get_inventory", ({ }),
207  objXML+exitXML+linkXML+userInvXML+containerXML }),
208  ]),
209  ]);
210 
211 mapping iconsXML = ([
212  CLASS_OBJECT:
213  ([ "icons": ({ THIS, "get_icons", ({ }), show }),
214  "user": ({ 0, this_user, ({ }), userXML }),
215  ])+objXML[CLASS_OBJECT], ]);
216 
217 mapping contentXML = ([
218  CLASS_OBJECT:
219  ([
220  "path": ({ CONV, "get_path", ({ THIS }), 0 }),
221  "user": ({ 0, this_user, ({ }), userXML }),
222  ])+objXML[CLASS_OBJECT],
223  CLASS_CONTAINER:
224  ([
225  "inventory": ({ THIS, "get_inventory", ({ }),
226  objXML+exitXML+linkXML+userInvXML+containerXML}),
227  ]),
228  ]);
229 
230 
231 
232 array __sanction;
233  mapping mXML = ([ ]);
234  mapping mSelection = ([ ]);
235  array selection;
236 
237 
238 protected:
239  mapping entities = ([
240  "ä": "&#228;",
241  "Ä": "&#196;",
242  "ü": "&#252;",
243  "Ü": "&#220;",
244  "ö": "&#246;",
245  "Ö": "&#214;",
246  "<": "&lt;",
247  ">": "&gt;",
248  ]);
249 
250 /**
251  * Initialize the module, this function is called when the module is loaded.
252  *
253  */
254 protected:
255  void load_module()
256 {
257  if ( objectp(_SECURITY) )
258  __sanction = _SECURITY->get_sanction_strings();
259  // if the state of an object changed, we have to update cache !
260 }
261 
262 public:
263 
264 string no_uml(string str)
265 {
266  return httplib.no_uml(str);
267 }
268 
269 
270 
271 /**
272  * Exchange some entities to fix the html sources. Especially umlaute.
273  *
274  * @param string txt - the text where to exchange Umlaute, etc.
275  * @return the replaced text.
276  * @see
277  */
278 string htmlize(string txt)
279 {
280  string html = replace(txt, indices(entities), values(entities));
281  return html;
282 }
283 
284 /**
285  * Show function to bring a config mapping in xml format.
286  * It will have each configuration listed as config name='config-name'
287  * with the value as container data.
288  *
289  * @param mapping configs - the configuration mapping to bring to xml.
290  * @return the converted mapping.
291  */
292 string show_configs(mapping configs)
293 {
294  string xml = "";
295  foreach(indices(configs), mixed index) {
296  if ( stringp(configs[index]) || intp(configs[index]) )
297  xml += "\t<config name=\""+index+"\">"+configs[index]+"</config>\n";
298  }
299  return xml;
300 }
301 
302 string show_ports(array ports)
303 {
304  string xml = "";
305  foreach(ports, object port) {
306  xml += "<port nr='"+port->get_port()+"'>"+port->describe()+"</port>";
307  }
308  return xml;
309 }
310 
311 /**
312  * Time function just calls time().
313  *
314  * @return the current timestamp (unix-time).
315  */
316 int gettime()
317 {
318  return time();
319 }
320 
321 int cmp_names(object obj1, object obj2)
322 {
323  return lower_case(obj1->get_identifier())>lower_case(obj2->get_identifier());
324 }
325 
326 int cmp_size(object obj1, object obj2)
327 {
328  if ( obj1->get_object_class() & CLASS_CONTAINER )
329  return sizeof(obj1->get_inventory()) > sizeof(obj2->get_inventory());
330  return obj1->get_content_size() > obj2->get_content_size();
331 }
332 
333 int cmp_date(object obj1, object obj2)
334 {
335  return obj1->query_attribute(DOC_LAST_MODIFIED) >
336  obj2->query_attribute(DOC_LAST_MODIFIED);
337 }
338 
339 int cmp_names_rev(object obj1, object obj2)
340 {
341  return lower_case(obj1->get_identifier())<lower_case(obj2->get_identifier());
342 }
343 
344 int cmp_size_rev(object obj1, object obj2)
345 {
346  if ( obj1->get_object_class() & CLASS_CONTAINER )
347  return sizeof(obj1->get_inventory()) < sizeof(obj2->get_inventory());
348  return obj1->get_content_size() < obj2->get_content_size();
349 }
350 
351 int cmp_date_rev(object obj1, object obj2)
352 {
353  return obj1->query_attribute(DOC_LAST_MODIFIED) <
354  obj2->query_attribute(DOC_LAST_MODIFIED);
355 }
356 
357 /**
358  * Get the inventory of a container, parameters have to include
359  * an object range, optionally the container can bhe sorted with
360  * "name", "reverse-name", "size", "reverse-size", "modified" or
361  * "reverse-modified".
362  *
363  * @param object cont - the container to show
364  * @param int from_obj - the start of the object range
365  * @param int to_obj - the end of the object range.
366  * @param string sort - sort option.
367  * @return (sorted) array of objects
368  */
369 array
370 get_cont_inventory(object cont, int from_obj, int to_obj, void|string sort)
371 {
372  array inv = cont->get_inventory();
373  array arr = ({ });
374  array obj_arr = ({ });
375  array cont_arr = ({ });
376 
377  foreach( inv, object obj ) {
378  if ( obj->get_object_class() & CLASS_EXIT ||
379  obj->get_object_class() & CLASS_ROOM ||
380  obj->get_object_class() & CLASS_USER )
381  arr += ({ obj });
382  else if ( obj->get_object_class() & CLASS_CONTAINER )
383  cont_arr += ({ obj });
384  else if ( !(obj->get_object_class() & CLASS_DRAWING) )
385  obj_arr += ({ obj });
386  }
387  if ( !stringp(sort) || sort == "none" ) {
388  sort = cont->query_attribute("web:sort:objects");
389  if ( sort == "last-modified/time" )
390  sort = "modified";
391  }
392 
393  // sort the array of objects
394  if ( stringp(sort) ) {
395  switch ( sort ) {
396  case "name":
397  obj_arr = Array.sort_array(obj_arr, cmp_names);
398  cont_arr = Array.sort_array(cont_arr, cmp_names);
399  break;
400  case "size":
401  obj_arr = Array.sort_array(obj_arr, cmp_size);
402  cont_arr = Array.sort_array(cont_arr, cmp_size);
403  break;
404  case "modified":
405  obj_arr = Array.sort_array(obj_arr, cmp_date);
406  cont_arr = Array.sort_array(cont_arr, cmp_date);
407  break;
408  case "reverse-name":
409  obj_arr = Array.sort_array(obj_arr, cmp_names_rev);
410  cont_arr = Array.sort_array(cont_arr, cmp_names_rev);
411  break;
412  case "reverse-size":
413  obj_arr = Array.sort_array(obj_arr, cmp_size_rev);
414  cont_arr = Array.sort_array(cont_arr, cmp_size_rev);
415  break;
416  case "reverse-modified":
417  obj_arr = Array.sort_array(obj_arr, cmp_date_rev);
418  cont_arr = Array.sort_array(cont_arr, cmp_date_rev);
419  break;
420  }
421  }
422  obj_arr = cont_arr + obj_arr;
423  if ( to_obj == 0 ) to_obj = sizeof(obj_arr);
424 
425  return obj_arr[from_obj-1..to_obj-1] + arr;
426 }
427 
428 string show_inventory_size(object cont)
429 {
430  string xml = "";
431  int docs, conts, rooms, exits, users;
432 
433 
434  // fixme: use this function ?
435  array inv = cont->get_inventory();
436  foreach(inv, object o) {
437  if ( o->get_object_class() & CLASS_USER )
438  users++;
439  else if ( o->get_object_class() & CLASS_ROOM )
440  rooms++;
441  else if ( o->get_object_class() & CLASS_EXIT )
442  exits++;
443  else if ( o->get_object_class() & CLASS_CONTAINER )
444  conts++;
445  else if ( o->get_object_class() & CLASS_DOCUMENT )
446  docs++;
447  }
448  return xml;
449 }
450 
451 /**
452  *
453  *
454  * @param
455  * @return
456  * @see
457  */
458 int get_last_modified(object obj)
459 {
460  if ( obj->get_object_class() & CLASS_DOCUMENT )
461  return obj->query_attribute(DOC_LAST_MODIFIED);
462  else if ( obj->get_object_class() & CLASS_CONTAINER )
463  return obj->query_attribute(CONT_LAST_MODIFIED);
464  else
465  return obj->query_attribute(OBJ_LAST_CHANGED);
466 }
467 
468 /**
469  * Get the name for an object class. This function queries the factory
470  * of the object to get the name.
471  *
472  * @param int id - the class id
473  * @return the class-name string
474  */
475 string class_id_to_name(int id)
476 {
477  if ( id & CLASS_SCRIPT )
478  return "\"Script\"";
479 
480  object factory = _Server->get_factory(id);
481  if ( objectp(factory) )
482  return "\""+factory->get_class_name()+"\"";
483  else
484  return "\"Object\"";
485 }
486 
487 /**
488  * Show extended object information.
489  * <object type='Object'><name/><id/><path/><description/></object>
490  *
491  * @param object obj - the object to show.
492  * @return extended object information xml code.
493  */
494 string show_object_ext(object obj)
495 {
496  if ( !objectp(obj) )
497  return "";
498 
499  return "<object type="+class_id_to_name(obj->get_object_class())+
500  "><name><![CDATA["+obj->query_attribute(OBJ_NAME)+"]]></name>"+
501  "<id>"+obj->get_object_id()+"</id><path><![CDATA["+
502  (obj->get_object_class() & CLASS_DOCEXTERN ?
503  obj->query_attribute(DOC_EXTERN_URL):
504  replace_uml(_FILEPATH->object_to_filename(obj)))+
505  "]]></path><description><![CDATA["+
506  obj->query_attribute(OBJ_DESC)+"]]></description></object>";
507 }
508 
509 
510 string show_objects_ext(array objs)
511 {
512  string xml = "<array>";
513  foreach(objs, object obj)
514  xml += show_object_ext(obj);
515  xml += "</array>\n";
516  return xml;
517 }
518 
519 string show_trail(array trail, int|void sz)
520 {
521  array walk = ({ });
522  int i, way;
523 
524  if ( sz == 0 )
525  sz = 4;
526  string xml = "";
527 
528  // try to detect loop in trail, only A,B,A,B
529  way = 0;
530 
531 
532  xml = "<array>";
533  for ( i = sizeof(trail) - 1 - sz; i < sizeof(trail); i++ ) {
534  if ( i < 0 ) continue;
535  xml += show_object_ext(trail[i]);
536  }
537  xml += "</array>";
538 
539  return xml;
540 }
541 
542 
543 /**
544  * Show extended information for XSL objects in this converter.
545  *
546  * @param mixed s - the value to show in xml
547  * @return the value in xml
548  * @see show
549  */
550 string compose_scalar(mixed s)
551 {
552  if ( objectp(s) && s->get_object_class() & CLASS_DOCXSL) {
553  return "<object><name>"+s->get_identifier()+"</name>"+
554  "<id>"+s->get_object_id()+"</id><path>"+
555  _FILEPATH->object_to_filename(s)+"</path></object>";
556  }
557  return ::compose_scalar(s);
558 }
559 
560 /**
561  *
562  *
563  * @param
564  * @return
565  * @see
566  */
567 array get_filtered_inventory(object obj, mixed key, mixed val)
568 {
569  array inv = obj->get_inventory();
570  array res = ({ });
571  foreach ( inv, object o ) {
572  mixed v = o->query_attribute(key);
573  if ( objectp(val) )
574  if ( !v )
575  res += ({ o });
576  else if ( arrayp(v) && !arrayp(val) && search(v,val) >= 0 )
577  res += ({ o });
578  else if ( val == v )
579  res += ({ o });
580  }
581  return res;
582 }
583 
584 /**
585  * Show an attribute. This is done without the basic conversion to
586  * xml with string|int, because for example the data type of
587  * name or id tags is already known.
588  *
589  * @param mixed val - the value to convert
590  * @return the converted value
591  */
592 string show(string|int|object|mapping|program|array val)
593 {
594  DEBUG_XML("show:"+sprintf("%O", val));
595  if ( stringp(val) )
596  return "<![CDATA["+val+"]]>";
597  else if ( intp(val) )
598  return (string)val;
599  else if ( objectp(val) && stringp(val->query_attribute(OBJ_NAME)) &&
600  !xml.utf8_check(val->query_attribute(OBJ_NAME)) )
601  return "<invalid_object_utf8>"+val->get_object_id()+"</invalid_object_utf8>";
602  return compose(val);
603 }
604 
605 /**
606  * Show xml code for an exit - that is the destination.
607  *
608  * @param object exit - the exit to show.
609  * @return xml string representation.
610  * @see show
611  */
612 string show_exit(object exit)
613 {
614  string p = _FILEPATH->object_to_filename(exit);
615  if ( p[-1] != '/' )
616  p+="/";
617  p = no_uml(p);
618  return "<object><id>"+exit->get_object_id()+"</id><path>"+p+"</path>"+
619  "<name>"+exit->get_identifier()+"</name></object>\n";
620 }
621 
622 /**
623  * Gives xml code for the creator of an object.
624  *
625  * @param object creator - the creator.
626  * @return xml code for creator object.
627  */
628 string show_creator(object creator)
629 {
630  // show also type
631  return "<object type="+class_id_to_name(creator->get_object_class())+"><id>"+creator->get_object_id()+"</id>"+
632  "<name>"+creator->get_identifier()+"</name></object>\n";
633 }
634 
635 
636 /**
637  * Show the status status in terms of CLIENT_FEATURES_*
638  *
639  * @param int status - the status to xmlize.
640  * @return the xml converted status.
641  */
642 string show_status(int status)
643 {
644  string xml = "";
645 
646  if ( status & CLIENT_FEATURES_CHAT )
647  xml += "<chat>true</chat>";
648  else
649  xml += "<chat>false</chat>";
650 
651  if ( status & CLIENT_STATUS_CONNECTED )
652  xml += "<connected>true</connected>";
653  else
654  xml += "<connected>false</connected>";
655  return xml;
656 }
657 
658 /**
659  * Return false for value 0 and otherwise true.
660  *
661  * @param mixed val - the value for true or false
662  * @return true or false as a string
663  */
664 string show_truefalse(mixed val)
665 {
666  if ( val == 0 )
667  return "false";
668  return "true";
669 }
670 
671 /**
672  * Show the size of an array or the inventory size of an container.
673  * an container ?
674  *
675  * @param object|array o - the array or container to show its size.
676  * @return size of container or array.
677  */
678 string show_size(object|array o)
679 {
680  if ( arrayp(o) )
681  return (string)sizeof(o);
682  else if ( objectp(o) && o->get_object_class() & CLASS_CONTAINER )
683  return (string)sizeof(o->get_inventory());
684  return 0;
685 }
686 
687 string show_size_unread(object|array o)
688 {
689  object trd = _Server->get_module("table:read-documents");
690  if ( arrayp(o) ){
691  int sz = 0;
692  int msgs = 0;
693  foreach(o, object obj) {
694  o += obj->get_annotations();
695  if ( objectp(trd) ) {
696  if ( !trd->is_reader(obj, this_user()) )
697  sz++;
698  }
699  msgs++;
700  }
701  return"<unread>"+sz+"</unread><messages>"+msgs+"</messages>";
702  }
703  return "<unread>0</unread><messages>0</messages>";
704 }
705 
706 string show_mailbox_size(object|array o)
707 {
708  return show_size_unread(o);
709 }
710 
711 string show_annotations_size(object o)
712 {
713  if ( o->get_object_class() & CLASS_USER )
714  return "<unread>0</unread><messages>0</messages>";
715  return show_size_unread(o->get_annotations());
716 }
717 
718 
719 /**
720  * Get the permission role for some access bit array or an object.
721  *
722  * @param int|object access - the access integer or access object
723  * @return string description of the objects access permissions.
724  */
725 string get_role(int|object access)
726 {
727  if ( objectp(access) )
728  access = LAST->obj->query_sanction(access);
729 
730  if ( (access & SANCTION_ALL)==SANCTION_ALL )
731  return "admin";
732  else if ( access & SANCTION_READ && access & SANCTION_WRITE )
733  return "author";
734  else if ( (access & SANCTION_READ) && (access & SANCTION_ANNOTATE) )
735  return "reviewer";
736  else if ( access & (SANCTION_READ) )
737  return "reader";
738  return "nothing";
739 }
740 
741 /**
742  * Check the access of an object for a given access bit.
743  *
744  * @param object obj - the object to check access.
745  * @param object caller - the calling object.
746  * @param int accBit - the access Bit to test.
747  * @return true or false.
748  */
749 bool check_access(object obj, object caller, int accBit)
750 {
751  return _SECURITY->check_user_access(obj, caller, accBit, accBit, false);
752 }
753 
754 /**
755  * Get the time string for a given timestamp 't'.
756  *
757  * @param int tt - timestamp to get a string description for.
758  * @return string description of timestamp in "month date year/time".
759  */
760 string get_time(int tt)
761 {
762  int t = 0;
763  if ( intp(tt) ) t = tt;
764  string ti = ctime(t);
765  string month, year;
766  string date, hour, minute;
767 
768  if (sscanf(ti,"%*s %s %s %s:%s:%*d %s\n",month,date,hour,minute,year) != 5)
769  sscanf(ti,"%*s %s %s %s:%s:%*d %s\n", month,date,hour,minute,year);
770  string gettime = month + "/"+ date + "/" + (year[2..3]) + "/" + hour +
771  ":" + minute;
772  return "<date>"+gettime+"</date><time>"+t+"</time>";
773 }
774 
775 /**
776  * Get the standard ctime output format. <date>ctime(t)</date><time>t</time>.
777  *
778  * @param int t - the timestamp (unix)
779  */
780 string get_ctime(int tt)
781 {
782  int t = 0;
783  if ( intp(tt) ) t = tt;
784  return "<date>"+ctime(t)+"</date><time>"+t+"</time>";
785 }
786 
787 /**
788  * Get the content of an object.
789  *
790  * @param object obj - the object to get the content for.
791  * @return the content of the object.
792  */
793 string
794 get_obj_content(object obj)
795 {
796  if ( !objectp(obj) )
797  return "";
798  if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
799  search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
800  {
801  string content = obj->get_content();
802  if ( obj->query_attribute(DOC_MIME_TYPE) == "text/plain" )
803  content = text_to_html(content);
804  if ( !stringp(content) )
805  content = "";
806 
807  return "<![CDATA["+string_to_utf8(content)+"]]>";
808  }
809  return "";
810 }
811 
812 string get_obj_content_detect(object obj)
813 {
814  if ( !objectp(obj) )
815  return "";
816  if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
817  search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
818  {
819  string content = obj->get_content();
820  string encoding = obj->query_attribute(DOC_ENCODING);
821  if ( !stringp(encoding) &&
822  search(obj->query_attribute(DOC_MIME_TYPE), "html") >= 0 )
823  encoding = detect_encoding(content);
824 
825  if ( !stringp(content) )
826  content = "";
827 
828  if ( encoding != "utf-8" )
829  return "<![CDATA["+string_to_utf8(content)+"]]>";
830  else
831  return "<![CDATA["+content+"]]>";
832  }
833  return "";
834 }
835 
836 string
837 get_obj_content_raw(object obj)
838 {
839  if ( !objectp(obj) )
840  return "";
841  if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
842  search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
843  {
844  string content = obj->get_content();
845  if ( !stringp(content) )
846  content = "";
847  if ( obj->query_attribute(DOC_MIME_TYPE) == "text/plain" )
848  content = text_to_html(content);
849 
850  if ( obj->query_attribute(DOC_ENCODING) == "iso-8859-1" )
851  content = string_to_utf8(content);
852  if ( !xml.utf8_check(content) )
853  content = string_to_utf8(content);
854 
855  return "<![CDATA["+content+"]]>";
856  }
857  return "";
858 }
859 
860 class xsltTag {
861 public:
862  object get_object(string o) {
863  if ( (int)o > 0 )
864  return find_object((int)o);
865  else
866  return find_object(o);
867  }
868 
869  string execute(mapping vars) {
870  object obj;
871  object xsl;
872 
873  obj = get_object(vars->args->object);
874  if ( !objectp(obj) )
875  return "<!-- xslt: no object found ("+vars->args->object+")-->";
876  xsl = get_object(vars->args->xsl);
877  if ( !objectp(xsl) )
878  return "<!-- xslt: no xsl Stylesheet found ("+
879  vars->args->xsl+")-->";
880  return run_xml(obj, xsl, vars);
881  }
882 
883  int get_object_class() { return 0; }
884 }
885 
886 /**
887  * Get the content of a given object and parse all rxml tag
888  * inside the well formed html or text content.
889  *
890  * @param object obj - the object to get the content for.
891  * @return the resulting code
892  */
893 string get_obj_content_rxml(object obj)
894 {
895  if ( !objectp(obj) )
896  return "";
897 
898  return "<!-- this function is no longer available !-->";
899 
900  if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
901  search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
902  {
903  string content = obj->get_content();
904  mapping tags = ([ "xslt": xsltTag()->execute, ]);
905  string result;
906  mixed err = catch {
907  result = htmllib.parse_rxml(string_to_utf8(content),
908  XSL->vars, tags, "utf-8");
909  };
910  if ( err != 0 ) {
911  werror("Got error upon get_obj_content_rxml:\n%O", err);
912  result = err[0];
913  }
914  return "<![CDATA["+result+"]]>";
915  }
916  steam_error("Cannot parse rxml in non-text content !");
917 }
918 
919 
920 /**
921  * Describe the params of an attribute. The function gets the attribute
922  * registration array which is available from the factory.
923  *
924  * @param array reg - the registered attribute data.
925  * @return string description of the registered type.
926  */
927 string describe_params(mixed reg)
928 {
929  int type = reg[REGISTERED_TYPE];
930 
931  if ( type == CMD_TYPE_ARRAY )
932  return "array";
933  else if ( type == CMD_TYPE_FLOAT )
934  return "float";
935  else if ( type == CMD_TYPE_MAPPING )
936  return "mapping";
937  else if ( type == CMD_TYPE_STRING )
938  return "string";
939  else if ( type == CMD_TYPE_TIME )
940  return "time";
941  else if ( type == CMD_TYPE_INT )
942  return "int";
943  else if ( type == CMD_TYPE_OBJECT )
944  return "object";
945  return "mixed";
946 }
947 
948 array
949 _get_annotations_thread(object obj, object user , int d, int|void active_flag)
950 {
951  string xml;
952  int read;
953 
954  if ( !active_flag )
955  active_flag = activeThreadMap[obj];
956 
957  read =(search(
958  _Server->get_module("table:read-documents")->get_readers(obj),
959  user) >= 0 );
960  xml = "<thread>\n"+
961  "<depth>"+d+"</depth>\n"+
962  "<subject><![CDATA["+obj->query_attribute(OBJ_DESC_OR_NAME) +"]]></subject>"+
963  "<accessed>"+obj->query_attribute(DOC_TIMES_READ)+"</accessed>\n"+
964  "<id>"+obj->get_object_id() + "</id>\n"+
965  "<created>"+get_time(obj->query_attribute(OBJ_CREATION_TIME))+"</created>\n"+
966  "<modified>"+get_time(obj->query_attribute(DOC_LAST_MODIFIED))+"</modified>\n"+
967  "<active-thread>"+active_flag+"</active-thread>\n"+
968  "<read>"+read+"</read>\n"+
969  "<author>"+compose_scalar(obj->get_creator())+"</author>\n";
970 
971  array annotations = obj->get_annotations_for(user);
972  if ( arrayp(annotations) ) {
973  foreach(annotations, object ann) {
974  if ( !objectp(ann) ) continue;
975  array res;
976  res = _get_annotations_thread(ann, user, d+1, active_flag);
977  xml += res[0];
978  read = (read || res[1]);
979  }
980  }
981  xml += "<read_thread>"+read+"</read_thread>\n";
982  xml += "</thread>\n";
983  return ({ xml, read });
984 }
985 
986 /**
987  * Convert an annotation thread into xml. This function is called
988  * recursively. Dont call this function directly, use show_annotations
989  * instead.
990  *
991  * @param object obj - the current annotation object.
992  * @param object user - the user reading the annotations.
993  * @param int d - the current depth in the thread.
994  * @return xml string representation of an annotation thread.
995  * @see show_annotations
996  */
997 string
998 get_annotations_thread(object obj, object user, int d, int|void active_flag)
999 {
1000  return _get_annotations_thread(obj, user, d, active_flag)[0];
1001 }
1002 
1003 /**
1004  * Recursively insert annotations in the annotation array. This just
1005  * builds an array which is used by show_annotations. The user object
1006  * parameter is used for calling the get_annotations_for() function.
1007  *
1008  * @param object ann - the current annotation
1009  * @param object user - the user reading the anntotations.
1010  * @return
1011  * @see show_annotations
1012  */
1013 array insert_annotations(object ann, object user)
1014 {
1015  array annotations = ann->get_annotations_for(user);
1016  if ( arrayp(annotations) ) {
1017  foreach ( annotations, object a) {
1018  annotations += insert_annotations(a, user);
1019  }
1020  }
1021  else {
1022  return ({ });
1023  }
1024  return annotations;
1025 }
1026 
1027 /**
1028  * Bring the given array of annotation objects to XML.
1029  *
1030  * @param array annotations - array of annotation documents.
1031  * @return xml presentation of the annotations and their sub-annotations.
1032  * @see insert_annotations
1033  * @see get_annotations_thread
1034  */
1035 string show_annotations(array annotations)
1036 {
1037  string xml = "";
1038  for ( int i = 0; i < sizeof(annotations); i++ ) {
1039  if ( !objectp(annotations[i]) ) continue;
1040  xml += get_annotations_thread(annotations[i], this_user(), 0);
1041  }
1042  foreach ( annotations, object ann ) {
1043  annotations += insert_annotations(ann, this_user());
1044  }
1045  foreach(annotations, object annotation) {
1046  xml += serialize_xml_object(
1047  annotation, annotationXML, true);
1048  }
1049  return xml;
1050 }
1051 
1052 /**
1053  *
1054  *
1055  * @param
1056  * @return
1057  * @see
1058  */
1059 string do_show_attribute(object obj, mixed key, mixed val, mixed attrReg)
1060 {
1061  return
1062  "\t\t\t<locked>"+(obj->is_locked(key) ? "true":"false")+"</locked>\n"+
1063  "\t\t\t<type>"+describe_params(attrReg)+"</type>\n"+
1064  "\t\t\t<key>"+compose(key) + "</key>\n"+
1065  "\t\t\t<acquire>"+describe_acquire(val[1])+ "</acquire>\n"+
1066  "\t\t\t<description>"+attrReg[REGISTERED_DESC]+"</description>\n"+
1067  "\t\t\t<data>"+compose(val[0])+"</data>\n";
1068 }
1069 
1070 /**
1071  * Show the registered data of an attribute and its value. This is
1072  * used by attributes.xsl.
1073  *
1074  * @param KEYVALUE k - key/value pair from a mapping.
1075  * @return xml presentation of the attribute data.
1076  */
1077 string show_attribute(KEYVALUE k)
1078 {
1079  mixed key = k->key;
1080  mixed attrReg = k->val;
1081  mixed val= ({ obj->query_attribute(key), obj->get_acquire_attribute(key) });
1082  return do_show_attribute(obj, key, val, attrReg);
1083 }
1084 
1085 /**
1086  *
1087  *
1088  * @param
1089  * @return
1090  * @see
1091  */
1092 string show_attribute_reg(KEYVALUE k)
1093 {
1094  mixed key = k->key;
1095  mixed attrReg = k->val;
1096  mixed val= obj->get_attribute_default(key);
1097  return do_show_attribute(obj, key, val, attrReg);
1098 }
1099 
1100 /**
1101  * Show how many objects a user carries.
1102  *
1103  * @return the size of the current user selection.
1104  */
1105 string show_carry()
1106 {
1107  return (string)sizeof(selection);
1108 }
1109 
1110 /**
1111  * This checks if there is a valid proxy.
1112  *
1113  * @param object o - the object.
1114  * @return the proxy of the object
1115  * @see
1116  */
1117 object get_local_object(object o)
1118 {
1119  return 0;
1120 }
1121 
1122 /**
1123  * Describe a sanction bit array as a number of 'permission' tags.
1124  *
1125  * @param int saction - the permission bit array.
1126  * @return xml presentation of access permissions.
1127  */
1128 string show_access(int sanction)
1129 {
1130  string xml = "";
1131 
1132  int sz = sizeof(__sanction);
1133  for ( int i = 0; i < sz; i++ ) {
1134  if ( __sanction[i] == "free" ) continue;
1135 
1136  if ( sanction & ((1<<i)<<16) )
1137  xml += "\t\t\t<permission type=\""+__sanction[i]+
1138  "\">2</permission>\n";
1139  else if ( sanction & (1<<i) )
1140  xml += "\t\t\t<permission type=\""+__sanction[i]+
1141  "\">1</permission>\n";
1142  else
1143  xml += "\t\t\t<permission type=\""+__sanction[i]+
1144  "\">0</permission>\n";
1145  }
1146  return xml;
1147 }
1148 
1149 /**
1150  * Get basic access permissions for an object. Checks whether the
1151  * user can read,write,execute and annotate the object and if the
1152  * steam-group is able to read. Finally its checked if also everyone
1153  * can read the object.
1154  *
1155  * @param objcet obj - the object to check.
1156  * @return the xml access string.
1157  */
1158 string get_basic_access(object obj)
1159 {
1160  string xml;
1161 
1162  int access = _SECURITY->get_user_permissions(obj, this_user(), SANCTION_READ|SANCTION_WRITE|SANCTION_EXECUTE|SANCTION_ANNOTATE|SANCTION_INSERT);
1163  int gaccess = _SECURITY->get_user_permissions(obj, _WORLDUSER, SANCTION_READ|SANCTION_WRITE|SANCTION_EXECUTE|SANCTION_ANNOTATE|SANCTION_INSERT);
1164  int saccess = _SECURITY->get_user_permissions(obj, _STEAMUSER, SANCTION_READ);
1165  if ( obj == this_user() )
1166  access = saccess = SANCTION_ALL;
1167 
1168  xml = "";
1169  if ( gaccess & SANCTION_READ )
1170  xml += "<readable guest=\"true\" user=\"true\" steam=\"true\"/>";
1171  else
1172  xml += "\t<readable guest=\"false\" user=\""+
1173  ((access & SANCTION_READ) ? "true":"false") + "\" steam=\""+
1174  ((saccess&SANCTION_READ) ? "true":"false") + "\" />\n";
1175  if ( gaccess & SANCTION_WRITE )
1176  xml += "<writeable guest=\"true\" user=\"true\" steam=\"true\"/>";
1177  else
1178  xml += "\t<writeable guest=\"false\" user=\""+
1179  ((access&SANCTION_WRITE) ? "true":"false") + "\"/>\n";
1180 
1181  if ( gaccess & SANCTION_EXECUTE )
1182  xml += "<executeable guest=\"true\" user=\"true\" steam=\"true\"/>";
1183  else
1184  xml += "\t<executeable guest=\"false\" user=\""+
1185  ((access&SANCTION_EXECUTE)? "true":"false") + "\"/>\n";
1186  if ( gaccess & SANCTION_ANNOTATE )
1187  xml += "<annotateable guest=\"true\" user=\"true\" steam=\"true\"/>";
1188  else
1189  xml += "\t<annotateable guest=\"false\" user=\""+
1190  ((access&SANCTION_ANNOTATE) ? "true":"false") + "\"/>\n";
1191  if ( gaccess & SANCTION_INSERT )
1192  xml += "<insertable guest=\"true\" user=\"true\" steam=\"true\"/>";
1193  else
1194  xml += "\t<insertable guest=\"false\" user=\""+
1195  ((access&SANCTION_INSERT) ? "true":"false") + "\"/>\n";
1196  return xml;
1197 }
1198 
1199 /**
1200  * Describe the acquired access of an object.
1201  *
1202  * @param object obj - the object to describe its acquiring.
1203  * @return xml string about acquired access permission.
1204  */
1205 string get_acquired_access(object obj)
1206 {
1207  string xml = "";
1208  mapping mSanction;
1209  int sz;
1210 
1211  //DEBUG_XML("get_acquired_access("+obj->get_identifier()+")");
1212  object|function acquire = obj->get_acquire();
1213 
1214  if ( functionp(acquire) )
1215  acquire = acquire();
1216 
1217  while ( acquire != 0 ) {
1218  mSanction = acquire->get_sanction();
1219  foreach(indices(mSanction), object sanctioned) {
1220  if ( !objectp(sanctioned) ) continue;
1221  xml += "\t\t\t<Object "+
1222  "type="+class_id_to_name(sanctioned->get_object_class())+
1223  ">\n";
1224  xml += "\t\t\t\t<from>"+compose(acquire)+"</from>\n";
1225  xml += "\t\t\t\t<id>"+sanctioned->get_object_id() + "</id>\n"+
1226  "\t\t\t\t<name>"+sanctioned->get_identifier()+"</name>\n";
1227  sz = sizeof(__sanction);
1228  for ( int i = 0; i < sz; i++ ) {
1229  if ( __sanction[i] == "free" ) continue;
1230 
1231  if ( mSanction[sanctioned] & ((1<<i)<<16) )
1232  xml += "\t\t\t\t\t<permission type=\""+__sanction[i]+
1233  "\">2</permission>\n";
1234  else if ( mSanction[sanctioned] & (1<<i) )
1235  xml += "\t\t\t\t<permission type=\""+__sanction[i]+
1236  "\">1</permission>\n";
1237  else
1238  xml += "\t\t\t\t<permission type=\""+__sanction[i]+
1239  "\">0</permission>\n";
1240  }
1241  xml +="\t\t\t</Object>\n";
1242  }
1243  acquire = acquire->get_acquire();
1244  if ( functionp(acquire) )
1245  acquire = acquire();
1246  }
1247  return xml;
1248 }
1249 
1250 /**
1251  * Describe the acquire situation of an object.
1252  *
1253  * @param function|object acquire the acquire setting
1254  * @return xml description of the given function or object.
1255  */
1256 string describe_acquire(function|object|string acquire)
1257 {
1258  if ( functionp(acquire) && acquire == THIS->obj->get_environment )
1259  {
1260  acquire = acquire();
1261  if ( objectp(acquire) )
1262  return "<function><name>get_environment</name><id>"+
1263  acquire->get_object_id()+ "</id></function>\n";
1264  }
1265  else if ( stringp(acquire) && acquire == REG_ACQ_ENVIRONMENT )
1266  return "<function><name>get_environment</name></function>";
1267  else if ( objectp(acquire) )
1268  return compose_scalar(acquire);
1269  return "<object><name/><id>0</id></object>";
1270 }
1271 
1272 /**
1273  * Serialize an XML tag with serialization data 'data'.
1274  *
1275  * @param string tag - the name of the tag to serialize.
1276  * @param array data - the data for the tag.
1277  * @return tag and data in XML.
1278  */
1279 string serialize_xml_tag(string tag, array data)
1280 {
1281  function f;
1282  object o;
1283  mixed v;
1284  array params;
1285 
1286  DEBUG_XML("<"+tag+">");
1287 
1288  string xml = "<"+tag+">";
1289 
1290  if ( !arrayp(data) )
1291  return xml + "</"+tag+">";
1292 
1293  if ( functionp(data[ID_FUNC]) ) {
1294  f = data[ID_FUNC];
1295  }
1296  else {
1297  o = get_local_object(data[ID_OBJECT]);
1298  if ( objectp(o) )
1299  f = o->find_function(data[ID_FUNC]);
1300  }
1301 
1302  params = ({ });
1303  for ( int i = 0; i < sizeof(data[ID_PARAMS]); i++ ) {
1304  if ( objectp(data[ID_PARAMS][i]) )
1305  else
1306  params += ({ data[ID_PARAMS][i] });
1307  }
1308 
1309  mixed err;
1310 
1311  if ( functionp(f) ) {
1312  err = catch {
1313  v = f(@params);
1314  };
1315  if ( err != 0 ) {
1316  xml += "<!-- While serializing XML: " +err[0] + "-->\n";
1317  }
1318  }
1319  else
1320  v = -1;
1321 
1322  if ( functionp(data[ID_CONV]) ) {
1323  err = catch {
1324  xml += data[ID_CONV](v);
1325  };
1326  if ( err != 0 ) {
1327  FATAL("While serializing XML:\n"+err[0]+
1328  sprintf("%O", err[1]));
1329  }
1330  }
1331  else if ( mappingp(data[ID_CONV]) )
1332  {
1333  if ( arrayp(v) ) {
1334  foreach( v, object obj) {
1335  if ( data[ID_CONV]->name == "none" )
1336  xml += serialize_xml_object(obj, data[ID_CONV], false);
1337  else
1338  xml += serialize_xml_object(obj, data[ID_CONV], true);
1339  }
1340  }
1341  else if ( mappingp(v) ) {
1342  foreach( indices(v), mixed ind ) {
1343  ENTRY->key = ind;
1344  ENTRY->val = v[ind];
1345  if ( objectp(ind) && intp(data[ID_CONV][0]) ) {
1346  LAST->obj = THIS->obj;
1347  if ( data[ID_CONV]->name == "none" )
1348  xml += serialize_xml_object(ind, data[ID_CONV], false);
1349  else
1350  xml += serialize_xml_object(ind, data[ID_CONV], true);
1351 
1352  }
1353  else {
1354  foreach(indices(data[ID_CONV]), mixed idx) {
1355  xml += serialize_xml_tag(idx, data[ID_CONV][idx]);
1356  }
1357  }
1358  }
1359  }
1360  else if ( objectp(v) ) {
1361  LAST->obj = THIS->obj;
1362  xml += serialize_xml_object(v, data[ID_CONV], false);
1363  }
1364  }
1365  else if ( objectp(v) ) {
1366  xml += compose(v);
1367  }
1368  else if ( stringp(v) || intp(v) )
1369  xml += v;
1370 
1371  xml += "</"+tag+">\n";
1372  DEBUG_XML("</"+tag+">");
1373  return xml;
1374 
1375 }
1376 
1377 /**
1378  * Serialize an object to XML using the xml description mapping 'mXML'.
1379  * The mapping defines what the xml code for the object should look like.
1380  *
1381  * @param object obj - the object to serialize.
1382  * @param mapping mXML - xml description mapping.
1383  * @return xml code for object 'obj'.
1384  * @see serialize_xml_tag
1385  */
1386 string
1387 serialize_xml_object(object obj, mapping mXML, bool|void obj_tag )
1388 {
1389  object xml = String.Buffer();
1390 
1391  if ( !objectp(obj) )
1392  return "<!-- Null Object cannot be serialized -->";
1393 
1394  if ( !mappingp(mXML) )
1395  return "";
1396 
1397  if (obj->status()<PSTAT_DISK) // broken instance already loaded
1398  return "<!-- Unable to load broken instance from DB -->";
1399 
1400  if (!functionp(obj->this)) // broken instance on first load
1401  return "";
1402 
1403  ENV->obj = obj->get_environment();
1404 
1405  DEBUG_XML("serialize_xml_object(THIS="+THIS->obj->get_identifier()+",LAST="+
1406  (objectp(LAST->obj) ? LAST->obj->get_identifier():"NULL")+")");
1407 
1408  string tagname = mXML->name;
1409  if ( !stringp(tagname) )
1410  tagname = "Object";
1411  if ( obj_tag )
1412  xml->add("<"+tagname+" type="+
1413  class_id_to_name(obj->get_object_class())+
1414  (mSelection[obj] ?
1415  " selected=\"true\"":" selected=\"false\"")+
1416  ">");
1417 
1418  for ( int i = 31; i >= 0; i-- ) {
1419  int idx = (1<<i);
1420  if ( (idx & obj->get_object_class()) && mappingp(mXML[idx]) )
1421  {
1422  foreach(indices(mXML[idx]), string tag) {
1423  xml->add(serialize_xml_tag(tag, mXML[idx][tag]));
1424  }
1425  }
1426  }
1427  if ( obj_tag )
1428  xml->add("</"+tagname+">\n");
1429  return xml->get();
1430 }
1431 
1432 /**
1433  * Show the content description of an object 'p'. For Documents it
1434  * will list the size and the mime-type. For Containers it lists the
1435  * html:index atribute for the containers index file.
1436  *
1437  * @param object p - the content object
1438  * @return content description for the object.
1439  */
1440 string show_content(object p)
1441 {
1442  if ( p->get_object_class() & CLASS_DOCUMENT )
1443  return "<size>"+p->get_content_size()+"</size>"+
1444  "<mime-type>"+p->query_attribute(DOC_MIME_TYPE) + "</mime-type>";
1445  if ( p->get_object_class() & CLASS_CONTAINER )
1446  return "<index>"+p->query_attribute("html:index") + "</index>";
1447  return "";
1448 }
1449 
1450 
1451 /**
1452  * show a simple mapping in compact form
1453  * each key is a tag, and the value its content
1454  *
1455  * @param mapping of strings
1456  * @return xml form of the mapping
1457  */
1458 string show_mapping(mapping(string:string) data)
1459 {
1460  string xml="";
1461  if(mappingp(data))
1462  foreach(data; string key; string value)
1463  foreach(value/"\0";; string part)
1464  xml += sprintf("<%s><![CDATA[%s]]></%s>\n", key, part, key);
1465  return xml;
1466 }
1467 
1468 /**
1469  * Get a path as a series of object tags in XML.
1470  *
1471  * @param object p - the object to get the path for.
1472  * @return xml path description for the object.
1473  */
1474 string get_path(object p)
1475 {
1476  object xml = String.Buffer();
1477 
1478  array(object|string) paths = ({ });
1479  string path = "";
1480  string s;
1481  while ( p != null ) {
1482  if ( stringp(s=_FILEPATH->check_tilde(p)) ) {
1483  paths = ({ p, s }) + paths;
1484  p = null;
1485  }
1486  else {
1487  paths = ({ p, p->get_identifier() }) + paths;
1488  p = p->get_environment();
1489  }
1490  }
1491  for ( int i = 0; i < sizeof(paths)-2; i+=2 ) {
1492  xml->add("<object><id>");
1493  xml->add((string)paths[i]->get_object_id());
1494  xml->add("</id><name><![CDATA[");
1495  xml->add(paths[i+1]);
1496  xml->add("]]></name>");
1497  path += paths[i+1] + "/";
1498  xml->add("<path>"+no_uml(path)+"</path></object>");
1499  }
1500  if ( paths[-2]->get_object_class() & CLASS_CONTAINER )
1501  path += paths[-1] + "/";
1502  else
1503  path += paths[-1];
1504 
1505  xml += "<path>"+no_uml(path)+"</path>\n";
1506  return xml->get();
1507 }
1508 
1509 /**
1510  * Get a path as a series of object tags in XML.
1511  *
1512  * XML Description of returned value
1513  * <!Element path (object*)> <!-- sequence of objects in path -->
1514  * <!Element object (name, description, relpath)> <!-- data per object -->
1515  * <!Element name (#cdata)> <!-- attribute OBJ_NAME -->
1516  * <!Element description (#cdata)> <!-- attribute OBJ_DESC -->
1517  * <!Element relpath (#cdata)> <!-- relative path to object p -->
1518  *
1519  * @param object p - the object to get the path for.
1520  * @return xml path description for the object.
1521  */
1522 string get_rel_path(object p, void|int fsname)
1523 {
1524  object xml = String.Buffer();
1525 
1526  array(object|string) paths = ({ });
1527  string path = "";
1528  string s;
1529  while ( p != null ) {
1530  if ( stringp(s=_FILEPATH->check_tilde(p)) ) {
1531  paths = ({ p, s }) + paths;
1532  p = null;
1533  }
1534  else {
1535  paths = ({ p,
1536  (fsname ?
1537  p->query_attribute("fs_name") : p->get_identifier())
1538  }) + paths;
1539  p = p->get_environment();
1540  }
1541  }
1542  for ( int i = 0; i < sizeof(paths)-2; i+=2 ) {
1543  xml->add("<object><id>");
1544  xml->add((string)paths[i]->get_object_id());
1545  xml->add("</id><name><![CDATA[");
1546  xml->add(paths[i+1]);
1547  xml->add("]]></name><description><![CDATA[");
1548  xml->add(paths[i]->query_attribute(OBJ_DESC));
1549  xml->add("]]></description><relpath>");
1550  xml->add("../"*((sizeof(paths)-i)/2)+paths[i+1]);
1551  xml->add("</relpath></object>");
1552  path += paths[i+1] + "/";
1553  }
1554  if ( paths[-2]->get_object_class() & CLASS_CONTAINER )
1555  path += paths[-1] + "/";
1556  else
1557  path += paths[-1];
1558 
1559  xml += "<path>"+no_uml(path)+"</path>\n";
1560  return xml->get();
1561 }
1562 
1563 /**
1564  * Get the neighbours of an object.
1565  * This function returns a XML part containing the left and right neighbours of
1566  * the object. The optional argument filterclass allows to find the neighbours
1567  * of the same objectclass only. (previous/next image, container)
1568  *
1569  * XML Description of returned value
1570  * <!Element left (object*)> <!-- left neighbour -->
1571  * <!Element right (object*)> <!-- right neighbour -->
1572  * <!Element object (id, name, description)> <!-- information per object -->
1573  * <!Element id (#cdata)> <!-- decimal object id -->
1574  * <!Element name (#cdata)> <!-- attribute OBJ_NAME -->
1575  * <!Element description (#cdata)> <!-- attribute OBJ_DESC -->
1576  *
1577  * @param object o - The object to calculate the neighbours for.
1578  * @param void|int filterclass - (bool)
1579  * @caveats This function doesn't regard the currently active sorting option of
1580  * the user but uses unsorted inventory always.
1581  *
1582  */
1583 string get_neighbours(object p, void|int filterclass, void|int fsname)
1584 {
1585  DEBUG_XML(sprintf("get_neighbours %O, %d\n", p, filterclass));
1586  object env = p->get_environment();
1587  array inv;
1588  if (!filterclass)
1589  inv = env->get_inventory();
1590  else
1591  {
1592  inv = env->get_inventory_by_class(p->get_object_class());
1593  DEBUG_XML(sprintf("inv is %O\n", inv));
1594  }
1595  int i = search(inv, p);
1596  object xml = String.Buffer();
1597 
1598  object left, right;
1599  if (i>0) left = inv[i-1];
1600  if ((i!=-1) && (i<sizeof(inv)-1)) right = inv[i+1];
1601 
1602  xml->add("<left>");
1603  if (objectp(left))
1604  {
1605  xml->add("<object><id>");
1606  xml->add((string)left->get_object_id());
1607  xml->add("</id><name><![CDATA[");
1608  xml->add((string)left->get_identifier());
1609  xml->add("]]></name>");
1610  if (fsname)
1611  {
1612  xml->add("<fsname>");
1613  xml->add((string)left->query_attribute("fs_name"));
1614  xml->add("</fsname>");
1615  }
1616  xml->add("<description><![CDATA[");
1617  xml->add(left->query_attribute(OBJ_DESC));
1618  xml->add("]]></description></object>");
1619  }
1620  xml->add("</left><right>");
1621  if (objectp(right))
1622  {
1623  xml->add("<object><id>");
1624  xml->add((string)right->get_object_id());
1625  xml->add("</id><name><![CDATA[");
1626  xml->add((string)right->get_identifier());
1627  xml->add("]]></name>");
1628  if (fsname)
1629  {
1630  xml->add("<fsname>");
1631  xml->add((string)right->query_attribute("fs_name"));
1632  xml->add("</fsname>");
1633  }
1634  xml->add("<description><![CDATA[");
1635  xml->add(right->query_attribute(OBJ_DESC));
1636  xml->add("]]></description></object>");
1637  }
1638  xml->add("</right>");
1639 
1640  return xml->get();
1641 }
1642 
1643 private:
1644 private
1645 void xml_describe(object node, int selected, int depth, string url,
1646  String.Buffer xml)
1647 {
1648  string fsname;
1649  object o = node->get_object();
1650  function qa = o->query_attribute;
1651 
1652  xml->add("<id>");
1653  xml->add((string)o->get_object_id());
1654  xml->add("</id>\n<name><![CDATA[");
1655  xml->add((string)o->get_identifier());
1656  xml->add("]]></name>\n");
1657  if (fsname = qa("fs_name"))
1658  {
1659  xml->add("<fsname>");
1660  xml->add(fsname);
1661  xml->add("</fsname>\n");
1662  }
1663  xml->add("<description><![CDATA[");
1664  xml->add(qa(OBJ_DESC));
1665  xml->add("]]></description>\n<selected>");
1666  if (selected)
1667  xml->add("yes");
1668  else
1669  xml->add("no");
1670  xml->add("</selected>\n<depth>");
1671  xml->add((string)depth);
1672  xml->add("</depth>\n<url><![CDATA[");
1673  xml->add(url+"/");
1674  xml->add("]]></url>\n");
1675 }
1676 
1677 public:
1678 
1679 private:
1680 private
1681 void xml_recurse(object root, int depth, int level, string url, int filter,
1682  String.Buffer xml)
1683 {
1684  xml->add("<object>\n");
1685  xml_describe(root, 0, level, url, xml);
1686  array inv = root->get_inventory_by_class(filter);
1687  foreach(inv, object node)
1688  {
1689  if (depth==0) {
1690  xml->add("<object>\n");
1691  xml_describe(node, 0, level,
1692  url + "/" + root->query_attribute(OBJ_NAME),
1693  xml);
1694  xml->add("</object>\n");
1695  }
1696  else
1697  xml_recurse(node, depth-1, level+1,
1698  url + "/" + root->query_attribute(OBJ_NAME),
1699  filter, xml);
1700  }
1701  xml->add("</object>\n");
1702 }
1703 
1704 public:
1705 
1706 private:
1707 private
1708 void xml_subtree(array path, String.Buffer xml,
1709  int depth, int level, string url, int filter)
1710 {
1711  object root = path[0];
1712  path = path[1..];
1713 
1714  xml->add("<object>\n");
1715  xml_describe(root, 1, level, url, xml);
1716 
1717  object nextnode = sizeof(path) ? path[0] : 0;
1718  array inv = root->get_inventory_by_class(filter);
1719  foreach(inv, object node)
1720  {
1721  if (node == nextnode)
1722  xml_subtree(path, xml, depth-1, level+1,
1723  url+"/"+node->query_attribute(OBJ_NAME), filter);
1724  else
1725  if (depth==0) {
1726  xml->add("<object>\n");
1727  xml_describe(node, 0, level+1,
1728  url + "/" + node->query_attribute(OBJ_NAME),
1729  xml);
1730  xml->add("</object>\n");
1731  }
1732  else
1733  xml_recurse(node, depth-1 , level+1,
1734  url + "/" + node->query_attribute(OBJ_NAME),
1735  filter, xml);
1736  }
1737  xml->add("</object>\n");
1738 }
1739 
1740 public:
1741 
1742 string get_rel_tree(object root, object leaf, int depth, int filter)
1743 {
1744  array path = ({ leaf });
1745 
1746  object node = leaf;
1747  while (node && node!=root)
1748  {
1749  node = node->get_environment();
1750  if (node)
1751  path = ({ node }) + path;
1752  }
1753  if (node != root)
1754  return "<relpath></relpath>";
1755 
1756  object xml = String.Buffer();
1757  xml_subtree(path, xml, depth, 0, "", filter);
1758  return xml->get();
1759 }
1760 
1761 
1762 
1763 /**
1764  * Get the public path of an object.
1765  * This calculation uses the public "url" of its closest published parent and
1766  * combines this with the relative path from this object to its published parent.
1767  *
1768  * @param object o - The object to get the path for.
1769  * @return (string) The public path of the object
1770  */
1771 string get_public_name(object o)
1772 {
1773  string sPublicRoot;
1774  string sPublicPath;
1775  object x = o;
1776 
1777  sPublicPath = o->get_identifier();
1778  while ((x=x->get_environment()) && !(sPublicRoot = x->query_attribute("url")))
1779  {
1780  if (objectp(x))
1781  sPublicPath = x->get_identifier() + "/" + sPublicPath;
1782  }
1783 
1784  if (sPublicRoot)
1785  return combine_path(sPublicRoot, sPublicPath);
1786 
1787  return 0;
1788 }
1789 
1790 
1791 /**
1792  * Get the XML representation of this object. To speed up things, the
1793  * type selects which part of the data should be xmlified.
1794  *
1795  * @param obj - the object to convert
1796  * @param type - the type of the object
1797  * @return the xml data
1798  */
1799 string get_xml(object obj, object xsl, void|mapping vars, mixed|void active)
1800 {
1801  object xml = String.Buffer(32468);
1802  int i;
1803  object user;
1804  mixed err;
1805 
1806 
1807  if ( mappingp(vars) && vars->this_user > 0 )
1808  user = find_object(vars->this_user);
1809  else
1810  user = this_user();
1811 
1812  if ( !objectp(user) )
1813  user = CALLER;
1814 
1815  object pike = xsl->query_attribute(DOC_XSL_PIKE);
1816  if ( objectp(xsl) && objectp(pike) ) {
1817  string res;
1818  array pikeErr = pike->get_errors();
1819  if ( arrayp(pikeErr) && sizeof(pikeErr) > 0 )
1820  throw( ({pikeErr*"\n", backtrace()}));
1821  object inst = pike->get_instance();
1822  if ( objectp(inst) ) {
1823  err = catch(res=inst->xmlify(obj, vars));
1824  if ( err ) {
1825  mixed errerr = catch {
1826  array lines = pike->get_content() / "\n";
1827  int line;
1828  string func;
1829  string outp = sprintf("\n%O", err[1][-1]);
1830  sscanf(outp, "%*s.pike:%d, %s,%*s", line, func);
1831  int fromline = max(0, line-20);
1832  int toline = min(line+20, sizeof(lines)-1);
1833  for (i=fromline; i<toline;i++)
1834  err[0] += sprintf("%d: %s\n", i, lines[i]);
1835  };
1836  if ( errerr ) {
1837  FATAL("Error modifying error in xml_converter.pike: %O",
1838  errerr);
1839  }
1840 
1841  throw(err);
1842  }
1843  return res;
1844  }
1845  }
1846 
1847 
1848  selection = user->query_attribute(USER_SELECTION);
1849  if ( !arrayp(selection) )
1850  selection = ({ });
1851  mSelection = mkmapping(selection, selection);
1852 
1853 
1854 
1855 
1856  mapping mXML =
1857  ([ CLASS_OBJECT:
1858  ([
1859  "path": ({ CONV, "get_path", ({ THIS }), 0 }),
1860  "user": ({ 0, this_user, ({ }), userXML }),
1861  ])+objXML[CLASS_OBJECT],
1862  CLASS_CONTAINER:
1863  ([
1864  "inventory": ({ THIS, "get_inventory", ({ }),
1865  objXML+exitXML+linkXML+userXML+containerXML}),
1866  ]),
1867  ]);
1868 
1869  if ( objectp(xsl) && mappingp(xsl->get_xml_structure()) ) {
1870  mXML = xsl->get_xml_structure();
1871  if ( equal(mXML, ([ ])) ) {
1872  xsl->load_xml_structure();
1873  mXML = xsl->get_xml_structure();
1874  }
1875  }
1876  if ( equal(mXML, ([ ])) )
1877  THROW("No XML Description found for Stylesheet !", E_ERROR);
1878 
1879  THIS_USER->obj = user;
1880  LAST->obj = obj;
1881  XSL->obj = xsl;
1882 
1883  if (!mappingp(vars))
1884  vars = ([]);
1885  XSL->vars = vars;
1886 
1887 
1888  foreach(indices(params), string p) {
1889  if ( vars[p] ) {
1890  int d;
1891  sscanf(vars[p], "%d", d);
1892  if ( (string)d == vars[p] ) {
1893  if ( objectp(params[p]->val) )
1894  params[p]->val = find_object(d);
1895  else
1896  params[p]->val = d;
1897  }
1898  else
1899  params[p]->val = vars[p];
1900  }
1901  else
1902  params[p]->val = params[p]->def;
1903  }
1904 
1905 
1906  if ( intp(active) && active > 0 ) {
1907  ACTIVE->obj = find_object(active);
1908  }
1909  else {
1910  if ( vars->type == "annotations" ||
1911  obj->get_object_class() & CLASS_MESSAGEBOARD )
1912  {
1913  object from_obj = get_var("from_obj", 1);
1914  array annotations = obj->get_annotations_for(
1915  this_user(),
1916  (int)get_var("from_obj", 1)->val,
1917  (int)get_var("to_obj", 20)->val);
1918  if ( sizeof(annotations) > 0 )
1919  ACTIVE->obj = annotations[0];
1920  }
1921 
1922  }
1923  if ( objectp(ACTIVE->obj) ) {
1924  activeThreadMap = ([ ACTIVE->obj: 1, ]);
1925  object ann = ACTIVE->obj->get_annotating();
1926  while ( objectp(ann) ) {
1927  activeThreadMap[ann] = 1;
1928  ann = ann->get_annotating();
1929  }
1930  }
1931 
1932  DEBUG_XML("XML:Convertor - Using\n"+sprintf("%O", mXML));
1933 
1934  xml->add( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1935  xml->add( serialize_xml_object(obj, mXML, true) );
1936 
1937  string result = xml->get();
1938  return result;
1939 }
1940 
1941 bool check_swap() { return false; }
1942 string get_identifier() { return "Converter:XML"; }
1943 function find_function(string f) { return this_object()[f]; }
1944 
1945 object get_var(string name, mixed val)
1946 {
1947  object param = params[name];
1948  if ( !objectp(param) ) {
1949  param = Param();
1950  int v;
1951  if ( !stringp(val) ) {
1952  param->val = val;
1953  param->def = val;
1954  }
1955  else {
1956  sscanf(val, "%d", v);
1957  if ( (string)v == val ) {
1958  param->val = v;
1959  param->def = v;
1960  }
1961  else {
1962  param->val = val;
1963  param->def = val;
1964  }
1965  }
1966  param->name = name;
1967  params[name] = param;
1968  }
1969  return param;
1970 }
1971 
1972 {
1973  // try images folder...
1974  object images = find_object("/images");
1975  if ( !objectp(images) )
1976  return 0;
1977 
1978  array inv;
1979  if (sizeof(images->get_inventory()) < 15) {
1980  error(sprintf("/images Container not filled correctly:\n%O",
1981  images->get_inventory()));
1982  }
1983  inv = get_cont_inventory(images, 1, 15);
1984  if ( sizeof(inv) != 15 ) // no rooms in image container
1985  error("Test failed - from 1 to 15 are not 15 objects, but " + sizeof(inv));
1986  int containers = 1;
1987  foreach(inv, object obj) {
1988  if ( !(obj->get_object_class() & CLASS_CONTAINER) )
1989  containers = 0;
1990  if ( !containers && obj->get_object_class() & CLASS_CONTAINER )
1991  error("Containers not correctly sorted");
1992  }
1993 
1994  object rxml = get_factory(CLASS_DOCUMENT)->execute(
1995  ([ "name": "rxml.html", ]));
1996  rxml->set_content("<html><body><xslt object='/home/sTeam/bugs' "+
1997  "xsl='/stylesheets/annotations.xsl'/></body></html>");
1998  XSL->vars = ([ "__internal": ([ ]), ]);
1999  return get_obj_content_rxml(rxml);
2000 }
2001 
2002 
2003 
2004 
2005 };