mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	20954: Calendar Dashlet updates. Fixes: ALF-2907 (meeting workspace issue)
   20968: Minor VersionableAspect fix to onDeleteNode policy firing (follow-on for r19507)
   20981: Removed Install Jammer installers from V3.3.3
   20982: AVMTestSuite - run PurgeTestP after AVMServiceTest (investigating ALF-3611)
   20997: Fix for ALF-2605 - updated share-config-custom.xml.sample and removed obsolete extension files
   21030: Pulled XAMConnector AMP into main 3.3SP3 codeline.  Apart from build changes (incl. EOL), there are no repo changes.
   21032: StoreSelector passes through NodeContentContext allowing stores access to node information
   21036: Fix ALF-245: Can't delete space that contains "translation without content"
      - Delete triggers 'unmakeTranslation'
      - Empty translations are marked with sys:temporary before being deleted
   21051: More on fix ALF-245.  Reduced complexity by not deleting empty translations twice
   21064: Merged V3.3 to V3.3-BUG_FIX
      20898: Merged HEAD to V3.3
         20724: AVMTestSuite - temporarily comment out PurgeTestP
            - TODO: investigate intermittent test failure
      20903: Incremented version revision
      20921: AVM - fix purge store so that vr nodes are actually orphaned (ALF-3627)
      20952: Fix for ALF-3704: Module conflict - Alfresco web client config property page missing metadata. 
         This is application of a fix made to the config service in a hotfix. The change provides a deterministic load order for config files loaded via the ConfigBootstrap spring bean. More importantly it means that config files loaded by modules on different machines in a cluster load in the same order.
         The forms client and AWE config files have been updated to take advantage of the new loading order.
      21061: Merged PATCHES/V3.1.2 to V3.3 (RECORD ONLY)
         20890: ALF-3687: Apply LUCENE-1383 patch to Lucene 2.1.0 to reduce memory leaks from ThreadLocals
         20891: ALF-3687: Build classpath fix
         20892: Incremented version label
      21062: Merged PATCHES/V3.2.1 to V3.3
         20897: (RECORD ONLY) Incremented version label
         20901: (RECORD ONLY) ALF-3740: Merged V3.3 to PATCHES/V3.2.1
            20524: VersionMigrator - option to run as scheduled job (ALF-1000)
         20904: (RECORD ONLY) ALF-3732: Merged PATCHES/V3.2.r to PATCHES/V3.2.1
            19803: ALF-558: File servers (CIFS / FTP / NFS) can now handle concurrent write operations on Alfresco repository
               - ContentDiskDriver / AVMDiskDriver now use retrying transactions for write operations
               - Disable EagerContentStoreCleaner on ContentDiskDriver / AVMDiskDriver closeFile() operations so that they may be retried after rollback (Sony zero byte problem)
               - Allow manual association of AVM ContentData with nodes so that closeFile() may be retried
               - Propagation of new argument through AVM interfaces
         20905: (RECORD ONLY) ALF-3732: Rolled back the now unnecessary reference()/dereference() stuff from ALF-558
         20906: (RECORD ONLY) ALF-3732: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.2.1
            20623: Fix for ALF-3188 : Access Denied when updating doc via CIFS
         20907: (RECORD ONLY) ALF-3732: Merged V3.3 to PATCHES/V3.2.1
            20173: Propagate IOExceptions from retryable write transactions in AlfrescoDiskDriver
         20950: ALF-3779: Upgrades on large repositories from v2.1 and v2.2 were failing on MySQL due to "The total number of locks exceeds the lock table size" errors
            - Solution was to add support for new --BEGIN TXN and --END TXN comments and execute LOCK TABLES statements in the same transaction as large INSERT - SELECT statements.
         20990: ALF-3789: Concurrency issues with InMemoryTicketComponentImpl
            - Previous ETHREEOH-1842 method of caching web session 'ref counts' against tickets could cause tickets to unpredictably fall out of the transactional cache
            - Rolled back original ETHREEOH-1842 fix. Would be too much overhead to keep these ref counts consistent across a cluster.
            - Instead, avoid invalidating tickets on web session timeout and only do it on explicit log out.
            - Now tickets maintained in non-transactional shared cache so they can't drop out unpredictably
            - Logic for ticket inactivity timeout caching improved so that it should work across a cluster
         20991: (RECORD ONLY) Incremented version label
         20993: ALF-3789: Fixed Spring configuration backward compatibily issue with previous fix
            - Ticket cache bean name restored to ticketsCache. This is actually now a non-transactional cache.
            - Also externalized parameters so that they can now be controlled by alfresco-global.properties without any bean overrides
               authentication.ticket.ticketsExpire=false
               authentication.ticket.expiryMode=AFTER_FIXED_TIME
               authentication.ticket.validDuration=PT1H
         20994: Eclipse classpath fixes for unit testing after ant build
         21057: ALF-3592: PassthruCifsAuthenticator now auto-creates / imports users who do not already exist in Alfresco
            - At least one of the following properties must be true for this to happen
               synchronization.autoCreatePeopleOnLogin
               synchronization.syncWhenMissingPeopleLogIn
            - Also improved debug logging of unknown passthru domains
      21063: Merged PATCHES/V3.2.r to V3.3
         21037: ALF-3793: Final attempt at realigning saved XForm data with a modified Schema
            - removeRemovedNodes / insertUpdatedNodes / insertPrototypeNodes replaced by a one stop recursive process that builds a new instance tree from scratch
            - Nodes copied over in correct order
            - Missing nodes added in and extra nodes discarded
            - Prototype nodes appended at appropriate points
         21038: (RECORD ONLY) Incremented version label
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21065 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
	
		
			
				
	
	
		
			789 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			789 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2005-2010 Alfresco Software Limited.
 | |
|  *
 | |
|  * This file is part of Alfresco
 | |
|  *
 | |
|  * Alfresco is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU Lesser General Public License as published by
 | |
|  * the Free Software Foundation, either version 3 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * Alfresco is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public License
 | |
|  * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| package org.alfresco.filesys.repo;
 | |
| 
 | |
| import java.io.FileNotFoundException;
 | |
| 
 | |
| import org.alfresco.filesys.alfresco.AlfrescoClientInfo;
 | |
| import org.alfresco.filesys.alfresco.AlfrescoContext;
 | |
| import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
 | |
| import org.alfresco.filesys.alfresco.DesktopAction;
 | |
| import org.alfresco.filesys.alfresco.DesktopActionTable;
 | |
| import org.alfresco.filesys.alfresco.DesktopParams;
 | |
| import org.alfresco.filesys.alfresco.DesktopResponse;
 | |
| import org.alfresco.filesys.alfresco.DesktopTarget;
 | |
| import org.alfresco.filesys.alfresco.IOControl;
 | |
| import org.alfresco.filesys.alfresco.IOControlHandler;
 | |
| import org.alfresco.jlan.server.SrvSession;
 | |
| import org.alfresco.jlan.server.auth.ClientInfo;
 | |
| import org.alfresco.jlan.server.filesys.IOControlNotImplementedException;
 | |
| import org.alfresco.jlan.server.filesys.NetworkFile;
 | |
| import org.alfresco.jlan.server.filesys.TreeConnection;
 | |
| import org.alfresco.jlan.smb.SMBException;
 | |
| import org.alfresco.jlan.smb.SMBStatus;
 | |
| import org.alfresco.jlan.smb.nt.NTIOCtl;
 | |
| import org.alfresco.jlan.util.DataBuffer;
 | |
| import org.alfresco.model.ContentModel;
 | |
| import org.alfresco.repo.security.authentication.AuthenticationException;
 | |
| import org.alfresco.service.cmr.lock.LockType;
 | |
| import org.alfresco.service.cmr.repository.ContentData;
 | |
| import org.alfresco.service.cmr.repository.NodeRef;
 | |
| import org.alfresco.service.cmr.repository.NodeService;
 | |
| import org.alfresco.service.cmr.security.AuthenticationService;
 | |
| import org.alfresco.service.transaction.TransactionService;
 | |
| import org.apache.commons.logging.Log;
 | |
| import org.apache.commons.logging.LogFactory;
 | |
| 
 | |
| /**
 | |
|  * Content Disk Driver I/O Control Handler Class
 | |
|  *
 | |
|  * <p>Provides the custom I/O control code handling used by the CIFS client interface application.
 | |
|  * 
 | |
|  * @author gkspencer
 | |
|  */
 | |
| public class ContentIOControlHandler implements IOControlHandler
 | |
| {
 | |
|     // Logging
 | |
|     
 | |
|     private static final Log logger = LogFactory.getLog(ContentIOControlHandler.class);
 | |
|     
 | |
|     // Filesystem driver and context
 | |
|     
 | |
|     private ContentDiskDriver contentDriver;
 | |
|     private ContentContext contentContext;
 | |
|     
 | |
|     /**
 | |
|      * Default constructor
 | |
|      */
 | |
|     public ContentIOControlHandler()
 | |
|     {
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Initalize the I/O control handler
 | |
|      *
 | |
|      * @param filesysDriver AlfrescoDiskDriver
 | |
|      * @param context AlfrescoContext
 | |
|      */
 | |
|     public void initialize( AlfrescoDiskDriver filesysDriver, AlfrescoContext context)
 | |
|     {
 | |
|         this.contentDriver  = (ContentDiskDriver) filesysDriver;
 | |
|         this.contentContext = (ContentContext) context;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the CIFS helper
 | |
|      * 
 | |
|      * @return CifsHelper
 | |
|      */
 | |
|     public final CifsHelper getCifsHelper()
 | |
|     {
 | |
|     	return contentDriver.getCifsHelper();
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Return the authentication service
 | |
|      * 
 | |
|      * @return AuthenticationService
 | |
|      */
 | |
|     public final AuthenticationService getAuthenticationService()
 | |
|     {
 | |
|     	return contentDriver.getAuthenticationService();
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Return the transaction service
 | |
|      * 
 | |
|      * @return TransactionService
 | |
|      */
 | |
|     public final TransactionService getTransactionService()
 | |
|     {
 | |
|     	return contentDriver.getTransactionService();
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Return the node service
 | |
|      * 
 | |
|      * @return NodeService
 | |
|      */
 | |
|     public final NodeService getNodeService()
 | |
|     {
 | |
|     	return contentDriver.getNodeService();
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Return the filesystem driver
 | |
|      * 
 | |
|      * @return ContentDiskDriver
 | |
|      */
 | |
|     public final ContentDiskDriver getContentDriver()
 | |
|     {
 | |
|     	return contentDriver;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Return the filesystem context
 | |
|      * 
 | |
|      * @return ContentContext
 | |
|      */
 | |
|     public final ContentContext getContentContext()
 | |
|     {
 | |
|     	return contentContext;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Process a filesystem I/O control request
 | |
|      * 
 | |
|      * @param sess Server session
 | |
|      * @param tree Tree connection.
 | |
|      * @param ctrlCode I/O control code
 | |
|      * @param fid File id
 | |
|      * @param dataBuf I/O control specific input data
 | |
|      * @param isFSCtrl true if this is a filesystem control, or false for a device control
 | |
|      * @param filter if bit0 is set indicates that the control applies to the share root handle
 | |
|      * @return DataBuffer
 | |
|      * @exception IOControlNotImplementedException
 | |
|      * @exception SMBException
 | |
|      */
 | |
|     public org.alfresco.jlan.util.DataBuffer processIOControl(SrvSession sess, TreeConnection tree, int ctrlCode, int fid, DataBuffer dataBuf,
 | |
|             boolean isFSCtrl, int filter)
 | |
|         throws IOControlNotImplementedException, SMBException
 | |
|     {
 | |
|         // Validate the file id
 | |
|         
 | |
|         NetworkFile netFile = tree.findFile(fid);
 | |
|         if ( netFile == null || netFile.isDirectory() == false)
 | |
|             throw new SMBException(SMBStatus.NTErr, SMBStatus.NTInvalidParameter);
 | |
|         
 | |
|         // Split the control code
 | |
|         
 | |
|         int devType = NTIOCtl.getDeviceType(ctrlCode);
 | |
|         int ioFunc  = NTIOCtl.getFunctionCode(ctrlCode);
 | |
|         
 | |
|         // Check for I/O controls that require a success status
 | |
|         
 | |
|         if ( devType == NTIOCtl.DeviceFileSystem)
 | |
|         {
 | |
| 	        // I/O control requests that require a success status
 | |
| 	        //
 | |
| 	        // Create or get object id
 | |
| 	        	
 | |
| 	        if ( ioFunc == NTIOCtl.FsCtlCreateOrGetObjectId)
 | |
| 	        	return null;
 | |
|         }
 | |
|         
 | |
|         // Check if the I/O control looks like a custom I/O control request
 | |
|         
 | |
|         if ( devType != NTIOCtl.DeviceFileSystem || dataBuf == null)
 | |
|             throw new IOControlNotImplementedException();
 | |
|         
 | |
|         // Check if the request has a valid signature for an Alfresco CIFS server I/O control
 | |
|         
 | |
|         if ( dataBuf.getLength() < IOControl.Signature.length())
 | |
|             throw new IOControlNotImplementedException("Bad request length");
 | |
|         
 | |
|         String sig = dataBuf.getFixedString(IOControl.Signature.length(), false);
 | |
|         
 | |
|         if ( sig == null || sig.compareTo(IOControl.Signature) != 0)
 | |
|             throw new IOControlNotImplementedException("Bad request signature");
 | |
|         
 | |
|         // Get the node for the parent folder, make sure it is a folder
 | |
|         
 | |
|         NodeRef folderNode = null;
 | |
|         
 | |
|         try
 | |
|         {
 | |
|             folderNode = contentDriver.getNodeForPath(tree, netFile.getFullName());
 | |
|             
 | |
|             if ( getCifsHelper().isDirectory( folderNode) == false)
 | |
|                 folderNode = null;
 | |
|         }
 | |
|         catch ( FileNotFoundException ex)
 | |
|         {
 | |
|             folderNode = null;
 | |
|         }
 | |
| 
 | |
|         // If the folder node is not valid return an error
 | |
|         
 | |
|         if ( folderNode == null)
 | |
|             throw new SMBException(SMBStatus.NTErr, SMBStatus.NTAccessDenied);
 | |
|         
 | |
|         // Debug
 | |
|         
 | |
|         if ( logger.isDebugEnabled()) {
 | |
|             logger.debug("IO control func=0x" + Integer.toHexString(ioFunc) + ", fid=" + fid + ", buffer=" + dataBuf);
 | |
|             logger.debug("  Folder nodeRef=" + folderNode);
 | |
|         }
 | |
| 
 | |
|         // Check if the I/O control code is one of our custom codes
 | |
| 
 | |
|         DataBuffer retBuffer = null;
 | |
|         
 | |
|         switch ( ioFunc)
 | |
|         {
 | |
| 	        // Probe to check if this is an Alfresco CIFS server
 | |
| 	        
 | |
| 	        case IOControl.CmdProbe:
 | |
| 	            
 | |
| 	            // Return a buffer with the signature and protocol version
 | |
| 	            
 | |
| 	            retBuffer = new DataBuffer(IOControl.Signature.length());
 | |
| 	            retBuffer.putFixedString(IOControl.Signature, IOControl.Signature.length());
 | |
| 	            retBuffer.putInt(DesktopAction.StsSuccess);
 | |
| 	            retBuffer.putInt(IOControl.Version);
 | |
| 	            break;
 | |
| 	            
 | |
| 	        // Get file information for a file within the current folder
 | |
| 	            
 | |
| 	        case IOControl.CmdFileStatus:
 | |
| 	
 | |
| 	            // Process the file status request
 | |
| 	            
 | |
| 	            retBuffer = procIOFileStatus( sess, tree, dataBuf, folderNode);
 | |
| 	            break;
 | |
| 	
 | |
| 	        // Get action information for the specified executable path
 | |
| 	            
 | |
| 	        case IOControl.CmdGetActionInfo:
 | |
| 	        	
 | |
| 	        	// Process the get action information request
 | |
| 	        	
 | |
| 	        	retBuffer = procGetActionInfo(sess, tree, dataBuf, folderNode, netFile);
 | |
| 	        	break;
 | |
| 	        	
 | |
| 	        // Run the named action
 | |
| 	        	
 | |
| 	        case IOControl.CmdRunAction:
 | |
| 	
 | |
| 	        	// Process the run action request
 | |
| 	        	
 | |
| 	        	retBuffer = procRunAction(sess, tree, dataBuf, folderNode, netFile);
 | |
| 	        	break;
 | |
| 
 | |
| 	        // Return the authentication ticket
 | |
| 	        	
 | |
| 	        case IOControl.CmdGetAuthTicket:
 | |
| 	        	
 | |
| 	        	// Process the get auth ticket request
 | |
| 	        	
 | |
| 	        	retBuffer = procGetAuthTicket(sess, tree, dataBuf, folderNode, netFile);
 | |
| 	        	break;
 | |
| 	        	
 | |
| 	        // Unknown I/O control code
 | |
| 	            
 | |
| 	        default:
 | |
| 	            throw new IOControlNotImplementedException();
 | |
|         }
 | |
|         
 | |
|         // Return the reply buffer, may be null
 | |
|         
 | |
|         return retBuffer;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Process the file status I/O request
 | |
|      * 
 | |
|      * @param sess Server session
 | |
|      * @param tree Tree connection
 | |
|      * @param reqBuf Request buffer
 | |
|      * @param folderNode NodeRef of parent folder
 | |
|      * @return DataBuffer
 | |
|      */
 | |
|     private final DataBuffer procIOFileStatus( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode)
 | |
|     {
 | |
|         // Start a transaction
 | |
|         
 | |
|         contentDriver.beginReadTransaction( sess);
 | |
|         
 | |
|         // Get the file name from the request
 | |
|         
 | |
|         String fName = reqBuf.getString( true);
 | |
| 
 | |
|         if ( logger.isDebugEnabled())
 | |
|         	logger.debug("  File status, fname=" + fName);
 | |
| 
 | |
|         // Create a response buffer
 | |
|         
 | |
|         DataBuffer respBuf = new DataBuffer(256);
 | |
|         respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
 | |
|         
 | |
|         // Get the node for the file/folder
 | |
|         
 | |
|         NodeRef childNode = null;
 | |
|         
 | |
|         try
 | |
|         {
 | |
|             childNode = getCifsHelper().getNodeRef( folderNode, fName);
 | |
|         }
 | |
|         catch (FileNotFoundException ex)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         // Check if the file/folder was found
 | |
|         
 | |
|         if ( childNode == null)
 | |
|         {
 | |
|             // Return an error response
 | |
|             
 | |
|             respBuf.putInt(DesktopAction.StsFileNotFound);
 | |
|             return respBuf;
 | |
|         }
 | |
| 
 | |
|         // Check if this is a file or folder node
 | |
|         
 | |
|         if ( getCifsHelper().isDirectory( childNode))
 | |
|         {
 | |
|             // Only return the status and node type for folders
 | |
|             
 | |
|             respBuf.putInt(DesktopAction.StsSuccess);
 | |
|             respBuf.putInt(IOControl.TypeFolder);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // Indicate that this is a file node
 | |
|             
 | |
|             respBuf.putInt(DesktopAction.StsSuccess);
 | |
|             respBuf.putInt(IOControl.TypeFile);
 | |
| 
 | |
|             // Check if this file is a working copy
 | |
|             
 | |
|             if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
 | |
|             {
 | |
|                 // Indicate that this is a working copy
 | |
|                 
 | |
|                 respBuf.putInt(IOControl.True);
 | |
|                 
 | |
|                 // Get the owner username and file it was copied from
 | |
|                 
 | |
|                 String owner = (String) getNodeService().getProperty( childNode, ContentModel.PROP_WORKING_COPY_OWNER);
 | |
|                 String copiedFrom = null;
 | |
|                 
 | |
|                 if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_COPIEDFROM))
 | |
|                 {
 | |
|                     // Get the path of the file the working copy was generated from
 | |
|                     
 | |
|                     NodeRef fromNode = (NodeRef) getNodeService().getProperty( childNode, ContentModel.PROP_COPY_REFERENCE);
 | |
|                     if ( fromNode != null)
 | |
|                         copiedFrom = (String) getNodeService().getProperty( fromNode, ContentModel.PROP_NAME);
 | |
|                 }
 | |
|                 
 | |
|                 // Pack the owner and copied from values
 | |
|                 
 | |
|                 respBuf.putString(owner != null ? owner : "", true, true);
 | |
|                 respBuf.putString(copiedFrom != null ? copiedFrom : "", true, true);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // Not a working copy
 | |
|                 
 | |
|                 respBuf.putInt(IOControl.False);
 | |
|             }
 | |
|             
 | |
|             // Check the lock status of the file
 | |
|             
 | |
|             if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_LOCKABLE))
 | |
|             {
 | |
|                 // Get the lock type and owner
 | |
|                 
 | |
|                 String lockTypeStr = (String) getNodeService().getProperty( childNode, ContentModel.PROP_LOCK_TYPE);
 | |
|                 String lockOwner = null;
 | |
|                 
 | |
|                 if ( lockTypeStr != null)
 | |
|                     lockOwner = (String) getNodeService().getProperty( childNode, ContentModel.PROP_LOCK_OWNER);
 | |
|                 
 | |
|                 // Pack the lock type, and owner if there is a lock on the file
 | |
|                 
 | |
|                 if ( lockTypeStr == null)
 | |
|                     respBuf.putInt(IOControl.LockNone);
 | |
|                 else
 | |
|                 {
 | |
|                     LockType lockType = LockType.valueOf( lockTypeStr);
 | |
|                     
 | |
|                     respBuf.putInt(lockType == LockType.READ_ONLY_LOCK ? IOControl.LockRead : IOControl.LockWrite);
 | |
|                     respBuf.putString(lockOwner != null ? lockOwner : "", true, true);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // File is not lockable
 | |
|                 
 | |
|                 respBuf.putInt(IOControl.LockNone);
 | |
|             }
 | |
|             
 | |
|             // Get the content data details for the file
 | |
|             
 | |
|             ContentData contentData = (ContentData) getNodeService().getProperty( childNode, ContentModel.PROP_CONTENT);
 | |
|             
 | |
|             if ( contentData != null)
 | |
|             {
 | |
|                 // Get the content mime-type
 | |
|                 
 | |
|                 String mimeType = contentData.getMimetype();
 | |
|                 
 | |
|                 // Pack the content length and mime-type
 | |
| 
 | |
|                 respBuf.putInt( IOControl.True);
 | |
|                 respBuf.putLong( contentData.getSize());
 | |
|                 respBuf.putString( mimeType != null ? mimeType : "", true, true);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // File does not have any content
 | |
|                 
 | |
|                 respBuf.putInt( IOControl.False);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         // Return the response
 | |
|         
 | |
|         return respBuf;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Process the get action information request
 | |
|      * 
 | |
|      * @param sess Server session
 | |
|      * @param tree Tree connection
 | |
|      * @param reqBuf Request buffer
 | |
|      * @param folderNode NodeRef of parent folder
 | |
|      * @param netFile NetworkFile for the folder
 | |
|      * @return DataBuffer
 | |
|      */
 | |
|     private final DataBuffer procGetActionInfo( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
 | |
|             NetworkFile netFile)
 | |
|     {
 | |
|         // Get the executable file name from the request
 | |
|         
 | |
|         String exeName = reqBuf.getString( true);
 | |
| 
 | |
|         if ( logger.isDebugEnabled())
 | |
|         	logger.debug("  Get action info, exe=" + exeName);
 | |
| 
 | |
|         // Create a response buffer
 | |
|         
 | |
|         DataBuffer respBuf = new DataBuffer(256);
 | |
|         respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
 | |
|         
 | |
|         // Get the desktop actions list
 | |
|         
 | |
|         DesktopActionTable deskActions = contentContext.getDesktopActions();
 | |
|         if ( deskActions == null)
 | |
|         {
 | |
|         	respBuf.putInt(DesktopAction.StsNoSuchAction);
 | |
|         	return respBuf;
 | |
|         }
 | |
|         
 | |
|         // Convert the executable name to an action name
 | |
|         
 | |
|         DesktopAction deskAction = deskActions.getActionViaPseudoName(exeName);
 | |
|         if ( deskAction == null)
 | |
|         {
 | |
|         	respBuf.putInt(DesktopAction.StsNoSuchAction);
 | |
|         	return respBuf;
 | |
|         }
 | |
|         
 | |
|         // Return the desktop action details
 | |
|         
 | |
|         respBuf.putInt(DesktopAction.StsSuccess);
 | |
|         respBuf.putString(deskAction.getName(), true);
 | |
|         respBuf.putInt(deskAction.getAttributes());
 | |
|         respBuf.putInt(deskAction.getPreProcessActions());
 | |
|         
 | |
|         String confirmStr = deskAction.getConfirmationString();
 | |
|         respBuf.putString(confirmStr != null ? confirmStr : "", true);
 | |
|         
 | |
|         // Return the response
 | |
|         
 | |
|         return respBuf;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Process the run action request
 | |
|      * 
 | |
|      * @param sess Server session
 | |
|      * @param tree Tree connection
 | |
|      * @param reqBuf Request buffer
 | |
|      * @param folderNode NodeRef of parent folder
 | |
|      * @param netFile NetworkFile for the folder
 | |
|      * @return DataBuffer
 | |
|      */
 | |
|     private final DataBuffer procRunAction( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
 | |
|             NetworkFile netFile)
 | |
|     {
 | |
|     	// Get the name of the action to run
 | |
|     	
 | |
|     	String actionName = reqBuf.getString(true);
 | |
|     	
 | |
|     	if ( logger.isDebugEnabled())
 | |
|     		logger.debug("  Run action, name=" + actionName);
 | |
| 
 | |
|         // Create a response buffer
 | |
|         
 | |
|         DataBuffer respBuf = new DataBuffer(256);
 | |
|         respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
 | |
|         
 | |
|     	// Find the action handler
 | |
|     	
 | |
|         DesktopActionTable deskActions = contentContext.getDesktopActions();
 | |
|         DesktopAction action = null;
 | |
|         
 | |
|         if ( deskActions != null)
 | |
|         	action = deskActions.getAction(actionName);
 | |
| 
 | |
|         if ( action == null)
 | |
|         {
 | |
|         	respBuf.putInt(DesktopAction.StsNoSuchAction);
 | |
|         	respBuf.putString("", true);
 | |
|         	return respBuf;
 | |
|         }
 | |
| 
 | |
|         // Start a transaction
 | |
|         
 | |
|         contentDriver.beginReadTransaction( sess);
 | |
| 
 | |
|         // Get an authentication ticket for the client, or validate the existing ticket. The ticket can be used when
 | |
|         // generating URLs for the client-side application so that the user does not have to re-authenticate
 | |
|         
 | |
|         getTicketForClient( sess);
 | |
|         
 | |
|         // Get the list of targets for the action
 | |
|         
 | |
|         int targetCnt = reqBuf.getInt();
 | |
|         DesktopParams deskParams = new DesktopParams(sess, contentDriver, folderNode, netFile);
 | |
|         
 | |
|         while ( reqBuf.getAvailableLength() > 4 && targetCnt > 0)
 | |
|         {
 | |
|         	// Get the desktop target details
 | |
|         	
 | |
|         	int typ = reqBuf.getInt();
 | |
|         	String path = reqBuf.getString(true);
 | |
|         	
 | |
|         	DesktopTarget target = new DesktopTarget(typ, path);
 | |
|         	deskParams.addTarget(target);
 | |
|         	
 | |
|         	// Find the node for the target path
 | |
|         	
 | |
|             NodeRef childNode = null;
 | |
|             
 | |
|             try
 | |
|             {
 | |
|             	// Check if the target path is relative to the folder we are working in or the root of the filesystem
 | |
|             	
 | |
|             	if ( path.startsWith("\\"))
 | |
|             	{
 | |
|             		// Path is relative to the root of the filesystem
 | |
|             		
 | |
|             		childNode = getCifsHelper().getNodeRef(contentContext.getRootNode(), path);
 | |
|             	}
 | |
|             	else
 | |
|             	{
 | |
|             		// Path is relative to the folder we are working in
 | |
|             	
 | |
|             		childNode = getCifsHelper().getNodeRef( folderNode, path);
 | |
|             	}
 | |
|             }
 | |
|             catch (FileNotFoundException ex)
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             // If the node is not valid then return an error status
 | |
|             
 | |
|             if (childNode != null)
 | |
|             {
 | |
|             	// Set the node ref for the target
 | |
|             	
 | |
|             	target.setNode(childNode);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|             	// Build an error response
 | |
|             	
 | |
|             	respBuf.putInt(DesktopAction.StsFileNotFound);
 | |
|             	respBuf.putString("Cannot find noderef for path " + path, true);
 | |
|             	
 | |
|             	return respBuf;
 | |
|             }
 | |
|             
 | |
|         	// Update the target count
 | |
|         	
 | |
|         	targetCnt--;
 | |
|         }
 | |
|         
 | |
|         // DEBUG
 | |
|         
 | |
|         if (logger.isDebugEnabled())
 | |
|         {
 | |
|         	logger.debug("    Desktop params: " + deskParams.numberOfTargetNodes());
 | |
|         	for ( int i = 0; i < deskParams.numberOfTargetNodes(); i++) {
 | |
|         		DesktopTarget target = deskParams.getTarget(i);
 | |
|         		logger.debug("      " + target);
 | |
|         	}
 | |
|         }
 | |
|         
 | |
|         // Run the desktop action
 | |
|         
 | |
|         DesktopResponse deskResponse = null;
 | |
|         
 | |
|         try
 | |
|         {
 | |
|         	// Run the desktop action
 | |
|         	
 | |
|         	deskResponse = action.runAction(deskParams);
 | |
|         }
 | |
|         catch (Exception ex)
 | |
|         {
 | |
|         	// Create an error response
 | |
|         	
 | |
|         	deskResponse = new DesktopResponse(DesktopAction.StsError, ex.getMessage());
 | |
|         }
 | |
|         
 | |
|         // Pack the action response
 | |
|         
 | |
|         if ( deskResponse != null)
 | |
|         {
 | |
|         	// Pack the status
 | |
|         	
 | |
|         	respBuf.putInt(deskResponse.getStatus());
 | |
|         	respBuf.putString(deskResponse.hasStatusMessage() ? deskResponse.getStatusMessage() : "", true);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|         	// Pack an error response
 | |
|         	
 | |
|         	respBuf.putInt(DesktopAction.StsError);
 | |
|         	respBuf.putString("Action did not return response", true);
 | |
|         }
 | |
|         
 | |
|         // Return the response
 | |
|         
 | |
|     	return respBuf;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Process the get authentication ticket request
 | |
|      * 
 | |
|      * @param sess Server session
 | |
|      * @param tree Tree connection
 | |
|      * @param reqBuf Request buffer
 | |
|      * @param folderNode NodeRef of parent folder
 | |
|      * @param netFile NetworkFile for the folder
 | |
|      * @return DataBuffer
 | |
|      */
 | |
|     private final DataBuffer procGetAuthTicket( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
 | |
|             NetworkFile netFile)
 | |
|     {
 | |
|     	// DEBUG
 | |
|     	
 | |
|     	if ( logger.isDebugEnabled())
 | |
|     		logger.debug("  Get Auth Ticket");
 | |
| 
 | |
|         // Create a response buffer
 | |
|         
 | |
|         DataBuffer respBuf = new DataBuffer(256);
 | |
|         respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
 | |
|         
 | |
|         // Start a transaction
 | |
|         
 | |
|         contentDriver.beginReadTransaction( sess);
 | |
| 
 | |
|         // Get an authentication ticket for the client, or validate the existing ticket. The ticket can be used when
 | |
|         // generating URLs for the client-side application so that the user does not have to re-authenticate
 | |
|         
 | |
|         getTicketForClient( sess);
 | |
| 
 | |
|         // Pack the response
 | |
|         
 | |
|         AlfrescoClientInfo cInfo = (AlfrescoClientInfo) sess.getClientInformation();
 | |
|         
 | |
|         if ( cInfo != null && cInfo.getAuthenticationTicket() != null) {
 | |
|             respBuf.putInt(DesktopAction.StsAuthTicket);
 | |
|         	respBuf.putString( cInfo.getAuthenticationTicket(), true);
 | |
|         }
 | |
|         else {
 | |
|             respBuf.putInt(DesktopAction.StsError);
 | |
|         	respBuf.putString( "Client information invalid", true);
 | |
|         }
 | |
| 
 | |
|         // Return the response
 | |
|         
 | |
|         return respBuf;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Get, or validate, an authentication ticket for the client
 | |
|      * 
 | |
|      * @param sess SrvSession
 | |
|      */
 | |
|     private final void getTicketForClient(SrvSession sess)
 | |
|     {
 | |
|     	// Get the client information and check if there is a ticket allocated
 | |
|     	
 | |
|     	AlfrescoClientInfo cInfo = (AlfrescoClientInfo) sess.getClientInformation();
 | |
|     	if ( cInfo == null)
 | |
|     		return;
 | |
|     	
 | |
|     	boolean needTicket = true;
 | |
|     	
 | |
|     	if ( cInfo.hasAuthenticationTicket())
 | |
|     	{
 | |
|     		// Validate the existing ticket, it may have expired
 | |
|     		
 | |
|     		try
 | |
|     		{
 | |
|     			// Validate the existing ticket
 | |
|     			
 | |
|     			getAuthenticationService().validate( cInfo.getAuthenticationTicket());
 | |
|     			needTicket = false;
 | |
|     		}
 | |
|     		catch ( AuthenticationException ex)
 | |
|     		{
 | |
|     			// Invalidate the current ticket
 | |
|     			
 | |
|     			try
 | |
|     			{
 | |
|     				getAuthenticationService().invalidateTicket( cInfo.getAuthenticationTicket());
 | |
|     				cInfo.setAuthenticationTicket( null);
 | |
|     			}
 | |
|     			catch (Exception ex2)
 | |
|     			{
 | |
|     				// DEBUG
 | |
|     				
 | |
|     				if ( logger.isDebugEnabled())
 | |
|     					logger.debug("Error during invalidate ticket", ex2);
 | |
|     			}
 | |
|     			
 | |
|     			// DEBUG
 | |
|     			
 | |
|     			if ( logger.isDebugEnabled())
 | |
|     				logger.debug("Auth ticket expired or invalid");
 | |
|     		}
 | |
|     	}
 | |
|     	
 | |
|     	// Check if a ticket needs to be allocated
 | |
|     	
 | |
|     	if ( needTicket == true)
 | |
|     	{
 | |
|     		// Allocate a new ticket and store in the client information for this session
 | |
|     		
 | |
|    			String ticket = getAuthenticationService().getCurrentTicket();
 | |
|    			cInfo.setAuthenticationTicket( ticket);
 | |
|     	}
 | |
|     }
 | |
| }
 |