handle multipart for EAS/ItemOperations
parent
135b463e8f
commit
d87056ebfa
|
@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#import <Foundation/NSProcessInfo.h>
|
#import <Foundation/NSProcessInfo.h>
|
||||||
#import <Foundation/NSTimeZone.h>
|
#import <Foundation/NSTimeZone.h>
|
||||||
#import <Foundation/NSURL.h>
|
#import <Foundation/NSURL.h>
|
||||||
|
#import <Foundation/NSValue.h>
|
||||||
|
|
||||||
#import <NGObjWeb/NSException+HTTP.h>
|
#import <NGObjWeb/NSException+HTTP.h>
|
||||||
#import <NGObjWeb/SoPermissions.h>
|
#import <NGObjWeb/SoPermissions.h>
|
||||||
|
@ -1215,71 +1216,136 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
{
|
{
|
||||||
NSString *fileReference, *realCollectionId;
|
NSString *fileReference, *realCollectionId;
|
||||||
NSMutableString *s;
|
NSMutableString *s;
|
||||||
|
NSArray *fetchRequests;
|
||||||
|
id aFetch;
|
||||||
|
int i;
|
||||||
|
|
||||||
SOGoMicrosoftActiveSyncFolderType folderType;
|
SOGoMicrosoftActiveSyncFolderType folderType;
|
||||||
|
|
||||||
fileReference = [[[(id)[theDocumentElement getElementsByTagName: @"FileReference"] lastObject] textValue] stringByUnescapingURL];
|
s = [NSMutableString string];
|
||||||
|
|
||||||
realCollectionId = [fileReference realCollectionIdWithFolderType: &folderType];
|
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||||
|
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||||
|
[s appendString: @"<ItemOperations xmlns=\"ItemOperations:\">"];
|
||||||
|
[s appendString: @"<Status>1</Status>"];
|
||||||
|
[s appendString: @"<Response>"];
|
||||||
|
|
||||||
|
fetchRequests = (id)[theDocumentElement getElementsByTagName: @"Fetch"];
|
||||||
|
|
||||||
if (folderType == ActiveSyncMailFolder)
|
if ([fetchRequests count])
|
||||||
{
|
{
|
||||||
id currentFolder, currentCollection, currentBodyPart;
|
NSMutableData *bytes, *parts;
|
||||||
NSString *folderName, *messageName, *pathToPart;
|
NSMutableArray *partLength;
|
||||||
SOGoMailAccounts *accountsFolder;
|
|
||||||
SOGoUserFolder *userFolder;
|
|
||||||
SOGoMailObject *mailObject;
|
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
|
||||||
NSRange r1, r2;
|
bytes = [NSMutableData data];
|
||||||
|
parts = [NSMutableData data];
|
||||||
|
partLength = [NSMutableArray array];
|
||||||
|
|
||||||
r1 = [realCollectionId rangeOfString: @"/"];
|
for (i = 0; i < [fetchRequests count]; i++)
|
||||||
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
|
{
|
||||||
|
aFetch = [fetchRequests objectAtIndex: i];
|
||||||
|
fileReference = [[[(id)[aFetch getElementsByTagName: @"FileReference"] lastObject] textValue] stringByUnescapingURL];
|
||||||
|
realCollectionId = [fileReference realCollectionIdWithFolderType: &folderType];
|
||||||
|
|
||||||
|
if (folderType == ActiveSyncMailFolder)
|
||||||
|
{
|
||||||
|
id currentFolder, currentCollection, currentBodyPart;
|
||||||
|
NSString *folderName, *messageName, *pathToPart;
|
||||||
|
SOGoMailAccounts *accountsFolder;
|
||||||
|
SOGoUserFolder *userFolder;
|
||||||
|
SOGoMailObject *mailObject;
|
||||||
|
|
||||||
|
NSRange r1, r2;
|
||||||
|
|
||||||
|
r1 = [realCollectionId rangeOfString: @"/"];
|
||||||
|
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
|
||||||
|
|
||||||
folderName = [realCollectionId substringToIndex: r1.location];
|
folderName = [realCollectionId substringToIndex: r1.location];
|
||||||
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
|
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
|
||||||
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
|
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
|
||||||
|
|
||||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
|
||||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
|
||||||
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
|
||||||
|
|
||||||
currentCollection = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", folderName]
|
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||||
inContext: context
|
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||||
acquire: NO];
|
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||||
|
|
||||||
mailObject = [currentCollection lookupName: messageName inContext: context acquire: NO];
|
|
||||||
currentBodyPart = [mailObject lookupImap4BodyPartKey: pathToPart inContext: context];
|
|
||||||
|
|
||||||
|
currentCollection = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", folderName]
|
||||||
|
inContext: context
|
||||||
|
acquire: NO];
|
||||||
|
|
||||||
s = [NSMutableString string];
|
mailObject = [currentCollection lookupName: messageName inContext: context acquire: NO];
|
||||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
currentBodyPart = [mailObject lookupImap4BodyPartKey: pathToPart inContext: context];
|
||||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
|
||||||
[s appendString: @"<ItemOperations xmlns=\"ItemOperations:\">"];
|
|
||||||
[s appendString: @"<Status>1</Status>"];
|
|
||||||
[s appendString: @"<Response>"];
|
|
||||||
|
|
||||||
[s appendString: @"<Fetch>"];
|
[s appendString: @"<Fetch>"];
|
||||||
[s appendString: @"<Status>1</Status>"];
|
[s appendString: @"<Status>1</Status>"];
|
||||||
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">%@</FileReference>", [fileReference stringByEscapingURL]];
|
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">%@</FileReference>", [fileReference stringByEscapingURL]];
|
||||||
[s appendString: @"<Properties>"];
|
[s appendString: @"<Properties>"];
|
||||||
|
|
||||||
[s appendFormat: @"<ContentType xmlns=\"AirSyncBase:\">%@/%@</ContentType>", [[currentBodyPart partInfo] objectForKey: @"type"], [[currentBodyPart partInfo] objectForKey: @"subtype"]];
|
[s appendFormat: @"<ContentType xmlns=\"AirSyncBase:\">%@/%@</ContentType>", [[currentBodyPart partInfo] objectForKey: @"type"], [[currentBodyPart partInfo] objectForKey: @"subtype"]];
|
||||||
[s appendFormat: @"<Data>%@</Data>", [[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context]];
|
|
||||||
|
|
||||||
[s appendString: @"</Properties>"];
|
if ([[theResponse headerForKey: @"Content-Type"] isEqualToString:@"application/vnd.ms-sync.multipart"])
|
||||||
[s appendString: @"</Fetch>"];
|
{
|
||||||
|
[s appendFormat: @"<Part>%d</Part>", i+1];
|
||||||
|
[partLength addObject: [NSNumber numberWithInteger: [[currentBodyPart fetchBLOB] length]]];
|
||||||
|
[parts appendData:[currentBodyPart fetchBLOB]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[s appendFormat: @"<Range>0-%d</Range>", [[[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context] length]-1];
|
||||||
|
[s appendFormat: @"<Data>%@</Data>", [[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[s appendString: @"</Properties>"];
|
||||||
|
[s appendString: @"</Fetch>"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[theResponse setStatus: 500];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[s appendString: @"</Response>"];
|
[s appendString: @"</Response>"];
|
||||||
[s appendString: @"</ItemOperations>"];
|
[s appendString: @"</ItemOperations>"];
|
||||||
|
|
||||||
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||||
[theResponse setContent: d];
|
|
||||||
}
|
if ([[theResponse headerForKey: @"Content-Type"] isEqualToString:@"application/vnd.ms-sync.multipart"])
|
||||||
else
|
{
|
||||||
{
|
uint32_t PartCount;
|
||||||
[theResponse setStatus: 500];
|
uint32_t Offset;
|
||||||
|
uint32_t Len;
|
||||||
|
|
||||||
|
// 2.2.2.9.1.1 - MultiPartResponse -- http://msdn.microsoft.com/en-us/library/jj663270%28v=exchg.80%29.aspx
|
||||||
|
PartCount = [partLength count] + 1;
|
||||||
|
Offset = ((PartCount) * 2) * 4 + 4;
|
||||||
|
Len = [d length];
|
||||||
|
|
||||||
|
[bytes appendBytes: &PartCount length: 4];
|
||||||
|
[bytes appendBytes: &Offset length: 4];
|
||||||
|
[bytes appendBytes: &Len length: 4];
|
||||||
|
|
||||||
|
// 2.2.2.9.1.1.1 - PartMetaData -- http://msdn.microsoft.com/en-us/library/jj663267%28v=exchg.80%29.aspx
|
||||||
|
for (i = 0; i < [fetchRequests count]; i++)
|
||||||
|
{
|
||||||
|
Offset = Offset + Len;
|
||||||
|
Len = [[partLength objectAtIndex:i] intValue];
|
||||||
|
[bytes appendBytes: &Offset length: 4];
|
||||||
|
[bytes appendBytes: &Len length: 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
// First part - webxml
|
||||||
|
[bytes appendData: d];
|
||||||
|
|
||||||
|
// Subsequent parts - requested data
|
||||||
|
[bytes appendData: parts];
|
||||||
|
|
||||||
|
[theResponse setContent: bytes];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[theResponse setContent: d];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2538,19 +2604,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Ping or Sync command with empty body
|
// Ping or Sync command with empty body
|
||||||
cmdName = [NSString stringWithFormat: @"process%@:inResponse:", cmdName];
|
cmdName = [NSString stringWithFormat: @"process%@:inResponse:", cmdName];
|
||||||
}
|
}
|
||||||
|
|
||||||
aSelector = NSSelectorFromString(cmdName);
|
aSelector = NSSelectorFromString(cmdName);
|
||||||
|
|
||||||
|
// The -processItemOperations: method will generate a multipart response when Content-Type is application/vnd.ms-sync.multipart
|
||||||
|
if ([[theRequest headerForKey: @"MS-ASAcceptMultiPart"] isEqualToString:@"T"])
|
||||||
|
[theResponse setHeader: @"application/vnd.ms-sync.multipart" forKey: @"Content-Type"];
|
||||||
|
else
|
||||||
|
[theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"];
|
||||||
|
|
||||||
[self performSelector: aSelector withObject: documentElement withObject: theResponse];
|
[self performSelector: aSelector withObject: documentElement withObject: theResponse];
|
||||||
|
|
||||||
[theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"];
|
|
||||||
[theResponse setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
|
[theResponse setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
|
||||||
[theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
[theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||||
[theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
[theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||||
|
|
||||||
RELEASE(context);
|
RELEASE(context);
|
||||||
RELEASE(pool);
|
RELEASE(pool);
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
NEWS
1
NEWS
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
- MultipleBookingsFieldName can be set to -1 to show busy status when booked at least once
|
- MultipleBookingsFieldName can be set to -1 to show busy status when booked at least once
|
||||||
|
- handle multipart objects in EAS/ItemOperations
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
- fixed calendar selection in event and task editors (#3049, #3050)
|
- fixed calendar selection in event and task editors (#3049, #3050)
|
||||||
|
|
Loading…
Reference in New Issue