Ejemplo n.º 1
0
        public void RemoteFolderDeletion(string ignoredCanonicalName, string ignoredLocalPath, string remoteFolderPath,
                                         string url, string user, string password, string repositoryId)
        {
            // Prepare remote folder and CmisSync process.
            IFolder remoteBaseFolder = ClearRemoteCMISFolder(url, user, password, repositoryId, remoteFolderPath);

            sync = new CmisSyncProcess(remoteFolderPath, url, user, password, repositoryId);

            // Create remote folder
            string foldername = "folder1";
            IDictionary <string, object> properties = new Dictionary <string, object>();

            properties[PropertyIds.Name]         = foldername;
            properties[PropertyIds.ObjectTypeId] = "cmis:folder";

            IFolder folder = remoteBaseFolder.CreateFolder(properties);

            // Wait for a few seconds so that sync gets a chance to sync things.
            Thread.Sleep(20 * 1000);

            // Check locally
            Assert.True(Directory.Exists(Path.Combine(sync.Folder(), (String)properties[PropertyIds.Name])));

            // Delete the folder.
            folder.DeleteTree(true, null, true);

            // Wait for 10 seconds so that sync gets a chance to sync things.
            Thread.Sleep(10 * 1000);

            // Check locally
            Assert.False(Directory.Exists(Path.Combine(sync.Folder(), (String)properties[PropertyIds.Name])));
        }
Ejemplo n.º 2
0
        public void RemovingRemoteFolderAndAddingADocumentToItShouldThrowException(
            string canonical_name,
            string localPath,
            string remoteFolderPath,
            string url,
            string user,
            string password,
            string repositoryId,
            string binding)
        {
            string   subFolderName = "subFolder";
            ISession session       = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding);

            try {
                IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder;
                if (dir != null)
                {
                    dir.DeleteTree(true, null, true);
                }
            } catch (CmisObjectNotFoundException) {
            }

            IFolder folder                = (IFolder)session.GetObjectByPath(remoteFolderPath);
            IFolder subFolder             = folder.CreateFolder(subFolderName);
            IFolder subFolderInstanceCopy = (IFolder)session.GetObject(subFolder.Id);

            subFolder.DeleteTree(true, null, true);

            Assert.Throws <CmisObjectNotFoundException>(() => subFolderInstanceCopy.CreateDocument("testFile.bin", "testContent"));
        }
Ejemplo n.º 3
0
            /// <summary>
            /// Sync deletions.
            /// </summary>
            private void WatchSyncDelete(string remoteFolder, string localFolder, string pathname)
            {
                sleepWhileSuspended();

                string filename = Path.GetFileName(pathname);

                if (!Utils.WorthSyncing(Path.GetDirectoryName(pathname), filename, repoinfo))
                {
                    return;
                }

                try
                {
                    string name       = pathname.Substring(localFolder.Length + 1);
                    string remoteName = Path.Combine(remoteFolder, name).Replace('\\', '/');

                    if (database.ContainsFile(pathname))
                    {
                        Logger.InfoFormat("Removing locally deleted file on server: {0}", pathname);
                        try
                        {
                            IDocument remote = (IDocument)session.GetObjectByPath(remoteName);
                            if (remote != null)
                            {
                                remote.DeleteAllVersions();
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Warn(String.Format("Exception when operate remote {0}", remoteName), ex);
                        }
                        database.RemoveFile(pathname);
                    }
                    else if (database.ContainsFolder(pathname))
                    {
                        Logger.InfoFormat("Removing locally deleted folder on server: {0}", pathname);
                        try
                        {
                            IFolder remote = (IFolder)session.GetObjectByPath(remoteName);
                            if (remote != null)
                            {
                                remote.DeleteTree(true, null, true);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Warn(String.Format("Exception when operate remote {0}", remoteName), ex);
                        }
                        database.RemoveFolder(pathname);
                    }
                    else
                    {
                        Logger.InfoFormat("Ignore the delete action for the local created and deleted file/folder: {0}", pathname);
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync update: " + pathname, e);
                }
            }
Ejemplo n.º 4
0
            /// <summary>
            /// Crawl remote subfolder, syncing down if needed.
            /// Meanwhile, cache and remoteFolders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList remoteFolders)
            {
                sleepWhileSuspended();

                try
                {
                    if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo))
                    {
                        //Logger.Debug("CrawlRemote dir: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name);
                        remoteFolders.Add(remoteSubFolder.Name);
                        string localSubFolder = Path.Combine(localFolder, remoteSubFolder.Name);

                        // Check whether local folder exists.
                        if (Directory.Exists(localSubFolder))
                        {
                            // Recurse into folder.
                            CrawlSync(remoteSubFolder, localSubFolder);
                        }
                        else
                        {
                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(localSubFolder))
                            {
                                File.Delete(localSubFolder);
                            }

                            if (database.ContainsFolder(localSubFolder))
                            {
                                // If there was previously a folder with this name, it means that
                                // the user has deleted it voluntarily, so delete it from server too.

                                // Delete the folder from the remote server.
                                remoteSubFolder.DeleteTree(true, null, true);

                                // Delete the folder from database.
                                database.RemoveFolder(localSubFolder);
                            }
                            else
                            {
                                // The folder has been recently created on server, so download it.
                                Directory.CreateDirectory(localSubFolder);

                                // Create database entry for this folder.
                                // TODO - Yannick - Add metadata
                                database.AddFolder(localSubFolder, remoteSubFolder.LastModificationDate);
                                Logger.Info("Added folder to database: " + localSubFolder);

                                // Recursive copy of the whole folder.
                                RecursiveFolderCopy(remoteSubFolder, localSubFolder);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Ejemplo n.º 5
0
        public static ISession Connect()
        {
            IDictionary <string, string> parameters = DefaultTestValues.SessionParameters;

            DefaultDocumentType = DefaultTestValues.DefaultDocumentType;
            DefaultFolderType   = DefaultTestValues.DefaulFolderType;

            SessionFactory factory = SessionFactory.NewInstance();

            ISession session = null;

            if (parameters.ContainsKey(SessionParameter.RepositoryId))
            {
                session = factory.CreateSession(parameters);
            }
            else
            {
                session = factory.GetRepositories(parameters)[0].CreateSession();
            }

            Assert.IsNotNull(session);
            Assert.IsNotNull(session.Binding);
            Assert.IsNotNull(session.RepositoryInfo);
            Assert.IsNotNull(session.RepositoryInfo.Id);

            string testRootFolderPath = DefaultTestValues.TestRootFolder;

            if (testRootFolderPath == null)
            {
                TestFolder = session.GetRootFolder();
            }
            else
            {
                TestFolder = session.GetObjectByPath(testRootFolderPath) as IFolder;
            }

            Assert.IsNotNull(TestFolder);
            Assert.IsNotNull(TestFolder.Id);

            foreach (ICmisObject cmisObject in TestFolder.GetChildren())
            {
                IFolder folder = cmisObject as IFolder;
                if (folder == null)
                {
                    cmisObject.Delete(true);
                }
                else
                {
                    folder.DeleteTree(true, null, true);
                }
            }

            return(session);
        }
Ejemplo n.º 6
0
        public void RenameRemoteFolderChangesChangeLogToken(
            string canonical_name,
            string localPath,
            string remoteFolderPath,
            string url,
            string user,
            string password,
            string repositoryId,
            string binding)
        {
            ISession session       = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding);
            IFolder  rootFolder    = (IFolder)session.GetObjectByPath(remoteFolderPath);
            string   folderName    = "1";
            string   newFolderName = "2";

            try {
                IFolder folder = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + folderName) as IFolder;
                if (folder != null)
                {
                    folder.DeleteTree(true, null, true);
                }

                folder = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + newFolderName) as IFolder;
                if (folder != null)
                {
                    folder.DeleteTree(true, null, true);
                }
            }
            catch (CmisObjectNotFoundException) {
            }

            IFolder newFolder      = rootFolder.CreateFolder(folderName);
            string  changeLogToken = session.RepositoryInfo.LatestChangeLogToken;
            string  changeToken    = newFolder.ChangeToken;

            newFolder.Rename(newFolderName, true);

            Assert.That(newFolder.ChangeToken, Is.Not.EqualTo(changeToken));

            newFolder.DeleteTree(true, null, true);
        }
Ejemplo n.º 7
0
            /// <summary>
            /// Upload folder recursively.
            /// After execution, the hierarchy on server will be: .../remoteBaseFolder/localFolder/...
            /// </summary>
            private void UploadFolderRecursively(IFolder remoteBaseFolder, string localFolder)
            {
                // Create remote folder.
                Dictionary <string, object> properties = new Dictionary <string, object>();

                properties.Add(PropertyIds.Name, Path.GetFileName(localFolder));
                properties.Add(PropertyIds.ObjectTypeId, "cmis:folder");
                IFolder folder = remoteBaseFolder.CreateFolder(properties);

                // Create database entry for this folder
                // TODO Add metadata
                database.AddFolder(localFolder, folder.LastModificationDate);

                try
                {
                    // Upload each file in this folder.
                    foreach (string file in Directory.GetFiles(localFolder))
                    {
                        if (Utils.WorthSyncing(file))
                        {
                            UploadFile(file, folder);
                        }
                    }

                    // Recurse for each subfolder in this folder.
                    foreach (string subfolder in Directory.GetDirectories(localFolder))
                    {
                        string path = subfolder.Substring(repoinfo.TargetDirectory.Length);
                        path = path.Replace("\\\\", "/");
                        if (Utils.WorthSyncing(subfolder) && !repoinfo.isPathIgnored(path))
                        {
                            UploadFolderRecursively(folder, subfolder);
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e is System.IO.DirectoryNotFoundException ||
                        e is IOException)
                    {
                        Logger.Warn("Folder deleted while trying to upload it, reverting.");
                        // Folder has been deleted while we were trying to upload/checksum/add.
                        // In this case, revert the upload.
                        folder.DeleteTree(true, null, true);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
Ejemplo n.º 8
0
        public void CheckoutTest(
            string canonical_name,
            string localPath,
            string remoteFolderPath,
            string url,
            string user,
            string password,
            string repositoryId,
            string binding)
        {
            string subFolderName = "subFolder";
            string fileName      = "testFile.bin";
            string subFolderPath = remoteFolderPath.TrimEnd('/') + "/" + subFolderName;
            string filePath      = subFolderPath + "/" + fileName;

            ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding);

            if (!session.ArePrivateWorkingCopySupported())
            {
                Assert.Ignore("PWCs are not supported");
            }

            try {
                IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder;
                if (dir != null)
                {
                    dir.DeleteTree(true, null, true);
                }
            } catch (CmisObjectNotFoundException) {
            }

            IFolder folder    = (IFolder)session.GetObjectByPath(remoteFolderPath);
            IFolder subFolder = folder.CreateFolder(subFolderName);

            IDocument doc         = subFolder.CreateDocument(fileName, "testContent", checkedOut: true);
            IObjectId checkoutId  = doc.CheckOut();
            IDocument docCheckout = (IDocument)session.GetObject(checkoutId);

            Assert.AreEqual(doc.ContentStreamLength, docCheckout.ContentStreamLength);
            doc.Refresh();
            Assert.IsTrue(doc.IsVersionSeriesCheckedOut.GetValueOrDefault());
            Assert.AreEqual(checkoutId.Id, doc.VersionSeriesCheckedOutId);

            docCheckout.CancelCheckOut();
            doc.Refresh();
            Assert.IsFalse(doc.IsVersionSeriesCheckedOut.GetValueOrDefault());
            Assert.IsNull(doc.VersionSeriesCheckedOutId);
        }
Ejemplo n.º 9
0
        public void TestUpdateProperties()
        {
            string name1 = "port-test-folder1";
            string name2 = "port-test-folder2";
            string name3 = "port-test-folder3";

            IOperationContext oc = Session.CreateOperationContext();

            oc.CacheEnabled = false;

            IFolder newFolder = null;

            try
            {
                // create folder
                IFolder root = Session.GetRootFolder();
                newFolder = CreateFolder(root, name1);
                Assert.IsNotNull(newFolder);

                IFolder newFolder2 = (IFolder)Session.GetObject(newFolder, oc);
                Assert.IsNotNull(newFolder2);
                Assert.IsNotNull(name1, newFolder2.Name);

                IDictionary <string, object> updateProps = new Dictionary <string, object>();
                updateProps[PropertyIds.Name] = name2;

                newFolder2.UpdateProperties(updateProps);

                IFolder newFolder3 = (IFolder)Session.GetObject(newFolder, oc);
                Assert.IsNotNull(newFolder3);
                Assert.IsNotNull(name2, newFolder3.Name);

                newFolder3.Rename(name3);

                IFolder newFolder4 = (IFolder)Session.GetObject(newFolder, oc);
                Assert.IsNotNull(newFolder4);
                Assert.IsNotNull(name3, newFolder4.Name);
            }
            finally
            {
                if (newFolder != null)
                {
                    newFolder.DeleteTree(true, UnfileObject.Delete, true);
                    Assert.IsFalse(Session.Exists(newFolder));
                }
            }
        }
Ejemplo n.º 10
0
        private IFolder ClearRemoteCMISFolderAndGetFolder(ISession session, string remoteFolderPath)
        {
            var folder = (IFolder)session.GetObjectByPath(remoteFolderPath, true);

            foreach (var child in folder.GetChildren())
            {
                if (child is IFolder)
                {
                    IFolder folderChild = (IFolder)child;
                    folderChild.DeleteTree(true, UnfileObject.Delete, true);
                }
                else
                {
                    child.Delete(true);
                }
            }

            return(folder);
        }
Ejemplo n.º 11
0
        public void RemovingRemoteFolderAndAddingADocumentToItShouldThrowException(
            string canonical_name,
            string localPath,
            string remoteFolderPath,
            string url,
            string user,
            string password,
            string repositoryId)
        {
            ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId);

            IFolder folder = (IFolder)session.GetObjectByPath(remoteFolderPath);

            IFolder subFolder = folder.CreateFolder("subFolder");

            IFolder subFolderInstanceCopy = (IFolder)session.GetObject(subFolder.Id);

            subFolder.DeleteTree(true, null, true);

            Assert.Throws <CmisObjectNotFoundException>(() => subFolderInstanceCopy.CreateDocument("testFile.bin", "testContent"));
        }
Ejemplo n.º 12
0
        public void TestCopy()
        {
            IFolder   rootFolder = Session.GetRootFolder();
            IFolder   folder1    = null;
            IFolder   folder2    = null;
            IDocument doc1       = null;
            IDocument doc2       = null;

            string content = "I'm unique!";

            try
            {
                folder1 = CreateFolder(rootFolder, "copy1");
                folder2 = CreateFolder(rootFolder, "copy2");
                doc1    = CreateTextDocument(folder1, "copydoc.xt", content);

                doc2 = doc1.Copy(folder2);

                Assert.IsNotNull(doc2);
                Assert.AreEqual(doc1.Name, doc2.Name);
                Assert.AreEqual(ConvertStreamToString(doc1.GetContentStream().Stream), ConvertStreamToString(doc2.GetContentStream().Stream));
                Assert.AreEqual(folder2.Id, doc2.Parents[0].Id);
            }
            finally
            {
                if (folder1 != null)
                {
                    folder1.DeleteTree(true, UnfileObject.Delete, true);
                    Assert.IsFalse(Session.Exists(folder1));
                }
                if (folder2 != null)
                {
                    folder2.DeleteTree(true, UnfileObject.Delete, true);
                    Assert.IsFalse(Session.Exists(folder2));
                }
            }
        }
Ejemplo n.º 13
0
            /// <summary>
            /// Crawl remote subfolder, syncing down if needed.
            /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList <string> remoteFolders)
            {
                SleepWhileSuspended();

                try
                {
                    if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo))
                    {
                        // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\"");
                        remoteFolders.Add(remoteSubFolder.Name);
                        var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                        if (null == subFolderItem)
                        {
                            subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo);
                        }

                        // Check whether local folder exists.
                        if (Directory.Exists(subFolderItem.LocalPath))
                        {
                            // Recurse into folder.
                            CrawlSync(remoteSubFolder, subFolderItem.LocalPath);
                        }
                        else
                        {
                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(subFolderItem.LocalPath))
                            {
                                activityListener.ActivityStarted();
                                File.Delete(subFolderItem.LocalPath);
                                activityListener.ActivityStopped();
                            }

                            if (database.ContainsFolder(subFolderItem))
                            {
                                // If there was previously a folder with this name, it means that
                                // the user has deleted it voluntarily, so delete it from server too.

                                activityListener.ActivityStarted();

                                // Delete the folder from the remote server.
                                remoteSubFolder.DeleteTree(true, null, true);
                                Logger.Debug("Remove remote folder tree: " + remoteSubFolder.Path);

                                // Delete the folder from database.
                                database.RemoveFolder(subFolderItem);

                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                if (Utils.IsInvalidFileName(remoteSubFolder.Name))
                                {
                                    Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name);
                                }
                                else
                                {
                                    // The folder has been recently created on server, so download it.
                                    activityListener.ActivityStarted();
                                    Directory.CreateDirectory(subFolderItem.LocalPath);

                                    // Create database entry for this folder.
                                    // TODO - Yannick - Add metadata
                                    database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                                    Logger.Info("Added folder to database: " + subFolderItem.LocalPath);

                                    // Recursive copy of the whole folder.
                                    RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath);

                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    activityListener.ActivityStopped();
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Ejemplo n.º 14
0
            private void WatcherSyncDelete(string remoteFolder, string localFolder, string pathname)
            {
                string        name        = pathname.Substring(localFolder.Length + 1);
                string        remoteName  = Path.Combine(remoteFolder, name).Replace('\\', '/');
                DbTransaction transaction = null;

                try
                {
                    transaction = database.BeginTransaction();
                    if (database.ContainsFile(pathname))
                    {
                        Logger.Info("Removing locally deleted file on server: " + pathname);
                        try
                        {
                            IDocument remote = (IDocument)session.GetObjectByPath(remoteName);
                            if (remote != null)
                            {
                                remote.DeleteAllVersions();
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Warn(String.Format("Exception when operate remote {0}: ", remoteName), e);
                        }
                        database.RemoveFile(pathname);
                    }
                    else if (database.ContainsFolder(pathname))
                    {
                        Logger.Info("Removing locally deleted folder on server: " + pathname);
                        try
                        {
                            IFolder remote = (IFolder)session.GetObjectByPath(remoteName);
                            if (remote != null)
                            {
                                remote.DeleteTree(true, null, true);
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Warn(String.Format("Exception when operate remote {0}: ", remoteName), e);
                        }
                        database.RemoveFolder(pathname);
                    }
                    else
                    {
                        Logger.Info("Ignore the delete action for the local created and deleted file/folder: " + pathname);
                    }
                    transaction.Commit();
                }
                catch (Exception e)
                {
                    if (transaction != null)
                    {
                        transaction.Rollback();
                    }
                    Logger.Warn(String.Format("Exception while sync to delete file/folder {0}: ", pathname), e);
                    return;
                }
                finally
                {
                    if (transaction != null)
                    {
                        transaction.Dispose();
                    }
                }

                repo.Watcher.RemoveChange(pathname, Watcher.ChangeTypes.Deleted);

                return;
            }
Ejemplo n.º 15
0
            /// <summary>
            /// Crawl remote subfolder, syncing down if needed.
            /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteFolder(IFolder remoteSubFolder, string remotePath, string localFolder, IList <string> remoteFolders)
            {
                SleepWhileSuspended();

                try
                {
                    if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoInfo))
                    {
                        // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\"");
                        remoteFolders.Add(remoteSubFolder.Name);
                        var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                        if (null == subFolderItem)
                        {
                            subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoInfo);
                        }

                        // Check whether local folder exists.
                        if (Directory.Exists(subFolderItem.LocalPath))
                        {
                            // Recurse into folder.
                            CrawlSync(remoteSubFolder, remotePath, subFolderItem.LocalPath);
                        }
                        else
                        {
                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(subFolderItem.LocalPath))
                            {
                                activityListener.ActivityStarted();
                                Utils.DeleteEvenIfReadOnly(subFolderItem.LocalPath);
                                activityListener.ActivityStopped();
                            }

                            if (database.ContainsFolder(subFolderItem))
                            {
                                // If there was previously a folder with this name, it means that
                                // the user has deleted it voluntarily, so delete it from server too.

                                activityListener.ActivityStarted();

                                // Delete the folder from the remote server.
                                try
                                {
                                    Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path);
                                    IList <string> failedIDs = remoteSubFolder.DeleteTree(true, null, true);
                                    if (failedIDs == null || failedIDs.Count != 0)
                                    {
                                        Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path);
                                        // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree.
                                    }
                                }
                                catch (CmisPermissionDeniedException e)
                                {
                                    // We don't have the permission to delete this folder. Warn and recreate it.
                                    Utils.NotifyUser("You don't have the necessary permissions to delete folder " + remoteSubFolder.Path
                                                     + "\nIf you feel you should be able to delete it, please contact your server administrator");
                                    RecursiveFolderCopy(remoteSubFolder, remotePath, subFolderItem.LocalPath);
                                }

                                // Delete the folder from database.
                                database.RemoveFolder(subFolderItem);

                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                if (Utils.IsInvalidFileName(remoteSubFolder.Name))
                                {
                                    Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name);
                                }
                                else
                                {
                                    // The folder has been recently created on server, so download it.
                                    activityListener.ActivityStarted();
                                    Directory.CreateDirectory(subFolderItem.LocalPath);

                                    // Create database entry for this folder.
                                    // TODO - Yannick - Add metadata
                                    database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                                    Logger.Info("Added folder to database: " + subFolderItem.LocalPath);

                                    // Recursive copy of the whole folder.
                                    RecursiveFolderCopy(remoteSubFolder, remotePath, subFolderItem.LocalPath);

                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    activityListener.ActivityStopped();
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Ejemplo n.º 16
0
            /// <summary>
            /// Crawl remote subfolder, syncing down if needed.
            /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList<string> remoteFolders)
            {
                SleepWhileSuspended();

                try
                {
                    if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo))
                    {
                        // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\"");
                        remoteFolders.Add(remoteSubFolder.Name);
                        var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                        if (null == subFolderItem)
                        {
                            subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo);
                        }

                        // Check whether local folder exists.
                        if (Directory.Exists(subFolderItem.LocalPath))
                        {
                            // Recurse into folder.
                            CrawlSync(remoteSubFolder, subFolderItem.LocalPath);
                        }
                        else
                        {
                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(subFolderItem.LocalPath))
                            {
                                activityListener.ActivityStarted();
                                File.Delete(subFolderItem.LocalPath);
                                activityListener.ActivityStopped();
                            }

                            if (database.ContainsFolder(subFolderItem))
                            {
                                // If there was previously a folder with this name, it means that
                                // the user has deleted it voluntarily, so delete it from server too.

                                activityListener.ActivityStarted();

                                // Delete the folder from the remote server.
                                try
                                {
                                    Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path);
                                    IList<string> failedIDs = remoteSubFolder.DeleteTree(true, null, true);
                                    if (failedIDs == null || failedIDs.Count != 0)
                                    {
                                        Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path);
                                        // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree.
                                    }
                                }
                                catch (CmisPermissionDeniedException e)
                                {
                                    // We don't have the permission to delete this folder. Warn and recreate it.
                                    Utils.NotifyUser("You don't have the necessary permissions to delete folder " + remoteSubFolder.Path
                                        + "\nIf you feel you should be able to delete it, please contact your server administrator");
                                    DownloadFolder(remoteSubFolder, localFolder);
                                }

                                // Delete the folder from database.
                                database.RemoveFolder(subFolderItem);

                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                if (Utils.IsInvalidFileName(remoteSubFolder.Name))
                                {
                                    Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name);
                                }
                                else
                                {
                                    // The folder has been recently created on server, so download it.
                                    activityListener.ActivityStarted();
                                    Directory.CreateDirectory(subFolderItem.LocalPath);

                                    // Create database entry for this folder.
                                    // TODO - Yannick - Add metadata
                                    database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                                    Logger.Info("Added folder to database: " + subFolderItem.LocalPath);

                                    // Recursive copy of the whole folder.
                                    RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath);

                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    activityListener.ActivityStopped();
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Ejemplo n.º 17
0
            /// <summary>
            /// Download a single folder from the CMIS server for sync.
            /// </summary>
            /// <returns>true if successful</returns>
            private bool SyncDownloadFolder(IFolder remoteSubFolder, string localFolder)
            {
                var syncItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo);
                string localName = PathRepresentationConverter.RemoteToLocal(remoteSubFolder.Name);

                // If the target folder has been removed/renamed, then relaunch sync.
                if (!Directory.Exists(localFolder))
                {
                    Logger.Warn("The target folder has been removed/renamed: " + localFolder);
                    return false;
                }

                if (Directory.Exists(syncItem.LocalPath))
                {
                    return true;
                }

                if (database.ContainsFolder(syncItem))
                {
                    // If there was previously a folder with this name, it means that
                    // the user has deleted it voluntarily, so delete it from server too.

                    // Delete the folder from the remote server.
                    Logger.Debug(String.Format("CMIS::DeleteTree({0})", remoteSubFolder.Path));
                    try
                    {
                        remoteSubFolder.DeleteTree(true, null, true);
                        // Delete the folder from database.
                        database.RemoveFolder(syncItem);
                    }
                    catch (Exception)
                    {
                        Logger.Info("Remote Folder could not be deleted: " + remoteSubFolder.Path);
                        // Just go on and try it the next time
                    }
                }
                else
                {
                    // The folder has been recently created on server, so download it.

                    // If there was previously a file with this name, delete it.
                    // TODO warn if local changes in the file.
                    if (File.Exists(syncItem.LocalPath))
                    {
                        string conflictFilename = Utils.CreateConflictFilename(syncItem.LocalPath, repoinfo.User);
                        Logger.Warn("Local file \"" + syncItem.LocalPath + "\" has been renamed to \"" + conflictFilename + "\"");
                        File.Move(syncItem.LocalPath, conflictFilename);
                    }

                    // Skip if invalid folder name. See https://github.com/aegif/CmisSync/issues/196
                    if (Utils.IsInvalidFolderName(localName))
                    {
                        Logger.Info("Skipping download of folder with illegal name: " + localName);
                    }
                    else if (repoinfo.isPathIgnored(syncItem.RemoteRelativePath))
                    {
                        Logger.Info("Skipping dowload of ignored folder: " + syncItem.RemoteRelativePath);
                    }
                    else
                    {
                        // Create local folder.remoteDocument.Name
                        Logger.Info("Creating local directory: " + syncItem.LocalPath);
                        Directory.CreateDirectory(syncItem.LocalPath);

                        // Should the local folder be made read-only?
                        // Check ther permissions of the current user to the remote folder.
                        bool readOnly = ! remoteSubFolder.AllowableActions.Actions.Contains(PermissionMappingKeys.CanAddToFolderObject);
                        if (readOnly)
                        {
                            new DirectoryInfo(syncItem.LocalPath).Attributes =  FileAttributes.ReadOnly;
                        }

                        // Create database entry for this folder.
                        // TODO - Yannick - Add metadata
                        database.AddFolder(syncItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                    }
                }

                return true;
            }
Ejemplo n.º 18
0
            /// <summary>
            /// Crawl remote subfolder, syncing down if needed.
            /// Meanwhile, cache and remoteFolders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList remoteFolders)
            {
                sleepWhileSuspended();

                try
                {
                    if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo))
                    {
                        //Logger.Debug("CrawlRemote dir: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name);
                        remoteFolders.Add(remoteSubFolder.Name);
                        string localSubFolder = Path.Combine(localFolder, remoteSubFolder.Name);

                        // Check whether local folder exists.
                        if (Directory.Exists(localSubFolder))
                        {
                            // Recurse into folder.
                            CrawlSync(remoteSubFolder, localSubFolder);
                        }
                        else
                        {
                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(localSubFolder))
                            {
                                File.Delete(localSubFolder);
                            }

                            if (database.ContainsFolder(localSubFolder))
                            {
                                // If there was previously a folder with this name, it means that
                                // the user has deleted it voluntarily, so delete it from server too.

                                // Delete the folder from the remote server.
                                remoteSubFolder.DeleteTree(true, null, true);

                                // Delete the folder from database.
                                database.RemoveFolder(localSubFolder);
                            }
                            else
                            {
                                // The folder has been recently created on server, so download it.
                                Directory.CreateDirectory(localSubFolder);

                                // Create database entry for this folder.
                                // TODO - Yannick - Add metadata
                                database.AddFolder(localSubFolder, remoteSubFolder.LastModificationDate);
                                Logger.Info("Added folder to database: " + localSubFolder);

                                // Recursive copy of the whole folder.
                                RecursiveFolderCopy(remoteSubFolder, localSubFolder);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Ejemplo n.º 19
0
            /// <summary>
            /// Delete the folder from the remote server.
            /// </summary>
            public void DeleteRemoteFolder(IFolder folder, SyncItem syncItem, string upperFolderPath)
            {
                try
                {
                    Logger.Debug("Removing remote folder tree: " + folder.Path);
                    IList<string> failedIDs = folder.DeleteTree(true, null, true);
                    if (failedIDs == null || failedIDs.Count != 0)
                    {
                        Logger.Error("Failed to completely delete remote folder " + folder.Path);
                        // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree.
                    }

                    // Delete the folder from database.
                    database.RemoveFolder(syncItem);
                }
                catch (CmisPermissionDeniedException e)
                {

                    // TODO: Add resource
                    string message = String.Format("フォルダ {0} に対して削除やリネームする権限がないため、サーバからこのフォルダを復元します(フォルダに含まれるファイル数が多い場合、復元に時間がかかります)。", syncItem.LocalPath);
                    Utils.NotifyUser(message);


                    // We don't have the permission to delete this folder. Warn and recreate it.
                    /*
                    Utils.NotifyUser("You don't have the necessary permissions to delete folder " + folder.Path
                        + "\nIf you feel you should be able to delete it, please contact your server administrator");
                    */
                    database.RemoveFolder(syncItem);
                    DownloadDirectory(folder, syncItem.RemotePath, syncItem.LocalPath);
                }
            }
Ejemplo n.º 20
0
            /// <summary>
            /// Download a single folder from the CMIS server for sync.
            /// </summary>
            private bool SyncDownloadFolder(IFolder remoteSubFolder, string localFolder)
            {
                string name = remoteSubFolder.Name;
                string remotePathname = remoteSubFolder.Path;
                string localSubFolder = Path.Combine(localFolder, name);
                if (!Directory.Exists(localFolder))
                {
                    // The target folder has been removed/renamed => relaunch sync
                    Logger.Warn("The target folder has been removed/renamed: " + localFolder);
                    return false;
                }

                if (Directory.Exists(localSubFolder))
                {
                    return true;
                }

                if (database.ContainsFolder(localSubFolder))
                {
                    // If there was previously a folder with this name, it means that
                    // the user has deleted it voluntarily, so delete it from server too.

                    // Delete the folder from the remote server.
                    Logger.Debug(String.Format("CMIS::DeleteTree({0})", remoteSubFolder.Path));
                    try
                    {
                        remoteSubFolder.DeleteTree(true, null, true);
                        // Delete the folder from database.
                        database.RemoveFolder(localSubFolder);
                    }
                    catch (Exception)
                    {
                        Logger.Info("Remote Folder could not be deleted: " + remoteSubFolder.Path);
                        // Just go on and try it the next time
                    }
                }
                else
                {
                    // The folder has been recently created on server, so download it.

                    // If there was previously a file with this name, delete it.
                    // TODO warn if local changes in the file.
                    if (File.Exists(localSubFolder))
                    {
                        Logger.Warn("Local file \"" + localSubFolder + "\" has been renamed to \"" + localSubFolder + ".conflict\"");
                        File.Move(localSubFolder, localSubFolder + ".conflict");
                    }

                    // Skip if invalid folder name. See https://github.com/nicolas-raoul/CmisSync/issues/196
                    if (Utils.IsInvalidFolderName(name))
                    {
                        Logger.Info("Skipping download of folder with illegal name: " + name);
                    }
                    else if (repoinfo.isPathIgnored(remotePathname))
                    {
                        Logger.Info("Skipping dowload of ignored folder: " + remotePathname);
                    }
                    else
                    {
                        // Create local folder.remoteDocument.Name
                        Logger.Info("Creating local directory: " + localSubFolder);
                        Directory.CreateDirectory(localSubFolder);

                        // Create database entry for this folder.
                        // TODO - Yannick - Add metadata
                        database.AddFolder(localSubFolder, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                    }
                }

                return true;
            }
Ejemplo n.º 21
0
            /// <summary>
            /// Crawl remote content, syncing down if needed.
            /// Meanwhile, cache remoteFiles and remoteFolders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemote(IFolder remoteFolder, string localFolder, IList remoteFiles, IList remoteFolders)
            {
                foreach (ICmisObject cmisObject in remoteFolder.GetChildren())
                {
                    while (repo.Status == SyncStatus.Suspend)
                    {
                        Logger.Info("Sync of " + repoinfo.Name + " is suspended, will retry in " + repoinfo.PollInterval + "ms");
                        System.Threading.Thread.Sleep((int)repoinfo.PollInterval); // TODO Should not sleep, but skip instead.
                    }

                    #region Cmis Folder
                    if (cmisObject is DotCMIS.Client.Impl.Folder)
                    {
                        // It is a CMIS folder.
                        IFolder remoteSubFolder = (IFolder)cmisObject;
                        if (Utils.WorthSyncing(remoteSubFolder.Name) && !repoinfo.isPathIgnored(remoteSubFolder.Path))
                        {
                            //Logger.Debug("CrawlRemote dir: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name);
                            remoteFolders.Add(remoteSubFolder.Name);
                            string localSubFolder = localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name;

                            // Check whether local folder exists.
                            if (Directory.Exists(localSubFolder))
                            {
                                // Recurse into folder.
                                CrawlSync(remoteSubFolder, localSubFolder);
                            }
                            else
                            {
                                // If there was previously a file with this name, delete it.
                                // TODO warn if local changes in the file.
                                if (File.Exists(localSubFolder))
                                {
                                    File.Delete(localSubFolder);
                                }

                                if (database.ContainsFolder(localSubFolder))
                                {
                                    // If there was previously a folder with this name, it means that
                                    // the user has deleted it voluntarily, so delete it from server too.

                                    // Delete the folder from the remote server.
                                    remoteSubFolder.DeleteTree(true, null, true);

                                    // Delete the folder from database.
                                    database.RemoveFolder(localSubFolder);
                                }
                                else
                                {
                                    // The folder has been recently created on server, so download it.

                                    // Skip if invalid folder name. See https://github.com/nicolas-raoul/CmisSync/issues/196
                                    if (Utils.IsInvalidFileName(remoteSubFolder.Name))
                                    {
                                        Logger.Info("Skipping download of folder with illegal name: " + remoteSubFolder.Name);
                                    }
                                    else if (repoinfo.isPathIgnored(remoteSubFolder.Path))
                                    {
                                        Logger.Info("Skipping dowload of ignored folder: " + remoteSubFolder.Name);
                                    }
                                    else
                                    {
                                        // Create local folder.remoteDocument.Name
                                        Directory.CreateDirectory(localSubFolder);

                                        // Create database entry for this folder.
                                        // TODO - Yannick - Add metadata
                                        database.AddFolder(localSubFolder, remoteFolder.LastModificationDate);

                                        // Recursive copy of the whole folder.
                                        RecursiveFolderCopy(remoteSubFolder, localSubFolder);
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    #region Cmis Document
                    else
                    {
                        // It is a CMIS document.
                        IDocument remoteDocument = (IDocument)cmisObject;

                        if (Utils.WorthSyncing(remoteDocument.Name))
                        {
                            // We use the filename of the document's content stream.
                            // This can be different from the name of the document.
                            // For instance in FileNet it is not usual to have a document where
                            // document.Name is "foo" and document.ContentStreamFileName is "foo.jpg".
                            string remoteDocumentFileName = remoteDocument.ContentStreamFileName;
                            //Logger.Debug("CrawlRemote doc: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteDocumentFileName);

                            // Check if file extension is allowed

                            remoteFiles.Add(remoteDocumentFileName);
                            // If this file does not have a filename, ignore it.
                            // It sometimes happen on IBM P8 CMIS server, not sure why.
                            if (remoteDocumentFileName == null)
                            {
                                Logger.Warn("Skipping download of '" + remoteDocument.Name + "' with null content stream in " + localFolder);
                                continue;
                            }

                            string filePath = localFolder + Path.DirectorySeparatorChar.ToString() + remoteDocumentFileName;

                            if (File.Exists(filePath))
                            {
                                // Check modification date stored in database and download if remote modification date if different.
                                DateTime?serverSideModificationDate = ((DateTime)remoteDocument.LastModificationDate).ToUniversalTime();
                                DateTime?lastDatabaseUpdate         = database.GetServerSideModificationDate(filePath);

                                if (lastDatabaseUpdate == null)
                                {
                                    Logger.Info("Downloading file absent from database: " + filePath);
                                    DownloadFile(remoteDocument, localFolder);
                                }
                                else
                                {
                                    // If the file has been modified since last time we downloaded it, then download again.
                                    if (serverSideModificationDate > lastDatabaseUpdate)
                                    {
                                        if (database.LocalFileHasChanged(filePath))
                                        {
                                            Logger.Info("Conflict with file: " + remoteDocumentFileName + ", backing up locally modified version and downloading server version");
                                            // Rename locally modified file.
                                            String ext      = Path.GetExtension(filePath);
                                            String filename = Path.GetFileNameWithoutExtension(filePath);
                                            String path     = Path.GetDirectoryName(filePath);

                                            String NewFileName = Utils.SuffixIfExists(filename + "_" + repoinfo.User + "-version");
                                            String newFilePath = Path.Combine(path, NewFileName);
                                            File.Move(filePath, newFilePath);

                                            // Download server version
                                            DownloadFile(remoteDocument, localFolder);
                                            repo.OnConflictResolved();

                                            // TODO move to OS-dependant layer
                                            //System.Windows.Forms.MessageBox.Show("Someone modified a file at the same time as you: " + filePath
                                            //    + "\n\nYour version has been saved with a '_your-version' suffix, please merge your important changes from it and then delete it.");
                                            // TODO show CMIS property lastModifiedBy
                                        }
                                        else
                                        {
                                            Logger.Info("Downloading modified file: " + remoteDocumentFileName);
                                            DownloadFile(remoteDocument, localFolder);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (database.ContainsFile(filePath))
                                {
                                    // File has been recently removed locally, so remove it from server too.
                                    Logger.Info("Removing locally deleted file on server: " + filePath);
                                    remoteDocument.DeleteAllVersions();
                                    // Remove it from database.
                                    database.RemoveFile(filePath);
                                }
                                else
                                {
                                    // New remote file, download it.
                                    Logger.Info("New remote file: " + filePath);
                                    DownloadFile(remoteDocument, localFolder);
                                }
                            }
                        }
                    }
                    #endregion
                }
            }
Ejemplo n.º 22
0
        public void CheckinTest(
            string canonical_name,
            string localPath,
            string remoteFolderPath,
            string url,
            string user,
            string password,
            string repositoryId,
            string binding)
        {
            string subFolderName = "subFolder";
            string fileName      = "testFile.bin";
            string subFolderPath = remoteFolderPath.TrimEnd('/') + "/" + subFolderName;
            string filePath      = subFolderPath + "/" + fileName;

            ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding);

            if (!session.ArePrivateWorkingCopySupported())
            {
                Assert.Ignore("PWCs are not supported");
            }

            try {
                IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder;
                if (dir != null)
                {
                    dir.DeleteTree(true, null, true);
                }
            } catch (CmisObjectNotFoundException) {
            }

            IFolder folder    = (IFolder)session.GetObjectByPath(remoteFolderPath);
            IFolder subFolder = folder.CreateFolder(subFolderName);

            string content = "testContent";

            IDocument doc         = subFolder.CreateDocument(fileName, "testContent", checkedOut: true);
            IObjectId checkoutId  = doc.CheckOut();
            IDocument docCheckout = session.GetObject(checkoutId) as IDocument;

            Assert.AreEqual(doc.ContentStreamLength, docCheckout.ContentStreamLength);

            ContentStream contentStream = new ContentStream();

            contentStream.FileName = fileName;
            contentStream.MimeType = MimeType.GetMIMEType(fileName);
            contentStream.Length   = content.Length;
            for (int i = 0; i < 10; ++i)
            {
                using (var memstream = new MemoryStream(Encoding.UTF8.GetBytes(content))) {
                    contentStream.Stream = memstream;
                    docCheckout.AppendContentStream(contentStream, i == 9);
                }
                Assert.That(docCheckout.ContentStreamLength, Is.EqualTo(content.Length * (i + 2)));
            }

            IObjectId checkinId  = docCheckout.CheckIn(true, null, null, "checkin");
            IDocument docCheckin = session.GetObject(checkinId) as IDocument;

            docCheckin.Refresh();   //  refresh is required, or DotCMIS will re-use the cached properties if checinId is the same as doc.Id
            Assert.That(docCheckin.ContentStreamLength, Is.EqualTo(content.Length * (9 + 2)));
        }
        /// <summary>
        /// Crawl remote subfolder, syncing down if needed.
        /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
        /// </summary>
        private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList<string> remoteFolders)
        {
            CheckPendingCancelation();

            try
            {
                if (SyncUtils.IsWorthSyncing(localFolder, remoteSubFolder.Name, SyncFolderInfo))
                {
                    // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\"");
                    remoteFolders.Add(remoteSubFolder.Name);

                    SyncItem subFolderItem = getSyncItemFromRemotePath(remoteSubFolder.Path);

                    // Check whether local folder exists.
                    if (Directory.Exists(subFolderItem.LocalPath))
                    {
                        // Recurse into folder.
                        CrawlSync(remoteSubFolder, subFolderItem.LocalPath);
                    }
                    else
                    {
                        // If there was previously a file with this name, delete it.
                        // TODO warn if local changes in the file.
                        if (File.Exists(subFolderItem.LocalPath))
                        {

                            File.Delete(subFolderItem.LocalPath);

                        }

                        if (database.ContainsFolder(subFolderItem))
                        {
                            // If there was previously a folder with this name, it means that
                            // the user has deleted it voluntarily, so delete it from server too.

                            // Delete the folder from the remote server.
                            try
                            {
                                Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path);
                                IList<string> failedIDs = remoteSubFolder.DeleteTree(true, null, true);
                                if (failedIDs == null || failedIDs.Count != 0)
                                {
                                    Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path);
                                    // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree.
                                }
                            }
                            catch (CmisPermissionDeniedException e)
                            {
                                HandleException(new DeleteRemoteFolderException(remoteSubFolder.Path, e));
                                //restore the folder
                                //TODO: check permissions before deleting the folder
                                DownloadFolder(remoteSubFolder, localFolder);
                                return;
                            }

                            // Delete the folder from database.
                            database.RemoveFolder(subFolderItem);

                        }
                        else
                        {
                            if (SyncUtils.IsInvalidFileName(remoteSubFolder.Name))
                            {
                                Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name);
                            }
                            else
                            {
                                // The folder has been recently created on server, so download it.

                                Directory.CreateDirectory(subFolderItem.LocalPath);

                                // Create database entry for this folder.
                                // TODO - Yannick - Add metadata
                                database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate);
                                Logger.Info("Added folder to database: " + subFolderItem.LocalPath);

                                // Recursive copy of the whole folder.
                                RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath);

                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {

                HandleException(new DownloadFolderException(remoteSubFolder.Path, e));
            }
        }