public override RFProcessingResult Process()
        {
            var result = new RFProcessingResult();

            if (!mConfig.SourceSite.Enabled)
            {
                Log.Debug("Not checking site {0} as it's disabled.", mConfig.SourceSite.SiteKey);
                return(result);
            }
            if (!mConfig.DestinationSite.Enabled)
            {
                Log.Debug("Not checking site {0} as it's disabled.", mConfig.DestinationSite.SiteKey);
                return(result);
            }
            var stateKey = GenerateStateKey("SeenFiles");

            var seenFiles      = new RFSeenFiles();
            var seenFilesEntry = Context.LoadEntry(stateKey);

            if (seenFilesEntry != null)
            {
                seenFiles = (seenFilesEntry as RFDocument).GetContent <RFSeenFiles>();
            }

            int newFiles        = 0;
            var destinationOpen = false;

            Log.Info("Checking for files to move from {0} to {1}", mConfig.SourceSite, mConfig.DestinationSite);
            try
            {
                mConfig.SourceSite.Open(Context);

                var availableFiles = mConfig.SourceSite.CheckSite(mConfig.MonitoredFiles);
                var utcNow         = DateTime.UtcNow;
                var filesToRemove  = new List <RFFileAvailableEvent>();
                foreach (var availableFile in availableFiles)
                {
                    if (RFSeenFiles.IsExpired(availableFile.FileAttributes, utcNow, mConfig.SourceSite.MaxAge))
                    {
                        var monitoredFile = mConfig.MonitoredFiles.FirstOrDefault(m => m.FileKey == availableFile.FileKey);
                        if (monitoredFile.RemoveExpired)
                        {
                            filesToRemove.Add(availableFile);
                        }
                        continue;
                    }
                    if (!HaveSeenFile(seenFiles, availableFile))
                    {
                        try
                        {
                            if (!IsCancelling)
                            {
                                Log.Info("Retrieving new file {0} from {1}", availableFile.FileAttributes.FileName, mConfig.SourceSite);

                                var data           = mConfig.SourceSite.GetFile(availableFile);
                                var fileAttributes = availableFile.FileAttributes;
                                var monitoredFile  = mConfig.MonitoredFiles.FirstOrDefault(m => m.FileKey == availableFile.FileKey);

                                if (monitoredFile.FileKey == RFInternalFileKey.ZIPArchive)
                                {
                                    // unpack and process each file if it matches monitored files
                                    Log.Info("Attempting to download and unpack archive {0}", fileAttributes.FileName);
                                    using (var ms = new MemoryStream(data))
                                    {
                                        foreach (var file in RIFF.Interfaces.Compression.ZIP.ZIPUtils.UnzipArchive(ms))
                                        {
                                            foreach (var candidateFile in mConfig.MonitoredFiles)
                                            {
                                                var isMatch = false;
                                                if (!string.IsNullOrWhiteSpace(candidateFile.FileNameRegex))
                                                {
                                                    var regex = new Regex(candidateFile.FileNameRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled);
                                                    isMatch |= regex.IsMatch(file.Item1.FileName);
                                                }
                                                if (!isMatch && !string.IsNullOrWhiteSpace(candidateFile.FileNameWildcard))
                                                {
                                                    var regex = new Regex(RFRegexHelpers.WildcardToRegex(candidateFile.FileNameWildcard), RegexOptions.IgnoreCase | RegexOptions.Compiled);
                                                    isMatch |= regex.IsMatch(file.Item1.FileName);
                                                }
                                                if (isMatch)
                                                {
                                                    try
                                                    {
                                                        // .zip does not contain timezone information
                                                        // so set file's update time to archive's
                                                        // update time
                                                        var newAttrs = new RFFileTrackedAttributes
                                                        {
                                                            FileName     = file.Item1.FileName,
                                                            FileSize     = file.Item1.FileSize,
                                                            FullPath     = file.Item1.FullPath,
                                                            ModifiedDate = fileAttributes.ModifiedDate
                                                        };
                                                        if (!destinationOpen)
                                                        {
                                                            mConfig.DestinationSite.Open(Context);
                                                            destinationOpen = true;
                                                        }
                                                        if (ProcessFile(new RFFileAvailableEvent
                                                        {
                                                            FileKey = candidateFile.FileKey,
                                                            FileAttributes = newAttrs,
                                                            SourceSite = availableFile.SourceSite
                                                        }, file.Item2, candidateFile, seenFiles))
                                                        {
                                                            newFiles++;
                                                        }
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        Log.UserError("Error extracting file {0} from archive {1}: {2}", file.Item1.FileName, availableFile.FileAttributes.FileName, ex.Message);
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    // add archive to seen files
                                    seenFiles.MarkSeenFile(monitoredFile.FileKey, fileAttributes);
                                }
                                else
                                {
                                    if (!destinationOpen)
                                    {
                                        mConfig.DestinationSite.Open(Context);
                                        destinationOpen = true;
                                    }

                                    if (ProcessFile(availableFile, data, monitoredFile, seenFiles))
                                    {
                                        newFiles++;
                                    }
                                }

                                // archive
                                try
                                {
                                    mConfig.SourceSite.ArchiveFile(availableFile);
                                } catch (Exception ex)
                                {
                                    Log.Warning("Unable to archive file {0}: {1}", availableFile.FileAttributes.FileName, ex.Message);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            var errorCode = ex.HResult & 0xFFFF;

                            if (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION)
                            {
                                Log.Info("Unable to download file {0}: {1}", availableFile.FileAttributes.FileName, ex.Message);
                            }
                            else
                            {
                                Log.UserError("Error downloading file {0}: {1}", availableFile.FileAttributes.FileName, ex.Message);
                            }
                        }
                    }
                }
                if (!IsCancelling)
                {
                    seenFiles.CleanUpMaxAge(utcNow, mConfig.SourceSite.MaxAge);
                }
                Context.SaveEntry(RFDocument.Create(stateKey, seenFiles));

                // try to remove
                if (!IsCancelling)
                {
                    foreach (var fileToRemove in filesToRemove)
                    {
                        try
                        {
                            mConfig.SourceSite.DeleteFile(fileToRemove);
                        }
                        catch (Exception ex)
                        {
                            Log.UserError("Error deleting file {0}: {1}", fileToRemove.FileAttributes.FullPath, ex.Message);
                        }
                    }
                    Log.Info("Finished checking for files on {0} - {1} new files of {2} total", mConfig.SourceSite, newFiles, availableFiles.Count);
                }
                else
                {
                    Log.Info("Interrupted when checking for files on {0} - {1} new files of {2} total", mConfig.SourceSite, newFiles, availableFiles.Count);
                }
            }
            catch (RFTransientSystemException)
            {
                throw;
            }
            catch (Exception ex)
            {
                Log.UserError("Error checking file site {0}: {1}", mConfig.SourceSite.SiteKey, ex.Message);
            }
            finally
            {
                try
                {
                    if (mConfig.SourceSite != null)
                    {
                        mConfig.SourceSite.Close();
                    }
                    if (mConfig.DestinationSite != null && destinationOpen)
                    {
                        mConfig.DestinationSite.Close();
                    }
                }
                catch (Exception ex)
                {
                    Log.Warning("Error closing site {0}: {1}", mConfig.SourceSite.SiteKey, ex.Message);
                }
            }
            result.WorkDone = newFiles > 0;
            return(result);
        }
 protected static void MarkSeenFile(RFSeenFiles seenFiles, RFFileAvailableEvent e)
 {
     seenFiles.MarkSeenFile(e.FileKey, e.FileAttributes);
 }
        private bool ProcessFile(RFFileAvailableEvent availableFile, byte[] data, RFMonitoredFile monitoredFile, RFSeenFiles seenFiles)
        {
            string finalName = null;

            data      = DecryptFile(data, availableFile.FileAttributes, out finalName);
            finalName = monitoredFile.TransformName(finalName);

            var decryptedFile = new RFFileAvailableEvent
            {
                FileKey        = availableFile.FileKey,
                FileAttributes = new RFFileTrackedAttributes
                {
                    FileName     = finalName,
                    FileSize     = data.Length,
                    FullPath     = availableFile.FileAttributes.FullPath,
                    ModifiedDate = availableFile.FileAttributes.ModifiedDate
                },
                SourceSite = availableFile.SourceSite
            };

            Log.Info("Storing new file {0} to {1}", finalName, mConfig.DestinationSite);
            mConfig.DestinationSite.PutFile(decryptedFile, monitoredFile, data);

            // mark original encrypted version as seen
            MarkSeenFile(seenFiles, availableFile); // only if successful on both fronts

            if (mConfig.DestinationSite is RFDocumentFileSite || mConfig.DestinationSite is RFLocalFileSite)
            {
                Log.Action("Download", "File Transfer", RFDate.NullDate, "Downloaded file {0} from {1}", availableFile.FileAttributes.FileName, mConfig.SourceSite);
            }
            else if (mConfig.SourceSite is RFDocumentFileSite || mConfig.SourceSite is RFLocalFileSite)
            {
                Log.Action("Upload", "File Transfer", RFDate.NullDate, "Uploaded file {0} to {1}", availableFile.FileAttributes.FileName, mConfig.DestinationSite);
            }
            else
            {
                Log.Action("Copy", "File Transfer", RFDate.NullDate, "Copied file {0} from {1} to {2}", availableFile.FileAttributes.FileName, mConfig.SourceSite, mConfig.DestinationSite);
            }

            return(true);
        }
 protected static bool HaveSeenFile(RFSeenFiles seenFiles, RFFileAvailableEvent e)
 {
     return(seenFiles.HaveSeenFile(e.FileKey, e.FileAttributes));
 }