source: trunk/phpgwapi/inc/class.vfs_dav.inc.php @ 5940

Revision 5940, 75.0 KB checked in by marcosw, 12 years ago (diff)

Ticket #2398 - Compatibilizacao com PHP-5.3 em alguns módulos do expresso

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