Revision 8f44fd3a

b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
219 219

  
220 220
        public void SelectiveSyncFolders()
221 221
        {
222
            var monitor = Shell.Monitors[CurrentAccount.AccountKey];
222
            //var monitor = Shell.Monitors[CurrentAccount.AccountKey];
223 223
            
224 224

  
225
            var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount.Account);
225
            var model = new SelectiveSynchViewModel(/*monitor,*/_events,CurrentAccount.Account,CurrentAccount.ApiKey);
226 226
            if (_windowManager.ShowDialog(model) == true)
227 227
            {
228 228
                
b/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs
163 163
            get
164 164
            {
165 165
                if (ObjectInfo != null)
166
                    return ObjectInfo.Name;
166
                    return ObjectInfo.Name.Split('/').Last();
167 167
                return _displayName;
168 168
            }
169 169
            set { _displayName = value; }
170 170
        }
171 171

  
172
        public bool IsExplicitlyChecked
173
        {
174
            set { _isChecked=value; }
175
        }
176

  
172 177
        public DirectoryRecord(ObjectInfo info)
173 178
        {
174 179
            ObjectInfo = info;
b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs
49 49
using Pithos.Client.WPF.Utils;
50 50
using Pithos.Core;
51 51
using Pithos.Interfaces;
52
using Pithos.Network;
52 53

  
53 54
namespace Pithos.Client.WPF.SelectiveSynch
54 55
{
......
66 67
        }
67 68

  
68 69
        private ObservableCollection<ObjectInfo> _checks;
69
        private readonly PithosMonitor _monitor;
70
        //private readonly PithosMonitor _monitor;
70 71
        private bool _isBusy=true;
72
        private string _apiKey;
71 73

  
72 74
        public ObservableCollection<ObjectInfo> Checks
73 75
        {
......
84 86
            NotifyOfPropertyChange(() => Checks);
85 87
        }
86 88

  
87
        public SelectiveSynchViewModel(PithosMonitor monitor, IEventAggregator events, AccountSettings account)
89
        public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey)
88 90
        {
89 91
            Account = account;
90 92
            AccountName = account.AccountName;
91 93
            DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName);
92
            _monitor = monitor;
94
            //_monitor = monitor;
93 95
            _events = events;
96
            _apiKey = apiKey;
94 97
            TaskEx.Run(LoadRootNode);
95 98
        }
96 99

  
97 100
        private void LoadRootNode()
98
        {
99
            var client = _monitor.CloudClient;
101
        {            
102
            //TODO: Check this
103
            var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};
104
            client.Authenticate();
105
            
100 106

  
101
            var dirs = from container in client.ListContainers(_monitor.UserName)                       
107
            var dirs = from container in client.ListContainers(AccountName)                       
102 108
                       select new DirectoryRecord
103 109
                                  {
104 110
                                      DisplayName = container.Name,
105 111
                                      Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)),
106
                                      Directories = (from dir in client.ListObjects(_monitor.UserName, container.Name)                                                     
112
                                      Directories = (from dir in client.ListObjects(AccountName, container.Name)                                                     
107 113
                                                     where dir.IsDirectory
108 114
                                                     select dir).ToTree()
109 115
                                  };
......
173 179
                           from DirectoryRecord record in rootRecord
174 180
                           select record).ToList();
175 181

  
182
            allNodes.Apply(record => record.IsChecked = false);
183

  
176 184
            if (selections.Count == 0)
177 185
            {
178
                allNodes.Apply(record => record.IsChecked = false);
186
            //    allNodes.Apply(record => record.IsChecked = false);
179 187
                return;
180 188
            } 
181 189
            
182 190
            var selects = (from DirectoryRecord rootRecord in RootNodes
183 191
                          from DirectoryRecord record in rootRecord
184
                          where record.Uri !=null &&  !selections.Contains(record.Uri.ToString())
192
                          where record.Uri !=null &&  selections.Contains(record.Uri.ToString())
185 193
                          select record).ToList();
186
            var shouldBeChecked = allNodes.Except(selects).ToList();
194
            //var shouldBeChecked = allNodes.Except(selects).ToList();
187 195

  
188
            selects.Apply(record=>record.IsChecked=false);
196
            selects.Apply(record=>record.IsExplicitlyChecked=true);
189 197

  
190
            shouldBeChecked.Apply(record => record.IsChecked = true);
198
            //shouldBeChecked.Apply(record => record.IsChecked = true);
191 199
            
192 200
            
193 201

  
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
957 957
		#region Event Handlers
958 958
		
959 959
		public void Handle(SelectiveSynchChanges message)
960
		{            
961
			PithosMonitor monitor;
962
			if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
963
			{
964
				monitor.SetSelectivePaths(message.Uris,message.Added,message.Removed);
960
        {
961
            PithosMonitor monitor;
962
            if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
963
            {
964
                monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed);
965 965

  
966
			}
966
            }
967 967

  
968
		    var account = Accounts.First(acc => acc.AccountKey == message.Account.AccountKey);
969
		    this._pollAgent.SetSelectivePaths(account, message.Added, message.Removed);
970
            
968
            var account = Accounts.FirstOrDefault(acc => acc.AccountKey == message.Account.AccountKey);
969
            if (account!=null)
970
            {
971
                this._pollAgent.SetSelectivePaths(account, message.Added, message.Removed);
972
            }
971 973

  
972
		}
974

  
975
        }
973 976

  
974 977

  
975 978
		private bool _pollStarted;
b/trunk/Pithos.Client.WPF/Utils/EnumerableExtensions.cs
85 85
            foreach (var item in orderedItems)
86 86
            {
87 87
                var path = item.Uri.ToString();
88
                var newNode = new DirectoryRecord{ DisplayName=item.Name,ObjectInfo=item};
88
                var newNode = new DirectoryRecord{ DisplayName=item.Name.Split('/').Last(),ObjectInfo=item};
89 89
                lookups[path] = newNode;
90 90

  
91 91
                var lastIndex = path.LastIndexOf("/", StringComparison.Ordinal);
b/trunk/Pithos.Core/Agents/CloudTransferAction.cs
139 139
            var capitalizedFileInfo = fileInfo.WithProperCapitalization();
140 140
            var fullLocalName = capitalizedFileInfo.FullName;
141 141
            var othersPath = Path.Combine(accountInfo.AccountPath, FolderConstants.OthersFolder);
142
            
142

  
143
            ObjectInfo objectInfo;
144

  
143 145
            var isShared = fullLocalName.StartsWith(othersPath, StringComparison.InvariantCultureIgnoreCase);
144 146
            if (isShared)
145 147
            {                
......
147 149
                var otherParts = pathRelativeToOther.Split('\\');
148 150
                var otherName = otherParts[0];
149 151
                var otherContainer = otherParts[1];
150
                return new ObjectInfo
152
                objectInfo=new ObjectInfo
151 153
                           {
152 154
                               Account = otherName, 
153 155
                               Container = otherContainer, 
154 156
                               Name = String.Join("/", otherParts.Splice(2))
155 157
                           };
156 158
            }
157
            return new ObjectInfo(accountInfo.AccountPath, accountInfo.UserName, fileInfo);
159
            else
160
                objectInfo=new ObjectInfo(accountInfo.AccountPath, accountInfo.UserName, fileInfo);
161
            
162
            objectInfo.Content_Type= (fileInfo is DirectoryInfo)
163
                                    ?   "appication/directory"
164
                                    :   "application/octet-stream";
165
            return objectInfo;
158 166
        }
159 167
    }    
160 168

  
......
178 186

  
179 187
        public override string ToString()
180 188
        {
181
            return String.Format("{0}: _ <- {1}", this.Action, this.CloudFile.Name);
189
            return String.Format("{0}: _ <- {1}", Action, CloudFile.Name);
182 190
        }
183 191
        
184 192
    }
b/trunk/Pithos.Core/Agents/CollectionExtensions.cs
168 168
            //the target is not below the root
169 169
            //DON'T FORGET that Uri segments include the slashes. Must remove them to ensure proper checks
170 170
            var mismatch = rootSegments
171
                .Where((t, i) => !String.Equals(targetSegments[i].TrimEnd('/'), t.TrimEnd('/')))
171
                .Where((t, i) => !String.Equals(targetSegments[i].TrimEnd('/'), t.TrimEnd('/'),StringComparison.InvariantCultureIgnoreCase))
172 172
                .Any();
173 173
            return !mismatch;
174 174
        }
b/trunk/Pithos.Core/Agents/Downloader.cs
99 99
                                    DownloadWithBlocks(accountInfo, client, cloudFile, relativeUrl, localPath,
100 100
                                                       serverHash);
101 101

  
102
                            if (cloudFile.AllowedTo == "read")
102
                            if (!cloudFile.IsWritable(accountInfo.UserName))
103 103
                            {
104 104
                                var attributes = File.GetAttributes(localPath);
105 105
                                File.SetAttributes(localPath, attributes | FileAttributes.ReadOnly);
b/trunk/Pithos.Core/Agents/StatusAgent.cs
346 346
                        command.Parameters.AddWithValue("path", path);
347 347
                        
348 348
                        var affected = command.ExecuteNonQuery();
349
                        if (affected == 0)
350
                        {
351
                            var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path));
352
                            createdState.FileStatus = status;
353
                            _persistenceAgent.Post(createdState.Create);
354
                        }
349 355
                        return affected;
350 356
                    }
351 357
                }
......
379 385
                        command.Parameters.AddWithValue("overlayStatus", overlayStatus);
380 386
                        
381 387
                        var affected = command.ExecuteNonQuery();
388
                        if (affected == 0)
389
                        {
390
                            var createdState=FileState.CreateFor(FileInfoExtensions.FromPath(absolutePath));
391
                            createdState.FileStatus = fileStatus;
392
                            createdState.OverlayStatus = overlayStatus;
393
                            _persistenceAgent.Post(createdState.Create);  
394
                        }
382 395
                        return affected;
383 396
                    }
384 397
                }
b/trunk/Pithos.Core/Agents/Uploader.cs
47 47
                        return;
48 48
                    }
49 49

  
50
                    var latestState = action.FileState;
51

  
50 52
                    //Do not upload files in conflict
51
                    if (action.FileState.FileStatus == FileStatus.Conflict)
53
                    if (latestState.FileStatus == FileStatus.Conflict)
52 54
                    {
53 55
                        Log.InfoFormat("Skipping file in conflict [{0}]", fileInfo.FullName);
54 56
                        return;
55 57
                    }
56 58
                    //Do not upload files when we have no permission
57
                    if (action.FileState.FileStatus == FileStatus.Forbidden)
59
                    if (latestState.FileStatus == FileStatus.Forbidden)
58 60
                    {
59 61
                        Log.InfoFormat("Skipping forbidden file [{0}]", fileInfo.FullName);
60 62
                        return;
......
85 87
                            var cloudInfo = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);
86 88

  
87 89
                            //If this is a read-only file, do not upload changes
88
                            if (cloudInfo.AllowedTo == "read")
90
                            if (!cloudInfo.IsWritable(action.AccountInfo.UserName))
89 91
                                return;
90 92

  
91 93
                            if (fileInfo is DirectoryInfo)
......
139 141
                            if (response.StatusCode == HttpStatusCode.Forbidden)
140 142
                            {
141 143
                                StatusKeeper.SetFileState(fileInfo.FullName, FileStatus.Forbidden, FileOverlayStatus.Conflict, "Forbidden");
144
                                
142 145
                            }
143 146
                            else
144 147
                                //In any other case, propagate the error
b/trunk/Pithos.Core/Agents/WorkflowAgent.cs
73 73
        [System.ComponentModel.Composition.Import]
74 74
        public IPithosSettings Settings { get; set; }
75 75

  
76
        private List<string> _selectivePaths = new List<string>();
77
        public List<string> SelectivePaths
78
        {
79
            get { return _selectivePaths; }
80
            set { _selectivePaths = value; }
81
        }
76 82

  
77 83
        public WorkflowAgent()
78 84
        {
......
245 251
                var pendingStates = pendingEntries
246 252
                    .Select(state => new WorkflowState(account, state))
247 253
                    .ToList();
248

  
254
                
255
                                
249 256
                if (Log.IsDebugEnabled)
250 257
                    Log.DebugFormat("Found {0} interrupted files", pendingStates.Count);
251 258

  
......
266 273
                return;*/
267 274
            //TODO: Need to handle folder renames            
268 275

  
276
            //If there are selective sync paths defined
277
            if (SelectivePaths.Count > 0
278
                //And the target file is not below any of the selective paths
279
                && !SelectivePaths.Any(workflowState.Path.IsAtOrDirectlyBelow))
280
            //abort the post
281
            {
282
                Log.InfoFormat("File skipped, not under a selected folder [{0}] ",workflowState.Path);
283
                return;
284
            }
285

  
286

  
269 287
            Debug.Assert(workflowState.Path.StartsWith(workflowState.AccountInfo.AccountPath, StringComparison.InvariantCultureIgnoreCase), "File from wrong account posted");
270 288

  
271 289
            _agent.Post(workflowState);
b/trunk/Pithos.Core/PithosMonitor.cs
193 193
            }
194 194
            _cancellationSource = new CancellationTokenSource();
195 195

  
196

  
197
            CloudClient = new CloudFilesClient(UserName, ApiKey)
198
                              {UsePithos = true, AuthenticationUrl = AuthenticationUrl};
199

  
200

  
201
            _accountInfo = CloudClient.Authenticate();            
196
            lock (this)
197
            {
198
                CloudClient = new CloudFilesClient(UserName, ApiKey)
199
                                  {UsePithos = true, AuthenticationUrl = AuthenticationUrl};
200
                _accountInfo = CloudClient.Authenticate();
201
            }
202 202
            _accountInfo.SiteUri = AuthenticationUrl;
203 203
            _accountInfo.AccountPath = RootPath;
204 204

  
......
432 432
            var selectivePaths = UrisToFilePaths(uris);
433 433
            
434 434
            FileAgent.SelectivePaths=selectivePaths;
435
            WorkflowAgent.SelectivePaths = selectivePaths;
435 436
            PollAgent.SetSyncUris(_accountInfo.AccountKey,uris);
436 437
            
437 438
            var removedPaths = UrisToFilePaths(removed);
b/trunk/Pithos.Interfaces/ObjectInfo.cs
328 328
                   && (this.Name == null || other.Name.StartsWith(this.Name));
329 329
        }
330 330

  
331
        public bool IsWritable(string account)
332
        {
333
            //If the Allowed To header has no value, try to determine the Share permissions
334
            if (AllowedTo == null)
335
            {
336
                //If this file has no permissions defined, we can probably write it
337
                //This case should occur only when the info comes from a listing of the user's own files
338
                if (Permissions == null || Permissions.Count == 0)
339
                    return true;
340
                string perms;
341

  
342
                //Do we have an explicit write share to this account?
343
                return Permissions.TryGetValue(account, out perms) 
344
                    && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
345
                
346
            }
347
            //Otherwise return the permissions specified by AllowedTo
348
            return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
349
        }
331 350

  
332 351
        public ObjectInfo Previous { get; private set; }
333 352

  
......
335 354
        {
336 355
            get
337 356
            {
357
                if (Content_Type == null)
358
                    return false;
338 359
                if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
339 360
                    return true;
340 361
                if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
b/trunk/Pithos.Network/RestClient.cs
107 107
            : base()
108 108
        {
109 109
            if (other==null)
110
                Log.ErrorFormat("[ERROR] No parameters provided to the rest client. \n{0}\n", other);
111
                //throw new ArgumentNullException("other");
110
                //Log.ErrorFormat("[ERROR] No parameters provided to the rest client. \n{0}\n", other);
111
                throw new ArgumentNullException("other");
112 112
            Contract.EndContractBlock();
113 113

  
114 114
            //The maximum error response must be large because missing server hashes are return as a Conflivt (409) error response

Also available in: Unified diff