merge of '8ae1b0b4d89d23b2996f0b95677ca5599649f47b'

and 'bc91dad52acb790e0e4511b1b3ac70a21efd53fb'

Monotone-Parent: 8ae1b0b4d89d23b2996f0b95677ca5599649f47b
Monotone-Parent: bc91dad52acb790e0e4511b1b3ac70a21efd53fb
Monotone-Revision: b6726f7b87c51426fc4fa2e3ed33d20cb47a89e0

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2011-01-14T15:35:46
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2011-01-14 15:35:46 +00:00
commit db851140d4
15 changed files with 336 additions and 29 deletions

View File

@ -8,6 +8,20 @@
* SoObjects/Appointments/SOGoAppointmentFolder.m
(-_flattenCycleRecord:forRange:intoArray:): idem.
2011-01-14 Ludovic Marcotte <lmarcotte@inverse.ca>
* Work on the OpenChange backend: added more property
support such as priority for tasks, events and mails,
secondary email address support for contacts, nickname
and birthday support for contacts and a few more or
some fixes there and there.
* OpenChange/SOGoMAPIFSMessage.m: -MAPISave added a hack
to AVOID saving informations on the fs when dealing
with the "inbox" folder - as it'll crash Outlook upon
next restarts
* Added OpenChange/MAPIStoreNotesMessageTable.{h,m} to
later extend and improve Notes support.
2011-01-13 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m

View File

@ -64,6 +64,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreContactsMessageTable.m \
MAPIStoreMailMessageTable.m \
MAPIStoreMailFolderTable.m \
MAPIStoreNotesMessageTable.m \
MAPIStoreTasksMessageTable.m \
\
SOGoAppointmentObject+MAPIStore.m \

View File

@ -124,9 +124,24 @@
*data = [[event created] asFileTimeInMemCtx: memCtx];
break;
case PidLidTimeZoneStruct:
case PR_IMPORTANCE:
{
unsigned int v;
event = [[self lookupChild: childKey] component: NO secure: NO];
if ([[event priority] isEqualToString: @"9"])
v = 0x0;
else if ([[event priority] isEqualToString: @"1"])
v = 0x2;
else
v = 0x1;
*data = MAPILongValue (memCtx, v);
}
break;
// case PidLidTimeZoneStruct:
// case PR_VD_NAME_UNICODE:
// *data = talloc_strdup(memCtx, "PR_VD_NAME_UNICODE");
// break;

View File

@ -31,6 +31,7 @@
#import <Contacts/SOGoContactGCSEntry.h>
#import "MAPIStoreTypes.h"
#import "NSCalendarDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "MAPIStoreContactsMessageTable.h"
@ -152,6 +153,52 @@
stringValue = [[child vCard] preferredEMail];
*data = [stringValue asUnicodeInMemCtx: memCtx];
break;
//
// TODO - same logic as -secondaryEmail in UI/Contacts/UIxContactView.m
// We should eventually merge that in order to not duplicate the code.
// We should also eventually handle PidLidEmail3OriginalDisplayName in
// SOGo, Thunderbird, etc.
//
case PidLidEmail2OriginalDisplayName: // Other email
{
NSMutableArray *emails;
NSString *email;
NGVCard *card;
emails = [NSMutableArray array];
stringValue = nil;
card = [[self lookupChild: childKey] vCard];
[emails addObjectsFromArray: [card childrenWithTag: @"email"]];
[emails removeObjectsInArray: [card childrenWithTag: @"email"
andAttribute: @"type"
havingValue: @"pref"]];
if ([emails count] > 0)
{
int i;
for (i = 0; i < [emails count]; i++)
{
email = [[emails objectAtIndex: i] value: 0];
if ([email caseInsensitiveCompare: [card preferredEMail]] != NSOrderedSame)
{
stringValue = email;
break;
}
}
}
if (!stringValue)
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
}
break;
// FIXME: this property does NOT work
case PR_BODY_UNICODE:
child = [self lookupChild: childKey];
stringValue = [[child vCard] note];
@ -160,7 +207,7 @@
case PR_OFFICE_TELEPHONE_NUMBER_UNICODE:
child = [self lookupChild: childKey];
element = [self _element: @"phone" ofType: @"work"
element = [self _element: @"tel" ofType: @"work"
excluding: @"fax"
inCard: [child vCard]];
if (element)
@ -171,7 +218,7 @@
break;
case PR_HOME_TELEPHONE_NUMBER_UNICODE:
child = [self lookupChild: childKey];
element = [self _element: @"phone" ofType: @"home"
element = [self _element: @"tel" ofType: @"home"
excluding: @"fax"
inCard: [child vCard]];
if (element)
@ -182,7 +229,7 @@
break;
case PR_MOBILE_TELEPHONE_NUMBER_UNICODE:
child = [self lookupChild: childKey];
element = [self _element: @"phone" ofType: @"cell"
element = [self _element: @"tel" ofType: @"cell"
excluding: nil
inCard: [child vCard]];
if (element)
@ -193,7 +240,7 @@
break;
case PR_PRIMARY_TELEPHONE_NUMBER_UNICODE:
child = [self lookupChild: childKey];
element = [self _element: @"phone" ofType: @"pref"
element = [self _element: @"tel" ofType: @"pref"
excluding: nil
inCard: [child vCard]];
if (element)
@ -228,7 +275,20 @@
case PidLidEmail3AddressType:
*data = [@"SMTP" asUnicodeInMemCtx: memCtx];
break;
case PidLidInstantMessagingAddress:
child = [self lookupChild: childKey];
stringValue = [[[child vCard] uniqueChildWithTag: @"x-aim"] value: 0];
if (!stringValue)
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
break;
//
// We don't handle 0x00000003 - The Other Address is the mailing address.
// See: http://msdn.microsoft.com/en-us/library/cc815430.aspx
//
case PidLidPostalAddressId:
child = [self lookupChild: childKey];
element = [self _element: @"adr" ofType: @"pref"
@ -236,12 +296,12 @@
inCard: [child vCard]];
if ([element hasAttribute: @"type"
havingValue: @"home"])
longValue = 1;
longValue = 1; // The Home Address is the mailing address.
else if ([element hasAttribute: @"type"
havingValue: @"work"])
longValue = 2;
longValue = 2; // The Work Address is the mailing address.
else
longValue = 0;
longValue = 0; // No address is selected as the mailing address.
*data = MAPILongValue (memCtx, longValue);
break;
@ -405,13 +465,34 @@
*data = [stringValue asUnicodeInMemCtx: memCtx];
break;
// PidTagNickname
// PidTagNickname
case PR_NICKNAME_UNICODE:
child = [self lookupChild: childKey];
stringValue = [[child vCard] nickname];
*data = [stringValue asUnicodeInMemCtx: memCtx];
break;
case PR_BIRTHDAY:
{
NSCalendarDate *dateValue;
child = [self lookupChild: childKey];
stringValue = [[child vCard] bday];
if (stringValue)
{
dateValue = [NSCalendarDate dateWithString: stringValue
calendarFormat: @"%Y-%m-%d"];
// FIXME: We add a day, otherwise Outlook 2003 will display at day earlier
dateValue = [dateValue addYear: 0 month: 0 day: 1 hour: 0 minute: 0 second: 0];
*data = [dateValue asFileTimeInMemCtx: memCtx];
}
else
rc = MAPI_E_NOT_FOUND;
}
break;
default:
rc = [super getChildProperty: data
forKey: childKey

View File

@ -1127,15 +1127,15 @@ _prepareContextClass (struct mapistore_context *newMemCtx,
{
*path = [[objectURL substringFromIndex: 7]
asUnicodeInMemCtx: memCtx];
[self logWithFormat: @"found path for fmid %.16x: '%s'",
fmid, *path];
[self logWithFormat: @"found path '%s' for fmid %.16x",
*path, fmid];
rc = MAPISTORE_SUCCESS;
}
else
{
[self warnWithFormat: @"fmid 0x%.16x was found but is not"
@" part of this context (%@, %@)",
fmid, objectURL, uri];
[self logWithFormat: @"context (%@, %@) does not contain"
@" found fmid: 0x%.16x",
objectURL, uri, fmid];
*path = NULL;
rc = MAPI_E_NOT_FOUND;
}

View File

@ -21,6 +21,7 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
@ -132,12 +133,22 @@ static Class NSDataK, NSStringK;
*data = [[child date] asFileTimeInMemCtx: memCtx];
break;
case PR_MESSAGE_FLAGS: // TODO
// NSDictionary *coreInfos;
// NSArray *flags;
// child = [self lookupChild: childKey];
// coreInfos = [child fetchCoreInfos];
// flags = [coreInfos objectForKey: @"flags"];
*data = MAPILongValue (memCtx, 0x02 | 0x20); // fromme + unmodified
{
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v;
child = [self lookupChild: childKey];
coreInfos = [child fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
v = MSGFLAG_FROMME;
if ([flags containsObject: @"seen"])
v |= MSGFLAG_READ;
*data = MAPILongValue (memCtx, v);
}
break;
case PR_FLAG_STATUS: // TODO
@ -191,6 +202,30 @@ static Class NSDataK, NSStringK;
case PidNameContentType:
*data = [@"message/rfc822" asUnicodeInMemCtx: memCtx];
break;
//
// TODO: Merge with the code in UI/MailerUI/UIxMailListActions.m: -messagePriority
// to avoid the duplication of the logic
//
case PR_IMPORTANCE:
{
unsigned int v;
NSString *s;
child = [self lookupChild: childKey];
s = [[child mailHeaders] objectForKey: @"x-priority"];
v = 0x1;
if ([s hasPrefix: @"1"]) v = 0x2;
else if ([s hasPrefix: @"2"]) v = 0x2;
else if ([s hasPrefix: @"4"]) v = 0x0;
else if ([s hasPrefix: @"5"]) v = 0x0;
*data = MAPILongValue (memCtx, v);
}
break;
case PR_BODY:
case PR_BODY_UNICODE:

View File

@ -1,6 +1,6 @@
/* MAPIStoreNotesContext.m - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
* Copyright (C) 2010-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -25,6 +25,7 @@
#import "MAPIStoreMapping.h"
#import "MAPIStoreNotesContext.h"
#import "MAPIStoreNotesMessageTable.h"
@implementation MAPIStoreNotesContext
@ -39,4 +40,9 @@
withID: 0x1c0001];
}
- (Class) messageTableClass
{
return [MAPIStoreNotesMessageTable class];
}
@end

View File

@ -0,0 +1,31 @@
/* MAPIStoreNotesMessageTable.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTORENOTESMESSAGETABLE_H
#define MAPISTORENOTESMESSAGETABLE_H
#import "MAPIStoreFSMessageTable.h"
@interface MAPIStoreNotesMessageTable : MAPIStoreFSMessageTable
@end
#endif /* MAPISTORENOTESMESSAGETABLE_H */

View File

@ -0,0 +1,72 @@
/* MAPIStoreNotesMessageTable.m - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <SOGo/SOGoFolder.h>
#import <SOGo/SOGoObject.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
#import "NSData+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "MAPIStoreNotesMessageTable.h"
#undef DEBUG
#include <stdbool.h>
#include <gen_ndr/exchange.h>
#include <libmapiproxy.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_nameid.h>
#include <talloc.h>
@implementation MAPIStoreNotesMessageTable
- (enum MAPISTATUS) getChildProperty: (void **) data
forKey: (NSString *) childKey
withTag: (enum MAPITAGS) propTag
{
int rc;
rc = MAPI_E_SUCCESS;
switch (propTag)
{
case PR_ICON_INDEX: // TODO
/* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */
// *longValue = 0x00000300 for blue
// *longValue = 0x00000301 for green
// *longValue = 0x00000302 for pink
// *longValue = 0x00000303 for yellow
// *longValue = 0x00000304 for white
*data = MAPILongValue (memCtx, 0x00000303);
break;
default:
rc = [super getChildProperty: data
forKey: childKey
withTag: propTag];
}
return rc;
}
@end

View File

@ -664,6 +664,7 @@ static Class NSDataK, NSStringK;
}
value = NSObjectFromMAPISPropValue (&res->lpProp);
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: property
operatorSelector: operator
value: value];

View File

@ -30,6 +30,7 @@
#import "MAPIStoreTypes.h"
#import "NSCalendarDate+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "MAPIStoreTasksMessageTable.h"
@ -72,6 +73,28 @@
task = [[self lookupChild: childKey] component: NO secure: NO];
*data = [[task summary] asUnicodeInMemCtx: memCtx];
break;
//
// Not to be confused with PR_PRIORITY
//
// IMPORTANCE_LOW = 0x0, IMPORTANCE_NORMAL = 0x1 and IMPORTANCE_HIGH = 0x2
//
case PR_IMPORTANCE:
{
unsigned int v;
task = [[self lookupChild: childKey] component: NO secure: NO];
if ([[task priority] isEqualToString: @"9"])
v = 0x0;
else if ([[task priority] isEqualToString: @"1"])
v = 0x2;
else
v = 0x1;
*data = MAPILongValue (memCtx, v);
}
break;
case PidLidTaskComplete:
task = [[self lookupChild: childKey] component: NO secure: NO];
*data = MAPIBoolValue (memCtx,
@ -90,8 +113,12 @@
else
rc = MAPI_E_NOT_FOUND;
break;
case PidLidTaskState: // TODO (check)
*data = MAPILongValue (memCtx, 0x02 | 0x03);
// http://msdn.microsoft.com/en-us/library/cc765590.aspx
// It's important to have a proper value for PidLidTaskState
// as it'll affect the UI options of Outlook - making the
// task non-editable in some cases.
case PidLidTaskState:
*data = MAPILongValue (memCtx, 0x1); // not assigned
break;
case PidLidTaskMode: // TODO
*data = MAPILongValue (memCtx, 0x0);
@ -151,9 +178,19 @@
case 0x68340003:
case 0x683a0003:
case 0x68410003:
*data = MAPILongValue (memCtx, 0);
*data = MAPILongValue (memCtx, 0);
break;
// FIXME - use the current user
case PidLidTaskOwner:
*data = [@"openchange@example.com" asUnicodeInMemCtx: memCtx];
break;
// See http://msdn.microsoft.com/en-us/library/cc842113.aspx
case PidLidTaskOwnership:
*data = MAPILongValue (memCtx, 0x0); // not assigned
break;
// #define PidLidFlagRequest 0x9027001f
// #define PidNameContentType 0x905a001f
// #define PidLidBillingInformation 0x908b001f

View File

@ -121,7 +121,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
case PT_CLSID:
result = [NSData dataWithGUID: &value->value.lpguid];
break;
default:
// #define PT_UNSPECIFIED 0x0
// #define PT_I2 0x2

View File

@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
@ -70,6 +71,7 @@
- (void) MAPISave
{
NSArray *pathComponents;
NSString *filePath;
[self logWithFormat: @"-MAPISave"];
@ -78,6 +80,18 @@
filePath = [[container directory]
stringByAppendingPathComponent: nameInContainer];
// FIXME
// We do NOT save the FAI data for the Inbox, as upon the
// next Outlook restart, when restoring those saved properties,
// Outlook will crash.
pathComponents = [filePath pathComponents];
if ([[pathComponents objectAtIndex: [pathComponents count]-2] isEqualToString: @"inbox"])
{
[self logWithFormat: @"-MAPISave - skipping FAI at path %@", filePath];
return;
}
if (![properties writeToFile: filePath atomically: YES])
[NSException raise: @"MAPIStoreIOException"
format: @"could not save message"];

View File

@ -133,13 +133,13 @@
{
switch ([value intValue])
{
case 0: // Low
case 0: // IMPORTANCE_LOW
priority = @"9";
break;
case 2: // High
case 2: // IMPORTANCE_HIGH
priority = @"1";
break;
default: // Normal
default: // IMPORTANCE_NORMAL
priority = @"5";
}
}

View File

@ -25,7 +25,7 @@
var uixEmailUsr =
"([a-zA-Z0-9][a-zA-Z0-9_.-]*|\"([^\\\\\x80-\xff\015\012\"]|\\\\[^\x80-\xff])+\")";
var uixEmailDomain =
"([a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,5}";
"([a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,6}";
var uixEmailRegex = new RegExp("^"+uixEmailUsr+"\@"+uixEmailDomain+"$");
var dateRegex = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;