From 2974a91c5ed296948f881a78f065af2af2f002fc Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 7 Jun 2011 00:17:46 +0000 Subject: [PATCH] Monotone-Parent: a1865313ff7142cbf139f7645dcbb299dd1acb92 Monotone-Revision: 06779f0bbfe40e7611b69790cf2eff4809382438 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-06-07T00:17:46 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 11 ++ OpenChange/MAPIStoreCalendarMessage.h | 5 - OpenChange/MAPIStoreCalendarMessage.m | 140 +++++++++------- OpenChange/MAPIStoreContext.h | 9 + OpenChange/MAPIStoreContext.m | 192 +++++++++++++++------ OpenChange/MAPIStoreDraftsMessage.m | 24 +++ OpenChange/MAPIStoreFAIMessage.m | 5 + OpenChange/MAPIStoreFAIMessageTable.m | 7 + OpenChange/MAPIStoreFSFolder.m | 78 +++++++++ OpenChange/MAPIStoreFSMessage.m | 93 ++++++++++ OpenChange/MAPIStoreFolder.h | 13 +- OpenChange/MAPIStoreFolder.m | 233 +++++++++++++++++++++----- OpenChange/MAPIStoreGCSFolder.m | 11 +- OpenChange/MAPIStoreGCSMessage.m | 17 ++ OpenChange/MAPIStoreMailFolder.h | 5 + OpenChange/MAPIStoreMailFolder.m | 79 +++++---- OpenChange/MAPIStoreMailMessage.m | 56 ++++--- OpenChange/MAPIStoreMessage.m | 74 +++----- OpenChange/MAPIStoreObject.h | 20 ++- OpenChange/MAPIStoreObject.m | 108 ++++++++++-- OpenChange/MAPIStoreTable.m | 5 +- OpenChange/MAPIStoreTasksMessage.h | 5 - OpenChange/MAPIStoreTasksMessage.m | 64 +++---- 23 files changed, 923 insertions(+), 331 deletions(-) diff --git a/ChangeLog b/ChangeLog index c25de6398..c39a0daa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2011-06-06 Wolfgang Sourdeau + * OpenChange/*: + - (context) cached last requested folder and table + - (context) open folders are now cached in an nsdictionary + - getPrLastModificationTime and getPrCreationTime are now + centralized in MAPIStoreObject and rely on mandator lastModificationTime + and creationTime methods on individual subclasses. + - openMessage now takes a "struct mapistore_message **" argument. + - MAPIStoreFSFolder can now create subfolders + - converted MAPIStoreFolder to the new property API, by + implementing one method per property. + * OpenChange/MAPIStoreMailMessage.m: (-getPrExpiryTime:) removed method as we don't want the message to appear as "expired". (-getPrOriginalSensitivity:): uppercased the "o" in "getPrOriginal..." diff --git a/OpenChange/MAPIStoreCalendarMessage.h b/OpenChange/MAPIStoreCalendarMessage.h index 04a92712b..cfc6b1c5f 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -25,12 +25,7 @@ #import "MAPIStoreGCSMessage.h" -@class iCalEvent; - @interface MAPIStoreCalendarMessage : MAPIStoreGCSMessage -{ - iCalEvent *event; -} @end diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index db208d4f7..7edfe631d 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -73,36 +73,17 @@ static NSTimeZone *utcTZ; [utcTZ retain]; } -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer -{ - if ((self = [super initWithSOGoObject: newSOGoObject - inContainer: newContainer])) - { - ASSIGN (event, [newSOGoObject component: NO secure: NO]); - } - - return self; -} - - (id) init { if ((self = [super init])) { attachmentKeys = [NSMutableArray new]; attachmentParts = [NSMutableDictionary new]; - event = nil; } return self; } -- (void) dealloc -{ - [event release]; - [super dealloc]; -} - - (NSTimeZone *) ownerTimeZone { NSString *owner; @@ -124,6 +105,9 @@ static NSTimeZone *utcTZ; struct Binary_r *blob; struct AppointmentRecurrencePattern *pattern; NSMutableArray *otherEvents; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; /* cleanup */ otherEvents = [[calendar events] mutableCopy]; @@ -169,7 +153,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, struct SBinary_short *sBin; NSCalendarDate *firstStartDate; iCalRecurrenceRule *rule; + iCalEvent *event; + event = [sogoObject component: NO secure: NO]; rule = [[event recurrenceRules] objectAtIndex: 0]; firstStartDate = [event firstRecurrenceStartDate]; @@ -204,6 +190,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPrIconIndex: (void **) data // TODO { uint32_t longValue; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; /* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ // *longValue = 0x00000401 for recurring event @@ -232,6 +221,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPrStartDate: (void **) data { NSCalendarDate *dateValue; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; if ([event isRecurrent]) dateValue = [event firstRecurrenceStartDate]; @@ -256,6 +248,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPrEndDate: (void **) data { NSCalendarDate *dateValue; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; if ([event isRecurrent]) dateValue = [event firstRecurrenceStartDate]; @@ -285,6 +280,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidAppointmentDuration: (void **) data { NSTimeInterval timeValue; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; timeValue = [[event endDate] timeIntervalSinceDate: [event startDate]]; *data = MAPILongValue (memCtx, (uint32_t) (timeValue / 60)); @@ -294,6 +292,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidAppointmentSubType: (void **) data { + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; *data = MAPIBoolValue (memCtx, [event isAllDay]); return MAPISTORE_SUCCESS; @@ -308,6 +309,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPrSubject: (void **) data // SUMMARY { + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; *data = [[event summary] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -315,6 +319,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidLocation: (void **) data // LOCATION { + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; *data = [[event location] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -331,17 +338,12 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, return [self getLongZero: data]; } -- (int) getPrCreationTime: (void **) data -{ - *data = [[event created] asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - - (int) getPrImportance: (void **) data { uint32_t v; + iCalEvent *event; + event = [sogoObject component: NO secure: NO]; if ([[event priority] isEqualToString: @"9"]) v = 0x0; else if ([[event priority] isEqualToString: @"1"]) @@ -356,6 +358,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidIsRecurring: (void **) data { + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; *data = MAPIBoolValue (memCtx, [event isRecurrent]); return MAPISTORE_SUCCESS; @@ -363,6 +368,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidRecurring: (void **) data { + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; *data = MAPIBoolValue (memCtx, [event isRecurrent]); return MAPISTORE_SUCCESS; @@ -371,6 +379,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (int) getPidLidAppointmentRecur: (void **) data { int rc = MAPISTORE_SUCCESS; + iCalEvent *event; + + event = [sogoObject component: NO secure: NO]; if ([event isRecurrent]) *data = [self _computeAppointmentRecur]; @@ -382,50 +393,57 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - (void) openMessage: (struct mapistore_message *) msg { - NSString *name, *email; + NSString *text; NSArray *attendees; iCalPerson *person; struct SRowSet *recipients; int count, max; + iCalEvent *event; [super openMessage: msg]; + + event = [sogoObject component: NO secure: NO]; attendees = [event attendees]; max = [attendees count]; - recipients = msg->recipients; + recipients = talloc_zero (memCtx, struct SRowSet); recipients->cRows = max; recipients->aRow = talloc_array (recipients, struct SRow, max); - for (count = 0; count < max; count++) { recipients->aRow[count].ulAdrEntryPad = 0; recipients->aRow[count].cValues = 3; recipients->aRow[count].lpProps = talloc_array (recipients->aRow, struct SPropValue, - 3); + 4); // TODO (0x01 = primary recipient) - set_SPropValue_proptag (&(recipients->aRow[count].lpProps[0]), + set_SPropValue_proptag (recipients->aRow[count].lpProps, PR_RECIPIENT_TYPE, - MAPILongValue (memCtx, 0x01)); - + MAPILongValue (recipients->aRow[count].lpProps, 0x01)); + + set_SPropValue_proptag (recipients->aRow[count].lpProps + 1, + PR_ADDRTYPE_UNICODE, + [@"SMTP" asUnicodeInMemCtx: recipients->aRow]); + person = [attendees objectAtIndex: count]; - - name = [person cn]; - if (!name) - name = @""; - - email = [person email]; - if (!email) - email = @""; - - set_SPropValue_proptag (&(recipients->aRow[count].lpProps[1]), - PR_DISPLAY_NAME, - [name asUnicodeInMemCtx: recipients->aRow[count].lpProps]); - set_SPropValue_proptag (&(recipients->aRow[count].lpProps[2]), - PR_EMAIL_ADDRESS, - [email asUnicodeInMemCtx: recipients->aRow[count].lpProps]); + text = [person rfc822Email]; + if (!text) + text = @""; + set_SPropValue_proptag (recipients->aRow[count].lpProps + 2, + PR_EMAIL_ADDRESS_UNICODE, + [text asUnicodeInMemCtx: recipients->aRow]); + + text = [person cn]; + if ([text length] > 0) + { + recipients->aRow[count].cValues++; + set_SPropValue_proptag (recipients->aRow[count].lpProps + 3, + PR_DISPLAY_NAME_UNICODE, + [text asUnicodeInMemCtx: recipients->aRow]); + } } + msg->recipients = recipients; } - (void) save @@ -446,28 +464,24 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, if (![content length]) { newEvent = [sogoObject component: YES secure: NO]; - if (newEvent != event) - ASSIGN (event, newEvent); - vCalendar = [event parent]; + vCalendar = [newEvent parent]; [vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; content = [vCalendar versitString]; } vCalendar = [iCalCalendar parseSingleFromSource: content]; newEvent = [[vCalendar events] objectAtIndex: 0]; - if (newEvent != event) - ASSIGN (event, newEvent); // summary value = [newProperties objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)]; if (value) - [event setSummary: value]; + [newEvent setSummary: value]; // Location value = [newProperties objectForKey: MAPIPropertyKey (PidLidLocation)]; if (value) - [event setLocation: value]; + [newEvent setLocation: value]; tzName = [[self ownerTimeZone] name]; tz = [iCalTimeZone timeZoneForName: tzName]; @@ -479,7 +493,7 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, value = [newProperties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; if (value) { - start = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"]; + start = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtstart"]; [start setTimeZone: tz]; [start setDateTime: value]; } @@ -490,7 +504,7 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, value = [newProperties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)]; if (value) { - end = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"]; + end = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtend"]; [end setTimeZone: tz]; [end setDateTime: value]; } @@ -498,9 +512,9 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, now = [NSCalendarDate date]; if ([sogoObject isNew]) { - [event setCreated: now]; + [newEvent setCreated: now]; } - [event setTimeStampAsDate: now]; + [newEvent setTimeStampAsDate: now]; // Organizer and attendees value = [newProperties objectForKey: @"recipients"]; @@ -517,7 +531,7 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, person = [iCalPerson new]; [person setCn: [dict objectForKey: @"fullName"]]; [person setEmail: [dict objectForKey: @"email"]]; - [event setOrganizer: person]; + [newEvent setOrganizer: person]; [person release]; recipients = [value objectForKey: @"to"]; @@ -534,8 +548,8 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, [person setRole: @"REQ-PARTICIPANT"]; // FIXME: We must NOT always rely on this - if (![event isAttendee: [person rfc822Email]]) - [event addToAttendees: person]; + if (![newEvent isAttendee: [person rfc822Email]]) + [newEvent addToAttendees: person]; [person release]; } @@ -549,7 +563,7 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, fromData: value]; // [sogoObject saveContentString: [vCalendar versitString]]; - [sogoObject saveComponent: event]; + [sogoObject saveComponent: newEvent]; } /* TODO: those are stubs meant to prevent OpenChange from crashing when a diff --git a/OpenChange/MAPIStoreContext.h b/OpenChange/MAPIStoreContext.h index d8bb94e71..1a6bf3b8f 100644 --- a/OpenChange/MAPIStoreContext.h +++ b/OpenChange/MAPIStoreContext.h @@ -62,6 +62,15 @@ /* for active messages (NSDictionary instances) */ NSMutableDictionary *messages; + + /* for active folders (NSDictionary instances) */ + NSMutableDictionary *folders; + + /* hackish table cache */ + MAPIStoreTable *cachedTable; + MAPIStoreFolder *cachedFolder; + uint64_t cachedTableFID; + uint8_t cachedTableType; } + (id) contextFromURI: (const char *) newUri diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 2bb300ea5..d9dd013e6 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -136,6 +136,8 @@ _prepareContextClass (struct mapistore_context *newMemCtx, [context setupRequest]; [context setupBaseFolder: url]; + [context->folders setObject: context->baseFolder + forKey: [NSNumber numberWithUnsignedLongLong: fid]]; [context tearDownRequest]; return context; @@ -192,14 +194,15 @@ _prepareContextClass (struct mapistore_context *newMemCtx, if ((self = [super init])) { messages = [NSMutableDictionary new]; + folders = [NSMutableDictionary new]; woContext = [WOContext contextWithRequest: nil]; [woContext retain]; baseFolder = nil; contextUrl = nil; + cachedTable = nil; + cachedFolder = nil; } - [self logWithFormat: @"-init"]; - return self; } @@ -244,9 +247,10 @@ _prepareContextClass (struct mapistore_context *newMemCtx, - (void) dealloc { - [self logWithFormat: @"-dealloc"]; - [messages release]; + [folders release]; + [cachedTable release]; + [cachedFolder release]; [baseFolder release]; [woContext release]; @@ -305,10 +309,78 @@ _prepareContextClass (struct mapistore_context *newMemCtx, [MAPIApp setMAPIStoreContext: nil]; } -- (MAPIStoreFolder *) lookupFolder: (NSString *) folderURL +- (MAPIStoreObject *) _lookupObjectWithParts: (NSArray *) parts { + NSUInteger count, max; + NSString *currentPart; + MAPIStoreObject *currentObject; + + currentObject = baseFolder; + max = [parts count]; + for (count = 0; count < max; count++) + { + currentPart = [parts objectAtIndex: count]; + if ([currentPart length] > 0) + currentObject = [currentObject lookupChild: currentPart]; + } + + return currentObject; +} + +- (id) lookupObject: (NSString *) childURL +{ + NSString *baseURL, *subURL; + MAPIStoreObject *foundObject; + NSArray *parts; + + baseURL = [contextUrl absoluteString]; + if (![baseURL hasSuffix: @"/"]) + baseURL = [NSString stringWithFormat: @"%@/", baseURL]; + if (![childURL hasSuffix: @"/"]) + childURL = [NSString stringWithFormat: @"%@/", childURL]; + if ([childURL isEqualToString: baseURL]) + foundObject = baseFolder; + else if ([childURL hasPrefix: baseURL]) + { + subURL = [childURL substringFromIndex: [baseURL length]]; + parts = [subURL componentsSeparatedByString: @"/"]; + foundObject = [self _lookupObjectWithParts: parts]; + [self logWithFormat: @"returning object '%@'", childURL]; + } + else + { + [self errorWithFormat: @"url '%@' is not a child of this context (%@)", + childURL, baseURL]; + foundObject = nil; + } + /* TODO hierarchy */ - return baseFolder; + return foundObject; +} + +- (id) lookupFolderWithFID: (uint64_t) fid +{ + MAPIStoreFolder *folder; + NSNumber *fidKey; + NSString *folderURL; + + fidKey = [NSNumber numberWithUnsignedLongLong: fid]; + folder = [folders objectForKey: fidKey]; + if (!folder) + { + /* TODO: should handle folder hierarchies */ + folderURL = [mapping urlFromID: fid]; + if (folderURL) + { + folder = [self lookupObject: folderURL]; + if (folder) + [folders setObject: folder forKey: fidKey]; + } + else + [self errorWithFormat: @"folder with url '%@' not found", folderURL]; + } + + return folder; } /** @@ -323,8 +395,8 @@ _prepareContextClass (struct mapistore_context *newMemCtx, withFID: (uint64_t) fid inParentFID: (uint64_t) parentFID { - NSString *folderURL, *folderKey, *parentFolderURL; - MAPIStoreFolder *parentFolder; + NSString *folderURL, *folderKey; + MAPIStoreFolder *parentFolder, *newFolder; int rc; [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; @@ -334,16 +406,22 @@ _prepareContextClass (struct mapistore_context *newMemCtx, rc = MAPISTORE_ERR_EXIST; else { - parentFolderURL = [mapping urlFromID: parentFID]; - if (parentFolderURL) + parentFolder = [self lookupFolderWithFID: parentFID]; + if (parentFolder) { - parentFolder = [self lookupFolder: parentFolderURL]; - folderKey = [parentFolder createFolder: aRow]; + folderKey = [parentFolder createFolder: aRow withFID: fid]; if (folderKey) { - folderURL = [NSString stringWithFormat: @"%@%@/", - parentFolderURL, folderKey]; + [parentFolder cleanupCaches]; + folderURL = [NSString stringWithFormat: @"%@%@", + [parentFolder url], folderKey]; [mapping registerURL: folderURL withID: fid]; + newFolder = [parentFolder lookupChild: folderKey]; + if (newFolder) + [newFolder setProperties: aRow]; + else + [NSException raise: @"MAPIStoreIOException" + format: @"unable to fetch created folder"]; rc = MAPISTORE_SUCCESS; } else @@ -413,13 +491,19 @@ _prepareContextClass (struct mapistore_context *newMemCtx, { MAPIStoreFolder *folder; MAPIStoreTable *table; - NSString *folderURL; -/* TODO: should handle folder hierarchies */ - folderURL = [mapping urlFromID: fid]; - if (folderURL) + if (fid == cachedTableFID && tableType == cachedTableType) + table = cachedTable; + else { - folder = [self lookupFolder: folderURL]; + [cachedTable release]; + cachedTable = nil; + [cachedFolder release]; + cachedFolder = nil; + cachedTableFID = 0; + cachedTableType = 0; + + folder = [self lookupFolderWithFID: fid]; if (folder) { if (tableType == MAPISTORE_MESSAGE_TABLE) @@ -432,21 +516,24 @@ _prepareContextClass (struct mapistore_context *newMemCtx, { table = nil; [NSException raise: @"MAPIStoreIOException" - format: @"unsupported table type: %d", tableType]; + format: @"unsupported table type: %d", tableType]; + } + + if (table) + { + cachedTableFID = fid; + cachedTableType = tableType; + ASSIGN (cachedTable, table); + ASSIGN (cachedFolder, folder); } } else { table = nil; - [self errorWithFormat: @"folder with url '%@' not found", folderURL]; + [self errorWithFormat: @"folder with fid %Lu not found", + (unsigned long long) fid]; } } - else - { - table = nil; - [self errorWithFormat: @"folder with fid %Lu not found", - (unsigned long long) fid]; - } return table; } @@ -475,7 +562,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, url = [mapping urlFromID: fid]; if (url) { - folder = [self lookupFolder: url]; + folder = [self lookupFolderWithFID: fid]; if (folder) { if (tableType == MAPISTORE_MESSAGE_TABLE) @@ -559,16 +646,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, const char *propName; int rc; - [self errorWithFormat: @"%s: obsolete method", __FUNCTION__]; - - // [self logWithFormat: @"METHOD '%s' (%d) -- proptag: %s (0x%.8x), pos: %.8x," - // @" tableType: %d, queryType: %d, fid: %.16x", - // __FUNCTION__, __LINE__, propName, proptag, pos, tableType, queryType, fid]; - - // [self logWithFormat: @"context restriction state is: %@", - // MAPIStringForRestrictionState (restrictionState)]; - // if (restriction) - // [self logWithFormat: @" active qualifier: %@", restriction]; + // [self errorWithFormat: @"%s: obsolete method", __FUNCTION__]; folderURL = [mapping urlFromID: fid]; if (folderURL) @@ -642,7 +720,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, withMID: (uint64_t) mid inFID: (uint64_t) fid { - NSString *messageKey, *folderURL, *messageURL; + NSString *messageKey, *messageURL; MAPIStoreMessage *message; MAPIStoreFolder *folder; NSNumber *midKey; @@ -659,9 +737,9 @@ _prepareContextClass (struct mapistore_context *newMemCtx, messageURL = [mapping urlFromID: mid]; if (messageURL) { + folder = [self lookupFolderWithFID: fid]; messageKey = [self extractChildNameFromURL: messageURL - andFolderURLAt: &folderURL]; - folder = [self lookupFolder: folderURL]; + andFolderURLAt: NULL]; message = [folder lookupChild: messageKey]; if (message) { @@ -681,7 +759,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, isAssociated: (BOOL) isAssociated { NSNumber *midKey; - NSString *folderURL, *childURL; + NSString *childURL; MAPIStoreMessage *message; MAPIStoreFolder *folder; int rc; @@ -695,17 +773,16 @@ _prepareContextClass (struct mapistore_context *newMemCtx, rc = MAPISTORE_ERR_EXIST; else { - folderURL = [mapping urlFromID: fid]; - if (folderURL) + folder = [self lookupFolderWithFID: fid]; + if (folder) { - folder = [self lookupFolder: folderURL]; message = [folder createMessage: isAssociated]; if (message) { [messages setObject: message forKey: midKey]; [message setMAPIRetainCount: [message mapiRetainCount] + 1]; childURL = [NSString stringWithFormat: @"%@%@", - folderURL, [message nameInContainer]]; + [folder url], [message nameInContainer]]; [mapping registerURL: childURL withID: mid]; rc = MAPISTORE_SUCCESS; } @@ -749,6 +826,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, { rc = MAPISTORE_SUCCESS; folder = (MAPIStoreFolder *) [message container]; + [self logWithFormat: @"folder for message is: %p", folder]; if (isSave) { /* notifications */ @@ -985,6 +1063,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, inRow: (struct SRow *) aRow { MAPIStoreMessage *message; + MAPIStoreFolder *folder; NSMutableDictionary *properties; NSNumber *midKey; struct SPropValue *cValue; @@ -1023,9 +1102,11 @@ _prepareContextClass (struct mapistore_context *newMemCtx, } break; case MAPISTORE_FOLDER: - [self logWithFormat: @"%s: ignored setting of props on folders", - __FUNCTION__]; - rc = MAPISTORE_SUCCESS; + folder = [self lookupFolderWithFID: fmid]; + if (folder) + rc = [folder setProperties: aRow]; + else + rc = MAPISTORE_ERR_NOT_FOUND; break; default: [self errorWithFormat: @"%s: value of tableType not handled: %d", @@ -1152,7 +1233,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, inFID: (uint64_t) fid withFlags: (uint8_t) flags { - NSString *childURL, *folderURL, *childKey; + NSString *childURL, *childKey; MAPIStoreFolder *folder; MAPIStoreMessage *message; NSArray *activeTables; @@ -1167,9 +1248,10 @@ _prepareContextClass (struct mapistore_context *newMemCtx, { [self logWithFormat: @"-deleteMessageWithMID: url (%@) found for object", childURL]; + folder = [self lookupFolderWithFID: fid]; + childKey = [self extractChildNameFromURL: childURL - andFolderURLAt: &folderURL]; - folder = [self lookupFolder: folderURL]; + andFolderURLAt: NULL]; message = [folder lookupChild: childKey]; if (message) { @@ -1233,7 +1315,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, [[activeTables objectAtIndex: count] notifyChangesForChild: message]; } - [self logWithFormat: @"sucessfully deleted object at URL: %@", childURL]; + [self logWithFormat: @"successfully deleted object at URL: %@", childURL]; [mapping unregisterURLWithID: mid]; [folder cleanupCaches]; rc = MAPISTORE_SUCCESS; @@ -1431,10 +1513,10 @@ _prepareContextClass (struct mapistore_context *newMemCtx, *count = [[message childKeysMatchingQualifier: nil andSortOrderings: nil] count]; attTable = [message attachmentTable]; - *tablePtr = attTable; if (attTable) { [attTable retain]; + *tablePtr = attTable; rc = MAPISTORE_SUCCESS; } } @@ -1463,10 +1545,10 @@ _prepareContextClass (struct mapistore_context *newMemCtx, if (aid < [keys count]) { attachment = [message lookupChild: [keys objectAtIndex: aid]]; - *attachmentPtr = attachment; if (attachment) { [attachment retain]; + *attachmentPtr = attachment; rc = MAPISTORE_SUCCESS; } } diff --git a/OpenChange/MAPIStoreDraftsMessage.m b/OpenChange/MAPIStoreDraftsMessage.m index 82b51fcc2..e3183da79 100644 --- a/OpenChange/MAPIStoreDraftsMessage.m +++ b/OpenChange/MAPIStoreDraftsMessage.m @@ -37,6 +37,7 @@ #include #include +#include @implementation MAPIStoreDraftsMessage @@ -51,6 +52,19 @@ return self; } +- (int) getPrMessageFlags: (void **) data +{ + unsigned int v = MSGFLAG_FROMME; + + if ([[self childKeysMatchingQualifier: nil + andSortOrderings: nil] count] > 0) + v |= MSGFLAG_HASATTACH; + + *data = MAPILongValue (memCtx, v); + + return MAPISTORE_SUCCESS; +} + - (void) _saveAttachment: (NSString *) attachmentKey { NSDictionary *properties, *metadata; @@ -233,4 +247,14 @@ e) [self logWithFormat: @"ignored scheduling message"]; } +- (NSCalendarDate *) creationTime +{ + return [newProperties objectForKey: MAPIPropertyKey (PR_CREATION_TIME)]; +} + +- (NSCalendarDate *) lastModificationTime +{ + return [newProperties objectForKey: MAPIPropertyKey (PR_LAST_MODIFICATION_TIME)]; +} + @end diff --git a/OpenChange/MAPIStoreFAIMessage.m b/OpenChange/MAPIStoreFAIMessage.m index c48431de8..10fb4e600 100644 --- a/OpenChange/MAPIStoreFAIMessage.m +++ b/OpenChange/MAPIStoreFAIMessage.m @@ -24,4 +24,9 @@ @implementation MAPIStoreFAIMessage +- (int) getPrAssociated: (void **) data +{ + return [self getYes: data]; +} + @end diff --git a/OpenChange/MAPIStoreFAIMessageTable.m b/OpenChange/MAPIStoreFAIMessageTable.m index 956be332a..9e931a631 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.m +++ b/OpenChange/MAPIStoreFAIMessageTable.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#import "MAPIStoreFolder.h" + #import "MAPIStoreFAIMessageTable.h" #undef DEBUG @@ -37,4 +39,9 @@ return self; } +- (NSArray *) childKeys +{ + return [(MAPIStoreFolder *) container faiMessageKeys]; +} + @end diff --git a/OpenChange/MAPIStoreFSFolder.m b/OpenChange/MAPIStoreFSFolder.m index 81979fe22..f68fe5103 100644 --- a/OpenChange/MAPIStoreFSFolder.m +++ b/OpenChange/MAPIStoreFSFolder.m @@ -22,11 +22,14 @@ #import #import +#import #import #import "EOQualifier+MAPIFS.h" #import "MAPIStoreFSMessage.h" #import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreFolderTable.h" +#import "MAPIStoreTypes.h" #import "SOGoMAPIFSFolder.h" #import "SOGoMAPIFSMessage.h" @@ -71,6 +74,22 @@ static Class MAPIStoreFSMessageK; return MAPIStoreFSMessageK; } +- (NSString *) createFolder: (struct SRow *) aRow + withFID: (uint64_t) newFID +{ + NSString *newKey, *urlString; + SOGoMAPIFSFolder *childFolder; + + newKey = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; + + urlString = [NSString stringWithFormat: @"%@/%@", [self url], newKey]; + childFolder = [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: urlString] + andTableType: MAPISTORE_MESSAGE_TABLE]; + [childFolder ensureDirectory]; + + return newKey; +} + - (MAPIStoreMessage *) createMessage { MAPIStoreMessage *newMessage; @@ -122,4 +141,63 @@ static Class MAPIStoreFSMessageK; return keys; } +- (NSArray *) folderKeys +{ + if (!folderKeys) + ASSIGN (folderKeys, [sogoObject toManyRelationshipKeys]); + + return folderKeys; +} + +- (id) lookupChild: (NSString *) childKey +{ + id childObject; + SOGoMAPIFSFolder *childFolder; + + [self folderKeys]; + if ([folderKeys containsObject: childKey]) + { + childFolder = [sogoObject lookupName: childKey inContext: nil + acquire: NO]; + childObject = [MAPIStoreFSFolder mapiStoreObjectWithSOGoObject: childFolder + inContainer: self]; + } + else + childObject = [super lookupChild: childKey]; + + return childObject; +} + +- (MAPIStoreFAIMessageTable *) folderTable +{ + return [MAPIStoreFolderTable tableForContainer: self]; +} + +- (NSDate *) lastMessageModificationTime +{ + NSUInteger count, max; + NSDate *date, *fileDate; + MAPIStoreFSMessage *msg; + + [self messageKeys]; + + date = [NSCalendarDate date]; + [self logWithFormat: @"current date: %@", date]; + + max = [messageKeys count]; + for (count = 0; count < max; count++) + { + msg = [self lookupChild: [messageKeys objectAtIndex: count]]; + fileDate = [msg lastModificationTime]; + if ([date laterDate: fileDate] == fileDate) + { + [self logWithFormat: @"current date: %@", date]; + + date = fileDate; + } + } + + return date; +} + @end diff --git a/OpenChange/MAPIStoreFSMessage.m b/OpenChange/MAPIStoreFSMessage.m index 441cf9002..bd63052c4 100644 --- a/OpenChange/MAPIStoreFSMessage.m +++ b/OpenChange/MAPIStoreFSMessage.m @@ -20,16 +20,49 @@ * Boston, MA 02111-1307, USA. */ +#import +#import #import +#import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" #import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" #import "SOGoMAPIFSMessage.h" #import "MAPIStoreFSMessage.h" +#undef DEBUG +#include + @implementation MAPIStoreFSMessage ++ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP +{ + struct SPropTagArray *properties; + NSUInteger count; + enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102, + 0x683f0102, 0x68410003, 0x68420102, + 0x68450102, 0x68460003 }; + + properties = talloc_zero (NULL, struct SPropTagArray); + properties->cValues = MAPIStoreSupportedPropertiesCount + 8; + properties->aulPropTag = talloc_array (NULL, enum MAPITAGS, + MAPIStoreSupportedPropertiesCount + 8); + + for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) + properties->aulPropTag[count] = MAPIStoreSupportedProperties[count]; + + /* FIXME (hack): append a few undocumented properties that can be added to + FAI messages */ + for (count = 0; count < 8; count++) + properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] = faiProperties[count]; + + *propertiesP = properties; + + return MAPISTORE_SUCCESS; +} + - (enum MAPISTATUS) getProperty: (void **) data withTag: (enum MAPITAGS) propTag { @@ -45,10 +78,70 @@ return rc; } +- (int) getPrSubject: (void **) data +{ + /* if we get here, it means that the properties file didn't contain a + relevant value */ + return [self getEmptyString: data]; +} + +- (int) getPrMessageClass: (void **) data +{ + /* if we get here, it means that the properties file didn't contain a + relevant value */ + + *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP +{ + NSArray *keys; + NSUInteger count, max; + struct SPropTagArray *properties; + + keys = [[sogoObject properties] allKeys]; + max = [keys count]; + + properties = talloc_zero (NULL, struct SPropTagArray); + properties->cValues = max; + properties->aulPropTag = talloc_array (properties, enum MAPITAGS, max); + for (count = 0; count < max; count++) + { +// #if (GS_SIZEOF_LONG == 4) +// return [NSNumber numberWithUnsignedLong: propTag]; +// #elif (GS_SIZEOF_INT == 4) +// return [NSNumber numberWithUnsignedInt: propTag]; +// #else + +#if (GS_SIZEOF_LONG == 4) + properties->aulPropTag[count] = [[keys objectAtIndex: count] unsignedLongValue]; +#elif (GS_SIZEOF_INT == 4) + properties->aulPropTag[count] = [[keys objectAtIndex: count] unsignedIntValue]; +#endif + } + + *propertiesP = properties; + + return MAPISTORE_SUCCESS; +} + - (void) save { [sogoObject appendProperties: newProperties]; [sogoObject save]; + [self resetNewProperties]; +} + +- (NSDate *) creationTime +{ + return [sogoObject creationTime]; +} + +- (NSDate *) lastModificationTime +{ + return [sogoObject lastModificationTime]; } @end diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 4c95e0e30..4f663441f 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -38,6 +38,7 @@ @class MAPIStoreFolderTable; @class MAPIStoreMessageTable; @class SOGoMAPIFSFolder; +@class SOGoMAPIFSMessage; #import "MAPIStoreObject.h" @@ -49,10 +50,11 @@ NSArray *faiMessageKeys; NSMutableArray *folderKeys; - SOGoMAPIFSFolder *faiFolder; + NSDictionary *properties; - NSMutableArray *activeMessageTables; - NSMutableArray *activeFAIMessageTables; + SOGoMAPIFSFolder *faiFolder; + SOGoMAPIFSFolder *propsFolder; + SOGoMAPIFSMessage *propsMessage; } + (id) baseFolderWithURL: (NSURL *) newURL @@ -73,7 +75,8 @@ - (NSArray *) folderKeys; - (MAPIStoreMessage *) createMessage: (BOOL) isAssociated; -- (NSString *) createFolder: (struct SRow *) aRow; +- (NSString *) createFolder: (struct SRow *) aRow + withFID: (uint64_t) newFID; /* helpers */ - (uint64_t) idForObjectWithKey: (NSString *) childKey; @@ -82,6 +85,8 @@ - (Class) messageClass; - (MAPIStoreMessage *) createMessage; +- (NSCalendarDate *) lastMessageModificationTime; + @end #endif /* MAPISTOREFOLDER_H */ diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 8e8739009..2bfc24273 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -23,6 +23,7 @@ /* TODO: main key arrays must be initialized */ #import +#import #import #import #import @@ -36,7 +37,9 @@ #import "MAPIStoreFolder.h" #import "MAPIStoreMessage.h" #import "MAPIStoreTypes.h" +#import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" +#import "NSObject+MAPIStore.h" #import "SOGoMAPIFSFolder.h" #import "SOGoMAPIFSMessage.h" @@ -45,7 +48,7 @@ #undef DEBUG #include #include -// #include +#include Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStoreFolderTableK; @@ -81,11 +84,14 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore folderURL = nil; context = nil; + propsFolder = nil; + propsMessage = nil; } return self; } +/* from context */ - (id) initWithURL: (NSURL *) newURL inContext: (MAPIStoreContext *) newContext { @@ -96,13 +102,71 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore ASSIGN (faiFolder, [SOGoMAPIFSFolder folderWithURL: newURL andTableType: MAPISTORE_FAI_TABLE]); + ASSIGN (propsFolder, + [SOGoMAPIFSFolder folderWithURL: newURL + andTableType: MAPISTORE_FOLDER_TABLE]); + ASSIGN (propsMessage, + [SOGoMAPIFSMessage objectWithName: @"properties.plist" + inContainer: propsFolder]); } return self; } +/* from parent folder */ +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + NSURL *propsURL; + + if ((self = [super initWithSOGoObject: newSOGoObject inContainer: newContainer])) + { + propsURL = [NSURL URLWithString: [self url]]; + ASSIGN (propsFolder, + [SOGoMAPIFSFolder folderWithURL: propsURL + andTableType: MAPISTORE_FOLDER_TABLE]); + ASSIGN (propsMessage, + [SOGoMAPIFSMessage objectWithName: @"properties.plist" + inContainer: propsFolder]); + } + + return self; +} + +- (int) setProperties: (struct SRow *) aRow +{ + static enum MAPITAGS bannedProps[] = { PR_MID, PR_FID, PR_PARENT_FID, + PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, + PR_CHANGE_NUM, PR_CHANGE_KEY, + 0x00000000 }; + enum MAPITAGS *currentProp; + int rc; + + rc = [super setProperties: aRow]; + + /* TODO: this should no longer be required once mapistore v2 API is in + place, when we can then do this from -dealloc below */ + if ([newProperties count] > 0) + { + currentProp = bannedProps; + while (*currentProp) + { + [newProperties removeObjectForKey: MAPIPropertyKey (*currentProp)]; + currentProp++; + } + + [propsMessage appendProperties: newProperties]; + [propsMessage save]; + [self resetNewProperties]; + } + + return rc; +} + - (void) dealloc { + [propsMessage release]; + [propsFolder release]; [folderURL release]; [messageKeys release]; [faiMessageKeys release]; @@ -209,8 +273,8 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore if ([faiMessageKeys containsObject: childKey]) { msgObject = [faiFolder lookupName: childKey - inContext: nil - acquire: NO]; + inContext: nil + acquire: NO]; newChild = [MAPIStoreFAIMessage mapiStoreObjectWithSOGoObject: msgObject inContainer: self]; @@ -218,8 +282,8 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore else { msgObject = [sogoObject lookupName: childKey - inContext: nil - acquire: NO]; + inContext: nil + acquire: NO]; if ([msgObject isKindOfClass: NSExceptionK]) msgObject = nil; @@ -237,48 +301,111 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore return newChild; } -- (enum MAPISTATUS) getProperty: (void **) data - withTag: (enum MAPITAGS) propTag +- (int) getPrParentFid: (void **) data +{ + *data = MAPILongLongValue (memCtx, [container objectId]); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrFid: (void **) data +{ + *data = MAPILongLongValue (memCtx, [self objectId]); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrAccess: (void **) data +{ + *data = MAPILongValue (memCtx, 0x63); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrAccessLevel: (void **) data +{ + *data = MAPILongValue (memCtx, 0x01); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrAttrHidden: (void **) data +{ + return [self getNo: data]; +} + +- (int) getPrAttrSystem: (void **) data +{ + return [self getNo: data]; +} + +- (int) getPrAttrReadOnly: (void **) data +{ + return [self getNo: data]; +} + +- (int) getPrSubfolders: (void **) data +{ + *data = MAPIBoolValue (memCtx, [folderKeys count] > 0); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrFolderChildCount: (void **) data; +{ + *data = MAPILongValue (memCtx, [[self folderKeys] count]); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrContentCount: (void **) data +{ + *data = MAPILongValue (memCtx, [[self messageKeys] count]); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrContentUnread: (void **) data +{ + *data = MAPILongValue (memCtx, 0); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrAssocContentCount: (void **) data +{ + *data = MAPILongValue (memCtx, [[self faiMessageKeys] count]); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrDeletedCountTotal: (void **) data +{ + /* TODO */ + *data = MAPILongValue (memCtx, 0); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrLocalCommitTimeMax: (void **) data +{ + *data = [[self lastMessageModificationTime] asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag { int rc; + id value; - rc = MAPI_E_SUCCESS; - switch (propTag) - { - case PR_FID: - /* TODO: incomplete */ - *data = MAPILongValue (memCtx, [self objectId]); - break; - case PR_ACCESS: // TODO - *data = MAPILongValue (memCtx, 0x63); - break; - case PR_ACCESS_LEVEL: // TODO - *data = MAPILongValue (memCtx, 0x01); - break; - case PR_PARENT_FID: - *data = MAPILongLongValue (memCtx, [container objectId]); - break; - case PR_ATTR_HIDDEN: - case PR_ATTR_SYSTEM: - case PR_ATTR_READONLY: - *data = MAPIBoolValue (memCtx, NO); - break; - case PR_SUBFOLDERS: - *data = MAPIBoolValue (memCtx, [folderKeys count]); - // [[child toManyRelationshipKeys] count] > 0); - break; - case PR_CONTENT_COUNT: - *data = MAPILongValue (memCtx, [messageKeys count]); - break; - // case PR_EXTENDED_FOLDER_FLAGS: // TODO: DOUBT: how to indicate the - // // number of subresponses ? - // binaryValue = talloc_zero(memCtx, struct Binary_r); - // *data = binaryValue; - // break; - default: - rc = [super getProperty: data - withTag: propTag]; - } + value = [[propsMessage properties] + objectForKey: MAPIPropertyKey (propTag)]; + if (value) + rc = [value getMAPIValue: data forTag: propTag inMemCtx: memCtx]; + else + rc = [super getProperty: data withTag: propTag]; return rc; } @@ -313,6 +440,7 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore } - (NSString *) createFolder: (struct SRow *) aRow + withFID: (uint64_t) newFID { [self errorWithFormat: @"new folders cannot be created in this context"]; @@ -351,6 +479,16 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore inFolderURL: [self url]]; } +- (NSCalendarDate *) creationTime +{ + return [propsMessage creationTime]; +} + +- (NSCalendarDate *) lastModificationTime +{ + return [propsMessage lastModificationTime]; +} + /* subclasses */ - (MAPIStoreMessageTable *) messageTable @@ -371,4 +509,11 @@ Class NSExceptionK, MAPIStoreMessageTableK, MAPIStoreFAIMessageTableK, MAPIStore return nil; } +- (NSCalendarDate *) lastMessageModificationTime +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + @end diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index 64882d8c8..90c7fd6ba 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -31,6 +31,10 @@ #import "NSDate+MAPIStore.h" #import "MAPIStoreGCSFolder.h" +#import "MAPIStoreTypes.h" + +#undef DEBUG +#include @implementation MAPIStoreGCSFolder @@ -60,7 +64,7 @@ } else fetchQualifier = componentQualifier; - + ocsFolder = [sogoObject ocsFolder]; fs = [EOFetchSpecification fetchSpecificationWithEntityName: [ocsFolder folderName] @@ -73,6 +77,11 @@ return keys; } +- (NSDate *) lastMessageModificationTime +{ + return [[sogoObject ocsFolder] lastModificationDate]; +} + /* subclasses */ - (EOQualifier *) componentQualifier diff --git a/OpenChange/MAPIStoreGCSMessage.m b/OpenChange/MAPIStoreGCSMessage.m index e7569c044..0f51e2bc6 100644 --- a/OpenChange/MAPIStoreGCSMessage.m +++ b/OpenChange/MAPIStoreGCSMessage.m @@ -20,8 +20,25 @@ * Boston, MA 02111-1307, USA. */ +#import + +#import "MAPIStoreTypes.h" + #import "MAPIStoreGCSMessage.h" +#undef DEBUG +#include + @implementation MAPIStoreGCSMessage +- (NSCalendarDate *) creationTime +{ + return [sogoObject creationDate]; +} + +- (NSCalendarDate *) lastModificationTime +{ + return [sogoObject lastModified]; +} + @end diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 8479cc729..ef0cb9901 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -30,7 +30,12 @@ @class SOGoMailAccount; @class SOGoMailFolder; +@class MAPIStoreMailMessageTable; + @interface MAPIStoreMailFolder : MAPIStoreFolder +{ + MAPIStoreMailMessageTable *messageTable; +} /* subclasses */ - (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) account diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 54522e02b..c14f1660e 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -53,6 +53,7 @@ static Class SOGoMailFolderK; #undef DEBUG #include +#include @implementation MAPIStoreMailFolder @@ -108,6 +109,12 @@ static Class SOGoMailFolderK; return self; } +- (void) dealloc +{ + [messageTable release]; + [super dealloc]; +} + - (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder inContext: (WOContext *) woContext { @@ -118,7 +125,13 @@ static Class SOGoMailFolderK; - (MAPIStoreMessageTable *) messageTable { - return [MAPIStoreMailMessageTable tableForContainer: self]; + if (!messageTable) + { + ASSIGN (messageTable, [MAPIStoreMailMessageTable tableForContainer: self]); + [self logWithFormat: @"new message table"]; + } + + return messageTable; } - (Class) messageClass @@ -127,6 +140,7 @@ static Class SOGoMailFolderK; } - (NSString *) createFolder: (struct SRow *) aRow + withFID: (uint64_t) newFID { NSString *folderName, *nameInContainer; SOGoMailFolder *newFolder; @@ -156,42 +170,33 @@ static Class SOGoMailFolderK; return nameInContainer; } -- (enum MAPISTATUS) getProperty: (void **) data - withTag: (enum MAPITAGS) propTag +- (int) getPrContentUnread: (void **) data { - enum MAPISTATUS rc; EOQualifier *searchQualifier; - uint32_t intValue; + uint32_t longValue; + + searchQualifier + = [EOQualifier qualifierWithQualifierFormat: @"flags = %@", @"unseen"]; + longValue = [[sogoObject fetchUIDsMatchingQualifier: searchQualifier + sortOrdering: nil] + count]; + *data = MAPILongValue (memCtx, longValue); - rc = MAPI_E_SUCCESS; - switch (propTag) - { - case PR_CONTENT_UNREAD: - searchQualifier - = [EOQualifier qualifierWithQualifierFormat: @"flags = %@", @"unseen"]; - intValue = [[sogoObject fetchUIDsMatchingQualifier: searchQualifier - sortOrdering: nil] count]; - *data = MAPILongValue (memCtx, intValue); - break; - case PR_CONTAINER_CLASS_UNICODE: - *data = [@"IPF.Note" asUnicodeInMemCtx: memCtx]; - break; - default: - { - const char *propName; + return MAPISTORE_SUCCESS; +} - propName = get_proptag_name (propTag); - if (!propName) - propName = ""; - [self warnWithFormat: @"get folder tag: %s (0x%.8x)", propName, - propTag]; - } - - - rc = [super getProperty: data withTag: propTag]; - } +- (int) getPrContainerClass: (void **) data +{ + *data = [@"IPF.Note" asUnicodeInMemCtx: memCtx]; - return rc; + return MAPISTORE_SUCCESS; +} + +- (int) getPrMessageClass: (void **) data +{ + *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; } - (NSArray *) childKeysMatchingQualifier: (EOQualifier *) qualifier @@ -263,6 +268,16 @@ static Class SOGoMailFolderK; return childObject; } +- (NSCalendarDate *) creationTime +{ + return [NSCalendarDate dateWithTimeIntervalSince1970: 0x4dbb2dbe]; /* oc_version_time */ +} + +- (NSCalendarDate *) lastModificationTime +{ + return [NSCalendarDate date]; +} + @end @implementation MAPIStoreInboxFolder : MAPIStoreMailFolder diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 65ccb36d7..271cf120b 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -85,6 +85,11 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; MAPIStoreDraftsFolderK = [MAPIStoreDraftsFolder class]; } ++ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP +{ + return [super getAvailableProperties: propertiesP]; +} + - (int) getPrIconIndex: (void **) data { uint32_t longValue; @@ -187,16 +192,14 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; return MAPISTORE_SUCCESS; } -- (int) getPrCreationTime: (void **) data // DOUBT +- (NSCalendarDate *) creationTime { - *data = [[sogoObject date] asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; + return [sogoObject date]; } -- (int) getPrLastModificationTime: (void **) data // DOUBT +- (NSCalendarDate *) lastModificationTime { - return [self getPrCreationTime: data]; + return [sogoObject date]; } - (int) getPrLatestDeliveryTime: (void **) data // DOUBT @@ -651,7 +654,7 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; NSArray *to; NSInteger count, max; NGImap4EnvelopeAddress *currentAddress; - NSString *name; + NSString *text; [super openMessage: msg]; /* Retrieve recipients from the message */ @@ -663,25 +666,38 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; for (count = 0; count < max; count++) { recipients->aRow[count].ulAdrEntryPad = 0; - recipients->aRow[count].cValues = 2; + recipients->aRow[count].cValues = 3; recipients->aRow[count].lpProps = talloc_array (recipients->aRow, struct SPropValue, - 2); + 4); // TODO (0x01 = primary recipient) - set_SPropValue_proptag (&(recipients->aRow[count].lpProps[0]), + set_SPropValue_proptag (recipients->aRow[count].lpProps + 0, PR_RECIPIENT_TYPE, - MAPILongValue (memCtx, 0x01)); - + MAPILongValue (recipients->aRow, 0x01)); + + set_SPropValue_proptag (recipients->aRow[count].lpProps + 1, + PR_ADDRTYPE_UNICODE, + [@"SMTP" asUnicodeInMemCtx: recipients->aRow]); + currentAddress = [to objectAtIndex: count]; - // name = [currentAddress personalName]; - // if (![name length]) - name = [currentAddress baseEMail]; - if (!name) - name = @""; - set_SPropValue_proptag (&(recipients->aRow[count].lpProps[1]), - PR_DISPLAY_NAME, - [name asUnicodeInMemCtx: recipients->aRow[count].lpProps]); + // text = [currentAddress personalName]; + // if (![text length]) + text = [currentAddress baseEMail]; + if (!text) + text = @""; + set_SPropValue_proptag (recipients->aRow[count].lpProps + 2, + PR_EMAIL_ADDRESS_UNICODE, + [text asUnicodeInMemCtx: recipients->aRow]); + + text = [currentAddress personalName]; + if ([text length] > 0) + { + recipients->aRow[count].cValues++; + set_SPropValue_proptag (recipients->aRow[count].lpProps + 3, + PR_DISPLAY_NAME_UNICODE, + [text asUnicodeInMemCtx: recipients->aRow]); + } } msg->recipients = recipients; } diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 1e524f512..e9c0050aa 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -180,15 +180,15 @@ return MAPISTORE_SUCCESS; } -- (int) getPrViewStyle: (void **) data -{ - return [self getLongZero: data]; -} +// - (int) getPrViewStyle: (void **) data +// { +// return [self getLongZero: data]; +// } -- (int) getPrViewMajorversion: (void **) data -{ - return [self getLongZero: data]; -} +// - (int) getPrViewMajorversion: (void **) data +// { +// return [self getLongZero: data]; +// } - (int) getPidLidSideEffects: (void **) data // TODO { @@ -281,35 +281,6 @@ return [self getLongZero: data]; } -// TODO: PR_CHANGE_KEY is a GID based on the ReplGUID -- (int) getPrChangeKey: (void **) data -{ - int rc = MAPISTORE_SUCCESS; - NSString *stringValue; - NSUInteger length; - - stringValue = [sogoObject davEntityTag]; - if (stringValue) - { - stringValue = @"-1"; - length = [stringValue length]; - if (length < 6) /* guid = 16 bytes */ - length += 6; - stringValue = [NSString stringWithFormat: @"000000%@", - stringValue]; - if (length > 6) - stringValue = [stringValue substringFromIndex: length - 6]; - stringValue = [NSString stringWithFormat: @"SOGo%@%@%@", - stringValue, stringValue, stringValue]; - *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] - asBinaryInMemCtx: memCtx]; - } - else - rc = MAPISTORE_ERR_NOT_FOUND; - - return rc; -} - - (int) getPrSubject: (void **) data { [self subclassResponsibility: _cmd]; @@ -352,20 +323,20 @@ return [self getEmptyString: data]; } -- (int) getPrOriginalDisplayTo: (void **) data -{ - return [self getPrDisplayTo: data]; -} +// - (int) getPrOriginalDisplayTo: (void **) data +// { +// return [self getPrDisplayTo: data]; +// } -- (int) getPrOriginalDisplayCc: (void **) data -{ - return [self getPrDisplayCc: data]; -} +// - (int) getPrOriginalDisplayCc: (void **) data +// { +// return [self getPrDisplayCc: data]; +// } -- (int) getPrOriginalDisplayBcc: (void **) data -{ - return [self getPrDisplayBcc: data]; -} +// - (int) getPrOriginalDisplayBcc: (void **) data +// { +// return [self getPrDisplayBcc: data]; +// } - (int) getPrLastModifierName: (void **) data { @@ -398,6 +369,11 @@ return MAPISTORE_SUCCESS; } +- (int) getPrAssociated: (void **) data +{ + return [self getNo: data]; +} + - (void) save { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index fc040ab83..cdb06cb71 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -49,7 +49,7 @@ + (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newContainer; -+ (int) getAvailableProperties: (struct SPropTagArray **) properties; ++ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP; - (id) initWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newFolder; @@ -69,7 +69,6 @@ - (uint64_t) objectId; - (NSString *) url; - /* properties */ - (void) addNewProperties: (NSDictionary *) newNewProperties; @@ -77,7 +76,7 @@ - (void) resetNewProperties; /* ops */ -- (int) getAvailableProperties: (struct SPropTagArray **) properties; +- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP; - (int) getProperties: (struct mapistore_property_data *) data withTags: (enum MAPITAGS *) tags andCount: (uint16_t) columnCount; @@ -92,8 +91,23 @@ - (int) getLongZero: (void **) data; - (int) getYes: (void **) data; - (int) getNo: (void **) data; +- (int) getReplicaKey: (void **) data + fromGlobCnt: (uint64_t) objectCnt; + +/* implemented getters */ +- (int) getPrDisplayName: (void **) data; +- (int) getPrSearchKey: (void **) data; +- (int) getPrGenerateExchangeViews: (void **) data; +- (int) getPrParentSourceKey: (void **) data; +- (int) getPrSourceKey: (void **) data; +- (int) getPrChangeKey: (void **) data; +- (int) getPrCreationTime: (void **) data; +- (int) getPrLastModificationTime: (void **) data; /* subclasses */ +- (NSDate *) creationTime; +- (NSDate *) lastModificationTime; + - (id) lookupChild: (NSString *) childKey; - (NSArray *) childKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index f390f6fbb..51aeea09c 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -24,9 +24,11 @@ #import #import +#import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" #import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" +#import "NSDate+MAPIStore.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -119,10 +121,10 @@ static Class NSExceptionK, MAPIStoreFolderK; - (void) dealloc { + [sogoObject release]; + [newProperties release]; [parentContainersBag release]; [container release]; - [sogoObject release]; - [newProperties dealloc]; talloc_free (memCtx); [super dealloc]; } @@ -192,8 +194,6 @@ static Class NSExceptionK, MAPIStoreFolderK; containerURL, [self nameInContainer]]; } - - - (void) addNewProperties: (NSDictionary *) newNewProperties { [newProperties addEntriesFromDictionary: newNewProperties]; @@ -233,12 +233,12 @@ static Class NSExceptionK, MAPIStoreFolderK; propName = get_proptag_name (propTag); if (!propName) propName = ""; - [self warnWithFormat: - @"unimplemented selector (%@) for %s (0x%.8x)", - NSStringFromSelector (methodSel), propName, propTag]; + // [self warnWithFormat: + // @"unimplemented selector (%@) for %s (0x%.8x)", + // NSStringFromSelector (methodSel), propName, propTag]; } - else - [self warnWithFormat: @"unsupported property tag: 0x%.8x", propTag]; + // else + // [self warnWithFormat: @"unsupported property tag: 0x%.8x", propTag]; } return rc; @@ -273,8 +273,34 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +- (int) getReplicaKey: (void **) data + fromGlobCnt: (uint64_t) objectCnt +{ + struct mapistore_connection_info *connInfo; + NSMutableData *replicaKey; + char buffer[6]; + NSUInteger count; + + connInfo = [[self context] connectionInfo]; + + for (count = 0; count < 6; count++) + { + buffer[count] = objectCnt & 0xff; + objectCnt >>= 8; + } + + replicaKey = [NSMutableData dataWithCapacity: 22]; + [replicaKey appendBytes: &connInfo->replica_guid + length: sizeof (struct GUID)]; + [replicaKey appendBytes: buffer + length: 6]; + *data = [replicaKey asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + /* getters */ - - (int) getPrDisplayName: (void **) data +- (int) getPrDisplayName: (void **) data { *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; @@ -297,6 +323,54 @@ static Class NSExceptionK, MAPIStoreFolderK; return [self getNo: data]; } +- (int) getPrParentSourceKey: (void **) data +{ + return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16]; +} + +- (int) getPrSourceKey: (void **) data +{ + return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16]; +} + +- (uint64_t) objectVersion +{ + uint32_t lmTime; + + lmTime = (uint32_t) [[self lastModificationTime] timeIntervalSince1970]; + if (lmTime < 0x4dbb2dbe) /* oc_version_time */ + lmTime = 0x4dbb2dbe; + + return ((([self objectId] & 0xffff000000000000LL) >> 16) + | (exchange_globcnt((uint64_t) lmTime - 0x4dbb2dbe) >> 16)); +} + +- (int) getPrChangeKey: (void **) data +{ + return [self getReplicaKey: data fromGlobCnt: [self objectVersion]]; +} + +- (int) getPrChangeNum: (void **) data +{ + *data = MAPILongLongValue (memCtx, ([self objectVersion] << 16) | 0x0001); + + return MAPISTORE_SUCCESS; +} + +- (int) getPrCreationTime: (void **) data +{ + *data = [[self creationTime] asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPrLastModificationTime: (void **) data +{ + *data = [[self lastModificationTime] asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + - (int) getAvailableProperties: (struct SPropTagArray **) propertiesP { return [isa getAvailableProperties: propertiesP]; @@ -332,6 +406,20 @@ static Class NSExceptionK, MAPIStoreFolderK; } /* subclasses */ +- (NSDate *) creationTime +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSDate *) lastModificationTime +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + - (id) lookupChild: (NSString *) childKey { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index 7cd0ebc06..9c8736461 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -718,6 +718,9 @@ static Class NSDataK, NSStringK; case 6: state = [self evaluateBitmaskRestriction: &res->res.resBitmask intoQualifier: qualifier]; break; + + case 7: state = MAPIRestrictionStateAlwaysTrue; /* let's cheat a little */ + break; case 8: state = [self evaluateExistRestriction: &res->res.resExist intoQualifier: qualifier]; break; @@ -727,7 +730,7 @@ static Class NSDataK, NSStringK; // case 10: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; default: [NSException raise: @"MAPIStoreRestrictionException" - format: @"unhandled restriction type"]; + format: @"unhandled restriction type: %.2x", res->rt]; state = MAPIRestrictionStateAlwaysTrue; } diff --git a/OpenChange/MAPIStoreTasksMessage.h b/OpenChange/MAPIStoreTasksMessage.h index ad3ddcd40..273cde7cb 100644 --- a/OpenChange/MAPIStoreTasksMessage.h +++ b/OpenChange/MAPIStoreTasksMessage.h @@ -25,12 +25,7 @@ #import "MAPIStoreGCSMessage.h" -@class iCalToDo; - @interface MAPIStoreTasksMessage : MAPIStoreGCSMessage -{ - iCalToDo *task; -} @end diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index b11266693..d05cc107d 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -49,24 +49,6 @@ @implementation MAPIStoreTasksMessage -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer -{ - if ((self = [super initWithSOGoObject: newSOGoObject - inContainer: newContainer])) - { - ASSIGN (task, [newSOGoObject component: NO secure: NO]); - } - - return self; -} - -- (void) dealloc -{ - [task release]; - [super dealloc]; -} - - (int) getPrIconIndex: (void **) data // TODO { /* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ @@ -90,6 +72,9 @@ - (int) getPrSubject: (void **) data // SUMMARY { + iCalToDo *task; + + task = [sogoObject component: NO secure: NO]; *data = [[task summary] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -98,7 +83,9 @@ - (int) getPrImportance: (void **) data { uint32_t v; - + iCalToDo *task; + + task = [sogoObject component: NO secure: NO]; if ([[task priority] isEqualToString: @"9"]) v = 0x0; else if ([[task priority] isEqualToString: @"1"]) @@ -113,6 +100,9 @@ - (int) getPidLidTaskComplete: (void **) data { + iCalToDo *task; + + task = [sogoObject component: NO secure: NO]; *data = MAPIBoolValue (memCtx, [[task status] isEqualToString: @"COMPLETED"]); @@ -122,6 +112,9 @@ - (int) getPidLidPercentComplete: (void **) data { double doubleValue; + iCalToDo *task; + + task = [sogoObject component: NO secure: NO]; doubleValue = ((double) [[task percentComplete] intValue] / 100); *data = MAPIDoubleValue (memCtx, doubleValue); @@ -131,8 +124,11 @@ - (int) getPidLidTaskDateCompleted: (void **) data { - NSCalendarDate *dateValue; int rc = MAPISTORE_SUCCESS; + NSCalendarDate *dateValue; + iCalToDo *task; + + task = [sogoObject component: NO secure: NO]; dateValue = [task completed]; if (dateValue) @@ -182,52 +178,42 @@ - (int) getPidLidTaskDueDate: (void **) data { - NSCalendarDate *dateValue; int rc = MAPISTORE_SUCCESS; + NSCalendarDate *dateValue; + iCalToDo *task; + task = [sogoObject component: NO secure: NO]; dateValue = [task due]; if (dateValue) *data = [dateValue asFileTimeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; - return MAPISTORE_SUCCESS; -} - -- (int) getPrCreationTime: (void **) data -{ - *data = [[task created] asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; + return rc; } - (int) getPrMessageDeliveryTime: (void **) data { - *data = [[task lastModified] asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; + return [self getPrLastModificationTime: data]; } - (int) getClientSubmitTime: (void **) data { - return [self getPrMessageDeliveryTime: data]; + return [self getPrLastModificationTime: data]; } - (int) getLocalCommitTime: (void **) data { - return [self getPrMessageDeliveryTime: data]; -} - -- (int) getLastModificationTime: (void **) data -{ - return [self getPrMessageDeliveryTime: data]; + return [self getPrLastModificationTime: data]; } - (int) getPidLidTaskStatus: (void **) data // status { NSString *status; uint32_t longValue; + iCalToDo *task; + task = [sogoObject component: NO secure: NO]; status = [task status]; if (![status length] || [status isEqualToString: @"NEEDS-ACTION"])