Use user catalog in sync
[pithos-macos] / pithos-macos / PithosUtilities.m
index 151ddb7..d48928a 100644 (file)
@@ -2,7 +2,7 @@
 //  PithosUtilities.m
 //  pithos-macos
 //
-// Copyright 2011 GRNET S.A. All rights reserved.
+// Copyright 2011-2012 GRNET S.A. All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or
 // without modification, are permitted provided that the following
@@ -36,6 +36,8 @@
 // or implied, of GRNET S.A.
 
 #import "PithosUtilities.h"
+#import "ASINetworkQueue.h"
+#import "ASIPithos.h"
 #import "ASIPithosContainerRequest.h"
 #import "ASIPithosObjectRequest.h"
 #import "ASIPithosObject.h"
 #pragma mark -
 #pragma mark Download
 
-+ (ASIPithosObjectRequest *)objectDataRequestWithContainerName:(NSString *)containerName 
-                                                    objectName:(NSString *)objectName 
-                                                   toDirectory:(NSString *)directoryPath 
-                                                 checkIfExists:(BOOL)ifExists 
-                                                sharingAccount:(NSString *)sharingAccount {
-    NSString *fileName = [objectName lastPathComponent];
-    if([objectName hasSuffix:@"/"])
-        fileName = [fileName stringByAppendingString:@"/"];    
++ (ASIPithosObjectRequest *)objectDataRequestWithPithos:(ASIPithos *)pithos 
+                                          containerName:(NSString *)containerName 
+                                             objectName:(NSString *)objectName 
+                                                version:(NSString *)version 
+                                            toDirectory:(NSString *)directoryPath 
+                                        withNewFileName:(NSString *)newFileName 
+                                          checkIfExists:(BOOL)ifExists 
+                                         sharingAccount:(NSString *)sharingAccount {
+    NSString *fileName;
+    if (newFileName) {
+        fileName = [NSString stringWithString:newFileName];
+    } else {
+        fileName = [objectName lastPathComponent];
+        if ([objectName hasSuffix:@"/"])
+            fileName = [fileName stringByAppendingString:@"/"];    
+    }
     fileName = [fileName stringByReplacingOccurrencesOfString:@"/" withString:@":"];
     
     NSFileManager *fileManager = [NSFileManager defaultManager];
     
     NSString *destinationPath = [directoryPath stringByAppendingPathComponent:fileName];
     if (ifExists && [fileManager fileExistsAtPath:destinationPath]) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"File Exists"];
-        [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", fileName]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert addButtonWithTitle:@"Cancel"];
-        NSInteger choice = [alert runModal];
+        __block NSInteger choice;
+        dispatch_sync(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"File Exists"];
+            [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", fileName]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert addButtonWithTitle:@"Cancel"];
+            choice = [alert runModal];
+        });
         if (choice == NSAlertSecondButtonReturn)
             return nil;
     }
         [fileManager removeItemAtPath:directoryPath error:&error];
     }
     if (error) {
-        NSLog(@"Cannot remove existing file '%@': %@", fileName, error);
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"Removal Error"];
-        [alert setInformativeText:[NSString stringWithFormat:@"Cannot remove existing file '%@': %@", fileName, error]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert runModal];
+        DLog(@"Cannot remove existing file '%@': %@", fileName, error);
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Removal Error"];
+            [alert setInformativeText:[NSString stringWithFormat:@"Cannot remove existing file '%@': %@", 
+                                       fileName, [error localizedDescription]]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        });
         return nil;
     }
 
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectDataRequestWithContainerName:containerName 
-                                                                                            objectName:objectName];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectDataRequestWithPithos:pithos 
+                                                                                  containerName:containerName 
+                                                                                     objectName:objectName 
+                                                                                        version:version];
     if (sharingAccount)
-        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     objectRequest.downloadDestinationPath = destinationPath;
     objectRequest.allowResumeForFileDownloads = YES;
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
     return objectRequest;
 }
 
-+ (NSArray *)objectDataRequestsForSubdirWithContainerName:(NSString *)containerName 
-                                               objectName:(NSString *)objectName 
-                                              toDirectory:(NSString *)directoryPath 
-                                            checkIfExists:(BOOL)ifExists 
-                                           sharingAccount:(NSString *)sharingAccount {
++ (NSArray *)objectDataRequestsForSubdirWithPithos:(ASIPithos *)pithos 
+                                     containerName:(NSString *)containerName 
+                                        objectName:(NSString *)objectName 
+                                       toDirectory:(NSString *)directoryPath 
+                                     checkIfExists:(BOOL)ifExists 
+                                    sharingAccount:(NSString *)sharingAccount {
     NSString *subdirName = [objectName lastPathComponent];
     NSString *destinationPath = [directoryPath stringByAppendingPathComponent:subdirName];
     if (ifExists && [[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"File exists"];
-        [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", subdirName]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert addButtonWithTitle:@"Cancel"];
-        NSInteger choice = [alert runModal];
+        __block NSInteger choice;
+        dispatch_sync(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"File exists"];
+            [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", subdirName]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert addButtonWithTitle:@"Cancel"];
+            choice = [alert runModal];
+        });
         if (choice == NSAlertSecondButtonReturn)
             return nil;
     }
     
-    NSArray *objects = [self objectsForSubdirWithContainerName:containerName objectName:objectName 
-                                                     delimiter:nil sharingAccount:sharingAccount];
+    NSArray *objects = [self objectsForSubdirWithPithos:pithos containerName:containerName objectName:objectName 
+                                              delimiter:nil sharingAccount:sharingAccount];
     if (objects == nil)
         return nil;
     
     NSError *error = nil;
     [fileManager createDirectoryAtPath:[directoryPath stringByAppendingPathComponent:subdirName] withIntermediateDirectories:YES attributes:nil error:&error];
     if (error) {
-        NSLog(@"Cannot create directory at '%@': %@", directoryPath, error);
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"Create Directory Error"];
-        [alert setInformativeText:[NSString stringWithFormat:@"Cannot create directory at '%@': %@", 
-                                   directoryPath, error]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert runModal];
+        DLog(@"Cannot create directory at '%@': %@", directoryPath, error);
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Create Directory Error"];
+            [alert setInformativeText:[NSString stringWithFormat:@"Cannot create directory at '%@': %@", 
+                                       directoryPath, [error localizedDescription]]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        });
     }
     
     for (ASIPithosObject *object in objects) {
-        if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
+        if ([self isContentTypeDirectory:object.contentType]) {
             NSString *subdirDirectoryPath = [directoryPath stringByAppendingPathComponent:subdirName];
             subdirDirectoryPath = [subdirDirectoryPath stringByAppendingPathComponent:[object.name substringFromIndex:subdirPrefixLength]];
             
             if (!directoryExists) {
                 [fileManager createDirectoryAtPath:subdirDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error];
                 if (error) {
-                    NSLog(@"Cannot create directory at '%@': %@", subdirDirectoryPath, error);
-                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-                    [alert setMessageText:@"Create Directory Error"];
-                    [alert setInformativeText:[NSString stringWithFormat:@"Cannot create directory at '%@': %@", 
-                                               subdirDirectoryPath, error]];
-                    [alert addButtonWithTitle:@"OK"];
-                    [alert runModal];
+                    DLog(@"Cannot create directory at '%@': %@", subdirDirectoryPath, error);
+                    dispatch_async(dispatch_get_main_queue(), ^{
+                        NSAlert *alert = [[NSAlert alloc] init];
+                        [alert setMessageText:@"Create Directory Error"];
+                        [alert setInformativeText:[NSString stringWithFormat:@"Cannot create directory at '%@': %@", 
+                                                   subdirDirectoryPath, [error localizedDescription]]];
+                        [alert addButtonWithTitle:@"OK"];
+                        [alert runModal];
+                    });
                 }
             } else if (!directoryIsDirectory) {
                 [fileManager removeItemAtPath:subdirDirectoryPath error:&error];
                 if (error) {
-                    NSLog(@"Cannot remove existing file at '%@': %@", subdirDirectoryPath, error);
-                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-                    [alert setMessageText:@"Remove File Error"];
-                    [alert setInformativeText:[NSString stringWithFormat:@"Cannot remove existing file at '%@': %@", 
-                                               subdirDirectoryPath, error]];
-                    [alert addButtonWithTitle:@"OK"];
-                    [alert runModal];
+                    DLog(@"Cannot remove existing file at '%@': %@", subdirDirectoryPath, error);
+                    dispatch_async(dispatch_get_main_queue(), ^{
+                        NSAlert *alert = [[NSAlert alloc] init];
+                        [alert setMessageText:@"Remove File Error"];
+                        [alert setInformativeText:[NSString stringWithFormat:@"Cannot remove existing file at '%@': %@", 
+                                                   subdirDirectoryPath, [error localizedDescription]]];
+                        [alert addButtonWithTitle:@"OK"];
+                        [alert runModal];
+                    });
                 }
             }
         } else {
             NSString *objectDirectoryPath = [directoryPath stringByAppendingPathComponent:subdirName];
             objectDirectoryPath = [objectDirectoryPath stringByAppendingPathComponent:[object.name substringWithRange:NSMakeRange(subdirPrefixLength, [object.name length] - subdirPrefixLength - [fileName length])]];
             
-            ASIPithosObjectRequest *objectRequest = [self objectDataRequestWithContainerName:containerName 
-                                                                                  objectName:object.name 
-                                                                                 toDirectory:objectDirectoryPath 
-                                                                               checkIfExists:NO 
-                                                                              sharingAccount:sharingAccount];
+            ASIPithosObjectRequest *objectRequest = [self objectDataRequestWithPithos:pithos 
+                                                                        containerName:containerName 
+                                                                           objectName:object.name 
+                                                                              version:nil 
+                                                                          toDirectory:objectDirectoryPath 
+                                                                      withNewFileName:nil 
+                                                                        checkIfExists:NO 
+                                                                       sharingAccount:sharingAccount];
             [(NSMutableDictionary *)objectRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:object.bytes] forKey:@"bytes"];
             [objectRequests addObject:objectRequest];
         }
 #pragma mark -
 #pragma mark Download Block
 
-+ (ASIPithosObjectRequest *)objectBlockDataRequestWithContainerName:(NSString *)containerName 
-                                                             object:(ASIPithosObject *)object 
-                                                         blockIndex:(NSUInteger)blockIndex 
-                                                          blockSize:(NSUInteger)blockSize {
++ (ASIPithosObjectRequest *)objectBlockDataRequestWithPithos:(ASIPithos *)pithos 
+                                               containerName:(NSString *)containerName 
+                                                      object:(ASIPithosObject *)object 
+                                                  blockIndex:(NSUInteger)blockIndex 
+                                                   blockSize:(NSUInteger)blockSize {
     NSUInteger rangeStart = blockIndex * blockSize;
     NSUInteger rangeEnd = (rangeStart + blockSize <= object.bytes) ? (rangeStart + blockSize - 1) : (object.bytes - 1);
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectDataRequestWithContainerName:containerName
-                                                                                            objectName:object.name
-                                                                                               version:nil
-                                                                                                 range:[NSString stringWithFormat:@"bytes=%lu-%lu", rangeStart, rangeEnd]
-                                                                                               ifMatch:object.hash];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectDataRequestWithPithos:pithos 
+                                                                                  containerName:containerName
+                                                                                     objectName:object.name
+                                                                                        version:nil
+                                                                                          range:[NSString stringWithFormat:@"bytes=%lu-%lu", rangeStart, rangeEnd]
+                                                                                        ifMatch:object.hash];
     return objectRequest;
 }
 
 #pragma mark -
 #pragma mark Upload
 
-+ (ASIPithosObjectRequest *)writeObjectDataRequestWithContainerName:(NSString *)containerName
-                                                         objectName:(NSString *)objectName
-                                                        contentType:(NSString *)contentType 
-                                                          blockSize:(NSUInteger)blockSize 
-                                                          blockHash:(NSString *)blockHash 
-                                                            forFile:(NSString *)filePath 
-                                                      checkIfExists:(BOOL)ifExists 
-                                                             hashes:(NSArray **)hashes 
-                                                     sharingAccount:(NSString *)sharingAccount {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:containerName objectName:objectName 
-                                                 sharingAccount:(NSString *)sharingAccount])
++ (ASIPithosObjectRequest *)writeObjectDataRequestWithPithos:(ASIPithos *)pithos 
+                                               containerName:(NSString *)containerName
+                                                  objectName:(NSString *)objectName
+                                                 contentType:(NSString *)contentType 
+                                                   blockSize:(NSUInteger)blockSize 
+                                                   blockHash:(NSString *)blockHash 
+                                                     forFile:(NSString *)filePath 
+                                               checkIfExists:(BOOL)ifExists 
+                                                      hashes:(NSArray **)hashes 
+                                              sharingAccount:(NSString *)sharingAccount {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:containerName objectName:objectName 
+                                          sharingAccount:(NSString *)sharingAccount])
         return nil;
     
     if (*hashes == nil)
     if ([filePath hasSuffix:@"/"])
         fileName = [fileName stringByAppendingString:@"/"];
     NSUInteger bytes = [self bytesOfFile:filePath];
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName 
-                                                                                                 objectName:objectName 
-                                                                                                contentType:contentType 
-                                                                                            contentEncoding:nil 
-                                                                                         contentDisposition:nil 
-                                                                                                   manifest:nil 
-                                                                                                    sharing:nil 
-                                                                                                   isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                                   metadata:nil
-                                                                                                  blockSize:blockSize
-                                                                                                  blockHash:blockHash 
-                                                                                                     hashes:*hashes 
-                                                                                                      bytes:bytes];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos 
+                                                                                       containerName:containerName 
+                                                                                          objectName:objectName 
+                                                                                         contentType:contentType 
+                                                                                     contentEncoding:nil 
+                                                                                  contentDisposition:nil 
+                                                                                            manifest:nil 
+                                                                                             sharing:nil 
+                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                            metadata:nil
+                                                                                           blockSize:blockSize
+                                                                                           blockHash:blockHash 
+                                                                                              hashes:*hashes 
+                                                                                               bytes:bytes];
     if (sharingAccount) 
-        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                               fileName, @"fileName", 
                               [NSNumber numberWithUnsignedInteger:bytes], @"bytes", 
     return objectRequest;
 }
 
-+ (NSIndexSet *)missingBlocksForHashes:(NSArray *)hashes withMissingHashesResponse:(NSString *)missingHashesResponse {
-    NSArray *responseLines = [missingHashesResponse componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
++ (NSIndexSet *)missingBlocksForHashes:(NSArray *)hashes withMissingHashes:(NSArray *)missingHashes {
     NSMutableIndexSet *missingBlocks = [NSMutableIndexSet indexSet];
-    for (NSString *line in responseLines) {
-        if (![line length])
+    for (NSString *missingHash in missingHashes) {
+        if (![missingHash length])
             break;
-        NSUInteger missingBlock = [hashes indexOfObject:line];
+        NSUInteger missingBlock = [hashes indexOfObject:missingHash];
         if (missingBlock != NSNotFound)
             [missingBlocks addIndex:missingBlock];
     }
     return missingBlocks;
 }
 
-+ (ASIPithosContainerRequest *)updateContainerDataRequestWithContainerName:(NSString *)containerName 
-                                                                 blockSize:(NSUInteger)blockSize 
-                                                                   forFile:(NSString *)filePath 
-                                                                    hashes:(NSArray *)hashes 
-                                                     missingHashesResponse:(NSString *)missingHashesResponse 
-                                                            sharingAccount:(NSString *)sharingAccount {
-    NSIndexSet *missingBlocks = [self missingBlocksForHashes:hashes withMissingHashesResponse:missingHashesResponse];
++ (ASIPithosContainerRequest *)updateContainerDataRequestWithPithos:(ASIPithos *)pithos 
+                                                      containerName:(NSString *)containerName 
+                                                          blockSize:(NSUInteger)blockSize 
+                                                            forFile:(NSString *)filePath 
+                                                             hashes:(NSArray *)hashes 
+                                                      missingHashes:(NSArray *)missingHashes 
+                                                     sharingAccount:(NSString *)sharingAccount {
+    NSIndexSet *missingBlocks = [self missingBlocksForHashes:hashes withMissingHashes:missingHashes];
     
     NSFileManager *fileManager = [NSFileManager defaultManager];
     NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
     strcpy(tempFileNameCString, tempFileTemplateCString);
     int fileDescriptor = mkstemp(tempFileNameCString);
     NSString *tempFilePath = [fileManager stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
+    free(tempFileNameCString);
     if (fileDescriptor == -1) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"Create Temporary File Error"];
-        [alert setInformativeText:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", tempFilePath]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert runModal];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Create Temporary File Error"];
+            [alert setInformativeText:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", tempFilePath]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        });
         return nil;
     }
-    free(tempFileNameCString);
     NSFileHandle *tempFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileDescriptor closeOnDealloc:YES];
 
     [missingBlocks enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
     [tempFileHandle closeFile];
     [fileHandle closeFile];
 
-    ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest updateContainerDataRequestWithContainerName:containerName 
-                                                                                                                  policy:nil 
-                                                                                                                metadata:nil 
-                                                                                                                  update:YES 
-                                                                                                                    file:tempFilePath];
+    ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest updateContainerDataRequestWithPithos:pithos 
+                                                                                                    containerName:containerName 
+                                                                                                           policy:nil 
+                                                                                                         metadata:nil 
+                                                                                                           update:YES 
+                                                                                                             file:tempFilePath];
     if (sharingAccount)
-        [containerRequest setRequestUserFromDefaultTo:sharingAccount];
+        [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     return containerRequest;
 }
 
-+ (ASIPithosContainerRequest *)updateContainerDataRequestWithContainerName:(NSString *)containerName 
-                                                                 blockSize:(NSUInteger)blockSize 
-                                                                   forFile:(NSString *)filePath 
-                                                         missingBlockIndex:(NSUInteger)missingBlockIndex 
-                                                            sharingAccount:(NSString *)sharingAccount {
++ (ASIPithosContainerRequest *)updateContainerDataRequestWithPithos:(ASIPithos *)pithos 
+                                                      containerName:(NSString *)containerName 
+                                                          blockSize:(NSUInteger)blockSize 
+                                                            forFile:(NSString *)filePath 
+                                                  missingBlockIndex:(NSUInteger)missingBlockIndex 
+                                                     sharingAccount:(NSString *)sharingAccount {
     NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
     [fileHandle seekToFileOffset:(missingBlockIndex *blockSize)];
     NSData *blockData = [fileHandle readDataOfLength:blockSize];
     [fileHandle closeFile];
-    ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest updateContainerDataRequestWithContainerName:containerName 
-                                                                                                                  policy:nil 
-                                                                                                                metadata:nil 
-                                                                                                                  update:YES 
-                                                                                                                    data:blockData];
+    ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest updateContainerDataRequestWithPithos:pithos 
+                                                                                                    containerName:containerName 
+                                                                                                           policy:nil 
+                                                                                                         metadata:nil 
+                                                                                                           update:YES 
+                                                                                                             data:blockData];
     if (sharingAccount)
-        [containerRequest setRequestUserFromDefaultTo:sharingAccount];
+        [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     return containerRequest;
 }
 
-+ (NSArray *)writeObjectDataRequestsWithContainerName:(NSString *)containerName
-                                           objectName:(NSString *)objectName
-                                            blockSize:(NSUInteger)blockSize 
-                                            blockHash:(NSString *)blockHash 
-                                         forDirectory:(NSString *)directoryPath 
-                                        checkIfExists:(BOOL)ifExists 
-                                          objectNames:(NSMutableArray **)objectNames
-                                         contentTypes:(NSMutableArray **)contentTypes
-                                            filePaths:(NSMutableArray **)filePaths 
-                                         hashesArrays:(NSMutableArray **)hashesArrays 
-                              directoryObjectRequests:(NSMutableArray **) directoryObjectRequests 
-                                       sharingAccount:(NSString *)sharingAccount {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:containerName objectName:objectName sharingAccount:sharingAccount])
++ (NSArray *)writeObjectDataRequestsWithPithos:(ASIPithos *)pithos 
+                                 containerName:(NSString *)containerName
+                                    objectName:(NSString *)objectName
+                                     blockSize:(NSUInteger)blockSize 
+                                     blockHash:(NSString *)blockHash 
+                                  forDirectory:(NSString *)directoryPath 
+                                 checkIfExists:(BOOL)ifExists 
+                                   objectNames:(NSMutableArray **)objectNames
+                                  contentTypes:(NSMutableArray **)contentTypes
+                                     filePaths:(NSMutableArray **)filePaths 
+                                  hashesArrays:(NSMutableArray **)hashesArrays 
+                       directoryObjectRequests:(NSMutableArray **) directoryObjectRequests 
+                                sharingAccount:(NSString *)sharingAccount {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:containerName objectName:objectName 
+                                          sharingAccount:sharingAccount])
         return nil;
 
     NSFileManager *fileManager = [NSFileManager defaultManager];
     NSError *error = nil;
     NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:directoryPath error:&error];
     if (error) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        [alert setMessageText:@"Directory Read Error"];
-        [alert setInformativeText:[NSString stringWithFormat:@"Cannot read contents of directory '%@': %@", 
-                                   [directoryPath lastPathComponent], error]];
-        [alert addButtonWithTitle:@"OK"];
-        [alert runModal];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Directory Read Error"];
+            [alert setInformativeText:[NSString stringWithFormat:@"Cannot read contents of directory '%@': %@", 
+                                       [directoryPath lastPathComponent], [error localizedDescription]]];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        });
         return nil;
     }
     
     *directoryObjectRequests = [NSMutableArray arrayWithCapacity:[subPaths count]];
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName 
-                                                                                                 objectName:objectName 
-                                                                                                       eTag:nil 
-                                                                                                contentType:@"application/directory" 
-                                                                                            contentEncoding:nil 
-                                                                                         contentDisposition:nil 
-                                                                                                   manifest:nil 
-                                                                                                    sharing:nil 
-                                                                                                   isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                                   metadata:nil 
-                                                                                                       data:[NSData data]];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos 
+                                                                                       containerName:containerName 
+                                                                                          objectName:objectName 
+                                                                                                eTag:nil 
+                                                                                         contentType:@"application/directory" 
+                                                                                     contentEncoding:nil 
+                                                                                  contentDisposition:nil 
+                                                                                            manifest:nil 
+                                                                                             sharing:nil 
+                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                            metadata:nil 
+                                                                                                data:[NSData data]];
     if (sharingAccount)
-        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                               [directoryPath lastPathComponent], @"fileName", 
                               nil];
             if (!isDirectory) {
                 hashes = [HashMapHash objectHashMapStrings:filePath withBlockHash:blockHash andBlockSize:blockSize];
                 if (hashes) {
-                    subObjectName = [objectName stringByAppendingPathComponent:objectNameSuffix];
+                    subObjectName = [[objectName stringByAppendingPathComponent:objectNameSuffix] precomposedStringWithCanonicalMapping];
                     fileName = [filePath lastPathComponent];
                     if ([filePath hasSuffix:@"/"])
                         fileName = [fileName stringByAppendingString:@"/"];
                     contentType = [self contentTypeOfFile:filePath error:&error];
                     if (contentType == nil)
                         contentType = @"application/octet-stream";
+                    #if DEBUG_PITHOS
                     if (error)
-                        NSLog(@"contentType detection error: %@", error);
-                    objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName 
-                                                                                         objectName:subObjectName 
-                                                                                        contentType:contentType 
-                                                                                    contentEncoding:nil 
-                                                                                 contentDisposition:nil 
-                                                                                           manifest:nil 
-                                                                                            sharing:nil 
-                                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                           metadata:nil
-                                                                                          blockSize:blockSize
-                                                                                          blockHash:blockHash 
-                                                                                             hashes:hashes 
-                                                                                              bytes:bytes];
+                        DLog(@"contentType detection error: %@", error);
+                    #endif
+                    objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos 
+                                                                               containerName:containerName 
+                                                                                  objectName:subObjectName 
+                                                                                 contentType:contentType 
+                                                                             contentEncoding:nil 
+                                                                          contentDisposition:nil 
+                                                                                    manifest:nil 
+                                                                                     sharing:nil 
+                                                                                    isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                    metadata:nil
+                                                                                   blockSize:blockSize
+                                                                                   blockHash:blockHash 
+                                                                                      hashes:hashes 
+                                                                                       bytes:bytes];
                     if (sharingAccount)
-                        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
                     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                               fileName, @"fileName", 
                                               [NSNumber numberWithUnsignedInteger:bytes], @"bytes", 
                 }
                 
             } else {
-                subObjectName = [objectName stringByAppendingPathComponent:objectNameSuffix];
+                subObjectName = [[objectName stringByAppendingPathComponent:objectNameSuffix] precomposedStringWithCanonicalMapping];
                 fileName = [filePath lastPathComponent];
-                objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName 
-                                                                                     objectName:subObjectName 
-                                                                                           eTag:nil 
-                                                                                    contentType:@"application/directory" 
-                                                                                contentEncoding:nil 
-                                                                             contentDisposition:nil 
-                                                                                       manifest:nil 
-                                                                                        sharing:nil 
-                                                                                       isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                       metadata:nil 
-                                                                                           data:[NSData data]];
+                objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos 
+                                                                           containerName:containerName 
+                                                                              objectName:subObjectName 
+                                                                                    eTag:nil 
+                                                                             contentType:@"application/directory" 
+                                                                         contentEncoding:nil 
+                                                                      contentDisposition:nil 
+                                                                                manifest:nil 
+                                                                                 sharing:nil 
+                                                                                isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                metadata:nil 
+                                                                                    data:[NSData data]];
                 if (sharingAccount)
-                    [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                    [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
                 objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                           fileName, @"fileName", 
                                           nil];
 #pragma mark -
 #pragma mark Delete
 
-+ (NSArray *)deleteObjectRequestsForSubdirWithContainerName:(NSString *)containerName objectName:(NSString *)objectName {
-    NSArray *objects = [self objectsForSubdirWithContainerName:containerName objectName:objectName delimiter:nil sharingAccount:nil];
++ (NSArray *)deleteObjectRequestsForSubdirWithPithos:(ASIPithos *)pithos 
+                                       containerName:(NSString *)containerName 
+                                          objectName:(NSString *)objectName {
+    NSArray *objects = [self objectsForSubdirWithPithos:pithos containerName:containerName objectName:objectName delimiter:nil 
+                                         sharingAccount:nil];
     if (objects == nil)
         return nil;
 
     NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:([objects count] + 1)];
     ASIPithosObjectRequest *objectRequest;
     if (![objectName hasSuffix:@"/"]) {
-        objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:objectName];
+        objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos containerName:containerName objectName:objectName];
         objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   [objectName lastPathComponent], @"fileName", 
                                   nil];
         fileName = [object.name lastPathComponent];
         if ([object.name hasSuffix:@"/"])
             fileName = [fileName stringByAppendingString:@"/"];
-        objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:object.name];
+        objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos containerName:containerName objectName:object.name];
         objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   fileName, @"fileName", 
                                   nil];
 #pragma mark -
 #pragma mark Copy
 
-+ (ASIPithosObjectRequest *)copyObjectRequestWithContainerName:(NSString *)containerName 
-                                                    objectName:(NSString *)objectName 
-                                      destinationContainerName:(NSString *)destinationContainerName 
-                                         destinationObjectName:(NSString *)destinationObjectName 
-                                                 checkIfExists:(BOOL)ifExists 
-                                                sharingAccount:(NSString *)sharingAccount {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:destinationContainerName objectName:destinationObjectName sharingAccount:nil])
++ (ASIPithosObjectRequest *)cpyObjectRequestWithPithos:(ASIPithos *)pithos 
+                                          containerName:(NSString *)containerName 
+                                             objectName:(NSString *)objectName 
+                               destinationContainerName:(NSString *)destinationContainerName 
+                                  destinationObjectName:(NSString *)destinationObjectName 
+                                          checkIfExists:(BOOL)ifExists 
+                                         sharingAccount:(NSString *)sharingAccount {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:destinationContainerName objectName:destinationObjectName 
+                                          sharingAccount:nil])
         return nil;
     
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest copyObjectDataRequestWithContainerName:containerName 
-                                                                                                objectName:objectName 
-                                                                                               contentType:nil 
-                                                                                           contentEncoding:nil 
-                                                                                        contentDisposition:nil 
-                                                                                                  manifest:nil 
-                                                                                                   sharing:nil 
-                                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                                  metadata:nil 
-                                                                                  destinationContainerName:destinationContainerName 
-                                                                                     destinationObjectName:destinationObjectName 
-                                                                                        destinationAccount:nil
-                                                                                             sourceVersion:nil];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest cpyObjectDataRequestWithPithos:pithos 
+                                                                                      containerName:containerName 
+                                                                                         objectName:objectName 
+                                                                                        contentType:nil 
+                                                                                    contentEncoding:nil 
+                                                                                 contentDisposition:nil 
+                                                                                           manifest:nil 
+                                                                                            sharing:nil 
+                                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                           metadata:nil 
+                                                                           destinationContainerName:destinationContainerName 
+                                                                              destinationObjectName:destinationObjectName 
+                                                                                 destinationAccount:nil
+                                                                                      sourceVersion:nil];
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                               containerName, @"sourceContainerName", 
                               objectName, @"sourceObjectName", 
                               destinationObjectName, @"destinationObjectName", 
                               nil];
     if (sharingAccount) 
-        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
     return objectRequest;
 }
 
-+ (NSArray *)copyObjectRequestsForSubdirWithContainerName:(NSString *)containerName 
-                                               objectName:(NSString *)objectName 
-                                 destinationContainerName:(NSString *)destinationContainerName 
-                                    destinationObjectName:(NSString *)destinationObjectName 
-                                            checkIfExists:(BOOL)ifExists 
-                                           sharingAccount:(NSString *)sharingAccount {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:destinationContainerName objectName:destinationObjectName sharingAccount:nil])
++ (NSArray *)cpyObjectRequestsForSubdirWithPithos:(ASIPithos *)pithos 
+                                     containerName:(NSString *)containerName 
+                                        objectName:(NSString *)objectName 
+                          destinationContainerName:(NSString *)destinationContainerName 
+                             destinationObjectName:(NSString *)destinationObjectName 
+                                     checkIfExists:(BOOL)ifExists 
+                                    sharingAccount:(NSString *)sharingAccount {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:destinationContainerName objectName:destinationObjectName 
+                                          sharingAccount:nil])
         return nil;
     
-    NSArray *objects = [self objectsForSubdirWithContainerName:containerName objectName:objectName 
-                                                     delimiter:nil sharingAccount:sharingAccount];
+    NSArray *objects = [self objectsForSubdirWithPithos:pithos containerName:containerName objectName:objectName 
+                                              delimiter:nil sharingAccount:sharingAccount];
     if (objects == nil)
         return nil;
     
     ASIPithosObjectRequest *objectRequest;
     if ([objectName isEqualToString:destinationObjectName]) {
         if (![objectName hasSuffix:@"/"]) {
-            objectRequest = [ASIPithosObjectRequest copyObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:objectName 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:objectName 
-                                                                        destinationAccount:nil 
-                                                                             sourceVersion:nil];
+            objectRequest = [ASIPithosObjectRequest cpyObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:objectName 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:objectName 
+                                                                 destinationAccount:nil 
+                                                                      sourceVersion:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       objectName, @"sourceObjectName", 
                                       objectName, @"destinationObjectName", 
                                       nil];
             if (sharingAccount)
-                [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
             [objectRequests addObject:objectRequest];
         }
         for (ASIPithosObject *object in objects) {
-            objectRequest = [ASIPithosObjectRequest copyObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:object.name 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:object.name 
-                                                                        destinationAccount:nil 
-                                                                             sourceVersion:nil];
+            objectRequest = [ASIPithosObjectRequest cpyObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:object.name 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:object.name 
+                                                                 destinationAccount:nil 
+                                                                      sourceVersion:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       object.name, @"sourceObjectName", 
                                       object.name, @"destinationObjectName", 
                                       nil];
             if (sharingAccount)
-                [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
             [objectRequests addObject:objectRequest];
         }
     } else {
         if (![objectName hasSuffix:@"/"]) {
-            objectRequest = [ASIPithosObjectRequest copyObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:objectName 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:destinationObjectName 
-                                                                        destinationAccount:nil 
-                                                                             sourceVersion:nil];
+            objectRequest = [ASIPithosObjectRequest cpyObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:objectName 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:destinationObjectName 
+                                                                 destinationAccount:nil 
+                                                                      sourceVersion:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       objectName, @"sourceObjectName", 
                                       destinationObjectName, @"destinationObjectName", 
                                       nil];
             if (sharingAccount)
-                [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
             [objectRequests addObject:objectRequest];
         }
         NSRange prefixRange = NSMakeRange(0, [objectName length]);
                                                                    withString:destinationObjectName
                                                                       options:NSAnchoredSearch
                                                                         range:prefixRange];
-            objectRequest = [ASIPithosObjectRequest copyObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:object.name 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:newObjectName 
-                                                                        destinationAccount:nil 
-                                                                             sourceVersion:nil];
+            objectRequest = [ASIPithosObjectRequest cpyObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:object.name 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:newObjectName 
+                                                                 destinationAccount:nil 
+                                                                      sourceVersion:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       object.name, @"sourceObjectName", 
                                       newObjectName, @"destinationObjectName", 
                                       nil];
             if (sharingAccount)
-                [objectRequest setRequestUserFromDefaultTo:sharingAccount];
+                [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
             [objectRequests addObject:objectRequest];
         }
     }
 #pragma mark -
 #pragma mark Move
 
-+ (ASIPithosObjectRequest *)moveObjectRequestWithContainerName:(NSString *)containerName 
-                                     objectName:(NSString *)objectName 
-                       destinationContainerName:(NSString *)destinationContainerName 
-                          destinationObjectName:(NSString *)destinationObjectName 
-                                  checkIfExists:(BOOL)ifExists {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:destinationContainerName objectName:destinationObjectName sharingAccount:nil])
++ (ASIPithosObjectRequest *)moveObjectRequestWithPithos:(ASIPithos *)pithos 
+                                          containerName:(NSString *)containerName 
+                                             objectName:(NSString *)objectName 
+                               destinationContainerName:(NSString *)destinationContainerName 
+                                  destinationObjectName:(NSString *)destinationObjectName 
+                                          checkIfExists:(BOOL)ifExists {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:destinationContainerName objectName:destinationObjectName 
+                                          sharingAccount:nil])
         return nil;
     
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                                objectName:objectName 
-                                                                                               contentType:nil 
-                                                                                           contentEncoding:nil 
-                                                                                        contentDisposition:nil 
-                                                                                                  manifest:nil 
-                                                                                                   sharing:nil 
-                                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                                  metadata:nil 
-                                                                                  destinationContainerName:destinationContainerName 
-                                                                                     destinationObjectName:destinationObjectName 
-                                                                                        destinationAccount:nil];
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithPithos:pithos 
+                                                                                      containerName:containerName 
+                                                                                         objectName:objectName 
+                                                                                        contentType:nil 
+                                                                                    contentEncoding:nil 
+                                                                                 contentDisposition:nil 
+                                                                                           manifest:nil 
+                                                                                            sharing:nil 
+                                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                           metadata:nil 
+                                                                           destinationContainerName:destinationContainerName 
+                                                                              destinationObjectName:destinationObjectName 
+                                                                                 destinationAccount:nil];
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                               containerName, @"sourceContainerName", 
                               objectName, @"sourceObjectName", 
     return objectRequest;
 }
 
-+ (NSArray *)moveObjectRequestsForSubdirWithContainerName:(NSString *)containerName 
-                                               objectName:(NSString *)objectName 
-                                 destinationContainerName:(NSString *)destinationContainerName 
-                                    destinationObjectName:(NSString *)destinationObjectName 
-                                            checkIfExists:(BOOL)ifExists {
-    if (ifExists && ![self proceedIfObjectExistsAtContainerName:destinationContainerName objectName:destinationObjectName sharingAccount:nil])
++ (NSArray *)moveObjectRequestsForSubdirWithPithos:(ASIPithos *)pithos 
+                                     containerName:(NSString *)containerName 
+                                        objectName:(NSString *)objectName 
+                          destinationContainerName:(NSString *)destinationContainerName 
+                             destinationObjectName:(NSString *)destinationObjectName 
+                                     checkIfExists:(BOOL)ifExists {
+    if (ifExists && ![self proceedIfObjectExistsAtPithos:pithos containerName:destinationContainerName objectName:destinationObjectName 
+                                          sharingAccount:nil])
         return nil;
     
-    NSArray *objects = [self objectsForSubdirWithContainerName:containerName objectName:objectName delimiter:nil sharingAccount:nil];
+    NSArray *objects = [self objectsForSubdirWithPithos:pithos containerName:containerName objectName:objectName 
+                                              delimiter:nil sharingAccount:nil];
     if (objects == nil)
         return nil;
     
     NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:([objects count] + 1)];
     if ([objectName isEqualToString:destinationObjectName]) {
         if (![objectName hasSuffix:@"/"]) {
-            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:objectName 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:objectName 
-                                                                        destinationAccount:nil];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:objectName 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:objectName 
+                                                                 destinationAccount:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       objectName, @"sourceObjectName", 
             [objectRequests addObject:objectRequest];
         }
         for (ASIPithosObject *object in objects) {
-            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:object.name 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:object.name 
-                                                                        destinationAccount:nil];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:object.name 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:object.name 
+                                                                 destinationAccount:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       object.name, @"sourceObjectName", 
         }
     } else {
         if (![objectName hasSuffix:@"/"]) {
-            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:objectName 
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:destinationObjectName 
-                                                                        destinationAccount:nil];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:objectName 
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:destinationObjectName 
+                                                                 destinationAccount:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       objectName, @"sourceObjectName", 
                                                                    withString:destinationObjectName
                                                                       options:NSAnchoredSearch
                                                                         range:prefixRange];
-            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                objectName:object.name
-                                                                               contentType:nil 
-                                                                           contentEncoding:nil 
-                                                                        contentDisposition:nil 
-                                                                                  manifest:nil 
-                                                                                   sharing:nil 
-                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                  metadata:nil 
-                                                                  destinationContainerName:destinationContainerName 
-                                                                     destinationObjectName:newObjectName 
-                                                                        destinationAccount:nil];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithPithos:pithos 
+                                                                      containerName:containerName 
+                                                                         objectName:object.name
+                                                                        contentType:nil 
+                                                                    contentEncoding:nil 
+                                                                 contentDisposition:nil 
+                                                                           manifest:nil 
+                                                                            sharing:nil 
+                                                                           isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                           metadata:nil 
+                                                           destinationContainerName:destinationContainerName 
+                                                              destinationObjectName:newObjectName 
+                                                                 destinationAccount:nil];
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       containerName, @"sourceContainerName", 
                                       object.name, @"sourceObjectName", 
 + (NSUInteger)bytesOfFile:(NSString *)filePath {
     NSFileManager *fileManager = [NSFileManager defaultManager];
     NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
-    return [[attributes objectForKey:NSFileSize] intValue];
+    return [[attributes objectForKey:NSFileSize] unsignedIntegerValue];
 }
 
 // Content type of the file or nil if it cannot be determined
 + (NSString *)contentTypeOfFile:(NSString *)filePath error:(NSError **)error {
-    NSURLResponse *response = nil;
-    [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath] 
-                                                             cachePolicy:NSURLCacheStorageNotAllowed 
-                                                         timeoutInterval:.1] 
-                          returningResponse:&response 
-                                      error:error];
-    return [response MIMEType];
+    // Based on http://www.ddeville.me/2011/12/mime-to-UTI-cocoa/
+    // and Apple example ImageBrowserViewAppearance/ImageBrowserController.m
+    LSItemInfoRecord info;
+    CFStringRef uti = NULL;
+    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)filePath, kCFURLPOSIXPathStyle, FALSE);
+    if (LSCopyItemInfoForURL(url, kLSRequestExtension | kLSRequestTypeCreator, &info) == noErr) {
+        // Obtain the UTI using the file information.
+        // If there is a file extension, get the UTI.
+        if (info.extension != NULL) {
+            uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, info.extension, kUTTypeData);
+            CFRelease(info.extension);
+        }
+        // No UTI yet
+        if (uti == NULL) {
+            // If there is an OSType, get the UTI.
+            CFStringRef typeString = UTCreateStringForOSType(info.filetype);
+            if ( typeString != NULL) {
+                uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, typeString, kUTTypeData);
+                CFRelease(typeString);
+            }
+        }
+        if (uti != NULL) {
+            CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
+            CFRelease(uti);
+            CFRelease(url);
+            return (__bridge_transfer NSString *)MIMEType;
+        }
+    }
+    CFRelease(url);
+    return nil;
+}
+
+// Creates a directory if it doesn't exist and returns if successful
++ (BOOL)safeCreateDirectory:(NSString *)directoryPath error:(NSError **)error {
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    BOOL isDirectory;
+    BOOL fileExists = [fileManager fileExistsAtPath:directoryPath isDirectory:&isDirectory];
+    if (fileExists)
+        return isDirectory;
+    if (![fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:error] || *error)
+        return NO;
+    return YES;
+}
+
+// Removes contents of a directory and the directory itself if selected
++ (void)removeContentsAtPath:(NSString *)dirPath andDirectory:(BOOL)removeDirectory {
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    NSError *error = nil;
+    BOOL isDirectory;
+    if (![fileManager fileExistsAtPath:dirPath isDirectory:&isDirectory])
+        return;
+    if (isDirectory) {
+        for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:dirPath error:&error]) {
+            if (error) {
+                [self fileActionFailedAlertWithTitle:@"Directory Contents Error" 
+                                             message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", dirPath] 
+                                               error:error];
+                break;
+            }
+            NSString *subFilePath = [dirPath stringByAppendingPathComponent:subPath];
+            if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
+                [self fileActionFailedAlertWithTitle:@"Remove File Error" 
+                                             message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath] 
+                                               error:error];
+            }
+            error = nil;
+        }
+        if (removeDirectory && (![fileManager removeItemAtPath:dirPath error:&error] || error)) {
+            [self fileActionFailedAlertWithTitle:@"Remove Directory Error"
+                                         message:[NSString stringWithFormat:@"Cannot remove directory at '%@'", dirPath]
+                                           error:error];
+        }
+    } else if (![fileManager removeItemAtPath:dirPath error:&error] || error) {
+        [self fileActionFailedAlertWithTitle:@"Remove File Error" 
+                                     message:[NSString stringWithFormat:@"Cannot remove file at '%@'", dirPath] 
+                                       error:error];
+    }
+}
+
+// Removes contents of a directory
++ (void)removeContentsAtPath:(NSString *)dirPath {
+    [self removeContentsAtPath:dirPath andDirectory:NO];
 }
 
 // Returns if an object is a directory based on its content type
 
 // Returns if an object exists at the given container/object path and if this object is an application/directory
 // If an error occured an alert is shown and it is returned so the caller won't proceed
-+ (BOOL)objectExistsAtContainerName:(NSString *)containerName objectName:(NSString *)objectName 
-                              error:(NSError **)error isDirectory:(BOOL *)isDirectory 
-                     sharingAccount:(NSString *)sharingAccount {
-    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectMetadataRequestWithContainerName:containerName 
-                                                                                                objectName:objectName];
++ (BOOL)objectExistsAtPithos:(ASIPithos *)pithos containerName:(NSString *)containerName objectName:(NSString *)objectName 
+                       error:(NSError **)error isDirectory:(BOOL *)isDirectory sharingAccount:(NSString *)sharingAccount {
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectMetadataRequestWithPithos:pithos 
+                                                                                      containerName:containerName 
+                                                                                         objectName:objectName];
     if (sharingAccount)
-        [objectRequest setRequestUserFromDefaultTo:sharingAccount];
-    [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
-    while (![objectRequest isFinished]) {
-        sleep(1);
-    }
-    *error = [objectRequest error];
-    if (*error) {
-        [self httpRequestErrorAlertWithRequest:objectRequest];
-        return NO;
-    } else if (objectRequest.responseStatusCode == 200) {
-        *isDirectory = [self isContentTypeDirectory:[objectRequest contentType]];
-        return YES;
+        [objectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
+    [self startAndWaitForRequest:objectRequest];
+    if (error != NULL) {
+        *error = [objectRequest error];
+        if (*error) {
+            [self httpRequestErrorAlertWithRequest:objectRequest];
+            return NO;
+        } else if (objectRequest.responseStatusCode == 200) {
+            *isDirectory = [self isContentTypeDirectory:[objectRequest contentType]];
+            return YES;
+        }
     }
     return NO;
 }
 
-// Returns if the called should proceed, after an interactive check if an object exists 
+// Returns if the caller should proceed, after an interactive check if an object exists 
 // at the given container/object path is performed
-+ (BOOL)proceedIfObjectExistsAtContainerName:(NSString *)containerName objectName:(NSString *)objectName 
-                              sharingAccount:(NSString *)sharingAccount {
++ (BOOL)proceedIfObjectExistsAtPithos:(ASIPithos *)pithos containerName:(NSString *)containerName objectName:(NSString *)objectName 
+                       sharingAccount:(NSString *)sharingAccount {
     NSError *error = nil;
     BOOL isDirectory;
-    BOOL objectExists = [self objectExistsAtContainerName:containerName 
-                                               objectName:objectName
-                                                    error:&error 
-                                              isDirectory:&isDirectory 
-                                           sharingAccount:sharingAccount];
+    BOOL objectExists = [self objectExistsAtPithos:pithos containerName:containerName objectName:objectName 
+                                             error:&error isDirectory:&isDirectory sharingAccount:sharingAccount];
     if (error) {
         return NO;
     } else if (objectExists) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-        if (isDirectory) {
-            [alert setMessageText:@"Directory Exists"];
-            if (sharingAccount)
-                [alert setInformativeText:[NSString stringWithFormat:@"A directory with path '%@' in the container '%@' of user '%@' already exists, do you want to replace it?", objectName, containerName, sharingAccount]];
-            else
-                [alert setInformativeText:[NSString stringWithFormat:@"A directory with path '%@' in the container '%@' already exists, do you want to replace it?", objectName, containerName]];
-        } else {
-            [alert setMessageText:@"Object Exists"];
-            if (sharingAccount)
-                [alert setInformativeText:[NSString stringWithFormat:@"An object with path '%@' in the container '%@' of user '%@' already exists, do you want to replace it?", objectName, containerName, sharingAccount]];
-            else
-                [alert setInformativeText:[NSString stringWithFormat:@"An object with path '%@' in the container '%@' already exists, do you want to replace it?", objectName, containerName]];
-        }
-        [alert addButtonWithTitle:@"OK"];
-        [alert addButtonWithTitle:@"Cancel"];
-        NSInteger choice = [alert runModal];
+        __block NSInteger choice;
+        dispatch_sync(dispatch_get_main_queue(), ^{
+            NSAlert *alert = [[NSAlert alloc] init];
+            if (isDirectory) {
+                [alert setMessageText:@"Directory Exists"];
+                if (sharingAccount)
+                    [alert setInformativeText:[NSString stringWithFormat:@"A directory with path '%@' in the container '%@' of user '%@' already exists, do you want to replace it?", objectName, containerName, sharingAccount]];
+                else
+                    [alert setInformativeText:[NSString stringWithFormat:@"A directory with path '%@' in the container '%@' already exists, do you want to replace it?", objectName, containerName]];
+            } else {
+                [alert setMessageText:@"Object Exists"];
+                if (sharingAccount)
+                    [alert setInformativeText:[NSString stringWithFormat:@"An object with path '%@' in the container '%@' of user '%@' already exists, do you want to replace it?", objectName, containerName, sharingAccount]];
+                else
+                    [alert setInformativeText:[NSString stringWithFormat:@"An object with path '%@' in the container '%@' already exists, do you want to replace it?", objectName, containerName]];
+            }
+            [alert addButtonWithTitle:@"OK"];
+            [alert addButtonWithTitle:@"Cancel"];
+            choice = [alert runModal];
+        });
         if (choice == NSAlertSecondButtonReturn)
             return NO;
     }
     return YES;
 }
 
-
 // List of objects at the given container/object path, with prefix and or delimiter
-+ (NSArray *)objectsWithContainerName:(NSString *)containerName objectNamePrefix:(NSString *)objectNamePrefix 
-                            delimiter:(NSString *)delimiter sharingAccount:(NSString *)sharingAccount {
++ (NSArray *)objectsWithPithos:(ASIPithos *)pithos containerName:(NSString *)containerName objectNamePrefix:(NSString *)objectNamePrefix 
+                     delimiter:(NSString *)delimiter sharingAccount:(NSString *)sharingAccount {
     NSMutableArray *objects = [NSMutableArray array];
     NSString *marker = nil;
     do {
-        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:containerName 
-                                                                                                               limit:0 
-                                                                                                              marker:marker 
-                                                                                                              prefix:objectNamePrefix 
-                                                                                                           delimiter:delimiter 
-                                                                                                                path:nil 
-                                                                                                                meta:nil 
-                                                                                                              shared:NO 
-                                                                                                               until:nil];
+        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos 
+                                                                                                containerName:containerName 
+                                                                                                        limit:0 
+                                                                                                       marker:marker 
+                                                                                                       prefix:objectNamePrefix 
+                                                                                                    delimiter:delimiter 
+                                                                                                         path:nil 
+                                                                                                         meta:nil 
+                                                                                                       shared:NO 
+                                                                                                        until:nil];
         if (sharingAccount)
-            [containerRequest setRequestUserFromDefaultTo:sharingAccount];
-        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
-        while (![containerRequest isFinished]) {
-            sleep(1);
-        }
+            [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
+        [self startAndWaitForRequest:containerRequest];
         if ([containerRequest error]) {
             [self httpRequestErrorAlertWithRequest:containerRequest];
             return nil;
 
 // List of objects at the given container/object path, that may be a subdir or an application/directory, 
 // with prefix and or delimiter
-+ (NSArray *)objectsForSubdirWithContainerName:(NSString *)containerName objectName:(NSString *)objectName 
-                                     delimiter:(NSString *)delimiter sharingAccount:(NSString *)sharingAccount {
++ (NSArray *)objectsForSubdirWithPithos:(ASIPithos *)pithos containerName:(NSString *)containerName objectName:(NSString *)objectName 
+                              delimiter:(NSString *)delimiter sharingAccount:(NSString *)sharingAccount {
     NSString *subdirNamePrefix = [NSString stringWithString:objectName];
     if (![subdirNamePrefix hasSuffix:@"/"])
         subdirNamePrefix = [subdirNamePrefix stringByAppendingString:@"/"];
-    return [self objectsWithContainerName:containerName objectNamePrefix:subdirNamePrefix 
-                                delimiter:delimiter sharingAccount:sharingAccount];
+    return [self objectsWithPithos:pithos containerName:containerName objectNamePrefix:subdirNamePrefix 
+                         delimiter:delimiter sharingAccount:sharingAccount];
 }
 
 // A safe object name at the given container/object path
 // The original name has " %d" appended to it before any ".*" suffix, for the first integer that produces a name that is free to use
 // If the original name hasn't got a "." but has a "/" suffix, then it is replaced with " %d/" instead
 // Subdirs are taken into consideration
-+ (NSString *)safeObjectNameForContainerName:(NSString *)containerName objectName:(NSString *)objectName {
++ (NSString *)safeObjectNameForPithos:(ASIPithos *)pithos containerName:(NSString *)containerName objectName:(NSString *)objectName {
     NSString *objectNamePrefix;
     NSString *objectNameExtraSuffix;
     NSRange lastDotRange = [objectName rangeOfString:@"." options:NSBackwardsSearch];
         objectNameExtraSuffix = [objectName substringFromIndex:lastDotRange.location];
     } else if ([objectName hasSuffix:@"/"]) {
         objectNamePrefix = [objectName substringToIndex:([objectName length] - 1)];
-        objectNameExtraSuffix = [NSString stringWithString:@"/"];
+        objectNameExtraSuffix = @"/";
     } else {
         objectNamePrefix = [NSString stringWithString:objectName];
         objectNameExtraSuffix = [NSString string];
     }
-    NSArray *objects = [self objectsWithContainerName:containerName 
-                                     objectNamePrefix:[objectNamePrefix stringByDeletingLastPathComponent] 
-                                            delimiter:@"/" 
-                                       sharingAccount:nil];
+    NSArray *objects = [self objectsWithPithos:pithos containerName:containerName 
+                              objectNamePrefix:[objectNamePrefix stringByDeletingLastPathComponent] 
+                                     delimiter:@"/" sharingAccount:nil];
     if (objects == nil)
         return nil;
     if ([objects count] == 0)
 // The original name has " %d" appended to it, for the first integer that produces a name that is free to use
 // If the original name has a "/" suffix, then it is replaced with " %d/" instead
 // Subdirs are taken into consideration
-+ (NSString *)safeSubdirNameForContainerName:(NSString *)containerName subdirName:(NSString *)subdirName {
++ (NSString *)safeSubdirNameForPithos:(ASIPithos *)pithos containerName:(NSString *)containerName subdirName:(NSString *)subdirName {
     NSString *subdirNamePrefix;
     NSString *subdirNameExtraSuffix;
     if ([subdirName hasSuffix:@"/"]) {
         subdirNamePrefix = [subdirName substringToIndex:([subdirName length] - 1)];
-        subdirNameExtraSuffix = [NSString stringWithString:@"/"];
+        subdirNameExtraSuffix = @"/";
     } else {
         subdirNamePrefix = [NSString stringWithString:subdirName];
         subdirNameExtraSuffix = [NSString string];
     }
-    NSArray *objects = [self objectsWithContainerName:containerName 
-                                     objectNamePrefix:[subdirNamePrefix stringByDeletingLastPathComponent] 
-                                            delimiter:@"/" 
-                                       sharingAccount:nil];
+    NSArray *objects = [self objectsWithPithos:pithos containerName:containerName 
+                              objectNamePrefix:[subdirNamePrefix stringByDeletingLastPathComponent] 
+                                     delimiter:@"/" sharingAccount:nil];
     if (objects == nil)
         return nil;
     if ([objects count] == 0)
 #pragma mark -
 #pragma mark Alerts
 
-+ (NSInteger)httpRequestErrorAlertWithRequest:(ASIPithosRequest *)request {
++ (void)httpRequestErrorAlertWithRequest:(ASIPithosRequest *)request {
+    if (request.responseStatusCode == 401) {
+        [self httpAuthenticationError];
+        return;
+    }
     NSString *message = [NSString stringWithFormat:
                          @"HTTP request error: %@\n%@ URL: %@\nRequest Headers: %@\nResponse Headers: %@\nResponse String: %@", 
-                         [request error], 
+                         [[request error] localizedDescription], 
                          request.requestMethod, 
                          request.url, 
                          [request requestHeaders], 
                          [request responseHeaders], 
                          [request responseString]];
-    NSLog(@"%@", message);
-    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-    [alert setMessageText:@"HTTP Request Error"];
-    [alert setInformativeText:message];
-    [alert addButtonWithTitle:@"OK"];
-    return [alert runModal];
+    DLog(@"%@", message);
+    dispatch_async(dispatch_get_main_queue(), ^{    
+        @autoreleasepool {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"HTTP Request Error"];
+            [alert setInformativeText:message];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        }
+    });
 }
 
-+ (NSInteger)unexpectedResponseStatusAlertWithRequest:(ASIPithosRequest *)request {
++ (void)unexpectedResponseStatusAlertWithRequest:(ASIPithosRequest *)request {
+    if (request.responseStatusCode == 401) {
+        [self httpAuthenticationError];
+        return;
+    }
     NSString *message = [NSString stringWithFormat:
                          @"Unexpected response status %d: %@\n%@ URL: %@\nRequest Headers: %@\nResponse Headers: %@\nResponse String: %@", 
                          request.responseStatusCode, 
                          [request requestHeaders], 
                          [request responseHeaders], 
                          [request responseString]];
-    NSLog(@"%@", message);
-    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-    [alert setMessageText:@"Unexpected Response Status"];
-    [alert setInformativeText:message];
-    [alert addButtonWithTitle:@"OK"];
-    return [alert runModal];
+    DLog(@"%@", message);
+    dispatch_async(dispatch_get_main_queue(), ^{
+        @autoreleasepool {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Unexpected Response Status"];
+            [alert setInformativeText:message];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        }
+    });
+}
+
++ (void)httpAuthenticationError {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        @autoreleasepool {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Authentication Error"];
+            [alert setInformativeText:@"Authentication error, please check your token or login again"];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        }
+    });
 }
 
-+ (NSInteger)fileActionFailedAlertWithTitle:(NSString *)title message:(NSString *)message error:(NSError *)error {
-    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-    [alert setMessageText:title];
-    if (error)
-        [alert setInformativeText:[NSString stringWithFormat:@"%@: %@", message, error]];
-    else
-        [alert setInformativeText:message];
-    [alert addButtonWithTitle:@"OK"];
-    return [alert runModal];
++ (void)fileActionFailedAlertWithTitle:(NSString *)title message:(NSString *)message error:(NSError *)error {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        @autoreleasepool {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:title];
+            if (error)
+                [alert setInformativeText:[NSString stringWithFormat:@"%@: %@", message, [error localizedDescription]]];
+            else
+                [alert setInformativeText:message];
+            [alert addButtonWithTitle:@"OK"];
+            [alert runModal];
+        }
+    });
 }
 
 #pragma mark -
 }
 
 + (ASIPithosRequest *)copyRequest:(ASIPithosRequest *)request {
-    NSMutableDictionary *userInfo = [[request.userInfo retain] autorelease];
+    NSMutableDictionary *userInfo = (NSMutableDictionary *)request.userInfo;
     request.userInfo = nil;
     ASIPithosRequest *newRequest = [request copy];
     newRequest.userInfo = userInfo;
     return newRequest;
 }
 
++ (void)startAndWaitForRequest:(ASIPithosRequest *)request {
+    ASINetworkQueue *networkQueue = [ASINetworkQueue queue];
+    [networkQueue go];
+    [networkQueue addOperations:[NSArray arrayWithObject:[self prepareRequest:request]] waitUntilFinished:YES];
+}
+
 @end