source: branches/2.2/phpgwapi/inc/class.vfs_dav.inc.php @ 3862

Revision 3862, 74.9 KB checked in by alexandrecorreia, 13 years ago (diff)

Ticket #000 - 0000000000000000000000000000000000000000000000

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2
3
4
5
6
7  /**************************************************************************\
8  * eGroupWare API - VFS                                                     *
9  * This file written by Jason Wies (Zone) <zone@phpgroupware.org>           *
10  * This class handles file/dir access for eGroupWare                        *
11  * Copyright (C) 2001-2003 Jason Wies, Jonathon Sim                         *
12  * -------------------------------------------------------------------------*
13  * This library is part of the eGroupWare API                               *
14  * http://www.egroupware.org/api                                            *
15  * ------------------------------------------------------------------------ *
16  * This library is free software; you can redistribute it and/or modify it  *
17  * under the terms of the GNU Lesser General Public License as published by *
18  * the Free Software Foundation; either version 2.1 of the License,         *
19  * or any later version.                                                    *
20  * This library is distributed in the hope that it will be useful, but      *
21  * WITHOUT ANY WARRANTY; without even the implied warranty of               *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
23  * See the GNU Lesser General Public License for more details.              *
24  * You should have received a copy of the GNU Lesser General Public License *
25  * along with this library; if not, write to the Free Software Foundation,  *
26  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA            *
27  \**************************************************************************/
28
29
30        /*Different aspects of debugging. DEBUG enables debug output for this class
31        DEBUG_SQL enables some SQL debugging.  DEBUG_DAV enables (LOTS) of debugging inside
32        the HTTP class
33        */
34        define ('DEBUG', 0);
35        define ('TRACE', 0);//This generates a whole lotta output
36        define ('DEBUG_SQL', 0);
37        define ('DEBUG_DAV', 0);
38
39        class vfs
40        {
41                var $basedir;
42                var $fakebase;
43                var $relative;
44                var $working_id;
45                var $working_lid;
46                var $attributes;
47                var $override_acl;
48                var $linked_dirs;
49                var $meta_types;
50                var $now;
51                var $override_locks;
52
53                //These are DAV-native properties that have different names in VFS
54                var $vfs_property_map = array(
55                        'creationdate' => 'created',
56                        'getlastmodified' => 'modified',
57                        'getcontentlength' => 'size',
58                        'getcontenttype' => 'mime_type',
59                        'description' => 'comment',
60                        'creator_id' => 'createdby_id',
61                        'contributor_id' => 'modifiedby_id',
62                        'publisher_id' => 'owner_id'
63                );
64               
65                /*!
66                @function vfs
67                @abstract constructor, sets up variables
68                */
69
70                function vfs ()
71                {
72                        $this->basedir = $GLOBALS['phpgw_info']['server']['files_dir'];
73                        $this->fakebase = '/home';
74                        $this->working_id = $GLOBALS['phpgw_info']['user']['account_id'];
75                        $this->working_lid = $GLOBALS['phpgw']->accounts->id2name($this->working_id);
76                        $this->now = date ('Y-m-d');
77                        $this->override_acl = 0;
78                        /*
79                           File/dir attributes, each corresponding to a database field.  Useful for use in loops
80                           If an attribute was added to the table, add it here and possibly add it to
81                           set_attributes ()
82
83                           set_attributes now uses this array().   07-Dec-01 skeeter
84                        */
85
86                        $this->attributes = array(
87                                'file_id',
88                                'owner_id',
89                                'createdby_id',
90                                'modifiedby_id',
91                                'created',
92                                'modified',
93                                'size',
94                                'mime_type',
95                                'deleteable',
96                                'comment',
97                                'app',
98                                'directory',
99                                'name',
100                                'link_directory',
101                                'link_name',
102                                'version'
103                        );
104
105                        /*
106                           These are stored in the MIME-type field and should normally be ignored.
107                           Adding a type here will ensure it is normally ignored, but you will have to
108                           explicitly add it to acl_check (), and to any other SELECT's in this file
109                        */
110
111                        $this->meta_types = array ('journal', 'journal-deleted');
112
113                        /* We store the linked directories in an array now, so we don't have to make the SQL call again */
114                        if ($GLOBALS['phpgw_info']['server']['db_type']=='mssql'
115                                || $GLOBALS['phpgw_info']['server']['db_type']=='sybase')
116                        {
117                                $query = $GLOBALS['phpgw']->db->query ("SELECT directory, name, link_directory, link_name FROM phpgw_vfs WHERE CONVERT(varchar,link_directory) != '' AND CONVERT(varchar,link_name) != ''" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__,__FILE__);
118                        }
119                        else
120                        {
121                                $query = $GLOBALS['phpgw']->db->query ("SELECT directory, name, link_directory, link_name FROM phpgw_vfs WHERE (link_directory IS NOT NULL or link_directory != '') AND (link_name IS NOT NULL or link_name != '')" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__,__FILE__);
122                        }
123
124                        $this->linked_dirs = array ();
125                        while ($GLOBALS['phpgw']->db->next_record ())
126                        {
127                                $this->linked_dirs[] = $GLOBALS['phpgw']->db->Record;
128                        }
129
130                       
131                        $this->repository = $GLOBALS['phpgw_info']['server']['files_dir'];
132                        $this->dav_user=$GLOBALS['phpgw_info']['user']['userid'];
133                        $this->dav_pwd=$GLOBALS['phpgw_info']['user']['passwd'];
134                        $parsed_url = parse_url($this->repository);
135                        $this->dav_host=$parsed_url['host'];
136                        $this->dav_port=@isset($parsed_url['port']) ? $parsed_url['port'] : 80;
137
138                        $this->dav_client = CreateObject('phpgwapi.http_dav_client');
139                        $this->dav_client->set_credentials($this->dav_user,$this->dav_pwd);
140                        $this->dav_client->set_attributes($this->attributes,$this->vfs_property_map);
141                        $result = $this->dav_client->connect($this->dav_host,$this->dav_port);
142                        if (DEBUG_DAV)
143                        {
144                                echo '<b>DAV client debugging enabled!</b>';
145                                $this->dav_client->set_debug(DBGTRACE|DBGINDATA|DBGOUTDATA|DBGSOCK|DBGLOW);
146                        }
147                        if (!$result)
148                        {
149                                echo '<h2>Cannot connect to the file repository server!</h2>';
150                                die($this->dav_client->get_body());
151                        }
152                        //determine the supported DAV features
153/*                      $features = $this->dav_client->dav_features('http://'.$this->dav_host);
154                        if (!$features || ! in_array( '1', $features) )
155                        {
156                                die("Error :: The specified file repository: $this->dav_host doesn't appear to support WebDAV! ");
157                       
158                        }
159*/     
160                        //Reload the overriden_locks
161                        $app = $GLOBALS['phpgw_info']['flags']['currentapp'];
162                        $session_data = base64_decode($GLOBALS['phpgw']->session->appsession ('vfs_dav',$app));
163                        $this->override_locks = array();
164                        if ($session_data)
165                        {
166                                $locks = explode('\n', $session_data); 
167                                foreach ($locks as $lock)
168                                {
169                                        $lockdata = explode(';', $lock);
170                                        $name = $lockdata[0];
171                                        $token = $lockdata[1];
172                                        $this->override_locks[$name] = $token;
173                                }
174                        }
175
176                                register_shutdown_function(array(&$this, 'vfs_umount'));
177                                $this->debug('Constructed with debug enabled');
178                       
179                }
180
181                //TODO:  Get rid of this
182                //A quick, temporary debug output function
183                function debug($info) {
184                        if (DEBUG)
185                        {
186                                echo '<b> vfs_sql_dav debug:<em> ';
187                                if (is_array($info))
188                                {
189                                        print_r($info);
190                                }
191                                else
192                                {
193                                        echo $info;
194                                }
195                                echo '</em></b><br>';
196                        }
197                }
198
199                /*!
200                @function dav_path
201                @abstract Apaches mod_dav in particular requires that the path sent in a dav request NOT be a URI
202                */
203                function dav_path($uri) {
204                        //$this->debug('DAV path');
205                        $parsed = parse_url($uri);
206                        return $parsed['path'];
207                }
208
209                /*!
210                @function glue_url
211                @abstract glues a parsed url (ie parsed using PHP's parse_url) back
212                        together
213                @param $url     The parsed url (its an array)
214                */
215                function glue_url ($url){
216                        if (!is_array($url))
217                        {
218                                return false;
219                        }
220                        // scheme
221                        $uri = (!empty($url['scheme'])) ? $url['scheme'].'://' : '';
222                        // user & pass
223                        if (!empty($url['user']))
224                        {
225                                $uri .= $url['user'];
226                                if (!empty($url['pass']))
227                                {
228                                        $uri .=':'.$url['pass'];
229                                }
230                                $uri .='@';
231                        }
232                        // host
233                        $uri .= $url['host'];
234                        // port
235                        $port = (!empty($url['port'])) ? ':'.$url['port'] : '';
236                        $uri .= $port;
237                        // path
238                        $uri .= $url['path'];
239                        // fragment or query
240                        if (isset($url['fragment']))
241                        {
242                                $uri .= '#'.$url['fragment'];
243                        } elseif (isset($url['query']))
244                        {
245                                $uri .= '?'.$url['query'];
246                        }
247                        return $uri;
248                }
249
250                function dav_host($uri) {
251                        //$this->debug('DAV path');
252                        $parsed = parse_url($uri);
253                        $parsed['path'] = '';
254                        $host = $this->glue_url($parsed);
255                        return $host;
256                }
257
258                function vfs_umount()
259                {
260                        $this->dav_client->disconnect();
261                }
262
263
264                /*!
265                @function set_relative
266                @abstract Set path relativity
267                @param mask Relative bitmask (see RELATIVE_ defines)
268                */
269                function set_relative ($data)
270                {
271                        if (!is_array ($data))
272                        {
273                                $data = array ();
274                        }
275
276                        if (!$data['mask'])
277                        {
278                                unset ($this->relative);
279                        }
280                        else
281                        {
282                                $this->relative = $data['mask'];
283                        }
284                }
285
286                /*!
287                @function get_relative
288                @abstract Return relativity bitmask
289                @discussion Returns relativity bitmask, or the default of "completely relative" if unset
290                */
291                function get_relative ()
292                {
293                        if (isset ($this->relative) && $this->relative)
294                        {
295                                return $this->relative;
296                        }
297                        else
298                        {
299                                return RELATIVE_ALL;
300                        }
301                }
302
303                /*!
304                @function sanitize
305                @abstract Removes leading .'s from 'string'
306                @discussion You should not pass all filenames through sanitize () unless you plan on rejecting
307                                .files.  Instead, pass the name through securitycheck () first, and if it fails,
308                                pass it through sanitize
309                @param string string to sanitize
310                @result $string 'string' without it's leading .'s
311                */
312                function sanitize ($data)
313                {
314                        if (!is_array ($data))
315                        {
316                                $data = array ();
317                        }
318
319                        /* We use path_parts () just to parse the string, not translate paths */
320                        $p = $this->path_parts (array(
321                                        'string' => $data['string'],
322                                        'relatives' => array (RELATIVE_NONE)
323                                )
324                        );
325
326                        return (ereg_replace ('^\.+', '', $p->fake_name));
327                }
328
329                /*!
330                @function securitycheck
331                @abstract Security check function
332                @discussion Checks for basic violations such as ..
333                                If securitycheck () fails, run your string through vfs->sanitize ()
334                @param string string to check security of
335                @result Boolean True/False.  True means secure, False means insecure
336                */
337                function securitycheck ($data)
338                {
339                        if (!is_array ($data))
340                        {
341                                $data = array ();
342                        }
343
344                        if (substr ($data['string'], 0, 1) == "\\" || strstr ($data['string'], "..") || strstr ($data['string'], "\\..") || strstr ($data['string'], ".\\."))
345                        {
346                                return False;
347                        }
348                        else
349                        {
350                                return True;
351                        }
352                }
353
354                /*!
355                @function db_clean
356                @abstract Clean 'string' for use in database queries
357                @param string String to clean
358                @result Cleaned version of 'string'
359                */
360                function db_clean ($data)
361                {
362                        if (!is_array ($data))
363                        {
364                                $data = array ();
365                        }
366
367                        $string = ereg_replace ("'", "\'", $data['string']);
368
369                        return $string;
370                }
371
372                /*!
373                @function extra_sql
374                @abstract Return extra SQL code that should be appended to certain queries
375                @param query_type The type of query to get extra SQL code for, in the form of a VFS_SQL define
376                @result Extra SQL code
377                */
378                function extra_sql ($data)
379                { //This is purely for SQL
380                        return '';
381                }
382
383                /*!
384                @function add_journal
385                @abstract Add a journal entry after (or before) completing an operation,
386                          and increment the version number.  This function should be used internally only
387                @discussion Note that state_one and state_two are ignored for some VFS_OPERATION's, for others
388                            they are required.  They are ignored for any "custom" operation
389                            The two operations that require state_two:
390                            operation                   state_two
391                            VFS_OPERATION_COPIED        fake_full_path of copied to
392                            VFS_OPERATION_MOVED         fake_full_path of moved to
393
394                            If deleting, you must call add_journal () before you delete the entry from the database
395                @param string File or directory to add entry for
396                @param relatives Relativity array
397                @param operation The operation that was performed.  Either a VFS_OPERATION define or
398                                  a non-integer descriptive text string
399                @param state_one The first "state" of the file or directory.  Can be a file name, size,
400                                  location, whatever is appropriate for the specific operation
401                @param state_two The second "state" of the file or directory
402                @param incversion Boolean True/False.  Increment the version for the file?  Note that this is
403                                   handled automatically for the VFS_OPERATION defines.
404                                   i.e. VFS_OPERATION_EDITED would increment the version, VFS_OPERATION_COPIED
405                                   would not
406                @result Boolean True/False
407                */
408                function add_journal ($data) {
409                //The journalling dont work :(  Ideally this will become "versioning"
410                        return True;
411                }
412
413
414                /*!
415                @function flush_journal
416                @abstract Flush journal entries for $string.  Used before adding $string
417                @discussion flush_journal () is an internal function and should be called from add_journal () only
418                @param string File/directory to flush journal entries of
419                @param relatives Realtivity array
420                @param deleteall Delete all types of journal entries, including the active Create entry.
421                                  Normally you only want to delete the Create entry when replacing the file
422                                  Note that this option does not effect $deleteonly
423                @param deletedonly Only flush 'journal-deleted' entries (created when $string was deleted)
424                @result Boolean True/False
425                */
426                function flush_journal ($data)
427                {
428                        return True;
429                }
430
431
432                /*!
433                @function get_journal
434                @abstract Retrieve journal entries for $string
435                @param string File/directory to retrieve journal entries of
436                @param relatives Relativity array
437                @param type 0/False = any, 1 = 'journal', 2 = 'journal-deleted'
438                @result Array of arrays of journal entries
439                */
440                function get_journal ($data)
441                {
442                        return array();
443                }
444
445                /*!
446                @function path_parts
447                @abstract take a real or fake pathname and return an array of its component parts
448                @param string full real or fake path
449                @param relatives Relativity array
450                @param object True returns an object instead of an array
451                @param nolinks Don't check for links (made with make_link ()).  Used internally to prevent recursion
452                @result $rarray/$robject Array or object containing the fake and real component parts of the path
453                @discussion Returned values are:
454                                mask
455                                outside
456                                fake_full_path
457                                fake_leading_dirs
458                                fake_extra_path         BROKEN
459                                fake_name
460                                real_full_path
461                                real_leading_dirs
462                                real_extra_path         BROKEN
463                                real_name
464                                fake_full_path_clean
465                                fake_leading_dirs_clean
466                                fake_extra_path_clean   BROKEN
467                                fake_name_clean
468                                real_full_path_clean
469                                real_leading_dirs_clean
470                                real_extra_path_clean   BROKEN
471                                real_name_clean
472                                real_uri
473                        "clean" values are run through vfs->db_clean () and
474                        are safe for use in SQL queries that use key='value'
475                        They should be used ONLY for SQL queries, so are used
476                        mostly internally
477                        mask is either RELATIVE_NONE or RELATIVE_NONE|VFS_REAL,
478                        and is used internally
479                        outside is boolean, True if 'relatives' contains VFS_REAL
480                */
481                function path_parts ($data)
482                {
483                        $default_values = array
484                                (
485                                        'relatives'     => array (RELATIVE_CURRENT),
486                                        'object'        => True,
487                                        'nolinks'       => False
488                                );
489
490                        $data = array_merge ($this->default_values ($data, $default_values), $data);
491
492                        $sep = SEP;
493
494                        $rarray['mask'] = RELATIVE_NONE;
495
496                        if (!($data['relatives'][0] & VFS_REAL))
497                        {
498                                $rarray['outside'] = False;
499                                $fake = True;
500                        }
501                        else
502                        {
503                                $rarray['outside'] = True;
504                                $rarray['mask'] |= VFS_REAL;
505                        }
506
507                        $string = $this->getabsolutepath (array(
508                                        'string'        => $data['string'],
509                                        'mask'  => array ($data['relatives'][0]),
510                                        'fake'  => $fake
511                                )
512                        );
513
514                        if ($fake)
515                        {
516                                $base_sep = '/';
517                                $base = '/';
518
519                                $opp_base = $this->basedir . $sep;
520
521                                $rarray['fake_full_path'] = $string;
522                        }
523                        else
524                        {
525                                $base_sep = $sep;
526                                if (ereg ("^$this->basedir" . $sep, $string))
527                                {
528                                        $base = $this->basedir . $sep;
529                                }
530                                else
531                                {
532                                        $base = $sep;
533                                }
534
535                                $opp_base = '/';
536                                $rarray['real_full_url'] = $string;
537                                $rarray['real_full_path'] = $this->dav_path($string);
538                        }
539
540                        /* This is needed because of substr's handling of negative lengths */
541                        $baselen = strlen ($base);
542                        $lastslashpos = strrpos ($string, $base_sep);
543                        $lastslashpos < $baselen ? $length = 0 : $length = $lastslashpos - $baselen;
544
545                        $extra_path = $rarray['fake_extra_path'] = $rarray['real_extra_path'] = substr ($string, strlen ($base), $length);
546                        $name = $rarray['fake_name'] = $rarray['real_name'] = substr ($string, strrpos ($string, $base_sep) + 1);
547
548                        if ($fake)
549                        {
550                                $rarray['real_extra_path'] ? $dispsep = $sep : $dispsep = '';
551                                $rarray['real_full_url'] = $opp_base . $rarray['real_extra_path'] . $dispsep . $rarray['real_name'];
552                                $rarray['real_full_path'] = $this->dav_path($rarray['real_full_url']);
553                                if ($extra_path)
554                                {
555                                        $rarray['fake_leading_dirs'] = $base . $extra_path;
556                                        $rarray['real_leading_dirs'] = $this->dav_path($opp_base . $extra_path);
557                                }
558                                elseif (strrpos ($rarray['fake_full_path'], $sep) == 0)
559                                {
560                                        /* If there is only one $sep in the path, we don't want to strip it off */
561                                        $rarray['fake_leading_dirs'] = $sep;
562                                        $rarray['real_leading_dirs'] = $this->dav_path( substr ($opp_base, 0, strlen ($opp_base) - 1));
563                                }
564                                else
565                                {
566                                        /* These strip the ending / */
567                                        $rarray['fake_leading_dirs'] = substr ($base, 0, strlen ($base) - 1);
568                                        $rarray['real_leading_dirs'] = $this->dav_path( substr ($opp_base, 0, strlen ($opp_base) - 1));
569                                }
570                        }
571                        else
572                        {
573                                $rarray['fake_full_path'] = $opp_base . $rarray['fake_extra_path'] . '/' . $rarray['fake_name'];
574                                if ($extra_path)
575                                {
576                                        $rarray['fake_leading_dirs'] = $opp_base . $extra_path;
577                                        $rarray['real_leading_dirs'] = $this->dav_path($base . $extra_path);
578                                }
579                                else
580                                {
581                                        $rarray['fake_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
582                                        $rarray['real_leading_dirs'] = $this->dav_path(substr ($base, 0, strlen ($base) - 1));
583                                }
584                        }
585
586                        /* We check for linked dirs made with make_link ().  This could be better, but it works */
587                        if (!$data['nolinks'])
588                        {
589                                reset ($this->linked_dirs);
590                                while (list ($num, $link_info) = each ($this->linked_dirs))
591                                {
592                                        if (ereg ("^$link_info[directory]/$link_info[name](/|$)", $rarray['fake_full_path']))
593                                        {
594                                                $rarray['real_full_path'] = ereg_replace ("^$this->basedir", '', $rarray['real_full_path']);
595                                                $rarray['real_full_path'] = ereg_replace ("^$link_info[directory]" . SEP . "$link_info[name]", $link_info['link_directory'] . SEP . $link_info['link_name'], $rarray['real_full_path']);
596
597                                                $p = $this->path_parts (array(
598                                                                'string'        => $rarray['real_full_path'],
599                                                                'relatives'     => array (RELATIVE_NONE|VFS_REAL),
600                                                                'nolinks'       => True
601                                                        )
602                                                );
603
604                                                $rarray['real_leading_dirs'] = $this->dav_path($p->real_leading_dirs);
605                                                $rarray['real_extra_path'] = $p->real_extra_path;
606                                                $rarray['real_name'] = $p->real_name;
607                                        }
608                                }
609                        }
610                       
611                        /*
612                                Create the 'real_auth_url', which includes the user and
613                                password (for the view method to redirect you there)
614                        */
615
616                        $parsed_url = parse_url($rarray['real_full_url']);
617                        $parsed_url['user'] = $this->dav_user;
618//                      $parsed_url['pass'] = $this->dav_pwd;
619                        $rarray['real_full_auth_url'] = $this->glue_url($parsed_url);
620                                       
621                        $parsed_url = parse_url($rarray['real_full_url']);
622                        $parsed_url['scheme'] = 'https';
623                        $parsed_url['user'] = $this->dav_user;
624                        $rarray['real_full_secure_url'] = $this->glue_url($parsed_url);
625                       
626                       
627                        /*
628                           We have to count it before because new keys will be added,
629                           which would create an endless loop
630                        */
631                        $count = count ($rarray);
632                        reset ($rarray);
633                        for ($i = 0; (list ($key, $value) = each ($rarray)) && $i != $count; $i++)
634                        {
635                                $rarray[$key . '_clean'] = $this->db_clean (array ('string' => $value));
636                        }
637
638                        if ($data['object'])
639                        {
640                                $robject = new path_class;
641
642                                reset ($rarray);
643                                while (list ($key, $value) = each ($rarray))
644                                {
645                                        $robject->$key = $value;
646                                }
647                        }
648
649/*
650                        echo "<br>fake_full_path: $rarray[fake_full_path]
651                                <br>fake_leading_dirs: $rarray[fake_leading_dirs]
652                                <br>fake_extra_path: $rarray[fake_extra_path]
653                                <br>fake_name: $rarray[fake_name]
654                                <br>real_full_path: $rarray[real_full_path]
655                                <br>real_full_url: $rarray[real_full_url]
656                                <br>real_leading_dirs: $rarray[real_leading_dirs]
657                                <br>real_extra_path: $rarray[real_extra_path]
658                                <br>real_name: $rarray[real_name]";
659*/
660
661                        if ($data['object'])
662                        {
663                                return ($robject);
664                        }
665                        else
666                        {
667                                return ($rarray);
668                        }
669                }
670
671                /*!
672                @function getabsolutepath
673                @abstract get the absolute path
674                @param string defaults to False, directory/file to get path of, relative to relatives[0]
675                @param mask Relativity bitmask (see RELATIVE_ defines).  RELATIVE_CURRENT means use $this->relative
676                @param fake Returns the "fake" path, ie /home/user/dir/file (not always possible.  use path_parts () instead)
677                @result $basedir Full fake or real path
678                */
679                function getabsolutepath ($data)
680                {
681                        $default_values = array
682                                (
683                                        'string'        => False,
684                                        'mask'  => array (RELATIVE_CURRENT),
685                                        'fake'  => True
686                                );
687
688                        $data = array_merge ($this->default_values ($data, $default_values), $data);
689
690                        $currentdir = $this->pwd (False);
691
692                        /* If they supply just VFS_REAL, we assume they want current relativity */
693                        if ($data['mask'][0] == VFS_REAL)
694                        {
695                                $data['mask'][0] |= RELATIVE_CURRENT;
696                        }
697
698                        if (!$this->securitycheck (array(
699                                        'string'        => $data['string']
700                                ))
701                        )
702                        {
703                                return False;
704                        }
705
706                        if ($data['mask'][0] & RELATIVE_NONE)
707                        {
708                                return $data['string'];
709                        }
710
711                        if ($data['fake'])
712                        {
713                                $sep = '/';
714                        }
715                        else
716                        {
717                                $sep = SEP;
718                        }
719
720                        /* if RELATIVE_CURRENT, retrieve the current mask */
721                        if ($data['mask'][0] & RELATIVE_CURRENT)
722                        {
723                                $mask = $data['mask'][0];
724                                /* Respect any additional masks by re-adding them after retrieving the current mask*/
725                                $data['mask'][0] = $this->get_relative () + ($mask - RELATIVE_CURRENT);
726                        }
727
728                        if ($data['fake'])
729                        {
730                                $basedir = '/';
731                        }
732                        else
733                        {
734                                $basedir = $this->basedir . $sep;
735
736                                /* This allows all requests to use /'s */
737                                $data['string'] = preg_replace ("|/|", $sep, $data['string']);
738                        }
739
740                        if (($data['mask'][0] & RELATIVE_PATH) && $currentdir)
741                        {
742                                $basedir = $basedir . $currentdir . $sep;
743                        }
744                        elseif (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
745                        {
746                                $basedir = $basedir . $this->fakebase . $sep;
747                        }
748
749                        if ($data['mask'][0] & RELATIVE_CURR_USER)
750                        {
751                                $basedir = $basedir . $this->working_lid . $sep;
752                        }
753
754                        if (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
755                        {
756                                $basedir = $basedir . $GLOBALS['phpgw_info']['user']['account_lid'] . $sep;
757                        }
758
759                        if ($data['mask'][0] & RELATIVE_USER_APP)
760                        {
761                                $basedir = $basedir . "." . $GLOBALS['phpgw_info']['flags']['currentapp'] . $sep;
762                        }
763
764                        /* Don't add string if it's a /, just for aesthetics */
765                        if ($data['string'] && $data['string'] != $sep)
766                        {
767                                $basedir = $basedir . $data['string'];
768                        }
769
770                        /* Let's not return // */
771                        while (ereg ($sep . $sep, $basedir))
772                        {
773                                $basedir = ereg_replace ($sep . $sep, $sep, $basedir);
774                        }
775
776                        $basedir = ereg_replace ($sep . '$', '', $basedir);
777
778                        return $basedir;
779                }
780
781                /*!
782                @function acl_check
783                @abstract Check ACL access to $file for $GLOBALS['phpgw_info']["user"]["account_id"];
784                @param string File to check access of
785                @discussion To check the access for a file or directory, pass 'string'/'relatives'/'must_exist'.
786                                To check the access to another user or group, pass 'owner_id'.
787                                If 'owner_id' is present, we bypass checks on 'string'/'relatives'/'must_exist'
788                @param relatives Standard relativity array
789                @param operation Operation to check access to.  In the form of a PHPGW_ACL defines bitmask.  Default is read
790                @param owner_id Owner id to check access of (see discussion above)
791                @param must_exist Boolean.  Set to True if 'string' must exist.  Otherwise, we check the parent directory as well
792                @result Boolean.  True if access is ok, False otherwise
793                */
794                function acl_check ($data)
795                {
796                        return True;
797                        $default_values = array
798                                (
799                                        'relatives'     => array (RELATIVE_CURRENT),
800                                        'operation'     => PHPGW_ACL_READ,
801                                        'must_exist'    => False
802                                );
803
804                        $data = array_merge ($this->default_values ($data, $default_values), $data);
805
806                        /* Accommodate special situations */
807                        if ($this->override_acl || $data['relatives'][0] == RELATIVE_USER_APP)
808                        {
809                                return True;
810                        }
811
812                        if (!$data['owner_id'])
813                        {
814                                $p = $this->path_parts (array(
815                                                'string'        => $data['string'],
816                                                'relatives'     => array ($data['relatives'][0])
817                                        )
818                                );
819
820                                /* Temporary, until we get symlink type files set up */
821                                if ($p->outside)
822                                {
823                                        return True;
824                                }
825
826                                /* Read access is always allowed here, but nothing else is */
827                                if ($data['string'] == '/' || $data['string'] == $this->fakebase)
828                                {
829                                        if ($data['operation'] == PHPGW_ACL_READ)
830                                        {
831                                                return True;
832                                        }
833                                        else
834                                        {
835                                                return False;
836                                        }
837                                }
838
839                                /* If the file doesn't exist, we get ownership from the parent directory */
840                                if (!$this->file_exists (array(
841                                                'string'        => $p->fake_full_path,
842                                                'relatives'     => array ($p->mask)
843                                        ))
844                                )
845                                {
846                                        if ($data['must_exist'])
847                                        {
848                                                return False;
849                                        }
850
851                                        $data['string'] = $p->fake_leading_dirs;
852                                        $p2 = $this->path_parts (array(
853                                                        'string'        => $data['string'],
854                                                        'relatives'     => array ($p->mask)
855                                                )
856                                        );
857
858                                        if (!$this->file_exists (array(
859                                                        'string'        => $data['string'],
860                                                        'relatives'     => array ($p->mask)
861                                                ))
862                                        )
863                                        {
864                                                return False;
865                                        }
866                                }
867                                else
868                                {
869                                        $p2 = $p;
870                                }
871
872                                $file_info = $this->ls($data);
873                                $owner_id = $file_info['owner_id'];
874                        }
875                        else
876                        {
877                                $owner_id = $data['owner_id'];
878                        }
879
880                        /* This is correct.  The ACL currently doesn't handle undefined values correctly */
881                        if (!$owner_id)
882                        {
883                                $owner_id = 0;
884                        }
885
886                        $user_id = $GLOBALS['phpgw_info']['user']['account_id'];
887
888                        /* They always have access to their own files */
889                        if ($owner_id == $user_id)
890                        {
891                                return True;
892                        }
893
894                        /* Check if they're in the group */
895                        $memberships = $GLOBALS['phpgw']->accounts->membership ($user_id);
896
897                        if (is_array ($memberships))
898                        {
899                                reset ($memberships);
900                                while (list ($num, $group_array) = each ($memberships))
901                                {
902                                        if ($owner_id == $group_array['account_id'])
903                                        {
904                                                $group_ok = 1;
905                                                break;
906                                        }
907                                }
908                        }
909
910                        $acl = CreateObject ('phpgwapi.acl', $owner_id);
911                        $acl->account_id = $owner_id;
912                        $acl->read_repository ();
913
914                        $rights = $acl->get_rights ($user_id);
915
916                        /* Add privileges from the groups this user belongs to */
917                        if (is_array ($memberships))
918                        {
919                                reset ($memberships);
920                                while (list ($num, $group_array) = each ($memberships))
921                                {
922                                        $rights |= $acl->get_rights ($group_array['account_id']);
923                                }
924                        }
925
926                        if ($rights & $data['operation'])
927                        {
928                                return True;
929                        }
930                        elseif (!$rights && $group_ok)
931                        {
932                                $conf = CreateObject('phpgwapi.config', 'phpgwapi');
933                                $conf->read_repository();
934                                if ($conf->config_data['acl_default'] == 'grant')
935                                {
936                                        return True;
937                                }
938                                else
939                                {
940                                        return False;
941                                }
942                        }
943                        else
944                        {
945                                return False;
946                        }
947                }
948
949                /*!
950                @function cd
951                @abstract Change directory
952                @discussion To cd to the files root '/', use cd ('/', False, array (RELATIVE_NONE));
953                @param string default '/'.  directory to cd into.  if "/" and $relative is True, uses "/home/<working_lid>";
954                @param relative default True/relative means add target to current path, else pass $relative as mask to getabsolutepath()
955                @param relatives Relativity array
956                */
957                function cd ($data = '')
958                {
959                        if (!is_array ($data))
960                        {
961                                $noargs = 1;
962                                $data = array ();
963                        }
964
965                        $default_values = array
966                                (
967                                        'string'        => '/',
968                                        'relative'      => True,
969                                        'relatives'     => array (RELATIVE_CURRENT)
970                                );
971
972                        $data = array_merge ($this->default_values ($data, $default_values), $data);
973
974                        if ($data['relatives'][0] & VFS_REAL)
975                        {
976                                $sep = SEP;
977                        }
978                        else
979                        {
980                                $sep = '/';
981                        }
982
983                        if ($data['relative'] == 'relative' || $data['relative'] == True)
984                        {
985                                /* if 'string' is "/" and 'relative' is set, we cd to the user/group home dir */
986                                if ($data['string'] == '/')
987                                {
988                                        $data['relatives'][0] = RELATIVE_USER;
989                                        $basedir = $this->getabsolutepath (array(
990                                                        'string'        => False,
991                                                        'mask'  => array ($data['relatives'][0]),
992                                                        'fake'  => True
993                                                )
994                                        );
995                                }
996                                else
997                                {
998                                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
999                                        $basedir = $this->getabsolutepath (array(
1000                                                        'string'        => $currentdir . $sep . $data['string'],
1001                                                        'mask'  => array ($data['relatives'][0]),
1002                                                        'fake'  => True
1003                                                )
1004                                        );
1005                                }
1006                        }
1007                        else
1008                        {
1009                                $basedir = $this->getabsolutepath (array(
1010                                                'string'        => $data['string'],
1011                                                'mask'  => array ($data['relatives'][0])
1012                                        )
1013                                );
1014                        }
1015
1016                        $GLOBALS['phpgw']->session->appsession('vfs','',$basedir);
1017
1018                        return True;
1019                }
1020
1021                /*!
1022                @function pwd
1023                @abstract current working dir
1024                @param full default True returns full fake path, else just the extra dirs (false strips the leading /)
1025                @result $currentdir currentdir
1026                */
1027                function pwd ($data = '')
1028                {
1029                        $default_values = array
1030                                (
1031                                        'full'  => True
1032                                );
1033
1034                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1035
1036                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
1037
1038                        if (!$data['full'])
1039                        {
1040                                $currentdir = ereg_replace ("^/", '', $currentdir);
1041                        }
1042
1043                        if ($currentdir == '' && $data['full'])
1044                        {
1045                                $currentdir = '/';
1046                        }
1047
1048                        $currentdir = trim ($currentdir);
1049
1050                        return $currentdir;
1051                }
1052
1053                /*!
1054                @function read
1055                @abstract return file contents
1056                @param string filename
1057                @param relatives Relativity array
1058                @result $contents Contents of $file, or False if file cannot be read
1059                */
1060                function read ($data)
1061                {
1062
1063                        /*If the user really wants to 'view' the file in the browser, it
1064                        is much smarter simply to redirect them to the files web-accessable
1065                        url */
1066/*                      $app = $GLOBALS['phpgw_info']['flags']['currentapp'];
1067                        if ( ! $data['noview'] && ($app == 'phpwebhosting' || $app = 'filemanager' ))
1068                        {
1069                                $this->view($data);
1070                        }       
1071*/                     
1072                        if (!is_array ($data))
1073                        {
1074                                $data = array ();
1075                        }
1076
1077                        $default_values = array
1078                                (
1079                                        'relatives'     => array (RELATIVE_CURRENT)
1080                                );
1081
1082                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1083
1084                        $p = $this->path_parts (array(
1085                                        'string'        => $data['string'],
1086                                        'relatives'     => array ($data['relatives'][0])
1087                                )
1088                        );
1089
1090                        if (!$this->acl_check (array(
1091                                        'string'        => $p->fake_full_path,
1092                                        'relatives'     => array ($p->mask),
1093                                        'operation'     => PHPGW_ACL_READ
1094                                ))
1095                        )
1096                        {
1097                                return False;
1098                        }
1099                        if ($p->outside)
1100                        {
1101                                           
1102                            if (! $fp = fopen ($p->real_full_path, 'r'))
1103                            {
1104                                return False;
1105                            }
1106                            $size=filesize($p->real_full_path);
1107                            $buffer=fread($fp, $size);
1108                            fclose ($fp);
1109                                return $buffer;
1110                        }
1111                        else
1112                        {
1113                                $status=$this->dav_client->get($p->real_full_path);
1114        $this->debug($this->dav_client->get_headers());
1115       
1116                                if($status != 200) return False;
1117                                $contents=$this->dav_client->get_body();
1118        $this->debug('Read:returning contents.  Status:'.$status);
1119                                return $contents;
1120                        }
1121                }
1122               
1123                /*
1124                @function view
1125                @abstract Redirect the users browser to the file
1126                @param string filename
1127                @param relatives Relativity array
1128                @result None (doesnt return)
1129                @discussion In the case of WebDAV, the file is web-accessible.  So instead
1130                of reading it into memory and then dumping it back out again when someone
1131                views a file, it makes much more sense to simply redirect, which is what
1132                this method does (its only called when reading from the file in the file manager,
1133                when the variable "noview" isnt set to "true"
1134                */
1135                function view($data)
1136                {       
1137               
1138                        $default_values = array
1139                                (
1140                                        'relatives'     => array (RELATIVE_CURRENT)
1141                                );
1142                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1143                        $p = $this->path_parts (array(
1144                                        'string'        => $data['string'],
1145                                        'relatives'     => array ($data['relatives'][0])
1146                                )
1147                        );
1148                       
1149                        //Determine whether the repository supports SSL
1150                        $parsed_url = parse_url($this->repository);
1151                        if ($parsed_url['scheme']=='https')
1152                        {
1153                                header( 'Location: '.$p->real_full_secure_url, true );
1154                        }
1155                        else
1156                        {
1157                                header( 'Location: '.$p->real_full_auth_url, true );                   
1158                        }
1159                        exit();
1160
1161                }
1162               
1163                /*
1164                @function lock
1165                @abstract DAV (class 2) locking - sets an exclusive write lock
1166                @param string filename
1167                @param relatives Relativity array
1168                @result True if successfull
1169                */             
1170                function lock ($data)
1171                {
1172                        $default_values = array
1173                                (
1174                                        'relatives'     => array (RELATIVE_CURRENT),
1175                                        'timeout'       => 'infinity',
1176                                       
1177                                );
1178
1179                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1180
1181                        $p = $this->path_parts (array(
1182                                        'string'        => $data['string'],
1183                                        'relatives'     => array ($data['relatives'][0])
1184                                )
1185                        );             
1186                        return $this->dav_client->lock($p->real_full_url, $this->dav_user, 0, $data['timeout']);
1187
1188                }
1189                function lock_token ($data)
1190                {
1191                        $default_values = array
1192                                (
1193                                        'relatives'     => array (RELATIVE_CURRENT),
1194                                        'token' => ''
1195                                );
1196
1197                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1198                       
1199                        $ls_array = $GLOBALS['phpgw']->vfs->ls (array (
1200                        'string'        => $data['string'],
1201                        'relatives'     => $data['relatives']
1202                        )
1203                        );     
1204                         $lock = @end($ls_array[0]['locks']);
1205                         $token = @end($lock['lock_tokens']);
1206                         return $token['full_name'];
1207                }
1208               
1209               
1210                /*
1211                @function add_lock_override
1212                @abstract override a lock
1213                @param string filename
1214                @param relatives Relativity array
1215                @param token (optional) a token for the lock we want to override
1216                @result None
1217                @discussion locks are no good unless you can write to a file you yourself locked:
1218                to do this call add_lock_override with the lock token (or without it - it will
1219                find it itself, so long as there is only one).  lock_override info is stored in
1220                the groupware session, so it will persist between page loads, but will be lost
1221                when the browser is closed
1222                */     
1223                function add_lock_override($data)
1224                {
1225                        $default_values = array
1226                        (
1227                                'relatives'     => array (RELATIVE_CURRENT),
1228                                'token' => ''
1229                               
1230                        );
1231
1232                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1233                       
1234                        if (!strlen($data['token']))
1235                        {
1236                                $ls_array = $GLOBALS['phpgw']->vfs->ls (array (
1237                                'string'        => $data['string'],
1238                                'relatives'     => $data['relatives']
1239                                )
1240                                );     
1241                                 $lock = @end($ls_array[0]['locks']);
1242                                 $token_array = @end($lock['lock_tokens']);
1243                                 $token =  $token_array['full_name'];
1244                        }
1245                        else
1246                        {
1247                                $token = $data['token'];
1248                        }
1249                         
1250                        $p = $this->path_parts (array(
1251                                        'string'        => $data['string'],
1252                                        'relatives'     => array ($data['relatives'][0])
1253                                )
1254                        );             
1255                        $this->override_locks[$p->real_full_path] = $token;
1256                        $this->save_session();
1257                }
1258               
1259                /*
1260                @function remove_lock_override
1261                @abstract stops overriding a lock
1262                @param string filename
1263                @param relatives Relativity array
1264                @result None
1265                */     
1266                function remove_lock_override($data)
1267                {
1268                        $default_values = array
1269                        (
1270                                'relatives'     => array (RELATIVE_CURRENT)
1271                               
1272                        );
1273
1274                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1275                       
1276                        if (!strlen($data['token']))
1277                        {
1278                                $ls_array = $GLOBALS['phpgw']->vfs->ls (array (
1279                                'string'        => $data['string'],
1280                                'relatives'     => $data['relatives']
1281                                )
1282                                );     
1283                                 $lock = @end($ls_array[0]['locks']);
1284                                 $token_array = @end($lock['lock_tokens']);
1285                                 $token =  $token_array['full_name'];
1286                        }
1287                        else
1288                        {
1289                                $token = $data['token'];
1290                        }
1291                         
1292                        $p = $this->path_parts (array(
1293                                        'string'        => $data['string'],
1294                                        'relatives'     => array ($data['relatives'][0])
1295                                )
1296                        );             
1297                        unset($this->override_locks[$p->real_full_path]);
1298                        $this->save_session();
1299                }       
1300               
1301                /*
1302                @function unlock
1303                @abstract DAV (class 2) unlocking - unsets the specified lock
1304                @param string filename
1305                @param relatives Relativity array
1306                @param tocken   The token for the lock we wish to remove.
1307                @result True if successfull
1308                */             
1309                function unlock ($data, $token)
1310                {
1311                        $default_values = array
1312                                (
1313                                        'relatives'     => array (RELATIVE_CURRENT),
1314                                        'content'       => ''
1315                                );
1316
1317                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1318
1319                        $p = $this->path_parts (array(
1320                                        'string'        => $data['string'],
1321                                        'relatives'     => array ($data['relatives'][0])
1322                                )
1323                        );
1324                        $this->remove_lock_override (array(
1325                                        'string'        => $data['string'],
1326                                        'relatives'     => array ($data['relatives'][0])
1327                                )
1328                        );
1329                        return $this->dav_client->unlock($p->real_full_url, $token);
1330
1331
1332                }
1333               
1334                /*
1335                @function options
1336                @abstract Allows querying for optional features - esp optional DAV features
1337                like locking
1338                @param option   The option you want to test for.  Options include 'LOCKING'
1339                        'VIEW', 'VERSION-CONTROL (eventually) etc
1340                @result true if the specified option is supported
1341                @discussion This should really check the server.  Unfortunately the overhead of doing this
1342                in every VFS instance is unacceptable (it essentially doubles the time for any request). Ideally
1343                we would store these features in the session perhaps?
1344                */             
1345                function options($option)
1346                {
1347                        switch ($option)
1348                        {
1349                        case 'LOCKING':
1350                                return true;
1351                        case 'VIEW':
1352                                return true;
1353                        default:
1354                                return false;
1355                        }
1356                }
1357               
1358                /*!
1359                @function write
1360                @abstract write to a file
1361                @param string file name
1362                @param relatives Relativity array
1363                @param content content
1364                @result Boolean True/False
1365                */
1366                function write ($data)
1367                {
1368                        $default_values = array
1369                                (
1370                                        'relatives'     => array (RELATIVE_CURRENT),
1371                                        'content'       => ''
1372                                );
1373
1374                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1375
1376                        $p = $this->path_parts (array(
1377                                        'string'        => $data['string'],
1378                                        'relatives'     => array ($data['relatives'][0])
1379                                )
1380                        );
1381
1382                        if ($this->file_exists (array (
1383                                        'string'        => $data['string'],
1384                                        'relatives'     => array ($data['relatives'][0])
1385                                ))
1386                        )
1387                        {
1388                                $acl_operation = PHPGW_ACL_EDIT;
1389                                $journal_operation = VFS_OPERATION_EDITED;
1390                        }
1391                        else
1392                        {
1393                                $acl_operation = PHPGW_ACL_ADD;
1394                        }
1395
1396                        if (!$this->acl_check (array(
1397                                        'string'        => $p->fake_full_path,
1398                                        'relatives'     => array ($p->mask),
1399                                        'operation'     => $acl_operation
1400                                ))
1401                        )
1402                        {
1403                                return False;
1404                        }
1405
1406                        //umask(000);
1407
1408                        /*
1409                           If 'string' doesn't exist, touch () creates both the file and the database entry
1410                           If 'string' does exist, touch () sets the modification time and modified by
1411                        */
1412                        /*$this->touch (array(
1413                                        'string'        => $p->fake_full_path,
1414                                        'relatives'     => array ($p->mask)
1415                                )
1416                        );*/
1417                       
1418                        $size=strlen($data['content']);
1419                        if ($p->outside)
1420                        {                           
1421                            if (! $fp = fopen ($p->real_full_path, 'w'))
1422                            {
1423                                return False;
1424                            }
1425                            $result = fwrite($fp, $data['content']);
1426                            fclose ($fp);
1427                            return $result;
1428                        }
1429                        else
1430                        {
1431                                $token =  $this->override_locks[$p->real_full_path];
1432                                $status=$this->dav_client->put($p->real_full_path,$data['content'],$token);
1433$this->debug('Put complete,  status: '.$status);
1434                                if($status!=201 && $status!=204)
1435                                {
1436                                        return False;
1437                                }
1438                                else
1439                                {
1440                                        return True;
1441                                }
1442                        }
1443                }
1444
1445                /*!
1446                @function touch
1447                @abstract Create blank file $file or set the modification time and modified by of $file to current time and user
1448                @param string File to touch or set modifies
1449                @param relatives Relativity array
1450                @result Boolean True/False
1451                */
1452                function touch ($data)
1453                {
1454                        $default_values = array(
1455                                                'relatives'     => array (RELATIVE_CURRENT)
1456                                                );
1457                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1458
1459                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1460                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1461
1462                        $p = $this->path_parts (array(
1463                                                      'string'  => $data['string'],
1464                                                      'relatives'       => array ($data['relatives'][0])
1465                                                      )
1466                                                );
1467                        umask (000);
1468
1469                        /*
1470                           PHP's touch function will automatically decide whether to
1471                           create the file or set the modification time
1472                        */
1473                        if($p->outside)
1474                        {
1475                          return @touch($p->real_full_path);
1476                        }
1477                        elseif ($this->file_exists (array(
1478                                        'string'        => $p->fake_full_path,
1479                                        'relatives'     => array ($p->mask)
1480                                ))
1481                        )
1482                        {
1483                                $result =  $this->set_attributes (array(
1484                                                'string'        => $p->fake_full_path,
1485                                                'relatives'     => array ($p->mask),
1486                                                'attributes'    => array(
1487                                                                        'modifiedby_id' => $account_id,
1488                                                                        'modified' => $this->now
1489                                                )));
1490                        }
1491                        else
1492                        {
1493                                if (!$this->acl_check (array(
1494                                                'string'        => $p->fake_full_path,
1495                                                'relatives'     => array ($p->mask),
1496                                                'operation'     => PHPGW_ACL_ADD
1497                                        ))
1498                                ) return False;
1499                                $result = $this->write (array(
1500                                                      'string'  => $data['string'],
1501                                                      'relatives'       => array ($data['relatives'][0]),
1502                                                      'content' => ''
1503                                                      ));
1504                                $this->set_attributes(array(
1505                                        'string'        => $p->fake_full_path,
1506                                        'relatives'     => array ($p->mask),
1507                                        'attributes'    => array (
1508                                                                'createdby_id' => $account_id,
1509                                                                'created' => $this->now,
1510                                                                'app' => $currentapp
1511                                                        )));
1512                        }
1513
1514                        return ($result);
1515                }
1516
1517                /*!
1518                @function cp
1519                @abstract copy file
1520                @param from from file/directory
1521                @param to to file/directory
1522                @param relatives Relativity array
1523                @result boolean True/False
1524                */
1525                function cp ($data)
1526                {
1527                        $default_values = array
1528                                (
1529                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1530                                );
1531
1532                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1533
1534                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1535
1536                        $f = $this->path_parts (array(
1537                                        'string'        => $data['from'],
1538                                        'relatives'     => array ($data['relatives'][0])
1539                                )
1540                        );
1541
1542                        $t = $this->path_parts (array(
1543                                        'string'        => $data['to'],
1544                                        'relatives'     => array ($data['relatives'][1])
1545                                )
1546                        );
1547
1548                        if (!$this->acl_check (array(
1549                                        'string'        => $f->fake_full_path,
1550                                        'relatives'     => array ($f->mask),
1551                                        'operation'     => PHPGW_ACL_READ
1552                                ))
1553                        )
1554                        {
1555                                return False;
1556                        }
1557
1558                        if ($this->file_exists (array(
1559                                        'string'        => $t->fake_full_path,
1560                                        'relatives'     => array ($t->mask)
1561                                ))
1562                        )
1563                        {
1564                                $remote_operation=PHPGW_ACL_EDIT;
1565                        }
1566                        else
1567                        {
1568                                $remote_operation=PHPGW_ACL_ADD;
1569
1570                        }
1571                        if (!$this->acl_check (array(
1572                                                     'string'   => $t->fake_full_path,
1573                                                     'relatives'        => array ($t->mask),
1574                                                     'operation'        => $remote_operation
1575                                                     ))
1576                            )
1577                        {
1578                                return False;
1579                        }
1580
1581                        umask(000);
1582
1583                        if ($this->file_type (array(
1584                                        'string'        => $f->fake_full_path,
1585                                        'relatives'     => array ($f->mask)
1586                                )) != 'Directory'
1587                        )
1588                        {
1589                         
1590                                if ($f->outside && $t->outside)
1591                                {
1592                                        return copy($f->real_full_path, $t->real_full_url);
1593                                }
1594                                elseif ($f->outside || $t->outside)
1595                                {
1596                                $content = $this->read(array(
1597                                                'string'        => $f->fake_full_path,
1598                                                'noview' => true,
1599                                                'relatives'     => array ($f->mask)
1600                                                )
1601                                        );
1602                                        $result = $this->write(array(
1603                                                'string'        => $t->fake_full_path,
1604                                                'relatives'     => array ($t->mask),
1605                                                'content' => $content
1606                                                )
1607                                        );
1608                            }
1609                                else
1610                                {
1611                                    $status=$this->dav_client->copy($f->real_full_path, $t->real_full_url,True, 'Infinity', $this->override_locks[$p->real_full_path]);
1612                                    $result = $status == 204 || $status==201;
1613                                    if (!$result)
1614                                    {
1615                                        return False;
1616                                    }
1617                                 }
1618
1619                                $this->set_attributes(array(
1620                                        'string'        => $t->fake_full_path,
1621                                        'relatives'     => array ($t->mask),
1622                                        'attributes' => array (
1623                                                                'owner_id' => $this->working_id,
1624                                                                'createdby_id' => $account_id,
1625                                                        )
1626                                                )
1627                                        );
1628                                return $result;
1629
1630                        }
1631                        else if (!($f->outside || $t->outside))
1632                        {
1633                                //if the files are both on server, its just a depth=infinity copy
1634                                $status=$this->dav_client->copy($f->real_full_path, $t->real_full_url,True, 'infinity', $this->override_locks[$p->real_full_path]);
1635                            if($status != 204 && $status!=201)
1636                            {
1637                                return False;
1638                            }
1639                            else
1640                            {
1641                                return True;
1642                            }
1643                        }
1644                        else    /* It's a directory, and one of the files is local */
1645                        {
1646                                /* First, make the initial directory */
1647                                $this->mkdir (array(
1648                                                'string'        => $data['to'],
1649                                                'relatives'     => array ($data['relatives'][1])
1650                                        )
1651                                );
1652
1653                                /* Next, we create all the directories below the initial directory */
1654                                $ls = $this->ls (array(
1655                                                'string'        => $f->fake_full_path,
1656                                                'relatives'     => array ($f->mask),
1657                                                'checksubdirs'  => True,
1658                                                'mime_type'     => 'Directory'
1659                                        )
1660                                );
1661
1662                                while (list ($num, $entry) = each ($ls))
1663                                {
1664                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1665                                        $this->mkdir (array(
1666                                                        'string'        => $newdir.'/'.$entry['name'],
1667                                                        'relatives'     => array ($t->mask)
1668                                                )
1669                                        );
1670                                }
1671
1672                                /* Lastly, we copy the files over */
1673                                $ls = $this->ls (array(
1674                                                'string'        => $f->fake_full_path,
1675                                                'relatives'     => array ($f->mask)
1676                                        )
1677                                );
1678
1679                                while (list ($num, $entry) = each ($ls))
1680                                {
1681                                        if ($entry['mime_type'] == 'Directory')
1682                                        {
1683                                                continue;
1684                                        }
1685
1686                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1687                                        $this->cp (array(
1688                                                        'from'  => "$entry[directory]/$entry[name]",
1689                                                        'to'    => "$newdir/$entry[name]",
1690                                                        'relatives'     => array ($f->mask, $t->mask)
1691                                                )
1692                                        );
1693                                }
1694                        }
1695
1696                        return True;
1697                }
1698
1699                function copy ($data)
1700                {
1701                        return $this->cp ($data);
1702                }
1703
1704                /*!
1705                @function mv
1706                @abstract move file/directory
1707                @param from from file/directory
1708                @param to to file/directory
1709                @param relatives Relativity array
1710                @result boolean True/False
1711                */
1712                function mv ($data)
1713                {
1714                        $default_values = array
1715                                (
1716                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1717                                );
1718
1719                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1720
1721                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1722
1723                        $f = $this->path_parts (array(
1724                                        'string'        => $data['from'],
1725                                        'relatives'     => array ($data['relatives'][0])
1726                                )
1727                        );
1728
1729                        $t = $this->path_parts (array(
1730                                        'string'        => $data['to'],
1731                                        'relatives'     => array ($data['relatives'][1])
1732                                )
1733                        );
1734
1735                        if (!$this->acl_check (array(
1736                                        'string'        => $f->fake_full_path,
1737                                        'relatives'     => array ($f->mask),
1738                                        'operation'     => PHPGW_ACL_READ
1739                                ))
1740                                || !$this->acl_check (array(
1741                                        'string'        => $f->fake_full_path,
1742                                        'relatives'     => array ($f->mask),
1743                                        'operation'     => PHPGW_ACL_DELETE
1744                                ))
1745                        )
1746                        {
1747                                return False;
1748                        }
1749
1750                        if (!$this->acl_check (array(
1751                                        'string'        => $t->fake_full_path,
1752                                        'relatives'     => array ($t->mask),
1753                                        'operation'     => PHPGW_ACL_ADD
1754                                ))
1755                        )
1756                        {
1757                                return False;
1758                        }
1759
1760                        if ($this->file_exists (array(
1761                                        'string'        => $t->fake_full_path,
1762                                        'relatives'     => array ($t->mask)
1763                                ))
1764                        )
1765                        {
1766                                if (!$this->acl_check (array(
1767                                                'string'        => $t->fake_full_path,
1768                                                'relatives'     => array ($t->mask),
1769                                                'operation'     => PHPGW_ACL_EDIT
1770                                        ))
1771                                )
1772                                {
1773                                        return False;
1774                                }
1775                        }
1776                        umask (000);
1777
1778                        /* We can't move directories into themselves */
1779                        if (($this->file_type (array(
1780                                        'string'        => $f->fake_full_path,
1781                                        'relatives'     => array ($f->mask)
1782                                ) == 'Directory'))
1783                                && ereg ("^$f->fake_full_path", $t->fake_full_path)
1784                        )
1785                        {
1786                                if (($t->fake_full_path == $f->fake_full_path) || substr ($t->fake_full_path, strlen ($f->fake_full_path), 1) == '/')
1787                                {
1788                                        return False;
1789                                }
1790                        }
1791
1792                        if ($this->file_exists (array(
1793                                        'string'        => $f->fake_full_path,
1794                                        'relatives'     => array ($f->mask)
1795                                ))
1796                        )
1797                        {
1798                                /* We get the listing now, because it will change after we update the database */
1799                                $ls = $this->ls (array(
1800                                                'string'        => $f->fake_full_path,
1801                                                'relatives'     => array ($f->mask)
1802                                        )
1803                                );
1804
1805                                if ($this->file_exists (array(
1806                                                'string'        => $t->fake_full_path,
1807                                                'relatives'     => array ($t->mask)
1808                                        ))
1809                                )
1810                                {
1811                                        $this->rm (array(
1812                                                        'string'        => $t->fake_full_path,
1813                                                        'relatives'     => array ($t->mask)
1814                                                )
1815                                        );
1816                                }
1817
1818                                $this->correct_attributes (array(
1819                                                'string'        => $t->fake_full_path,
1820                                                'relatives'     => array ($t->mask)
1821                                        )
1822                                );
1823                               
1824                                if ($f->outside && $t->outside)
1825                                {
1826                                        echo 'local';
1827                                        $result = rename ($f->real_full_path, $t->real_full_path);
1828                                }
1829                                else if ($f->outside || $t->outside) //if either file is local, read then write
1830                                {
1831                                        $content = $this->read(array(
1832                                                'string'        => $f->fake_full_path,
1833                                                'noview' => true,
1834                                                'relatives'     => array ($f->mask)
1835                                                )
1836                                        );
1837                                        $result = $this->write(array(
1838                                                'string'        => $t->fake_full_path,
1839                                                'relatives'     => array ($t->mask),
1840                                                'content' => $content
1841                                                )
1842                                        );
1843                                        if ($result)
1844                                        {
1845                                                $result = $this->rm(array(
1846                                                        'string'        => $f->fake_full_path,
1847                                                        'relatives'     => array ($f->mask),
1848                                                        'content' => $content
1849                                                        )
1850                                                );
1851                                        }
1852                                }
1853                                else {  //we can do a server-side copy if both files are on the server
1854                                        $status=$this->dav_client->move($f->real_full_path, $t->real_full_url,True, 'infinity', $this->override_locks[$p->real_full_path]);
1855                                $result = ($status==201 || $status==204);
1856                                }
1857                               
1858                                if ($result) $this->set_attributes(array(
1859                                                'string'        => $t->fake_full_path,
1860                                                'relatives'     => array ($t->mask),
1861                                                'attributes'    => array (
1862                                                                        'modifiedby_id' => $account_id,
1863                                                                        'modified' => $this->now
1864                                                                )));
1865                                return $result;
1866                        }
1867                        else
1868                        {
1869                                return False;
1870                        }
1871
1872                        $this->add_journal (array(
1873                                        'string'        => $t->fake_full_path,
1874                                        'relatives'     => array ($t->mask),
1875                                        'operation'     => VFS_OPERATION_MOVED,
1876                                        'state_one'     => $f->fake_full_path,
1877                                        'state_two'     => $t->fake_full_path
1878                                )
1879                        );
1880
1881                        return True;
1882                }
1883
1884                /*!
1885                @function move
1886                @abstract shortcut to mv
1887                */
1888                function move ($data)
1889                {
1890                        return $this->mv ($data);
1891                }
1892
1893                /*!
1894                @function rm
1895                @abstract delete file/directory
1896                @param string file/directory to delete
1897                @param relatives Relativity array
1898                @result boolean True/False
1899                */
1900                function rm ($data)
1901                {
1902                        $default_values = array
1903                                (
1904                                        'relatives'     => array (RELATIVE_CURRENT)
1905                                );
1906
1907                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1908                        $p = $this->path_parts (array(
1909                                        'string'        => $data['string'],
1910                                        'relatives'     => array ($data['relatives'][0])
1911                                )
1912                        );
1913                        $this->debug("rm: $p->real_full_path");
1914                        if (!$this->acl_check (array(
1915                                        'string'        => $p->fake_full_path,
1916                                        'relatives'     => array ($p->mask),
1917                                        'operation'     => PHPGW_ACL_DELETE
1918                                ))
1919                        )
1920                        {
1921                                return False;
1922                        }
1923
1924/*this would become apparent soon enough anyway?
1925                        if (!$this->file_exists (array(
1926                                        'string'        => $data['string'],
1927                                        'relatives'     => array ($data['relatives'][0])
1928                                ))
1929                        ) return False;
1930*/
1931                        if ($this->file_type (array(
1932                                        'string'        => $data['string'],
1933                                        'relatives'     => array ($data['relatives'][0])
1934                                )) != 'Directory'
1935                        )
1936                        {
1937                                if ($p->outside)
1938                                {
1939                                        return unlink($p->real_full_path);
1940                                }
1941                                else
1942                                {
1943                                        $rr=$this->dav_client->delete($p->real_full_path, 0, $this->override_locks[$p->real_full_path]);
1944                                        return $rr == 204;     
1945                                }
1946                        }
1947                        else
1948                        {
1949                                $ls = $this->ls (array(
1950                                                'string'        => $p->fake_full_path,
1951                                                'relatives'     => array ($p->mask)
1952                                        )
1953                                );
1954
1955                                while (list ($num, $entry) = each ($ls))
1956                                {
1957                                        $this->rm (array(
1958                                                        'string'        => "$entry[directory]/$entry[name]",
1959                                                        'relatives'     => array ($p->mask)
1960                                                )
1961                                        );
1962                                }
1963
1964                                /* If the directory is linked, we delete the placeholder directory */
1965                                $ls_array = $this->ls (array(
1966                                                'string'        => $p->fake_full_path,
1967                                                'relatives'     => array ($p->mask),
1968                                                'checksubdirs'  => False,
1969                                                'mime_type'     => False,
1970                                                'nofiles'       => True
1971                                        )
1972                                );
1973                                $link_info = $ls_array[0];
1974
1975                                if ($link_info['link_directory'] && $link_info['link_name'])
1976                                {
1977                                        $path = $this->path_parts (array(
1978                                                        'string'        => $link_info['directory'] . '/' . $link_info['name'],
1979                                                        'relatives'     => array ($p->mask),
1980                                                        'nolinks'       => True
1981                                                )
1982                                        );
1983                                        $this->dav_client->delete($path->real_full_path,0, $this->override_locks[$p->real_full_path]);
1984                                }
1985
1986                                /* Last, we delete the directory itself */
1987                                $this->add_journal (array(
1988                                                'string'        => $p->fake_full_path,
1989                                                'relatives'     => array ($p->mask),
1990                                                'operaton'      => VFS_OPERATION_DELETED
1991                                        )
1992                                );
1993
1994                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean'" . $this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1995
1996                                //rmdir ($p->real_full_path);
1997                                $this->dav_client->delete($p->real_full_path.'/','Infinity', $this->override_locks[$p->real_full_path]);
1998
1999                                return True;
2000                        }
2001                }
2002
2003                /*!
2004                @function delete
2005                @abstract shortcut to rm
2006                */
2007                function delete ($data)
2008                {
2009                        error_log("Aqui", 3, "/tmp/log");
2010                       
2011                        return $this->rm ($data);
2012                }
2013
2014                /*!
2015                @function mkdir
2016                @abstract make a new directory
2017                @param string Directory name
2018                @param relatives Relativity array
2019                @result boolean True on success
2020                */
2021                function mkdir ($data)
2022                {
2023                        if (!is_array ($data))
2024                        {
2025                                $data = array ();
2026                        }
2027
2028                        $default_values = array
2029                                (
2030                                        'relatives'     => array (RELATIVE_CURRENT)
2031                                );
2032
2033                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2034
2035                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
2036                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
2037
2038                        $p = $this->path_parts (array(
2039                                        'string'        => $data['string'],
2040                                        'relatives'     => array ($data['relatives'][0])
2041                                )
2042                        );
2043
2044                        if (!$this->acl_check (array(
2045                                        'string'        => $p->fake_full_path,
2046                                        'relatives'     => array ($p->mask),
2047                                        'operation'     => PHPGW_ACL_ADD)
2048                                )
2049                        )
2050                        {
2051                                return False;
2052                        }
2053
2054                        /* We don't allow /'s in dir names, of course */
2055                        if (ereg ('/', $p->fake_name))
2056                        {
2057                                return False;
2058                        }
2059                        if ($p->outside)
2060                        {
2061                                if (!mkdir($p->real_full_path, 0777))
2062                                {
2063                                        return False;
2064                                }
2065                        }
2066                        else if($this->dav_client->mkcol($p->real_full_path, $this->override_locks[$p->real_full_path]) != 201)
2067                        {
2068                                return False;
2069                        }
2070                       
2071
2072                        if (!$this->file_exists (array(
2073                                        'string'        => $p->fake_full_path.'/'
2074                                ))
2075                        )
2076                        {
2077                                /*Now we need to set access control for this dir.  Simply create an .htaccess
2078                                file limiting access to this user, if we are creating this dir in the user's home dir*/
2079                                $homedir = $this->fakebase.'/'.$this->dav_user;
2080                                if ( substr($p->fake_leading_dirs, 0, strlen($homedir)) == $homedir)
2081                                {
2082                                        $conf = CreateObject('phpgwapi.config', 'phpgwapi');
2083                                        $conf->read_repository();
2084                                        if (!$conf->config_data['acl_default'] == 'grant')
2085                                        {
2086                                                $htaccess = 'require user '.$GLOBALS['phpgw_info']['user']['account_lid'];
2087                                                if ( ! $this->write(array(
2088                                                                'string' =>  $p->fake_full_path.'/.htaccess',
2089                                                                'content' => $htaccess,
2090                                                                'relatives' => array(RELATIVE_NONE)
2091                                                        )))
2092                                                {
2093                                                        echo '<p><b>Unable to write .htaccess file</b></p></b>';
2094                                                };     
2095                                        }
2096                                }
2097                                return True;
2098                        }
2099                        else
2100                        {
2101                                return False;
2102                        }
2103                }
2104
2105                /*!
2106                @function make_link
2107                @abstract Make a link from virtual directory 'vdir' to real directory 'rdir'
2108                @discussion Making a link from 'vdir' to 'rdir' will cause path_parts () to substitute 'rdir' for the real
2109                                path variables when presented with 'vdir'
2110                @param vdir Virtual dir to make link from
2111                @param rdir Real dir to make link to
2112                @param relatives Relativity array
2113                @result Boolean True/False
2114                */
2115                function make_link ($data)
2116                {
2117                        return False; //This code certainly wont work anymore.  Does anything use it?
2118                /*
2119                        $default_values = array
2120                                (
2121                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
2122                                );
2123
2124                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2125
2126                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
2127                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
2128
2129                        $vp = $this->path_parts (array(
2130                                        'string'        => $data['vdir'],
2131                                        'relatives'     => array ($data['relatives'][0])
2132                                )
2133                        );
2134
2135                        $rp = $this->path_parts (array(
2136                                        'string'        => $data['rdir'],
2137                                        'relatives'     => array ($data['relatives'][1])
2138                                )
2139                        );
2140
2141                        if (!$this->acl_check (array(
2142                                        'string'        => $vp->fake_full_path,
2143                                        'relatives'     => array ($vp->mask),
2144                                        'operation'     => PHPGW_ACL_ADD
2145                                ))
2146                        ) return False;
2147
2148                        if ((!$this->file_exists (array(
2149                                        'string'        => $rp->real_full_path,
2150                                        'relatives'     => array ($rp->mask)
2151                                )))
2152                                && !mkdir ($rp->real_full_path, 0770)) return False;
2153
2154                        if (!$this->mkdir (array(
2155                                        'string'        => $vp->fake_full_path,
2156                                        'relatives'     => array ($vp->mask)
2157                                ))
2158                        )return False;
2159
2160                        $size = $this->get_size (array(
2161                                        'string'        => $rp->real_full_path,
2162                                        'relatives'     => array ($rp->mask)
2163                                )
2164                        );
2165
2166                        $this->set_attributes(array(
2167                                        'string'        => $vp->fake_full_path,
2168                                        'relatives'     => array ($vp->mask),
2169                                        'attributes'    => array (
2170                                                                'link_directory' => $rp->real_leading_dirs,
2171                                                                'link_name' => $rp->real_name,
2172                                                                'size' => $size
2173                                                        )
2174                                )
2175                        );
2176
2177                        $this->correct_attributes (array(
2178                                        'string'        => $vp->fake_full_path,
2179                                        'relatives'     => array ($vp->mask)
2180                                )
2181                        );
2182
2183                        return True;
2184        */
2185                }
2186
2187                /*!
2188                @function set_attributes
2189                @abstract Update database entry for 'string' with the attributes in 'attributes'
2190                @param string file/directory to update
2191                @param relatives Relativity array
2192                @param attributes keyed array of attributes.  key is attribute name, value is attribute value
2193                @result Boolean True/False
2194                @discussion Valid attributes are:
2195                                owner_id
2196                                createdby_id
2197                                modifiedby_id
2198                                created
2199                                modified
2200                                size
2201                                mime_type
2202                                deleteable
2203                                comment
2204                                app
2205                                link_directory
2206                                link_name
2207                                version
2208                                name
2209                                directory
2210                */
2211                function set_attributes ($data,$operation=PHPGW_ACL_EDIT)
2212                {
2213                        /*To get much benefit out of DAV properties we should use
2214                        some sensible XML namespace.  We will use the Dublin Core
2215                        metadata specification (http://dublincore.org/) here where
2216                        we can*/
2217                        $p = $this->path_parts (array(
2218                                'string'        => $data['string'],
2219                                'relatives'     => array ($data['relatives'][0])
2220                                ));
2221                        $dav_properties = array();
2222                        $lid=''; $fname = ''; $lname='';
2223                        if ($data['attributes']['comment'])
2224                        {
2225                                $dav_properties['dc:description'] = $data['attributes']['comment'];
2226                        }
2227                        if ($id=$data['attributes']['owner_id'])
2228                        {
2229                                $GLOBALS['phpgw']->accounts->get_account_name($id,&$lid,&$fname,&$lname);
2230                                $dav_properties['dc:publisher'] = $fname .' '. $lname;
2231                                $dav_properties['publisher_id'] = $id;
2232                        }
2233                        if ($id=$data['attributes']['createdby_id'])
2234                        {
2235                                $GLOBALS['phpgw']->accounts->get_account_name($id,&$lid,&$fname,&$lname);
2236                                $dav_properties['dc:creator'] = $fname .' '. $lname;
2237                                $dav_properties['creator_id'] = $id;
2238                        }
2239                        if ($id=$data['attributes']['modifiedby_id'])
2240                        {
2241                                $GLOBALS['phpgw']->accounts->get_account_name($id,&$lid,&$fname,&$lname);
2242                                $dav_properties['dc:contributor'] = $fname .' '. $lname;
2243                                $dav_properties['contributor_id'] = $id;
2244                        }
2245
2246                        $xmlns = 'xmlns:dc="http://purl.org/dc/elements/1.0/"';
2247                        $this->dav_client->proppatch($p->real_full_path, $dav_properties, $xmlns, $this->override_locks[$p->real_full_path]);
2248                        return True;
2249                }
2250
2251                /*!
2252                @function correct_attributes
2253                @abstract Set the correct attributes for 'string' (e.g. owner)
2254                @param string File/directory to correct attributes of
2255                @param relatives Relativity array
2256                @result Boolean True/False
2257                */
2258                function correct_attributes ($data)
2259                {
2260                        $default_values = array
2261                                (
2262                                        'relatives'     => array (RELATIVE_CURRENT)
2263                                );
2264
2265                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2266                        $this->debug('correct_attributes: '.$data['string']);
2267                        $p = $this->path_parts (array(
2268                                        'string'        => $data['string'],
2269                                        'relatives'     => array ($data['relatives'][0])
2270                                )
2271                        );
2272
2273                        if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/')
2274                        {
2275                                $ls_array = $this->ls (array(
2276                                                'string'        => $p->fake_leading_dirs,
2277                                                'relatives'     => array ($p->mask),
2278                                                'checksubdirs'  => False,
2279                                                'nofiles'       => True
2280                                        )
2281                                );
2282                                $set_attributes_array = Array(
2283                                        'owner_id' => $ls_array[0]['owner_id']
2284                                );
2285                        }
2286                        elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches))
2287                        {
2288                                $set_attributes_array = Array(
2289                                        'owner_id' => $GLOBALS['phpgw']->accounts->name2id ($matches[1])
2290                                );
2291                        }
2292                        else
2293                        {
2294                                $set_attributes_array = Array(
2295                                        'owner_id' => 0
2296                                );
2297                        }
2298
2299                        $this->set_attributes (array(
2300                                        'string'        => $p->fake_full_name,
2301                                        'relatives'     => array ($p->mask),
2302                                        'attributes'    => $set_attributes_array
2303                                )
2304                        );
2305
2306                        return True;
2307                }
2308
2309                /*!
2310                @function file_type
2311                @abstract return file/dir type (MIME or other)
2312                @param string File or directory path (/home/user/dir/dir2/dir3, /home/user/dir/dir2/file)
2313                @param relatives Relativity array
2314                @result MIME type, "Directory", or nothing if MIME type is not known
2315                */
2316                function file_type ($data)
2317                {
2318$this->debug('file_type');
2319                        $default_values = array
2320                                (
2321                                        'relatives'     => array (RELATIVE_CURRENT)
2322                                );
2323
2324                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2325
2326                        $p = $this->path_parts (array(
2327                                        'string'        => $data['string'],
2328                                        'relatives'     => array ($data['relatives'][0])
2329                                )
2330                        );
2331
2332                        if (!$this->acl_check (array(
2333                                        'string'        => $p->fake_full_path,
2334                                        'relatives'     => array ($p->mask),
2335                                        'operation'     => PHPGW_ACL_READ,
2336                                        'must_exist'    => True
2337                                ))
2338                        ) return False;
2339
2340                        if ($p->outside)
2341                        {
2342                          if(is_dir($p->real_full_path)) return ('Directory');
2343                          else return $this->get_ext_mime_type(array('string' => $p->real_full_path));
2344
2345                        }
2346                        $tmp_prop=$this->dav_client->get_properties($p->real_full_path);
2347$this->debug('tmpprop: '.$p->real_full_path);
2348$this->debug($tmp_prop);
2349                        $mime_type=$tmp_prop[$p->real_full_path]['mime_type'];
2350                        if ($mime_type == 'httpd/unix-directory' || $tmp_prop[$p->real_full_path]['is_dir']== '1')
2351                        {
2352                                $mime_type='Directory';
2353                        }
2354$this->debug('file_type: Mime type : '.$mime_type);
2355                        return $mime_type;
2356                }
2357
2358                /*!
2359                @function get_ext_mime_type
2360                @abstract return MIME type based on file extension
2361                @description Authors: skeeter
2362                             Internal use only.  Applications should call vfs->file_type ()
2363                @param string File name, with or without leading paths
2364                @result MIME type based on file extension
2365                */
2366                function get_ext_mime_type ($data)
2367                {
2368                        $file=basename($data['string']);
2369                        $mimefile=PHPGW_API_INC.'/phpgw_mime.types';
2370                        $fp=fopen($mimefile,'r');
2371                        $contents = explode("\n",fread($fp,filesize($mimefile)));
2372                        fclose($fp);
2373
2374                        $parts=explode('.',strtolower($file));
2375                        $ext=$parts[(sizeof($parts)-1)];
2376
2377                        for($i=0;$i<sizeof($contents);$i++)
2378                        {
2379                                if (!ereg("^#",$contents[$i]))
2380                                {
2381                                        $line=split("[[:space:]]+", $contents[$i]);
2382                                        if (sizeof($line) >= 2)
2383                                        {
2384                                                for($j=1;$j<sizeof($line);$j++)
2385                                                {
2386                                                        if($line[$j] == $ext)
2387                                                        {
2388                                                                return $line[0];
2389                                                        }
2390                                                }
2391                                        }
2392                                }
2393                        }
2394
2395                        return '';
2396                }
2397               
2398
2399 
2400                /*!
2401                @function file_exists
2402                @abstract check if file/directory exists
2403                @param string file/directory to check existance of
2404                @param relatives Relativity array
2405                @result Boolean True/False
2406                */
2407                function file_exists ($data)
2408                {
2409                        $default_values = array
2410                                (
2411                                        'relatives'     => array (RELATIVE_CURRENT)
2412                                );
2413
2414                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2415
2416                        $p = $this->path_parts (array(
2417                                        'string'        => $data['string'],
2418                                        'relatives'     => array ($data['relatives'][0])
2419                                )
2420                        );
2421$this->debug('vfs->file_exists() data:'.$data['string']);
2422$this->debug('vfs->file_exists() full_path:  '.$p->real_full_path);
2423                        if ($p->outside)
2424                        {
2425                          return file_exists($p->real_full_path);
2426                        }
2427                       
2428                        $path = $p->real_full_path;
2429                       
2430                        //Even though this does full XML parsing on the output, because
2431                        // it then caches the result this limits the amount of traffic to
2432                        //the dav server (which makes it faster even over a local connection)
2433                        $props = $this->dav_client->get_properties($path);
2434                        if ($props[$path])
2435                        {
2436                                $this->debug('found');
2437                                return True;
2438                        }
2439                        else
2440                        {
2441                                $this->debug('not found');
2442                                return False;
2443                        }
2444                }
2445
2446                /*!
2447                @function get_size
2448                @abstract Return size of 'string'
2449                @param string file/directory to get size of
2450                @param relatives Relativity array
2451                @param checksubdirs Boolean, recursively add the size of all sub directories as well?
2452                @result Size of 'string' in bytes
2453                */
2454                function get_size ($data)
2455                {
2456                        if (!is_array ($data))
2457                        {
2458                                $data = array ();
2459                        }
2460
2461                        $default_values = array
2462                                (
2463                                        'relatives'     => array (RELATIVE_CURRENT),
2464                                        'checksubdirs'  => True
2465                                );
2466
2467                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2468
2469                        $p = $this->path_parts (array(
2470                                        'string'        => $data['string'],
2471                                        'relatives'     => array ($data['relatives'][0])
2472                                )
2473                        );
2474
2475                        if (!$this->acl_check (array(
2476                                        'string'        => $p->fake_full_path,
2477                                        'relatives'     => array ($p->mask),
2478                                        'operation'     => PHPGW_ACL_READ,
2479                                        'must_exist'    => True
2480                                ))
2481                        )
2482                        {
2483                                return False;
2484                        }
2485
2486                        /*
2487                           WIP - this should run through all of the subfiles/directories in the directory and tally up
2488                           their sizes.  Should modify ls () to be able to return a list for files outside the virtual root
2489                        */
2490                        if ($p->outside){
2491                          return filesize($p->real_full_path);
2492                        }
2493
2494                        $ls_array = $this->ls (array(
2495                                        'string'        => $p->fake_full_path,
2496                                        'relatives'     => array ($p->mask),
2497                                        'checksubdirs'  => $data['checksubdirs'],
2498                                        'nofiles'       => !$data['checksubdirs']
2499                                )
2500                        );
2501
2502                        while (list ($num, $file_array) = each ($ls_array))
2503                        {
2504                                /*
2505                                   Make sure the file is in the directory we want, and not
2506                                   some deeper nested directory with a similar name
2507                                */
2508/*
2509                                if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path))
2510                                {
2511                                        continue;
2512                                }
2513*/
2514
2515                                $size += $file_array['size'];
2516$this->debug('size:getting size from fs: '.$size);
2517                        }
2518
2519                        return $size;
2520                }
2521
2522                /*!
2523                @function checkperms
2524                @abstract Check if $this->working_id has write access to create files in $dir
2525                @discussion Simple call to acl_check
2526                @param string Directory to check access of
2527                @param relatives Relativity array
2528                @result Boolean True/False
2529                */
2530                function checkperms ($data)
2531                {
2532                        if (!is_array ($data))
2533                        {
2534                                $data = array ();
2535                        }
2536
2537                        $default_values = array
2538                                (
2539                                        'relatives'     => array (RELATIVE_CURRENT)
2540                                );
2541
2542                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2543
2544                        $p = $this->path_parts (array(
2545                                        'string'        => $data['string'],
2546                                        'relatives'     => array ($data['relatives'][0])
2547                                )
2548                        );
2549
2550                        if (!$this->acl_check (array(
2551                                        'string'        => $p->fake_full_path,
2552                                        'relatives'     => array ($p->mask),
2553                                        'operation'     => PHPGW_ACL_ADD
2554                                ))
2555                        )
2556                        {
2557                                return False;
2558                        }
2559                        else
2560                        {
2561                                return True;
2562                        }
2563                }
2564
2565                /*!
2566                @function ls
2567                @abstract get directory listing or info about a single file
2568                @discussion Note: The entries are not guaranteed to be returned in any logical order
2569                            Note: The size for directories does not include subfiles/subdirectories.
2570                                  If you need that, use $this->get_size ()
2571                @param string File or Directory
2572                @param relatives Relativity array
2573                @param checksubdirs Boolean, recursively list all sub directories as well?
2574                @param mime_type Only return entries matching MIME-type 'mime_type'.  Can be any MIME-type, "Directory" or "\ " for those without MIME types
2575                @param nofiles Boolean.  True means you want to return just the information about the directory $dir.  If $dir is a file, $nofiles is implied.  This is the equivalent of 'ls -ld $dir'
2576                @param orderby How to order results.  Note that this only works for directories inside the virtual root
2577                @result array of arrays.  Subarrays contain full info for each file/dir.
2578                */
2579                function ls ($data)
2580                {
2581                        $default_values = array
2582                                (
2583                                        'relatives'     => array (RELATIVE_CURRENT),
2584                                        'checksubdirs'  => True,
2585                                        'mime_type'     => False,
2586                                        'nofiles'       => False,
2587                                        'orderby'       => 'directory'
2588                                );
2589                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2590                        //Stupid "nofiles" fix"
2591                        if ($data['nofiles'])
2592                        {
2593                                $data['relatives'] = array (RELATIVE_NONE);
2594                        }
2595                        $p = $this->path_parts (array(
2596                                        'string'        => $data['string'],
2597                                        'relatives'     => array ($data['relatives'][0])
2598                                )
2599                        );
2600               
2601                        if ($data['checksubdirs']==False && ereg('.*/$', $data['string']) && $data['nofiles'] )
2602                        {
2603$this->debug('Returning empty for'.$data['string']);
2604                                return array();
2605                        }
2606                        $dir = $p->fake_full_path;
2607$this->debug("ls'ing dir: $dir path: ".$p->real_full_path);
2608                        /* If they pass us a file or 'nofiles' is set, return the info for $dir only */
2609                        if (((($type = $this->file_type (array(
2610                                        'string'        => $dir,
2611                                        'relatives'     => array ($p->mask)
2612                                )) != 'Directory'))
2613                                || ($data['nofiles'])) && !$p->outside
2614                        )
2615                        {
2616$this->debug('ls branch 1');
2617                        $prop=$this->dav_client->get_properties($p->real_full_path, 1);
2618                        //make the key the 'orderby' attribute
2619                        if (! ($data['orderby'] == 'directory'))
2620                        {
2621                                $tmp_prop = array();
2622                                $id=0;
2623                                foreach ( $prop as $key=>$value)
2624                                {
2625                                        $id++;
2626                                        $new_key =  substr($value[$data['orderby']].'        ',0, 8);
2627                                        $tmp_prop[strtolower($new_key).'_'.$id] = $value;
2628                                }
2629                        }
2630                        else
2631                        {
2632                                $tmp_prop = $prop;
2633                        }
2634                        ksort($tmp_prop);
2635                        $rarray = array ();
2636                        foreach($tmp_prop as $idx => $value)
2637                        {
2638                                if($value['mime_type']==$data['mime_type'] or $data['mime_type']=='')
2639                                {
2640                                        $directory = $this->path_parts($value['directory']);
2641                                        $value['directory'] = $directory->fake_full_path;
2642                                        if($value['is_dir']) $value['mime_type']='Directory';
2643                                        $rarray[] = $value;
2644                                }
2645                        }
2646$this->debug('ls returning 1:');
2647                                return $rarray;
2648                        }
2649
2650                        //WIP - this should recurse using the same options the virtual part of ls () does
2651                        /* If $dir is outside the virutal root, we have to check the file system manually */
2652                        if ($p->outside)
2653                        {
2654$this->debug('ls branch 2 (outside)');
2655                                if ($this->file_type (array(
2656                                                'string'        => $p->fake_full_path,
2657                                                'relatives'     => array ($p->mask)
2658                                        )) == 'Directory'
2659                                        && !$data['nofiles']
2660                                )
2661                                {
2662                                        $dir_handle = opendir ($p->real_full_path);
2663                                        while ($filename = readdir ($dir_handle))
2664                                        {
2665                                                if ($filename == '.' || $filename == '..')
2666                                                {
2667                                                        continue;
2668                                                }
2669
2670                                                $rarray[] = $this->get_real_info (array(
2671                                                                'string'        => $p->real_full_path . SEP . $filename,
2672                                                                'relatives'     => array ($p->mask)
2673                                                        )
2674                                                );
2675                                        }
2676                                }
2677                                else
2678                                {
2679                                        $rarray[] = $this->get_real_info (array(
2680                                                        'string'        => $p->real_full_path,
2681                                                        'relatives'     => array ($p->mask)
2682                                                )
2683                                        );
2684                                }
2685$this->debug('ls returning 2:');
2686                                return $rarray;
2687                        }
2688$this->debug('ls branch 3');
2689                        /* $dir's not a file, is inside the virtual root, and they want to check subdirs */
2690                        $prop=$this->dav_client->get_properties($p->real_full_path,1);
2691                        unset($prop[$p->real_full_path]);
2692                        //make the key the 'orderby' attribute
2693
2694                        if (! ($data['orderby'] == 'directory'))
2695                        {
2696                                $tmp_prop = array();
2697                                $id=0;
2698                                foreach ( $prop as $key=>$value)
2699                                {
2700                                        $id++;
2701                                        $new_key =  substr($value[$data['orderby']].'        ',0, 8);
2702                                        $tmp_prop[strtolower($new_key).'_'.$id] = $value;
2703                                }
2704                        }
2705                        else
2706                        {
2707                                $tmp_prop = $prop;
2708                        }
2709                       
2710                        ksort($tmp_prop);
2711
2712                        unset($tmp_prop[ $p->real_full_path]);
2713                        $rarray = array ();
2714                        foreach($tmp_prop as $idx => $value)
2715                        {       
2716                                if($data['mime_type']=='' || $value['mime_type']==$data['mime_type'])
2717                                {
2718                                        //$directory = $this->path_parts($value['directory']);
2719                                        $value['directory'] = $p->fake_full_path;
2720                                        $rarray[] = $value;
2721                                }
2722                        }               
2723$this->debug('ls:returning 3:');
2724                        return $rarray;
2725                }
2726
2727                /*!
2728                @function dir
2729                @abstract shortcut to ls
2730                */
2731                function dir ($data)
2732                {
2733                        return $this->ls ($data);
2734                }
2735
2736                /*!
2737                @function command_line
2738                @abstract Process and run a Unix-sytle command line
2739                @discussion EXPERIMENTAL.  DANGEROUS.  DO NOT USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
2740                            This is mostly working, but the command parser needs to be improved to take
2741                            files with spaces into consideration (those should be in "").
2742                @param command_line Unix-style command line with one of the commands in the $args array
2743                @result $result The return value of the actual VFS call
2744                */
2745                function command_line ($data)
2746                {
2747                        if (!is_array ($data))
2748                        {
2749                                $data = array ();
2750                        }
2751
2752                        $args = array
2753                        (
2754                                array ('name'   => 'mv', 'params'       => 2),
2755                                array ('name'   => 'cp', 'params'       => 2),
2756                                array ('name'   => 'rm', 'params'       => 1),
2757                                array ('name'   => 'ls', 'params'       => -1),
2758                                array ('name'   => 'du', 'params'       => 1, 'func'    => get_size),
2759                                array ('name'   => 'cd', 'params'       => 1),
2760                                array ('name'   => 'pwd', 'params'      => 0),
2761                                array ('name'   => 'cat', 'params'      => 1, 'func'    => read),
2762                                array ('name'   => 'file', 'params'     => 1, 'func'    => file_type),
2763                                array ('name'   => 'mkdir', 'params'    => 1),
2764                                array ('name'   => 'touch', 'params'    => 1)
2765                        );
2766
2767                        if (!$first_space = strpos ($data['command_line'], ' '))
2768                        {
2769                                $first_space = strlen ($data['command_line']);
2770                        }
2771                        if ((!$last_space = strrpos ($data['command_line'], ' ')) || ($last_space == $first_space))
2772                        {
2773                                $last_space = strlen ($data['command_line']) + 1;
2774                        }
2775                        $argv[0] = substr ($data['command_line'], 0, $first_space);
2776                        if (strlen ($argv[0]) != strlen ($data['command_line']))
2777                        {
2778                                $argv[1] = substr ($data['command_line'], $first_space + 1, $last_space - ($first_space + 1));
2779                                if ((strlen ($argv[0]) + 1 + strlen ($argv[1])) != strlen ($data['command_line']))
2780                                {
2781                                        $argv[2] = substr ($data['command_line'], $last_space + 1);
2782                                }
2783                        }
2784                        $argc = count ($argv);
2785
2786                        reset ($args);
2787                        while (list (,$arg_info) = each ($args))
2788                        {
2789                                if ($arg_info['name'] == $argv[0])
2790                                {
2791                                        $command_ok = 1;
2792                                        if (($argc == ($arg_info['params'] + 1)) || ($arg_info['params'] == -1))
2793                                        {
2794                                                $param_count_ok = 1;
2795                                        }
2796                                        break;
2797                                }
2798                        }
2799
2800                        if (!$command_ok)
2801                        {
2802//                              return E_VFS_BAD_COMMAND;
2803                                return False;
2804                        }
2805                        if (!$param_count_ok)
2806                        {
2807//                              return E_VFS_BAD_PARAM_COUNT;
2808                                return False;
2809                        }
2810
2811                        for ($i = 1; $i != ($arg_info['params'] + 1); $i++)
2812                        {
2813                                if (substr ($argv[$i], 0, 1) == '/')
2814                                {
2815                                        $relatives[] = RELATIVE_NONE;
2816                                }
2817                                else
2818                                {
2819                                        $relatives[] = RELATIVE_ALL;
2820                                }
2821                        }
2822
2823                        $func = $arg_info['func'] ? $arg_info['func'] : $arg_info['name'];
2824
2825                        if (!$argv[2])
2826                        {
2827                                $rv = $this->$func (array(
2828                                                'string'        => $argv[1],
2829                                                'relatives'     => $relatives
2830                                        )
2831                                );
2832                        }
2833                        else
2834                        {
2835                                $rv = $this->$func (array(
2836                                                'from'  => $argv[1],
2837                                                'to'    => $argv[2],
2838                                                'relatives'     => $relatives
2839                                        )
2840                                );
2841                        }
2842
2843                        return ($rv);
2844                }
2845
2846                /* Helper functions */
2847
2848                function default_values ($data, $default_values)
2849                {
2850                  if(!is_array($data)) $data=array();
2851                        for ($i = 0; list ($key, $value) = each ($default_values); $i++)
2852                        {
2853                                if (!isset ($data[$key]))
2854                                {
2855                                        $data[$key] = $value;
2856                                }
2857                        }
2858
2859                        return $data;
2860                }
2861
2862                /* Since we are always dealing with real info, this just calls ls */
2863                function get_real_info ($data){
2864                        if (!is_array ($data))
2865                        {
2866                                $data = array ();
2867                        }
2868
2869                        $default_values = array
2870                                (
2871                                        'relatives'     => array (RELATIVE_CURRENT)
2872                                );
2873
2874                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2875
2876                        $p = $this->path_parts (array(
2877                                        'string'        => $data['string'],
2878                                        'relatives'     => array ($data['relatives'][0])
2879                                )
2880                        );
2881
2882                        if ( $this->file_type(array('string' => $p->real_full_path, 'relatives' => array (RELATIVE_ROOT))) == 'Directory')
2883                        {
2884                                $mime_type = 'Directory';
2885                        }
2886                        else
2887                        {
2888                                $mime_type = $this->get_ext_mime_type (array(
2889                                                'string'        => $p->fake_name
2890                                        )
2891                                );
2892
2893                        }
2894
2895                        $size = filesize ($p->real_full_path);
2896                        $rarray = array(
2897                                'directory' => $p->fake_leading_dirs,
2898                                'name' => $p->fake_name,
2899                                'size' => $size,
2900                                'mime_type' => $mime_type
2901                        );
2902
2903                        return ($rarray);
2904                }
2905               
2906                function update_real()
2907                { //hmmm. things break without this, but it does nothing in this implementation
2908                        return True;
2909                }
2910               
2911                function save_session()
2912                {
2913                        //Save the overrided locks in the session
2914                        $app = $GLOBALS['phpgw_info']['flags']['currentapp'];
2915                        $a = array();
2916                        foreach ($this->override_locks as $name => $token)
2917                        {
2918                                $a[] = $name.';'.$token;       
2919                        }       
2920                        $session_data = implode('\n', $a);
2921                        $this->session = $GLOBALS['phpgw']->session->appsession ('vfs_dav',$app, base64_encode($session_data));
2922                               
2923                }       
2924        }
2925?>
Note: See TracBrowser for help on using the repository browser.