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: DocHTML.pike,v 1.2 2009/08/07 16:14:56 nicke Exp $
19 inherit "/classes/Document";
24 #include <exception.h>
25 #include <attributes.h>
27 //! This document type holds html data and handles link consistency.
28 class DocHTML : public Document{
36 private function fExchange;
38 private string sFilePosition;
39 private object oParser;
46 * Initialize the document and set data storage.
53 add_data_storage(STORE_HTMLLINK, store_links, restore_links);
60 * Return the quoted tag.
62 * @param Parser.HTML p - parser context.
63 * @param string tag - the tag.
67 mixed quote(Parser.HTML p, string tag) {
68 return ({ "<!--"+tag+"-->" });
73 * A scrip tag was found while parsing.
75 * @param Parser.HTML p - the parser context.
79 mixed script(Parser.HTML p, string tag) {
80 LOG("Script Tag!!!\n"+tag+"\nEND\n");
81 return ({ "<SCRIPT "+tag+"SCRIPT>" });
87 * Main function for link exchange. Called every time a potential
88 * link tag was parsed.
90 * @param Parser.HTML p - the parser context.
91 * @param string tag - the tag found.
92 * @return tag with exchanged links.
95 mixed exchange_links(Parser.HTML p, string tag) {
105 // MESSAGE("TAG:"+tag);
115 if ( tag[i] == '"' || tag[i] == '\'' )
117 else if ( (tag[i] == ' ' || tag[i] == '\t' || tag[i]=='\n') &&
118 mode == MODE_NORMAL )
120 attr += ({ tag[start..i-1] });
126 if ( tag[l-2] == '/' ) {
128 attr += ({ tag[start..l-3] });
130 else if ( start <= l-2 ) {
131 attr += ({ tag[start..l-2] });
134 if ( arrayp(attr) && sizeof(attr) > 0 ) {
139 for ( int i = 1; i < sizeof(attr); i++ ) {
140 if ( (p = search(attr[i], "=")) > 0 ) {
143 if ( strlen(b) > 0 ) {
144 if ( b[0] == '"' || b[0] == '\'' )
145 b = b[1..strlen(b)-2];
151 attr = indices(attributes);
152 foreach(attr, attribute) {
153 if ( lower_case(attribute) == "src" ||
154 lower_case(attribute) == "href" ||
155 lower_case(attribute) == "background" )
158 mixed res = fExchange(attributes[attribute]);
159 if ( intp(res) && res > 0 ) {
160 attributes["oid"] = (string)res;
163 else if ( stringp(res) )
164 attributes[attribute] = res;
167 FATAL("Error exchange links: %O\n%O", err[0], err[1]);
170 else if ( lower_case(attribute) == "content" ) {
172 if ( sscanf(attributes[attribute], "%*scharset=%s", ctype) )
173 do_set_attribute(DOC_ENCODING, lower_case(ctype));
183 foreach(attr, attribute) {
184 result += " " + attribute + "=\""+attributes[attribute] + "\"";
186 if ( search(tag, "/>") > -1 )
190 //werror("Exchanged Tag: " + result+"\n");
195 return ({ result }); // nothing to be done
200 class UploadHTMLParser {
202 object oContentHandle;
203 void create(object ContentHandle) {
204 oContentHandle = ContentHandle;
208 * Callback function to save a chunk of data received by the server.
210 * @param string chunk - the received chunk.
212 void save_chunk(string chunk) {
214 if ( objectp(oParser) ) {
215 if ( !stringp(chunk) ) {
216 err = catch(oParser->finish());
218 FATAL("Parsing HTML failed: %O:%O\n", err[0], err[1]);
221 oContentHandle->save_chunk(0);
225 err = catch(oParser->feed(chunk, 1));
227 FATAL("Parsing HTML failed: %O:%O\n", err[0], err[1]);
231 if ( stringp(chunk) ) {
232 oContentHandle->save_chunk(chunk);
235 oContentHandle->save_chunk(0);
241 * Function to start an upload. Returns the save_chunk function.
243 * @param int content_size the size of the content.
244 * @return upload function.
246 function receive_content(int content_size)
249 if ( (obj->get_object_class() & CLASS_USER) &&
250 (functionp(obj->get_user_object) ) &&
251 objectp(obj->get_user_object()) )
252 obj = obj->get_user_object();
254 try_event(EVENT_UPLOAD, obj, content_size);
256 sFilePosition = _FILEPATH->object_to_path(this_object());
257 oParser = Parser.HTML();
258 oParser->_set_tag_callback(exchange_links);
259 oParser->add_quote_tag("!--", quote, "--");
260 oParser->add_quote_tag("SCRIPT", script, "SCRIPT");
261 oParser->add_quote_tag("script", script, "script");
262 fExchange = exchange_ref;
265 // duplicate object with old content id
266 int version = do_query_attribute(DOC_VERSION);
270 seteuid(get_creator());
271 object oldversion = duplicate( ([ "content_id": get_content_id(), ]));
272 mapping versions = do_query_attribute(DOC_VERSIONS);
273 oldversion->set_attribute(DOC_VERSIONS, copy_value(versions));
274 if ( !mappingp(versions) )
276 versions[version] = oldversion;
278 oldversion->set_attribute(DOC_LAST_MODIFIED, do_query_attribute(DOC_LAST_MODIFIED));
279 oldversion->set_attribute(DOC_USER_MODIFIED, do_query_attribute(DOC_USER_MODIFIED));
280 oldversion->set_attribute(OBJ_CREATION_TIME, do_query_attribute(OBJ_CREATION_TIME));
283 do_set_attribute(DOC_VERSIONS, versions);
285 do_set_attribute(DOC_VERSION, version);
287 do_set_attribute(DOC_LAST_MODIFIED, time());
288 do_set_attribute(DOC_USER_MODIFIED, this_user());
290 object oContentHandler = get_upload_handler(content_size);
291 object oUploadHTMLParser = UploadHTMLParser(oContentHandler);
292 return oUploadHTMLParser->save_chunk;
296 * Create a path inside steam which is a sequenz of containers.
298 * @param string p - the path to create.
299 * @return the container created last.
302 object create_path(string p)
304 //MESSAGE("create_path("+p+")");
305 if ( strlen(p) == 0 )
306 return get_environment();
308 array tokens = p / "/";
309 object cont = _ROOTROOM;
310 object factory = _Server->get_factory(CLASS_CONTAINER);
312 for ( int i = 0; i < sizeof(tokens)-1; i++) {
314 if ( tokens[i] == "" )
316 obj = _FILEPATH->resolve_path(cont, tokens[i]);
317 if ( !objectp(obj) ) {
318 obj = factory->execute((["name":tokens[i],]));
321 //else MESSAGE("Found path in cont: " + tokens[i]);
324 //MESSAGE("Found:" + cont->get_identifier());
330 int exchange_ref(string link)
333 string linkstr, position, type;
335 if ( !objectp(get_environment()) )
338 link = replace(link, "\\", "/");
339 if ( search(link, "get.pike") >= 0 || search(link, "navigate.pike") >= 0 )
341 if ( sscanf(link, "%s://%s", type, linkstr) == 2 ) {
342 add_extern_link(linkstr, type);
345 if ( sscanf(link, "mailto:%s", linkstr) == 1 )
347 add_extern_link(linkstr, "mailto");
350 if ( sscanf(lower_case(link), "javascript:%s", linkstr) == 1 )
352 if ( sscanf(link, "%s#%s", linkstr, position) == 2 ) {
356 if ( link == get_identifier() ) {
359 link = combine_path(_FILEPATH->object_to_filename(get_environment()),
362 obj = _FILEPATH->path_to_object(link);
367 add_local_link(obj, type, position, link);
368 return obj->get_object_id();
371 object get_link(string href)
373 mapping links = do_query_attribute(OBJ_LINKS);
374 if ( mappingp(links) )
382 * Return mapping with save data used by _Database.
384 * @return all the links.
390 if ( CALLER != _Database )
391 THROW("Caller is not Database !", E_ACCESS);
392 return ([ "Links": mLinks, ]);
398 * Restore the saved link data. This is called by database and
399 * sets the Links mapping again.
401 * @param mixed data - saved data.
404 void restore_links(mixed data)
406 if (CALLER != _Database ) THROW("Caller is not Database !", E_ACCESS);
407 mLinks = data["Links"];
415 * @param object o - the object containing a reference to this doc.
416 * @param string type - the typ of reference.
417 * @string position - where the link points.
420 void add_local_link(object o, string type, string position, string link)
422 if ( o->get_object_id() == get_object_id() )
423 return; // no links to ourself!
424 if ( !mappingp(mLinks[o]) )
425 mLinks[o] = ([ position: 1 ]);
427 if ( zero_type(mLinks[o][position]) )
428 mLinks[o][position] = 1;
430 mLinks[o][position]++;
432 mapping links = do_query_attribute(OBJ_LINKS);
433 if ( !mappingp(links) )
436 do_set_attribute(OBJ_LINKS, links);
438 require_save(STORE_HTMLLINK);
444 * Get an array of links pointing to local(steam) objects.
446 * @return array of link objects.
448 array get_local_links()
450 array result = ({ });
451 array index = indices(mLinks);
453 foreach(index, mixed idx) {
461 * Add an extern link to some URL.
463 * @param string url - the url to point to.
464 * @param string type - the type of the link.
467 void add_extern_link(string url, string type)
469 if ( zero_type(mLinks[url]) )
473 require_save(STORE_HTMLLINK);
480 * an object was deleted and so the link to this object is outdated !
485 object creator = get_creator();
486 run_event(EVENT_REF_GONE, link, creator);
491 * Reset all saved link data.
497 // first remove all references on other objects
498 if ( mappingp(mLinks) ) {
499 foreach(indices(mLinks), mixed index) {
500 if ( objectp(index) && index->status() >= 0 ) {
510 * Get a copy of the Links mapping.
512 * @return copied link mapping.
516 return copy_value(mLinks);
521 * Get the object class which is CLASS_DOCHTML of course.
523 * @return the object class.
528 return ::get_object_class() | CLASS_DOCHTML;
531 string get_class() { return "DocHTML"; }
534 * Get the size of the content which is the size of the document
535 * with exchanged links.
537 * @return the content size.
539 int get_content_size()
541 return (__size > 0 ? __size : ::get_content_size());
546 // todo: funktionen hinzu zum testen von create_path() und links austauschen