propagate from branch 'ca.inverse.sogo.1_3_12' (head 235258efee8273e9b6d2822d3d5da125520631c7)

to branch 'ca.inverse.sogo' (head b2bfdd5b59fed2950707131eca171b4758bcd635)

Monotone-Parent: 235258efee8273e9b6d2822d3d5da125520631c7
Monotone-Parent: b2bfdd5b59fed2950707131eca171b4758bcd635
Monotone-Revision: f67fbb0139df60f0e98c0aede6b166d1a8b15d81

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2012-02-08T04:24:33
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Francis Lachapelle
2012-02-08 04:24:33 +00:00
132 changed files with 5043 additions and 3264 deletions
@@ -2617,11 +2617,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return @"Appointment";
}
- (NSString *) outlookFolderClass
{
return @"IPF.Appointment";
}
- (BOOL) isActive
{
SOGoUserSettings *settings;
@@ -26,6 +26,7 @@
#import <SOGo/SOGoParentFolder.h>
@class NSArray;
@class NSMutableArray;
@class SOGoWebAppointmentFolder;
+7 -4
View File
@@ -9,17 +9,20 @@ Contacts_PRINCIPAL_CLASS = SOGoContactsProduct
Contacts_OBJC_FILES = \
Product.m \
NGVCard+SOGo.m \
NGVList+SOGo.m \
NGVCard+SOGo.m \
NGVList+SOGo.m \
SOGoFolder+CardDAV.m \
SOGoContactFolders.m \
SOGoContactGCSEntry.m \
SOGoContactGCSList.m \
SOGoContactGCSFolder.m \
SOGoContactLDIFEntry.m \
SOGoContactSourceFolder.m \
SOGoUserFolder+Contacts.m \
SOGoContactSourceFolder.m \
SOGoUserFolder+Contacts.m \
SOGoContactEntryPhoto.m \
\
NSDictionary+LDIF.m \
NSString+LDIF.m
Contacts_RESOURCE_FILES += \
product.plist \
+5 -1
View File
@@ -25,9 +25,13 @@
#import <NGCards/NGVCard.h>
@class NSDictionary;
@class NSMutableDictionary;
@interface NGVCard (SOGoExtensions)
- (NSString *) ldifString;
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord;
- (NSMutableDictionary *) asLDIFRecord;
@end
+574 -117
View File
@@ -21,153 +21,610 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <NGCards/NSArray+NGCards.h>
#import <NGCards/NSString+NGCards.h>
#import "NSDictionary+LDIF.h"
#import "NGVCard+SOGo.h"
/*
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
DESC 'RFC2256: an organizational person'
SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
objectclass ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
STRUCTURAL
MAY (
audio $ businessCategory $ carLicense $ departmentNumber $
displayName $ employeeNumber $ employeeType $ givenName $
homePhone $ homePostalAddress $ initials $ jpegPhoto $
labeledURI $ mail $ manager $ mobile $ o $ pager $
photo $ roomNumber $ secretary $ uid $ userCertificate $
x500uniqueIdentifier $ preferredLanguage $
userSMIMECertificate $ userPKCS12 )
)
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
SUP top AUXILIARY
MUST ( cn )
MAY( c $
description $
displayName $
facsimileTelephoneNumber $
givenName $
homePhone $
l $
mail $
mobile $
mozillaCustom1 $
mozillaCustom2 $
mozillaCustom3 $
mozillaCustom4 $
mozillaHomeCountryName $
mozillaHomeLocalityName $
mozillaHomePostalCode $
mozillaHomeState $
mozillaHomeStreet $
mozillaHomeStreet2 $
mozillaHomeUrl $
mozillaNickname $
mozillaSecondEmail $
mozillaUseHtmlMail $
mozillaWorkStreet2 $
mozillaWorkUrl $
nsAIMid $
o $
ou $
pager $
postalCode $
postOfficeBox $
sn $
st $
street $
telephoneNumber $
title ) )
additional vcard fields:
"vcardCategories"
test contact (export from tb):
dn:: Y249UHLDqW5vbSBOb20sbWFpbD1hZHIxQGVsZS5jb20=
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mozillaAbPersonAlpha
givenName:: UHLDqW5vbQ==
sn: Nom
cn:: UHLDqW5vbSBOb20=
mozillaNickname: Surnom
mail: adr1@ele.com
mozillaSecondEmail: adralt@ele.com
nsAIMid: pseudo aim
modifytimestamp: 1324509379
telephoneNumber: travail
homePhone: dom
facsimiletelephonenumber: fax
pager: pager
mobile: port
mozillaHomeStreet:: YWRyMSBwcml2w6ll
mozillaHomeStreet2:: YWRyMiBwcml2w6ll
mozillaHomeLocalityName: ville/locallite
mozillaHomeState:: w6l0YXQvcHJvdg==
mozillaHomePostalCode: codepos
mozillaHomeCountryName: pays
street: adr1 pro
mozillaWorkStreet2: adr2 pro
l: ville pro
st: etat pro
postalCode: codepro
c: payspro
title: fonction pro
ou: service pro
o: soc pro
mozillaWorkUrl: webpro
mozillaHomeUrl: web
birthyear: 1946
birthmonth: 12
birthday: 04
mozillaCustom1: d1
mozillaCustom2: d2
mozillaCustom3: d3
mozillaCustom4: d4
description: notes
convention:
- our "LDIF records" are inetOrgPerson + mozillaAbPersonAlpha + a few custom
fields (categories)
- all keys are lowercase
*/
@implementation NGVCard (SOGoExtensions)
- (NSString *) ldifString
/* LDIF -> VCARD */
- (CardElement *) _elementWithTag: (NSString *) elementTag
ofType: (NSString *) type
{
NSMutableString *rc;
NSString *buffer;
NSArray *array;
NSMutableArray *marray;
NSMutableDictionary *entry;
NSArray *elements;
CardElement *element;
id tmp;
entry = [NSMutableDictionary dictionary];
elements = [self childrenWithTag: elementTag
andAttribute: @"type" havingValue: type];
if ([elements count] > 0)
element = [elements objectAtIndex: 0];
else
{
element = [CardElement elementWithTag: elementTag];
[element addType: type];
[self addChild: element];
}
[entry setObject: [NSString stringWithFormat: @"cn=%@,mail=%@",
[self fn], [self preferredEMail]]
forKey: @"dn"];
[entry setObject: [NSArray arrayWithObjects: @"top", @"person",
@"organizationalPerson", @"inetOrgPerson",
@"mozillaAbPersonObsolete", nil]
forKey: @"objectclass"];
return element;
}
- (void) _setPhoneValues: (NSDictionary *) ldifRecord
{
CardElement *phone;
phone = [self _elementWithTag: @"tel" ofType: @"work"];
[phone setSingleValue: [ldifRecord objectForKey: @"telephonenumber"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"home"];
[phone setSingleValue: [ldifRecord objectForKey: @"homephone"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"cell"];
[phone setSingleValue: [ldifRecord objectForKey: @"mobile"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"fax"];
[phone setSingleValue: [ldifRecord objectForKey: @"facsimiletelephonenumber"]
forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"pager"];
[phone setSingleValue: [ldifRecord objectForKey: @"pager"] forKey: @""];
}
- (void) _setEmails: (NSDictionary *) ldifRecord
{
CardElement *mail, *homeMail;
mail = [self _elementWithTag: @"email" ofType: @"work"];
[mail setSingleValue: [ldifRecord objectForKey: @"mail"] forKey: @""];
homeMail = [self _elementWithTag: @"email" ofType: @"home"];
[homeMail setSingleValue: [ldifRecord objectForKey: @"mozillasecondemail"] forKey: @""];
[[self uniqueChildWithTag: @"x-mozilla-html"]
setSingleValue: [ldifRecord objectForKey: @"mozillausehtmlmail"]
forKey: @""];
}
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord
{
CardElement *element;
NSArray *units;
NSInteger year, yearOfToday, month, day;
NSCalendarDate *now;
NSString *ou;
[self setNWithFamily: [ldifRecord objectForKey: @"sn"]
given: [ldifRecord objectForKey: @"givenname"]
additional: nil prefixes: nil suffixes: nil];
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
[self setFn: [ldifRecord objectForKey: @"displayname"]];
[self setTitle: [ldifRecord objectForKey: @"title"]];
element = [self _elementWithTag: @"adr" ofType: @"home"];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet2"]
atIndex: 1 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet"]
atIndex: 2 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomelocalityname"]
atIndex: 3 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestate"]
atIndex: 4 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomepostalcode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomecountryname"]
atIndex: 6 forKey: @""];
element = [self _elementWithTag: @"adr" ofType: @"work"];
[element setSingleValue: [ldifRecord objectForKey: @"mozillaworkstreet2"]
atIndex: 1 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"street"]
atIndex: 2 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"l"]
atIndex: 3 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"st"]
atIndex: 4 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"postalcode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"c"]
atIndex: 6 forKey: @""];
ou = [ldifRecord objectForKey: @"ou"];
if (ou)
units = [NSArray arrayWithObject: ou];
else
units = nil;
[self setOrg: [ldifRecord objectForKey: @"o"]
units: units];
[self _setPhoneValues: ldifRecord];
[self _setEmails: ldifRecord];
[[self _elementWithTag: @"url" ofType: @"home"]
setSingleValue: [ldifRecord objectForKey: @"mozillahomeurl"] forKey: @""];
[[self _elementWithTag: @"url" ofType: @"work"]
setSingleValue: [ldifRecord objectForKey: @"mozillaworkurl"] forKey: @""];
[[self uniqueChildWithTag: @"x-aim"]
setSingleValue: [ldifRecord objectForKey: @"nsaimid"]
forKey: @""];
now = [NSCalendarDate date];
year = [[ldifRecord objectForKey: @"birthyear"] intValue];
if (year < 100)
{
yearOfToday = [now yearOfCommonEra];
if (year == 0)
year = yearOfToday;
else if (yearOfToday < (year + 2000))
year += 1900;
else
year += 2000;
}
month = [[ldifRecord objectForKey: @"birthmonth"] intValue];
day = [[ldifRecord objectForKey: @"birthday"] intValue];
if (year && month && day)
[self setBday: [NSString stringWithFormat: @"%.4d-%.2d-%.2d",
year, month, day]];
else
[self setBday: @""];
[self setNote: [ldifRecord objectForKey: @"description"]];
[self setCategories: [ldifRecord objectForKey: @"vcardcategories"]];
[self cleanupEmptyChildren];
}
/* VCARD -> LDIF */
- (NSString *) _simpleValueForType: (NSString *) aType
inArray: (NSArray *) anArray
excluding: (NSString *) aTypeToExclude
{
NSArray *elements;
NSString *value;
elements = [anArray cardElementsWithAttribute: @"type"
havingValue: aType];
value = nil;
if ([elements count] > 0)
{
CardElement *ce;
int i;
for (i = 0; i < [elements count]; i++)
{
ce = [elements objectAtIndex: i];
value = [ce flattenedValuesForKey: @""];
if (!aTypeToExclude)
break;
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
break;
value = nil;
}
}
return value;
}
- (void) _setValue: (NSString *) key
to: (NSString *) aValue
inLDIFRecord: (NSMutableDictionary *) ldifRecord
{
if (!aValue)
aValue = @"";
[ldifRecord setObject: aValue forKey: key];
}
- (void) _setupEmailFieldsInLDIFRecord: (NSMutableDictionary *) ldifRecord
{
NSArray *elements;
NSString *workMail, *homeMail, *potential;
unsigned int max;
elements = [self childrenWithTag: @"email"];
max = [elements count];
workMail = [self _simpleValueForType: @"work"
inArray: elements excluding: nil];
homeMail = [self _simpleValueForType: @"home"
inArray: elements excluding: nil];
if (max > 0)
{
potential = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
if (!workMail)
{
if (homeMail && homeMail == potential)
{
if (max > 1)
workMail = [[elements objectAtIndex: 1] flattenedValuesForKey: @""];
}
else
workMail = potential;
}
if (!homeMail && max > 1)
{
if (workMail && workMail == potential)
homeMail = [[elements objectAtIndex: 1] flattenedValuesForKey: @""];
else
homeMail = potential;
}
}
[self _setValue: @"mail" to: workMail inLDIFRecord: ldifRecord];
[self _setValue: @"mozillasecondemail" to: homeMail inLDIFRecord: ldifRecord];
[self _setValue: @"mozillausehtmlmail"
to: [[self uniqueChildWithTag: @"x-mozilla-html"]
flattenedValuesForKey: @""]
inLDIFRecord: ldifRecord];
}
- (void) _setupOrgFieldsInLDIFRecord: (NSMutableDictionary *) ldifRecord
{
NSMutableArray *orgServices;
CardElement *org;
NSString *service;
NSUInteger count, max;
org = [self org];
[self _setValue: @"o"
to: [org flattenedValueAtIndex: 0 forKey: @""]
inLDIFRecord: ldifRecord];
max = [[org valuesForKey: @""] count];
if (max > 1)
{
orgServices = [NSMutableArray arrayWithCapacity: max];
for (count = 1; count < max; count++)
{
service = [org flattenedValueAtIndex: count forKey: @""];
if ([service length] > 0)
[orgServices addObject: service];
}
[self _setValue: @"ou"
to: [orgServices componentsJoinedByString: @", "]
inLDIFRecord: ldifRecord];
}
}
- (NSMutableDictionary *) asLDIFRecord
{
NSArray *elements, *categories;
CardElement *element;
NSMutableDictionary *ldifRecord;
NSCalendarDate *birthDay;
NSString *dn, *stringValue, *stringValue2;
ldifRecord = [NSMutableDictionary dictionaryWithCapacity: 32];
[ldifRecord setObject: [NSArray arrayWithObjects: @"top", @"inetOrgPerson",
@"mozillaAbPersonAlpha", nil]
forKey: @"objectClass"];
element = [self n];
tmp = [element flattenedValueAtIndex: 1 forKey: @""];
if ([tmp length] > 0)
[entry setObject: tmp forKey: @"givenName"];
tmp = [element flattenedValueAtIndex: 0 forKey: @""];
if ([tmp length] > 0)
[entry setObject: tmp forKey: @"sn"];
[self _setValue: @"sn"
to: [element flattenedValueAtIndex: 0 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"givenname"
to: [element flattenedValueAtIndex: 1 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"displayname" to: [self fn]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillanickname" to: [self nickname]
inLDIFRecord: ldifRecord];
tmp = [self fn];
if (tmp)
[entry setObject: tmp forKey: @"cn"];
tmp = [self preferredEMail];
if (tmp)
[entry setObject: tmp forKey: @"mail"];
[entry setObject: @"0Z" forKey: @"modifytimestamp"];
elements = [self childrenWithTag: @"tel"];
// We do this (exclude FAX) in order to avoid setting the WORK number as the FAX
// one if we do see the FAX field BEFORE the WORK number.
[self _setValue: @"telephonenumber"
to: [self _simpleValueForType: @"work" inArray: elements
excluding: @"fax"]
inLDIFRecord: ldifRecord];
[self _setValue: @"homephone"
to: [self _simpleValueForType: @"home" inArray: elements
excluding: @"fax"]
inLDIFRecord: ldifRecord];
[self _setValue: @"mobile"
to: [self _simpleValueForType: @"cell" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
[self _setValue: @"facsimiletelephonenumber"
to: [self _simpleValueForType: @"fax" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
[self _setValue: @"pager"
to: [self _simpleValueForType: @"pager" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
buffer = [self nickname];
if (buffer && [buffer length] > 0)
[entry setObject: buffer forKey: @"mozillaNickname"];
// If we don't have a "home" and "work" phone number but
// we have a "voice" one defined, we set it to the "work" value
// This can happen when we have :
// VERSION:2.1
// N:name;surname;;;;
// TEL;VOICE;HOME:
// TEL;VOICE;WORK:
// TEL;PAGER:
// TEL;FAX;WORK:
// TEL;CELL:514 123 1234
// TEL;VOICE:450 456 6789
// ADR;HOME:;;;;;;
// ADR;WORK:;;;;;;
// ADR:;;;;;;
if ([[ldifRecord objectForKey: @"telephonenumber"] length] == 0 &&
[[ldifRecord objectForKey: @"homephone"] length] == 0 &&
[elements count] > 0)
[self _setValue: @"telephonenumber"
to: [self _simpleValueForType: @"voice" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
marray = [NSMutableArray arrayWithArray: [self childrenWithTag: @"email"]];
[marray removeObjectsInArray: [self childrenWithTag: @"email"
andAttribute: @"type"
havingValue: @"pref"]];
if ([marray count])
[self _setupEmailFieldsInLDIFRecord: ldifRecord];
[self _setValue: @"nsaimid"
to: [[self uniqueChildWithTag: @"x-aim"]
flattenedValuesForKey: @""]
inLDIFRecord: ldifRecord];
elements = [self childrenWithTag: @"adr"
andAttribute: @"type" havingValue: @"work"];
if (elements && [elements count] > 0)
{
buffer = [[marray objectAtIndex: [marray count]-1]
flattenedValuesForKey: @""];
if ([buffer caseInsensitiveCompare: [self preferredEMail]] != NSOrderedSame)
[entry setObject: buffer forKey: @"mozillaSecondEmail"];
element = [elements objectAtIndex: 0];
[self _setValue: @"mozillaworkstreet2"
to: [element flattenedValueAtIndex: 1 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"street"
to: [element flattenedValueAtIndex: 2 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"l"
to: [element flattenedValueAtIndex: 3 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"st"
to: [element flattenedValueAtIndex: 4 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"postalcode"
to: [element flattenedValueAtIndex: 5 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"c"
to: [element flattenedValueAtIndex: 6 forKey: @""]
inLDIFRecord: ldifRecord];
}
array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"home"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"homePhone"];
array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"fax"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"fax"];
array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"cell"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"mobile"];
array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"pager"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"pager"];
array = [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"];
if ([array count])
elements = [self childrenWithTag: @"adr"
andAttribute: @"type" havingValue: @"home"];
if (elements && [elements count] > 0)
{
tmp = [array objectAtIndex: 0];
[entry setObject: [tmp flattenedValueAtIndex: 1 forKey: @""]
forKey: @"mozillaHomeStreet2"];
[entry setObject: [tmp flattenedValueAtIndex: 2 forKey: @""]
forKey: @"homeStreet"];
[entry setObject: [tmp flattenedValueAtIndex: 3 forKey: @""]
forKey: @"mozillaHomeLocalityName"];
[entry setObject: [tmp flattenedValueAtIndex: 4 forKey: @""]
forKey: @"mozillaHomeState"];
[entry setObject: [tmp flattenedValueAtIndex: 5 forKey: @""]
forKey: @"mozillaHomePostalCode"];
[entry setObject: [tmp flattenedValueAtIndex: 6 forKey: @""]
forKey: @"mozillaHomeCountryName"];
element = [elements objectAtIndex: 0];
[self _setValue: @"mozillahomestreet2"
to: [element flattenedValueAtIndex: 1 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomestreet"
to: [element flattenedValueAtIndex: 2 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomelocalityname"
to: [element flattenedValueAtIndex: 3 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomestate"
to: [element flattenedValueAtIndex: 4 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomepostalcode"
to: [element flattenedValueAtIndex: 5 forKey: @""]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomecountryname"
to: [element flattenedValueAtIndex: 6 forKey: @""]
inLDIFRecord: ldifRecord];
}
element = [self org];
tmp = [element flattenedValueAtIndex: 0 forKey: @""];
if ([tmp length] > 0)
[entry setObject: tmp forKey: @"o"];
array = [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"];
if ([array count])
elements = [self childrenWithTag: @"url"];
[self _setValue: @"mozillaworkurl"
to: [self _simpleValueForType: @"work" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
[self _setValue: @"mozillahomeurl"
to: [self _simpleValueForType: @"home" inArray: elements
excluding: nil]
inLDIFRecord: ldifRecord];
// If we don't have a "work" or "home" URL but we still have
// an URL field present, let's add it to the "home" value
if ([[ldifRecord objectForKey: @"mozillaworkurl"] length] == 0 &&
[[ldifRecord objectForKey: @"mozillahomeurl"] length] == 0 &&
[elements count] > 0)
[self _setValue: @"mozillahomeurl"
to: [[elements objectAtIndex: 0]
flattenedValuesForKey: @""]
inLDIFRecord: ldifRecord];
// If we do have a "work" URL but no "home" URL but two
// values URLs present, let's add the second one as the home URL
else if ([[ldifRecord objectForKey: @"mozillaworkurl"] length] > 0 &&
[[ldifRecord objectForKey: @"mozillahomeurl"] length] == 0 &&
[elements count] > 1)
{
tmp = [array objectAtIndex: 0];
[entry setObject: [tmp flattenedValueAtIndex: 1 forKey: @""]
forKey: @"mozillaWorkStreet2"];
[entry setObject: [tmp flattenedValueAtIndex: 2 forKey: @""]
forKey: @"street"];
[entry setObject: [tmp flattenedValueAtIndex: 3 forKey: @""]
forKey: @"l"];
[entry setObject: [tmp flattenedValueAtIndex: 4 forKey: @""]
forKey: @"st"];
[entry setObject: [tmp flattenedValueAtIndex: 5 forKey: @""]
forKey: @"postalCode"];
[entry setObject: [tmp flattenedValueAtIndex: 6 forKey: @""]
forKey: @"c"];
int i;
for (i = 0; i < [elements count]; i++)
{
if ([[[elements objectAtIndex: i] flattenedValuesForKey: @""]
caseInsensitiveCompare: [ldifRecord objectForKey: @"mozillaworkurl"]] != NSOrderedSame)
{
[self _setValue: @"mozillahomeurl"
to: [[elements objectAtIndex: i]
flattenedValuesForKey: @""]
inLDIFRecord: ldifRecord];
break;
}
}
}
[self _setValue: @"title" to: [self title] inLDIFRecord: ldifRecord];
[self _setupOrgFieldsInLDIFRecord: ldifRecord];
array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"work"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"telephoneNumber"];
categories = [self categories];
if ([categories count] > 0)
[ldifRecord setValue: categories forKey: @"vcardcategories"];
array = [self childrenWithTag: @"url" andAttribute: @"type" havingValue: @"work"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"workurl"];
birthDay = [[self bday] asCalendarDate];
if (birthDay)
{
stringValue = [NSString stringWithFormat: @"%.4d", [birthDay yearOfCommonEra]];
[self _setValue: @"birthyear" to: stringValue inLDIFRecord: ldifRecord];
stringValue = [NSString stringWithFormat: @"%.2d", [birthDay monthOfYear]];
[self _setValue: @"birthmonth" to: stringValue inLDIFRecord: ldifRecord];
stringValue = [NSString stringWithFormat: @"%.2d", [birthDay dayOfMonth]];
[self _setValue: @"birthday" to: stringValue inLDIFRecord: ldifRecord];
}
[self _setValue: @"description" to: [self note] inLDIFRecord: ldifRecord];
array = [self childrenWithTag: @"url" andAttribute: @"type" havingValue: @"home"];
if ([array count])
[entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""]
forKey: @"homeurl"];
stringValue = [ldifRecord objectForKey: @"displayname"];
stringValue2 = [ldifRecord objectForKey: @"mail"];
if ([stringValue length] > 0)
{
if ([stringValue2 length] > 0)
dn = [NSString stringWithFormat: @"cn=%@,mail=%@",
stringValue, stringValue2];
else
dn = [NSString stringWithFormat: @"cn=%@", stringValue];
}
else if ([stringValue2 length] > 0)
dn = [NSString stringWithFormat: @"mail=%@", stringValue2];
else
dn = @"";
[ldifRecord setObject: dn forKey: @"dn"];
tmp = [self note];
if (tmp && [tmp length])
[entry setObject: tmp forKey: @"description"];
rc = [NSMutableString stringWithString: [entry userRecordAsLDIFEntry]];
[rc appendFormat: @"\n"];
return rc;
return ldifRecord;
}
@end /* NGVCard */
+2 -2
View File
@@ -27,7 +27,7 @@
#import <NGCards/NGVCardReference.h>
#import <SOGo/NSDictionary+Utilities.h>
#import "NSDictionary+LDIF.h"
#import "NGVList+SOGo.h"
@@ -65,7 +65,7 @@
}
[entry setObject: members forKey: @"member"];
rc = [NSMutableString stringWithString: [entry userRecordAsLDIFEntry]];
rc = [NSMutableString stringWithString: [entry ldifRecordAsString]];
[rc appendFormat: @"\n"];
return rc;
+34
View File
@@ -0,0 +1,34 @@
/* NSDictionary+LDIF.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 NSDICTIONARY_LDIF_H
#define NSDICTIONARY_LDIF_H
#import <Foundation/NSDictionary.h>
@interface NSDictionary (SOGoLDIF)
- (NSString *) ldifRecordAsString;
@end
#endif /* NSDICTIONARY_LDIF_H */
+111
View File
@@ -0,0 +1,111 @@
/* NSDictionary+LDIF.m - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSString+LDIF.h"
#import "NSDictionary+LDIF.h"
@implementation NSDictionary (SOGoLDIF)
- (void) _appendLDIFKey: (NSString *) key
value: (NSString *) value
toString: (NSMutableString *) ldifString
{
if ([value isKindOfClass: [NSString class]] && [value length] > 0)
{
if ([value mustEncodeLDIFValue])
[ldifString appendFormat: @"%@:: %@\n",
key, [value stringByEncodingBase64]];
else
[ldifString appendFormat: @"%@: %@\n", key, value];
}
}
- (void) _appendLDIFKey: (NSString *) key
toString: (NSMutableString *) ldifString
{
id value;
int count, max;
value = [self objectForKey: key];
if ([value isKindOfClass: [NSArray class]])
{
max = [value count];
for (count = 0; count < max; count++)
[self _appendLDIFKey: key value: [value objectAtIndex: count]
toString: ldifString];
}
else
[self _appendLDIFKey: key value: [self objectForKey: key]
toString: ldifString];
}
- (void) _appendObjectClassesToString: (NSMutableString *) ldifString
{
NSEnumerator *classes;
NSString *currentClass;
NSArray *objectClass;
objectClass = [self objectForKey: @"objectClass"];
if ([objectClass isKindOfClass: [NSString class]])
[self _appendLDIFKey: @"objectClass" value: (NSString *) objectClass
toString: ldifString];
else
{
classes = [objectClass objectEnumerator];
while ((currentClass = [classes nextObject]))
[self _appendLDIFKey: @"objectClass" value: currentClass
toString: ldifString];
}
}
- (NSString *) ldifRecordAsString
{
NSArray *keys;
NSMutableString *ldifString;
NSUInteger count, max;
NSString *currentKey;
// {CalendarAccess = YES; MailAccess = YES; c_cn = "Wolfgang Sourdeau"; c_emails = ("wolfgang@test.com"); c_name = "wolfgang@test.com"; c_uid = "wolfgang@test.com"; cn = "wolfgang@test.com"; displayName = "Wolfgang Sourdeau"; dn = "cn=wolfgang@test.com,ou=evariste,o=inverse.ca"; givenName = Wolfgang; mail = "wolfgang@test.com"; objectClass = organizationalPerson; sn = Sourdeau; }
ldifString = [NSMutableString string];
[self _appendLDIFKey: @"dn" toString: ldifString];
[self _appendObjectClassesToString: ldifString];
keys = [self allKeys];
max = [keys count];
for (count = 0; count < max; count++)
{
currentKey = [keys objectAtIndex: count];
if (!([currentKey hasPrefix: @"objectClass"]
|| [currentKey isEqualToString: @"dn"]))
[self _appendLDIFKey: currentKey toString: ldifString];
}
return ldifString;
}
@end
+34
View File
@@ -0,0 +1,34 @@
/* NSString+LDIF.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 NSSTRING_LDIF_H
#define NSSTRING_LDIF_H
#import <Foundation/NSString.h>
@interface NSString (SOGoLDIF)
- (BOOL) mustEncodeLDIFValue;
@end
#endif /* NSSTRING_LDIF_H */
+67
View File
@@ -0,0 +1,67 @@
/* NSString+LDIF.m - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 <Foundation/NSCharacterSet.h>
#import "NSString+LDIF.h"
@implementation NSString (SOGoLDIF)
static NSMutableCharacterSet *safeLDIFChars = nil;
static NSMutableCharacterSet *safeLDIFStartChars = nil;
- (void) _initSafeLDIFChars
{
safeLDIFChars = [NSMutableCharacterSet new];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x01, 9)];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x0b, 2)];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x0e, 114)];
safeLDIFStartChars = [safeLDIFChars mutableCopy];
[safeLDIFStartChars removeCharactersInString: @" :<"];
}
- (BOOL) mustEncodeLDIFValue
{
int count, max;
BOOL rc;
if (!safeLDIFChars)
[self _initSafeLDIFChars];
rc = NO;
max = [self length];
if (max > 0)
{
if ([safeLDIFStartChars characterIsMember: [self characterAtIndex: 0]])
for (count = 1; !rc && count < max; count++)
rc = ![safeLDIFChars
characterIsMember: [self characterAtIndex: count]];
else
rc = YES;
}
return rc;
}
@end
@@ -30,11 +30,6 @@
int photoID;
}
+ (id) entryPhotoWithID: (int) photoId
inContainer: (id) container;
- (void) setPhotoID: (int) newPhotoID;
- (NSString *) davContentType;
@end
+1 -28
View File
@@ -35,36 +35,9 @@
@implementation SOGoContactEntryPhoto
+ (id) entryPhotoWithID: (int) photoID
inContainer: (id) container
{
id photo;
photo
= [super objectWithName: [NSString stringWithFormat: @"photo%d", photoID]
inContainer: container];
[photo setPhotoID: photoID];
return photo;
}
- (void) setPhotoID: (int) newPhotoID
{
photoID = newPhotoID;
}
- (NGVCardPhoto *) photo
{
NGVCardPhoto *photo;
NSArray *photoElements;
photoElements = [[container vCard] childrenWithTag: @"photo"];
if ([photoElements count] > photoID)
photo = [photoElements objectAtIndex: photoID];
else
photo = nil;
return photo;
return (NGVCardPhoto *) [[container vCard] firstChildWithTag: @"photo"];
}
- (id) GETAction: (WOContext *) localContext
+4
View File
@@ -27,6 +27,10 @@
@interface SOGoContactFolders : SOGoParentFolder
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
withDisplayName: (NSString *) newDisplayName;
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
@end
#endif /* SOGOCONTACTFOLDERS_H */
+140
View File
@@ -33,6 +33,7 @@
#import <Foundation/NSEnumerator.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
@@ -45,6 +46,7 @@
#import "SOGoContactGCSFolder.h"
#import "SOGoContactSourceFolder.h"
#import "SOGoContactFolders.h"
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@@ -60,6 +62,62 @@
return [SOGoContactGCSFolder class];
}
- (void) _fetchLDAPAddressBooks: (id <SOGoSource>) source
{
id <SOGoSource> abSource;
SOGoContactSourceFolder *folder;
NSArray *abSources;
NSUInteger count, max;
NSString *name;
abSources = [source addressBookSourcesForUser: owner];
max = [abSources count];
for (count = 0; count < max; count++)
{
abSource = [abSources objectAtIndex: count];
name = [abSource sourceID];
folder = [SOGoContactSourceFolder folderWithName: name
andDisplayName: [abSource displayName]
inContainer: self];
[folder setSource: abSource];
[folder setIsPersonalSource: YES];
[subFolders setObject: folder forKey: name];
}
}
- (NSException *) appendPersonalSources
{
SOGoUser *currentUser;
NSException *result;
id <SOGoSource> source;
currentUser = [context activeUser];
source = [currentUser authenticationSource];
if ([source hasUserAddressBooks])
{
result = nil;
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
the owner has access to his addressbooks. */
if (activeUserIsOwner
|| [[currentUser login] isEqualToString: owner])
{
[self _fetchLDAPAddressBooks: source];
if (![subFolders objectForKey: @"personal"])
{
result = [source addAddressBookSource: @"personal"
withDisplayName: [self defaultFolderName]
forUser: owner];
if (!result)
[self _fetchLDAPAddressBooks: source];
}
}
}
else
result = [super appendPersonalSources];
return result;
}
- (NSException *) appendSystemSources
{
SOGoUserManager *um;
@@ -101,6 +159,88 @@
return nil;
}
- (NSException *) newFolderWithName: (NSString *) name
andNameInContainer: (NSString *) newNameInContainer
{
SOGoUser *currentUser;
NSException *result;
id <SOGoSource> source;
currentUser = [context activeUser];
source = [currentUser authenticationSource];
if ([source hasUserAddressBooks])
{
result = nil;
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
the owner has access to his addressbooks. */
if (activeUserIsOwner
|| [[currentUser login] isEqualToString: owner])
{
result = [source addAddressBookSource: newNameInContainer
withDisplayName: name
forUser: owner];
if (!result)
[self _fetchLDAPAddressBooks: source];
}
}
else
result = [super newFolderWithName: name
andNameInContainer: newNameInContainer];
return result;
}
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
withDisplayName: (NSString *) newDisplayName
{
NSException *result;
SOGoUser *currentUser;
id <SOGoSource> source;
currentUser = [context activeUser];
source = [currentUser authenticationSource];
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
the owner has access to his addressbooks. */
if (activeUserIsOwner
|| [[currentUser login] isEqualToString: owner])
result = [source renameAddressBookSource: sourceID
withDisplayName: newDisplayName
forUser: owner];
else
result = [NSException exceptionWithHTTPStatus: 403
reason: @"operation denied"];
return result;
}
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID
{
NSException *result;
SOGoUser *currentUser;
id <SOGoSource> source;
if ([sourceID isEqualToString: @"personal"])
result = [NSException exceptionWithHTTPStatus: 403
reason: @"folder 'personal' cannot be deleted"];
else
{
result = nil;
currentUser = [context activeUser];
source = [currentUser authenticationSource];
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
the owner has access to his addressbooks. */
if (activeUserIsOwner
|| [[currentUser login] isEqualToString: owner])
result = [source removeAddressBookSource: sourceID
forUser: owner];
else
result = [NSException exceptionWithHTTPStatus: 403
reason: @"operation denied"];
}
return result;
}
- (NSString *) defaultFolderName
{
+30 -12
View File
@@ -19,11 +19,15 @@
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGCards/NGVCard.h>
#import <NGCards/NGVCardPhoto.h>
#import "NGVCard+SOGo.h"
#import "SOGoContactEntryPhoto.h"
#import "SOGoContactGCSEntry.h"
@@ -62,6 +66,21 @@
return card;
}
- (void) setLDIFRecord: (NSDictionary *) newLDIFRecord
{
[[self vCard] updateFromLDIFRecord: newLDIFRecord];
}
- (NSDictionary *) ldifRecord
{
return [[self vCard] asLDIFRecord];
}
- (BOOL) hasPhoto
{
return ([[self vCard] firstChildWithTag: @"photo"] != nil);
}
/* actions */
- (id) lookupName: (NSString *) lookupName
@@ -69,16 +88,12 @@
acquire: (BOOL) acquire
{
id obj;
int photoIndex;
NSArray *photoElements;
if ([lookupName hasPrefix: @"photo"])
if ([lookupName isEqualToString: @"photo"])
{
photoElements = [[self vCard] childrenWithTag: @"photo"];
photoIndex = [[lookupName substringFromIndex: 5] intValue];
if (photoIndex > -1 && photoIndex < [photoElements count])
obj = [SOGoContactEntryPhoto entryPhotoWithID: photoIndex
inContainer: self];
if ([self hasPhoto])
obj = [SOGoContactEntryPhoto objectWithName: lookupName
inContainer: self];
else
obj = nil;
}
@@ -127,13 +142,16 @@
/* specialized actions */
- (void) save
- (NSException *) save
{
NGVCard *vcard;
NSException *result;
vcard = [self vCard];
if (card)
result = [self saveContentString: [card versitString]];
else
result = nil; /* TODO: we should probably return an exception instead */
[self saveContentString: [vcard versitString]];
return result;
}
- (NSException *) saveContentString: (NSString *) newContent
+1 -5
View File
@@ -45,6 +45,7 @@
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/NSObject+DAV.h>
#import <SOGo/WORequest+SOGo.h>
#import "SOGoContactGCSEntry.h"
#import "SOGoContactGCSList.h"
@@ -375,11 +376,6 @@ static NSArray *folderListingFields = nil;
return @"Contact";
}
- (NSString *) outlookFolderClass
{
return @"IPF.Contact";
}
/* TODO: multiget reorg */
- (NSString *) _nodeTagForProperty: (NSString *) property
{
+4 -1
View File
@@ -31,8 +31,8 @@
@interface SOGoContactLDIFEntry : SOGoObject <SOGoContactObject>
{
BOOL isNew;
NSDictionary *ldifEntry;
NGVCard *vcard;
}
+ (SOGoContactLDIFEntry *) contactEntryWithName: (NSString *) newName
@@ -42,6 +42,9 @@
withLDIFEntry: (NSDictionary *) newEntry
inContainer: (id) newContainer;
- (BOOL) isNew;
- (void) setIsNew: (BOOL) newIsNew;
- (NSString *) davEntityTag;
@end
+75 -157
View File
@@ -29,9 +29,13 @@
#import <NGCards/CardVersitRenderer.h>
#import <SOGo/SOGoBuild.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoPermissions.h>
#import "NGVCard+SOGo.h"
#import "SOGoContactGCSEntry.h"
#import "SOGoContactLDIFEntry.h"
#import "SOGoContactSourceFolder.h"
@implementation SOGoContactLDIFEntry
@@ -42,8 +46,8 @@
SOGoContactLDIFEntry *entry;
entry = [[self alloc] initWithName: newName
withLDIFEntry: newEntry
inContainer: newContainer];
withLDIFEntry: newEntry
inContainer: newContainer];
[entry autorelease];
return entry;
@@ -56,7 +60,7 @@
if ((self = [self initWithName: newName inContainer: newContainer]))
{
ASSIGN (ldifEntry, newEntry);
vcard = nil;
isNew = NO;
}
return self;
@@ -64,169 +68,34 @@
- (void) dealloc
{
[vcard release];
[ldifEntry release];
[super dealloc];
}
- (BOOL) isNew
{
return isNew;
}
- (void) setIsNew: (BOOL) newIsNew
{
isNew = newIsNew;
}
- (NSString *) contentAsString
{
return [[self vCard] versitString];
}
- (void) _setPhonesOfVCard: (NGVCard *) vCard
{
NSString *info;
info = [ldifEntry objectForKey: @"telephonenumber"];
if (info)
[vCard addTel: info
types: [NSArray arrayWithObjects: @"work", @"voice", @"pref", nil]];
info = [ldifEntry objectForKey: @"homephone"];
if (info)
[vCard addTel: info
types: [NSArray arrayWithObjects: @"home", @"voice", nil]];
info = [ldifEntry objectForKey: @"fax"];
if (info)
[vCard addTel: info
types: [NSArray arrayWithObjects: @"work", @"fax", nil]];
info = [ldifEntry objectForKey: @"pager"];
if (info)
[vCard addTel: info
types: [NSArray arrayWithObjects: @"pager", nil]];
info = [ldifEntry objectForKey: @"mobile"];
if (info)
[vCard addTel: info
types: [NSArray arrayWithObjects: @"cell", @"voice", nil]];
// telephoneNumber: work phone
// homePhone: home phone
// fax: fax phone
// pager: page phone
// mobile: mobile phone
}
- (NGVCard *) vCard
{
NSString *info, *surname, *streetAddress, *location, *region, *postalCode, *country, *org, *orgunit;
CardElement *element;
unsigned int count;
NGVCard *vcard;
if (!vcard)
{
vcard = [[NGVCard alloc] initWithUid: [self nameInContainer]];
[vcard setVClass: @"PUBLIC"];
[vcard setProdID: [NSString
stringWithFormat: @"-//Inverse inc./SOGo %@//EN",
SOGoVersion]];
[vcard setProfile: @"VCARD"];
info = [ldifEntry objectForKey: @"c_cn"];
if (![info length])
{
info = [ldifEntry objectForKey: @"displayname"];
if (![info length])
info = [ldifEntry objectForKey: @"cn"];
}
[vcard setFn: info];
surname = [ldifEntry objectForKey: @"sn"];
if (!surname)
surname = [ldifEntry objectForKey: @"surname"];
[vcard setNWithFamily: surname
given: [ldifEntry objectForKey: @"givenname"]
additional: nil
prefixes: nil
suffixes: nil];
info = [ldifEntry objectForKey: @"title"];
if (info)
[vcard setTitle: info];
info = [ldifEntry objectForKey: @"mozillanickname"];
if (info)
[vcard setNickname: info];
/* If "c_info" is defined, we set as the NOTE value in order for
Thunderbird (or any other CardDAV client) to display it. */
info = [ldifEntry objectForKey: @"c_info"];
if (![info length])
info = [ldifEntry objectForKey: @"description"];
if ([info length])
[vcard setNote: info];
info = [ldifEntry objectForKey: @"mail"];
if (info)
[vcard addEmail: info
types: [NSArray arrayWithObjects: @"internet", @"pref", nil]];
[self _setPhonesOfVCard: vcard];
streetAddress = [ldifEntry objectForKey: @"street"];
if (!streetAddress)
streetAddress = [ldifEntry objectForKey: @"streetaddress"];
location = [ldifEntry objectForKey: @"l"];
if (!location)
location = [ldifEntry objectForKey: @"locality"];
region = [ldifEntry objectForKey: @"st"];
if (!region)
region = [ldifEntry objectForKey: @"region"];
postalCode = [ldifEntry objectForKey: @"postalcode"];
if (!postalCode)
postalCode = [ldifEntry objectForKey: @"zip"];
country = [ldifEntry objectForKey: @"c"];
if (!country)
country = [ldifEntry objectForKey: @"countryname"];
element = [CardElement elementWithTag: @"adr"];
[element setValue: 0 ofAttribute: @"type" to: @"work"];
if (streetAddress)
[element setSingleValue: streetAddress atIndex: 2 forKey: @""];
if (location)
[element setSingleValue: location atIndex: 3 forKey: @""];
if (region)
[element setSingleValue: region atIndex: 4 forKey: @""];
if (postalCode)
[element setSingleValue: postalCode atIndex: 5 forKey: @""];
if (country)
[element setSingleValue: country atIndex: 6 forKey: @""];
if (streetAddress || location || region || postalCode || country)
[vcard addChild: element];
// We handle the org/orgunit stuff
element = [CardElement elementWithTag: @"org"];
org = [ldifEntry objectForKey: @"o"];
orgunit = [ldifEntry objectForKey: @"ou"];
if (!orgunit)
orgunit = [ldifEntry objectForKey: @"orgunit"];
if (org)
[element setSingleValue: org atIndex: 0 forKey: @""];
if (orgunit)
[element setSingleValue: orgunit atIndex: 1 forKey: @""];
if (org || orgunit)
[vcard addChild: element];
info = [ldifEntry objectForKey: @"calFBURL"];
if (info)
[vcard addChildWithTag: @"FBURL"
types: nil
singleValue: info];
for (count = 1; count < 5; count++)
{
info = [ldifEntry objectForKey:
[NSString stringWithFormat: @"mozillacustom%d",
count]];
if (info)
[vcard addChildWithTag: [NSString stringWithFormat: @"CUSTOM%d",
count]
types: nil
singleValue: info];
}
}
vcard = [NGVCard cardWithUid: [self nameInContainer]];
[vcard setProdID: [NSString
stringWithFormat: @"-//Inverse inc./SOGo %@//EN",
SOGoVersion]];
[vcard updateFromLDIFRecord: [self ldifRecord]];
return vcard;
}
@@ -236,6 +105,21 @@
return NO;
}
- (void) setLDIFRecord: (NSDictionary *) newLDIFRecord
{
ASSIGN (ldifEntry, newLDIFRecord);
}
- (NSDictionary *) ldifRecord
{
return ldifEntry;
}
- (BOOL) hasPhoto
{
return NO;
}
- (NSString *) davEntityTag
{
unsigned int hash;
@@ -251,13 +135,47 @@
return @"text/x-vcard";
}
- (NSArray *) aclsForUser: (NSString *) uid
- (NSException *) save
{
return nil;
return [(SOGoContactSourceFolder *) container saveLDIFEntry: self];
}
- (void) save
- (NSException *) delete
{
return [(SOGoContactSourceFolder *) container deleteLDIFEntry: self];
}
/* acl */
- (NSArray *) aclsForUser: (NSString *) uid
{
NSMutableArray *acls;
NSArray *containerAcls;
acls = [NSMutableArray array];
/* this is unused... */
// ownAcls = [container aclsForUser: uid
// forObjectAtPath: [self pathArrayToSOGoObject]];
// [acls addObjectsFromArray: ownAcls];
containerAcls = [container aclsForUser: uid];
if ([containerAcls count] > 0)
{
[acls addObjectsFromArray: containerAcls];
/* The creation of an object is actually a "modification" to an
unexisting object. When the object is new, we give the
"ObjectCreator" the "ObjectModifier" role temporarily while we
disallow the "ObjectModifier" users to modify them, unless they are
ObjectCreators too. */
if (isNew)
{
if ([containerAcls containsObject: SOGoRole_ObjectCreator])
[acls addObject: SOGoRole_ObjectEditor];
else
[acls removeObject: SOGoRole_ObjectEditor];
}
}
return acls;
}
/* DAV */
+8 -13
View File
@@ -22,25 +22,20 @@
#ifndef __Contacts_SOGoContactObject_H__
#define __Contacts_SOGoContactObject_H__
/*
SOGoContactObject
Represents a single contact. This SOPE controller object manages all the
attendee storages (that is, it might store into multiple folders for meeting
appointments!).
Note: SOGoContactObject do not need to exist yet. They can also be "new"
appointments with an externally generated unique key.
*/
@class NSDictionary;
@class NSString;
@class NGVCard;
@protocol SOGoContactObject
- (NGVCard *) vCard;
- (void) save;
- (BOOL) hasPhoto;
/* web editing */
- (void) setLDIFRecord: (NSDictionary *) newLDIFRecord;
- (NSDictionary *) ldifRecord;
- (NSException *) save;
- (NSException *) delete;
@end
+12 -4
View File
@@ -26,14 +26,16 @@
#import "SOGoContactFolder.h"
#import "SOGoFolder+CardDAV.h"
@class NSMutableDictionary;
#import <SOGo/SOGoSource.h>
#import "../SOGo/SOGoSource.h"
@class NSMutableDictionary;
@class SOGoContactLDIFEntry;
@interface SOGoContactSourceFolder : SOGoFolder <SOGoContactFolder>
{
id source;
id <SOGoSource> source;
NSMutableDictionary *childRecords;
BOOL isPersonalSource;
}
+ (id) folderWithName: (NSString *) aName
@@ -42,7 +44,13 @@
- (id) initWithName: (NSString *) newName
andDisplayName: (NSString *) newDisplayName
inContainer: (id) newContainer;
- (void) setSource: (id) newSource;
- (void) setSource: (id <SOGoSource>) newSource;
- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry;
- (NSException *) deleteLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry;
- (void) setIsPersonalSource: (BOOL) isPersonal;
- (BOOL) isPersonalSource;
@end
+152 -16
View File
@@ -38,11 +38,16 @@
#import <EOControl/EOSortOrdering.h>
#import <SaxObjC/XMLNamespaces.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/WORequest+SOGo.h>
#import "SOGoContactFolders.h"
#import "SOGoContactGCSFolder.h"
#import "SOGoContactLDIFEntry.h"
#import "SOGoContactSourceFolder.h"
@@ -97,11 +102,26 @@
[super dealloc];
}
- (void) setSource: (id) newSource
- (void) setSource: (id <SOGoSource>) newSource
{
ASSIGN (source, newSource);
}
- (id <SOGoSource>) source
{
return source;
}
- (void) setIsPersonalSource: (BOOL) isPersonal
{
isPersonalSource = isPersonal;
}
- (BOOL) isPersonalSource
{
return isPersonalSource;
}
- (NSString *) groupDavResourceType
{
return @"vcard-collection";
@@ -127,7 +147,10 @@
acquire: (BOOL) acquire
{
NSDictionary *ldifEntry;
id obj;
SOGoContactLDIFEntry *obj;
NSString *url;
BOOL isNew = NO;
NSArray *baseClasses;
/* first check attributes directly bound to the application */
obj = [super lookupName: objectName inContext: lookupContext acquire: NO];
@@ -140,11 +163,28 @@
ldifEntry = [source lookupContactEntry: objectName];
if (ldifEntry)
[childRecords setObject: ldifEntry forKey: objectName];
else if ([self isValidContentName: objectName])
{
url = [[[lookupContext request] uri] urlWithoutParameters];
if ([url hasSuffix: @"AsContact"])
{
baseClasses = [NSArray arrayWithObjects: @"inetorgperson",
@"mozillaabpersonalpha", nil];
ldifEntry = [NSMutableDictionary
dictionaryWithObject: baseClasses
forKey: @"objectclass"];
isNew = YES;
}
}
}
if (ldifEntry)
obj = [SOGoContactLDIFEntry contactEntryWithName: objectName
withLDIFEntry: ldifEntry
inContainer: self];
{
obj = [SOGoContactLDIFEntry contactEntryWithName: objectName
withLDIFEntry: ldifEntry
inContainer: self];
if (isNew)
[obj setIsNew: YES];
}
else
obj = [NSException exceptionWithHTTPStatus: 404];
}
@@ -157,6 +197,19 @@
return [source allEntryIDs];
}
- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry
{
return (([ldifEntry isNew])
? [source addContactEntry: [ldifEntry ldifRecord]
withID: [ldifEntry nameInContainer]]
: [source updateContactEntry: [ldifEntry ldifRecord]]);
}
- (NSException *) deleteLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry
{
return [source removeContactEntryWithID: [ldifEntry nameInContainer]];
}
- (NSDictionary *) _flattenedRecord: (NSDictionary *) oldRecord
{
NSMutableDictionary *newRecord;
@@ -267,7 +320,8 @@
result = nil;
if ([filter length] > 0 && [criteria isEqualToString: @"name_or_address"])
if (([filter length] > 0 && [criteria isEqualToString: @"name_or_address"])
|| ![source listRequiresDot])
{
records = [source fetchContactsMatching: filter];
[childRecords setObjects: records
@@ -308,22 +362,88 @@
- (NSComparisonResult) compare: (id) otherFolder
{
NSComparisonResult comparison;
BOOL otherIsPersonal;
if ([NSStringFromClass([otherFolder class])
isEqualToString: @"SOGoContactGCSFolder"])
comparison = NSOrderedDescending;
otherIsPersonal = ([otherFolder isKindOfClass: [SOGoContactGCSFolder class]]
|| ([otherFolder isKindOfClass: isa] && [otherFolder isPersonalSource]));
if (isPersonalSource)
{
if (otherIsPersonal && ![nameInContainer isEqualToString: @"personal"])
{
if ([[otherFolder nameInContainer] isEqualToString: @"personal"])
comparison = NSOrderedDescending;
else
comparison
= [[self displayName]
localizedCaseInsensitiveCompare: [otherFolder displayName]];
}
else
comparison = NSOrderedAscending;
}
else
comparison
= [[self displayName]
localizedCaseInsensitiveCompare: [otherFolder displayName]];
{
if (otherIsPersonal)
comparison = NSOrderedDescending;
else
comparison
= [[self displayName]
localizedCaseInsensitiveCompare: [otherFolder displayName]];
}
return comparison;
}
/* common methods */
- (NSException *) delete
{
NSException *error;
if (isPersonalSource)
{
error = [(SOGoContactFolders *) container
removeLDAPAddressBook: nameInContainer];
if (!error && [[context request] handledByDefaultHandler])
[self sendFolderAdvisoryTemplate: @"Removal"];
}
else
error = [NSException exceptionWithHTTPStatus: 501 /* not implemented */
reason: @"delete not available on system sources"];
return error;
}
- (void) renameTo: (NSString *) newName
{
NSException *error;
if (isPersonalSource)
{
if (![[source displayName] isEqualToString: newName])
{
error = [(SOGoContactFolders *) container
renameLDAPAddressBook: nameInContainer
withDisplayName: newName];
if (!error)
[self setDisplayName: newName];
}
}
/* If public source then method is ignored, maybe we should return an
NSException instead... */
}
/* acls */
- (NSString *) ownerInContext: (WOContext *) noContext
{
return @"nobody";
NSString *sourceOwner;
if (isPersonalSource)
sourceOwner = [[source modifiers] objectAtIndex: 0];
else
sourceOwner = @"nobody";
return sourceOwner;
}
- (NSArray *) subscriptionRoles
@@ -331,10 +451,26 @@
return [NSArray arrayWithObject: SoRole_Authenticated];
}
/* TODO: this might change one day when we support LDAP acls */
- (NSArray *) aclsForUser: (NSString *) uid
{
return nil;
NSArray *acls, *modifiers;
static NSArray *modifierRoles = nil;
if (!modifierRoles)
modifierRoles = [[NSArray alloc] initWithObjects: @"Owner",
@"ObjectViewer",
@"ObjectEditor", @"ObjectCreator",
@"ObjectEraser", nil];
modifiers = [source modifiers];
if ([modifiers containsObject: uid])
acls = [modifierRoles copy];
else
acls = [NSArray new];
[acls autorelease];
return acls;
}
@end
+4 -4
View File
@@ -118,10 +118,10 @@
newString = [theString lowercaseString];
return ([theString isEqualToString: @"sn"]
|| [theString isEqualToString: @"givenname"]
|| [theString isEqualToString: @"mail"]
|| [theString isEqualToString: @"telephonenumber"]);
return ([newString isEqualToString: @"sn"]
|| [newString isEqualToString: @"givenname"]
|| [newString isEqualToString: @"mail"]
|| [newString isEqualToString: @"telephonenumber"]);
}
- (NSDictionary *) _parseContactFilter: (id <DOMElement>) filterElement
+4 -2
View File
@@ -82,10 +82,14 @@
- (void) markForExpunge;
- (void) expungeLastMarkedFolder;
- (BOOL) exists;
- (BOOL) create;
- (NSException *) expunge;
- (NSException *) renameTo: (NSString *) newName;
- (NSCalendarDate *) mostRecentMessageDate;
/* flags */
@@ -94,8 +98,6 @@
/* folder type */
- (NSString *) outlookFolderClass;
- (NSArray *) subfolders;
- (BOOL) isSpecialFolder;
+56 -30
View File
@@ -248,7 +248,7 @@ static NSString *defaultUserID = @"anyone";
if (!filenames)
{
filenames = [NSMutableArray new];
if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]])
if ([self exists])
{
uids = [self fetchUIDsMatchingQualifier: nil sortOrdering: @"DATE"];
if (![uids isKindOfClass: [NSException class]])
@@ -267,6 +267,53 @@ static NSString *defaultUserID = @"anyone";
return filenames;
}
- (NSException *) renameTo: (NSString *) newName
{
NSException *error;
SOGoMailFolder *inbox;
NSURL *destURL;
NSString *path;
NGImap4Client *client;
if ([newName length] > 0)
{
[self imap4URL];
[self imap4Connection];
client = [imap4 client];
inbox = [[self mailAccountFolder] inboxFolderInContext: context];
[client select: [inbox absoluteImap4Name]];
path = [[imap4URL path] stringByDeletingLastPathComponent];
if (![path hasSuffix: @"/"])
path = [path stringByAppendingString: @"/"];
destURL = [[NSURL alloc] initWithScheme: [imap4URL scheme]
host: [imap4URL host]
path: [NSString stringWithFormat: @"%@%@",
path, newName]];
[destURL autorelease];
error = [imap4 moveMailboxAtURL: imap4URL
toURL: destURL];
if (!error)
{
// We unsubscribe to the old one, and subscribe back to the new one
if ([[[context activeUser] userDefaults]
mailShowSubscribedFoldersOnly])
{
[client subscribe: [destURL path]];
[client unsubscribe: [imap4URL path]];
}
}
}
else
error = [NSException exceptionWithName: @"SOGoMailException"
reason: @"given name is empty"
userInfo: nil];
return error;
}
/* messages */
- (void) prefetchCoreInfosForMessageKeys: (NSArray *) keys
{
@@ -508,7 +555,7 @@ static NSString *defaultUserID = @"anyone";
NSString *archiveName;
EOQualifier *notDeleted;
if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]])
if ([self exists])
{
notDeleted = [EOQualifier qualifierWithQualifierFormat:
@"(not (flags = %@))", @"deleted"];
@@ -675,7 +722,7 @@ static NSString *defaultUserID = @"anyone";
{
// We check for the existence of the IMAP folder (likely to be the
// Sent mailbox) prior to appending messages to it.
if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]]
if ([self exists]
|| ![[self imap4Connection] createMailbox: [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]]
atURL: [[self mailAccountFolder] imap4URL]])
return [[self imap4Connection] postData: _data flags: _flags
@@ -788,7 +835,7 @@ static NSString *defaultUserID = @"anyone";
inContainer: self];
}
else if (isdigit ([_key characterAtIndex: 0])
&& [[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]])
&& [self exists])
{
obj = [SOGoMailObject objectWithName: _key inContainer: self];
if ([_key hasSuffix: @".eml"])
@@ -816,6 +863,11 @@ static NSString *defaultUserID = @"anyone";
return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
}
- (BOOL) exists
{
return [[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]];
}
- (BOOL) create
{
NSException *error;
@@ -889,32 +941,6 @@ static NSString *defaultUserID = @"anyone";
return @"Mail";
}
- (NSString *) outlookFolderClass
{
// TODO: detect Trash/Sent/Drafts folders
SOGoMailAccount *account;
NSString *name;
if (!folderType)
{
account = [self mailAccountFolder];
name = [self traversalFromMailAccount];
if ([name isEqualToString: [account trashFolderNameInContext: nil]])
folderType = @"IPF.Trash";
else if ([name
isEqualToString: [account inboxFolderNameInContext: nil]])
folderType = @"IPF.Inbox";
else if ([name
isEqualToString: [account sentFolderNameInContext: nil]])
folderType = @"IPF.Sent";
else
folderType = @"IPF.Folder";
}
return folderType;
}
/* acls */
- (NSArray *) _imapAclsToSOGoAcls: (NSString *) imapAcls
-6
View File
@@ -25,10 +25,4 @@
@implementation SOGoSentFolder
/* folder type */
- (NSString *)outlookFolderClass {
return @"IPF.Sent";
}
@end /* SOGoSentFolder */
-6
View File
@@ -25,10 +25,4 @@
@implementation SOGoTrashFolder
/* folder type */
- (NSString *)outlookFolderClass {
return @"IPF.Trash";
}
@end /* SOGoTrashFolder */
+2
View File
@@ -28,6 +28,7 @@ SOGo_HEADER_FILES = \
\
SOGoUserManager.h \
LDAPSource.h \
LDAPSourceSchema.h \
SQLSource.h \
SOGoUserProfile.h \
SOGoDateFormatter.h \
@@ -97,6 +98,7 @@ SOGo_OBJC_FILES = \
SOGoStartupLogger.m \
SOGoUserManager.m \
LDAPSource.m \
LDAPSourceSchema.m \
SQLSource.m \
SOGoUserProfile.m \
SOGoSQLUserProfile.m \
+25 -4
View File
@@ -30,10 +30,12 @@
#include "SOGoSource.h"
#include "SOGoConstants.h"
@class NSDictionary;
@class NSString;
@class NGLdapConnection;
@class LDAPSourceSchema;
@class NGLdapEntry;
@class NSException;
@class NSMutableArray;
@class NSMutableDictionary;
@class NSString;
@interface LDAPSource : NSObject <SOGoDNSource>
{
@@ -41,6 +43,8 @@
int queryTimeout;
NSString *sourceID;
NSString *displayName;
NSString *bindDN; // The bindDN/password could be either the source's one
NSString *password; // or the current user if _bindAsCurrentUser is set to YES
NSString *sourceBindDN; // while sourceBindDN/sourceBindPassword always belong to the source
@@ -49,21 +53,27 @@
unsigned int port;
NSString *encryption;
NSString *_filter;
BOOL _bindAsCurrentUser;
NSString *_scope;
NSString *_userPasswordAlgorithm;
NSString *baseDN;
LDAPSourceSchema *schema;
NSString *IDField; // the first part of a user DN
NSString *CNField;
NSString *UIDField;
NSArray *mailFields, *searchFields;
NSString *IMAPHostField, *IMAPLoginField;
NSArray *bindFields;
BOOL _bindAsCurrentUser;
BOOL listRequiresDot;
NSString *domain;
NSString *contactInfoAttribute;
NSDictionary *contactMapping;
NSArray *contactObjectClasses;
NSDictionary *modulesConstraints;
NSMutableArray *searchAttributes;
@@ -77,6 +87,12 @@
NSString *multipleBookingsField;
NSString *MSExchangeHostname;
/* user addressbooks */
NSString *abOU;
/* ACL */
NSArray *modifiers;
}
- (void) setBindDN: (NSString *) newBindDN
@@ -98,6 +114,11 @@
kindField: (NSString *) newKindField
andMultipleBookingsField: (NSString *) newMultipleBookingsField;
/* This enable the convertion of a contact entry with inetOrgPerson and mozillaAbPerson
to and from an LDAP record */
- (void) setContactMapping: (NSDictionary *) newMapping
andObjectClasses: (NSArray *) newObjectClasses;
- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID;
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail;
- (NGLdapEntry *) lookupGroupEntryByAttribute: (NSString *) theAttribute
File diff suppressed because it is too large Load Diff
+45
View File
@@ -0,0 +1,45 @@
/* LDAPSourceSchema.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 LDAPSOURCESCHEMA_H
#define LDAPSOURCESCHEMA_H
#import <Foundation/NSObject.h>
@class NSMutableDictionary;
@class NGLdapConnection;
@interface LDAPSourceSchema : NSObject
{
NSMutableDictionary *schema;
}
- (void) readSchemaFromConnection: (NGLdapConnection *) conn;
- (NSArray *) fieldsForClass: (NSString *) className;
/* merged list of attributes with unique names */
- (NSArray *) fieldsForClasses: (NSArray *) className;
@end
#endif /* LDAPSOURCESCHEMA_H */
+295
View File
@@ -0,0 +1,295 @@
/* LDAPSourceSchema.m - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@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 2, 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 <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <EOControl/EOQualifier.h>
#import <NGLdap/NGLdapConnection.h>
#import <NGLdap/NGLdapAttribute.h>
#import <NGLdap/NGLdapEntry.h>
#import "LDAPSourceSchema.h"
#import "NSDictionary+Utilities.h"
static EOQualifier *allOCQualifier = nil;
@implementation LDAPSourceSchema
+ (void) initialize
{
allOCQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"objectClass"
operatorSelector: EOQualifierOperatorEqual
value: @"*"];
}
- (id) init
{
if ((self = [super init]))
{
schema = nil;
}
return self;
}
- (void) dealloc
{
[schema release];
[super dealloc];
}
static NSArray *
schemaTokens (NSString *schema)
{
unichar *characters;
NSUInteger count, max, parenLevel = 0, firstChar = (NSUInteger) -1;
NSMutableArray *arrayString, *parentArray, *currentArray = nil;
NSArray *topArray = nil;
NSString *token;
arrayString = [NSMutableArray array];
max = [schema length];
characters = malloc ((max + 1) * sizeof (unichar));
characters[max] = 0;
[schema getCharacters: characters];
for (count = 0; count < max; count++)
{
switch (characters[count])
{
case '(':
// NSLog (@"increase");
parenLevel++;
parentArray = currentArray;
currentArray = [NSMutableArray array];
if (parentArray == nil)
topArray = currentArray;
[parentArray addObject: currentArray];
[arrayString addObject: currentArray];
break;
case ')':
// NSLog (@"decrease");
parenLevel--;
[arrayString removeLastObject];
currentArray = [arrayString lastObject];
break;
case ' ':
if (firstChar != (NSUInteger) -1)
{
token = [NSString stringWithCharacters: characters + firstChar
length: (count - firstChar)];
if (![token isEqualToString: @"$"])
[currentArray addObject: token];
// NSLog (@"added token: %@", token);
firstChar = (NSUInteger) -1;
}
break;
default:
if (currentArray && (firstChar == (NSUInteger) -1))
firstChar = count;
}
}
free (characters);
return topArray;
}
static inline id
schemaValue (NSArray *tokens, NSString *key)
{
NSUInteger idx;
id value;
idx = [tokens indexOfObject: key];
if (idx != NSNotFound)
value = [tokens objectAtIndex: (idx + 1)];
else
value = nil;
return value;
}
static NSMutableDictionary *
parseSchema (NSString *schema)
{
NSArray *tokens;
NSMutableDictionary *schemaDict;
NSMutableArray *fields;
id value;
schemaDict = [NSMutableDictionary dictionaryWithCapacity: 6];
tokens = schemaTokens (schema);
// [schemaDict setObject: [tokens objectAtIndex: 0]
// forKey: @"oid"];
value = schemaValue (tokens, @"NAME");
if (value)
{
/* sometimes, objectClasses can have two names */
if ([value isKindOfClass: [NSString class]])
value = [NSArray arrayWithObject: value];
[schemaDict setObject: value forKey: @"names"];
}
value = schemaValue (tokens, @"SUP");
if (value)
[schemaDict setObject: value forKey: @"sup"];
fields = [NSMutableArray new];
[schemaDict setObject: fields forKey: @"fields"];
[fields release];
value = schemaValue (tokens, @"MUST");
if (value)
{
if ([value isKindOfClass: [NSArray class]])
[fields addObjectsFromArray: value];
else
[fields addObject: value];
}
value = schemaValue (tokens, @"MAY");
if (value)
{
if ([value isKindOfClass: [NSArray class]])
[fields addObjectsFromArray: value];
else
[fields addObject: value];
}
return schemaDict;
}
static void
fillSchemaFromEntry (NSMutableDictionary *schema, NGLdapEntry *entry)
{
NSEnumerator *strings;
NGLdapAttribute *attr;
NSMutableDictionary *schemaDict;
NSArray *names;
NSString *string, *name;
NSUInteger count, max;
attr = [entry attributeWithName: @"objectclasses"];
strings = [attr stringValueEnumerator];
while ((string = [strings nextObject]))
{
schemaDict = parseSchema (string);
names = [schemaDict objectForKey: @"names"];
max = [names count];
for (count = 0; count < max; count++)
{
name = [[names objectAtIndex: count] lowercaseString];
if ([name hasPrefix: @"'"] && [name hasSuffix: @"'"])
name
= [name substringWithRange: NSMakeRange (1, [name length] - 2)];
[schema setObject: schemaDict forKey: name];
}
/* the list of names is no longer required from the schema itself */
[schemaDict removeObjectForKey: @"names"];
}
}
- (void) readSchemaFromConnection: (NGLdapConnection *) conn
{
NSEnumerator *entries;
NGLdapEntry *entry;
NSString *dn;
ASSIGN (schema, [NSMutableDictionary new]);
[schema release];
entries = [conn baseSearchAtBaseDN: @""
qualifier: allOCQualifier
attributes: [NSArray arrayWithObject: @"subschemaSubentry"]];
entry = [entries nextObject];
if (entry)
{
dn = [[entry attributeWithName: @"subschemaSubentry"]
stringValueAtIndex: 0];
if (dn)
{
entries = [conn baseSearchAtBaseDN: dn
qualifier: allOCQualifier
attributes: [NSArray arrayWithObject: @"objectclasses"]];
entry = [entries nextObject];
if (entry)
fillSchemaFromEntry (schema, entry);
}
}
}
static void
fillFieldsForClass (NSMutableDictionary *schema, NSString *schemaName,
NSMutableArray *fields)
{
NSDictionary *schemaDict;
NSString *sup;
NSArray *schemaFields;
schemaDict = [schema objectForKey: [schemaName lowercaseString]];
if (schemaDict)
{
schemaFields = [schemaDict objectForKey: @"fields"];
if ([schemaFields count] > 0)
[fields addObjectsFromArray: schemaFields];
sup = [schemaDict objectForKey: @"sup"];
if ([sup length] > 0)
fillFieldsForClass (schema, sup, fields);
}
}
- (NSArray *) fieldsForClass: (NSString *) className
{
NSMutableArray *fields;
fields = [NSMutableArray arrayWithCapacity: 128];
fillFieldsForClass (schema, className, fields);
return fields;
}
- (NSArray *) fieldsForClasses: (NSArray *) classNames
{
NSMutableDictionary *fieldHash;
NSNumber *yesValue;
NSString *name;
NSUInteger count, max;
yesValue = [NSNumber numberWithBool: YES];
fieldHash = [NSMutableDictionary dictionary];
max = [classNames count];
for (count = 0; count < max; count++)
{
name = [classNames objectAtIndex: count];
[fieldHash setObject: yesValue forKeys: [self fieldsForClass: name]];
}
return [fieldHash allKeys];
}
@end
+1 -2
View File
@@ -35,8 +35,7 @@
- (NSString *) jsonRepresentation;
- (NSString *) keysWithFormat: (NSString *) keyFormat;
// LDIF methods
- (NSString *) userRecordAsLDIFEntry;
- (NSComparisonResult) caseInsensitiveDisplayNameCompare: (NSDictionary *) theDictionary;
@end
-82
View File
@@ -26,12 +26,8 @@
#import <Foundation/NSException.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
#import <Foundation/NSCharacterSet.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSArray+Utilities.h"
#import "NSObject+Utilities.h"
#import "NSString+Utilities.h"
#import "NSDictionary+Utilities.h"
@@ -109,84 +105,6 @@
return [[self objectForKey: @"cn"] caseInsensitiveCompare: [theDictionary objectForKey: @"cn"]];
}
// LDIF Methods
#warning We might want to support more than just strings here
- (void) _appendLDIFKey: (NSString *) key
value: (NSString *) value
toString: (NSMutableString *) ldifString
{
if ([value isKindOfClass: [NSString class]])
{
if ([value _isLDIFSafe])
[ldifString appendFormat: @"%@: %@\n", key, value];
else
[ldifString appendFormat: @"%@:: %@\n",
key, [value stringByEncodingBase64]];
}
}
- (void) _appendLDIFKey: (NSString *) key
toString: (NSMutableString *) ldifString
{
id value;
int count, max;
value = [self objectForKey: key];
if ([value isKindOfClass: [NSArray class]])
{
max = [value count];
for (count = 0; count < max; count++)
[self _appendLDIFKey: key value: [value objectAtIndex: count]
toString: ldifString];
}
else
[self _appendLDIFKey: key value: [self objectForKey: key]
toString: ldifString];
}
- (void) _appendObjectClassesToString: (NSMutableString *) ldifString
{
NSEnumerator *classes;
NSString *currentClass;
classes = [[self objectForKey: @"objectClasses"] objectEnumerator];
while ((currentClass = [classes nextObject]))
[self _appendLDIFKey: @"objectClass" value: currentClass
toString: ldifString];
}
- (NSString *) userRecordAsLDIFEntry
{
NSMutableString *ldifString;
NSEnumerator *keys;
NSString *currentKey;
// {CalendarAccess = YES; MailAccess = YES; c_cn = "Wolfgang Sourdeau"; c_emails = ("wolfgang@test.com"); c_name = "wolfgang@test.com"; c_uid = "wolfgang@test.com"; cn = "wolfgang@test.com"; displayName = "Wolfgang Sourdeau"; dn = "cn=wolfgang@test.com,ou=evariste,o=inverse.ca"; givenName = Wolfgang; mail = "wolfgang@test.com"; objectClass = organizationalPerson; sn = Sourdeau; }
ldifString = [NSMutableString string];
[self _appendLDIFKey: @"dn" toString: ldifString];
[self _appendObjectClassesToString: ldifString];
keys = [[self allKeys] objectEnumerator];
while ((currentKey = [keys nextObject]))
{
if (!([currentKey isEqualToString: @"CalendarAccess"]
|| [currentKey isEqualToString: @"MailAccess"]
|| [currentKey isEqualToString: @"ContactAccess"]
|| [currentKey hasPrefix: @"objectClass"]
|| [currentKey hasPrefix: @"c_"]
|| [currentKey isEqualToString: @"dn"]
|| [currentKey isEqualToString: @"isGroup"]
|| [currentKey isEqualToString: @"isResource"]
|| [currentKey isEqualToString: @"numberOfSimultaneousBookings"]
|| [currentKey isEqualToString: @"canAuthenticate"]))
[self _appendLDIFKey: currentKey toString: ldifString];
}
return ldifString;
}
@end
@implementation NSMutableDictionary (SOGoDictionaryUtilities)
-2
View File
@@ -62,8 +62,6 @@
- (int) timeValue;
- (BOOL) _isLDIFSafe;
- (BOOL) isJSONString;
- (id) objectFromJSONString;
-38
View File
@@ -486,44 +486,6 @@ static int cssEscapingCount;
return time;
}
static NSMutableCharacterSet *safeLDIFChars = nil;
static NSMutableCharacterSet *safeLDIFStartChars = nil;
- (void) _initSafeLDIFChars
{
safeLDIFChars = [NSMutableCharacterSet new];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x01, 9)];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x0b, 2)];
[safeLDIFChars addCharactersInRange: NSMakeRange (0x0e, 114)];
safeLDIFStartChars = [safeLDIFChars mutableCopy];
[safeLDIFStartChars removeCharactersInString: @" :<"];
}
- (BOOL) _isLDIFSafe
{
int count, max;
BOOL rc;
if (!safeLDIFChars)
[self _initSafeLDIFChars];
rc = YES;
max = [self length];
if (max > 0)
{
if ([safeLDIFStartChars characterIsMember: [self characterAtIndex: 0]])
for (count = 1; rc && count < max; count++)
rc = [safeLDIFChars
characterIsMember: [self characterAtIndex: count]];
else
rc = NO;
}
return rc;
}
- (BOOL) isJSONString
{
NSDictionary *jsonData;
+4 -2
View File
@@ -25,6 +25,8 @@
#import "SOGoObject.h"
@class NSString;
@interface SOGoFolder : SOGoObject
{
NSMutableString *displayName;
@@ -52,8 +54,8 @@
/* dav */
- (NSArray *) davResourceType;
/* outlook */
- (NSString *) outlookFolderClass;
/* email advisories */
- (void) sendFolderAdvisoryTemplate: (NSString *) template;
@end
+29 -7
View File
@@ -27,6 +27,7 @@
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/SoWebDAVValue.h>
@@ -37,12 +38,16 @@
#import <SaxObjC/XMLNamespaces.h>
#import <SOGoUI/SOGoFolderAdvisory.h>
#import "DOMNode+SOGo.h"
#import "NSArray+Utilities.h"
#import "NSObject+DAV.h"
#import "NSString+DAV.h"
#import "NSString+Utilities.h"
#import "SOGoPermissions.h"
#import "SOGoUser.h"
#import "SOGoDomainDefaults.h"
#import "SOGoWebDAVAclManager.h"
#import "WORequest+SOGo.h"
#import "WOResponse+SOGo.h"
@@ -248,6 +253,30 @@
return comparison;
}
/* email advisories */
- (void) sendFolderAdvisoryTemplate: (NSString *) template
{
NSString *pageName;
SOGoUser *user;
SOGoFolderAdvisory *page;
NSString *language;
user = [SOGoUser userWithLogin: [self ownerInContext: context]];
if ([[user domainDefaults] foldersSendEMailNotifications])
{
language = [[user userDefaults] language];
pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
language, template];
page = [[WOApplication application] pageWithName: pageName
inContext: context];
[page setFolderObject: self];
[page setRecipientUID: [user login]];
[page send];
}
}
/* WebDAV */
- (NSString *) davEntityTag
@@ -534,13 +563,6 @@
isEqualToString: [otherFolder nameInContainer]]);
}
- (NSString *) outlookFolderClass
{
[self subclassResponsibility: _cmd];
return nil;
}
/* acls */
- (NSString *) defaultUserID
-3
View File
@@ -118,9 +118,6 @@
- (void) removeAclsForUsers: (NSArray *) users
forObjectAtPath: (NSArray *) objectPathArray;
/* advisories */
- (void) sendFolderAdvisoryTemplate: (NSString *) template;
/* DAV */
- (NSURL *) publicDavURL;
- (NSURL *) realDavURL;
-23
View File
@@ -52,7 +52,6 @@
#import <GDLContentStore/GCSFolder.h>
#import <GDLContentStore/NSURL+GCS.h>
#import <SaxObjC/XMLNamespaces.h>
#import <SOGoUI/SOGoFolderAdvisory.h>
#import "NSDictionary+Utilities.h"
#import "NSArray+Utilities.h"
@@ -500,28 +499,6 @@ static NSArray *childRecordFields = nil;
return folder;
}
- (void) sendFolderAdvisoryTemplate: (NSString *) template
{
NSString *pageName;
SOGoUser *user;
SOGoFolderAdvisory *page;
NSString *language;
user = [SOGoUser userWithLogin: [self ownerInContext: context]];
if ([[user domainDefaults] foldersSendEMailNotifications])
{
language = [[user userDefaults] language];
pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
language, template];
page = [[WOApplication application] pageWithName: pageName
inContext: context];
[page setFolderObject: self];
[page setRecipientUID: [user login]];
[page send];
}
}
- (BOOL) create
{
NSException *result;
+3
View File
@@ -42,6 +42,9 @@
- (NSString *) defaultFolderName;
- (NSException *) appendPersonalSources;
- (void) removeSubFolder: (NSString *) subfolderName;
- (void) setBaseOCSPath: (NSString *) newOCSPath;
- (NSArray *) toManyRelationshipKeys;
+5 -3
View File
@@ -183,7 +183,6 @@ static SoSecurityManager *sm = nil;
SOGoGCSFolder *folder;
NSString *key;
NSException *error;
SOGoUser *currentUser;
if (!subFolderClass)
subFolderClass = [[self class] subFolderClass];
@@ -191,8 +190,6 @@ static SoSecurityManager *sm = nil;
error = [fc evaluateExpressionX: sql];
if (!error)
{
currentUser = [context activeUser];
attrs = [fc describeResults: NO];
while ((row = [fc fetchAttributes: attrs withZone: NULL]))
{
@@ -364,6 +361,11 @@ static SoSecurityManager *sm = nil;
return error;
}
- (void) removeSubFolder: (NSString *) subfolderName
{
[subFolders removeObjectForKey: subfolderName];
}
- (NSException *) initSubscribedSubFolders
{
NSException *error;
+34 -1
View File
@@ -28,9 +28,10 @@
#import "SOGoConstants.h"
@class NSDictionary;
@class NSException;
@class NSString;
@protocol SOGoSource
@protocol SOGoSource <NSObject>
+ (id) sourceFromUDSource: (NSDictionary *) udSource
inDomain: (NSString *) domain;
@@ -40,6 +41,10 @@
- (NSString *) domain;
/* requires a "." to obtain the full list of contacts */
- (void) setListRequiresDot: (BOOL) aBool;
- (BOOL) listRequiresDot;
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
perr: (SOGoPasswordPolicyError *) _perr
@@ -56,8 +61,36 @@
- (NSArray *) allEntryIDs;
- (NSArray *) fetchContactsMatching: (NSString *) filter;
- (void) setSourceID: (NSString *) newSourceID;
- (NSString *) sourceID;
- (void) setDisplayName: (NSString *) newDisplayName;
- (NSString *) displayName;
- (void) setModifiers: (NSArray *) newModifiers;
- (NSArray *) modifiers;
- (BOOL) hasUserAddressBooks;
- (NSArray *) addressBookSourcesForUser: (NSString *) user;
- (NSException *) addContactEntry: (NSDictionary *) roLdifRecord
withID: (NSString *) aId;
- (NSException *) updateContactEntry: (NSDictionary *) ldifRecord;
- (NSException *) removeContactEntryWithID: (NSString *) aId;
/* user address books */
- (NSArray *) addressBookSourcesForUser: (NSString *) user;
- (NSException *) addAddressBookSource: (NSString *) newId
withDisplayName: (NSString *) newDisplayName
forUser: (NSString *) user;
- (NSException *) renameAddressBookSource: (NSString *) newId
withDisplayName: (NSString *) newDisplayName
forUser: (NSString *) user;
- (NSException *) removeAddressBookSource: (NSString *) newId
forUser: (NSString *) user;
@end
@protocol SOGoDNSource <SOGoSource>
+3
View File
@@ -52,6 +52,8 @@
@class SOGoUserProfile;
@class SOGoUserSettings;
@protocol SOGoSource;
@interface SOGoUser : SoUser
{
SOGoUserDefaults *_defaults;
@@ -88,6 +90,7 @@
/* properties */
- (NSString *) domain;
- (id <SOGoSource>) authenticationSource;
- (NSArray *) allEmails;
- (BOOL) hasEmail: (NSString *) email;
+11
View File
@@ -287,6 +287,17 @@
return [self _fetchFieldForUser: @"c_domain"];
}
- (id <SOGoSource>) authenticationSource
{
NSString *sourceID;
SOGoUserManager *um;
sourceID = [self _fetchFieldForUser: @"SOGoSource"];
um = [SOGoUserManager sharedUserManager];
return [um sourceWithID: sourceID];
}
- (NSArray *) allEmails
{
if (!allEmails)
+4 -2
View File
@@ -586,7 +586,7 @@
NSMutableArray *emails;
NSDictionary *userEntry;
NSEnumerator *sogoSources;
NSObject <SOGoDNSource> *currentSource;
NSObject <SOGoSource> *currentSource;
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin;
NSArray *c_emails;
BOOL access;
@@ -605,12 +605,14 @@
sogoSources = [[self authenticationSourceIDsInDomain: domain]
objectEnumerator];
while ((sourceID = [sogoSources nextObject]))
userEntry = nil;
while (!userEntry && (sourceID = [sogoSources nextObject]))
{
currentSource = [_sources objectForKey: sourceID];
userEntry = [currentSource lookupContactEntryWithUIDorEmail: uid];
if (userEntry)
{
[currentUser setObject: sourceID forKey: @"SOGoSource"];
if (!cn)
cn = [userEntry objectForKey: @"c_cn"];
if (!c_uid)
+154 -2
View File
@@ -22,8 +22,9 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSURL.h>
@@ -379,6 +380,7 @@
{
NSMutableDictionary *response;
NSMutableArray *qualifiers;
NSArray *fieldNames;
EOAdaptorChannel *channel;
EOQualifier *loginQualifier, *qualifier;
GCSChannelManager *cm;
@@ -463,6 +465,16 @@
[response autorelease];
[channel cancelFetch];
/* Convert all c_ fields to obtain their ldif equivalent */
fieldNames = [response allKeys];
for (i = 0; i < [fieldNames count]; i++)
{
field = [fieldNames objectAtIndex: i];
if ([field hasPrefix: @"c_"])
[response setObject: [response objectForKey: field]
forKey: [field substringFromIndex: 2]];
}
// We have to do this here since we do not manage modules
// constraints right now over a SQL backend.
[response setObject: [NSNumber numberWithBool: YES] forKey: @"CalendarAccess"];
@@ -560,6 +572,8 @@
forKey: @"numberOfSimultaneousBookings"];
}
}
[response setObject: self forKey: @"source"];
}
else
[self errorWithFormat: @"could not run SQL '%@': %@", sql, ex];
@@ -666,7 +680,12 @@
attrs = [channel describeResults: NO];
while ((row = [channel fetchAttributes: attrs withZone: NULL]))
[results addObject: row];
{
row = [row mutableCopy];
[(NSMutableDictionary *) row setObject: self forKey: @"source"];
[results addObject: row];
[row release];
}
}
else
[self errorWithFormat: @"could not run SQL '%@': %@", sql, ex];
@@ -679,9 +698,142 @@
return results;
}
- (void) setSourceID: (NSString *) newSourceID
{
}
- (NSString *) sourceID
{
return _sourceID;
}
- (void) setDisplayName: (NSString *) newDisplayName
{
}
- (NSString *) displayName
{
/* This method is only used when supporting user "source" addressbooks,
which is only supported by the LDAP backend for now. */
return _sourceID;
}
- (void) setListRequiresDot: (BOOL) newListRequiresDot
{
}
- (BOOL) listRequiresDot
{
/* This method is not implemented for SQLSource. It must enable a mechanism
where using "." is not required to list the content of addressbooks. */
return YES;
}
/* card editing */
- (void) setModifiers: (NSArray *) newModifiers
{
}
- (NSArray *) modifiers
{
/* This method is only used when supporting card editing,
which is only supported by the LDAP backend for now. */
return nil;
}
- (NSException *) addContactEntry: (NSDictionary *) roLdifRecord
withID: (NSString *) aId
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
- (NSException *) updateContactEntry: (NSDictionary *) roLdifRecord
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
- (NSException *) removeContactEntryWithID: (NSString *) aId
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
/* user addressbooks */
- (BOOL) hasUserAddressBooks
{
return NO;
}
- (NSArray *) addressBookSourcesForUser: (NSString *) user
{
return nil;
}
- (NSException *) addAddressBookSource: (NSString *) newId
withDisplayName: (NSString *) newDisplayName
forUser: (NSString *) user
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
- (NSException *) renameAddressBookSource: (NSString *) newId
withDisplayName: (NSString *) newDisplayName
forUser: (NSString *) user
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
- (NSException *) removeAddressBookSource: (NSString *) newId
forUser: (NSString *) user
{
NSString *reason;
reason = [NSString stringWithFormat: @"method '%@' is not available"
@" for class '%@'", NSStringFromSelector (_cmd),
NSStringFromClass (isa)];
return [NSException exceptionWithName: @"SQLSourceIOException"
reason: reason
userInfo: nil];
}
@end