Revision 43dd02a8

b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
125 125
	    private readonly PollAgent _pollAgent;
126 126
	    private readonly NetworkAgent _networkAgent;
127 127

  
128
	    [Import]
129
	    public Selectives Selectives { get; set; }
128 130

  
129 131
	    private MiniStatusViewModel _miniStatus;
130 132

  
......
318 320

  
319 321
			    MigrateFolders(account);
320 322

  
323
			    Selectives.SetIsSelectiveEnabled(account.AccountKey, account.SelectiveSyncEnabled);
324

  
321 325
				if (Monitors.TryGetValue(account.AccountKey, out monitor))
322 326
				{
323 327
					//If the account is active
......
1012 1016
		        PithosMonitor monitor;
1013 1017
		        if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
1014 1018
		        {
1015
                    monitor.Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled);
1019
                    Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled);
1016 1020
		            monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed);
1017 1021
		        }
1018 1022

  
b/trunk/Pithos.Core.Test/LocalFileComparerTest.cs
16 16
        {
17 17
            var comparer = new LocalFileComparer();
18 18
            var account = new AccountInfo();
19
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"});
20
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" });
19
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"},null);
20
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" }, null);
21 21
            Assert.That(comparer.Equals(x, y), Is.True);
22 22
        }
23 23

  
......
26 26
        {
27 27
            var comparer = new LocalFileComparer();
28 28
            var account = new AccountInfo();
29
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"});
30
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a" });
29
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" }, null);
30
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a" }, null);
31 31
            Assert.That(comparer.Equals(x, y), Is.True);
32 32
        }
33 33
        [Test]
......
35 35
        {
36 36
            var comparer = new LocalFileComparer();
37 37
            var account = new AccountInfo();
38
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a",Content_Type = "application/directory"});
39
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a", Content_Type = "application/directory" });
38
            var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a",Content_Type = "application/directory"},null);
39
            var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a", Content_Type = "application/directory" }, null);
40 40
            Assert.That(comparer.Equals(x, y), Is.False);
41 41
        }
42 42

  
b/trunk/Pithos.Core/Agents/CloudTransferAction.cs
61 61

  
62 62
    public class CloudAction
63 63
    {
64

  
65
        public object Originator { get; set; }
64 66
        public AccountInfo AccountInfo { get; set; }
65 67
        public CloudActionType Action { get; set; }
66 68
        public FileSystemInfo LocalFile { get; set; }
......
86 88
            get { return  CloudFile!=null && AccountInfo.UserName != CloudFile.Account; }
87 89
        }
88 90

  
89
        protected CloudAction(AccountInfo accountInfo,CloudActionType action)
91
        protected CloudAction(AccountInfo accountInfo,CloudActionType action,object originator)
90 92
        {
91 93
            if (accountInfo==null)
92 94
                throw new ArgumentNullException("accountInfo");
......
94 96

  
95 97
            Action = action;
96 98
            AccountInfo = accountInfo;
99
            Originator = originator;
97 100
        }
98 101

  
99
        public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm)
100
            : this(accountInfo,action)
102
        public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm,object originator)
103
            : this(accountInfo,action,originator)
101 104
        {
102 105
            if(blockSize<=0)
103 106
                throw new ArgumentOutOfRangeException("blockSize");
......
168 171

  
169 172
    public class CloudDownloadAction:CloudAction
170 173
    {
171
        public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile)
172
            :base(accountInfo,CloudActionType.DownloadUnconditional)
174
        public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile,object originator)
175
            :base(accountInfo,CloudActionType.DownloadUnconditional,originator)
173 176
        {            
174 177
            if (String.IsNullOrWhiteSpace(cloudFile.Container))
175 178
                throw new ArgumentException("CloudFile.Container","cloudFile");
......
192 195
    }
193 196
    public class CloudDeleteAction:CloudAction
194 197
    {
195
        public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState)
196
            : this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState)
198
        public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState,object originator)
199
            : this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState,originator)
197 200
        {            
198 201
        }
199 202

  
200
        public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState) 
201
            : base(accountInfo,CloudActionType.DeleteCloud)
203
        public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState,object originator) 
204
            : base(accountInfo,CloudActionType.DeleteCloud,originator)
202 205
        {
203 206
            CloudFile = cloudFile;
204 207
            LocalFile = fileInfo;
......
206 209
        }
207 210

  
208 211
        public CloudDeleteAction(CloudAction action)
209
            : this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState)
212
            : this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState,action)
210 213
        {}
211 214

  
212 215
        [ContractInvariantMethod]
......
224 227

  
225 228
    public class CloudUploadAction:CloudAction
226 229
    {
227
        public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm)
228
            : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm)             
230
        public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm,object originator)
231
            : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm,originator)             
229 232
        {
230 233
        }
231 234

  
......
243 246

  
244 247
        public FileSystemInfo OldLocalFile { get; set; }
245 248

  
246
        public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile)
247
            :base(accountInfo,action)
249
        public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile,object originator)
250
            :base(accountInfo,action,originator)
248 251
        {
249 252
            LocalFile = newFile;
250 253
            CloudFile = CreateObjectInfoFor(accountInfo, newFile);
b/trunk/Pithos.Core/Agents/Downloader.cs
184 184
                if (!localHashes.ContainsKey(upHash))
185 185
                {
186 186
                    StatusNotification.Notify(new CloudNotification { Data = cloudFile });
187
                    ReportDownloadProgress(Path.GetFileName(localPath), i, upHashes.Length, cloudFile.Bytes);
187 188

  
188 189
                    if (blockUpdater.UseOrphan(i, upHash))
189 190
                    {
......
244 245
            var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
245 246
            StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Downloading {0}", Path.GetFileName(localPath)));
246 247
            StatusNotification.Notify(new CloudNotification { Data = cloudFile });
248
            ReportDownloadProgress(Path.GetFileName(localPath), 1, 1, cloudFile.Bytes);
247 249

  
248 250
            var fileAgent = GetFileAgent(accountInfo);
249 251
            //Calculate the relative file path for the new file
b/trunk/Pithos.Core/Agents/FileAgent.cs
94 94
                    if (change.ChangeType == WatcherChangeTypes.Renamed)
95 95
                    {
96 96
                        var rename = (MovedEventArgs) change;
97
                        _agent.Post(new WorkflowState
97
                        _agent.Post(new WorkflowState(change)
98 98
                                        {
99 99
                                            AccountInfo = AccountInfo,
100 100
                                            OldPath = rename.OldFullPath,
......
105 105
                                        });
106 106
                    }
107 107
                    else
108
                        _agent.Post(new WorkflowState
108
                        _agent.Post(new WorkflowState(change)
109 109
                        {
110 110
                            AccountInfo = AccountInfo,
111 111
                            Path = change.FullPath,
b/trunk/Pithos.Core/Agents/PollAgent.cs
507 507

  
508 508
                        yield return new CloudAction(accountInfo, CloudActionType.MustSynch,
509 509
                                                     localFile, objectInfo, state, accountInfo.BlockSize,
510
                                                     accountInfo.BlockHash);
510
                                                     accountInfo.BlockHash,"Poll Changes");
511 511
                    }
512 512
                }
513 513
                else
514 514
                {
515 515
                    //Remote files should be downloaded
516
                    yield return new CloudDownloadAction(accountInfo, objectInfo);
516
                    yield return new CloudDownloadAction(accountInfo, objectInfo,"Poll Changes");
517 517
                }
518 518
            }
519 519
        }
......
548 548
                        //For each moved object we need to move both the local file and update                                                
549 549
                        yield return new CloudAction(accountInfo, CloudActionType.RenameLocal,
550 550
                                                     previousFile, objectInfo, state, accountInfo.BlockSize,
551
                                                     accountInfo.BlockHash);
551
                                                     accountInfo.BlockHash,"Poll Moves");
552 552
                        //For modified files, we need to download the changes as well
553 553
                        if (objectInfo.Hash!=objectInfo.PreviousHash)
554
                            yield return new CloudDownloadAction(accountInfo,objectInfo);
554
                            yield return new CloudDownloadAction(accountInfo,objectInfo, "Poll Moves");
555 555
                    }
556 556
                }
557 557
                //If the previous file does not exist, we need to download it in the new location
558 558
                else
559 559
                {
560 560
                    //Remote files should be downloaded
561
                    yield return new CloudDownloadAction(accountInfo, objectInfo);
561
                    yield return new CloudDownloadAction(accountInfo, objectInfo, "Poll Moves");
562 562
                }
563 563
            }
564 564
        }
......
593 593
                    var state = StatusKeeper.GetStateByFilePath(localFile.WithProperCapitalization().FullName);
594 594
                    yield return new CloudAction(accountInfo, CloudActionType.MustSynch,
595 595
                                                     localFile, objectInfo, state, accountInfo.BlockSize,
596
                                                     accountInfo.BlockHash);                    
596
                                                     accountInfo.BlockHash,"Poll Creates");                    
597 597
                }
598 598
                else
599 599
                {
600 600
                    //Remote files should be downloaded
601
                    yield return new CloudDownloadAction(accountInfo, objectInfo);
601
                    yield return new CloudDownloadAction(accountInfo, objectInfo,"Poll Creates");
602 602
                }
603 603

  
604 604
            }
b/trunk/Pithos.Core/Agents/Uploader.cs
7 7
using System.Linq;
8 8
using System.Net;
9 9
using System.Reflection;
10
using System.Security.Cryptography;
10 11
using System.Threading;
11 12
using System.Threading.Tasks;
12 13
using Pithos.Interfaces;
......
144 145
                                    topHash = treeHash.TopHash.ToHashString();
145 146
                                }
146 147

  
148

  
149

  
147 150
                                //If the file hashes match, abort the upload
148
                                if (cloudInfo != ObjectInfo.Empty && topHash == cloudHash)
151
                                if (cloudInfo != ObjectInfo.Empty && (topHash == cloudHash ))
149 152
                                {
150 153
                                    //but store any metadata changes 
151 154
                                    StatusKeeper.StoreInfo(fullFileName, cloudInfo);
b/trunk/Pithos.Core/Agents/WorkflowAgent.cs
134 134
                            case FileStatus.Modified:
135 135
                                NetworkAgent.Post(new CloudUploadAction(accountInfo, info, fileState,
136 136
                                                                        accountInfo.BlockSize,
137
                                                                        accountInfo.BlockHash));
137
                                                                        accountInfo.BlockHash,state));
138 138
                                break;
139 139
                            case FileStatus.Deleted:
140 140
                                DeleteChildObjects(state, fileState);
141
                                NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState));
141
                                NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState,state));
142 142
                                break;
143 143
                            case FileStatus.Renamed:
144 144
                                if (state.OldPath == null)
......
156 156
                                                             : new FileInfo(state.Path);
157 157
                                NetworkAgent.Post(new CloudMoveAction(accountInfo, CloudActionType.RenameCloud,
158 158
                                                                      oldInfo,
159
                                                                      newInfo));                                
159
                                                                      newInfo,state));                                
160 160
                                //TODO: Do I have to move children as well or will Pithos handle this?
161 161
                               //Need to find all children of the OLD filepath
162 162
                                //MoveChildObjects(state);
......
185 185
                    var childInfo = child.IsFolder
186 186
                                        ? (FileSystemInfo) new DirectoryInfo(child.FilePath)
187 187
                                        : new FileInfo(child.FilePath);
188
                    NetworkAgent.Post(new CloudDeleteAction(state.AccountInfo, childInfo, child));
188
                    NetworkAgent.Post(new CloudDeleteAction(state.AccountInfo, childInfo, child,state));
189 189
                }
190 190
            }
191 191
        }
b/trunk/Pithos.Core/WorkflowState.cs
52 52
{
53 53
    public class WorkflowState
54 54
    {
55
        public object Originator { get; set; }
55 56
        public AccountInfo AccountInfo { get; set; }
56 57

  
57 58
        public string Path { get; set; }
......
76 77
        }
77 78
*/
78 79

  
79
        public WorkflowState()
80
        public WorkflowState(object originator)
80 81
        {
81
            
82
            Originator = originator;
82 83
        }
83 84

  
84 85
        public WorkflowState(AccountInfo accountInfo, FileState state)
......
89 90
                throw new ArgumentNullException("state");
90 91
            Contract.EndContractBlock();
91 92

  
93
            Originator = "Restart";
92 94
            AccountInfo = accountInfo;
93 95
            Path = state.FilePath.ToLower();
94 96
            FileName = System.IO.Path.GetFileName(state.FilePath).ToLower();
b/trunk/Pithos.Interfaces/ObjectInfo.cs
57 57
    {
58 58
        private readonly List<string> _knownContainers= new List<string>{"trash"};
59 59
        public string Name { get; set; }
60
        
61
        
60

  
61
        public string ETag { get; set; }
62

  
62 63
        public string Hash { get; set; }
63 64

  
64 65
        public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
b/trunk/Pithos.Network/CloudFilesClient.cs
788 788
                                                   Account = account,
789 789
                                                   Container = container,
790 790
                                                   Name = objectName,
791
                                                   Hash = client.GetHeaderValue("ETag"),
791
                                                   ETag = client.GetHeaderValue("ETag"),
792
                                                   X_Object_Hash = client.GetHeaderValue("X-Object-Hash"),
792 793
                                                   Content_Type = client.GetHeaderValue("Content-Type"),
793 794
                                                   Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length",true)),
794 795
                                                   Tags = tags,
b/trunk/Pithos.Network/Signature.cs
204 204
                {
205 205
                    Bytes = length,
206 206
                    BlockSize = blockSize,
207
                    Hashes = list
207
                    Hashes = list,
208 208
                };
209 209

  
210
                string fileHash;
211
                var hasher = HashAlgorithm.Create("MD5");
212
                stream.Position = 0;
213
                treeHash.MD5= hasher.ComputeHash(stream).ToHashString();
214

  
210 215
                return treeHash;
211 216
            }
212 217
        }
b/trunk/Pithos.Network/TreeHash.cs
172 172
            }
173 173
        }
174 174

  
175
        public string MD5 { get; set; }
176

  
175 177
        //Saves the Json representation to a file
176 178
        public async Task Save(string filePath)
177 179
        {

Also available in: Unified diff