Commit 6a8171af159131e5f34dfb5cdb75e88383b00485

Authored by Megan Watson
1 parent 9433000b

BBS-298

"Mac OS X Webdav as 3rd Party Client"
Fixed. Added small fixes in each function for .DS_Store and ._filename resource forks.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen



git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@7604 c91229c3-7414-0410-bfa2-8a42b809f60b
ktwebdav/lib/KTWebDAVServer.inc.php
... ... @@ -6,32 +6,32 @@
6 6 * KnowledgeTree Open Source Edition
7 7 * Document Management Made Simple
8 8 * Copyright (C) 2004 - 2007 The Jam Warehouse Software (Pty) Limited
9   - *
  9 + *
10 10 * This program is free software; you can redistribute it and/or modify it under
11 11 * the terms of the GNU General Public License version 3 as published by the
12 12 * Free Software Foundation.
13   - *
  13 + *
14 14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 17 * details.
18   - *
  18 + *
19 19 * You should have received a copy of the GNU General Public License
20 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21   - *
  21 + *
22 22 * You can contact The Jam Warehouse Software (Pty) Limited, Unit 1, Tramber Place,
23 23 * Blake Street, Observatory, 7925 South Africa. or email info@knowledgetree.com.
24   - *
  24 + *
25 25 * The interactive user interfaces in modified source and object code versions
26 26 * of this program must display Appropriate Legal Notices, as required under
27 27 * Section 5 of the GNU General Public License version 3.
28   - *
  28 + *
29 29 * In accordance with Section 7(b) of the GNU General Public License version 3,
30 30 * these Appropriate Legal Notices must retain the display of the "Powered by
31   - * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
32 32 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
33   - * must display the words "Powered by KnowledgeTree" and retain the original
34   - * copyright notice.
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
35 35 * Contributor( s): ______________________________________
36 36 *
37 37 */
... ... @@ -150,7 +150,6 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
150 150 * @return void
151 151 */
152 152 function KTWebDAVServer() {
153   -
154 153 // CGI compatible auth setup
155 154 $altinfo = KTUtil::arrayGet( $_SERVER, 'kt_auth', KTUtil::arrayGet( $_SERVER, 'REDIRECT_kt_auth'));
156 155 if ( !empty( $altinfo) && !isset( $_SERVER['PHP_AUTH_USER'])) {
... ... @@ -443,17 +442,22 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
443 442  
444 443 $path = $options["path"];
445 444  
446   - // Fix for Mac Clients
  445 + // Fix for the Mac Goliath Client
447 446 // Mac adds DS_Store files when folders are added and ._filename files when files are added
448 447 // The PUT function doesn't add these files to the dms but PROPFIND still looks for the .DS_Store file,
449 448 // and returns an error if not found. We emulate its existence by returning a positive result.
450   - if($this->dav_client == 'MC' || $this->dav_client == 'MG'){
  449 + if($this->dav_client == 'MG'){
451 450 // Remove filename from path
452 451 $aPath = explode('/', $path);
453 452 $fileName = $aPath[count($aPath)-1];
454   -
  453 +
455 454 if(strtolower($fileName) == '.ds_store'){
456   - $this->ktwebdavLog("Using a Mac client. Filename is .DS_Store so we emulate a positive result.", 'info', true);
  455 + $this->ktwebdavLog("Using a Mac client. Filename is .DS_Store so we emulate a positive result.", 'info', true);
  456 + // ignore
  457 + return true;
  458 + }
  459 + if($fileName[0] == '.' && $fileName[1] == '_'){
  460 + $this->ktwebdavLog("Using a Mac client. Filename is ._Filename so we emulate a positive result.", 'info', true);
457 461 // ignore
458 462 return true;
459 463 }
... ... @@ -571,6 +575,10 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
571 575 $this->ktwebdavLog("fspath is " . $fspath, 'info', true);
572 576  
573 577 // create result array
  578 + // Modified - 25/10/07 - spaces prevent files displaying in finder
  579 + if($this->dav_client == 'MC'){
  580 + $path = str_replace('%2F', '/', urlencode($path));
  581 + }
574 582 $info = array();
575 583 $info["path"] = $path;
576 584 $info["props"] = array();
... ... @@ -647,13 +655,18 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
647 655  
648 656 $this->ktwebdavLog("Entering _fileinfoForFolder. Folder is " . print_r($oFolder, true), 'info', true);
649 657  
  658 + // Fix for Mac
  659 + // Modified - 25/10/07 - spaces prevent files displaying in finder
  660 + if($this->dav_client == 'MC'){
  661 + $path = str_replace('%2F', '/', urlencode(utf8_encode($path)));
  662 + }
650 663 // create result array
651 664 $info = array();
652   - $info["path"] = $path;
  665 + $info["path"] = $path;
653 666 $fspath = $default->documentRoot . "/" . $this->rootFolder . $path;
654 667 //$fspath = $default->documentRoot . '/' . $oFolder->generateFolderPath($oFolder->getID());
655   - $info["props"] = array();
656 668  
  669 + $info["props"] = array();
657 670 // no special beautified displayname here ...
658 671 $info["props"][] = $this->mkprop("displayname", $oFolder->getName());
659 672  
... ... @@ -686,7 +699,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
686 699 } else {
687 700 $options["depth"] = "infinity";
688 701 }
689   -
  702 +
690 703 // analyze request payload
691 704 $propinfo = new _parse_propfind("php://input");
692 705 if (!$propinfo->success) {
... ... @@ -821,7 +834,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
821 834 echo " <D:response $ns_defs>\n";
822 835  
823 836 $tempHref = $this->_mergePathes($_SERVER['SCRIPT_NAME'], $path);
824   -
  837 +
825 838 // Ensure collections end in a slash
826 839 if(isset($file['props'])){
827 840 foreach($file['props'] as $v){
... ... @@ -833,9 +846,9 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
833 846 }
834 847 }
835 848 }
836   -
  849 +
837 850 $href = htmlspecialchars($tempHref);
838   -
  851 +
839 852 echo " <D:href>$href</D:href>\n";
840 853  
841 854 $this->ktwebdavLog("\nfile is: " . print_r($file, true), 'info', true);
... ... @@ -991,6 +1004,27 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
991 1004 // get path to requested resource
992 1005 $path = $options["path"];
993 1006  
  1007 + // Fix for Mac Clients
  1008 + // Mac adds DS_Store files when folders are added and ._filename files when files are added
  1009 + // The PUT function doesn't add these files to the dms but PROPFIND still looks for the .DS_Store file,
  1010 + // and returns an error if not found. We emulate its existence by returning a positive result.
  1011 + if($this->dav_client == 'MC' || $this->dav_client == 'MG'){
  1012 + // Remove filename from path
  1013 + $aPath = explode('/', $path);
  1014 + $fileName = $aPath[count($aPath)-1];
  1015 +
  1016 + if(strtolower($fileName) == '.ds_store'){
  1017 + $this->ktwebdavLog("Using a Mac client. Filename is .DS_Store so we emulate a positive result.", 'info', true);
  1018 + // ignore
  1019 + return true;
  1020 + }
  1021 + if($fileName[0] == '.' && $fileName[1] == '_'){
  1022 + $this->ktwebdavLog("Using a Mac client. Filename is ._Filename so we emulate a positive result.", 'info', true);
  1023 + // ignore
  1024 + return true;
  1025 + }
  1026 + }
  1027 +
994 1028 list($iFolderID, $iDocumentID) = $this->_folderOrDocument($path);
995 1029  
996 1030 if ($iDocumentID === false) {
... ... @@ -1223,21 +1257,22 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1223 1257 $this->ktwebdavLog("dav_client is: " . $this->dav_client, 'info', true);
1224 1258  
1225 1259 $path = $options["path"];
1226   -
  1260 +
1227 1261 // Fix for Mac
  1262 + // Modified - 22/10/07
1228 1263 // Mac adds DS_Store files when folders are added and ._filename files when files are added
1229 1264 // we want to ignore them.
1230 1265 if($this->dav_client == 'MC' || $this->dav_client == 'MG'){
1231 1266 // Remove filename from path
1232 1267 $aPath = explode('/', $path);
1233 1268 $fileName = $aPath[count($aPath)-1];
1234   -
  1269 +
1235 1270 if(strtolower($fileName) == '.ds_store'){
1236 1271 $this->ktwebdavLog("Using a mac client. Ignore the .DS_Store files created with every folder.", 'info', true);
1237 1272 // ignore
1238 1273 return "204 No Content";
1239 1274 }
1240   -
  1275 +
1241 1276 if($fileName[0] == '.' && $fileName[1] == '_'){
1242 1277 $fileName = substr($fileName, 2);
1243 1278 $this->ktwebdavLog("Using a mac client. Ignore the ._filename files created with every file.", 'info', true);
... ... @@ -1245,7 +1280,6 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1245 1280 return "204 No Content";
1246 1281 }
1247 1282 }
1248   -
1249 1283  
1250 1284 $res = $this->_folderOrDocument($path);
1251 1285 list($iFolderID, $iDocumentID) = $res;
... ... @@ -1329,7 +1363,13 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1329 1363 'metadata' => array(),
1330 1364 'novalidate' => true,
1331 1365 );
1332   - $oDocument =& KTDocumentUtil::add($oParentFolder, $name, $oUser, $aOptions);
  1366 + $this->ktwebdavLog("DEBUG: overwriting file. Options: ".print_r($aOptions, true));
  1367 + $this->ktwebdavLog("DEBUG: overwriting file. Temp name: ".$sTempFilename.' '.print_r($sTempFilename, true));
  1368 + $this->ktwebdavLog("DEBUG: overwriting file. Name: ".$name.' '.print_r($name, true));
  1369 +
  1370 + // Modified - 25/10/07 - changed add to overwrite
  1371 + //$oDocument =& KTDocumentUtil::add($oParentFolder, $name, $oUser, $aOptions);
  1372 + $oDocument =& KTDocumentUtil::overwrite($oDocument, $name, $sTempFilename, $oUser, $aOptions);
1333 1373  
1334 1374 if(PEAR::isError($oDocument)) {
1335 1375 $this->ktwebdavLog("oDocument ERROR: " . $oDocument->getMessage(), 'info', true);
... ... @@ -1340,7 +1380,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1340 1380 $this->ktwebdavLog("oDocument is " . print_r($oDocument, true), 'info', true);
1341 1381  
1342 1382 unlink($sTempFilename);
1343   - return "204 No Content";
  1383 + return "201 Created";
1344 1384 }
1345 1385  
1346 1386 $options["new"] = true;
... ... @@ -1682,8 +1722,9 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1682 1722 function _MOVEDocument($options, $iFolderID, $iDocumentID) {
1683 1723  
1684 1724 if ($options['dest'] == '') $options["dest"] = substr($options["dest_url"], strlen($_SERVER["SCRIPT_NAME"]));
1685   -
1686   - // Fix for Mac
  1725 +
  1726 + // Fix for Mac Goliath
  1727 + // Modified - 25/10/07 - remove ktwebdav from document path
1687 1728 if($this->dav_client == 'MG'){
1688 1729 $this->ktwebdavLog("Remove ktwebdav from destination path: ".$options['dest'], 'info', true);
1689 1730 if(!(strpos($options['dest'], 'ktwebdav/ktwebdav.php/') === FALSE)){
... ... @@ -1691,9 +1732,9 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1691 1732 }
1692 1733 if($options['dest'][0] != '/'){
1693 1734 $options['dest'] = '/'.$options['dest'];
1694   - }
  1735 + }
1695 1736 }
1696   -
  1737 +
1697 1738 $this->ktwebdavLog("Entering _MOVEDocument. options are " . print_r($options, true), 'info', true);
1698 1739 global $default;
1699 1740 $new = true;
... ... @@ -1840,6 +1881,18 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1840 1881 return "400 Bad request - depth must be 'inifinity'.";
1841 1882 }
1842 1883  
  1884 + // Fix for Mac Goliath
  1885 + // Modified - 30/10/07 - remove ktwebdav from folder path
  1886 + if($this->dav_client == 'MG'){
  1887 + $this->ktwebdavLog("Remove ktwebdav from destination path: ".$options['dest'], 'info', true);
  1888 + if(!(strpos($options['dest'], 'ktwebdav/ktwebdav.php/') === FALSE)){
  1889 + $options['dest'] = substr($options['dest'], 22);
  1890 + }
  1891 + if($options['dest'][0] != '/'){
  1892 + $options['dest'] = '/'.$options['dest'];
  1893 + }
  1894 + }
  1895 +
1843 1896 global $default;
1844 1897  
1845 1898 $source_path = $options["path"];
... ... @@ -2298,9 +2351,15 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
2298 2351  
2299 2352 }
2300 2353 // Mac Finder
2301   - if ($this->dav_client == 'MC') {
  2354 + if ($this->dav_client == 'MC' && $this->safeMode == 'off') {
  2355 +
  2356 + $this->ktwebdavLog("This is Mac Finder type client with SafeMode off.", 'info', true);
  2357 + return true;
  2358 +
  2359 + }
  2360 + if ($this->dav_client == 'MC' && $this->safeMode != 'off') {
2302 2361  
2303   - $this->ktwebdavLog("This is Mac Finder type client which only supports SafeMode.", 'info', true);
  2362 + $this->ktwebdavLog("This is Mac Finder type client with SafeMode on.", 'info', true);
2304 2363 return false;
2305 2364  
2306 2365 }
... ...
lib/documentmanagement/documentutil.inc.php
... ... @@ -295,6 +295,81 @@ class KTDocumentUtil {
295 295 return $oDocument;
296 296 }
297 297  
  298 + // Overwrite the document
  299 + function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) {
  300 + //$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false
  301 + $oStorage =& KTStorageManagerUtil::getSingleton();
  302 + $iFileSize = filesize($sTempFileName);
  303 +
  304 + // Check that document is not checked out
  305 + if($oDocument->getIsCheckedOut()) {
  306 + return PEAR::raiseError(_kt('Document is checkout and cannot be overwritten'));
  307 + }
  308 +
  309 + if (!$oStorage->upload($oDocument, $sTempFileName)) {
  310 + return PEAR::raiseError(_kt('An error occurred while storing the new file'));
  311 + }
  312 +
  313 + $oDocument->setLastModifiedDate(getCurrentDateTime());
  314 + $oDocument->setModifiedUserId($oUser->getId());
  315 +
  316 + $oDocument->setFileSize($iFileSize);
  317 +
  318 + $sOriginalFilename = $oDocument->getFileName();
  319 +
  320 + if($sOriginalFilename != $sFilename){
  321 + if(strlen($sFilename)) {
  322 + global $default;
  323 + $oDocument->setFileName($sFilename);
  324 + $default->log->info('renamed document ' . $oDocument->getId() . ' to ' . $sFilename);
  325 + }
  326 + $oDocument->setMinorVersionNumber($oDocument->getMinorVersionNumber()+1);
  327 + }
  328 +
  329 + $sType = KTMime::getMimeTypeFromFile($sFilename);
  330 + $iMimeTypeId = KTMime::getMimeTypeID($sType, $oDocument->getFileName());
  331 + $oDocument->setMimeTypeId($iMimeTypeId);
  332 +
  333 + $bSuccess = $oDocument->update();
  334 + if ($bSuccess !== true) {
  335 + if (PEAR::isError($bSuccess)) {
  336 + return $bSuccess;
  337 + }
  338 + return PEAR::raiseError(_kt('An error occurred while storing this document in the database'));
  339 + }
  340 +/*
  341 + // create the document transaction record
  342 + $oDocumentTransaction = new DocumentTransaction($oDocument, $sCheckInComment, 'ktcore.transactions.check_in');
  343 + $oDocumentTransaction->create();
  344 +
  345 + $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
  346 + $aTriggers = $oKTTriggerRegistry->getTriggers('content', 'scan');
  347 + foreach ($aTriggers as $aTrigger) {
  348 + $sTrigger = $aTrigger[0];
  349 + $oTrigger = new $sTrigger;
  350 + $oTrigger->setDocument($oDocument);
  351 + $ret = $oTrigger->scan();
  352 + if (PEAR::isError($ret)) {
  353 + $oDocument->delete();
  354 + return $ret;
  355 + }
  356 + }
  357 +
  358 + // NEW SEARCH
  359 +
  360 + Indexer::index($oDocument);
  361 +
  362 +
  363 + // fire subscription alerts for the checked in document
  364 + $oSubscriptionEvent = new SubscriptionEvent();
  365 + $oFolder = Folder::get($oDocument->getFolderID());
  366 + $oSubscriptionEvent->CheckinDocument($oDocument, $oFolder);
  367 +
  368 + KTDocumentUtil::updateSearchableText($oDocument);
  369 +*/
  370 + return true;
  371 + }
  372 +
298 373 // {{{ validateMetadata
299 374 function validateMetadata(&$oDocument, $aMetadata) {
300 375 $aFieldsets =& KTFieldset::getGenericFieldsets();
... ... @@ -477,32 +552,32 @@ class KTDocumentUtil {
477 552 function &_in_add($oFolder, $sFilename, $oUser, $aOptions) {
478 553 $aOrigOptions = $aOptions;
479 554 if (KTDocumentUtil::fileExists($oFolder, $sFilename)) {
480   - $oDoc = Document::getByFilenameAndFolder($sFilename, $oFolder->getId());
481   - if (PEAR::isError($oDoc)) {
482   - return PEAR::raiseError(_kt('Document with that filename already exists in this folder, and appears to be invalid. Please contact the system administrator.'));
483   - } else {
484   - if ($oDoc->getStatusID() != LIVE) {
485   - $sError = _kt('Document with that filename already exists in this folder, but it has been archived or deleted and is still available for restoration. To prevent it being overwritten, you are not allowed to add a document with the same title or filename.');
486   - } else {
487   - $sError = _kt('Document with that filename already exists in this folder.');
488   - }
489   -
490   - $sError .= _kt(' Document') . ': ' . $oDoc->getName() . ' (ID:' . $oDoc->getId() . ')';
491   - return PEAR::raiseError($sError);
492   - }
  555 + $oDoc = Document::getByFilenameAndFolder($sFilename, $oFolder->getId());
  556 + if (PEAR::isError($oDoc)) {
  557 + return PEAR::raiseError(_kt('Document with that filename already exists in this folder, and appears to be invalid. Please contact the system administrator.'));
  558 + } else {
  559 + if ($oDoc->getStatusID() != LIVE) {
  560 + $sError = _kt('Document with that filename already exists in this folder, but it has been archived or deleted and is still available for restoration. To prevent it being overwritten, you are not allowed to add a document with the same title or filename.');
  561 + } else {
  562 + $sError = _kt('Document with that filename already exists in this folder.');
  563 + }
  564 +
  565 + $sError .= _kt(' Document') . ': ' . $oDoc->getName() . ' (ID:' . $oDoc->getId() . ')';
  566 + return PEAR::raiseError($sError);
  567 + }
493 568 }
494 569 $sName = KTUtil::arrayGet($aOptions, 'description', $sFilename);
495 570 if (KTDocumentUtil::nameExists($oFolder, $sName)) {
496   - $oDoc = Document::getByNameAndFolder($sName, $oFolder->getId());
497   - if (PEAR::isError($oDoc)) {
498   - return PEAR::raiseError(_kt('Document with that title already exists in this folder, and appears to be invalid. Please contact the system administrator.'));
499   - } else {
500   - if ($oDoc->getStatusID != LIVE) {
501   - return PEAR::raiseError(_kt('Document with that title already exists in this folder, but it has been archived or deleted and is still available for restoration. To prevent it being overwritten, you are not allowed to add a document with the same title or filename.'));
502   - } else {
503   - return PEAR::raiseError(_kt('Document with that title already exists in this folder.'));
504   - }
505   - }
  571 + $oDoc = Document::getByNameAndFolder($sName, $oFolder->getId());
  572 + if (PEAR::isError($oDoc)) {
  573 + return PEAR::raiseError(_kt('Document with that title already exists in this folder, and appears to be invalid. Please contact the system administrator.'));
  574 + } else {
  575 + if ($oDoc->getStatusID != LIVE) {
  576 + return PEAR::raiseError(_kt('Document with that title already exists in this folder, but it has been archived or deleted and is still available for restoration. To prevent it being overwritten, you are not allowed to add a document with the same title or filename.'));
  577 + } else {
  578 + return PEAR::raiseError(_kt('Document with that title already exists in this folder.'));
  579 + }
  580 + }
506 581  
507 582 }
508 583  
... ... @@ -907,7 +982,6 @@ class KTDocumentUtil {
907 982 $oNewDocument->setIsCheckedOut(false);
908 983 $oNewDocument->setCheckedOutUserID(-1);
909 984  
910   -
911 985 // finally, copy the actual file.
912 986 $oStorage =& KTStorageManagerUtil::getSingleton();
913 987 $res = $oStorage->copy($oDocument, $oNewDocument);
... ...