/// <summary>
            /// Apply: Added folders.
            /// </summary>
            public bool ApplyAddedFolders(ref List <string> addedFolders)
            {
                bool success = true;

                foreach (string addedFolder in addedFolders)
                {
                    string   destinationFolderPath = Path.GetDirectoryName(addedFolder);
                    SyncItem destinationFolderItem = SyncItemFactory.CreateFromLocalPath(destinationFolderPath, true, repoInfo, database);
                    SyncItem addedFolderItem       = SyncItemFactory.CreateFromLocalPath(addedFolder, true, repoInfo, database);
                    try
                    {
                        IFolder destinationFolder = (IFolder)session.GetObjectByPath(destinationFolderItem.RemotePath, true);

                        IList <string> remoteFolders = new List <string>();

                        if (CmisUtils.FolderExists(session, addedFolderItem.RemotePath))
                        {
                            remoteFolders.Add(addedFolderItem.RemoteLeafname);
                        }

                        // TODO more efficient: first create said folder, then call CrawlSync in it.
                        CrawlSync(destinationFolder, destinationFolderItem.RemotePath, destinationFolderItem.LocalPath);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local folder addition to the server: " + addedFolder, e);
                        success = false;
                    }
                }
                return(success);
            }
Exemple #2
0
            /// <summary>
            /// Apply: Added files.
            /// </summary>
            public bool ApplyAddedFiles(ref List <string> addedFiles)
            {
                bool success = true;

                foreach (string addedFile in addedFiles)
                {
                    string   destinationFolderPath = Path.GetDirectoryName(addedFile);
                    SyncItem folderItem            = SyncItemFactory.CreateFromLocalPath(destinationFolderPath, true, repoInfo, database);
                    SyncItem fileItem = SyncItemFactory.CreateFromLocalPath(addedFile, false, repoInfo, database);
                    try
                    {
                        IFolder destinationFolder = (IFolder)session.GetObjectByPath(folderItem.RemotePath);

                        // Fill documents list, needed by the crawl method.
                        IList <string> remoteFiles = new List <string>();

                        if (CmisUtils.DocumentExists(session, fileItem.RemotePath))
                        {
                            remoteFiles.Add(fileItem.RemoteLeafname);
                        }

                        // Crawl this particular file.
                        CheckLocalFile(fileItem.LocalPath, destinationFolder, remoteFiles);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local file addition to the server: " + addedFile, e);
                        success = false;
                    }
                }
                return(success);
            }
Exemple #3
0
            /// <summary>
            /// Watchers the sync delete.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            private void WatcherSyncDelete(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('\\', '/'); // FIXME
                    if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo)))
                    {
                        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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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);
                }
            }
            /// <summary>
            /// Crawl local folder in a given directory (not recursive).
            /// </summary>
            private void CrawlLocalFolder(string localSubFolder, IFolder remoteFolder, IList <string> remoteFolders)
            {
                SleepWhileSuspended();
                try
                {
                    if (Utils.IsSymlink(new DirectoryInfo(localSubFolder)))
                    {
                        Logger.Info("Skipping symbolic link folder: " + localSubFolder);
                        return;
                    }

                    string folderName     = Path.GetFileName(localSubFolder);
                    var    syncFolderItem = database.GetFolderSyncItemFromLocalPath(localSubFolder);
                    if (null == syncFolderItem)
                    {
                        syncFolderItem = SyncItemFactory.CreateFromLocalPath(localSubFolder, repoInfo);
                    }

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localSubFolder), folderName, repoInfo))
                    {
                        if (!remoteFolders.Contains(syncFolderItem.RemoteFileName))
                        {
                            // This local folder is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                activityListener.ActivityStarted();
                                RemoveFolderLocally(localSubFolder);
                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // New local folder, upload recursively.
                                    activityListener.ActivityStarted();
                                    UploadFolderRecursively(remoteFolder, localSubFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local folder: " + localSubFolder, e);
                }
            }
            /// <summary>
            /// Apply: Deleted files.
            /// </summary>
            public bool ApplyDeletedFiles(ref List <string> deletedFiles)
            {
                bool success = true;

                foreach (string deletedFile in deletedFiles)
                {
                    SyncItem deletedItem = SyncItemFactory.CreateFromLocalPath(deletedFile, false, repoInfo, database);
                    try
                    {
                        IDocument deletedDocument = (IDocument)session.GetObjectByPath(deletedItem.RemotePath);

                        // Needed by the normal crawl, but actually not used in our particular case here.
                        IList <string> remoteFiles = new List <string>();
                        try
                        {
                            CrawlRemoteDocument(deletedDocument, deletedItem.RemotePath, deletedItem.LocalPath, remoteFiles);
                        }
                        catch (CmisPermissionDeniedException e)
                        {
                            Logger.Info("This user cannot delete file : " + deletedFile, e);
                            DownloadFile(deletedDocument, deletedItem.RemotePath, deletedItem.LocalPath);
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                        {
                            // Typical error when the document does not exist anymore on the server
                            // TODO Make DotCMIS generate a more precise exception.
                            Logger.Info("The document has probably been deleted on the server already: " + deletedFile, e);

                            // Delete local database entry.
                            database.RemoveFile(deletedItem);

                            // Note: This is not a failure per-se, so we don't need to modify the "success" variable.
                        }
                        else
                        {
                            // Could be a network error.
                            Logger.Error("Error applying local file deletion to the server: " + deletedFile, e);
                            success = false;
                        }
                    }
                }
                return(success);
            }
Exemple #6
0
            /// <summary>
            /// Apply: Modified files.
            /// </summary>
            public bool ApplyModifiedFiles(ref List <string> modifiedFiles)
            {
                bool success = true;

                foreach (string modifiedFile in modifiedFiles)
                {
                    SyncItem modifiedItem = SyncItemFactory.CreateFromLocalPath(modifiedFile, true, repoInfo, database);
                    try
                    {
                        IDocument modifiedDocument = (IDocument)session.GetObjectByPath(modifiedItem.RemotePath);
                        UpdateFile(modifiedItem.LocalPath, modifiedDocument);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local file modification to the server: " + modifiedFile, e);
                        success = false;
                    }
                }
                return(success);
            }
            /// <summary>
            /// Crawl local file in a given directory (not recursive).
            /// </summary>
            private void CrawlLocalFile(string filePath, IFolder remoteFolder, IList <string> remoteFiles)
            {
                SleepWhileSuspended();

                try
                {
                    if (Utils.IsSymlink(new FileInfo(filePath)))
                    {
                        Logger.Info("Skipping symbolic linked file: " + filePath);
                        return;
                    }

                    var item = database.GetSyncItemFromLocalPath(filePath);
                    if (null == item)
                    {
                        item = SyncItemFactory.CreateFromLocalPath(filePath, repoInfo);
                    }

                    // string fileName = Path.GetFileName(filePath);
                    string fileName = item.RemoteFileName;

                    if (Utils.WorthSyncing(Path.GetDirectoryName(filePath), fileName, repoInfo))
                    {
                        if (!(remoteFiles.Contains(fileName) ||
                              // Workaround for Documentum which sometimes put a ".zip" extension to document names.
                              (CmisUtils.IsDocumentum(session) && remoteFiles.Contains(fileName + ".zip"))))
                        {
                            // This local file is not on the CMIS server now, so
                            // check whether it used invalidFolderNameRegex to exist on server or not.
                            if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(filePath, repoInfo)))
                            {
                                if (database.LocalFileHasChanged(filePath))
                                {
                                    // If file has changed locally, move to 'your_version' and warn about conflict
                                    if (BIDIRECTIONAL)
                                    {
                                        // Local file was updated, sync up.
                                        Logger.Info("Uploading locally edited remotely removed file from the repository: " + filePath);
                                        activityListener.ActivityStarted();
                                        UploadFile(filePath, remoteFolder);
                                        activityListener.ActivityStopped();
                                    }
                                    else
                                    {
                                        Logger.Info("Conflict with file: " + filePath + ", backing up locally modified version.");
                                        activityListener.ActivityStarted();
                                        // Rename locally modified file.
                                        String newFilePath = Utils.CreateConflictFilename(filePath, repoInfo.User);

                                        // The file might be ReadOnly, so make it writable first, otherwise the move will fail.
                                        File.SetAttributes(filePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                        File.Move(filePath, newFilePath);

                                        // Delete file from database.
                                        database.RemoveFile(item);

                                        repo.OnConflictResolved();
                                        activityListener.ActivityStopped();
                                    }
                                }
                                else
                                {
                                    // File has been deleted on server, so delete it locally.
                                    Logger.Info("Removing remotely deleted file: " + filePath);
                                    activityListener.ActivityStarted();

                                    // The file might be ReadOnly, so make it writable first, otherwise removal will fail.
                                    File.SetAttributes(filePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                    // Delete from the local filesystem.
                                    File.Delete(filePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    activityListener.ActivityStopped();
                                }
                            }
                            else
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // New file, sync up.
                                    Logger.Info("Uploading file absent on repository: " + filePath);
                                    activityListener.ActivityStarted();
                                    UploadFile(filePath, remoteFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                        else
                        {
                            // The file exists both on server and locally.
                            if (database.LocalFileHasChanged(filePath))
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // Upload new version of file content.
                                    Logger.Info("Uploading file update on repository: " + filePath);
                                    activityListener.ActivityStarted();
                                    UpdateFile(filePath, remoteFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local file: " + filePath, e);
                }
            }
Exemple #8
0
            /// <summary>
            /// Sync update.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="localPath">Pathname.</param>
            /// <returns>Whether the update has now been synchronized, so that no further action is needed</returns>
            private bool WatcherSyncUpdate(string remoteFolder, string localFolder, string localPath)
            {
                SleepWhileSuspended();
                string localFilename = Path.GetFileName(localPath);

                if (!Utils.WorthSyncing(Path.GetDirectoryName(localPath), localFilename, repoInfo))
                {
                    return(true);
                }
                try
                {
                    string localName = localPath.Substring(localFolder.Length + 1);
                    bool   isFolder  = Utils.IsFolder(localPath);

                    SyncItem item = SyncItemFactory.CreateFromLocalPath(localPath, isFolder, repoInfo, database);

                    // Get the remote directory, needed by the update method.
                    string  remoteName = item.RemotePath;
                    IFolder remoteBase = null;
                    if (File.Exists(localPath) || Directory.Exists(localPath))
                    {
                        string remoteBaseName = CmisUtils.GetUpperFolderOfCmisPath(item.RemotePath);
                        remoteBase = (IFolder)session.GetObjectByPath(remoteBaseName);
                        if (null == remoteBase)
                        {
                            Logger.WarnFormat("The remote base folder {0} for local {1} does not exist, ignore for the update action", remoteBaseName, localPath);
                            return(true); // Ignore is not a failure.
                        }
                    }
                    else
                    {
                        Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", localPath);
                        return(true);
                    }

                    // Update the item.
                    if (File.Exists(localPath))
                    {
                        // The item is a file.
                        bool success = false;
                        if (database.ContainsLocalFile(localPath))
                        {
                            if (database.LocalFileHasChanged(localPath))
                            {
                                success = UpdateFile(localPath, remoteBase);
                                Logger.InfoFormat("Update {0}: {1}", localPath, success);
                            }
                            else
                            {
                                success = true;
                                Logger.InfoFormat("File {0} remains unchanged, ignore for the update action", localPath);
                            }
                        }
                        else
                        {
                            success = UploadFile(localPath, remoteBase);
                            Logger.InfoFormat("Upload {0}: {1}", localPath, success);
                        }
                        if (success)
                        {
                            return(true);
                        }
                        else
                        {
                            Logger.WarnFormat("Failure to update: {0}", localPath);
                            return(false);
                        }
                    }
                    if (Directory.Exists(localPath))
                    {
                        // The item is a folder.
                        bool success = true;
                        if (database.ContainsFolder(localPath))
                        {
                            Logger.InfoFormat("Folder exists in Database {0}, ignore for the update action", localPath);
                        }
                        else
                        {
                            Logger.InfoFormat("Create locally created folder on server: {0}", localPath);
                            success &= UploadFolderRecursively(remoteBase, localPath);
                        }
                        return(success);
                    }
                    Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", localPath);
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync update: " + localPath, e);
                    return(false);
                }
                return(true);
            }
Exemple #9
0
            /// <summary>
            /// An event was received from the filesystem watcher, analyze the change and apply it.
            /// <returns>Whether the move has now been synchronized, so that no further action is needed</returns>
            /// </summary>
            private bool WatchSyncMove(string remoteFolder, string localFolder, string oldPathname, string newPathname)
            {
                bool success = true;

                SleepWhileSuspended();

                // Old item.
                string   oldDirectory            = Path.GetDirectoryName(oldPathname);
                string   oldFilename             = Path.GetFileName(oldPathname);
                string   oldLocalName            = oldPathname.Substring(localFolder.Length + 1);
                SyncItem oldItem                 = database.GetSyncItemFromLocalPath(oldPathname);
                string   oldRemoteName           = oldItem.RemotePath;
                string   oldRemoteBaseName       = CmisUtils.GetUpperFolderOfCmisPath(oldRemoteName);
                bool     oldPathnameWorthSyncing = Utils.WorthSyncing(oldDirectory, oldFilename, repoInfo);

                // New item.
                bool     isFolder                = Utils.IsFolder(newPathname);
                string   newDirectory            = Path.GetDirectoryName(newPathname); // TODO do this only if isFolder is true, modify rest of the logic accordingly.
                string   newFilename             = Path.GetFileName(newPathname);
                string   newLocalName            = newPathname.Substring(localFolder.Length + 1);
                SyncItem newItem                 = SyncItemFactory.CreateFromLocalPath(newPathname, isFolder, repoInfo, database);
                string   newRemoteName           = newItem.RemotePath;
                string   newRemoteBaseName       = CmisUtils.GetUpperFolderOfCmisPath(newRemoteName);
                bool     newPathnameWorthSyncing = Utils.WorthSyncing(newDirectory, newFilename, repoInfo);

                // Operations.
                bool rename = oldDirectory.Equals(newDirectory) && !oldFilename.Equals(newFilename);
                bool move   = !oldDirectory.Equals(newDirectory) && oldFilename.Equals(newFilename);

                if ((rename && move) || (!rename && !move))
                {
                    Logger.ErrorFormat("Not a valid rename/move: {0} -> {1}", oldPathname, newPathname);
                    return(true); // It is not our problem that watcher data is not valid.
                }
                try
                {
                    if (oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        if (database.ContainsLocalFile(oldPathname))
                        {
                            if (database.ContainsLocalFile(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename file...
                                    IDocument remoteDocument = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    success &= RenameFile(oldDirectory, newFilename, remoteDocument);
                                }
                                else //move
                                {
                                    //move file...
                                    IDocument remoteDocument  = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    IFolder   oldRemoteFolder = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder   newRemoteFolder = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    success &= MoveFile(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteDocument);
                                }
                            }
                        }
                        else if (database.ContainsFolder(oldPathname))
                        {
                            if (database.ContainsFolder(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    success &= RenameFolder(oldDirectory, newFilename, remoteFolderObject);
                                }
                                else //move
                                {
                                    //move folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    IFolder oldRemoteFolder    = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder newRemoteFolder    = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    success &= MoveFolder(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteFolderObject);
                                }
                            }
                        }
                        else
                        {
                            //File/Folder has not been synced before so simply update
                            success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                        }
                    }
                    else if (oldPathnameWorthSyncing && !newPathnameWorthSyncing)
                    {
                        //New path not worth syncing
                        success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                    }
                    else if (!oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        //Old path not worth syncing
                        success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                    }
                    else
                    {
                        //Neither old or new path worth syncing
                    }
                }
                catch (Exception e)
                {
                    success = false;
                    ProcessRecoverableException("Could process watcher sync move: " + oldPathname + " -> " + newPathname, e);
                }
                return(success);
            }
Exemple #10
0
            /// <summary>
            /// Watchers the sync update.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            private void WatcherSyncUpdate(string remoteFolder, string localFolder, string pathname)
            {
                string name           = pathname.Substring(localFolder.Length + 1);
                string remotePathname = CmisUtils.PathCombine(remoteFolder, name);

                IFolder remoteBase = null;

                if (File.Exists(pathname) || Directory.Exists(pathname))
                {
                    string remoteBaseName = Path.GetDirectoryName(remotePathname).Replace('\\', '/');
                    try
                    {
                        remoteBase = (IFolder)session.GetObjectByPath(remoteBaseName);
                    }
                    catch (Exception e)
                    {
                        Logger.Warn(String.Format("Exception when query remote {0}: ", remoteBaseName), e);
                    }
                    if (null == remoteBase)
                    {
                        Logger.Warn(String.Format("The remote base folder {0} for local {1} does not exist, ignore for the update action", remoteBaseName, pathname));
                        return;
                    }
                }
                else
                {
                    Logger.Info(String.Format("The file/folder {0} is deleted, ignore for the update action", pathname));
                    return;
                }

                try
                {
                    if (File.Exists(pathname))
                    {
                        bool success = false;
                        repo.Watcher.RemoveChange(pathname, Watcher.ChangeTypes.Created);
                        repo.Watcher.RemoveChange(pathname, Watcher.ChangeTypes.Changed);

                        if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo)))
                        {
                            if (database.LocalFileHasChanged(pathname))
                            {
                                success = UpdateFile(pathname, remoteBase);
                                Logger.Info(String.Format("Update {0}: {1}", pathname, success));
                            }
                            else
                            {
                                success = true;
                                Logger.Info(String.Format("File {0} remains unchanged, ignore for the update action", pathname));
                            }
                        }
                        else
                        {
                            success = UploadFile(pathname, remoteBase);
                            Logger.Info(String.Format("Upload {0}: {1}", pathname, success));
                        }
                        if (!success)
                        {
                            Logger.Warn("Failure to update: " + pathname);
                            repo.Watcher.InsertChange(pathname, Watcher.ChangeTypes.Changed);
                        }
                        return;
                    }
                }
                catch (Exception e)
                {
                    Logger.Warn(String.Format("Exception while sync to update file {0} : ", pathname), e);
                    return;
                }

                try
                {
                    if (Directory.Exists(pathname))
                    {
                        if (repoinfo.isPathIgnored(remotePathname))
                        {
                            repo.Watcher.RemoveChange(pathname);
                            return;
                        }

                        if (database.ContainsFolder(pathname))
                        {
                            Logger.Info(String.Format("Database exists for {0}, ignore for the update action", pathname));
                            repo.Watcher.RemoveChange(pathname);
                        }
                        else
                        {
                            Logger.Info("Uploading local folder to server: " + pathname);
                            UploadFolderRecursively(remoteBase, pathname);
                            repo.Watcher.RemoveChange(pathname);
                        }
                        return;
                    }
                }
                catch (Exception e)
                {
                    Logger.Warn(String.Format("Exception while sync to update folder {0}: ", pathname), e);
                    return;
                }

                Logger.Info(String.Format("The file/folder {0} is deleted, ignore for the update action", pathname));
            }
            /// <summary>
            /// Apply: Deleted folders.
            /// </summary>
            public bool ApplyDeletedFolders(ref List <string> deletedFolders)
            {
                bool success = true;

                foreach (string deletedFolder in deletedFolders)
                {
                    SyncItem deletedItem = SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database);
                    try
                    {
                        var deletedIFolder = session.GetObjectByPath(deletedItem.RemotePath, true) as IFolder;

                        // Check whether the remote folder has changes we haven't gotten yet (conflict)
                        var changed = HasFolderChanged(deletedIFolder);

                        // Delete the remote folder if unchanged, otherwise let full sync handle the conflict.
                        var remotePath    = deletedItem.RemotePath;
                        var localPath     = deletedItem.LocalPath;
                        var remoteFolders = new List <string>();

                        if (changed)
                        {
                            // TODO: Internationalization
                            string message = String.Format("Restoring folder {0} because its sub-items have been modified on the server. You can delete it again.", localPath);
                            Utils.NotifyUser(message);

                            // TODO: Handle folder conflict
                            // Delete local database entry.
                            database.RemoveFolder(SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database));

                            DownloadDirectory(deletedIFolder, remotePath, localPath);

                            return(false);
                        }
                        else
                        {
                            DeleteRemoteFolder(deletedIFolder, deletedItem, Utils.UpperFolderLocal(deletedItem.LocalPath));
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                        {
                            // Typical error when the document does not exist anymore on the server
                            // TODO Make DotCMIS generate a more precise exception.

                            Logger.Error("The folder has probably been deleted on the server already: " + deletedFolder, e);

                            // Delete local database entry.
                            database.RemoveFolder(SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database));

                            // Note: This is not a failure per-se, so we don't need to modify the "success" variable.
                        }
                        else
                        {
                            Logger.Error("Error applying local folder deletion to the server: " + deletedFolder, e);
                            success = false;
                        }
                    }
                }
                return(success);
            }
Exemple #12
0
            /// <summary>
            /// Sync update.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            private bool WatcherSyncUpdate(string remoteFolder, string localFolder, string pathname)
            {
                SleepWhileSuspended();
                string filename = Path.GetFileName(pathname);

                if (!Utils.WorthSyncing(Path.GetDirectoryName(pathname), filename, repoInfo))
                {
                    return(true);
                }
                try
                {
                    string  name       = pathname.Substring(localFolder.Length + 1);
                    string  remoteName = Path.Combine(remoteFolder, name).Replace('\\', '/');
                    IFolder remoteBase = null;
                    if (File.Exists(pathname) || Directory.Exists(pathname))
                    {
                        string remoteBaseName = Path.GetDirectoryName(remoteName).Replace('\\', '/');
                        remoteBase = (IFolder)session.GetObjectByPath(remoteBaseName);
                        if (null == remoteBase)
                        {
                            Logger.WarnFormat("The remote base folder {0} for local {1} does not exist, ignore for the update action", remoteBaseName, pathname);
                            return(true); // Ignore is not a failure.
                        }
                    }
                    else
                    {
                        Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", pathname);
                        return(true);
                    }
                    if (File.Exists(pathname))
                    {
                        bool success = false;
                        if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(pathname, repoInfo)))
                        {
                            if (database.LocalFileHasChanged(pathname))
                            {
                                success = UpdateFile(pathname, remoteBase);
                                Logger.InfoFormat("Update {0}: {1}", pathname, success);
                            }
                            else
                            {
                                success = true;
                                Logger.InfoFormat("File {0} remains unchanged, ignore for the update action", pathname);
                            }
                        }
                        else
                        {
                            success = UploadFile(pathname, remoteBase);
                            Logger.InfoFormat("Upload {0}: {1}", pathname, success);
                        }
                        if (success)
                        {
                            return(true);
                        }
                        else
                        {
                            Logger.WarnFormat("Failure to update: {0}", pathname);
                            return(false);
                        }
                    }
                    if (Directory.Exists(pathname))
                    {
                        bool success = true;
                        if (database.ContainsFolder(pathname))
                        {
                            Logger.InfoFormat("Folder exists in Database {0}, ignore for the update action", pathname);
                        }
                        else
                        {
                            Logger.InfoFormat("Create locally created folder on server: {0}", pathname);
                            success &= UploadFolderRecursively(remoteBase, pathname);
                        }
                        return(success);
                    }
                    Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", pathname);
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync update: " + pathname, e);
                    return(false);
                }
                return(true);
            }
            /// <summary>
            /// Check whether a change is relevant for the current synchronized folder.
            /// </summary>

            /*private bool ChangeIsApplicable(IChangeEvent change)
             * {
             *  ICmisObject cmisObject = null;
             *  IFolder remoteFolder = null;
             *  IDocument remoteDocument = null;
             *  IList<string> remotePaths = null;
             *  var changeIdForDebug = change.Properties.ContainsKey("cmis:name") ?
             *      change.Properties["cmis:name"][0] : change.Properties["cmis:objectId"][0]; // TODO is it different from change.ObjectId ?
             *
             *  // Get the remote changed object.
             *  try
             *  {
             *      cmisObject = session.GetObject(change.ObjectId);
             *  }
             *  catch (CmisObjectNotFoundException)
             *  {
             *      Logger.Info("Changed object has already been deleted on the server. Syncing just in case: " + changeIdForDebug);
             *      // Unfortunately, in this case we can not know whether the object was relevant or not.
             *      return true;
             *  }
             *  catch (CmisRuntimeException e)
             *  {
             *      if (e.Message.Equals("Unauthorized"))
             *      {
             *          Logger.Info("We can not read the object id, so it is not an object we can sync anyway: " + changeIdForDebug);
             *          return false;
             *      }
             *      else
             *      {
             *          Logger.Info("A CMIS exception occured when querying the change. Syncing just in case: " + changeIdForDebug + " :", e);
             *          return true;
             *      }
             *
             *  }
             *  catch (CmisPermissionDeniedException e)
             *  {
             *      Logger.Info("Permission denied object  : " + changeIdForDebug + " :", e);
             *      return false;
             *  }
             *  catch (Exception e)
             *  {
             *      Logger.Warn("An exception occurred, syncing just in case: " + changeIdForDebug + " :", e);
             *      return true;
             *  }
             *
             *  // Check whether change is about a document or folder.
             *  remoteDocument = cmisObject as IDocument;
             *  remoteFolder = cmisObject as IFolder;
             *  if (remoteDocument == null && remoteFolder == null)
             *  {
             *      Logger.Info("Ignore change as it is not about a document nor folder: " + changeIdForDebug);
             *      return false;
             *  }
             *
             *  // Check whether it is a document worth syncing.
             *  if (remoteDocument != null)
             *  {
             *      if (!Utils.IsFileWorthSyncing(repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo))
             *      {
             *          Logger.Info("Ignore change as it is about a document unworth syncing: " + changeIdForDebug);
             *          return false;
             *      }
             *      if (remoteDocument.Paths.Count == 0)
             *      {
             *          Logger.Info("Ignore the unfiled object: " + changeIdForDebug);
             *          return false;
             *      }
             *
             *      // We will check the remote document's path(s) at the end of this method.
             *      remotePaths = remoteDocument.Paths;
             *  }
             *
             *  // Check whether it is a folder worth syncing.
             *  if (remoteFolder != null)
             *  {
             *      remotePaths = new List<string>();
             *      remotePaths.Add(remoteFolder.Path);
             *  }
             *
             *  // Check the object's path(s)
             *  foreach (string remotePath in remotePaths)
             *  {
             *      if (PathIsApplicable(remotePath))
             *      {
             *          Logger.Debug("Change is applicable. Sync:" + changeIdForDebug);
             *          return true;
             *      }
             *  }
             *
             *  // No path was relevant, so ignore the change.
             *  return false;
             * }*/


            /// <summary>
            /// Apply CMIS ChangeLog changes.
            /// </summary>
            private bool CrawlChangeLogSyncAndUpdateChangeLogToken(IList <IChangeEvent> changeLogs, IFolder remoteFolder, string remotePath, string localFolder)
            {
                SleepWhileSuspended();
                bool success = true;
                var  sw      = new System.Diagnostics.Stopwatch();

                activityListener.ActivityStarted();
                try
                {
                    sw.Start();
                    Logger.InfoFormat("Change log sync start : {0} logs", changeLogs.Count());

                    // TODO: Compact changelogs

                    foreach (var change in changeLogs)
                    {
                        var id = change.ObjectId;
                        try
                        {
                            Logger.InfoFormat("Change log : Type={0}, Name={1}, Id={2}", change.ChangeType, change.Properties["cmis:name"].First(), id);
                        }
                        catch
                        {
                            Logger.InfoFormat("Change log : Type={0}, Id={1} ", change.ChangeType, id);
                        }

                        try
                        {
                            // Get the object with that identifier. Note that it might not exist anymore, so errors are expected, no need to log their details.
                            var cmisObject = session.GetObject(id, false);
                            if (change.ChangeType == ChangeType.Updated)
                            {
                                // Updates are tricky, as they can be move/rename operations in which we don't get complete information about
                                // both the source and destination.
                                // So, just sync everything.

                                success &= CrawlSyncAndUpdateChangeLogToken(remoteFolder, remoteFolderPath, localFolder);;
                                break; // We synced everything, so no need to process the rest of the changes.
                            }
                            else
                            {
                                // The change only applies to the object itself, so only crawl that object.
                                success &= CrawlCmisObject(cmisObject);
                            }
                        }
                        catch (CmisObjectNotFoundException ex)
                        {
                            if (change.ChangeType == ChangeType.Deleted)
                            {
                                var local = database.GetSyncItem(id);
                                if (local != null)
                                {
                                    var destFolderPath = Path.GetDirectoryName(local.LocalPath);
                                    var destFolderItem = SyncItemFactory.CreateFromLocalPath(destFolderPath, true, repoInfo, database);

                                    try
                                    {
                                        var destCmisFolder = session.GetObjectByPath(destFolderItem.RemotePath, true) as IFolder;

                                        if (local.IsFolder)
                                        {
                                            success &= CrawlSync(destCmisFolder, destFolderItem.RemotePath, destFolderItem.LocalPath);
                                        }
                                        else
                                        {
                                            success &= CheckLocalFile(local.LocalPath, destCmisFolder, null);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                                        {
                                            // GetObjectByPath failure
                                            Logger.InfoFormat("Remote parent object not found, ignore. {0}", destFolderItem.RemotePath);
                                        }
                                        else
                                        {
                                            // Something really bad and unexpected happened.
                                            // Give up the ChangeLog strategy, and just crawl everything, this is better than failing.
                                            success &= CrawlSyncAndUpdateChangeLogToken(remoteFolder, remoteFolderPath, localFolder);;
                                            break; // We synced everything, so no need to process the rest of the changes.
                                        }
                                    }
                                }
                                else
                                {
                                    Logger.InfoFormat("Remote deleted object not in local database, ignore. {0}", id);
                                }
                            }
                            else
                            {
                                Logger.InfoFormat("Remote object not found but delete event, ignore. {0}", id);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                    }

                    sw.Stop();
                    Logger.InfoFormat("Change log sync end : {1} min / {0} logs", changeLogs.Count(), sw.Elapsed);
                }
                finally
                {
                    activityListener.ActivityStopped();
                }
                return(success);
            }
Exemple #14
0
            /// <summary>
            /// Check a local file in a given directory (not recursive).
            /// </summary>
            /// <param name="localFilenameTranslationOfExistingRemoteDocuments">Remove the file if it is not in this list of remote files (translated to local filenames). Ignored if null</param>
            private bool CheckLocalFile(string localFilePath, IFolder remoteFolder, IList <string> localFilenameTranslationOfExistingRemoteDocuments)
            {
                SleepWhileSuspended();
                bool success = true;

                try
                {
                    if (Utils.IsSymlink(new FileInfo(localFilePath)))
                    {
                        Logger.Info("Skipping symbolic linked file: " + localFilePath);
                        return(true);
                    }

                    var item = database.GetSyncItemFromLocalPath(localFilePath);
                    if (null == item)
                    {
                        // The file has been recently created locally (not synced from server).
                        item = SyncItemFactory.CreateFromLocalPath(localFilePath, false, repoInfo, database);
                    }

                    string fileName = item.LocalLeafname;

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localFilePath), fileName, repoInfo))
                    {
                        if (localFilenameTranslationOfExistingRemoteDocuments == null ||
                            !localFilenameTranslationOfExistingRemoteDocuments.Contains(fileName))
                        {
                            // This local file is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsLocalFile(localFilePath))
                            {
                                if (database.LocalFileHasChanged(localFilePath))
                                {
                                    // If file has changed locally, move to 'your_version' and warn about conflict
                                    Logger.Info("Conflict with file: " + localFilePath + ", backing up locally modified version.");
                                    activityListener.ActivityStarted();
                                    // Rename locally modified file.
                                    String newFilePath = Utils.CreateConflictFilename(localFilePath, repoInfo.User);

                                    // The file might be ReadOnly, so make it writable first, otherwise the move will fail.
                                    File.SetAttributes(localFilePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                    File.Move(localFilePath, newFilePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    repo.OnConflictResolved();
                                    activityListener.ActivityStopped();
                                }
                                else
                                {
                                    // File has been deleted on server, so delete it locally.
                                    Logger.Info("Removing remotely deleted file: " + localFilePath);
                                    activityListener.ActivityStarted();

                                    // Delete from the local filesystem.
                                    Utils.DeleteEvenIfReadOnly(localFilePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    activityListener.ActivityStopped();
                                }
                            }
                            else
                            {
                                // New file, sync up.
                                Logger.Info("Uploading file absent on repository: " + localFilePath);
                                activityListener.ActivityStarted();
                                success &= UploadFile(localFilePath, remoteFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                        else
                        {
                            // The file exists both on server and locally.
                            if (database.LocalFileHasChanged(localFilePath))
                            {
                                // Upload new version of file content.
                                Logger.Info("Uploading file update on repository: " + localFilePath);
                                activityListener.ActivityStarted();
                                success &= UpdateFile(localFilePath, remoteFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local file: " + localFilePath, e);
                    success = false;
                }
                return(success);
            }
Exemple #15
0
            /// <summary>
            /// Watchers the sync delete.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo))) // FIXME remote or local?
                    {
                        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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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;
            }
Exemple #16
0
            /// <summary>
            /// Sync move file.
            /// </summary>
            private void WatchSyncMove(string remoteFolder, string localFolder, string oldPathname, string newPathname)
            {
                SleepWhileSuspended();
                string oldDirectory            = Path.GetDirectoryName(oldPathname);
                string oldFilename             = Path.GetFileName(oldPathname);
                string oldLocalName            = oldPathname.Substring(localFolder.Length + 1);
                string oldRemoteName           = Path.Combine(remoteFolder, oldLocalName).Replace('\\', '/'); // FIXME
                string oldRemoteBaseName       = Path.GetDirectoryName(oldRemoteName).Replace('\\', '/');
                bool   oldPathnameWorthSyncing = Utils.WorthSyncing(oldDirectory, oldFilename, repoinfo);
                string newDirectory            = Path.GetDirectoryName(newPathname);
                string newFilename             = Path.GetFileName(newPathname);
                string newLocalName            = newPathname.Substring(localFolder.Length + 1);
                string newRemoteName           = Path.Combine(remoteFolder, newLocalName).Replace('\\', '/');
                string newRemoteBaseName       = Path.GetDirectoryName(newRemoteName).Replace('\\', '/');
                bool   newPathnameWorthSyncing = Utils.WorthSyncing(newDirectory, newFilename, repoinfo);
                bool   rename = oldDirectory.Equals(newDirectory) && !oldFilename.Equals(newFilename);
                bool   move   = !oldDirectory.Equals(newDirectory) && oldFilename.Equals(newFilename);

                if ((rename && move) || (!rename && !move))
                {
                    Logger.ErrorFormat("Not a valid rename/move: {0} -> {1}", oldPathname, newPathname);
                    return;
                }
                try
                {
                    if (oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(oldPathname, repoinfo)))
                        {
                            if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(newPathname, repoinfo)))
                            {
                                //database already contains path so revert back to delete/update
                                WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename file...
                                    IDocument remoteDocument = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    RenameFile(oldDirectory, newFilename, remoteDocument);
                                }
                                else //move
                                {
                                    //move file...
                                    IDocument remoteDocument  = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    IFolder   oldRemoteFolder = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder   newRemoteFolder = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    MoveFile(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteDocument);
                                }
                            }
                        }
                        else if (database.ContainsFolder(oldPathname))
                        {
                            if (database.ContainsFolder(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    RenameFolder(oldDirectory, newFilename, remoteFolderObject);
                                }
                                else //move
                                {
                                    //move folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    IFolder oldRemoteFolder    = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder newRemoteFolder    = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    MoveFolder(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteFolderObject);
                                }
                            }
                        }
                        else
                        {
                            //File/Folder has not been synced before so simply update
                            WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                        }
                    }
                    else if (oldPathnameWorthSyncing && !newPathnameWorthSyncing)
                    {
                        //New path not worth syncing
                        WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                    }
                    else if (!oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        //Old path not worth syncing
                        WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                    }
                    else
                    {
                        //Neither old or new path worth syncing
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync move: " + oldPathname + " -> " + newPathname, e);
                }
            }
Exemple #17
0
            /// <summary>
            /// Check whether a change is relevant for the current synchronized folder.
            /// </summary>

            /*private bool ChangeIsApplicable(IChangeEvent change)
             * {
             *  ICmisObject cmisObject = null;
             *  IFolder remoteFolder = null;
             *  IDocument remoteDocument = null;
             *  IList<string> remotePaths = null;
             *  var changeIdForDebug = change.Properties.ContainsKey("cmis:name") ?
             *      change.Properties["cmis:name"][0] : change.Properties["cmis:objectId"][0]; // TODO is it different from change.ObjectId ?
             *
             *  // Get the remote changed object.
             *  try
             *  {
             *      cmisObject = session.GetObject(change.ObjectId);
             *  }
             *  catch (CmisObjectNotFoundException)
             *  {
             *      Logger.Info("Changed object has already been deleted on the server. Syncing just in case: " + changeIdForDebug);
             *      // Unfortunately, in this case we can not know whether the object was relevant or not.
             *      return true;
             *  }
             *  catch (CmisRuntimeException e)
             *  {
             *      if (e.Message.Equals("Unauthorized"))
             *      {
             *          Logger.Info("We can not read the object id, so it is not an object we can sync anyway: " + changeIdForDebug);
             *          return false;
             *      }
             *      else
             *      {
             *          Logger.Info("A CMIS exception occured when querying the change. Syncing just in case: " + changeIdForDebug + " :", e);
             *          return true;
             *      }
             *
             *  }
             *  catch (CmisPermissionDeniedException e)
             *  {
             *      Logger.Info("Permission denied object  : " + changeIdForDebug + " :", e);
             *      return false;
             *  }
             *  catch (Exception e)
             *  {
             *      Logger.Warn("An exception occurred, syncing just in case: " + changeIdForDebug + " :", e);
             *      return true;
             *  }
             *
             *  // Check whether change is about a document or folder.
             *  remoteDocument = cmisObject as IDocument;
             *  remoteFolder = cmisObject as IFolder;
             *  if (remoteDocument == null && remoteFolder == null)
             *  {
             *      Logger.Info("Ignore change as it is not about a document nor folder: " + changeIdForDebug);
             *      return false;
             *  }
             *
             *  // Check whether it is a document worth syncing.
             *  if (remoteDocument != null)
             *  {
             *      if (!Utils.IsFileWorthSyncing(repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo))
             *      {
             *          Logger.Info("Ignore change as it is about a document unworth syncing: " + changeIdForDebug);
             *          return false;
             *      }
             *      if (remoteDocument.Paths.Count == 0)
             *      {
             *          Logger.Info("Ignore the unfiled object: " + changeIdForDebug);
             *          return false;
             *      }
             *
             *      // We will check the remote document's path(s) at the end of this method.
             *      remotePaths = remoteDocument.Paths;
             *  }
             *
             *  // Check whether it is a folder worth syncing.
             *  if (remoteFolder != null)
             *  {
             *      remotePaths = new List<string>();
             *      remotePaths.Add(remoteFolder.Path);
             *  }
             *
             *  // Check the object's path(s)
             *  foreach (string remotePath in remotePaths)
             *  {
             *      if (PathIsApplicable(remotePath))
             *      {
             *          Logger.Debug("Change is applicable. Sync:" + changeIdForDebug);
             *          return true;
             *      }
             *  }
             *
             *  // No path was relevant, so ignore the change.
             *  return false;
             * }*/


            /// <summary>
            /// Apply CMIS ChangeLog changes.
            /// </summary>
            private void CrawlChangeLogSyncAndUpdateChangeLogToken(IList <IChangeEvent> changeLogs, IFolder remoteFolder, string remotePath, string localFolder)
            {
                SleepWhileSuspended();

                var sw = new System.Diagnostics.Stopwatch();

                activityListener.ActivityStarted();
                try
                {
                    sw.Start();
                    Logger.InfoFormat("Change log sync start : {0} logs", changeLogs.Count());

                    // TODO: Compact changelogs

                    foreach (var change in changeLogs)
                    {
                        var id = change.ObjectId;
                        try
                        {
                            Logger.InfoFormat("Change log : Type={0}, Name={1}, Id={2}", change.ChangeType, change.Properties["cmis:name"].First(), id);
                        }
                        catch
                        {
                            Logger.InfoFormat("Change log : Type={0}, Id={1} ", change.ChangeType, id);
                        }

                        try
                        {
                            var cmisObject = session.GetObject(id);
                            CrawlCmisObject(cmisObject);
                        }
                        catch (CmisObjectNotFoundException ex)
                        {
                            if (change.ChangeType == ChangeType.Deleted)
                            {
                                var local = database.GetSyncItem(id);
                                if (local != null)
                                {
                                    var destFolderPath = Path.GetDirectoryName(local.LocalPath);
                                    var destFolderItem = SyncItemFactory.CreateFromLocalPath(destFolderPath, true, repoInfo, database);

                                    try
                                    {
                                        var destCmisFolder = session.GetObjectByPath(destFolderItem.RemotePath) as IFolder;

                                        if (local.IsFolder)
                                        {
                                            CrawlSync(destCmisFolder, destFolderItem.RemotePath, destFolderItem.LocalPath);
                                        }
                                        else
                                        {
                                            CheckLocalFile(local.LocalPath, destCmisFolder, new List <string>());
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                                        {
                                            // GetObjectByPath failure
                                            Logger.InfoFormat("Remote parent object not found, ignore. {0}", destFolderItem.RemotePath);
                                        }
                                        else
                                        {
                                            throw;
                                        }
                                    }
                                }
                                else
                                {
                                    Logger.InfoFormat("Remote deleted object not in local database, ignore. {0}", id);
                                }
                            }
                            else
                            {
                                Logger.InfoFormat("Remote object not found but delete event, ignore. {0}", id);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                    }

                    sw.Stop();
                    Logger.InfoFormat("Change log sync end : {1} min / {0} logs", changeLogs.Count(), sw.Elapsed);
                }
                finally
                {
                    activityListener.ActivityStopped();
                }
            }
Exemple #18
0
            /// <summary>
            /// Apply a remote change for Created or Updated.
            /// </summary>
            private bool ApplyRemoteChangeUpdate(IChangeEvent change)
            {
                ICmisObject cmisObject     = null;
                IFolder     remoteFolder   = null;
                IDocument   remoteDocument = null;
                string      remotePath     = null;
                ICmisObject remoteObject   = null;
                IFolder     remoteParent   = null;

                try
                {
                    cmisObject = session.GetObject(change.ObjectId);
                }
                catch (CmisObjectNotFoundException)
                {
                    Logger.Info("Ignore the missed object for " + change.ObjectId);
                    return(true);
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + change.ObjectId + " :", e);
                    return(false);
                }

                remoteDocument = cmisObject as IDocument;
                remoteFolder   = cmisObject as IFolder;
                if (remoteDocument == null && remoteFolder == null)
                {
                    Logger.Info("Change in no sync object: " + change.ObjectId);
                    return(true);
                }
                if (remoteDocument != null)
                {
                    if (!Utils.IsFileWorthSyncing(remoteDocument.Name, repoinfo))
                    {
                        Logger.Info("Change in remote unworth syncing file: " + remoteDocument.Paths);
                        return(true);
                    }
                    if (remoteDocument.Paths.Count == 0)
                    {
                        Logger.Info("Ignore the unfiled object: " + remoteDocument.Name);
                        return(true);
                    }
                    // TODO: Support Multiple Paths
                    remotePath   = remoteDocument.Paths[0];
                    remoteParent = remoteDocument.Parents[0];
                }
                if (remoteFolder != null)
                {
                    remotePath   = remoteFolder.Path;
                    remoteParent = remoteFolder.FolderParent;
                    foreach (string name in remotePath.Split('/'))
                    {
                        if (!String.IsNullOrEmpty(name) && Utils.IsInvalidFolderName(name))
                        {
                            Logger.Info(String.Format("Change in illegal syncing path name {0}: {1}", name, remotePath));
                            return(true);
                        }
                    }
                }

                if (!remotePath.StartsWith(this.remoteFolderPath))
                {
                    Logger.Info("Change in unrelated path: " + remotePath);
                    return(true);    // The change is not under the folder we care about.
                }

                if (this.repoinfo.isPathIgnored(remotePath))
                {
                    Logger.Info("Change in ignored path: " + remotePath);
                    return(true);
                }

                string relativePath = remotePath.Substring(remoteFolderPath.Length);

                if (relativePath.Length <= 0)
                {
                    Logger.Info("Ignore change in root path: " + remotePath);
                    return(true);
                }
                if (relativePath[0] == '/')
                {
                    relativePath = relativePath.Substring(1);
                }

                try
                {
                    remoteObject = session.GetObjectByPath(remotePath);
                }
                catch (CmisObjectNotFoundException)
                {
                    Logger.Info(String.Format("Ignore remote path {0} deleted from id {1}", remotePath, cmisObject.Id));
                    return(true);
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + remotePath + " : ", e);
                    return(false);
                }

                if (remoteObject.Id != cmisObject.Id)
                {
                    Logger.Info(String.Format("Ignore remote path {0} changed from id {1} to id {2}", remotePath, cmisObject.Id, remoteObject.Id));
                    return(true);
                }

                string localPath = Path.Combine(repoinfo.TargetDirectory, relativePath).Replace('/', Path.DirectorySeparatorChar);

                if (!DownloadFolder(remoteParent, Path.GetDirectoryName(localPath)))
                {
                    Logger.Warn("Failed to download the parent folder for " + localPath);
                    return(false);
                }

                if (null != remoteDocument)
                {
                    Logger.Info(String.Format("New remote file ({0}) found.", remotePath));
                    //  check moveObject
                    string savedDocumentPath = database.GetRemoteFilePath(change.ObjectId);
                    if ((null != savedDocumentPath) && (savedDocumentPath != localPath))
                    {
                        if (File.Exists(localPath))
                        {
                            File.Delete(savedDocumentPath);
                            database.RemoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo));
                        }
                        else
                        {
                            if (File.Exists(savedDocumentPath))
                            {
                                if (!Directory.Exists(Path.GetDirectoryName(localPath)))
                                {
                                    Logger.Warn("Creating local directory: " + localPath);
                                    Directory.CreateDirectory(Path.GetDirectoryName(localPath));
                                }
                                File.Move(savedDocumentPath, localPath);
                            }
                            database.MoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo), SyncItemFactory.CreateFromLocalPath(savedDocumentPath, repoinfo));
                        }
                    }

                    return(SyncDownloadFile(remoteDocument, Path.GetDirectoryName(localPath)));
                }

                if (null != remoteFolder)
                {
                    Logger.Info(String.Format("New remote folder ({0}) found.", remotePath));
                    //  check moveObject
                    string savedFolderPath = database.GetFolderPath(change.ObjectId);
                    if ((null != savedFolderPath) && (savedFolderPath != localPath))
                    {
// TODO                        MoveFolderLocally(savedFolderPath, localPath);
                        CrawlSync(remoteFolder, localPath);
                    }
                    else
                    {
                        SyncDownloadFolder(remoteFolder, Path.GetDirectoryName(localPath));
                        CrawlSync(remoteFolder, localPath);
                    }
                }

                return(true);
            }
Exemple #19
0
            /// <summary>
            /// Check a particular local folder (not recursive).
            /// See whether it has been deleted locally or not.
            /// </summary>
            private void CheckLocalFolder(string localSubFolder, IFolder remoteRoot, IList <string> remoteFolders)
            {
                SleepWhileSuspended();
                try
                {
                    if (Utils.IsSymlink(new DirectoryInfo(localSubFolder)))
                    {
                        Logger.Info("Skipping symbolic link folder: " + localSubFolder);
                        return;
                    }

                    string folderName = Path.GetFileName(localSubFolder);

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localSubFolder), folderName, repoInfo))
                    {
                        var syncFolderItem = database.GetFolderSyncItemFromLocalPath(localSubFolder);
                        if (null == syncFolderItem)
                        {
                            // The local item is not in database. It has not been uploaded yet.
                            syncFolderItem = SyncItemFactory.CreateFromLocalPath(localSubFolder, true, repoInfo, database);
                        }

                        if (remoteFolders.Contains(syncFolderItem.RemoteLeafname))
                        {
                            // The same folder exists locally and remotely.
                            // Are they synchronized, or were they just created (or moved) at the same time?
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                // Check modification dates of local folder and remote folder.
                                // TODO
                            }
                            else
                            {
                                // The folder just appeared both on the local and remote sides.
                                // Rename local folder then download remote folder.

                                IFolder remoteFolder = (IFolder)session.GetObjectByPath(syncFolderItem.RemotePath);

                                var path    = syncFolderItem.LocalPath;
                                var newPath = Utils.CreateConflictFoldername(path, repoInfo.User);

                                Directory.Move(path, newPath);

                                // Delete file from database.
                                database.RemoveFile(syncFolderItem);

                                repo.OnConflictResolved();

                                // Download folder from server.
                                DownloadDirectory(remoteFolder, syncFolderItem.RemotePath, path);
                            }
                        }
                        else
                        {
                            // This local folder is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                activityListener.ActivityStarted();
                                RemoveFolderLocally(localSubFolder);
                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                // New local folder, upload recursively.
                                activityListener.ActivityStarted();
                                UploadFolderRecursively(remoteRoot, localSubFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local folder: " + localSubFolder, e);
                }
            }