~ubuntu-branches/ubuntu/wily/steam/wily

« back to all changes in this revision

Viewing changes to server/classes/DocHTML.pike

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2013-10-29 19:51:18 UTC
  • mfrom: (1.1.4) (0.1.4 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20131029195118-b9bxciz5hwx5z459
Tags: 1:1.0.0.39-2ubuntu1
Add an epoch to the version number as there was an unrelated steam package
in the archive with a higher version number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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: DocHTML.pike,v 1.4 2006/10/09 08:22:47 astra Exp $
18
 
 */
19
 
 
20
 
constant cvs_version="$Id: DocHTML.pike,v 1.4 2006/10/09 08:22:47 astra Exp $";
21
 
 
22
 
inherit "/classes/Document";
23
 
 
24
 
//! This document type holds html data and handles link consistency.
25
 
 
26
 
#include <macros.h>
27
 
#include <classes.h>
28
 
#include <assert.h>
29
 
#include <database.h>
30
 
#include <exception.h>
31
 
#include <attributes.h>
32
 
#include <events.h>
33
 
 
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;
42
 
 
43
 
#define MODE_NORMAL 0
44
 
#define MODE_STRING 1
45
 
 
46
 
/**
47
 
 * Initialize the document and set data storage.
48
 
 *  
49
 
 * @author Thomas Bopp (astra@upb.de) 
50
 
 */
51
 
static void init_document()
52
 
{
53
 
    mLinks = ([ ]);
54
 
    add_data_storage(STORE_HTMLLINK, store_links, restore_links);
55
 
}
56
 
 
57
 
 
58
 
/**
59
 
 * Return the quoted tag.
60
 
 *  
61
 
 * @param Parser.HTML p - parser context.
62
 
 * @param string tag - the tag.
63
 
 * @return quoted tag.
64
 
 * @author <a href="mailto:astra@upb.de">Thomas Bopp</a>) 
65
 
 */
66
 
static mixed quote(Parser.HTML p, string tag) {
67
 
    return ({ "<!--"+tag+"-->" });
68
 
}
69
 
/**
70
 
 * A scrip tag was found while parsing.
71
 
 *  
72
 
 * @param Parser.HTML p - the parser context.
73
 
 * @return script tag.
74
 
 * @author <a href="mailto:astra@upb.de">Thomas Bopp</a>) 
75
 
 */
76
 
static mixed script(Parser.HTML p, string tag) {
77
 
    LOG("Script Tag!!!\n"+tag+"\nEND\n");
78
 
    return ({ "<SCRIPT "+tag+"SCRIPT>" });
79
 
}
80
 
 
81
 
/**
82
 
 * Main function for link exchange. Called every time a potential
83
 
 * link tag was parsed.
84
 
 *  
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) 
89
 
 */
90
 
static mixed exchange_links(Parser.HTML p, string tag) {
91
 
    array(string)  attr;
92
 
    mapping  attributes;
93
 
    mapping nattributes;
94
 
    string    attribute;
95
 
    bool   link = false;
96
 
    string        tname;
97
 
    int      mode, i, l;
98
 
    
99
 
    attributes = ([ ]);
100
 
    
101
 
    //        MESSAGE("TAG:"+tag);
102
 
    
103
 
    l = strlen(tag);
104
 
    mode = MODE_NORMAL;
105
 
    i = 1;
106
 
    tname = "";
107
 
    int start = 1;
108
 
    
109
 
    attr = ({ });
110
 
    while ( i < l ) {   
111
 
        if ( tag[i] == '"' || tag[i] == '\'' ) 
112
 
            mode = (mode+1)%2;
113
 
        else if ( (tag[i] == ' ' || tag[i] == '\t' || tag[i]=='\n') && 
114
 
                  mode == MODE_NORMAL ) 
115
 
        {
116
 
            attr += ({ tag[start..i-1] });
117
 
            start = i+1;
118
 
        }
119
 
        i++;
120
 
    }
121
 
    
122
 
    if ( tag[l-2] == '/' ) {
123
 
        if ( start < l-3 )
124
 
            attr += ({ tag[start..l-3] });
125
 
    }
126
 
    else if ( start <= l-2 ) {
127
 
        attr += ({ tag[start..l-2] });
128
 
    }
129
 
    
130
 
    if ( arrayp(attr) && sizeof(attr) > 0 ) {
131
 
        string a, b;
132
 
        int       p;
133
 
        
134
 
        tname = attr[0];
135
 
        for ( int i = 1; i < sizeof(attr); i++ ) {
136
 
            if ( (p = search(attr[i], "=")) > 0 ) {
137
 
                a = attr[i][..p-1];
138
 
                b = attr[i][p+1..];
139
 
                if ( strlen(b) > 0 ) {
140
 
                    if ( b[0] == '"' || b[0] == '\'' )
141
 
                        b = b[1..strlen(b)-2];
142
 
                    attributes[a] = b;
143
 
                }
144
 
            }
145
 
        }
146
 
    }
147
 
    attr = indices(attributes);
148
 
    foreach(attr, attribute) {
149
 
        if ( lower_case(attribute) == "src" || 
150
 
             lower_case(attribute) == "href" ||
151
 
             lower_case(attribute) == "background" )
152
 
        {
153
 
            mixed err = catch {
154
 
                mixed res = fExchange(attributes[attribute]);
155
 
                if ( intp(res) && res > 0 ) {
156
 
                    attributes["oid"] =  (string)res;
157
 
                    attr += ({ "oid" });
158
 
                }
159
 
                else if ( stringp(res) )
160
 
                    attributes[attribute] = res;
161
 
            };
162
 
            if ( err != 0 )
163
 
                werror("Error exchange links: %O\n", err);
164
 
            link = true;
165
 
        }
166
 
        else if ( lower_case(attribute) == "content" ) {
167
 
            string ctype;
168
 
            if ( sscanf(attributes[attribute], "%*scharset=%s", ctype) )
169
 
                do_set_attribute(DOC_ENCODING, lower_case(ctype));
170
 
        }
171
 
    }
172
 
    
173
 
    
174
 
    string result;
175
 
    
176
 
    
177
 
    if ( link ) {
178
 
        result = "<"+tname;
179
 
        foreach(attr, attribute) {
180
 
            result += " " + attribute + "=\""+attributes[attribute] + "\"";
181
 
        }
182
 
        if ( search(tag, "/>") > -1 )
183
 
            result += "/>";
184
 
        else
185
 
            result += ">";
186
 
        //werror("Exchanged Tag: " + result+"\n");
187
 
    }
188
 
    else
189
 
        result = tag;
190
 
    
191
 
    return ({ result }); // nothing to be done
192
 
}
193
 
 
194
 
class UploadHTMLParser {
195
 
    object oContentHandle;
196
 
    void create(object ContentHandle) {
197
 
        oContentHandle = ContentHandle;
198
 
    }
199
 
    
200
 
    /**
201
 
     * Upload is finished and links can be exchanged. Callback function.
202
 
     *  
203
 
     * @param int id - id for the content.
204
 
     * @author Thomas Bopp (astra@upb.de) 
205
 
     */
206
 
    void finish_upload(int id) {
207
 
        mixed err = catch {
208
 
            sFilePosition = _FILEPATH->object_to_path(this_object());
209
 
            reset_links();
210
 
            oContentHandle->save_chunk(sContentCache);
211
 
            oContentHandle->save_chunk(0);
212
 
            sContentCache = 0;
213
 
            __blocked = false;
214
 
        };
215
 
        if ( err != 0 ) {
216
 
            _LOG("Error while uploading:\n"+PRINT_BT(err));
217
 
            oContentHandle->save_chunk(0);
218
 
        }
219
 
    }
220
 
 
221
 
    /**
222
 
     * Callback function to save a chunk of data received by the server.
223
 
     *  
224
 
     * @param string chunk - the received chunk.
225
 
     * @author Thomas Bopp (astra@upb.de) 
226
 
     */
227
 
    void save_chunk(string chunk) {
228
 
        string _chunk;
229
 
        if ( objectp(oParser) ) {
230
 
            if ( !stringp(chunk) ) {
231
 
                oParser->finish();
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;
237
 
                }
238
 
                destruct(oParser);
239
 
                //finish_upload(get_object_id());
240
 
                oContentHandle->save_chunk(0);
241
 
                return;
242
 
            }
243
 
            else {
244
 
                oParser->feed(chunk, 1);
245
 
                _chunk = oParser->read();
246
 
            }
247
 
        }
248
 
        else
249
 
            _chunk = chunk;
250
 
        
251
 
        if ( stringp(_chunk) ) {
252
 
            oContentHandle->save_chunk(_chunk);
253
 
            sContentCache += _chunk;
254
 
        }
255
 
        else
256
 
            oContentHandle->save_chunk(0);
257
 
    }
258
 
 
259
 
}
260
 
 
261
 
/**
262
 
 * Function to start an upload. Returns the save_chunk function.
263
 
 *  
264
 
 * @param int content_size the size of the content.
265
 
 * @return upload function.
266
 
 */
267
 
function receive_content(int content_size)
268
 
{
269
 
    object obj = CALLER;
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();
274
 
    
275
 
    try_event(EVENT_UPLOAD, obj, content_size);
276
 
    
277
 
    sContentCache = "";
278
 
    if ( objectp(oEnvironment) && 
279
 
         oEnvironment->query_attribute(CONT_EXCHANGE_LINKS) == 1 ) 
280
 
    {
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;
288
 
        reset_links();
289
 
    }
290
 
 
291
 
    // duplicate object with old content id
292
 
    int version = do_query_attribute(DOC_VERSION);
293
 
    if ( !version )
294
 
      version = 1;
295
 
    else {
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) )
301
 
        versions = ([ ]);
302
 
      versions[version] = oldversion;
303
 
      oldversion->set_acquire(this());
304
 
 
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));
309
 
 
310
 
      version++;
311
 
      do_set_attribute(DOC_VERSIONS, versions);
312
 
    }
313
 
    do_set_attribute(DOC_VERSION, version);
314
 
 
315
 
    do_set_attribute(DOC_LAST_MODIFIED, time());
316
 
    do_set_attribute(DOC_USER_MODIFIED, this_user());
317
 
    
318
 
    object oContentHandler = get_upload_handler(content_size);
319
 
    object oUploadHTMLParser = UploadHTMLParser(oContentHandler);
320
 
    return oUploadHTMLParser->save_chunk;
321
 
}
322
 
 
323
 
/**
324
 
 * Analyse a given path. This function actually looks suspicious (bugs???).
325
 
 *  
326
 
 * @param string p - the path to analyse
327
 
 * @return array of size 2 with - I give up.
328
 
 */
329
 
array(string) analyse_path(string p)
330
 
{
331
 
    array(string) tokens = p / "/";
332
 
    int sz = sizeof(tokens);
333
 
    if ( sz < 2 )
334
 
       return ({ p, "" }); 
335
 
    else if ( sz == 2 )
336
 
       return ({ tokens[0], tokens[1] });
337
 
    return ({ tokens[sz-1], tokens[0..sz]*"/" });
338
 
}
339
 
 
340
 
/**
341
 
 * Create a path inside steam which is a sequenz of containers.
342
 
 *  
343
 
 * @param string p - the path to create.
344
 
 * @return the container created last.
345
 
 */
346
 
static object create_path(string p)
347
 
{
348
 
   //MESSAGE("create_path("+p+")");
349
 
   if ( strlen(p) == 0 )
350
 
     return get_environment();
351
 
 
352
 
   array(string) tokens = p / "/"; 
353
 
   object cont = _ROOTROOM;
354
 
   object factory = _Server->get_factory(CLASS_CONTAINER);
355
 
 
356
 
   for ( int i = 0; i < sizeof(tokens)-1; i++) {
357
 
      object obj;
358
 
      if ( tokens[i] == "" ) 
359
 
          continue;
360
 
      obj = _FILEPATH->resolve_path(cont, tokens[i]);
361
 
      if ( !objectp(obj) ) {
362
 
          obj = factory->execute((["name":tokens[i],]));
363
 
          obj->move(cont);
364
 
      }
365
 
      //else MESSAGE("Found path in cont: " + tokens[i]);
366
 
      cont = obj;
367
 
   }
368
 
   //MESSAGE("Found:" + cont->get_identifier());
369
 
   return cont;
370
 
}
371
 
 
372
 
int exchange_ref(string link)
373
 
{
374
 
    object                     obj;
375
 
    string linkstr, position, type;
376
 
    int                       i, l;
377
 
 
378
 
    if ( !objectp(get_environment()) )
379
 
      return 0;
380
 
 
381
 
    link = replace(link, "\\", "/");
382
 
    if ( search(link, "get.pike") >= 0 || search(link, "navigate.pike") >= 0 )
383
 
      return 0;
384
 
    if ( sscanf(link, "%s://%s", type, linkstr) == 2 ) {
385
 
        add_extern_link(linkstr, type);
386
 
        return 0;
387
 
    }
388
 
    if ( sscanf(link, "mailto:%s", linkstr) == 1 )
389
 
    {
390
 
        add_extern_link(linkstr, "mailto");
391
 
        return 0;
392
 
    }
393
 
    if ( sscanf(lower_case(link), "javascript:%s", linkstr) == 1 ) 
394
 
      return 0;
395
 
    if ( sscanf(link, "%s#%s", linkstr, position) == 2 ) {
396
 
        link = linkstr;
397
 
    }
398
 
 
399
 
    if ( link == get_identifier() ) {
400
 
      add_local_link(this(), type, position);
401
 
      return 0;
402
 
    }
403
 
    link = combine_path(_FILEPATH->object_to_filename(get_environment()),
404
 
                        link);
405
 
    mixed err = catch {
406
 
        obj = _FILEPATH->path_to_object(link);
407
 
    };
408
 
    if ( !objectp(obj) )
409
 
      return 0;
410
 
 
411
 
    add_local_link(obj, type, position);
412
 
    return obj->get_object_id();
413
 
}
414
 
 
415
 
/**
416
 
 * this is the content callback function
417
 
 * in this case we have to read the whole content at once hmmm
418
 
 *  
419
 
 * @param int pos - the current position of sending.
420
 
 * @return chunk of content.
421
 
 * @author Thomas Bopp (astra@upb.de) 
422
 
 * @see 
423
 
 */
424
 
private static string
425
 
send_content_html(int pos)
426
 
{
427
 
    string result;
428
 
 
429
 
    if ( !stringp(sContentCache) )
430
 
        return 0; // finished
431
 
    
432
 
    if ( strlen(sContentCache) < DB_CHUNK_SIZE ) {
433
 
        result = copy_value(sContentCache);
434
 
        sContentCache = 0;
435
 
    }
436
 
    else {
437
 
        result = sContentCache[..DB_CHUNK_SIZE-1];
438
 
        sContentCache = sContentCache[DB_CHUNK_SIZE..];
439
 
    }
440
 
    return result;
441
 
}
442
 
 
443
 
/**
444
 
 * Get the callback function for content.
445
 
 *  
446
 
 * @param mapping vars - the variables from the web server.
447
 
 * @return content function.
448
 
 * @author Thomas Bopp (astra@upb.de) 
449
 
 */
450
 
function get_content_callback(mapping vars)
451
 
{
452
 
    object caller = CALLER;
453
 
    // todo: need to re-exchange links (possible)
454
 
    string content = get_content();
455
 
    if ( !mappingp(vars) )
456
 
      vars = ([ ]);
457
 
    vars->fp = _FILEPATH;
458
 
    vars->env = get_environment();
459
 
    mapping tags = ([ 
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")),
464
 
    ]);
465
 
    if ( !vars->raw ) {
466
 
      string encoding = do_query_attribute(DOC_ENCODING);
467
 
 
468
 
      if ( stringp(encoding) ) {
469
 
        encoding = lower_case(encoding);
470
 
      }
471
 
      //sContentCache = htmllib.parse_rxml(content, vars, tags, encoding);
472
 
      sContentCache = content; // parse rxml now ???
473
 
      __size = strlen(sContentCache);
474
 
    }
475
 
    else {
476
 
      sContentCache = content;
477
 
      __size = strlen(content);
478
 
    }
479
 
    return send_content_html;
480
 
}
481
 
 
482
 
/**
483
 
 * Return mapping with save data used by _Database.
484
 
 *  
485
 
 * @return all the links.
486
 
 * @author Thomas Bopp (astra@upb.de) 
487
 
 */
488
 
mixed
489
 
store_links() 
490
 
{
491
 
    if ( CALLER != _Database ) 
492
 
        THROW("Caller is not Database !", E_ACCESS);
493
 
    return ([ "Links": mLinks, ]);
494
 
}
495
 
 
496
 
/**
497
 
 * Restore the saved link data. This is called by database and
498
 
 * sets the Links mapping again.
499
 
 *  
500
 
 * @param mixed data - saved data.
501
 
 * @author Thomas Bopp (astra@upb.de) 
502
 
 */
503
 
void restore_links(mixed data)
504
 
{
505
 
    if (CALLER != _Database ) THROW("Caller is not Database !", E_ACCESS);
506
 
    mLinks = data["Links"];
507
 
}
508
 
 
509
 
/**
510
 
 * Add a local link.
511
 
 *  
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) 
516
 
 */
517
 
static void add_local_link(object o, string type, string position)
518
 
{
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 ]);
523
 
    else {
524
 
        if ( zero_type(mLinks[o][position]) )
525
 
            mLinks[o][position] = 1;
526
 
        else
527
 
            mLinks[o][position]++;
528
 
    }
529
 
    o->add_reference(this());
530
 
    require_save(STORE_HTMLLINK);
531
 
}
532
 
 
533
 
/**
534
 
 * Get an array of links pointing to local(steam) objects.
535
 
 *  
536
 
 * @return array of link objects.
537
 
 */
538
 
array get_local_links()
539
 
{
540
 
    array result = ({ });
541
 
    array index = indices(mLinks);
542
 
 
543
 
    foreach(index, mixed idx) {
544
 
        if ( objectp(idx) )
545
 
            result += ({ idx });
546
 
    }
547
 
    return result;
548
 
}
549
 
 
550
 
/**
551
 
 * Add an extern link to some URL.
552
 
 *  
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) 
556
 
 */
557
 
static void add_extern_link(string url, string type)
558
 
{
559
 
    if ( zero_type(mLinks[url]) )
560
 
        mLinks[url] = 1;
561
 
    else
562
 
        mLinks[url]++;
563
 
    require_save(STORE_HTMLLINK);
564
 
        
565
 
}
566
 
 
567
 
/**
568
 
 * an object was deleted and so the link to this object is outdated !
569
 
 *  
570
 
 * @author Thomas Bopp (astra@upb.de) 
571
 
 */
572
 
void removed_link()
573
 
{
574
 
    object link = CALLER->this();
575
 
    object creator = get_creator();
576
 
    run_event(EVENT_REF_GONE, link, creator);
577
 
}
578
 
 
579
 
 
580
 
/**
581
 
 * Reset all saved link data.
582
 
 *  
583
 
 * @author Thomas Bopp (astra@upb.de) 
584
 
 */
585
 
static void reset_links()
586
 
{
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()));
592
 
            }
593
 
        }
594
 
    }
595
 
    mLinks = ([ ]);
596
 
}
597
 
 
598
 
/**
599
 
 * Get a copy of the Links mapping.
600
 
 *  
601
 
 * @return copied link mapping.
602
 
 * @author Thomas Bopp (astra@upb.de) 
603
 
 */
604
 
mapping get_links()
605
 
{
606
 
    return copy_value(mLinks);
607
 
}
608
 
 
609
 
 
610
 
/**
611
 
 * Get the object class which is CLASS_DOCHTML of course.
612
 
 *  
613
 
 * @return the object class.
614
 
 * @author Thomas Bopp (astra@upb.de) 
615
 
 */
616
 
int
617
 
get_object_class()
618
 
{
619
 
    return ::get_object_class() | CLASS_DOCHTML;
620
 
}
621
 
 
622
 
/**
623
 
 * Get the size of the content which is the size of the document
624
 
 * with exchanged links.
625
 
 *  
626
 
 * @return the content size.
627
 
 * @author Thomas Bopp (astra@upb.de) 
628
 
 */
629
 
int get_content_size()
630
 
{
631
 
    return (__size > 0 ? __size : ::get_content_size());
632
 
}
633
 
 
634
 
 
635
 
void test()
636
 
{
637
 
  // todo: funktionen hinzu zum testen von create_path() und links austauschen
638
 
  ::test();
639
 
}