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.4 2006/10/09 08:22:47 astra Exp $
20
constant cvs_version="$Id: DocHTML.pike,v 1.4 2006/10/09 08:22:47 astra Exp $";
22
inherit "/classes/Document";
24
//! This document type holds html data and handles link consistency.
30
#include <exception.h>
31
#include <attributes.h>
34
private static string sContentCache = 0;
35
private static function fExchange;
36
private static bool __blocked;
37
private static int __size;
38
private static int iLinkStatus;
39
private static string sFilePosition;
40
private static object oParser;
41
static mapping mLinks;
47
* Initialize the document and set data storage.
49
* @author Thomas Bopp (astra@upb.de)
51
static void init_document()
54
add_data_storage(STORE_HTMLLINK, store_links, restore_links);
59
* Return the quoted tag.
61
* @param Parser.HTML p - parser context.
62
* @param string tag - the tag.
64
* @author <a href="mailto:astra@upb.de">Thomas Bopp</a>)
66
static mixed quote(Parser.HTML p, string tag) {
67
return ({ "<!--"+tag+"-->" });
70
* A scrip tag was found while parsing.
72
* @param Parser.HTML p - the parser context.
74
* @author <a href="mailto:astra@upb.de">Thomas Bopp</a>)
76
static mixed script(Parser.HTML p, string tag) {
77
LOG("Script Tag!!!\n"+tag+"\nEND\n");
78
return ({ "<SCRIPT "+tag+"SCRIPT>" });
82
* Main function for link exchange. Called every time a potential
83
* link tag was parsed.
85
* @param Parser.HTML p - the parser context.
86
* @param string tag - the tag found.
87
* @return tag with exchanged links.
88
* @author Thomas Bopp (astra@upb.de)
90
static mixed exchange_links(Parser.HTML p, string tag) {
101
// MESSAGE("TAG:"+tag);
111
if ( tag[i] == '"' || tag[i] == '\'' )
113
else if ( (tag[i] == ' ' || tag[i] == '\t' || tag[i]=='\n') &&
114
mode == MODE_NORMAL )
116
attr += ({ tag[start..i-1] });
122
if ( tag[l-2] == '/' ) {
124
attr += ({ tag[start..l-3] });
126
else if ( start <= l-2 ) {
127
attr += ({ tag[start..l-2] });
130
if ( arrayp(attr) && sizeof(attr) > 0 ) {
135
for ( int i = 1; i < sizeof(attr); i++ ) {
136
if ( (p = search(attr[i], "=")) > 0 ) {
139
if ( strlen(b) > 0 ) {
140
if ( b[0] == '"' || b[0] == '\'' )
141
b = b[1..strlen(b)-2];
147
attr = indices(attributes);
148
foreach(attr, attribute) {
149
if ( lower_case(attribute) == "src" ||
150
lower_case(attribute) == "href" ||
151
lower_case(attribute) == "background" )
154
mixed res = fExchange(attributes[attribute]);
155
if ( intp(res) && res > 0 ) {
156
attributes["oid"] = (string)res;
159
else if ( stringp(res) )
160
attributes[attribute] = res;
163
werror("Error exchange links: %O\n", err);
166
else if ( lower_case(attribute) == "content" ) {
168
if ( sscanf(attributes[attribute], "%*scharset=%s", ctype) )
169
do_set_attribute(DOC_ENCODING, lower_case(ctype));
179
foreach(attr, attribute) {
180
result += " " + attribute + "=\""+attributes[attribute] + "\"";
182
if ( search(tag, "/>") > -1 )
186
//werror("Exchanged Tag: " + result+"\n");
191
return ({ result }); // nothing to be done
194
class UploadHTMLParser {
195
object oContentHandle;
196
void create(object ContentHandle) {
197
oContentHandle = ContentHandle;
201
* Upload is finished and links can be exchanged. Callback function.
203
* @param int id - id for the content.
204
* @author Thomas Bopp (astra@upb.de)
206
void finish_upload(int id) {
208
sFilePosition = _FILEPATH->object_to_path(this_object());
210
oContentHandle->save_chunk(sContentCache);
211
oContentHandle->save_chunk(0);
216
_LOG("Error while uploading:\n"+PRINT_BT(err));
217
oContentHandle->save_chunk(0);
222
* Callback function to save a chunk of data received by the server.
224
* @param string chunk - the received chunk.
225
* @author Thomas Bopp (astra@upb.de)
227
void save_chunk(string chunk) {
229
if ( objectp(oParser) ) {
230
if ( !stringp(chunk) ) {
232
_chunk = oParser->read();
233
LOG("Result chunk=\n"+_chunk);
234
if ( stringp(_chunk) && strlen(_chunk) > 0 ) {
235
oContentHandle->save_chunk(_chunk);
236
sContentCache += _chunk;
239
//finish_upload(get_object_id());
240
oContentHandle->save_chunk(0);
244
oParser->feed(chunk, 1);
245
_chunk = oParser->read();
251
if ( stringp(_chunk) ) {
252
oContentHandle->save_chunk(_chunk);
253
sContentCache += _chunk;
256
oContentHandle->save_chunk(0);
262
* Function to start an upload. Returns the save_chunk function.
264
* @param int content_size the size of the content.
265
* @return upload function.
267
function receive_content(int content_size)
270
if ( (obj->get_object_class() & CLASS_USER) &&
271
(functionp(obj->get_user_object) ) &&
272
objectp(obj->get_user_object()) )
273
obj = obj->get_user_object();
275
try_event(EVENT_UPLOAD, obj, content_size);
278
if ( objectp(oEnvironment) &&
279
oEnvironment->query_attribute(CONT_EXCHANGE_LINKS) == 1 )
281
sFilePosition = _FILEPATH->object_to_path(this_object());
282
oParser = Parser.HTML();
283
oParser->_set_tag_callback(exchange_links);
284
oParser->add_quote_tag("!--", quote, "--");
285
oParser->add_quote_tag("SCRIPT", script, "SCRIPT");
286
oParser->add_quote_tag("script", script, "script");
287
fExchange = exchange_ref;
291
// duplicate object with old content id
292
int version = do_query_attribute(DOC_VERSION);
296
seteuid(get_creator());
297
object oldversion = duplicate( ([ "content_id": get_content_id(), ]));
298
mapping versions = do_query_attribute(DOC_VERSIONS);
299
oldversion->set_attribute(DOC_VERSIONS, copy_value(versions));
300
if ( !mappingp(versions) )
302
versions[version] = oldversion;
303
oldversion->set_acquire(this());
305
oldversion->set_attribute(OBJ_VERSIONOF, this());
306
oldversion->set_attribute(DOC_LAST_MODIFIED, do_query_attribute(DOC_LAST_MODIFIED));
307
oldversion->set_attribute(DOC_USER_MODIFIED, do_query_attribute(DOC_USER_MODIFIED));
308
oldversion->set_attribute(OBJ_CREATION_TIME, do_query_attribute(OBJ_CREATION_TIME));
311
do_set_attribute(DOC_VERSIONS, versions);
313
do_set_attribute(DOC_VERSION, version);
315
do_set_attribute(DOC_LAST_MODIFIED, time());
316
do_set_attribute(DOC_USER_MODIFIED, this_user());
318
object oContentHandler = get_upload_handler(content_size);
319
object oUploadHTMLParser = UploadHTMLParser(oContentHandler);
320
return oUploadHTMLParser->save_chunk;
324
* Analyse a given path. This function actually looks suspicious (bugs???).
326
* @param string p - the path to analyse
327
* @return array of size 2 with - I give up.
329
array(string) analyse_path(string p)
331
array(string) tokens = p / "/";
332
int sz = sizeof(tokens);
336
return ({ tokens[0], tokens[1] });
337
return ({ tokens[sz-1], tokens[0..sz]*"/" });
341
* Create a path inside steam which is a sequenz of containers.
343
* @param string p - the path to create.
344
* @return the container created last.
346
static object create_path(string p)
348
//MESSAGE("create_path("+p+")");
349
if ( strlen(p) == 0 )
350
return get_environment();
352
array(string) tokens = p / "/";
353
object cont = _ROOTROOM;
354
object factory = _Server->get_factory(CLASS_CONTAINER);
356
for ( int i = 0; i < sizeof(tokens)-1; i++) {
358
if ( tokens[i] == "" )
360
obj = _FILEPATH->resolve_path(cont, tokens[i]);
361
if ( !objectp(obj) ) {
362
obj = factory->execute((["name":tokens[i],]));
365
//else MESSAGE("Found path in cont: " + tokens[i]);
368
//MESSAGE("Found:" + cont->get_identifier());
372
int exchange_ref(string link)
375
string linkstr, position, type;
378
if ( !objectp(get_environment()) )
381
link = replace(link, "\\", "/");
382
if ( search(link, "get.pike") >= 0 || search(link, "navigate.pike") >= 0 )
384
if ( sscanf(link, "%s://%s", type, linkstr) == 2 ) {
385
add_extern_link(linkstr, type);
388
if ( sscanf(link, "mailto:%s", linkstr) == 1 )
390
add_extern_link(linkstr, "mailto");
393
if ( sscanf(lower_case(link), "javascript:%s", linkstr) == 1 )
395
if ( sscanf(link, "%s#%s", linkstr, position) == 2 ) {
399
if ( link == get_identifier() ) {
400
add_local_link(this(), type, position);
403
link = combine_path(_FILEPATH->object_to_filename(get_environment()),
406
obj = _FILEPATH->path_to_object(link);
411
add_local_link(obj, type, position);
412
return obj->get_object_id();
416
* this is the content callback function
417
* in this case we have to read the whole content at once hmmm
419
* @param int pos - the current position of sending.
420
* @return chunk of content.
421
* @author Thomas Bopp (astra@upb.de)
424
private static string
425
send_content_html(int pos)
429
if ( !stringp(sContentCache) )
430
return 0; // finished
432
if ( strlen(sContentCache) < DB_CHUNK_SIZE ) {
433
result = copy_value(sContentCache);
437
result = sContentCache[..DB_CHUNK_SIZE-1];
438
sContentCache = sContentCache[DB_CHUNK_SIZE..];
444
* Get the callback function for content.
446
* @param mapping vars - the variables from the web server.
447
* @return content function.
448
* @author Thomas Bopp (astra@upb.de)
450
function get_content_callback(mapping vars)
452
object caller = CALLER;
453
// todo: need to re-exchange links (possible)
454
string content = get_content();
455
if ( !mappingp(vars) )
457
vars->fp = _FILEPATH;
458
vars->env = get_environment();
460
"a": htmllib.get_tag_function(OBJ("/tags/a.pike")),
461
"img": htmllib.get_tag_function(OBJ("/tags/img.pike")),
462
"javascript": htmllib.get_tag_function(OBJ("/tags/javascript.pike")),
463
"background": htmllib.get_tag_function(OBJ("/tags/background.pike")),
466
string encoding = do_query_attribute(DOC_ENCODING);
468
if ( stringp(encoding) ) {
469
encoding = lower_case(encoding);
471
//sContentCache = htmllib.parse_rxml(content, vars, tags, encoding);
472
sContentCache = content; // parse rxml now ???
473
__size = strlen(sContentCache);
476
sContentCache = content;
477
__size = strlen(content);
479
return send_content_html;
483
* Return mapping with save data used by _Database.
485
* @return all the links.
486
* @author Thomas Bopp (astra@upb.de)
491
if ( CALLER != _Database )
492
THROW("Caller is not Database !", E_ACCESS);
493
return ([ "Links": mLinks, ]);
497
* Restore the saved link data. This is called by database and
498
* sets the Links mapping again.
500
* @param mixed data - saved data.
501
* @author Thomas Bopp (astra@upb.de)
503
void restore_links(mixed data)
505
if (CALLER != _Database ) THROW("Caller is not Database !", E_ACCESS);
506
mLinks = data["Links"];
512
* @param object o - the object containing a reference to this doc.
513
* @param string type - the typ of reference.
514
* @string position - where the link points.
515
* @author Thomas Bopp (astra@upb.de)
517
static void add_local_link(object o, string type, string position)
519
if ( o->get_object_id() == get_object_id() )
520
return; // no links to ourself!
521
if ( !mappingp(mLinks[o]) )
522
mLinks[o] = ([ position: 1 ]);
524
if ( zero_type(mLinks[o][position]) )
525
mLinks[o][position] = 1;
527
mLinks[o][position]++;
529
o->add_reference(this());
530
require_save(STORE_HTMLLINK);
534
* Get an array of links pointing to local(steam) objects.
536
* @return array of link objects.
538
array get_local_links()
540
array result = ({ });
541
array index = indices(mLinks);
543
foreach(index, mixed idx) {
551
* Add an extern link to some URL.
553
* @param string url - the url to point to.
554
* @param string type - the type of the link.
555
* @author Thomas Bopp (astra@upb.de)
557
static void add_extern_link(string url, string type)
559
if ( zero_type(mLinks[url]) )
563
require_save(STORE_HTMLLINK);
568
* an object was deleted and so the link to this object is outdated !
570
* @author Thomas Bopp (astra@upb.de)
574
object link = CALLER->this();
575
object creator = get_creator();
576
run_event(EVENT_REF_GONE, link, creator);
581
* Reset all saved link data.
583
* @author Thomas Bopp (astra@upb.de)
585
static void reset_links()
587
// first remove all references on other objects
588
if ( mappingp(mLinks) ) {
589
foreach(indices(mLinks), mixed index) {
590
if ( objectp(index) && index->status() >= 0 ) {
591
catch(index->remove_reference(this()));
599
* Get a copy of the Links mapping.
601
* @return copied link mapping.
602
* @author Thomas Bopp (astra@upb.de)
606
return copy_value(mLinks);
611
* Get the object class which is CLASS_DOCHTML of course.
613
* @return the object class.
614
* @author Thomas Bopp (astra@upb.de)
619
return ::get_object_class() | CLASS_DOCHTML;
623
* Get the size of the content which is the size of the document
624
* with exchanged links.
626
* @return the content size.
627
* @author Thomas Bopp (astra@upb.de)
629
int get_content_size()
631
return (__size > 0 ? __size : ::get_content_size());
637
// todo: funktionen hinzu zum testen von create_path() und links austauschen