1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
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.
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.
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
17 * $Id: xml_converter.pike,v 1.3 2009/08/07 16:14:56 nicke Exp $
19 inherit "/kernel/module";
20 inherit "/base/xml_data";
23 #include <attributes.h>
30 class xml_converter : public module,xml_data{
34 /************** deprecated module *****************/
47 #define DEBUG_XML(s) werror(s+"\n")
58 #define ID_THIS_USER 2
60 #ifdef RESTRICTED_NAMES
61 #define OBJ_DESC_OR_NAME OBJ_DESC
63 #define OBJ_DESC_OR_NAME OBJ_NAME
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); }
79 mixed def; // the default value
82 mixed cast(string castto) {
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);
108 mapping activeThreadMap = ([ ]);
109 mapping params = ([ ]);
111 KEYVALUE ENTRY = KEYVALUE();
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 }),
130 mapping annotationXML = ([ CLASS_OBJECT: objXML[CLASS_OBJECT] +
131 ([ "mime-headers": ({ THIS, "query_attribute", ({ MAIL_MIMEHEADERS }),
133 "description": ({ THIS, "query_attribute", ({OBJ_DESC_OR_NAME}), show })
136 mapping linkXML = ([ CLASS_LINK: ([
137 "link": ({ THIS, "get_link_object", ({ }), show_object_ext }),
138 "action": ({ THIS, "get_link_action", ({ }), show }),
141 mapping exitXML = ([ CLASS_EXIT: ([
142 "exit": ({ THIS, "get_exit", ({ }), show_exit }),
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 }),
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 }),
174 mapping annotationsXML = ([ CLASS_OBJECT: ([
175 "annotations": ({ THIS, "get_annotations_for", ({ THIS_USER }),
177 "active-content": ({ ACTIVE, "get_content", ({ }), show }),
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})
187 ]) + userXML[CLASS_USER], ]);
190 mapping containerXML = ([
192 "description": ({ THIS, "query_attribute", ({ OBJ_DESC }), show }),
193 "inventory": ({ THIS, "get_inventory", ({ }), show_size }),
198 mapping mailboxXML = ([
201 "path": ({ CONV, "get_path", ({ THIS }), 0 }),
202 "user": ({ 0, this_user, ({ }), userXML }),
203 ])+objXML[CLASS_OBJECT],
206 "inventory": ({ THIS, "get_inventory", ({ }),
207 objXML+exitXML+linkXML+userInvXML+containerXML }),
211 mapping iconsXML = ([
213 ([ "icons": ({ THIS, "get_icons", ({ }), show }),
214 "user": ({ 0, this_user, ({ }), userXML }),
215 ])+objXML[CLASS_OBJECT], ]);
217 mapping contentXML = ([
220 "path": ({ CONV, "get_path", ({ THIS }), 0 }),
221 "user": ({ 0, this_user, ({ }), userXML }),
222 ])+objXML[CLASS_OBJECT],
225 "inventory": ({ THIS, "get_inventory", ({ }),
226 objXML+exitXML+linkXML+userInvXML+containerXML}),
233 mapping mXML = ([ ]);
234 mapping mSelection = ([ ]);
239 mapping entities = ([
251 * Initialize the module, this function is called when the module is loaded.
257 if ( objectp(_SECURITY) )
258 __sanction = _SECURITY->get_sanction_strings();
259 // if the state of an object changed, we have to update cache !
264 string no_uml(string str)
266 return httplib.no_uml(str);
272 * Exchange some entities to fix the html sources. Especially umlaute.
274 * @param string txt - the text where to exchange Umlaute, etc.
275 * @return the replaced text.
278 string htmlize(string txt)
280 string html = replace(txt, indices(entities), values(entities));
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.
289 * @param mapping configs - the configuration mapping to bring to xml.
290 * @return the converted mapping.
292 string show_configs(mapping configs)
295 foreach(indices(configs), mixed index) {
296 if ( stringp(configs[index]) || intp(configs[index]) )
297 xml += "\t<config name=\""+index+"\">"+configs[index]+"</config>\n";
302 string show_ports(array ports)
305 foreach(ports, object port) {
306 xml += "<port nr='"+port->get_port()+"'>"+port->describe()+"</port>";
312 * Time function just calls time().
314 * @return the current timestamp (unix-time).
321 int cmp_names(object obj1, object obj2)
323 return lower_case(obj1->get_identifier())>lower_case(obj2->get_identifier());
326 int cmp_size(object obj1, object obj2)
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();
333 int cmp_date(object obj1, object obj2)
335 return obj1->query_attribute(DOC_LAST_MODIFIED) >
336 obj2->query_attribute(DOC_LAST_MODIFIED);
339 int cmp_names_rev(object obj1, object obj2)
341 return lower_case(obj1->get_identifier())<lower_case(obj2->get_identifier());
344 int cmp_size_rev(object obj1, object obj2)
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();
351 int cmp_date_rev(object obj1, object obj2)
353 return obj1->query_attribute(DOC_LAST_MODIFIED) <
354 obj2->query_attribute(DOC_LAST_MODIFIED);
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".
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
370 get_cont_inventory(object cont, int from_obj, int to_obj, void|string sort)
372 array inv = cont->get_inventory();
374 array obj_arr = ({ });
375 array cont_arr = ({ });
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 )
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 });
387 if ( !stringp(sort) || sort == "none" ) {
388 sort = cont->query_attribute("web:sort:objects");
389 if ( sort == "last-modified/time" )
393 // sort the array of objects
394 if ( stringp(sort) ) {
397 obj_arr = Array.sort_array(obj_arr, cmp_names);
398 cont_arr = Array.sort_array(cont_arr, cmp_names);
401 obj_arr = Array.sort_array(obj_arr, cmp_size);
402 cont_arr = Array.sort_array(cont_arr, cmp_size);
405 obj_arr = Array.sort_array(obj_arr, cmp_date);
406 cont_arr = Array.sort_array(cont_arr, cmp_date);
409 obj_arr = Array.sort_array(obj_arr, cmp_names_rev);
410 cont_arr = Array.sort_array(cont_arr, cmp_names_rev);
413 obj_arr = Array.sort_array(obj_arr, cmp_size_rev);
414 cont_arr = Array.sort_array(cont_arr, cmp_size_rev);
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);
422 obj_arr = cont_arr + obj_arr;
423 if ( to_obj == 0 ) to_obj = sizeof(obj_arr);
425 return obj_arr[from_obj-1..to_obj-1] + arr;
428 string show_inventory_size(object cont)
431 int docs, conts, rooms, exits, users;
434 // fixme: use this function ?
435 array inv = cont->get_inventory();
436 foreach(inv, object o) {
437 if ( o->get_object_class() & CLASS_USER )
439 else if ( o->get_object_class() & CLASS_ROOM )
441 else if ( o->get_object_class() & CLASS_EXIT )
443 else if ( o->get_object_class() & CLASS_CONTAINER )
445 else if ( o->get_object_class() & CLASS_DOCUMENT )
458 int get_last_modified(object obj)
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);
465 return obj->query_attribute(OBJ_LAST_CHANGED);
469 * Get the name for an object class. This function queries the factory
470 * of the object to get the name.
472 * @param int id - the class id
473 * @return the class-name string
475 string class_id_to_name(int id)
477 if ( id & CLASS_SCRIPT )
480 object factory = _Server->get_factory(id);
481 if ( objectp(factory) )
482 return "\""+factory->get_class_name()+"\"";
488 * Show extended object information.
489 * <object type='Object'><name/><id/><path/><description/></object>
491 * @param object obj - the object to show.
492 * @return extended object information xml code.
494 string show_object_ext(object obj)
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>";
510 string show_objects_ext(array objs)
512 string xml = "<array>";
513 foreach(objs, object obj)
514 xml += show_object_ext(obj);
519 string show_trail(array trail, int|void sz)
528 // try to detect loop in trail, only A,B,A,B
533 for ( i = sizeof(trail) - 1 - sz; i < sizeof(trail); i++ ) {
534 if ( i < 0 ) continue;
535 xml += show_object_ext(trail[i]);
544 * Show extended information for XSL objects in this converter.
546 * @param mixed s - the value to show in xml
547 * @return the value in xml
550 string compose_scalar(mixed s)
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>";
557 return ::compose_scalar(s);
567 array get_filtered_inventory(object obj, mixed key, mixed val)
569 array inv = obj->get_inventory();
571 foreach ( inv, object o ) {
572 mixed v = o->query_attribute(key);
576 else if ( arrayp(v) && !arrayp(val) && search(v,val) >= 0 )
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.
589 * @param mixed val - the value to convert
590 * @return the converted value
592 string show(string|int|object|mapping|program|array val)
594 DEBUG_XML("show:"+sprintf("%O", val));
596 return "<![CDATA["+val+"]]>";
597 else if ( intp(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>";
606 * Show xml code for an exit - that is the destination.
608 * @param object exit - the exit to show.
609 * @return xml string representation.
612 string show_exit(object exit)
614 string p = _FILEPATH->object_to_filename(exit);
618 return "<object><id>"+exit->get_object_id()+"</id><path>"+p+"</path>"+
619 "<name>"+exit->get_identifier()+"</name></object>\n";
623 * Gives xml code for the creator of an object.
625 * @param object creator - the creator.
626 * @return xml code for creator object.
628 string show_creator(object creator)
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";
637 * Show the status status in terms of CLIENT_FEATURES_*
639 * @param int status - the status to xmlize.
640 * @return the xml converted status.
642 string show_status(int status)
646 if ( status & CLIENT_FEATURES_CHAT )
647 xml += "<chat>true</chat>";
649 xml += "<chat>false</chat>";
651 if ( status & CLIENT_STATUS_CONNECTED )
652 xml += "<connected>true</connected>";
654 xml += "<connected>false</connected>";
659 * Return false for value 0 and otherwise true.
661 * @param mixed val - the value for true or false
662 * @return true or false as a string
664 string show_truefalse(mixed val)
672 * Show the size of an array or the inventory size of an container.
675 * @param object|array o - the array or container to show its size.
676 * @return size of container or array.
678 string show_size(object|array o)
681 return (string)sizeof(o);
682 else if ( objectp(o) && o->get_object_class() & CLASS_CONTAINER )
683 return (string)sizeof(o->get_inventory());
687 string show_size_unread(object|array o)
689 object trd = _Server->get_module("table:read-documents");
693 foreach(o, object obj) {
694 o += obj->get_annotations();
695 if ( objectp(trd) ) {
696 if ( !trd->is_reader(obj, this_user()) )
701 return"<unread>"+sz+"</unread><messages>"+msgs+"</messages>";
703 return "<unread>0</unread><messages>0</messages>";
706 string show_mailbox_size(object|array o)
708 return show_size_unread(o);
711 string show_annotations_size(object o)
713 if ( o->get_object_class() & CLASS_USER )
714 return "<unread>0</unread><messages>0</messages>";
715 return show_size_unread(o->get_annotations());
720 * Get the permission role for some access bit array or an object.
722 * @param int|object access - the access integer or access object
723 * @return string description of the objects access permissions.
725 string get_role(int|object access)
727 if ( objectp(access) )
728 access = LAST->obj->query_sanction(access);
730 if ( (access & SANCTION_ALL)==SANCTION_ALL )
732 else if ( access & SANCTION_READ && access & SANCTION_WRITE )
734 else if ( (access & SANCTION_READ) && (access & SANCTION_ANNOTATE) )
736 else if ( access & (SANCTION_READ) )
742 * Check the access of an object for a given access bit.
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.
749 bool check_access(object obj, object caller, int accBit)
751 return _SECURITY->check_user_access(obj, caller, accBit, accBit, false);
755 * Get the time string for a given timestamp 't'.
757 * @param int tt - timestamp to get a string description for.
758 * @return string description of timestamp in "month date year/time".
760 string get_time(int tt)
763 if ( intp(tt) ) t = tt;
764 string ti = ctime(t);
766 string date, hour, minute;
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 +
772 return "<date>"+gettime+"</date><time>"+t+"</time>";
776 * Get the standard ctime output format. <date>ctime(t)</date><time>t</time>.
778 * @param int t - the timestamp (unix)
780 string get_ctime(int tt)
783 if ( intp(tt) ) t = tt;
784 return "<date>"+ctime(t)+"</date><time>"+t+"</time>";
788 * Get the content of an object.
790 * @param object obj - the object to get the content for.
791 * @return the content of the object.
794 get_obj_content(object obj)
798 if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
799 search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
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) )
807 return "<![CDATA["+string_to_utf8(content)+"]]>";
812 string get_obj_content_detect(object obj)
816 if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
817 search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
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);
825 if ( !stringp(content) )
828 if ( encoding != "utf-8" )
829 return "<![CDATA["+string_to_utf8(content)+"]]>";
831 return "<![CDATA["+content+"]]>";
837 get_obj_content_raw(object obj)
841 if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
842 search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
844 string content = obj->get_content();
845 if ( !stringp(content) )
847 if ( obj->query_attribute(DOC_MIME_TYPE) == "text/plain" )
848 content = text_to_html(content);
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);
855 return "<![CDATA["+content+"]]>";
862 object get_object(string o) {
864 return find_object((int)o);
866 return find_object(o);
869 string execute(mapping vars) {
873 obj = get_object(vars->args->object);
875 return "<!-- xslt: no object found ("+vars->args->object+")-->";
876 xsl = get_object(vars->args->xsl);
878 return "<!-- xslt: no xsl Stylesheet found ("+
879 vars->args->xsl+")-->";
880 return run_xml(obj, xsl, vars);
883 int get_object_class() { return 0; }
887 * Get the content of a given object and parse all rxml tag
888 * inside the well formed html or text content.
890 * @param object obj - the object to get the content for.
891 * @return the resulting code
893 string get_obj_content_rxml(object obj)
898 return "<!-- this function is no longer available !-->";
900 if ( search(obj->query_attribute(DOC_MIME_TYPE), "txt") >= 0 ||
901 search(obj->query_attribute(DOC_MIME_TYPE), "text") >= 0 )
903 string content = obj->get_content();
904 mapping tags = ([ "xslt": xsltTag()->execute, ]);
907 result = htmllib.parse_rxml(string_to_utf8(content),
908 XSL->vars, tags, "utf-8");
911 werror("Got error upon get_obj_content_rxml:\n%O", err);
914 return "<![CDATA["+result+"]]>";
916 steam_error("Cannot parse rxml in non-text content !");
921 * Describe the params of an attribute. The function gets the attribute
922 * registration array which is available from the factory.
924 * @param array reg - the registered attribute data.
925 * @return string description of the registered type.
927 string describe_params(mixed reg)
929 int type = reg[REGISTERED_TYPE];
931 if ( type == CMD_TYPE_ARRAY )
933 else if ( type == CMD_TYPE_FLOAT )
935 else if ( type == CMD_TYPE_MAPPING )
937 else if ( type == CMD_TYPE_STRING )
939 else if ( type == CMD_TYPE_TIME )
941 else if ( type == CMD_TYPE_INT )
943 else if ( type == CMD_TYPE_OBJECT )
949 _get_annotations_thread(object obj, object user , int d, int|void active_flag)
955 active_flag = activeThreadMap[obj];
958 _Server->get_module("table:read-documents")->get_readers(obj),
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";
971 array annotations = obj->get_annotations_for(user);
972 if ( arrayp(annotations) ) {
973 foreach(annotations, object ann) {
974 if ( !objectp(ann) ) continue;
976 res = _get_annotations_thread(ann, user, d+1, active_flag);
978 read = (read || res[1]);
981 xml += "<read_thread>"+read+"</read_thread>\n";
982 xml += "</thread>\n";
983 return ({ xml, read });
987 * Convert an annotation thread into xml. This function is called
988 * recursively. Dont call this function directly, use show_annotations
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
998 get_annotations_thread(object obj, object user, int d, int|void active_flag)
1000 return _get_annotations_thread(obj, user, d, active_flag)[0];
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.
1008 * @param object ann - the current annotation
1009 * @param object user - the user reading the anntotations.
1011 * @see show_annotations
1013 array insert_annotations(object ann, object user)
1015 array annotations = ann->get_annotations_for(user);
1016 if ( arrayp(annotations) ) {
1017 foreach ( annotations, object a) {
1018 annotations += insert_annotations(a, user);
1028 * Bring the given array of annotation objects to XML.
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
1035 string show_annotations(array annotations)
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);
1042 foreach ( annotations, object ann ) {
1043 annotations += insert_annotations(ann, this_user());
1045 foreach(annotations, object annotation) {
1046 xml += serialize_xml_object(
1047 annotation, annotationXML, true);
1059 string do_show_attribute(object obj, mixed key, mixed val, mixed attrReg)
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";
1071 * Show the registered data of an attribute and its value. This is
1072 * used by attributes.xsl.
1074 * @param KEYVALUE k - key/value pair from a mapping.
1075 * @return xml presentation of the attribute data.
1077 string show_attribute(KEYVALUE k)
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);
1092 string show_attribute_reg(KEYVALUE k)
1095 mixed attrReg = k->val;
1096 mixed val= obj->get_attribute_default(key);
1097 return do_show_attribute(obj, key, val, attrReg);
1101 * Show how many objects a user carries.
1103 * @return the size of the current user selection.
1107 return (string)sizeof(selection);
1111 * This checks if there is a valid proxy.
1113 * @param object o - the object.
1114 * @return the proxy of the object
1117 object get_local_object(object o)
1123 * Describe a sanction bit array as a number of 'permission' tags.
1125 * @param int saction - the permission bit array.
1126 * @return xml presentation of access permissions.
1128 string show_access(int sanction)
1132 int sz = sizeof(__sanction);
1133 for ( int i = 0; i < sz; i++ ) {
1134 if ( __sanction[i] == "free" ) continue;
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";
1143 xml += "\t\t\t<permission type=\""+__sanction[i]+
1144 "\">0</permission>\n";
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.
1155 * @param objcet obj - the object to check.
1156 * @return the xml access string.
1158 string get_basic_access(object obj)
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;
1169 if ( gaccess & SANCTION_READ )
1170 xml += "<readable guest=\"true\" user=\"true\" steam=\"true\"/>";
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\"/>";
1178 xml += "\t<writeable guest=\"false\" user=\""+
1179 ((access&SANCTION_WRITE) ? "true":"false") + "\"/>\n";
1181 if ( gaccess & SANCTION_EXECUTE )
1182 xml += "<executeable guest=\"true\" user=\"true\" steam=\"true\"/>";
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\"/>";
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\"/>";
1194 xml += "\t<insertable guest=\"false\" user=\""+
1195 ((access&SANCTION_INSERT) ? "true":"false") + "\"/>\n";
1200 * Describe the acquired access of an object.
1202 * @param object obj - the object to describe its acquiring.
1203 * @return xml string about acquired access permission.
1205 string get_acquired_access(object obj)
1211 //DEBUG_XML("get_acquired_access("+obj->get_identifier()+")");
1212 object|function acquire = obj->get_acquire();
1214 if ( functionp(acquire) )
1215 acquire = acquire();
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())+
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;
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";
1238 xml += "\t\t\t\t<permission type=\""+__sanction[i]+
1239 "\">0</permission>\n";
1241 xml +="\t\t\t</Object>\n";
1243 acquire = acquire->get_acquire();
1244 if ( functionp(acquire) )
1245 acquire = acquire();
1251 * Describe the acquire situation of an object.
1253 * @param function|object acquire the acquire setting
1254 * @return xml description of the given function or object.
1256 string describe_acquire(function|object|string acquire)
1258 if ( functionp(acquire) && acquire == THIS->obj->get_environment )
1260 acquire = acquire();
1261 if ( objectp(acquire) )
1262 return "<function><name>get_environment</name><id>"+
1263 acquire->get_object_id()+ "</id></function>\n";
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>";
1273 * Serialize an XML tag with serialization data 'data'.
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.
1279 string serialize_xml_tag(string tag, array data)
1286 DEBUG_XML("<"+tag+">");
1288 string xml = "<"+tag+">";
1290 if ( !arrayp(data) )
1291 return xml + "</"+tag+">";
1293 if ( functionp(data[ID_FUNC]) ) {
1297 o = get_local_object(data[ID_OBJECT]);
1299 f = o->find_function(data[ID_FUNC]);
1303 for ( int i = 0; i < sizeof(data[ID_PARAMS]); i++ ) {
1304 if ( objectp(data[ID_PARAMS][i]) )
1306 params += ({ data[ID_PARAMS][i] });
1311 if ( functionp(f) ) {
1316 xml += "<!-- While serializing XML: " +err[0] + "-->\n";
1322 if ( functionp(data[ID_CONV]) ) {
1324 xml += data[ID_CONV](v);
1327 FATAL("While serializing XML:\n"+err[0]+
1328 sprintf("%O", err[1]));
1331 else if ( mappingp(data[ID_CONV]) )
1334 foreach( v, object obj) {
1335 if ( data[ID_CONV]->name == "none" )
1336 xml += serialize_xml_object(obj, data[ID_CONV], false);
1338 xml += serialize_xml_object(obj, data[ID_CONV], true);
1341 else if ( mappingp(v) ) {
1342 foreach( indices(v), mixed 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);
1350 xml += serialize_xml_object(ind, data[ID_CONV], true);
1354 foreach(indices(data[ID_CONV]), mixed idx) {
1355 xml += serialize_xml_tag(idx, data[ID_CONV][idx]);
1360 else if ( objectp(v) ) {
1361 LAST->obj = THIS->obj;
1362 xml += serialize_xml_object(v, data[ID_CONV], false);
1365 else if ( objectp(v) ) {
1368 else if ( stringp(v) || intp(v) )
1371 xml += "</"+tag+">\n";
1372 DEBUG_XML("</"+tag+">");
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.
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
1387 serialize_xml_object(object obj, mapping mXML, bool|void obj_tag )
1389 object xml = String.Buffer();
1391 if ( !objectp(obj) )
1392 return "<!-- Null Object cannot be serialized -->";
1394 if ( !mappingp(mXML) )
1397 if (obj->status()<PSTAT_DISK) // broken instance already loaded
1398 return "<!-- Unable to load broken instance from DB -->";
1400 if (!functionp(obj->this)) // broken instance on first load
1403 ENV->obj = obj->get_environment();
1405 DEBUG_XML("serialize_xml_object(THIS="+THIS->obj->get_identifier()+",LAST="+
1406 (objectp(LAST->obj) ? LAST->obj->get_identifier():"NULL")+")");
1408 string tagname = mXML->name;
1409 if ( !stringp(tagname) )
1412 xml->add("<"+tagname+" type="+
1413 class_id_to_name(obj->get_object_class())+
1415 " selected=\"true\"":" selected=\"false\"")+
1418 for ( int i = 31; i >= 0; i-- ) {
1420 if ( (idx & obj->get_object_class()) && mappingp(mXML[idx]) )
1422 foreach(indices(mXML[idx]), string tag) {
1423 xml->add(serialize_xml_tag(tag, mXML[idx][tag]));
1428 xml->add("</"+tagname+">\n");
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.
1437 * @param object p - the content object
1438 * @return content description for the object.
1440 string show_content(object p)
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>";
1452 * show a simple mapping in compact form
1453 * each key is a tag, and the value its content
1455 * @param mapping of strings
1456 * @return xml form of the mapping
1458 string show_mapping(mapping(string:string) 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);
1469 * Get a path as a series of object tags in XML.
1471 * @param object p - the object to get the path for.
1472 * @return xml path description for the object.
1474 string get_path(object p)
1476 object xml = String.Buffer();
1478 array(object|string) paths = ({ });
1481 while ( p != null ) {
1482 if ( stringp(s=_FILEPATH->check_tilde(p)) ) {
1483 paths = ({ p, s }) + paths;
1487 paths = ({ p, p->get_identifier() }) + paths;
1488 p = p->get_environment();
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>");
1500 if ( paths[-2]->get_object_class() & CLASS_CONTAINER )
1501 path += paths[-1] + "/";
1505 xml += "<path>"+no_uml(path)+"</path>\n";
1510 * Get a path as a series of object tags in XML.
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 -->
1519 * @param object p - the object to get the path for.
1520 * @return xml path description for the object.
1522 string get_rel_path(object p, void|int fsname)
1524 object xml = String.Buffer();
1526 array(object|string) paths = ({ });
1529 while ( p != null ) {
1530 if ( stringp(s=_FILEPATH->check_tilde(p)) ) {
1531 paths = ({ p, s }) + paths;
1537 p->query_attribute("fs_name") : p->get_identifier())
1539 p = p->get_environment();
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] + "/";
1554 if ( paths[-2]->get_object_class() & CLASS_CONTAINER )
1555 path += paths[-1] + "/";
1559 xml += "<path>"+no_uml(path)+"</path>\n";
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)
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 -->
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.
1583 string get_neighbours(object p, void|int filterclass, void|int fsname)
1585 DEBUG_XML(sprintf("get_neighbours %O, %d\n", p, filterclass));
1586 object env = p->get_environment();
1589 inv = env->get_inventory();
1592 inv = env->get_inventory_by_class(p->get_object_class());
1593 DEBUG_XML(sprintf("inv is %O\n", inv));
1595 int i = search(inv, p);
1596 object xml = String.Buffer();
1599 if (i>0) left = inv[i-1];
1600 if ((i!=-1) && (i<sizeof(inv)-1)) right = inv[i+1];
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>");
1612 xml->add("<fsname>");
1613 xml->add((string)left->query_attribute("fs_name"));
1614 xml->add("</fsname>");
1616 xml->add("<description><![CDATA[");
1617 xml->add(left->query_attribute(OBJ_DESC));
1618 xml->add("]]></description></object>");
1620 xml->add("</left><right>");
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>");
1630 xml->add("<fsname>");
1631 xml->add((string)right->query_attribute("fs_name"));
1632 xml->add("</fsname>");
1634 xml->add("<description><![CDATA[");
1635 xml->add(right->query_attribute(OBJ_DESC));
1636 xml->add("]]></description></object>");
1638 xml->add("</right>");
1645 void xml_describe(object node, int selected, int depth, string url,
1649 object o = node->get_object();
1650 function qa = o->query_attribute;
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"))
1659 xml->add("<fsname>");
1661 xml->add("</fsname>\n");
1663 xml->add("<description><![CDATA[");
1664 xml->add(qa(OBJ_DESC));
1665 xml->add("]]></description>\n<selected>");
1670 xml->add("</selected>\n<depth>");
1671 xml->add((string)depth);
1672 xml->add("</depth>\n<url><![CDATA[");
1674 xml->add("]]></url>\n");
1681 void xml_recurse(object root, int depth, int level, string url, int filter,
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)
1690 xml->add("<object>\n");
1691 xml_describe(node, 0, level,
1692 url + "/" + root->query_attribute(OBJ_NAME),
1694 xml->add("</object>\n");
1697 xml_recurse(node, depth-1, level+1,
1698 url + "/" + root->query_attribute(OBJ_NAME),
1701 xml->add("</object>\n");
1708 void xml_subtree(array path, String.Buffer xml,
1709 int depth, int level, string url, int filter)
1711 object root = path[0];
1714 xml->add("<object>\n");
1715 xml_describe(root, 1, level, url, xml);
1717 object nextnode = sizeof(path) ? path[0] : 0;
1718 array inv = root->get_inventory_by_class(filter);
1719 foreach(inv, object node)
1721 if (node == nextnode)
1722 xml_subtree(path, xml, depth-1, level+1,
1723 url+"/"+node->query_attribute(OBJ_NAME), filter);
1726 xml->add("<object>\n");
1727 xml_describe(node, 0, level+1,
1728 url + "/" + node->query_attribute(OBJ_NAME),
1730 xml->add("</object>\n");
1733 xml_recurse(node, depth-1 , level+1,
1734 url + "/" + node->query_attribute(OBJ_NAME),
1737 xml->add("</object>\n");
1742 string get_rel_tree(object root, object leaf, int depth, int filter)
1744 array path = ({ leaf });
1747 while (node && node!=root)
1749 node = node->get_environment();
1751 path = ({ node }) + path;
1754 return "<relpath></relpath>";
1756 object xml = String.Buffer();
1757 xml_subtree(path, xml, depth, 0, "", filter);
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.
1768 * @param object o - The object to get the path for.
1769 * @return (string) The public path of the object
1771 string get_public_name(object o)
1777 sPublicPath = o->get_identifier();
1778 while ((x=x->get_environment()) && !(sPublicRoot = x->query_attribute("url")))
1781 sPublicPath = x->get_identifier() + "/" + sPublicPath;
1785 return combine_path(sPublicRoot, sPublicPath);
1792 * Get the XML representation of this object. To speed up things, the
1793 * type selects which part of the data should be xmlified.
1795 * @param obj - the object to convert
1796 * @param type - the type of the object
1797 * @return the xml data
1799 string get_xml(object obj, object xsl, void|mapping vars, mixed|void active)
1801 object xml = String.Buffer(32468);
1807 if ( mappingp(vars) && vars->this_user > 0 )
1808 user = find_object(vars->this_user);
1812 if ( !objectp(user) )
1815 object pike = xsl->query_attribute(DOC_XSL_PIKE);
1816 if ( objectp(xsl) && objectp(pike) ) {
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));
1825 mixed errerr = catch {
1826 array lines = pike->get_content() / "\n";
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]);
1837 FATAL("Error modifying error in xml_converter.pike: %O",
1848 selection = user->query_attribute(USER_SELECTION);
1849 if ( !arrayp(selection) )
1851 mSelection = mkmapping(selection, selection);
1859 "path": ({ CONV, "get_path", ({ THIS }), 0 }),
1860 "user": ({ 0, this_user, ({ }), userXML }),
1861 ])+objXML[CLASS_OBJECT],
1864 "inventory": ({ THIS, "get_inventory", ({ }),
1865 objXML+exitXML+linkXML+userXML+containerXML}),
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();
1876 if ( equal(mXML, ([ ])) )
1877 THROW("No XML Description found for Stylesheet !", E_ERROR);
1879 THIS_USER->obj = user;
1883 if (!mappingp(vars))
1888 foreach(indices(params), string p) {
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);
1899 params[p]->val = vars[p];
1902 params[p]->val = params[p]->def;
1906 if ( intp(active) && active > 0 ) {
1907 ACTIVE->obj = find_object(active);
1910 if ( vars->type == "annotations" ||
1911 obj->get_object_class() & CLASS_MESSAGEBOARD )
1913 object from_obj = get_var("from_obj", 1);
1914 array annotations = obj->get_annotations_for(
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];
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();
1932 DEBUG_XML("XML:Convertor - Using\n"+sprintf("%O", mXML));
1934 xml->add( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1935 xml->add( serialize_xml_object(obj, mXML, true) );
1937 string result = xml->get();
1941 bool check_swap() { return false; }
1942 string get_identifier() { return "Converter:XML"; }
1943 function find_function(string f) { return this_object()[f]; }
1945 object get_var(string name, mixed val)
1947 object param = params[name];
1948 if ( !objectp(param) ) {
1951 if ( !stringp(val) ) {
1956 sscanf(val, "%d", v);
1957 if ( (string)v == val ) {
1967 params[name] = param;
1973 // try images folder...
1974 object images = find_object("/images");
1975 if ( !objectp(images) )
1979 if (sizeof(images->get_inventory()) < 15) {
1980 error(sprintf("/images Container not filled correctly:\n%O",
1981 images->get_inventory()));
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));
1987 foreach(inv, object obj) {
1988 if ( !(obj->get_object_class() & CLASS_CONTAINER) )
1990 if ( !containers && obj->get_object_class() & CLASS_CONTAINER )
1991 error("Containers not correctly sorted");
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);