├── .gitattributes ├── .gitignore ├── Changelog.txt ├── FlagSync ├── FlagSync.Core │ ├── BackupJob.cs │ ├── DirectoryCreationEventArgs.cs │ ├── DirectoryDeletionEventArgs.cs │ ├── FileCopyErrorEventArgs.cs │ ├── FileCopyEventArgs.cs │ ├── FileDeletionErrorEventArgs.cs │ ├── FileDeletionEventArgs.cs │ ├── FileProceededEventArgs.cs │ ├── FileSystem │ │ ├── AccessException.cs │ │ ├── Base │ │ │ ├── IDirectoryInfo.cs │ │ │ ├── IFileInfo.cs │ │ │ ├── IFileSystem.cs │ │ │ └── IFileSystemInfo.cs │ │ ├── DirectoryFoundEventArgs.cs │ │ ├── FileCountResult.cs │ │ ├── FileCounter.cs │ │ ├── FileFoundEventArgs.cs │ │ ├── FileSystemScanner.cs │ │ ├── FileSystemUnavailableException.cs │ │ ├── Ftp │ │ │ ├── FtpDirectoryInfo.cs │ │ │ ├── FtpFileInfo.cs │ │ │ └── FtpFileSystem.cs │ │ ├── ITunes │ │ │ ├── ITunesDirectoryInfo.cs │ │ │ └── ITunesFileSystem.cs │ │ └── Local │ │ │ ├── LocalDirectoryInfo.cs │ │ │ ├── LocalFileInfo.cs │ │ │ └── LocalFileSystem.cs │ ├── FlagSync.Core.csproj │ ├── Job.cs │ ├── JobEventArgs.cs │ ├── JobWorker.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SyncJob.cs │ └── packages.config ├── FlagSync.Data │ ├── CorruptSaveFileException.cs │ ├── DataController.cs │ ├── FileSystemSetting.cs │ ├── FlagSync.Data.csproj │ ├── FtpFileSystemSetting.cs │ ├── ITunesFileSystemSetting.cs │ ├── ITunesNotOpenedException.cs │ ├── JobSetting.cs │ ├── JobSettingsLoadingResult.cs │ ├── LocalFileSystemSetting.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SyncMode.cs │ └── packages.config ├── FlagSync.Setup │ └── FlagSync.Setup.vdproj ├── FlagSync.View │ ├── App.xaml │ ├── App.xaml.cs │ ├── ByteToKiloByteConverter.cs │ ├── FlagSync.View.csproj │ ├── Images │ │ ├── Add.png │ │ ├── ApplicationIcon.ico │ │ ├── DownArrow.png │ │ ├── Error.png │ │ ├── FTPServer.png │ │ ├── Load.png │ │ ├── Local.png │ │ ├── OpenFolder.png │ │ ├── Remove.png │ │ ├── Save.png │ │ ├── Success.png │ │ ├── UpArrow.png │ │ └── iTunes.png │ ├── LogMessage.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.de-DE.Designer.cs │ │ ├── Resources.de-DE.resx │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── ViewModels │ │ ├── AboutBoxViewModel.cs │ │ ├── FtpFileSystemViewModel.cs │ │ ├── IFileSystemViewModel.cs │ │ ├── ITunesFileSystemViewModel.cs │ │ ├── JobCompositionViewModel.cs │ │ ├── JobSettingViewModel.cs │ │ ├── JobViewModel.cs │ │ ├── LocalFileSystemViewModel.cs │ │ └── MainWindowViewModel.cs │ ├── Views │ │ ├── AboutBox.xaml │ │ ├── AboutBox.xaml.cs │ │ ├── FtpFileSystemPanel.xaml │ │ ├── FtpFileSystemPanel.xaml.cs │ │ ├── ITunesFileSystemPanel.xaml │ │ ├── ITunesFileSystemPanel.xaml.cs │ │ ├── JobCompositionControl.xaml │ │ ├── JobCompositionControl.xaml.cs │ │ ├── LocalFileSystemPanel.xaml │ │ ├── LocalFileSystemPanel.xaml.cs │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ ├── app.config │ └── packages.config ├── FlagSync.sln └── packages │ ├── FlagFtp.0.1.2 │ ├── FlagFtp.0.1.2.nupkg │ └── lib │ │ ├── FlagFtp.dll │ │ └── FlagFtp.xml │ ├── MahApps.Metro.0.8.0.0 │ ├── MahApps.Metro.0.8.0.0.nupkg │ ├── lib │ │ └── net40 │ │ │ ├── MahApps.Metro.dll │ │ │ └── System.Windows.Interactivity.dll │ └── tools │ │ └── install.ps1 │ ├── Rareform.1.2.0 │ ├── Rareform.1.2.0.nupkg │ └── lib │ │ ├── Rareform.dll │ │ └── Rareform.xml │ └── repositories.config ├── Releases ├── 1.0.0 │ └── FlagSync-1.0.0.exe ├── 1.1.0 │ └── FlagSync-1.1.0.exe ├── 1.2.0 │ └── FlagSync-1.2.0.rar ├── 1.2.1 │ └── FlagSync-1.2.1.rar ├── 1.3.0 │ └── FlagSync-1.3.0.rar ├── 1.3.1 │ └── FlagSync-1.3.1.rar ├── 1.3.2 │ └── FlagSync-1.3.2.rar ├── 1.3.3 │ └── FlagSync-1.3.3.zip ├── 2.0.0 │ ├── FlagSync-2.0.0-portable.rar │ └── FlagSync-2.0.0.rar ├── 2.1.0 │ ├── FlagSync-2.1.0-portable.rar │ └── FlagSync-2.1.0.rar ├── 2.1.1 │ ├── FlagSync-2.1.1-portable.rar │ └── FlagSync-2.1.1.rar ├── 2.1.2 │ ├── FlagSync-2.1.2-portable.rar │ └── FlagSync-2.1.2.rar ├── 2.1.3 │ ├── FlagSync-2.1.3-portable.rar │ └── FlagSync-2.1.3.rar ├── 2.2.0 │ ├── FlagSync-2.2.0-portable.rar │ └── FlagSync-2.2.0.rar ├── 2.2.1 │ ├── FlagSync-2.2.1-portable.rar │ └── FlagSync-2.2.1.rar ├── 2.3.0 │ ├── FlagSync-2.3.0-portable.zip │ └── FlagSync-2.3.0.zip ├── 2.3.1 │ ├── FlagSync-2.3.1-portable.zip │ └── FlagSync-2.3.1.zip ├── 2.4.0 │ ├── FlagSync-2.4.0-portable.zip │ └── FlagSync-2.4.0.zip ├── 2.4.1 │ ├── FlagSync-2.4.1-portable.zip │ └── FlagSync-2.4.1.zip └── 2.4.2 │ ├── FlagSync-2.4.2-portable.zip │ └── FlagSync-2.4.2.zip └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | _ReSharper* 3 | [Bb]in/ 4 | [Oo]bj/ 5 | TestResults 6 | publish 7 | _NCrunch* 8 | 9 | *.suo 10 | *.user 11 | *.psess 12 | *.vsp 13 | *.ncrunchproject 14 | *.ncrunchsolution 15 | *.pdb 16 | /Espera/packages/Caliburn.Micro.1.3.1/lib/sl4 17 | /Espera/packages/Caliburn.Micro.1.3.1/lib/sl4-windowsphone71 18 | /Espera/packages/Caliburn.Micro.1.3.1/lib/sl5 19 | /Espera/packages/Caliburn.Micro.1.3.1/lib/WinRT45 20 | /Espera/packages/Caliburn.Micro.1.3.1/tools/sl4 21 | /Espera/packages/Caliburn.Micro.1.3.1/tools/sl4-windowsphone71 22 | /Espera/packages/Caliburn.Micro.1.3.1/tools/sl5 23 | /Espera/packages/Moq.4.0.10827/lib/NET35 24 | /Espera/packages/Moq.4.0.10827/lib/Silverlight4 25 | /espera/packages/Newtonsoft.Json.4.5.9/lib/sl4 26 | /espera/packages/Newtonsoft.Json.4.5.9/lib/sl4-windowsphone71 27 | /espera/packages/Newtonsoft.Json.4.5.9/lib/winrt45 28 | /espera/packages/Newtonsoft.Json.4.5.9/lib/net20 29 | /espera/packages/Newtonsoft.Json.4.5.9/lib/net35 30 | /espera/packages/Newtonsoft.Json.4.5.9/lib/sl3-wp -------------------------------------------------------------------------------- /Changelog.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------- v2.4.2 ----------------------------------- 2 | 3 | CHANGES: 4 | - Changed the look of the current job display a bit. 5 | 6 | IMPROVEMENTS: 7 | - The average speed is now hidden, when the user starts a preview. 8 | 9 | BUGFIXES: 10 | - Fixed a bug, that caused the average speed text to not appear when a new 11 | job starts. 12 | - Fixed a bug, that caused the application to crash during the calculation of 13 | the average speed. 14 | - Fixed a bug, that caused the application to crash during a synchonization 15 | with iTunes. 16 | - Fixed a bug, that caused a wrong synchronization with FTP-servers. 17 | 18 | ----------------------------------- v2.4.1 ----------------------------------- 19 | 20 | CHANGES: 21 | - Changed the button style, to be closer to a metro-look. 22 | 23 | IMRPOVEMENTS: 24 | - General layout and interface improvements. 25 | 26 | BUGFIXES: 27 | - Fixed a bug, which caused the application to crash, when copying files with 28 | a size of zero bytes. 29 | - Fixed a bug, which caused the progress of the last log message during a 30 | preview to be set to 100 percent. 31 | 32 | ----------------------------------- v2.4.0 ----------------------------------- 33 | 34 | FEATURES: 35 | - The progress is now shown in the taskbar, if the operating system supports 36 | this. 37 | - The order of the jobs can now be changed. 38 | 39 | BUGFIXES: 40 | - Fixed a bug, which caused the application to crash during a synchronization 41 | with iTunes. 42 | - Fixed a bug, which caused the start and preview buttons to be able to be 43 | pressed, if no job was included. 44 | 45 | ----------------------------------- v2.3.1 ----------------------------------- 46 | 47 | IMPROVEMENTS: 48 | - Decreased the application's startup time. 49 | - Added a log message, if the creation of a directory failed. 50 | 51 | BUGFIXES: 52 | - Fixed a bug which caused the application to crash, if there were no file or 53 | directory changes. 54 | - Fixed a bug, which caused the mode of of job to disapear in the current job 55 | display. 56 | - Fixed some typos. 57 | 58 | ----------------------------------- v2.3.0 ----------------------------------- 59 | 60 | CHANGES: 61 | - Changed the button, the tabs, the progressbar and the job setting menu 62 | style. 63 | - There is no default job anymore when the application starts. 64 | Instead, a message is displayed, that the user shoukld click on the "New" 65 | button to add a new job. 66 | 67 | IMPROVEMENTS: 68 | - The text in a log message now doesnt't cut off suddendly, instead it's 69 | prepended with dots, to indicate that there is more text. 70 | - The average speed is now calculated more accurately. 71 | - There is now an '@' in front of the average speed display. 72 | 73 | BUGFIXES: 74 | - Fixed a bug, which caused the progress of the current file not to jump to 75 | 100 percent. 76 | 77 | ----------------------------------- v2.2.1 ----------------------------------- 78 | 79 | BUGFIXES: 80 | - Fixed a bug, which caused the wrong iTunes playlist to be loaded, when the 81 | user loaded a job. 82 | 83 | ----------------------------------- v2.2.0 ----------------------------------- 84 | 85 | FEATURES: 86 | - Each log message now displays the size of the file. 87 | 88 | CHANGES: 89 | - Removed the detailed log, which writes to a file in the appdata directory. 90 | 91 | IMPROVEMENTS: 92 | - The average speed is now displayed dynamically, depending on the actual 93 | speed. 94 | - Improved the error displaying. 95 | - The FTP address is now validated to have the correct format. 96 | - The preview and start buttons now cannot be pressed anymore, if there are 97 | errors in the included job settings. 98 | 99 | BUGFIXES: 100 | - Fixed a bug, which caused a preview to list the subdirectories and files of 101 | a directory that should get deleted. 102 | - Fixed the misspelling of "Address" in the FTP settings panel. 103 | - Fixed a bug, which caused the application to crash if a song in iTunes got 104 | deleted, before it was synced. 105 | - Fixed a bug, which let the user select no iTunes playlist. 106 | 107 | ----------------------------------- v2.1.3 ----------------------------------- 108 | 109 | BUGFIXES: 110 | - Fixed a bug which caused files to be copied into the wrong directory on a 111 | FTP-Server. 112 | 113 | ----------------------------------- v2.1.2 ----------------------------------- 114 | 115 | CHANGES: 116 | - Changed the URL of the update download site. 117 | - The about box now only displays three version fields. 118 | 119 | BUGFIXES: 120 | - Fixed a bug which caused the application to crash if the target directory of 121 | an iTunes job doesn't exist. 122 | - Fixed a bug which caused the application to crash if the target directory of 123 | a FTP job doesn't exist. 124 | - Fixed a bug which caused iTunes to automatically open. 125 | 126 | ----------------------------------- v2.1.1 ----------------------------------- 127 | 128 | IMPROVEMENTS: 129 | - The application now displays a popup which prompts the user to open iTunes, 130 | if iTunes is not opened and the user tries to create or load an iTunes job. 131 | 132 | BUGFIXES: 133 | - Fixed a bug, which caused all jobs to disappear, if a corrupt setting has 134 | been loaded. 135 | 136 | ----------------------------------- v2.1.0 ----------------------------------- 137 | 138 | FEATURES: 139 | - The average speed is now displayed. 140 | - The application now informs in the bottom right corner, if a new version is 141 | available. 142 | 143 | CHANGES: 144 | - Changed the layout of the log, so that the current file progress is now 145 | visible beneath the total-progress progress-bar. 146 | 147 | IMPROVEMENTS: 148 | - Increased the performance of the application drastically. 149 | - Improved the file deletion handling. 150 | - The recycle-bin of a harddrive is now excluded from the synchronization and 151 | backup. 152 | - The current copy operations now gets aborted when the user stops the job. 153 | 154 | BUGFIXES: 155 | - Fixed a bug which caused the directory path to reset, if the folder 156 | selection dialog has been canceled. 157 | 158 | ----------------------------------- v2.0.0 ----------------------------------- 159 | 160 | FEATURES: 161 | - Added synchronization and backup for FTP servers. 162 | - The application can now synchronize an iTunes playlist with a folder 163 | (useful for MP3-Players). 164 | - The copy progress for each separate file is now visible. 165 | 166 | IMPROVEMENTS: 167 | - Complete new user interface. 168 | 169 | ----------------------------------- v1.3.3 ----------------------------------- 170 | 171 | FEATURES: 172 | - Added application icon. 173 | 174 | IMPROVEMENTS: 175 | - Many UI improvements. 176 | - Improved error handling. 177 | 178 | BUGFIXES: 179 | - Fixed a threading issue. 180 | 181 | ----------------------------------- v1.3.2 ----------------------------------- 182 | 183 | CHANGES: 184 | - Removed the 64-bit version of FlagSync. 185 | - The window now maximizes at startup. 186 | 187 | IMPROVEMENTS: 188 | - Improved progress-bar (now counts size of files, not number of all files). 189 | - Elapsed time counter now stops when a job gets paused. 190 | 191 | ----------------------------------- v1.3.1 ----------------------------------- 192 | 193 | FEATURES: 194 | - Added elapsed time. 195 | - Added error log, if an invalid settings file gets read. 196 | 197 | IMPROVEMENTS: 198 | - Improved log. 199 | 200 | ----------------------------------- v1.3.0 ----------------------------------- 201 | 202 | CHANGES: 203 | - Limited log to 60,000 characters. 204 | 205 | IMPROVEMENTS: 206 | - Improved user interface. 207 | - Improved stop function. 208 | 209 | ----------------------------------- v1.2.1 ----------------------------------- 210 | 211 | FEATURES: 212 | - Added tooltips. 213 | 214 | CHANGES: 215 | - New jobs are now at default checked. 216 | - When loading the settings, they are now at default checked. 217 | 218 | IMPROVEMENTS 219 | - Improved translations. 220 | 221 | ----------------------------------- v1.2.0 ----------------------------------- 222 | 223 | FEATURES: 224 | - Added German translation. 225 | 226 | ----------------------------------- v1.1.0 ----------------------------------- 227 | 228 | FEATURES: 229 | - Added job saving and loading. 230 | 231 | ----------------------------------- v1.0.0 ----------------------------------- 232 | 233 | - Release of public version. -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/BackupJob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FlagSync.Core.FileSystem.Base; 3 | 4 | namespace FlagSync.Core 5 | { 6 | /// 7 | /// A backup-job performs a synchronization only from directory A to directory B, but can delete files. 8 | /// 9 | public class BackupJob : Job 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The name of the job. 15 | /// The source file system. 16 | /// The target file system. 17 | /// The source directory. 18 | /// The target directory. 19 | public BackupJob(string name, IFileSystem sourceFileSystem, IFileSystem targetFileSystem, IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory) 20 | : base(name, sourceFileSystem, targetFileSystem, sourceDirectory, targetDirectory) { } 21 | 22 | /// 23 | /// Starts the BackupJob, copies new and modified files from directory A to directory B and finally checks for deletions 24 | /// 25 | /// if set to true a preview will be performed. 26 | public override void Start(bool preview) 27 | { 28 | this.BackupDirectoryRecursively(this.DirectoryA, this.DirectoryB, !preview); 29 | this.CheckDeletionsRecursively(this.DirectoryB, this.DirectoryA, !preview); 30 | 31 | this.OnFinished(EventArgs.Empty); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/DirectoryCreationEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | using FlagSync.Core.FileSystem.Base; 4 | 5 | namespace FlagSync.Core 6 | { 7 | /// 8 | /// Provides data for the events of the and the class. 9 | /// 10 | public class DirectoryCreationEventArgs : EventArgs 11 | { 12 | /// 13 | /// Gets the directory. 14 | /// 15 | /// 16 | /// The directory. 17 | /// 18 | public IDirectoryInfo Directory { get; private set; } 19 | 20 | /// 21 | /// Gets the target directory. 22 | /// 23 | /// 24 | /// The target directory. 25 | /// 26 | public IDirectoryInfo TargetDirectory { get; private set; } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The directory. 32 | /// The target directory. 33 | public DirectoryCreationEventArgs(IDirectoryInfo directory, IDirectoryInfo targetDirectory) 34 | { 35 | directory.ThrowIfNull(() => directory); 36 | targetDirectory.ThrowIfNull(() => targetDirectory); 37 | 38 | this.Directory = directory; 39 | this.TargetDirectory = targetDirectory; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/DirectoryDeletionEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | 4 | namespace FlagSync.Core 5 | { 6 | /// 7 | /// Provides data for the events of the and the class. 8 | /// 9 | public class DirectoryDeletionEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the directory path. 13 | /// 14 | /// 15 | /// The directory path. 16 | /// 17 | public string DirectoryPath { get; private set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The directory path. 23 | public DirectoryDeletionEventArgs(string directoryPath) 24 | { 25 | directoryPath.ThrowIfNull(() => directoryPath); 26 | 27 | this.DirectoryPath = directoryPath; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileCopyErrorEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | using FlagSync.Core.FileSystem.Base; 4 | 5 | namespace FlagSync.Core 6 | { 7 | /// 8 | /// Provides data for the events of the and the class. 9 | /// 10 | public class FileCopyErrorEventArgs : EventArgs 11 | { 12 | /// 13 | /// Gets the file. 14 | /// 15 | /// 16 | /// The file. 17 | /// 18 | public IFileInfo File { get; private set; } 19 | 20 | /// 21 | /// Gets the target directory. 22 | /// 23 | /// 24 | /// The target directory. 25 | /// 26 | public IDirectoryInfo TargetDirectory { get; private set; } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The file. 32 | /// The target directory. 33 | public FileCopyErrorEventArgs(IFileInfo file, IDirectoryInfo targetDirectory) 34 | { 35 | file.ThrowIfNull(() => file); 36 | targetDirectory.ThrowIfNull(() => targetDirectory); 37 | 38 | this.File = file; 39 | this.TargetDirectory = targetDirectory; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileCopyEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | using FlagSync.Core.FileSystem.Base; 4 | 5 | namespace FlagSync.Core 6 | { 7 | /// 8 | /// Provides data for the events of the and the class. 9 | /// 10 | public class FileCopyEventArgs : EventArgs 11 | { 12 | /// 13 | /// Gets the file. 14 | /// 15 | /// 16 | /// The file. 17 | /// 18 | public IFileInfo File { get; private set; } 19 | 20 | /// 21 | /// Gets the source directory. 22 | /// 23 | /// 24 | /// The source directory. 25 | /// 26 | public IDirectoryInfo SourceDirectory { get; private set; } 27 | 28 | /// 29 | /// Gets the target directory. 30 | /// 31 | /// 32 | /// The target directory. 33 | /// 34 | public IDirectoryInfo TargetDirectory { get; private set; } 35 | 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | /// The file. 40 | /// The source directory. 41 | /// The target directory. 42 | public FileCopyEventArgs(IFileInfo file, IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory) 43 | { 44 | file.ThrowIfNull(() => file); 45 | sourceDirectory.ThrowIfNull(() => sourceDirectory); 46 | targetDirectory.ThrowIfNull(() => targetDirectory); 47 | 48 | this.File = file; 49 | this.SourceDirectory = sourceDirectory; 50 | this.TargetDirectory = targetDirectory; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileDeletionErrorEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | using FlagSync.Core.FileSystem.Base; 4 | 5 | namespace FlagSync.Core 6 | { 7 | /// 8 | /// Provides data for the events of the and the class. 9 | /// 10 | public class FileDeletionErrorEventArgs : EventArgs 11 | { 12 | /// 13 | /// Gets the file. 14 | /// 15 | /// 16 | /// The file. 17 | /// 18 | public IFileInfo File { get; private set; } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The file. 24 | public FileDeletionErrorEventArgs(IFileInfo file) 25 | { 26 | file.ThrowIfNull(() => file); 27 | 28 | this.File = file; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileDeletionEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | 4 | namespace FlagSync.Core 5 | { 6 | /// 7 | /// Provides data for the events of the and the class. 8 | /// 9 | public class FileDeletionEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the file path. 13 | /// 14 | /// 15 | /// The file path. 16 | /// 17 | public string FilePath { get; private set; } 18 | 19 | /// 20 | /// Gets the size of the file. 21 | /// 22 | /// 23 | /// The size of the file. 24 | /// 25 | public long FileSize { get; private set; } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The file path. 31 | /// Size of the file. 32 | public FileDeletionEventArgs(string filePath, long fileSize) 33 | { 34 | filePath.ThrowIfNull(() => filePath); 35 | 36 | this.FilePath = filePath; 37 | this.FileSize = fileSize; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileProceededEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | 4 | namespace FlagSync.Core 5 | { 6 | /// 7 | /// Provides data for the events of the and the class. 8 | /// 9 | public class FileProceededEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the length of the file. 13 | /// 14 | /// 15 | /// The length of the file. 16 | /// 17 | public long FileLength { get; private set; } 18 | 19 | /// 20 | /// Gets the name of the file. 21 | /// 22 | /// 23 | /// The name of the file. 24 | /// 25 | public string FilePath { get; private set; } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The file path. 31 | /// The file length. 32 | public FileProceededEventArgs(string filePath, long fileLength) 33 | { 34 | filePath.ThrowIfNull(() => filePath); 35 | 36 | this.FilePath = filePath; 37 | this.FileLength = fileLength; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/AccessException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Core.FileSystem 4 | { 5 | /// 6 | /// The exception that is thrown, when a file or directory could not be accessed. 7 | /// 8 | public class AccessException : Exception 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The exception message. 14 | /// The inner exception. 15 | public AccessException(string message, Exception innerException) 16 | : base(message, innerException) 17 | { } 18 | } 19 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Base/IDirectoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace FlagSync.Core.FileSystem.Base 4 | { 5 | /// 6 | /// Provides the interface that all directory infos have to implement. 7 | /// 8 | public interface IDirectoryInfo : IFileSystemInfo 9 | { 10 | /// 11 | /// Gets the parent directory. 12 | /// 13 | IDirectoryInfo Parent { get; } 14 | 15 | /// 16 | /// Gets a value indicating whether the directory exists. 17 | /// 18 | /// 19 | /// true if the directory exists; otherwise, false. 20 | /// 21 | bool Exists { get; } 22 | 23 | /// 24 | /// Returns a list of all files in the directory. 25 | /// 26 | /// 27 | /// The files in the directory. 28 | /// 29 | /// 30 | /// The exception that is thrown if the directory is locked 31 | /// 32 | IEnumerable GetFiles(); 33 | 34 | /// 35 | /// Returns a list of all directories in the directory. 36 | /// 37 | /// 38 | /// The directories in the directory. 39 | /// 40 | /// 41 | /// The exception that is thrown if the directory is locked. 42 | /// 43 | IEnumerable GetDirectories(); 44 | } 45 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Base/IFileInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Core.FileSystem.Base 4 | { 5 | /// 6 | /// Provides the interface that all file infos have to implement. 7 | /// 8 | public interface IFileInfo : IFileSystemInfo 9 | { 10 | /// 11 | /// Gets the last write time. 12 | /// 13 | DateTime LastWriteTime { get; } 14 | 15 | /// 16 | /// Gets the length of the file. 17 | /// 18 | long Length { get; } 19 | 20 | /// 21 | /// Gets the directory. 22 | /// 23 | IDirectoryInfo Directory { get; } 24 | 25 | /// 26 | /// Gets a value indicating whether the file exists. 27 | /// 28 | /// 29 | /// true if exists; otherwise, false. 30 | /// 31 | bool Exists { get; } 32 | } 33 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Base/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Rareform.IO; 4 | 5 | namespace FlagSync.Core.FileSystem.Base 6 | { 7 | /// 8 | /// Provides the interface that all filesystems have to implement. 9 | /// 10 | public interface IFileSystem 11 | { 12 | /// 13 | /// Occurs when the file copy progress has changed. 14 | /// 15 | event EventHandler FileCopyProgressChanged; 16 | 17 | /// 18 | /// Deletes the specified file. 19 | /// 20 | /// The file to delete. 21 | /// 22 | /// true, if the deletion has succeed; otherwise, false. 23 | /// 24 | /// The file could not be accessed. 25 | /// The file system is currently unavailable. 26 | void DeleteFile(IFileInfo file); 27 | 28 | /// 29 | /// Creates the specified directory in the target directory. 30 | /// 31 | /// The source directory. 32 | /// The target directory. 33 | /// 34 | /// true, if the creation has succeed; otherwise, false. 35 | /// 36 | /// The directory could not be accessed. 37 | /// The file system is currently unavailable. 38 | void CreateDirectory(IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory); 39 | 40 | /// 41 | /// Deletes the specified directory. 42 | /// 43 | /// The directory to delete. 44 | /// 45 | /// true, if the deletion has succeed; otherwise, false. 46 | /// 47 | /// The directory could not be accessed. 48 | /// The file system is currently unavailable. 49 | void DeleteDirectory(IDirectoryInfo directory); 50 | 51 | /// 52 | /// Copies the specified file to the target directory. 53 | /// 54 | /// The source file system. 55 | /// The source file. 56 | /// The target directory. 57 | /// 58 | /// true, if the copy operation has succeed; otherwise, false. 59 | /// 60 | /// The source file or target directory could not be accessed. 61 | /// The file system is currently unavailable. 62 | void CopyFile(IFileSystem sourceFileSystem, IFileInfo sourceFile, IDirectoryInfo targetDirectory); 63 | 64 | /// 65 | /// Gets the file info at the specified path. 66 | /// 67 | /// The path of the file. 68 | /// 69 | /// An of the file from the specified path. 70 | /// 71 | IFileInfo GetFileInfo(string path); 72 | 73 | /// 74 | /// Gets the directory info at the specified path. 75 | /// 76 | /// The path of the directory. 77 | /// 78 | /// An of the directory from the specified path. 79 | /// 80 | IDirectoryInfo GetDirectoryInfo(string path); 81 | 82 | /// 83 | /// Determines if the file at the specified path exists. 84 | /// 85 | /// The path of the file. 86 | /// 87 | /// true, if the file exists; otherwise, false. 88 | /// 89 | bool FileExists(string path); 90 | 91 | /// 92 | /// Determines if the directory at the specified path exists. 93 | /// 94 | /// The path of the directory. 95 | /// 96 | /// true, if the directory exists; otherwise, false. 97 | /// 98 | bool DirectoryExists(string path); 99 | 100 | /// 101 | /// Opens the stream of the specified file. 102 | /// 103 | /// The file. 104 | /// 105 | /// A stream from the specified file. 106 | /// 107 | Stream OpenFileStream(IFileInfo file); 108 | 109 | /// 110 | /// Combines two paths for the specific file system. 111 | /// 112 | /// The first path. 113 | /// The second path. 114 | /// 115 | /// A path, which is the combination of the first and second path. 116 | /// 117 | string CombinePath(string path1, string path2); 118 | } 119 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Base/IFileSystemInfo.cs: -------------------------------------------------------------------------------- 1 | namespace FlagSync.Core.FileSystem.Base 2 | { 3 | /// 4 | /// Provides the interface for the 5 | /// and the interface. 6 | /// 7 | public interface IFileSystemInfo 8 | { 9 | /// 10 | /// Gets the full name of the file or directory. 11 | /// 12 | string FullName { get; } 13 | 14 | /// 15 | /// Gets the name of the file or directory. 16 | /// 17 | string Name { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/DirectoryFoundEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FlagSync.Core.FileSystem.Base; 3 | 4 | namespace FlagSync.Core.FileSystem 5 | { 6 | /// 7 | /// Provides data for the events of the class. 8 | /// 9 | public class DirectoryFoundEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the found the directory. 13 | /// 14 | /// 15 | /// The found directory. 16 | /// 17 | public IDirectoryInfo Directory { get; private set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The directory that has been found. 23 | public DirectoryFoundEventArgs(IDirectoryInfo directory) 24 | { 25 | this.Directory = directory; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/FileCountResult.cs: -------------------------------------------------------------------------------- 1 | using Rareform.Extensions; 2 | 3 | namespace FlagSync.Core.FileSystem 4 | { 5 | /// 6 | /// Contains the number of files counted and the total size of all files. 7 | /// 8 | public class FileCountResult 9 | { 10 | /// 11 | /// Gets the counted files. 12 | /// 13 | /// 14 | /// The counted files. 15 | /// 16 | public int CountedFiles { get; private set; } 17 | 18 | /// 19 | /// Gets the counted bytes. 20 | /// 21 | /// 22 | /// The counted bytes. 23 | /// 24 | public long CountedBytes { get; private set; } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// The counted files. 30 | /// The counted bytes. 31 | public FileCountResult(int countedFiles, long countedBytes) 32 | { 33 | this.CountedBytes = countedBytes; 34 | this.CountedFiles = countedFiles; 35 | } 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | public FileCountResult() 41 | : this(0, 0) 42 | { 43 | } 44 | 45 | /// 46 | /// Implements the operator +. 47 | /// 48 | /// The first file counter result 49 | /// The second file counter result 50 | /// 51 | /// The result of the operator. 52 | /// 53 | public static FileCountResult operator +(FileCountResult a, FileCountResult b) 54 | { 55 | a.ThrowIfNull(() => a); 56 | b.ThrowIfNull(() => b); 57 | 58 | return new FileCountResult(a.CountedFiles + b.CountedFiles, a.CountedBytes + b.CountedBytes); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/FileCounter.cs: -------------------------------------------------------------------------------- 1 | using Rareform.Extensions; 2 | using FlagSync.Core.FileSystem.Base; 3 | 4 | namespace FlagSync.Core.FileSystem 5 | { 6 | /// 7 | /// Provides a method for counting recursively the files of a directory. 8 | /// 9 | internal static class FileCounter 10 | { 11 | /// 12 | /// Counts recursively the files of the directory. 13 | /// 14 | /// The root directory. 15 | /// 16 | /// A which indicates the result of the count. 17 | /// 18 | public static FileCountResult CountFiles(IDirectoryInfo rootDirectory) 19 | { 20 | rootDirectory.ThrowIfNull(() => rootDirectory); 21 | 22 | int files = 0; 23 | long bytes = 0; 24 | 25 | var scanner = new FileSystemScanner(rootDirectory); 26 | 27 | scanner.FileFound += (sender, e) => 28 | { 29 | files++; 30 | bytes += e.File.Length; 31 | }; 32 | 33 | scanner.Start(); 34 | 35 | return new FileCountResult(files, bytes); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/FileFoundEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FlagSync.Core.FileSystem.Base; 3 | 4 | namespace FlagSync.Core.FileSystem 5 | { 6 | /// 7 | /// Provides data for the events of the class. 8 | /// 9 | public class FileFoundEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the found file. 13 | /// 14 | public IFileInfo File { get; private set; } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The found file. 20 | public FileFoundEventArgs(IFileInfo file) 21 | { 22 | this.File = file; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/FileSystemScanner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Security; 5 | using FlagSync.Core.FileSystem.Base; 6 | using Rareform.Extensions; 7 | 8 | namespace FlagSync.Core.FileSystem 9 | { 10 | internal class FileSystemScanner 11 | { 12 | private readonly IDirectoryInfo rootDirectory; 13 | 14 | /// 15 | /// Gets or sets a value indicating whether the scanner is stopped. 16 | /// 17 | /// true if the scanner is stopped; otherwise, false. 18 | public bool IsStopped { get; private set; } 19 | 20 | /// 21 | /// Occurs when a file has been found. 22 | /// 23 | public event EventHandler FileFound; 24 | 25 | /// 26 | /// Occurs when a directory has been found. 27 | /// 28 | public event EventHandler DirectoryFound; 29 | 30 | /// 31 | /// Occurs when a directory has been proceeded. 32 | /// 33 | public event EventHandler DirectoryProceeded; 34 | 35 | /// 36 | /// Stops the scanner. 37 | /// 38 | public void Stop() 39 | { 40 | this.IsStopped = true; 41 | } 42 | 43 | /// 44 | /// Starts the scanner. 45 | /// 46 | public void Start() 47 | { 48 | this.ScanDirectories(this.rootDirectory); 49 | } 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | /// The root directory. 55 | /// 56 | /// The exception that is thrown, if the root directory doesn't exists 57 | /// 58 | public FileSystemScanner(IDirectoryInfo rootDirectory) 59 | { 60 | rootDirectory.ThrowIfNull(() => rootDirectory); 61 | 62 | if (!rootDirectory.Exists) 63 | throw new ArgumentException("The root directory must exist!"); 64 | 65 | this.rootDirectory = rootDirectory; 66 | } 67 | 68 | /// 69 | /// Raises the event. 70 | /// 71 | /// The instance containing the event data. 72 | protected virtual void OnFileFound(FileFoundEventArgs e) 73 | { 74 | this.FileFound.RaiseSafe(this, e); 75 | } 76 | 77 | /// 78 | /// Raises the event. 79 | /// 80 | /// The instance containing the event data. 81 | protected virtual void OnDirectoryFound(DirectoryFoundEventArgs e) 82 | { 83 | this.DirectoryFound.RaiseSafe(this, e); 84 | } 85 | 86 | /// 87 | /// Raises the event. 88 | /// 89 | /// The instance containing the event data. 90 | protected virtual void OnDirectoryProceeded(EventArgs e) 91 | { 92 | this.DirectoryProceeded.RaiseSafe(this, e); 93 | } 94 | 95 | /// 96 | /// Scans a directory recursively. 97 | /// 98 | /// The root directory. 99 | private void ScanDirectories(IDirectoryInfo rootDirectory) 100 | { 101 | if (this.IsStopped) { return; } 102 | 103 | try 104 | { 105 | if (rootDirectory.Exists) 106 | { 107 | IEnumerable files = rootDirectory.GetFiles(); 108 | 109 | foreach (IFileInfo file in files) 110 | { 111 | if (this.IsStopped) { return; } 112 | 113 | if (file.Exists) 114 | { 115 | this.OnFileFound(new FileFoundEventArgs(file)); 116 | } 117 | } 118 | 119 | IEnumerable directories = rootDirectory.GetDirectories(); 120 | 121 | foreach (IDirectoryInfo directory in directories) 122 | { 123 | if (this.IsStopped) 124 | { 125 | return; 126 | } 127 | 128 | if (directory.Name == "$RECYCLE.BIN" || !directory.Exists) 129 | { 130 | continue; 131 | } 132 | 133 | this.OnDirectoryFound(new DirectoryFoundEventArgs(directory)); 134 | this.ScanDirectories(directory); 135 | } 136 | } 137 | } 138 | 139 | // Catch the exceptions and don't handle anything, 140 | // we want to skip those files or directories 141 | catch (UnauthorizedAccessException) 142 | { 143 | } 144 | 145 | catch (SecurityException) 146 | { 147 | } 148 | 149 | catch (IOException) 150 | { 151 | } 152 | 153 | this.OnDirectoryProceeded(EventArgs.Empty); 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/FileSystemUnavailableException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Core.FileSystem 4 | { 5 | /// 6 | /// The exception that is thrown, when the file system is unabailable. 7 | /// 8 | public class FileSystemUnavailableException : Exception 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The exception message. 14 | /// The inner exception. 15 | public FileSystemUnavailableException(string message, Exception innerException) 16 | : base(message, innerException) 17 | { } 18 | } 19 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Ftp/FtpDirectoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using FlagFtp; 7 | using Rareform.Extensions; 8 | using FlagSync.Core.FileSystem.Base; 9 | 10 | namespace FlagSync.Core.FileSystem.Ftp 11 | { 12 | /// 13 | /// Represents a directory on a FTP-server. 14 | /// 15 | [DebuggerDisplay("{FullName}")] 16 | public class FtpDirectoryInfo : IDirectoryInfo 17 | { 18 | private readonly FtpClient client; 19 | 20 | /// 21 | /// Gets the full name of the directory. 22 | /// 23 | public string FullName { get; private set; } 24 | 25 | /// 26 | /// Gets the name of the directory. 27 | /// 28 | public string Name 29 | { 30 | get { return Path.GetFileName(this.FullName); } 31 | } 32 | 33 | /// 34 | /// Gets the parent directory. 35 | /// 36 | public IDirectoryInfo Parent 37 | { 38 | get 39 | { 40 | string parentDirectoryName = Path.GetDirectoryName(this.FullName).Replace("\\", "//"); 41 | Uri parentDirectoryUri = new Uri(parentDirectoryName); 42 | 43 | FlagFtp.FtpDirectoryInfo directory = this.client.GetDirectoryInfo(parentDirectoryUri); 44 | 45 | return new FtpDirectoryInfo(directory.FullName, this.client); 46 | } 47 | } 48 | 49 | /// 50 | /// Gets a value indicating whether the directory exists. 51 | /// 52 | /// 53 | /// true if the directory exists; otherwise, false. 54 | /// 55 | public bool Exists 56 | { 57 | get { return true; } 58 | } 59 | 60 | /// 61 | /// Returns a list of all files in the directory. 62 | /// 63 | /// 64 | /// The files in the directory. 65 | /// 66 | /// 67 | /// The exception that is thrown if the directory is locked. 68 | /// 69 | public IEnumerable GetFiles() 70 | { 71 | return this.client 72 | .GetFiles(new Uri(this.FullName)) 73 | .Where(file => file.Name != ".ftpquota") 74 | .Select(file => new FtpFileInfo(file.FullName, file.LastWriteTime, file.Length, this.client)) 75 | .Cast() 76 | .ToList(); 77 | } 78 | 79 | /// 80 | /// Returns a list of all directories in the directory. 81 | /// 82 | /// 83 | /// The directories in the directory. 84 | /// 85 | /// 86 | /// The exception that is thrown if the directory is locked. 87 | /// 88 | public IEnumerable GetDirectories() 89 | { 90 | return this.client 91 | .GetDirectories(new Uri(this.FullName)) 92 | .Select(directory => new FtpDirectoryInfo(directory.FullName, this.client)) 93 | .Cast() 94 | .ToList(); 95 | } 96 | 97 | /// 98 | /// Initializes a new instance of the class. 99 | /// 100 | /// The full name. 101 | /// The client. 102 | public FtpDirectoryInfo(string fullName, FtpClient client) 103 | { 104 | fullName.ThrowIfNull(() => fullName); 105 | client.ThrowIfNull(() => client); 106 | 107 | this.FullName = fullName; 108 | this.client = client; 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Ftp/FtpFileInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using FlagFtp; 5 | using Rareform.Extensions; 6 | using FlagSync.Core.FileSystem.Base; 7 | 8 | namespace FlagSync.Core.FileSystem.Ftp 9 | { 10 | /// 11 | /// Represents a file on a FTP-server 12 | /// 13 | [DebuggerDisplay("{FullName}")] 14 | public class FtpFileInfo : IFileInfo 15 | { 16 | private readonly FtpClient client; 17 | 18 | /// 19 | /// Gets the last write time. 20 | /// 21 | public DateTime LastWriteTime { get; private set; } 22 | 23 | /// 24 | /// Gets the length of the file. 25 | /// 26 | public long Length { get; private set; } 27 | 28 | /// 29 | /// Gets the directory of the file. 30 | /// 31 | public IDirectoryInfo Directory 32 | { 33 | get 34 | { 35 | FlagFtp.FtpDirectoryInfo directory = 36 | this.client.GetDirectoryInfo(new Uri(Path.GetDirectoryName(this.FullName))); 37 | 38 | return new FtpDirectoryInfo(directory.FullName, this.client); 39 | } 40 | } 41 | 42 | /// 43 | /// Gets a value indicating whether the file exists. 44 | /// 45 | /// 46 | /// true if the file exists; otherwise, false. 47 | /// 48 | public bool Exists 49 | { 50 | get { return true; } 51 | } 52 | 53 | /// 54 | /// Gets the full name of the file. 55 | /// 56 | public string FullName { get; private set; } 57 | 58 | /// 59 | /// Gets the name of the file. 60 | /// 61 | public string Name 62 | { 63 | get { return Path.GetFileName(this.FullName); } 64 | } 65 | 66 | /// 67 | /// Initializes a new instance of the class. 68 | /// 69 | /// The full name. 70 | /// The last write time. 71 | /// The length. 72 | /// The client. 73 | public FtpFileInfo(string fullName, DateTime lastWriteTime, long length, FtpClient client) 74 | { 75 | fullName.ThrowIfNull(() => fullName); 76 | client.ThrowIfNull(() => client); 77 | 78 | this.FullName = fullName; 79 | this.LastWriteTime = lastWriteTime; 80 | this.Length = length; 81 | this.client = client; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Ftp/FtpFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using FlagFtp; 5 | using Rareform.Extensions; 6 | using Rareform.IO; 7 | using FlagSync.Core.FileSystem.Base; 8 | 9 | namespace FlagSync.Core.FileSystem.Ftp 10 | { 11 | public class FtpFileSystem : IFileSystem 12 | { 13 | private readonly FtpClient client; 14 | 15 | /// 16 | /// Occurs when the file copy progress has changed. 17 | /// 18 | public event EventHandler FileCopyProgressChanged; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The server address. 24 | /// The credentials. 25 | public FtpFileSystem(Uri serverAddress, NetworkCredential credentials) 26 | { 27 | serverAddress.ThrowIfNull(() => serverAddress); 28 | credentials.ThrowIfNull(() => credentials); 29 | 30 | this.client = new FtpClient(credentials); 31 | } 32 | 33 | /// 34 | /// Deletes the specified file. 35 | /// 36 | /// The file to delete. 37 | /// The file could not be accessed. 38 | /// The file is not of type . 39 | /// The file system is currently unavailable. 40 | public void DeleteFile(IFileInfo file) 41 | { 42 | file.ThrowIfNull(() => file); 43 | 44 | if (!(file is FtpFileInfo)) 45 | throw new ArgumentException("The file must be of type FtpFileInfo.", "file"); 46 | 47 | try 48 | { 49 | this.client.DeleteFile(new Uri(file.FullName)); 50 | } 51 | 52 | catch (WebException ex) 53 | { 54 | switch (ex.Status) 55 | { 56 | case WebExceptionStatus.ConnectFailure: 57 | case WebExceptionStatus.ProxyNameResolutionFailure: 58 | throw new FileSystemUnavailableException("The FTP server is currently unavailable.", ex); 59 | } 60 | 61 | throw new AccessException("The file could not be accessed", ex); 62 | } 63 | } 64 | 65 | /// 66 | /// Creates the specified directory in the target directory. 67 | /// 68 | /// The source directory. 69 | /// The target directory. 70 | /// The directory could not be accessed. 71 | public void CreateDirectory(IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory) 72 | { 73 | sourceDirectory.ThrowIfNull(() => sourceDirectory); 74 | targetDirectory.ThrowIfNull(() => targetDirectory); 75 | 76 | Uri newDirectory = (new Uri(new Uri(targetDirectory.FullName + "//"), sourceDirectory.Name)); 77 | 78 | try 79 | { 80 | this.client.CreateDirectory(newDirectory); 81 | } 82 | 83 | catch (WebException ex) 84 | { 85 | switch (ex.Status) 86 | { 87 | case WebExceptionStatus.ConnectFailure: 88 | case WebExceptionStatus.ProxyNameResolutionFailure: 89 | throw new FileSystemUnavailableException("The FTP server is currently unavailable.", ex); 90 | } 91 | 92 | throw new AccessException("The directory could not be accessed", ex); 93 | } 94 | } 95 | 96 | /// 97 | /// Deletes the specified directory. 98 | /// 99 | /// The directory to delete. 100 | /// The directory could not be accessed. 101 | /// /// The directory is not of type . 102 | public void DeleteDirectory(IDirectoryInfo directory) 103 | { 104 | directory.ThrowIfNull(() => directory); 105 | 106 | if (!(directory is FtpDirectoryInfo)) 107 | throw new ArgumentException("The directory must be of type FtpDirectoryInfo.", "directory"); 108 | 109 | try 110 | { 111 | this.client.DeleteDirectory(new Uri(directory.FullName + "/")); 112 | } 113 | 114 | catch (WebException ex) 115 | { 116 | switch (ex.Status) 117 | { 118 | case WebExceptionStatus.ConnectFailure: 119 | case WebExceptionStatus.ProxyNameResolutionFailure: 120 | throw new FileSystemUnavailableException("The FTP server is currently unavailable.", ex); 121 | } 122 | 123 | throw new AccessException("The directory could not be accessed", ex); 124 | } 125 | } 126 | 127 | /// 128 | /// Copies the specified file to the target directory. 129 | /// 130 | /// The source file system. 131 | /// The source file. 132 | /// The target directory. 133 | /// The source file or target directory could not be accessed. 134 | /// /// The target directory is not of type . 135 | public void CopyFile(IFileSystem sourceFileSystem, IFileInfo sourceFile, IDirectoryInfo targetDirectory) 136 | { 137 | sourceFileSystem.ThrowIfNull(() => sourceFileSystem); 138 | sourceFile.ThrowIfNull(() => sourceFile); 139 | targetDirectory.ThrowIfNull(() => targetDirectory); 140 | 141 | if (!(targetDirectory is FtpDirectoryInfo)) 142 | throw new ArgumentException("The target directory must be of type FtpDirectoryInfo.", "targetDirectory"); 143 | 144 | Uri targetFilePath = new Uri(this.CombinePath(targetDirectory.FullName, sourceFile.Name)); 145 | 146 | try 147 | { 148 | using (Stream sourceStream = sourceFileSystem.OpenFileStream(sourceFile)) 149 | { 150 | using (Stream targetStream = this.client.OpenWrite(targetFilePath)) 151 | { 152 | if (sourceFile.Length > 0) 153 | { 154 | var copyOperation = new StreamCopyOperation(sourceStream, targetStream, 8 * 1024, true); 155 | 156 | copyOperation.CopyProgressChanged += 157 | (sender, e) => this.FileCopyProgressChanged.RaiseSafe(this, e); 158 | 159 | copyOperation.Execute(); 160 | } 161 | } 162 | } 163 | } 164 | 165 | catch (WebException ex) 166 | { 167 | switch (ex.Status) 168 | { 169 | case WebExceptionStatus.ConnectFailure: 170 | case WebExceptionStatus.ProxyNameResolutionFailure: 171 | throw new FileSystemUnavailableException("The FTP server is currently unavailable.", ex); 172 | } 173 | 174 | throw new AccessException("The file could not be accessed", ex); 175 | } 176 | } 177 | 178 | /// 179 | /// Gets the file info at the specified path. 180 | /// 181 | /// The path of the file. 182 | /// 183 | /// An of the file from the specified path. 184 | /// 185 | public IFileInfo GetFileInfo(string path) 186 | { 187 | path.ThrowIfNull(() => path); 188 | 189 | path = FtpFileSystem.NormalizePath(path); 190 | FlagFtp.FtpFileInfo file = this.client.GetFileInfo(new Uri(path)); 191 | 192 | return new FtpFileInfo(file.FullName, file.LastWriteTime, file.Length, this.client); 193 | } 194 | 195 | /// 196 | /// Gets the directory info at the specified path. 197 | /// 198 | /// The path of the directory. 199 | /// 200 | /// An of the directory from the specified path. 201 | /// 202 | public IDirectoryInfo GetDirectoryInfo(string path) 203 | { 204 | path.ThrowIfNull(() => path); 205 | 206 | path = FtpFileSystem.NormalizePath(path); 207 | FlagFtp.FtpDirectoryInfo directory = this.client.GetDirectoryInfo(new Uri(path)); 208 | 209 | return new FtpDirectoryInfo(directory.FullName.Replace("%20", " "), this.client); 210 | } 211 | 212 | /// 213 | /// Determines if the file at the specified path exists. 214 | /// 215 | /// The path of the file. 216 | /// 217 | /// true, if the file exists; otherwise, false. 218 | /// 219 | public bool FileExists(string path) 220 | { 221 | path.ThrowIfNull(() => path); 222 | 223 | path = FtpFileSystem.NormalizePath(path); 224 | return this.client.FileExists(new Uri(path)); 225 | } 226 | 227 | /// 228 | /// Determines if the directory at the specified path exists. 229 | /// 230 | /// The path of the directory. 231 | /// 232 | /// true, if the directory exists; otherwise, false. 233 | /// 234 | public bool DirectoryExists(string path) 235 | { 236 | path.ThrowIfNull(() => path); 237 | 238 | path = FtpFileSystem.NormalizePath(path); 239 | return this.client.DirectoryExists(new Uri(path)); 240 | } 241 | 242 | /// 243 | /// Opens the stream of the specified file. 244 | /// 245 | /// The file. 246 | /// 247 | /// A stream from the specified file. 248 | /// 249 | public Stream OpenFileStream(IFileInfo file) 250 | { 251 | file.ThrowIfNull(() => file); 252 | 253 | return this.client.OpenRead(new Uri(file.FullName)); 254 | } 255 | 256 | /// 257 | /// Combines two paths for the specific file system. 258 | /// 259 | /// The first path. 260 | /// The second path. 261 | /// 262 | /// A path, which is the combination of the first and second path. 263 | /// 264 | public string CombinePath(string path1, string path2) 265 | { 266 | path1.ThrowIfNull(() => path1); 267 | path2.ThrowIfNull(() => path2); 268 | 269 | return path1 + "/" + path2; 270 | } 271 | 272 | /// 273 | /// Normalizes the path. 274 | /// 275 | /// The path. 276 | /// 277 | /// A normalized representation of the path. 278 | /// 279 | private static string NormalizePath(string path) 280 | { 281 | path.ThrowIfNull(() => path); 282 | 283 | return path.Replace("//", "/").Replace("/", "//").Replace("\\", "//").Replace("%20", " "); 284 | } 285 | } 286 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/ITunes/ITunesDirectoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using Rareform.Extensions; 6 | using FlagSync.Core.FileSystem.Base; 7 | 8 | namespace FlagSync.Core.FileSystem.ITunes 9 | { 10 | /// 11 | /// Represents a directory in the iTunes filesystem. 12 | /// 13 | /// 14 | /// A directory in the iTunes filesystem is usually 15 | /// the representation of an artist or an album of a song. 16 | /// 17 | [DebuggerDisplay("{FullName}")] 18 | public class ITunesDirectoryInfo : IDirectoryInfo 19 | { 20 | private string name; 21 | private readonly bool isRoot; 22 | private readonly IEnumerable directories; 23 | private readonly IEnumerable files; 24 | 25 | /// 26 | /// Gets the parent directory. 27 | /// 28 | public IDirectoryInfo Parent { get; set; } 29 | 30 | /// 31 | /// Gets a value indicating whether the directory exists. 32 | /// 33 | /// 34 | /// true if the directory exists; otherwise, false. 35 | /// 36 | public bool Exists { get; private set; } 37 | 38 | /// 39 | /// Return the files in the directory. 40 | /// 41 | /// 42 | /// The files in the directory. 43 | /// 44 | /// 45 | /// The exception that is thrown if the directory is locked 46 | /// 47 | public IEnumerable GetFiles() 48 | { 49 | return this.files; 50 | } 51 | 52 | /// 53 | /// Return the directories in the directory. 54 | /// 55 | /// 56 | /// The directories in the directory 57 | /// 58 | /// 59 | /// The exception that is thrown if the directory is locked 60 | /// 61 | public IEnumerable GetDirectories() 62 | { 63 | if (this.isRoot) 64 | { 65 | return ITunesFileSystem.MapPlaylistToDirectoryStructure(this.name); 66 | } 67 | 68 | return this.directories; 69 | } 70 | 71 | /// 72 | /// Gets the full name of the directory. 73 | /// 74 | public string FullName 75 | { 76 | get { return this.isRoot ? this.name : Path.Combine(this.Parent.FullName, this.Name); } 77 | } 78 | 79 | /// 80 | /// Gets the name of the directory. 81 | /// 82 | public string Name 83 | { 84 | get { return this.name; } 85 | } 86 | 87 | /// 88 | /// Initializes a new instance of the class. 89 | /// The directory will be the root directory an a playlist. 90 | /// 91 | /// The name of the playlist. 92 | public ITunesDirectoryInfo(string playlistName) 93 | : this((ITunesDirectoryInfo)null) 94 | { 95 | playlistName.ThrowIfNull(() => playlistName); 96 | 97 | this.name = playlistName; 98 | this.isRoot = true; 99 | } 100 | 101 | /// 102 | /// Initializes a new instance of the class. 103 | /// The directory will be the last level of the directory structure and contains the files. 104 | /// 105 | /// The name of the album. 106 | /// The files that are contained in this directory. 107 | /// The parent. 108 | public ITunesDirectoryInfo(string albumName, IEnumerable files, ITunesDirectoryInfo parent) 109 | : this(parent) 110 | { 111 | albumName.ThrowIfNull(() => albumName); 112 | files.ThrowIfNull(() => files); 113 | 114 | this.name = albumName; 115 | this.files = files; 116 | } 117 | 118 | /// 119 | /// Initializes a new instance of the class. 120 | /// The directory will be the middle level of the directory structure and contains the album directories. 121 | /// 122 | /// The name of the artist. 123 | /// The directories that are contained in this directory. 124 | /// The parent. 125 | public ITunesDirectoryInfo(string artistName, IEnumerable directories, ITunesDirectoryInfo parent) 126 | : this(parent) 127 | { 128 | artistName.ThrowIfNull(() => artistName); 129 | directories.ThrowIfNull(() => directories); 130 | 131 | this.name = artistName; 132 | this.directories = directories; 133 | } 134 | 135 | /// 136 | /// Prevents a default instance of the class from being created. 137 | /// 138 | /// The parent directory. 139 | private ITunesDirectoryInfo(ITunesDirectoryInfo parent) 140 | { 141 | this.Parent = parent; 142 | this.files = Enumerable.Empty(); 143 | this.directories = Enumerable.Empty(); 144 | this.Exists = true; 145 | } 146 | 147 | /// 148 | /// Creates an iTunes directory info which does not exist. 149 | /// 150 | /// The name of the directory. 151 | /// The parent directory. 152 | /// A directory whichs property is set to false. 153 | public static ITunesDirectoryInfo CreateNonExistantDirectoryInfo(string name, ITunesDirectoryInfo parent) 154 | { 155 | name.ThrowIfNull(() => name); 156 | parent.ThrowIfNull(() => parent); 157 | 158 | var directory = new ITunesDirectoryInfo(parent) { name = name, Exists = false }; 159 | 160 | return directory; 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/ITunes/ITunesFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using Rareform.Extensions; 7 | using Rareform.IO; 8 | using Rareform.Reflection; 9 | using FlagSync.Core.FileSystem.Base; 10 | using FlagSync.Core.FileSystem.Local; 11 | using iTunesLib; 12 | 13 | namespace FlagSync.Core.FileSystem.ITunes 14 | { 15 | /// 16 | /// Represents the file system of an iTunes playlist 17 | /// 18 | public class ITunesFileSystem : IFileSystem 19 | { 20 | private IEnumerable playlistStructureChache; 21 | 22 | /// 23 | /// Occurs when the file copy progress has changed. 24 | /// 25 | public event EventHandler FileCopyProgressChanged; 26 | 27 | /// 28 | /// Deletes the specified file. This method always throws a . 29 | /// 30 | /// The file to delete. 31 | /// The file could not be accessed. 32 | /// This method is not supported. 33 | public void DeleteFile(IFileInfo file) 34 | { 35 | throw new NotSupportedException(); 36 | } 37 | 38 | /// 39 | /// Creates the specified directory in the target directory. This method always throws a . 40 | /// 41 | /// The source directory. 42 | /// The target directory. 43 | /// The directory could not be accessed. 44 | /// This method is not supported. 45 | public void CreateDirectory(IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory) 46 | { 47 | throw new NotSupportedException(); 48 | } 49 | 50 | /// 51 | /// Deletes the specified directory. This method always throws a . 52 | /// 53 | /// The directory to delete. 54 | /// The directory could not be accessed. 55 | /// This method is not supported. 56 | public void DeleteDirectory(IDirectoryInfo directory) 57 | { 58 | throw new NotSupportedException(); 59 | } 60 | 61 | /// 62 | /// Copies the specified file to the target directory. This method always throws a . 63 | /// 64 | /// The source file system. 65 | /// The source file. 66 | /// The target directory. 67 | /// The source file or target directory could not be accessed. 68 | /// This method is not supported. 69 | public void CopyFile(IFileSystem sourceFileSystem, IFileInfo sourceFile, IDirectoryInfo targetDirectory) 70 | { 71 | throw new NotSupportedException(); 72 | } 73 | 74 | /// 75 | /// Gets the file info at the specified path. 76 | /// 77 | /// The path of the file. 78 | /// 79 | /// An of the file from the specified path. 80 | /// 81 | public IFileInfo GetFileInfo(string path) 82 | { 83 | path.ThrowIfNull(() => path); 84 | 85 | string[] split = path.Split(Path.DirectorySeparatorChar); 86 | 87 | if (split.Length < 4) 88 | throw new ArgumentException("The path is not valid.", "path"); 89 | 90 | string playlist = split[0]; 91 | string artist = split[1]; 92 | string album = split[2]; 93 | string title = split[3]; 94 | 95 | var root = this.GetPlaylistStructure(playlist); 96 | 97 | IFileInfo fileInfo = root 98 | .Single(dir => dir.Name == artist) 99 | .GetDirectories() 100 | .Single(albumDir => albumDir.Name == album) 101 | .GetFiles() 102 | .Single(file => file.Name == title); 103 | 104 | return fileInfo; 105 | } 106 | 107 | /// 108 | /// Gets the directory info at the specified path. 109 | /// 110 | /// The path of the directory. 111 | /// 112 | /// An of the directory from the specified path. 113 | /// 114 | public IDirectoryInfo GetDirectoryInfo(string path) 115 | { 116 | path.ThrowIfNull(() => path); 117 | 118 | if (!this.DirectoryExists(path)) 119 | { 120 | return ITunesDirectoryInfo 121 | .CreateNonExistantDirectoryInfo(Path.GetFileName(path), (ITunesDirectoryInfo)this.GetDirectoryInfo(Path.GetDirectoryName(path))); 122 | } 123 | 124 | string[] split = path.Split(Path.DirectorySeparatorChar); 125 | 126 | string playlist = split[0]; 127 | string album = null; 128 | 129 | if (split.Length > 1) 130 | { 131 | string artist = split[1]; 132 | 133 | if (split.Length > 2) 134 | { 135 | album = split[2]; 136 | } 137 | 138 | var root = this.GetPlaylistStructure(playlist); 139 | 140 | IDirectoryInfo directoryInfo = root 141 | .SingleOrDefault(dir => dir.Name == artist); 142 | 143 | if (directoryInfo == null) 144 | { 145 | directoryInfo = ITunesDirectoryInfo 146 | .CreateNonExistantDirectoryInfo(album ?? artist, (ITunesDirectoryInfo)this.GetDirectoryInfo(Path.GetDirectoryName(path))); 147 | } 148 | 149 | else if (album != null) 150 | { 151 | directoryInfo = directoryInfo 152 | .GetDirectories() 153 | .Single(albumDir => albumDir.Name == album); 154 | } 155 | 156 | return directoryInfo; 157 | } 158 | 159 | return new ITunesDirectoryInfo(playlist); 160 | } 161 | 162 | /// 163 | /// Determines if the file at the specified path exists. 164 | /// 165 | /// The path of the file. 166 | /// 167 | /// true, if the file exists; otherwise, false. 168 | /// 169 | public bool FileExists(string path) 170 | { 171 | path.ThrowIfNull(() => path); 172 | 173 | string[] split = path.Split(Path.DirectorySeparatorChar); 174 | 175 | if (split.Length < 4) 176 | return false; 177 | 178 | string playlist = split[0]; 179 | string artist = split[1]; 180 | string album = split[2]; 181 | string title = split[3]; 182 | 183 | try 184 | { 185 | var root = this.GetPlaylistStructure(playlist); 186 | 187 | var artistDirectory = root.SingleOrDefault(dir => dir.Name == artist); 188 | 189 | if (artistDirectory != null) 190 | { 191 | var albumDirectory = artistDirectory 192 | .GetDirectories() 193 | .SingleOrDefault(albumDir => albumDir.Name == album); 194 | 195 | if (albumDirectory != null) 196 | { 197 | return albumDirectory 198 | .GetFiles() 199 | .Any(file => file.Name == title); 200 | } 201 | } 202 | } 203 | 204 | catch (COMException) 205 | { 206 | return false; 207 | } 208 | 209 | return false; 210 | } 211 | 212 | /// 213 | /// Determines if the directory at the specified path exists. 214 | /// 215 | /// The path of the directory. 216 | /// 217 | /// true, if the directory exists; otherwise, false. 218 | /// 219 | public bool DirectoryExists(string path) 220 | { 221 | path.ThrowIfNull(() => path); 222 | 223 | string[] split = path.Split(Path.DirectorySeparatorChar); 224 | 225 | if (split.Length == 1) 226 | { 227 | return PlaylistExists(split[0]); 228 | } 229 | 230 | string playlist = split[0]; 231 | string artist = split[1]; 232 | 233 | string album = null; 234 | 235 | if (split.Length > 2) 236 | { 237 | album = split[2]; 238 | } 239 | 240 | try 241 | { 242 | var root = this.GetPlaylistStructure(playlist); 243 | 244 | if (album == null) 245 | { 246 | return root.Any(artistDir => artistDir.Name == artist); 247 | } 248 | 249 | var artistDirectory = root.SingleOrDefault(artistDir => artistDir.Name == artist); 250 | 251 | if (artistDirectory != null) 252 | { 253 | return artistDirectory 254 | .GetDirectories() 255 | .Any(albumDir => albumDir.Name == album); 256 | } 257 | 258 | return false; 259 | } 260 | 261 | catch (COMException) 262 | { 263 | return false; 264 | } 265 | } 266 | 267 | /// 268 | /// Opens the stream of the specified file. 269 | /// 270 | /// The file. 271 | /// 272 | /// A stream from the specified file. 273 | /// 274 | public Stream OpenFileStream(IFileInfo file) 275 | { 276 | file.ThrowIfNull(() => file); 277 | 278 | return File.Open(file.FullName, FileMode.Open, FileAccess.Read); 279 | } 280 | 281 | /// 282 | /// Combines two paths for the specific file system. This method always throws a . 283 | /// 284 | /// The first path. 285 | /// The second path. 286 | /// 287 | /// A path, which is the combination of the first and second path. 288 | /// 289 | public string CombinePath(string path1, string path2) 290 | { 291 | throw new NotSupportedException(); 292 | } 293 | 294 | /// 295 | /// Maps the specified iTunes playlist to a directory structure. 296 | /// 297 | /// The playlist. 298 | /// A directory structure which represents the specified iTunes playlist 299 | public static IEnumerable MapPlaylistToDirectoryStructure(string playlistName) 300 | { 301 | if (String.IsNullOrEmpty(playlistName)) 302 | throw new ArgumentException("The playlist name name cannot be null or empty", Reflector.GetMemberName(() => playlistName)); 303 | 304 | var root = new ITunesDirectoryInfo(playlistName); 305 | 306 | var files = new iTunesApp() 307 | .LibrarySource 308 | .Playlists 309 | .ItemByName[playlistName] 310 | .Tracks 311 | .Cast(); 312 | 313 | var tracksByArtist = files 314 | .GroupBy(file => file.Artist) 315 | .OrderBy(group => group.Key); 316 | 317 | var artistDirectories = new List(); 318 | 319 | foreach (var artistGroup in tracksByArtist) 320 | { 321 | var albumGroups = artistGroup 322 | .GroupBy(track => track.Album); 323 | 324 | // The artist name has to be normalized, so that it doesn't contain any characters that are invalid for a path 325 | string artistName = NormalizeArtistOrAlbumName(artistGroup.Key); 326 | 327 | var albumDirectories = albumGroups 328 | .Select(album => new { Album = album, AlbumName = NormalizeArtistOrAlbumName(album.Key) }) 329 | .Select 330 | ( 331 | directory => 332 | new ITunesDirectoryInfo 333 | ( 334 | directory.AlbumName, 335 | directory.Album 336 | .Where(track => track.Location != null) 337 | .Select 338 | ( 339 | track => (IFileInfo)new LocalFileInfo(new FileInfo(track.Location)) 340 | ), 341 | null 342 | ) 343 | ) 344 | .ToList(); //Execute the query immediately, because a streaming causes weird bugs 345 | 346 | var artistDirectory = new ITunesDirectoryInfo(artistName, albumDirectories, root); 347 | 348 | foreach (ITunesDirectoryInfo albumDirectory in artistDirectory.GetDirectories()) 349 | { 350 | albumDirectory.Parent = artistDirectory; 351 | } 352 | 353 | artistDirectories.Add(artistDirectory); 354 | } 355 | 356 | return artistDirectories; 357 | } 358 | 359 | /// 360 | /// Normalizes the name of the artist or album. 361 | /// 362 | /// Name of the artist or album. 363 | /// A normalized form of the artist or album string 364 | private static string NormalizeArtistOrAlbumName(string artistOrAlbumName) 365 | { 366 | artistOrAlbumName.ThrowIfNull(() => artistOrAlbumName); 367 | 368 | var invalidCharacters = Path.GetInvalidPathChars().Concat(Path.GetInvalidFileNameChars()).Distinct(); 369 | 370 | foreach (char invalidCharacter in invalidCharacters) 371 | { 372 | artistOrAlbumName = artistOrAlbumName.Replace(invalidCharacter.ToString(), string.Empty); 373 | } 374 | 375 | return artistOrAlbumName; 376 | } 377 | 378 | /// 379 | /// Determines, if the playlist with the specified name exists. 380 | /// 381 | /// Th name of the playlist. 382 | /// True, if the playlist exists; otherwise, false. 383 | private static bool PlaylistExists(string playlistName) 384 | { 385 | var playlist = new iTunesApp() 386 | .LibrarySource 387 | .Playlists 388 | .ItemByName[playlistName]; 389 | 390 | return playlist != null; 391 | } 392 | 393 | /// 394 | /// Gets the structure of the specified playlist. 395 | /// 396 | /// The playlist. 397 | /// A wich represents the playlist structure. 398 | private IEnumerable GetPlaylistStructure(string playlistName) 399 | { 400 | if (String.IsNullOrEmpty(playlistName)) 401 | throw new ArgumentException("The playlist name cannot be empty", Reflector.GetMemberName(() => playlistName)); 402 | 403 | if (this.playlistStructureChache == null) 404 | { 405 | this.playlistStructureChache = MapPlaylistToDirectoryStructure(playlistName); 406 | } 407 | 408 | return playlistStructureChache; 409 | } 410 | } 411 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Local/LocalDirectoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using FlagSync.Core.FileSystem.Base; 6 | 7 | namespace FlagSync.Core.FileSystem.Local 8 | { 9 | /// 10 | /// Represents a directory in the local filesystem. 11 | /// 12 | /// 13 | /// The class is basically a wrapper around 14 | /// the class and abstracts it to be 15 | /// used as an . 16 | /// 17 | [DebuggerDisplay("{FullName}")] 18 | public class LocalDirectoryInfo : IDirectoryInfo 19 | { 20 | private readonly DirectoryInfo directoryInfo; 21 | 22 | /// 23 | /// Gets the parent directory. 24 | /// 25 | public IDirectoryInfo Parent 26 | { 27 | get { return new LocalDirectoryInfo(this.directoryInfo.Parent); } 28 | } 29 | 30 | /// 31 | /// Gets the full name of the directory. 32 | /// 33 | public string FullName 34 | { 35 | get { return this.directoryInfo.FullName; } 36 | } 37 | 38 | /// 39 | /// Gets the name of the directory. 40 | /// 41 | public string Name 42 | { 43 | get { return this.directoryInfo.Name; } 44 | } 45 | 46 | /// 47 | /// Gets a value indicating whether the directory exists. 48 | /// 49 | /// 50 | /// true if the directory exists; otherwise, false. 51 | /// 52 | public bool Exists 53 | { 54 | get { return this.directoryInfo.Exists; } 55 | } 56 | 57 | /// 58 | /// Initializes a new instance of the class. 59 | /// 60 | /// The directory info to wrap. 61 | public LocalDirectoryInfo(DirectoryInfo directoryInfo) 62 | { 63 | //Don't check for null here 64 | 65 | this.directoryInfo = directoryInfo; 66 | } 67 | 68 | /// 69 | /// Returns a list of all files in the directory. 70 | /// 71 | /// 72 | /// The files in the directory. 73 | /// 74 | /// 75 | /// The exception that is thrown if the directory is locked 76 | /// 77 | public IEnumerable GetFiles() 78 | { 79 | return this.directoryInfo 80 | .GetFiles() 81 | .Select(file => (IFileInfo)new LocalFileInfo(file)); 82 | } 83 | 84 | /// 85 | /// Returns a list of all directories in the directory. 86 | /// 87 | /// 88 | /// The directories in the directory. 89 | /// 90 | /// 91 | /// The exception that is thrown if the directory is locked. 92 | /// 93 | public IEnumerable GetDirectories() 94 | { 95 | return this.directoryInfo 96 | .GetDirectories() 97 | .Select(directory => (IDirectoryInfo)new LocalDirectoryInfo(directory)); 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Local/LocalFileInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using Rareform.Extensions; 5 | using FlagSync.Core.FileSystem.Base; 6 | 7 | namespace FlagSync.Core.FileSystem.Local 8 | { 9 | /// 10 | /// Represents a file on the local file system. 11 | /// 12 | /// 13 | /// The class is basically a wrapper around 14 | /// the class and abstracts it to be 15 | /// used as an . 16 | /// 17 | [DebuggerDisplay("{FullName}")] 18 | public class LocalFileInfo : IFileInfo 19 | { 20 | private readonly FileInfo fileInfo; 21 | 22 | /// 23 | /// Gets the last write time. 24 | /// 25 | public DateTime LastWriteTime 26 | { 27 | get { return this.fileInfo.LastWriteTime; } 28 | } 29 | 30 | /// 31 | /// Gets the length of the file. 32 | /// 33 | public long Length 34 | { 35 | get { return this.fileInfo.Length; } 36 | } 37 | 38 | /// 39 | /// Gets the full name of the file. 40 | /// 41 | public string FullName 42 | { 43 | get { return this.fileInfo.FullName; } 44 | } 45 | 46 | /// 47 | /// Gets the name of the file. 48 | /// 49 | public string Name 50 | { 51 | get { return this.fileInfo.Name; } 52 | } 53 | 54 | /// 55 | /// Gets the directory. 56 | /// 57 | public IDirectoryInfo Directory 58 | { 59 | get { return new LocalDirectoryInfo(this.fileInfo.Directory); } 60 | } 61 | 62 | /// 63 | /// Gets a value indicating whether the file exists. 64 | /// 65 | /// 66 | /// true if the file exists; otherwise, false. 67 | /// 68 | public bool Exists 69 | { 70 | get { return this.fileInfo.Exists; } 71 | } 72 | 73 | /// 74 | /// Initializes a new instance of the class. 75 | /// 76 | /// The file info to wrap. 77 | public LocalFileInfo(FileInfo fileInfo) 78 | { 79 | fileInfo.ThrowIfNull(() => fileInfo); 80 | 81 | this.fileInfo = fileInfo; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FileSystem/Local/LocalFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security; 4 | using Rareform.Extensions; 5 | using Rareform.IO; 6 | using FlagSync.Core.FileSystem.Base; 7 | 8 | namespace FlagSync.Core.FileSystem.Local 9 | { 10 | public class LocalFileSystem : IFileSystem 11 | { 12 | /// 13 | /// Occurs when the file copy progress has changed. 14 | /// 15 | public event EventHandler FileCopyProgressChanged; 16 | 17 | /// 18 | /// Deletes the specified file. 19 | /// 20 | /// The file to delete. 21 | /// The file could not be accessed. 22 | public void DeleteFile(IFileInfo file) 23 | { 24 | file.ThrowIfNull(() => file); 25 | 26 | if (!(file is LocalFileInfo)) 27 | throw new ArgumentException("The file must be of type LocalFileInfo.", "file"); 28 | 29 | try 30 | { 31 | File.SetAttributes(file.FullName, FileAttributes.Normal); 32 | File.Delete(file.FullName); 33 | } 34 | 35 | catch (IOException ex) 36 | { 37 | throw new AccessException("The file could not be accessed.", ex); 38 | } 39 | 40 | catch (SecurityException ex) 41 | { 42 | throw new AccessException("The file could not be accessed.", ex); 43 | } 44 | 45 | catch (UnauthorizedAccessException ex) 46 | { 47 | throw new AccessException("The file could not be accessed.", ex); 48 | } 49 | } 50 | 51 | /// 52 | /// Creates the specified directory in the target directory. 53 | /// 54 | /// The source directory. 55 | /// The target directory. 56 | /// The directory could not be accessed. 57 | public void CreateDirectory(IDirectoryInfo sourceDirectory, IDirectoryInfo targetDirectory) 58 | { 59 | sourceDirectory.ThrowIfNull(() => sourceDirectory); 60 | targetDirectory.ThrowIfNull(() => targetDirectory); 61 | 62 | try 63 | { 64 | Directory.CreateDirectory(this.CombinePath(targetDirectory.FullName, sourceDirectory.Name)); 65 | } 66 | 67 | catch (DirectoryNotFoundException ex) 68 | { 69 | throw new AccessException("The file could not be accessed.", ex); 70 | } 71 | 72 | catch (PathTooLongException ex) 73 | { 74 | throw new AccessException("The file could not be accessed.", ex); 75 | } 76 | 77 | catch (IOException ex) 78 | { 79 | throw new AccessException("The file could not be accessed.", ex); 80 | } 81 | 82 | catch (UnauthorizedAccessException ex) 83 | { 84 | throw new AccessException(ex.Message, ex); 85 | } 86 | } 87 | 88 | /// 89 | /// Deletes the specified directory. 90 | /// 91 | /// The directory to delete. 92 | /// The directory could not be accessed. 93 | public void DeleteDirectory(IDirectoryInfo directory) 94 | { 95 | directory.ThrowIfNull(() => directory); 96 | 97 | if (!(directory is LocalDirectoryInfo)) 98 | throw new ArgumentException("The directory must be of type LocalDirectoryInfo.", "directory"); 99 | 100 | try 101 | { 102 | Directory.Delete(directory.FullName, true); 103 | } 104 | 105 | catch (DirectoryNotFoundException ex) 106 | { 107 | throw new AccessException("The file could not be accessed.", ex); 108 | } 109 | 110 | catch (IOException ex) 111 | { 112 | throw new AccessException("The file could not be accessed.", ex); 113 | } 114 | 115 | catch (UnauthorizedAccessException ex) 116 | { 117 | throw new AccessException("The file could not be accessed.", ex); 118 | } 119 | } 120 | 121 | /// 122 | /// Copies the specified file to the target directory. 123 | /// 124 | /// The source file system. 125 | /// The source file. 126 | /// The target directory. 127 | /// The source file or target directory could not be accessed. 128 | public void CopyFile(IFileSystem sourceFileSystem, IFileInfo sourceFile, IDirectoryInfo targetDirectory) 129 | { 130 | sourceFileSystem.ThrowIfNull(() => sourceFileSystem); 131 | sourceFile.ThrowIfNull(() => sourceFile); 132 | targetDirectory.ThrowIfNull(() => targetDirectory); 133 | 134 | if (!(targetDirectory is LocalDirectoryInfo)) 135 | throw new ArgumentException("The target directory must be of type LocalDirectoryInfo.", "targetDirectory"); 136 | 137 | try 138 | { 139 | using (Stream sourceStream = sourceFileSystem.OpenFileStream(sourceFile)) 140 | { 141 | string targetFilePath = this.CombinePath(targetDirectory.FullName, sourceFile.Name); 142 | 143 | try 144 | { 145 | using (FileStream targetStream = File.Create(targetFilePath)) 146 | { 147 | if (sourceFile.Length > 0) 148 | { 149 | var copyOperation = new StreamCopyOperation(sourceStream, targetStream, 256 * 1024, true); 150 | 151 | copyOperation.CopyProgressChanged += 152 | (sender, e) => this.FileCopyProgressChanged.RaiseSafe(this, e); 153 | 154 | copyOperation.Execute(); 155 | } 156 | } 157 | } 158 | 159 | catch (IOException) 160 | { 161 | File.Delete(targetFilePath); 162 | 163 | throw; 164 | } 165 | } 166 | } 167 | 168 | catch (UnauthorizedAccessException ex) 169 | { 170 | throw new AccessException("The file could not be accessed.", ex); 171 | } 172 | 173 | catch (SecurityException ex) 174 | { 175 | throw new AccessException("The file could not be accessed.", ex); 176 | } 177 | 178 | catch (IOException ex) 179 | { 180 | throw new AccessException("The file could not be accessed.", ex); 181 | } 182 | } 183 | 184 | /// 185 | /// Gets the file info at the specified path. 186 | /// 187 | /// The path of the file. 188 | /// 189 | /// An of the file from the specified path. 190 | /// 191 | public IFileInfo GetFileInfo(string path) 192 | { 193 | path.ThrowIfNull(() => path); 194 | 195 | return new LocalFileInfo(new FileInfo(path)); 196 | } 197 | 198 | /// 199 | /// Gets the directory info at the specified path. 200 | /// 201 | /// The path of the directory. 202 | /// 203 | /// An of the directory from the specified path. 204 | /// 205 | public IDirectoryInfo GetDirectoryInfo(string path) 206 | { 207 | path.ThrowIfNull(() => path); 208 | 209 | return new LocalDirectoryInfo(new DirectoryInfo(path)); 210 | } 211 | 212 | /// 213 | /// Determines if the file at the specified path exists. 214 | /// 215 | /// The path of the file. 216 | /// 217 | /// true, if the file exists; otherwise, false. 218 | /// 219 | public bool FileExists(string path) 220 | { 221 | path.ThrowIfNull(() => path); 222 | 223 | return File.Exists(path); 224 | } 225 | 226 | /// 227 | /// Determines if the directory at the specified path exists. 228 | /// 229 | /// The path of the directory. 230 | /// 231 | /// true, if the directory exists; otherwise, false. 232 | /// 233 | public bool DirectoryExists(string path) 234 | { 235 | path.ThrowIfNull(() => path); 236 | 237 | return Directory.Exists(path); 238 | } 239 | 240 | /// 241 | /// Opens the stream of the specified file. 242 | /// 243 | /// The file. 244 | /// 245 | /// A stream from the specified file. 246 | /// 247 | public Stream OpenFileStream(IFileInfo file) 248 | { 249 | file.ThrowIfNull(() => file); 250 | 251 | return File.Open(file.FullName, FileMode.Open, FileAccess.Read); 252 | } 253 | 254 | /// 255 | /// Combines two paths for the specific file system. 256 | /// 257 | /// The first path. 258 | /// The second path. 259 | /// 260 | /// A path, which is the combination of the first and second path. 261 | /// 262 | public string CombinePath(string path1, string path2) 263 | { 264 | path1.ThrowIfNull(() => path1); 265 | path2.ThrowIfNull(() => path2); 266 | 267 | return Path.Combine(path1, path2); 268 | } 269 | } 270 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/FlagSync.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647} 9 | Library 10 | Properties 11 | FlagSync.Core 12 | FlagSync.Core 13 | v4.0 14 | 512 15 | Client 16 | 17 | 18 | true 19 | bin\Debug\ 20 | x86 21 | bin\Debug\FlagSync.Core.dll.CodeAnalysisLog.xml 22 | true 23 | GlobalSuppressions.cs 24 | AllRules.ruleset 25 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 26 | false 27 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 28 | true 29 | 30 | 31 | bin\Release\ 32 | x86 33 | bin\Release\FlagSync.Core.dll.CodeAnalysisLog.xml 34 | true 35 | GlobalSuppressions.cs 36 | MinimumRecommendedRules.ruleset 37 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 38 | false 39 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 40 | true 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | ..\packages\FlagFtp.0.1.2\lib\FlagFtp.dll 79 | 80 | 81 | False 82 | ..\packages\Rareform.1.2.0\lib\Rareform.dll 83 | 84 | 85 | 86 | 87 | 88 | {9E93C96F-CF0D-43F6-8BA8-B807A3370712} 89 | 1 90 | 13 91 | 0 92 | tlbimp 93 | False 94 | True 95 | 96 | 97 | 98 | 99 | 100 | 101 | 108 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/JobEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rareform.Extensions; 3 | 4 | namespace FlagSync.Core 5 | { 6 | /// 7 | /// Provides data for events of the class. 8 | /// 9 | public class JobEventArgs : EventArgs 10 | { 11 | /// 12 | /// Gets the job. 13 | /// 14 | public Job Job { get; private set; } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The job. 20 | public JobEventArgs(Job job) 21 | { 22 | job.ThrowIfNull(() => job); 23 | 24 | this.Job = job; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // Allgemeine Informationen über eine Assembly werden über die folgenden 5 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 6 | // die mit einer Assembly verknüpft sind. 7 | [assembly: AssemblyTitle("FlagSync.Core")] 8 | [assembly: AssemblyDescription("Synchronization & Backup Core")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("FlagSync.Core")] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 17 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 18 | // COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. 19 | [assembly: ComVisible(false)] 20 | 21 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 22 | [assembly: Guid("b4db4066-eaaa-4f11-b92f-2f1bd0397a5c")] 23 | 24 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 25 | // 26 | // Hauptversion 27 | // Nebenversion 28 | // Buildnummer 29 | // Revision 30 | // 31 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 32 | // übernehmen, indem Sie "*" eingeben: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("2.4.2")] 35 | [assembly: AssemblyFileVersion("2.4.2")] -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/SyncJob.cs: -------------------------------------------------------------------------------- 1 | using FlagSync.Core.FileSystem.Base; 2 | 3 | namespace FlagSync.Core 4 | { 5 | public class SyncJob : Job 6 | { 7 | /// 8 | /// Initializes a new instance of the class. 9 | /// 10 | /// The name of the job. 11 | /// The file system A. 12 | /// The file system B. 13 | /// The directory A. 14 | /// The directory B. 15 | public SyncJob(string name, IFileSystem fileSystemA, IFileSystem fileSystemB, IDirectoryInfo directoryA, IDirectoryInfo directoryB) 16 | : base(name, fileSystemA, fileSystemB, directoryA, directoryB) { } 17 | 18 | /// 19 | /// Starts the job, opies new and modified files from directory A to directory B and then switches the direction. 20 | /// 21 | /// if set to true a preview will be performed. 22 | public override void Start(bool preview) 23 | { 24 | this.BackupDirectoryRecursively(this.DirectoryA, this.DirectoryB, !preview); 25 | this.BackupDirectoryRecursively(this.DirectoryB, this.DirectoryA, !preview); 26 | 27 | this.OnFinished(System.EventArgs.Empty); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/CorruptSaveFileException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Data 4 | { 5 | public class CorruptSaveFileException : Exception 6 | { 7 | public CorruptSaveFileException(string message, Exception innerException) 8 | : base(message, innerException) 9 | { } 10 | } 11 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/DataController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using FlagSync.Core; 8 | using FlagSync.Core.FileSystem.Base; 9 | using Rareform.Serialization; 10 | 11 | namespace FlagSync.Data 12 | { 13 | /// 14 | /// Provides methods for data-access. 15 | /// 16 | public static class DataController 17 | { 18 | /// 19 | /// Gets the app data folder path. 20 | /// 21 | public static string AppDataFolderPath 22 | { 23 | get 24 | { 25 | return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FlagSync"); 26 | } 27 | } 28 | 29 | /// 30 | /// Creates the app data folder. 31 | /// 32 | public static void CreateAppDataFolder() 33 | { 34 | Directory.CreateDirectory(DataController.AppDataFolderPath); 35 | } 36 | 37 | /// 38 | /// Determines whether the iTunes application is opened. 39 | /// 40 | /// 41 | /// true if the iTunes application is opened; otherwise, false. 42 | /// 43 | public static bool IsITunesOpened() 44 | { 45 | return Process.GetProcessesByName("iTunes").Any(); 46 | } 47 | 48 | /// 49 | /// Determines whether a new version of this application is available. 50 | /// 51 | /// The current version of the application. 52 | /// 53 | /// true if a new version of this application is available; otherwise, false. 54 | /// 55 | public static bool IsNewVersionAvailable(Version currentVersion) 56 | { 57 | var client = new WebClient(); 58 | string versionString; 59 | 60 | try 61 | { 62 | Debug.WriteLine("Checking for newer version..."); 63 | versionString = client.DownloadString("http://flagbug.bitbucket.org/flagsyncversion"); 64 | Debug.WriteLine("Version on server is " + versionString); 65 | } 66 | 67 | catch (WebException) 68 | { 69 | Debug.WriteLine("Exception while retrieving the new version."); 70 | return false; 71 | } 72 | 73 | var webVersion = new Version(versionString); 74 | 75 | Debug.WriteLine("Current version is " + currentVersion); 76 | 77 | bool newVersionAvailable = webVersion > currentVersion; 78 | 79 | Debug.WriteLine("New version available: " + newVersionAvailable); 80 | 81 | return newVersionAvailable; 82 | } 83 | 84 | /// 85 | /// Tries the load the job settings from the specified path. 86 | /// 87 | /// The path to the file with the serialized setzings. 88 | /// The save file is in an invalid state. 89 | /// The iTunes process is not started.. 90 | /// 91 | /// The result of the operation. 92 | /// 93 | public static IEnumerable LoadJobSettings(string path) 94 | { 95 | IEnumerable settings; 96 | 97 | try 98 | { 99 | settings = GenericXmlSerializer.DeserializeCollection(path); 100 | } 101 | 102 | catch (InvalidOperationException ex) 103 | { 104 | throw new CorruptSaveFileException("The save file is corrupt.", ex); 105 | } 106 | 107 | if (settings.Any(setting => setting.FirstFileSystemSetting is ITunesFileSystemSetting && !DataController.IsITunesOpened())) 108 | { 109 | throw new ITunesNotOpenedException("iTunes is not opened."); 110 | } 111 | 112 | return settings; 113 | } 114 | 115 | /// 116 | /// Saves the job settings to the specified path. 117 | /// 118 | /// The settings. 119 | /// The path. 120 | public static void SaveJobSettings(IEnumerable settings, string path) 121 | { 122 | GenericXmlSerializer.SerializeCollection(settings.ToList(), path); 123 | } 124 | 125 | /// 126 | /// Creates a job from the specified job setting. 127 | /// 128 | /// The job setting. 129 | /// 130 | /// A job that is created from the specified job setting. 131 | /// 132 | public static Job CreateJobFromSetting(JobSetting setting) 133 | { 134 | IFileSystem firstFileSystem = setting.FirstFileSystemSetting.GetFileSystem(); 135 | IFileSystem secondFileSystem = setting.SecondFileSystemSetting.GetFileSystem(); 136 | 137 | IDirectoryInfo firstRootDirectory = setting.FirstFileSystemSetting.GetRootDirectory(); 138 | IDirectoryInfo secondRootDirectory = setting.SecondFileSystemSetting.GetRootDirectory(); 139 | 140 | switch (setting.SyncMode) 141 | { 142 | case SyncMode.Backup: 143 | return new BackupJob(setting.Name, firstFileSystem, secondFileSystem, firstRootDirectory, secondRootDirectory); 144 | 145 | case SyncMode.Synchronization: 146 | return new SyncJob(setting.Name, firstFileSystem, secondFileSystem, firstRootDirectory, secondRootDirectory); 147 | } 148 | 149 | throw new InvalidOperationException(); 150 | } 151 | } 152 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/FileSystemSetting.cs: -------------------------------------------------------------------------------- 1 | using FlagSync.Core.FileSystem.Base; 2 | 3 | namespace FlagSync.Data 4 | { 5 | public abstract class FileSystemSetting 6 | { 7 | public string Source { get; set; } 8 | 9 | public abstract IFileSystem GetFileSystem(); 10 | 11 | public abstract IDirectoryInfo GetRootDirectory(); 12 | } 13 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/FlagSync.Data.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {080FB9A0-A2F9-438F-8F84-60B7FB448633} 9 | Library 10 | Properties 11 | FlagSync.Data 12 | FlagSync.Data 13 | v4.0 14 | 512 15 | Client 16 | 17 | 18 | true 19 | bin\x86\Debug\ 20 | DEBUG;TRACE 21 | full 22 | x86 23 | bin\Debug\FlagSync.Data.dll.CodeAnalysisLog.xml 24 | true 25 | GlobalSuppressions.cs 26 | prompt 27 | MinimumRecommendedRules.ruleset 28 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 29 | true 30 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 31 | true 32 | 33 | 34 | bin\x86\Release\ 35 | TRACE 36 | true 37 | pdbonly 38 | x86 39 | bin\Release\FlagSync.Data.dll.CodeAnalysisLog.xml 40 | true 41 | GlobalSuppressions.cs 42 | prompt 43 | MinimumRecommendedRules.ruleset 44 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 45 | true 46 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 47 | 48 | 49 | 50 | ..\packages\FlagFtp.0.1.2\lib\FlagFtp.dll 51 | 52 | 53 | False 54 | ..\packages\Rareform.1.2.0\lib\Rareform.dll 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647} 75 | FlagSync.Core 76 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/FtpFileSystemSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FlagFtp; 4 | using FlagSync.Core.FileSystem.Base; 5 | using FlagSync.Core.FileSystem.Ftp; 6 | using FtpDirectoryInfo = FlagSync.Core.FileSystem.Ftp.FtpDirectoryInfo; 7 | 8 | namespace FlagSync.Data 9 | { 10 | public class FtpFileSystemSetting : FileSystemSetting 11 | { 12 | public string Username { get; set; } 13 | 14 | public string Password { get; set; } 15 | 16 | public override IFileSystem GetFileSystem() 17 | { 18 | return new FtpFileSystem(new Uri(this.Source), new NetworkCredential(this.Username, this.Password)); 19 | } 20 | 21 | public override IDirectoryInfo GetRootDirectory() 22 | { 23 | return new FtpDirectoryInfo(this.Source, new FtpClient(new NetworkCredential(this.Username, this.Password))); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/ITunesFileSystemSetting.cs: -------------------------------------------------------------------------------- 1 | using FlagSync.Core.FileSystem.Base; 2 | using FlagSync.Core.FileSystem.ITunes; 3 | 4 | namespace FlagSync.Data 5 | { 6 | public class ITunesFileSystemSetting : FileSystemSetting 7 | { 8 | public override IFileSystem GetFileSystem() 9 | { 10 | return new ITunesFileSystem(); 11 | } 12 | 13 | public override IDirectoryInfo GetRootDirectory() 14 | { 15 | return new ITunesDirectoryInfo(this.Source); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/ITunesNotOpenedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Data 4 | { 5 | public class ITunesNotOpenedException : Exception 6 | { 7 | public ITunesNotOpenedException(string message) 8 | : base(message) 9 | { } 10 | } 11 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/JobSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FlagSync.Data 4 | { 5 | [Serializable] 6 | public class JobSetting 7 | { 8 | public FileSystemSetting FirstFileSystemSetting { get; set; } 9 | 10 | public FileSystemSetting SecondFileSystemSetting { get; set; } 11 | 12 | /// 13 | /// Gets or sets the sync mode. 14 | /// 15 | /// The sync mode. 16 | public SyncMode SyncMode { get; set; } 17 | 18 | /// 19 | /// Gets or sets the name. 20 | /// 21 | /// The name. 22 | public string Name { get; set; } 23 | 24 | /// 25 | /// Gets or sets a value indicating whether this instance is included. 26 | /// 27 | /// true if this instance is included; otherwise, false. 28 | public bool IsIncluded { get; set; } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The name. 34 | public JobSetting(string name) 35 | : this() 36 | { 37 | this.Name = name; 38 | } 39 | 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// 43 | public JobSetting() 44 | { 45 | this.IsIncluded = true; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/JobSettingsLoadingResult.cs: -------------------------------------------------------------------------------- 1 | namespace FlagSync.Data 2 | { 3 | public enum JobSettingsLoadingResult 4 | { 5 | Succeed, 6 | ITunesNotOpened, 7 | CorruptFile 8 | } 9 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/LocalFileSystemSetting.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using FlagSync.Core.FileSystem.Base; 3 | using FlagSync.Core.FileSystem.Local; 4 | 5 | namespace FlagSync.Data 6 | { 7 | public class LocalFileSystemSetting : FileSystemSetting 8 | { 9 | public override IFileSystem GetFileSystem() 10 | { 11 | return new LocalFileSystem(); 12 | } 13 | 14 | public override IDirectoryInfo GetRootDirectory() 15 | { 16 | return new LocalDirectoryInfo(new DirectoryInfo(this.Source)); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("FlagSync.Data")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("FlagSync.Data")] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("d5e933e1-9bb4-4ed3-967b-9c8e1612ee10")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("2.4.2")] 35 | [assembly: AssemblyFileVersion("2.4.2")] -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/SyncMode.cs: -------------------------------------------------------------------------------- 1 | namespace FlagSync.Data 2 | { 3 | /// 4 | /// Specifies the sync mode of a job. Used by the class. 5 | /// 6 | public enum SyncMode 7 | { 8 | Backup, 9 | Synchronization 10 | } 11 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.Data/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 25 | 26 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace FlagSync.View 4 | { 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ByteToKiloByteConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace FlagSync.View 6 | { 7 | [ValueConversion(typeof(long), typeof(int))] 8 | public class ByteToKiloByteConverter : IValueConverter 9 | { 10 | /// 11 | /// Converts a value. 12 | /// 13 | /// The value produced by the binding source. 14 | /// The type of the binding target property. 15 | /// The converter parameter to use. 16 | /// The culture to use in the converter. 17 | /// 18 | /// A converted value. If the method returns null, the valid null value is used. 19 | /// 20 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | long bytes = (long)value; 23 | return (int)(bytes / 1024); 24 | } 25 | 26 | /// 27 | /// Converts a value. 28 | /// 29 | /// The value that is produced by the binding target. 30 | /// The type to convert to. 31 | /// The converter parameter to use. 32 | /// The culture to use in the converter. 33 | /// 34 | /// A converted value. If the method returns null, the valid null value is used. 35 | /// 36 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 37 | { 38 | int kiloBytes = (int)value; 39 | return (long)(kiloBytes * 1024); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/FlagSync.View.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {91E37F1B-FE0F-456F-8F67-4058A854FDF8} 9 | WinExe 10 | Properties 11 | FlagSync.View 12 | FlagSync 13 | v4.0 14 | 512 15 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 4 17 | Client 18 | 19 | 20 | x86 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | AllRules.ruleset 29 | 30 | 31 | x86 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | Images\ApplicationIcon.ico 41 | 42 | 43 | 44 | False 45 | ..\packages\MahApps.Metro.0.8.0.0\lib\net40\MahApps.Metro.dll 46 | 47 | 48 | False 49 | ..\packages\Rareform.1.2.0\lib\Rareform.dll 50 | 51 | 52 | 53 | 54 | ..\packages\MahApps.Metro.0.8.0.0\lib\net40\System.Windows.Interactivity.dll 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | MSBuild:Compile 65 | Designer 66 | 67 | 68 | Designer 69 | MSBuild:Compile 70 | 71 | 72 | Designer 73 | MSBuild:Compile 74 | 75 | 76 | Designer 77 | MSBuild:Compile 78 | 79 | 80 | Designer 81 | MSBuild:Compile 82 | 83 | 84 | Designer 85 | MSBuild:Compile 86 | 87 | 88 | MSBuild:Compile 89 | Designer 90 | 91 | 92 | 93 | 94 | AboutBox.xaml 95 | 96 | 97 | 98 | App.xaml 99 | Code 100 | 101 | 102 | 103 | FtpFileSystemPanel.xaml 104 | 105 | 106 | 107 | ITunesFileSystemPanel.xaml 108 | 109 | 110 | 111 | JobCompositionControl.xaml 112 | 113 | 114 | 115 | 116 | LocalFileSystemPanel.xaml 117 | 118 | 119 | 120 | 121 | 122 | MainWindow.xaml 123 | Code 124 | 125 | 126 | 127 | 128 | Code 129 | 130 | 131 | Resources.de-DE.resx 132 | True 133 | True 134 | 135 | 136 | True 137 | True 138 | Resources.resx 139 | 140 | 141 | True 142 | Settings.settings 143 | True 144 | 145 | 146 | PublicResXFileCodeGenerator 147 | Resources.de-DE.Designer.cs 148 | Designer 149 | 150 | 151 | PublicResXFileCodeGenerator 152 | Designer 153 | Resources.Designer.cs 154 | 155 | 156 | 157 | 158 | SettingsSingleFileGenerator 159 | Settings.Designer.cs 160 | 161 | 162 | 163 | 164 | 165 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647} 166 | FlagSync.Core 167 | 168 | 169 | {080FB9A0-A2F9-438F-8F84-60B7FB448633} 170 | FlagSync.Data 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | {9E93C96F-CF0D-43F6-8BA8-B807A3370712} 198 | 1 199 | 13 200 | 0 201 | tlbimp 202 | False 203 | True 204 | True 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 226 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Add.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/ApplicationIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/ApplicationIcon.ico -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/DownArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/DownArrow.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Error.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/FTPServer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/FTPServer.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Load.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Local.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/OpenFolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/OpenFolder.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Remove.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Save.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/Success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/Success.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/UpArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/UpArrow.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Images/iTunes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Images/iTunes.png -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/LogMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Media; 3 | using System.Windows.Media.Imaging; 4 | using Rareform.Extensions; 5 | using Rareform.Patterns.MVVM; 6 | 7 | namespace FlagSync.View 8 | { 9 | public class LogMessage : ViewModelBase 10 | { 11 | private int progress; 12 | private long? fileSize; 13 | 14 | /// 15 | /// Gets or sets the type (file or directory). 16 | /// 17 | /// The type. 18 | public string Type { get; private set; } 19 | 20 | /// 21 | /// Gets or sets the action. 22 | /// 23 | /// The action. 24 | public string Action { get; private set; } 25 | 26 | /// 27 | /// Gets or sets the path of file A. 28 | /// 29 | /// The path of file A. 30 | public string SourcePath { get; private set; } 31 | 32 | /// 33 | /// Gets or sets the path of file B. 34 | /// 35 | /// The path of file B. 36 | public string TargetPath { get; private set; } 37 | 38 | /// 39 | /// Gets or sets the current progress of the file (0 - 100). 40 | /// 41 | /// The current progress of the file. 42 | public int Progress 43 | { 44 | get { return this.progress; } 45 | set 46 | { 47 | if (value < 0 || value > 100) 48 | throw new ArgumentOutOfRangeException("value", "Value must be between 0 and 100"); 49 | 50 | if (this.Progress != value) 51 | { 52 | this.progress = value; 53 | this.OnPropertyChanged(vm => vm.Progress); 54 | this.OnPropertyChanged(vm => vm.IsInProgress); 55 | this.OnPropertyChanged(vm => vm.Image); 56 | } 57 | } 58 | } 59 | 60 | /// 61 | /// Gets a value indicating whether the current file is in progress. 62 | /// 63 | /// true if the current file is in progress; otherwise, false. 64 | public bool IsInProgress 65 | { 66 | get { return this.Progress != 100; } 67 | } 68 | 69 | /// 70 | /// Gets the image for the log message. 71 | /// 72 | public ImageSource Image 73 | { 74 | get 75 | { 76 | if (IsInProgress && !IsErrorMessage) 77 | return null; 78 | 79 | const string successImagePath = "pack://application:,,,/FlagSync;component/Images/Success.png"; 80 | const string errorImagePath = "pack://application:,,,/FlagSync;component/Images/Error.png"; 81 | 82 | var logo = new BitmapImage(); 83 | 84 | logo.BeginInit(); 85 | logo.UriSource = new Uri(this.IsErrorMessage ? errorImagePath : successImagePath); 86 | logo.EndInit(); 87 | logo.Freeze(); 88 | 89 | return logo; 90 | } 91 | } 92 | 93 | /// 94 | /// Gets a value indicating whether the log message is a error message. 95 | /// 96 | /// 97 | /// true if the log message is a error message; otherwise, false. 98 | /// 99 | public bool IsErrorMessage { get; private set; } 100 | 101 | /// 102 | /// Gets the size of the file. 103 | /// 104 | /// 105 | /// The size of the file. 106 | /// 107 | public string FileSize 108 | { 109 | get 110 | { 111 | return this.fileSize.HasValue ? this.fileSize.Value.ToSizeString() : String.Empty; 112 | } 113 | } 114 | 115 | /// 116 | /// Initializes a new instance of the class. 117 | /// 118 | /// The type. 119 | /// The action. 120 | /// The source path. 121 | /// The target path. 122 | /// if set to true, the message is a error message. 123 | /// The size of the file. 124 | public LogMessage(string type, string action, string sourcePath, string targetPath, bool isErrorMessage, long? fileSize) 125 | { 126 | this.Type = type; 127 | this.Action = action; 128 | this.SourcePath = sourcePath; 129 | this.TargetPath = targetPath; 130 | this.IsErrorMessage = isErrorMessage; 131 | this.fileSize = fileSize; 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.InteropServices; 4 | using System.Windows; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("FlagSync")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("FlagSync")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | //In order to begin building localizable applications, set 24 | //CultureYouAreCodingWith in your .csproj file 25 | //inside a . For example, if you are using US english 26 | //in your source files, set the to en-US. Then uncomment 27 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 28 | //the line below to match the UICulture setting in the project file. 29 | 30 | [assembly: NeutralResourcesLanguage("en")] 31 | 32 | [assembly: ThemeInfo( 33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 34 | //(used if a resource is not found in the page, 35 | // or application resource dictionaries) 36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 37 | //(used if a resource is not found in the page, 38 | // app, or any theme specific resource dictionaries) 39 | )] 40 | 41 | // Version information for an assembly consists of the following four values: 42 | // 43 | // Major Version 44 | // Minor Version 45 | // Build Number 46 | // Revision 47 | // 48 | // You can specify all the values or you can default the Build and Revision Numbers 49 | // by using the '*' as shown below: 50 | // [assembly: AssemblyVersion("1.0.*")] 51 | [assembly: AssemblyVersion("2.4.2")] 52 | [assembly: AssemblyFileVersion("2.4.2")] -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Properties/Resources.de-DE.Designer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/FlagSync.View/Properties/Resources.de-DE.Designer.cs -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.239 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace FlagSync.View.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("en-US")] 29 | public global::System.Globalization.CultureInfo Language { 30 | get { 31 | return ((global::System.Globalization.CultureInfo)(this["Language"])); 32 | } 33 | set { 34 | this["Language"] = value; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | en-US 7 | 8 | 9 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/AboutBoxViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace FlagSync.View.ViewModels 4 | { 5 | public class AboutBoxViewModel 6 | { 7 | /// 8 | /// Gets the application version. 9 | /// 10 | /// The application version. 11 | public static string Version 12 | { 13 | get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(3); } 14 | } 15 | 16 | /// 17 | /// Gets the author of the application 18 | /// 19 | /// The author of the application. 20 | public static string Author 21 | { 22 | get { return "Dennis Daume"; } 23 | } 24 | 25 | /// 26 | /// Gets the title of the application. 27 | /// 28 | /// The title of the application. 29 | public static string Title 30 | { 31 | get { return "FlagSync"; } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/FtpFileSystemViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | using FlagSync.Data; 3 | using FlagSync.View.Views; 4 | using Rareform.Patterns.MVVM; 5 | 6 | namespace FlagSync.View.ViewModels 7 | { 8 | public class FtpFileSystemViewModel : ViewModelBase, IFileSystemViewModel 9 | { 10 | private readonly FtpFileSystemSetting setting; 11 | 12 | public string ServerAddress 13 | { 14 | get { return this.setting.Source; } 15 | set 16 | { 17 | if (this.setting.Source != value) 18 | { 19 | this.setting.Source = value; 20 | this.OnPropertyChanged(vm => vm.ServerAddress); 21 | } 22 | } 23 | } 24 | 25 | public string Username 26 | { 27 | get { return this.setting.Username; } 28 | set 29 | { 30 | if (this.setting.Username != value) 31 | { 32 | this.setting.Username = value; 33 | this.OnPropertyChanged(vm => vm.Username); 34 | } 35 | } 36 | } 37 | 38 | public string Password 39 | { 40 | get { return this.setting.Password; } 41 | set 42 | { 43 | if (this.setting.Password != value) 44 | { 45 | this.setting.Password = value; 46 | this.OnPropertyChanged(vm => vm.Password); 47 | } 48 | } 49 | } 50 | 51 | public FtpFileSystemViewModel(FtpFileSystemSetting setting) 52 | { 53 | this.setting = setting; 54 | } 55 | 56 | public UserControl CreateView() 57 | { 58 | return new FtpFileSystemPanel(this); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/IFileSystemViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace FlagSync.View.ViewModels 4 | { 5 | public interface IFileSystemViewModel 6 | { 7 | UserControl CreateView(); 8 | } 9 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/ITunesFileSystemViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Windows.Controls; 4 | using FlagSync.Data; 5 | using FlagSync.View.Views; 6 | using iTunesLib; 7 | using Rareform.Patterns.MVVM; 8 | 9 | namespace FlagSync.View.ViewModels 10 | { 11 | public class ITunesFileSystemViewModel : ViewModelBase, IFileSystemViewModel 12 | { 13 | private readonly ITunesFileSystemSetting setting; 14 | 15 | public string Playlist 16 | { 17 | get { return this.setting.Source; } 18 | set 19 | { 20 | if (this.setting.Source != value) 21 | { 22 | this.setting.Source = value; 23 | this.OnPropertyChanged(vm => vm.Playlist); 24 | } 25 | } 26 | } 27 | 28 | public static IEnumerable AvailablePlaylists 29 | { 30 | get 31 | { 32 | var iTunesApp = new iTunesApp(); 33 | 34 | return iTunesApp.LibrarySource.Playlists 35 | .Cast() 36 | .Where(pl => pl.Kind == ITPlaylistKind.ITPlaylistKindUser) 37 | .Select(pl => pl.Name) 38 | .OrderBy(name => name); 39 | } 40 | } 41 | 42 | public ITunesFileSystemViewModel(ITunesFileSystemSetting setting) 43 | { 44 | this.setting = setting; 45 | 46 | this.Playlist = this.setting.Source ?? AvailablePlaylists.First(); 47 | } 48 | 49 | public UserControl CreateView() 50 | { 51 | return new ITunesFileSystemPanel(this); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/JobCompositionViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Windows.Controls; 3 | using System.Windows.Input; 4 | using FlagSync.Data; 5 | using Rareform.Patterns.MVVM; 6 | 7 | namespace FlagSync.View.ViewModels 8 | { 9 | public class JobCompositionViewModel : ViewModelBase 10 | { 11 | private readonly JobSettingViewModel setting; 12 | private IFileSystemViewModel firstFileSystem; 13 | private IFileSystemViewModel secondFileSystem; 14 | 15 | public ObservableCollection CurrentFirstFileSystem { get; private set; } 16 | 17 | public ObservableCollection CurrentSecondFileSystem { get; private set; } 18 | 19 | public IFileSystemViewModel FirstFileSystem 20 | { 21 | set 22 | { 23 | this.firstFileSystem = value; 24 | 25 | this.CurrentFirstFileSystem.Clear(); 26 | this.CurrentFirstFileSystem.Add(this.firstFileSystem.CreateView()); 27 | } 28 | } 29 | 30 | public IFileSystemViewModel SecondFileSystem 31 | { 32 | set 33 | { 34 | this.secondFileSystem = value; 35 | 36 | this.CurrentSecondFileSystem.Clear(); 37 | this.CurrentSecondFileSystem.Add(this.secondFileSystem.CreateView()); 38 | } 39 | } 40 | 41 | public string Name 42 | { 43 | get { return this.setting.Name; } 44 | set 45 | { 46 | if (this.Name != value) 47 | { 48 | this.setting.Name = value; 49 | this.OnPropertyChanged(vm => vm.Name); 50 | } 51 | } 52 | } 53 | 54 | public bool IsBackup 55 | { 56 | get { return this.setting.SyncMode == SyncMode.Backup; } 57 | set 58 | { 59 | if (this.IsBackup != value) 60 | { 61 | this.setting.SyncMode = value ? SyncMode.Backup : SyncMode.Synchronization; 62 | 63 | this.OnPropertyChanged(vm => vm.IsBackup); 64 | } 65 | } 66 | } 67 | 68 | public bool IsSynchronization 69 | { 70 | get { return this.setting.SyncMode == SyncMode.Synchronization; } 71 | set 72 | { 73 | if (this.IsSynchronization != value) 74 | { 75 | this.setting.SyncMode = value ? SyncMode.Synchronization : SyncMode.Backup; 76 | 77 | this.OnPropertyChanged(vm => vm.IsSynchronization); 78 | } 79 | } 80 | } 81 | 82 | public ICommand CreateFirstFileSystemCommand 83 | { 84 | get 85 | { 86 | return new RelayCommand 87 | ( 88 | param => 89 | { 90 | var fileSystem = (string)param; 91 | 92 | switch (fileSystem) 93 | { 94 | case "Local": 95 | var localSetting = new LocalFileSystemSetting(); 96 | this.setting.FirstFileSystem = localSetting; 97 | this.FirstFileSystem = new LocalFileSystemViewModel(localSetting); 98 | break; 99 | 100 | case "Ftp": 101 | var ftpSetting = new FtpFileSystemSetting(); 102 | this.setting.FirstFileSystem = ftpSetting; 103 | this.FirstFileSystem = new FtpFileSystemViewModel(ftpSetting); 104 | break; 105 | 106 | case "iTunes": 107 | var iTunesSetting = new ITunesFileSystemSetting(); 108 | this.setting.FirstFileSystem = iTunesSetting; 109 | this.FirstFileSystem = new ITunesFileSystemViewModel(iTunesSetting); 110 | break; 111 | } 112 | } 113 | ); 114 | } 115 | } 116 | 117 | public ICommand CreateSecondFileSystemCommand 118 | { 119 | get 120 | { 121 | return new RelayCommand 122 | ( 123 | param => 124 | { 125 | var fileSystem = (string)param; 126 | 127 | switch (fileSystem) 128 | { 129 | case "Local": 130 | var localSetting = new LocalFileSystemSetting(); 131 | this.setting.SecondFileSystem = localSetting; 132 | this.SecondFileSystem = new LocalFileSystemViewModel(localSetting); 133 | break; 134 | 135 | case "Ftp": 136 | var ftpSetting = new FtpFileSystemSetting(); 137 | this.setting.SecondFileSystem = ftpSetting; 138 | this.SecondFileSystem = new FtpFileSystemViewModel(ftpSetting); 139 | break; 140 | } 141 | } 142 | ); 143 | } 144 | } 145 | 146 | public JobCompositionViewModel(JobSettingViewModel setting) 147 | { 148 | this.setting = setting; 149 | this.CurrentFirstFileSystem = new ObservableCollection(); 150 | this.CurrentSecondFileSystem = new ObservableCollection(); 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/JobSettingViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using FlagSync.Data; 4 | using FlagSync.View.Properties; 5 | using Rareform.Patterns.MVVM; 6 | 7 | namespace FlagSync.View.ViewModels 8 | { 9 | public class JobSettingViewModel : ViewModelBase, IDataErrorInfo 10 | { 11 | /// 12 | /// Gets or sets a value indicating whether this job is included syncing. 13 | /// 14 | /// 15 | /// true if this job is included for syncing; otherwise, false. 16 | /// 17 | public bool IsIncluded 18 | { 19 | get { return this.InternJobSetting.IsIncluded; } 20 | set 21 | { 22 | if (this.IsIncluded != value) 23 | { 24 | this.InternJobSetting.IsIncluded = value; 25 | this.OnPropertyChanged(vm => vm.IsIncluded); 26 | } 27 | } 28 | } 29 | 30 | public FileSystemSetting FirstFileSystem 31 | { 32 | get { return this.InternJobSetting.FirstFileSystemSetting; } 33 | set 34 | { 35 | if (this.FirstFileSystem != value) 36 | { 37 | this.InternJobSetting.FirstFileSystemSetting = value; 38 | this.OnPropertyChanged(vm => vm.FirstFileSystem); 39 | } 40 | } 41 | } 42 | 43 | public FileSystemSetting SecondFileSystem 44 | { 45 | get { return this.InternJobSetting.SecondFileSystemSetting; } 46 | set 47 | { 48 | if (this.SecondFileSystem != value) 49 | { 50 | this.InternJobSetting.SecondFileSystemSetting = value; 51 | this.OnPropertyChanged(vm => vm.SecondFileSystem); 52 | } 53 | } 54 | } 55 | 56 | public string Name 57 | { 58 | get { return this.InternJobSetting.Name; } 59 | set 60 | { 61 | if (this.Name != value) 62 | { 63 | this.InternJobSetting.Name = value; 64 | this.OnPropertyChanged(vm => vm.Name); 65 | } 66 | } 67 | } 68 | 69 | public SyncMode SyncMode 70 | { 71 | get { return this.InternJobSetting.SyncMode; } 72 | set 73 | { 74 | if (this.SyncMode != value) 75 | { 76 | this.InternJobSetting.SyncMode = value; 77 | this.OnPropertyChanged(vm => vm.SyncMode); 78 | this.OnPropertyChanged(vm => vm.SyncModeString); 79 | } 80 | } 81 | } 82 | 83 | /// 84 | /// Gets or sets the name. 85 | /// 86 | /// 87 | /// The name. 88 | /// 89 | public string SyncModeString 90 | { 91 | get 92 | { 93 | switch (this.SyncMode) 94 | { 95 | case SyncMode.Backup: 96 | return Resources.BackupString; 97 | 98 | case SyncMode.Synchronization: 99 | return Resources.SynchronizationString; 100 | } 101 | 102 | throw new InvalidOperationException(); 103 | } 104 | } 105 | 106 | /// 107 | /// Gets the intern job setting. 108 | /// 109 | /// The intern job setting. 110 | /// 111 | public JobSetting InternJobSetting { get; private set; } 112 | 113 | /// 114 | /// Initializes a new instance of the class. 115 | /// 116 | /// The name. 117 | /// 118 | public JobSettingViewModel(string name) 119 | : this(new JobSetting(name)) 120 | { 121 | } 122 | 123 | /// 124 | /// Initializes a new instance of the class. 125 | /// 126 | /// The intern job setting. 127 | /// 128 | public JobSettingViewModel(JobSetting internJobSetting) 129 | { 130 | this.InternJobSetting = internJobSetting; 131 | } 132 | 133 | public string this[string columnName] 134 | { 135 | get { throw new NotImplementedException(); } 136 | } 137 | 138 | public string Error 139 | { 140 | get { throw new NotImplementedException(); } 141 | } 142 | 143 | public bool HasErrors 144 | { 145 | get { return false; } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/JobViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FlagSync.Core; 3 | using FlagSync.View.Properties; 4 | 5 | namespace FlagSync.View.ViewModels 6 | { 7 | internal class JobViewModel 8 | { 9 | private readonly Job model; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The model. 15 | public JobViewModel(Job model) 16 | { 17 | this.model = model; 18 | } 19 | 20 | /// 21 | /// Gets the directory A. 22 | /// 23 | public string DirectoryA 24 | { 25 | get { return this.model.DirectoryA.FullName; } 26 | } 27 | 28 | /// 29 | /// Gets the directory B. 30 | /// 31 | public string DirectoryB 32 | { 33 | get { return this.model.DirectoryB.FullName; } 34 | } 35 | 36 | /// 37 | /// Gets the name. 38 | /// 39 | public string Name 40 | { 41 | get { return this.model.Name; } 42 | } 43 | 44 | /// 45 | /// Gets the sync mode string. 46 | /// 47 | public string SyncModeString 48 | { 49 | get 50 | { 51 | if (this.model is BackupJob) 52 | { 53 | return Resources.BackupString; 54 | } 55 | 56 | if (this.model is SyncJob) 57 | { 58 | return Resources.SynchronizationString; 59 | } 60 | 61 | throw new NotSupportedException("No such job."); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/ViewModels/LocalFileSystemViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | using FlagSync.Data; 3 | using FlagSync.View.Views; 4 | using Rareform.Patterns.MVVM; 5 | 6 | namespace FlagSync.View.ViewModels 7 | { 8 | public class LocalFileSystemViewModel : ViewModelBase, IFileSystemViewModel 9 | { 10 | private readonly LocalFileSystemSetting setting; 11 | 12 | public string Directory 13 | { 14 | get { return this.setting.Source; } 15 | set 16 | { 17 | if (this.setting.Source != value) 18 | { 19 | this.setting.Source = value; 20 | this.OnPropertyChanged(vm => vm.Directory); 21 | } 22 | } 23 | } 24 | 25 | public LocalFileSystemViewModel(LocalFileSystemSetting setting) 26 | { 27 | this.setting = setting; 28 | } 29 | 30 | public UserControl CreateView() 31 | { 32 | return new LocalFileSystemPanel(this); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/AboutBox.xaml: -------------------------------------------------------------------------------- 1 |  15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 67 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/AboutBox.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace FlagSync.View.Views 2 | { 3 | /// 4 | /// Interaction logic for AboutBox.xaml 5 | /// 6 | public sealed partial class AboutBox 7 | { 8 | public AboutBox() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/FtpFileSystemPanel.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 34 | 40 | 47 | 53 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/FtpFileSystemPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using FlagSync.View.ViewModels; 4 | 5 | namespace FlagSync.View.Views 6 | { 7 | /// 8 | /// Interaction logic for FtpFileSystemPanel.xaml 9 | /// 10 | public sealed partial class FtpFileSystemPanel 11 | { 12 | private readonly FtpFileSystemViewModel viewModel; 13 | 14 | public FtpFileSystemPanel(FtpFileSystemViewModel viewModel) 15 | { 16 | InitializeComponent(); 17 | 18 | this.viewModel = viewModel; 19 | this.DataContext = viewModel; 20 | } 21 | 22 | private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) 23 | { 24 | this.viewModel.Password = ((PasswordBox)sender).Password; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/ITunesFileSystemPanel.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/ITunesFileSystemPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using FlagSync.View.ViewModels; 2 | 3 | namespace FlagSync.View.Views 4 | { 5 | /// 6 | /// Interaction logic for ITunesFileSystemPanel.xaml 7 | /// 8 | public sealed partial class ITunesFileSystemPanel 9 | { 10 | private ITunesFileSystemViewModel viewModel; 11 | 12 | public ITunesFileSystemPanel(ITunesFileSystemViewModel viewModel) 13 | { 14 | InitializeComponent(); 15 | 16 | this.viewModel = viewModel; 17 | this.DataContext = viewModel; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/JobCompositionControl.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 28 | 32 | 36 | 51 | 67 | 83 | 84 | 87 | 88 | 91 | 97 | 102 | 106 | 122 | 138 | 139 | 142 | 143 | 146 | 151 | 155 | 156 | 160 | 163 | 167 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/JobCompositionControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using FlagSync.View.ViewModels; 2 | 3 | namespace FlagSync.View.Views 4 | { 5 | /// 6 | /// Interaction logic for JobCompositionControl.xaml 7 | /// 8 | public partial class JobCompositionControl 9 | { 10 | public JobCompositionControl(JobCompositionViewModel viewModel) 11 | { 12 | InitializeComponent(); 13 | 14 | this.DataContext = viewModel; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/LocalFileSystemPanel.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 14 | 15 | 16 | 17 | 18 | 29 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/LocalFileSystemPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using FlagSync.View.ViewModels; 3 | 4 | namespace FlagSync.View.Views 5 | { 6 | /// 7 | /// Interaction logic for LocalFileSystemPanel.xaml 8 | /// 9 | public sealed partial class LocalFileSystemPanel 10 | { 11 | private readonly LocalFileSystemViewModel viewModel; 12 | 13 | public LocalFileSystemPanel(LocalFileSystemViewModel viewModel) 14 | { 15 | InitializeComponent(); 16 | 17 | this.viewModel = viewModel; 18 | this.DataContext = viewModel; 19 | } 20 | 21 | private void directoryAButton_Click(object sender, RoutedEventArgs e) 22 | { 23 | string result = ShowFolderDialog(); 24 | 25 | if (result != null) 26 | { 27 | this.viewModel.Directory = result; 28 | } 29 | } 30 | 31 | private static string ShowFolderDialog() 32 | { 33 | string selectedFolder = null; 34 | 35 | using (var dialog = new System.Windows.Forms.FolderBrowserDialog()) 36 | { 37 | var result = dialog.ShowDialog(); 38 | 39 | if (result == System.Windows.Forms.DialogResult.OK) 40 | { 41 | selectedFolder = dialog.SelectedPath; 42 | } 43 | } 44 | 45 | return selectedFolder; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/Views/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using FlagSync.Data; 9 | using FlagSync.View.Properties; 10 | 11 | namespace FlagSync.View.Views 12 | { 13 | /// 14 | /// Interaction logic for MainWindow.xaml 15 | /// 16 | public sealed partial class MainWindow 17 | { 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public MainWindow() 22 | { 23 | Properties.Resources.Culture = Settings.Default.Language; 24 | InitializeComponent(); 25 | } 26 | 27 | private void Window_Loaded(object sender, RoutedEventArgs e) 28 | { 29 | string[] args = Environment.GetCommandLineArgs(); 30 | 31 | if (args.Length == 2) 32 | { 33 | this.WindowState = WindowState.Minimized; 34 | 35 | try 36 | { 37 | this.mainWindowViewModel.LoadJobSettings(args[1]); 38 | } 39 | 40 | catch (CorruptSaveFileException) 41 | { 42 | this.WindowState = WindowState.Maximized; 43 | 44 | MessageBox.Show 45 | ( 46 | Properties.Resources.LoadSettingsErrorMessage, 47 | Properties.Resources.ErrorString, 48 | MessageBoxButton.OK, 49 | MessageBoxImage.Error 50 | ); 51 | 52 | Application.Current.Shutdown(); 53 | } 54 | 55 | catch (ITunesNotOpenedException) 56 | { 57 | this.WindowState = WindowState.Maximized; 58 | 59 | ShowITunesErrorMessageBox(); 60 | 61 | Application.Current.Shutdown(); 62 | } 63 | 64 | this.mainWindowViewModel.StartJobWorkerCommand.Execute(false); 65 | } 66 | } 67 | 68 | private void loadJobsButton_Click(object sender, RoutedEventArgs e) 69 | { 70 | using (var dialog = new System.Windows.Forms.OpenFileDialog()) 71 | { 72 | dialog.Filter = "|*.xml"; 73 | dialog.InitialDirectory = DataController.AppDataFolderPath; 74 | dialog.Multiselect = false; 75 | 76 | dialog.FileOk += (dialogSender, dialogEventArgs) => 77 | { 78 | try 79 | { 80 | this.mainWindowViewModel.LoadJobSettings(dialog.FileName); 81 | } 82 | catch (CorruptSaveFileException) 83 | { 84 | MessageBox.Show 85 | ( 86 | Properties.Resources.LoadSettingsErrorMessage, 87 | Properties.Resources.ErrorString, 88 | MessageBoxButton.OK, 89 | MessageBoxImage.Error 90 | ); 91 | } 92 | 93 | catch (ITunesNotOpenedException) 94 | { 95 | ShowITunesErrorMessageBox(); 96 | } 97 | }; 98 | 99 | dialog.ShowDialog(); 100 | } 101 | } 102 | 103 | private void saveJobsButton_Click(object sender, RoutedEventArgs e) 104 | { 105 | using (var dialog = new System.Windows.Forms.SaveFileDialog()) 106 | { 107 | dialog.AddExtension = true; 108 | dialog.DefaultExt = ".xml"; 109 | dialog.FileName = "NewJobSettings"; 110 | dialog.InitialDirectory = DataController.AppDataFolderPath; 111 | 112 | dialog.FileOk += (dialogSender, dialogEventArgs) => 113 | this.mainWindowViewModel.SaveJobSettings(dialog.FileName); 114 | 115 | dialog.ShowDialog(); 116 | } 117 | } 118 | 119 | private void TextBox_TextChanged(object sender, TextChangedEventArgs e) 120 | { 121 | ((TextBox)sender).ScrollToEnd(); 122 | } 123 | 124 | private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e) 125 | { 126 | var messages = this.mainWindowViewModel.LogMessages; 127 | bool isPreview = this.mainWindowViewModel.IsPreview; 128 | bool isRunning = this.mainWindowViewModel.IsRunning; 129 | bool isPaused = this.mainWindowViewModel.IsPaused; 130 | 131 | if (!isPreview && messages.Any() && isRunning && !isPaused) 132 | { 133 | ((ListView)sender).ScrollIntoView(messages.Last()); 134 | } 135 | } 136 | 137 | private void englishMenuItem_Click(object sender, RoutedEventArgs e) 138 | { 139 | Settings.Default.Language = new CultureInfo("en-US"); 140 | Restart(); 141 | } 142 | 143 | private void germanMenuItem_Click(object sender, RoutedEventArgs e) 144 | { 145 | Settings.Default.Language = new CultureInfo("de-DE"); 146 | Restart(); 147 | } 148 | 149 | /// 150 | /// Restarts this instance. 151 | /// 152 | private static void Restart() 153 | { 154 | var result = MessageBox.Show( 155 | Properties.Resources.ApplicationRestartMessageBoxText, 156 | Properties.Resources.ApplicationRestartMessageBoxCaption, 157 | MessageBoxButton.YesNo, MessageBoxImage.Question); 158 | 159 | if (result == MessageBoxResult.Yes) 160 | { 161 | Application.Current.Shutdown(); 162 | Process.Start(System.Reflection.Assembly.GetEntryAssembly().Location); 163 | } 164 | } 165 | 166 | private void Window_Closing(object sender, CancelEventArgs e) 167 | { 168 | Settings.Default.Save(); 169 | } 170 | 171 | private void aboutMenuItem_Click(object sender, RoutedEventArgs e) 172 | { 173 | var aboutBox = new AboutBox(); 174 | aboutBox.ShowDialog(); 175 | } 176 | 177 | private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) 178 | { 179 | Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); 180 | e.Handled = true; 181 | } 182 | 183 | private static void ShowITunesErrorMessageBox() 184 | { 185 | MessageBox.Show 186 | ( 187 | Properties.Resources.iTunesErrorMessageBoxText, 188 | Properties.Resources.iTunesErrorMessageBoxCaption, 189 | MessageBoxButton.OK, 190 | MessageBoxImage.Error 191 | ); 192 | } 193 | } 194 | } -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | en-US 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.View/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /FlagSync/FlagSync.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlagSync.Core", "FlagSync.Core\FlagSync.Core.csproj", "{1149F3C5-DBFE-4CFD-98F6-DB396343E647}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlagSync.View", "FlagSync.View\FlagSync.View.csproj", "{91E37F1B-FE0F-456F-8F67-4058A854FDF8}" 7 | EndProject 8 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FlagSync.Setup", "FlagSync.Setup\FlagSync.Setup.vdproj", "{F1E3BF8E-9B77-404F-ADB2-FC2F8CFFB577}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlagSync.Data", "FlagSync.Data\FlagSync.Data.csproj", "{080FB9A0-A2F9-438F-8F84-60B7FB448633}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3E98AE14-9CE5-4194-A0F1-D23ED830E6E0}" 13 | ProjectSection(SolutionItems) = preProject 14 | ..\Changelog.txt = ..\Changelog.txt 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(TestCaseManagementSettings) = postSolution 19 | CategoryFile = FlagSync.vsmdi 20 | EndGlobalSection 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|x86 = Debug|x86 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647}.Debug|x86.ActiveCfg = Debug|x86 27 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647}.Debug|x86.Build.0 = Debug|x86 28 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647}.Release|x86.ActiveCfg = Release|x86 29 | {1149F3C5-DBFE-4CFD-98F6-DB396343E647}.Release|x86.Build.0 = Release|x86 30 | {91E37F1B-FE0F-456F-8F67-4058A854FDF8}.Debug|x86.ActiveCfg = Debug|x86 31 | {91E37F1B-FE0F-456F-8F67-4058A854FDF8}.Debug|x86.Build.0 = Debug|x86 32 | {91E37F1B-FE0F-456F-8F67-4058A854FDF8}.Release|x86.ActiveCfg = Release|x86 33 | {91E37F1B-FE0F-456F-8F67-4058A854FDF8}.Release|x86.Build.0 = Release|x86 34 | {F1E3BF8E-9B77-404F-ADB2-FC2F8CFFB577}.Debug|x86.ActiveCfg = Debug 35 | {F1E3BF8E-9B77-404F-ADB2-FC2F8CFFB577}.Release|x86.ActiveCfg = Release 36 | {F1E3BF8E-9B77-404F-ADB2-FC2F8CFFB577}.Release|x86.Build.0 = Release 37 | {080FB9A0-A2F9-438F-8F84-60B7FB448633}.Debug|x86.ActiveCfg = Debug|x86 38 | {080FB9A0-A2F9-438F-8F84-60B7FB448633}.Debug|x86.Build.0 = Debug|x86 39 | {080FB9A0-A2F9-438F-8F84-60B7FB448633}.Release|x86.ActiveCfg = Release|x86 40 | {080FB9A0-A2F9-438F-8F84-60B7FB448633}.Release|x86.Build.0 = Release|x86 41 | EndGlobalSection 42 | GlobalSection(SolutionProperties) = preSolution 43 | HideSolutionNode = FALSE 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /FlagSync/packages/FlagFtp.0.1.2/FlagFtp.0.1.2.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/FlagFtp.0.1.2/FlagFtp.0.1.2.nupkg -------------------------------------------------------------------------------- /FlagSync/packages/FlagFtp.0.1.2/lib/FlagFtp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/FlagFtp.0.1.2/lib/FlagFtp.dll -------------------------------------------------------------------------------- /FlagSync/packages/MahApps.Metro.0.8.0.0/MahApps.Metro.0.8.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/MahApps.Metro.0.8.0.0/MahApps.Metro.0.8.0.0.nupkg -------------------------------------------------------------------------------- /FlagSync/packages/MahApps.Metro.0.8.0.0/lib/net40/MahApps.Metro.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/MahApps.Metro.0.8.0.0/lib/net40/MahApps.Metro.dll -------------------------------------------------------------------------------- /FlagSync/packages/MahApps.Metro.0.8.0.0/lib/net40/System.Windows.Interactivity.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/MahApps.Metro.0.8.0.0/lib/net40/System.Windows.Interactivity.dll -------------------------------------------------------------------------------- /FlagSync/packages/MahApps.Metro.0.8.0.0/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($rootPath, $toolsPath, $package, $project) 2 | 3 | $project.DTE.ItemOperations.Navigate('http://mahapps.com/MahApps.Metro/') -------------------------------------------------------------------------------- /FlagSync/packages/Rareform.1.2.0/Rareform.1.2.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/Rareform.1.2.0/Rareform.1.2.0.nupkg -------------------------------------------------------------------------------- /FlagSync/packages/Rareform.1.2.0/lib/Rareform.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/FlagSync/packages/Rareform.1.2.0/lib/Rareform.dll -------------------------------------------------------------------------------- /FlagSync/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Releases/1.0.0/FlagSync-1.0.0.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.0.0/FlagSync-1.0.0.exe -------------------------------------------------------------------------------- /Releases/1.1.0/FlagSync-1.1.0.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.1.0/FlagSync-1.1.0.exe -------------------------------------------------------------------------------- /Releases/1.2.0/FlagSync-1.2.0.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.2.0/FlagSync-1.2.0.rar -------------------------------------------------------------------------------- /Releases/1.2.1/FlagSync-1.2.1.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.2.1/FlagSync-1.2.1.rar -------------------------------------------------------------------------------- /Releases/1.3.0/FlagSync-1.3.0.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.3.0/FlagSync-1.3.0.rar -------------------------------------------------------------------------------- /Releases/1.3.1/FlagSync-1.3.1.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.3.1/FlagSync-1.3.1.rar -------------------------------------------------------------------------------- /Releases/1.3.2/FlagSync-1.3.2.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.3.2/FlagSync-1.3.2.rar -------------------------------------------------------------------------------- /Releases/1.3.3/FlagSync-1.3.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/1.3.3/FlagSync-1.3.3.zip -------------------------------------------------------------------------------- /Releases/2.0.0/FlagSync-2.0.0-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.0.0/FlagSync-2.0.0-portable.rar -------------------------------------------------------------------------------- /Releases/2.0.0/FlagSync-2.0.0.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.0.0/FlagSync-2.0.0.rar -------------------------------------------------------------------------------- /Releases/2.1.0/FlagSync-2.1.0-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.0/FlagSync-2.1.0-portable.rar -------------------------------------------------------------------------------- /Releases/2.1.0/FlagSync-2.1.0.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.0/FlagSync-2.1.0.rar -------------------------------------------------------------------------------- /Releases/2.1.1/FlagSync-2.1.1-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.1/FlagSync-2.1.1-portable.rar -------------------------------------------------------------------------------- /Releases/2.1.1/FlagSync-2.1.1.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.1/FlagSync-2.1.1.rar -------------------------------------------------------------------------------- /Releases/2.1.2/FlagSync-2.1.2-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.2/FlagSync-2.1.2-portable.rar -------------------------------------------------------------------------------- /Releases/2.1.2/FlagSync-2.1.2.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.2/FlagSync-2.1.2.rar -------------------------------------------------------------------------------- /Releases/2.1.3/FlagSync-2.1.3-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.3/FlagSync-2.1.3-portable.rar -------------------------------------------------------------------------------- /Releases/2.1.3/FlagSync-2.1.3.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.1.3/FlagSync-2.1.3.rar -------------------------------------------------------------------------------- /Releases/2.2.0/FlagSync-2.2.0-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.2.0/FlagSync-2.2.0-portable.rar -------------------------------------------------------------------------------- /Releases/2.2.0/FlagSync-2.2.0.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.2.0/FlagSync-2.2.0.rar -------------------------------------------------------------------------------- /Releases/2.2.1/FlagSync-2.2.1-portable.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.2.1/FlagSync-2.2.1-portable.rar -------------------------------------------------------------------------------- /Releases/2.2.1/FlagSync-2.2.1.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.2.1/FlagSync-2.2.1.rar -------------------------------------------------------------------------------- /Releases/2.3.0/FlagSync-2.3.0-portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.3.0/FlagSync-2.3.0-portable.zip -------------------------------------------------------------------------------- /Releases/2.3.0/FlagSync-2.3.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.3.0/FlagSync-2.3.0.zip -------------------------------------------------------------------------------- /Releases/2.3.1/FlagSync-2.3.1-portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.3.1/FlagSync-2.3.1-portable.zip -------------------------------------------------------------------------------- /Releases/2.3.1/FlagSync-2.3.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.3.1/FlagSync-2.3.1.zip -------------------------------------------------------------------------------- /Releases/2.4.0/FlagSync-2.4.0-portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.0/FlagSync-2.4.0-portable.zip -------------------------------------------------------------------------------- /Releases/2.4.0/FlagSync-2.4.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.0/FlagSync-2.4.0.zip -------------------------------------------------------------------------------- /Releases/2.4.1/FlagSync-2.4.1-portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.1/FlagSync-2.4.1-portable.zip -------------------------------------------------------------------------------- /Releases/2.4.1/FlagSync-2.4.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.1/FlagSync-2.4.1.zip -------------------------------------------------------------------------------- /Releases/2.4.2/FlagSync-2.4.2-portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.2/FlagSync-2.4.2-portable.zip -------------------------------------------------------------------------------- /Releases/2.4.2/FlagSync-2.4.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flagbug/FlagSync/e1bab60d085de0685773c593ee77f7f9a5c3324c/Releases/2.4.2/FlagSync-2.4.2.zip -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # FlagSync 2 | 3 | ## Overview 4 | 5 | FlagSync is a synchronization and backup tool, that allows you to synchronize or backup your files 6 | with local folders (or an external hard- or flashdrive) or an FTP-Server, as well as synchronize your non-iPod MP3-Player with iTunes. 7 | 8 | ## Features 9 | 10 | - **Backup & Synchronization:** Make a backup to your external harddrive, or synchronize your USB-Stick with your computer. 11 | - **FTP:** Backup your data to an FTP-server or synchronize the files on the server with your PC. 12 | - **iTunes:** You use iTunes but don't have an iPod? FlagSync synchronizes your MP3-Player with iTunes! 13 | - **Batch jobs:** Create an infinite amount of jobs that can be started with one click. 14 | - **Multi-Language:** FlagSync is available in English and German. 15 | - **Portable:** FlagSync is fully portable, but a version for installation is also available. 16 | 17 | ## Media 18 | 19 | - [Addictive Tips][1] - *Aug 19 2011* 20 | 21 | ## Screenshot 22 | 23 | ***Local backup*** 24 | ![Local backup][2] 25 | 26 | ***iTunes sync*** 27 | ![iTunes sync][3] 28 | 29 | ***FTP backup*** 30 | ![FTP backup][4] 31 | 32 | [1]: http://www.addictivetips.com/windows-tips/sync-itunes-with-portable-media-player-backup-data-on-ftp-usb-flagsync 33 | [2]: http://flagbug.github.com/flagsync/local-backup.jpg 34 | [3]: http://flagbug.github.com/flagsync/iTunes-sync.JPG 35 | [4]: http://flagbug.github.com/flagsync/ftp-backup.jpg 36 | --------------------------------------------------------------------------------