/// <summary>
            /// Synchronize changes made to a particular CMIS object.
            /// </summary>
            private bool CrawlCmisObject(ICmisObject cmisObject)
            {
                bool success = true;

                if (cmisObject is DotCMIS.Client.Impl.Folder)
                {
                    var remoteSubFolder = cmisObject as IFolder;

                    // Look for the local equivalent.
                    var localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                    while (true)
                    {
                        // If other local folders have the same id, they are obsolete and must be deteled.
                        var foldersToDelete = database.GetAllFoldersWithCmisId(cmisObject.Id).Where(p => p.RemotePath != remoteSubFolder.Path);
                        foreach (var folderToDelete in foldersToDelete)
                        {
                            success &= RemoveFolderLocally(folderToDelete.LocalPath);
                        }
                        ;

                        if (localFolderItem != null || remoteSubFolder.IsRootFolder)
                        {
                            break;
                        }

                        // Go up one level before performing the same thing.
                        remoteSubFolder = remoteSubFolder.Parents[0]; //TODO: Fix Parents[0] for multi-parent repositories
                        localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                    }
                    ;

                    success &= CrawlSync(remoteSubFolder, remoteSubFolder.Path, localFolderItem.LocalPath);
                }
                else if (cmisObject is DotCMIS.Client.Impl.Document)
                {
                    var remoteDocument = cmisObject as IDocument;

                    // Apply the change on all paths via which it is applicable.
                    foreach (IFolder remoteIFolder in remoteDocument.Parents)
                    {
                        if (PathIsApplicable(remoteIFolder.Path))
                        {
                            Logger.Debug("Document change is applicable:" + remoteIFolder);

                            var localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteIFolder.Path);
                            var localFolder     = localFolderItem.LocalPath;

                            var remoteDocumentPath = CmisUtils.PathCombine(remoteIFolder.Path, repoInfo.CmisProfile.localFilename(remoteDocument));
                            var documentItem       = SyncItemFactory.CreateFromRemoteDocument(remoteDocumentPath, remoteDocument, repoInfo, database);

                            success &= CrawlRemoteDocument(remoteDocument, documentItem.RemotePath, localFolder, null);
                        }
                    }
                }
                return(success);
            }
Exemple #2
0
            /// <summary>
            /// Check 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, repoInfo.CmisProfile.localFilename(remoteDocument), 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 = repoInfo.CmisProfile.localFilename(remoteDocument);
                    //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 '" + repoInfo.CmisProfile.localFilename(remoteDocument) + "' with null content stream in " + localFolder);
                        return;
                    }

                    if (remoteFiles != null)
                    {
                        remoteFiles.Add(remoteDocumentFileName);
                    }

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

                    // Get HashCodes from the server
                    string hashDoc      = remoteDocument.GetPropertyValue("sy:hashDoc") as string;
                    string hashMetadata = remoteDocument.GetPropertyValue("sy:hashDoc") as string;

                    if (syncItem.FileExistsLocal())
                    {
                        // 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.GetFileChecksum(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
                                {
                                    if (database.GetFileChecksum(syncItem.LocalPath) != hashDoc || hashDoc == null)
                                    {
                                        Logger.Info("Downloading modified file: " + remoteDocumentFileName);
                                        DownloadFile(remoteDocument, remotePath, localFolder);
                                    }
                                    else
                                    {
                                        // Only the metadatas have changed
                                        Logger.Info("Updating modified remote metadata: " + remoteDocumentFileName);
                                        CreateMetadataFile(syncItem);
                                        database.SetFileServerSideModificationDate(syncItem, serverSideModificationDate);
                                    }
                                }

                                activityListener.ActivityStopped();
                            }
                        }
                    }
                    else
                    {
                        // The remote file does not exist on the local filesystem.

                        // Maybe the whole synchronized folder has disappeared?
                        // While rare for normal filesystems, that happens rather often with mounted folders (for instance encrypted folders)
                        // In such a case, we should abort this synchronization rather than delete the remote file.
                        if (!Directory.Exists(repoInfo.TargetDirectory))
                        {
                            throw new Exception("Local target directory has disappeared: " + repoInfo.TargetDirectory + " , aborting synchronization");
                        }

                        if (database.ContainsLocalFile(syncItem.LocalRelativePath))
                        {
                            // 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.

                            DeleteRemoteDocument(remoteDocument, syncItem);
                        }
                        else
                        {
                            // Maybe the file has been renamed
                            // Check if a file in the local folder with the remote document id exists
                            string id       = Utils.RemoveVersion(remoteDocument.Id);
                            string filePath = database.GetFilePath(id);
                            if (filePath != null)
                            {
                                // File has been moved
                                SyncItem oldSynctItem = database.GetSyncItem(id);
                                string   metadataFile = filePath + ".metadata";

                                if (database.GetFileChecksum(syncItem.LocalPath) != hashDoc || hashDoc == null)
                                {
                                    // New content, so delete the old and download the new
                                    File.Delete(filePath);
                                    database.RemoveFile(oldSynctItem);
                                    if (metadataFile != null)
                                    {
                                        File.Delete(metadataFile);
                                        database.RemoveMetadataFile(oldSynctItem);
                                    }
                                    // New remote file, download it.
                                    Logger.Info("New remote file: " + syncItem.RemotePath);
                                    activityListener.ActivityStarted();
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                    activityListener.ActivityStopped();
                                }
                                else
                                {
                                    // File content has not change, just move it locally
                                    File.Move(filePath, syncItem.LocalPath);
                                    database.MoveFile(oldSynctItem, syncItem);

                                    // Update Metadatas
                                    File.Delete(metadataFile);
                                    database.RemoveMetadataFile(oldSynctItem);
                                    CreateMetadataFile(syncItem);
                                }
                            }
                        }
                        // New remote file, download it.
                        Logger.Info("New remote file: " + syncItem.RemotePath);
                        activityListener.ActivityStarted();
                        DownloadFile(remoteDocument, remotePath, localFolder);
                        activityListener.ActivityStopped();
                    }
                }
            }
Exemple #3
0
            private bool CrawlSyncQuery(IFolder remoteFolder, string remoteFolderPath, string localFolder)
            {
                bool success = true;

                try
                {
                    //IList<string> remoteFolders = new List<string>();

                    //IList<string> localFolders = database.getfoldersId();

                    IList <string> qFolders = queryAddedAndModifiedFolders(remoteFolder);


                    // Folders
                    foreach (string fId in qFolders)
                    {
                        try
                        {
                            IFolder folder = session.GetObject(fId) as IFolder;

                            SyncItem newFolderItem = SyncItemFactory.CreateFromRemoteFolder(folder.Path, repoInfo, database);

                            // Check if the folder already exists
                            IList <SyncItem> localfolders = database.GetAllFoldersWithCmisId(fId);
                            if (localfolders != null)
                            {
                                foreach (SyncItem oldFolderItem in localfolders)
                                {
                                    // if directory did not exists -> Move
                                    if (!Directory.Exists(newFolderItem.LocalPath))
                                    {
                                        //Directory.CreateDirectory(newFolderItem.LocalPath);
                                        //Directory.Delete(newFolderItem.LocalPath);
                                        Directory.Move(oldFolderItem.LocalPath, newFolderItem.LocalPath);
                                        database.MoveFolder(oldFolderItem, newFolderItem);
                                        //var test = database.getMetadataInfo();
                                    }

                                    /*
                                     * else
                                     * {
                                     *  // Directory already exists, move content of the old folder and update database
                                     *
                                     *
                                     *  // Files
                                     *  foreach (string filePath in Directory.GetFiles(oldFolderItem.LocalPath))
                                     *  {
                                     *      string fileName = Path.GetFileName(filePath);
                                     *      string newFilePath = Path.Combine(newFolderItem.LocalPath, fileName);
                                     *
                                     *      File.Move(filePath, newFilePath);
                                     *      SyncItem oldFileItem = database.GetSyncItemFromLocalPath(filePath);
                                     *      if (oldFileItem == null)
                                     *          oldFileItem = SyncItemFactory.CreateFromLocalPath(filePath, false, repoInfo, database);
                                     *
                                     *      SyncItem newFileItem = SyncItemFactory.CreateFromLocalPath(newFilePath, false, repoInfo, database);
                                     *
                                     *      if (Utils.IsMetadataFile(newFilePath))
                                     *      {
                                     *          database.MoveMetadataFile(oldFileItem, newFileItem, newFileItem.LocalPath + ".metadata");
                                     *      }
                                     *      else
                                     *      {
                                     *          database.MoveFile(oldFileItem, newFileItem);
                                     *      }
                                     *  }
                                     */
                                }
                            }
                            Directory.CreateDirectory(newFolderItem.LocalPath);
                        }
                        catch (CmisBaseException e)
                        {
                            ProcessRecoverableException("Could not access remote folder : ", e);
                            success = false;
                        }
                    }

                    IList <string> qDocs = queryAddedAndModifiedFiles(remoteFolder);

                    IList <string> remoteFiles = new List <string>();
                    // Files
                    foreach (string docId in qDocs)
                    {
                        try
                        {
                            IDocument doc = session.GetObject(docId) as IDocument;

                            SyncItem syncItem = SyncItemFactory.CreateFromRemoteDocument(doc.Paths[0], doc, repoInfo, database);

                            // Check if the file already exists
                            string id       = docId.Remove(docId.IndexOf(';'));
                            string filePath = database.GetFilePath(id);
                            if (filePath != null)
                            {
                                // File already exists, delete
                                File.Delete(filePath);
                                SyncItem si = database.GetSyncItemFromLocalPath(filePath);
                                database.RemoveFile(si);

                                // Delete Metadata
                                if (database.ContainsLocalMetadata(filePath + ".metadata"))
                                {
                                    File.Delete(filePath + ".metadata");
                                    database.RemoveMetadataFile(si);
                                }
                            }
                            CrawlRemoteDocument(doc, syncItem.RemotePath, syncItem.LocalPath, remoteFiles);
                        }
                        catch (CmisBaseException e)
                        {
                            ProcessRecoverableException("Could not access remote document : ", e);
                            success = false;
                        }
                    }
                    database.setLastSyncDate(DateTimeOffset.Now.ToString("O"));
                }
                catch (CmisBaseException e)
                {
                    ProcessRecoverableException("Could not access remote objects: ", e);
                    success = false;
                }
                catch (Exception e)
                {
                    Logger.Error("Error in CrawlSyncQuery", e);
                    success = false;
                }
                return(success);
            }
Exemple #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, repoInfo.CmisProfile.localFilename(remoteDocument), 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 = repoInfo.CmisProfile.localFilename(remoteDocument);
                    //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 '" + repoInfo.CmisProfile.localFilename(remoteDocument) + "' 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.CreateFromRemoteDocument(remotePath, repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo, database);
                    }

                    if (syncItem.FileExistsLocal())
                    {
                        // 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 does not exist on the local filesystem.

                        // Maybe the whole synchronized folder has disappeared?
                        // While rare for normal filesystems, that happens rather often with mounted folders (for instance encrypted folders)
                        // In such a case, we should abort this synchronization rather than delete the remote file.
                        if (!Directory.Exists(repoInfo.TargetDirectory))
                        {
                            throw new Exception("Local folder has disappeared: " + repoInfo.TargetDirectory + " , aborting synchronization");
                        }

                        if (database.ContainsLocalFile(syncItem.LocalRelativePath))
                        {
                            // 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 &&
                                !remoteDocument.VersionSeriesCheckedOutBy.Equals(repoInfo.User))
                            {
                                string message = String.Format("Restoring file \"{0}\" because it is checked out on the server by another user: {1}",
                                                               syncItem.LocalPath, remoteDocument.VersionSeriesCheckedOutBy);
                                Logger.Info(message);
                                Utils.NotifyUser(message);

                                // Restore the deleted file
                                activityListener.ActivityStarted();
                                DownloadFile(remoteDocument, remotePath, localFolder);
                                activityListener.ActivityStopped();
                            }
                            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();
                        }
                    }
                }
            }