예제 #1
0
            /// <summary>
            /// Takes the loaded and given descendants as children of the given remoteFolder and checks agains the localFolder
            /// </summary>
            /// <param name="remoteFolder">Folder which contains to given children</param>
            /// <param name="children">All children of the given remote folder</param>
            /// <param name="localFolder">The local folder, with which the remoteFolder should be synchronized</param>
            /// <returns></returns>
            private void CrawlDescendants(IFolder remoteFolder, IList <ITree <IFileableCmisObject> > children, string localFolder)
            {
                // Lists of files/folders, to delete those that have been removed on the server.
                IList <string> remoteFiles      = new List <string>();
                IList <string> remoteSubfolders = new List <string>();

                if (children != null)
                {
                    foreach (ITree <IFileableCmisObject> node in children)
                    {
                        #region Cmis Folder
                        if (node.Item is Folder)
                        {
                            // It is a CMIS folder.
                            IFolder remoteSubFolder = (IFolder)node.Item;
                            remoteSubfolders.Add(remoteSubFolder.Name);
                            if (!Utils.IsInvalidFolderName(remoteSubFolder.Name) && !repoinfo.isPathIgnored(remoteSubFolder.Path))
                            {
                                var syncItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                                if (null == syncItem)
                                {
                                    syncItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo);
                                }

                                //Check whether local folder exists.
                                if (Directory.Exists(syncItem.LocalPath))
                                {
                                    CrawlDescendants(remoteSubFolder, node.Children, syncItem.LocalPath);
                                }
                                else
                                {
                                    DownloadFolder(remoteSubFolder, localFolder);
                                    if (Directory.Exists(syncItem.LocalPath))
                                    {
                                        RecursiveFolderCopy(remoteSubFolder, syncItem.LocalPath);
                                    }
                                }
                            }
                        }
                        #endregion

                        #region Cmis Document
                        else if (node.Item is Document)
                        {
                            // It is a CMIS document.
                            string    remoteFolderPath   = remoteFolder.Path;
                            string    remoteDocumentName = ((IDocument)node.Item).Name;
                            IDocument remoteDocument     = (IDocument)node.Item;
                            SyncDownloadFile(remoteDocument, localFolder, remoteFiles);
                        }
                        #endregion
                    }
                }
                CrawlLocalFiles(localFolder, remoteFolder, remoteFiles);
                CrawlLocalFolders(localFolder, remoteFolder, remoteSubfolders);
            }
예제 #2
0
            /// <summary>
            /// Apply a remote change for Deleted.
            /// </summary>
            private bool ApplyRemoteChangeDelete(IChangeEvent change)
            {
                try
                {
                    ICmisObject remoteObject = session.GetObject(change.ObjectId);
                    if (null != remoteObject)
                    {
                        //  should be moveObject
                        Logger.Info("Ignore moveObject for id " + change.ObjectId);
                        return(true);
                    }
                }
                catch (CmisObjectNotFoundException)
                {
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + change.ObjectId + " : ", e);
                }
                string savedDocumentPath = database.GetRemoteFilePath(change.ObjectId); // FIXME use SyncItem to differentiate between local path and remote path

                if (null != savedDocumentPath)
                {
                    Logger.Info("Remove local document: " + savedDocumentPath);
                    if (File.Exists(savedDocumentPath))
                    {
                        File.Delete(savedDocumentPath);
                    }

                    database.RemoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo));
                    Logger.Info("Removed local document: " + savedDocumentPath);
                    return(true);
                }

                string savedFolderPath = database.GetFolderPath(change.ObjectId);

                if (null != savedFolderPath)
                {
                    Logger.Info("Remove local folder: " + savedFolderPath);
                    if (Directory.Exists(savedFolderPath))
                    {
                        Directory.Delete(savedFolderPath, true);
                        database.RemoveFolder(SyncItemFactory.CreateFromRemotePath(savedFolderPath, repoinfo));
                    }
                    Logger.Info("Removed local folder: " + savedFolderPath);
                    return(true);
                }

                return(true);
            }
예제 #3
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);
            }
예제 #4
0
            /// <summary>
            /// Crawl remote document, syncing down if needed.
            /// Meanwhile, cache remoteFiles, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteDocument(IDocument remoteDocument, string remotePath, string localFolder, IList <string> remoteFiles)
            {
                SleepWhileSuspended();

                if (Utils.WorthSyncing(localFolder, remoteDocument.Name, repoInfo))
                {
                    // 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 unusual to have a document where
                    // document.Name is "foo" and document.ContentStreamFileName is "foo.jpg".
                    string remoteDocumentFileName = remoteDocument.ContentStreamFileName;
                    //Logger.Debug("CrawlRemote doc: " + localFolder + CmisUtils.CMIS_FILE_SEPARATOR + 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);
                        return;
                    }

                    remoteFiles.Add(remoteDocumentFileName);

                    var paths      = remoteDocument.Paths;
                    var pathsCount = paths.Count;
                    var syncItem   = database.GetSyncItemFromRemotePath(remotePath);
                    if (null == syncItem)
                    {
                        syncItem = SyncItemFactory.CreateFromRemotePath(remotePath, repoInfo);
                    }

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

                        if (lastDatabaseUpdate == null)
                        {
                            Logger.Info("Downloading file absent from database: " + syncItem.LocalPath);
                            activityListener.ActivityStarted();
                            DownloadFile(remoteDocument, remotePath, localFolder);
                            activityListener.ActivityStopped();
                        }
                        else
                        {
                            // If the file has been modified since last time we downloaded it, then download again.
                            if (serverSideModificationDate > lastDatabaseUpdate)
                            {
                                activityListener.ActivityStarted();

                                if (database.LocalFileHasChanged(syncItem.LocalPath))
                                {
                                    Logger.Info("Conflict with file: " + remoteDocumentFileName + ", backing up locally modified version and downloading server version");
                                    Logger.Info("- serverSideModificationDate: " + serverSideModificationDate);
                                    Logger.Info("- lastDatabaseUpdate: " + lastDatabaseUpdate);
                                    Logger.Info("- Checksum in database: " + database.GetChecksum(syncItem.LocalPath));
                                    Logger.Info("- Checksum of local file: " + Database.Database.Checksum(syncItem.LocalPath));

                                    // Rename locally modified file.
                                    String newFilePath = Utils.CreateConflictFilename(syncItem.LocalPath, repoInfo.User);
                                    File.Move(syncItem.LocalPath, newFilePath);

                                    // Download server version
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                    Logger.Info("- Checksum of remote file: " + Database.Database.Checksum(syncItem.LocalPath));
                                    repo.OnConflictResolved();

                                    // Notify the user.
                                    string lastModifiedBy = CmisUtils.GetProperty(remoteDocument, "cmis:lastModifiedBy");
                                    string message        = String.Format(
                                        // Properties_Resources.ResourceManager.GetString("ModifiedSame", CultureInfo.CurrentCulture),
                                        "User {0} modified file \"{1}\" at the same time as you.",
                                        lastModifiedBy, syncItem.LocalPath)
                                                            + "\n\n"
                                                            // + Properties_Resources.ResourceManager.GetString("YourVersion", CultureInfo.CurrentCulture);
                                                            + "Your version has been saved as \"" + newFilePath + "\", please merge your important changes from it and then delete it.";
                                    Logger.Info(message);
                                    Utils.NotifyUser(message);
                                }
                                else
                                {
                                    Logger.Info("Downloading modified file: " + remoteDocumentFileName);
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                }

                                activityListener.ActivityStopped();
                            }
                        }
                    }
                    else
                    {
                        // The remote file exists locally.

                        if (database.ContainsFile(syncItem))
                        {
                            // The file used to be present locally (as revealed by the database), but does not exist anymore locally.
                            // So, it must have been deleted locally by the user.
                            // Thus, CmisSync must remove the file from the server too.

                            string message0 = "CmisSync Warning: You have deleted file " + syncItem.LocalPath + "\nCmisSync will now delete it from the server. If you actually did not delete this file, please report a bug at [email protected]";
                            Logger.Info(message0);
                            //Utils.NotifyUser(message0);

                            if ((bool)remoteDocument.IsVersionSeriesCheckedOut)
                            {
                                string message = String.Format("File {0} is checked out on the server by another user: {1}", syncItem.LocalPath, remoteDocument.CheckinComment);
                                Logger.Info(message);
                                Utils.NotifyUser(message);
                            }
                            else
                            {
                                // File has been recently removed locally, so remove it from server too.

                                activityListener.ActivityStarted();
                                Logger.Info("Removing locally deleted file on server: " + syncItem.RemotePath);
                                remoteDocument.DeleteAllVersions();
                                // Remove it from database.
                                database.RemoveFile(syncItem);
                                activityListener.ActivityStopped();
                            }
                        }
                        else
                        {
                            // New remote file, download it.

                            Logger.Info("New remote file: " + syncItem.RemotePath);
                            activityListener.ActivityStarted();
                            DownloadFile(remoteDocument, remotePath, localFolder);
                            activityListener.ActivityStopped();
                        }
                    }
                }
            }
예제 #5
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);
                }
            }
예제 #6
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);
                }
            }