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

to branch 'ca.inverse.sogo' (head 638f19a902b772b34bc553dda4b8925b5d0639df)

Monotone-Parent: 1efb09bf023898a5a0088c9ba29ca00f1a304611
Monotone-Parent: 638f19a902b772b34bc553dda4b8925b5d0639df
Monotone-Revision: 876471503a0b45122655ff11d2726d5413827ddb

Monotone-Author: jraby@inverse.ca
Monotone-Date: 2012-02-02T18:05:51
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Jean Raby 2012-02-02 18:05:51 +00:00
commit f620cef0d3
131 changed files with 4742 additions and 3252 deletions

337
ChangeLog
View File

@ -1,3 +1,29 @@
2012-02-01 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreUserContext.m (-destroy): dont't release
"username" as it is not initially retained.
(+userContextWithUsername:andTDBIndexing:): the resulting instance
is cached in the table from here instead.
* OpenChange/MAPIStoreTable.m (-destroyHandle:): skih operation if
the handle parameter is 0.
* OpenChange/SOGoMAPIFSMessage.m (-delete): returns the exception
rather than raising it.
* OpenChange/SOGoMAPIFSFolder.m (-delete): new method that removes
the directory from the filesystem.
* OpenChange/MAPIStoreGCSFolder.m (-deleteFolder): overriden method.
* OpenChange/MAPIStoreFolder.m (-deleteFolder): implemented method.
* SoObjects/SOGo/SOGoParentFolder.m (-removeSubFolder): new method
that removes a subfolder entry from the folder cache.
* OpenChange/MAPIApplication.m (-setUserContext:): do not retain
the user context.
2012-02-01 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/UIxCalUserRightsEditor.js (onUpdateACL):
@ -19,6 +45,40 @@
(-pathToLocaleForLanguageNamed:): if the language has a CamelCase
form, add the first part to the lookup languages.
2012-01-31 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreMailContext.m
(+listContextsForUser:withTDBIndexing:inMemCtx:): now returns
secondary folders.
(+[MAPIStoreOutboxContext
listContextsForUser:withTDBIndexing:inMemCtx:]): overridden method
in outbox-specific class.
2012-01-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreMailFolder.m (-addProperties): overriden
method in order to intercept rename operations.
(-initWithSOGoObject:inContainer:): removed obsolete method.
* OpenChange/MAPIStoreGCSFolder.m (-addProperties): overriden
method in order to intercept rename operations.
* SoObjects/Mailer/SOGoMailFolder.m (-renameTo:): new method,
implementing most of the code from [UIxMailFolderActions
renameFolderAction].
* OpenChange/MAPIStoreFallbackContext.m
(+listContextsForUser:withTDBIndexing:inMemCtx:): now returns the
fallback subfolders as secondary contexts (tmp hack).
* OpenChange/MAPIStoreUserContext.m (-rootFolders): new method
replacing the "...root" methods in way that can match the
MAPIModuleName.
* OpenChange/MAPIStoreGCSBaseContext.m
(+listContextsForUser:inMemCtx:): centralized code for all GCS
classes.
2012-01-30 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/UIxCalUserRightsEditor.js (onUpdateACL):
@ -36,6 +96,47 @@
function now accepts two additional arguments to change the
default "yes" and "no" buttons.
2012-01-29 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreMailContext.[hm]: removed
"MAPIStoreInboxContext", "MAPIStoreSentItemsContext",
and child folders."MAPIStoreDraftsContext" and
"MAPIStoreOutboxContext" which have made obsolete by the new
provisioning and instantiation mechanisms.
* OpenChange/MAPIStoreContext.m (-woContext:, -mapping)
(-authenticator): those methods are now part of
MAPIStoreUserContext.
(-setupBaseFolder:): removed method, obsoleted by those below.
(-getRootFolder:withFID:): the "root folder" is now instantiated
by lookups from the root folder provided by the user context and
the chain of folders listed in the context url path.
(-MAPIStoreFolderClass): new method returning the Class object
representing the context's class of objects.
(-rootSOGoFolder): new method that returns the proper root folder
depending on the context's class of objects.
* OpenChange/MAPIStoreFolder.m (-initWithURL:inContext:): all
folders are now instantiated the same way since root objects are
now stored in the MAPIStoreUserContext instancesB.
(-setContext:): new setter to provide a reference to the folder's
mapistore context instance from the topmost parent.
(-setupVersionsMessage:): new helper method invoked during the
folder instantiations, from the moment its parent context has been
made available, which does not occur at the same moment for parent
and child folders...
* OpenChange/MAPIApplication.m (-init): removed the "mapiContext"
but added the "userContext" ivars.
* SoObjects/SOGo/SOGoFolder.m (-outlookFolderClass): removed
useless method.
* OpenChange/MAPIStoreUserContext.[hm]: new class for accessing
user data common to all "mapistore contexts" as a singleton: the
same instance is used across all requests until all related
objects have been freed.
2012-01-27 Ludovic Marcotte <lmarcotte@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentFolder.m
@ -46,6 +147,34 @@
(_folderCalenars) - we now ask for the c_content and use
a local autorelease pool to avoid consuming too much memory
2012-01-26 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreCommonViewsContext.[hm],
OpenChange/MAPIStoreDeferredActionsContext.[hm],
OpenChange/MAPIStoreFreebusyContext.[hm],
OpenChange/MAPIStoreJournalContext.[hm],
OpenChange/MAPIStoreRemindersContext.[hm],
OpenChange/MAPIStoreScheduleContext.[hm],
OpenChange/MAPIStoreSearchContext.[hm],
OpenChange/MAPIStoreShortcutsContext.[hm],
OpenChange/MAPIStoreSpoolerContext.[hm],
OpenChange/MAPIStoreViewsContext.[hm]: deleted obsolete classes.
* OpenChange/MAPIStoreFolder.m (supportsSubFolders): new
overridable method that returns whether the current folder can
contain subfolders, nowithstanding the right of the current user
to create or access them.
* OpenChange/MAPIStoreSOGo.m (sogo_backend_list_contexts): new
backend method.
* OpenChange/MAPIStoreContext.m
(+listAllContextsForUser:inMemCtx:): centralized method for
returning all contexts available from all context classes for one
user.
(+listContextsForUser:inMemCtx:): new individual method invoked by
the above. Overridden by concrete subclasses.
2012-01-26 Ludovic Marcotte <lmarcotte@inverse.ca>
* SoObjects/SOGo/LDAPSource.{h,m} - now honor
@ -81,6 +210,12 @@
menu is disabled. When switching to text-based message,
the popup menu is now correctly re-enabled.
2012-01-16 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/SQLSource.m (_lookupContactEntry:considerEmail:)
(fetchContactsMatching:): assigned self to the "source" key of the
returned dictionaries.
2012-01-13 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentFolder.m
@ -142,16 +277,115 @@
when a contact uid is specified. Otherwise, perform the query on
the user instance as usual (/SOGo/so/<contactuser>/freebusy.ifb/ajaxRead).
2012-01-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreCalendarMessage.m (-save): same as below +
ensure that nil fields are removed from non-new instances.
* OpenChange/MAPIStoreAppointmentWrapper.m
(-getPrStartDate:inMemCtx:, -getPrEndDate:inMemCtx:): remove the
tz offset from dates in all-day events.
* OpenChange/MAPIStoreTasksMessage.m (-save): the dates provided
by Outlook for start, due and completed are all-day dates, we thus
need to remove the timezone offset from those dates.
2012-01-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreGCSMessageTable.m
(_fixedDatePropertyRestriction:inMemCtx:): attached the result to
the memCtx passed as parameter to avoid a leak.
2012-01-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentObject.m
(_requireResponseFromAttendees:): initialize listHasChanged to NO.
* OpenChange/MAPIStoreMailFolder.m (_parseCOPYUID): the uniString
buffer was allocated one byte too short.
2012-01-09 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/NSObject+MAPIStore.m (-getValue:forTag:inMemCtx:):
handle PT_SVREID just as PT_BINARY.
* OpenChange/MAPIStoreCalendarFolder.m (-exchangeRightsForRoles):
add the freebusy read rights when the user has read permission on
calendar objects.
2012-01-05 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/SOGo/SOGoUserManager.m (-_registerSource:inDomain::):
log error when duplicated IDs are found.
2012-01-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/WebServerResources/ContactsUI.js
(onAddressBooksMenuPrepareVisibility): the "new list", "sharing" and "import"
options are now greyed out properly, depending on the object type
and the new attributes below.
* UI/Contacts/UIxContactFoldersView.m
(-currentContactFolderAclEditing)
(-currentContactFolderListEditing): new attribute accessors.
* SoObjects/SOGo/SOGoFolder.m (-sendFolderAdvisoryTemplate:):
moved method from SOGoGCSFolder in order to make it available to
other folder classes.
* SoObjects/SOGo/LDAPSource.m (-initFromUDSource:inDomain:): use
the new setters for certain ivars + take the new "abOU" key into
account.
(-setListRequiresDot:, -listRequiresDot:, -setSourceID:)
(-setDisplayName, -displayName, -setModifiers:): new accessors.
(-_convertRecordToLDAPAttributes): we now strip object classes that
are not supported by the server prior to remove the related fields.
(-hasUserAddressBooks): new method that returns whether user
addressbooks are supported, i.e. when "abOU" is set.
(-addressBookSourcesForUser:): when "abOU" is set, returns an
array of LDAPSource instances representing the personal
addressbooks of the specified user.
(-addAddressBookSource:withDisplayName:forUser:)
(-renameAddressBookSource:withDisplayName:forUser:)
(-removeAddressBookSource:forUser:): new methods with a
self-explicit name.
* SoObjects/Contacts/SOGoContactSourceFolder.m
(-setIsPersonalSource, -isPersonalSource): new accessors for the
"isPersonalSource ivar".
(-lookupName:inContext:acquire:): setup the object classes of the
new entries to "inetorgperson" and "mozillaabpersonalpha".
(-lookupContactsWithFilter:onCriteria:sortBy:ordering:): check
whether "listRequiresDot" is set on the current source and return
the full listing if not required.
(-compare:): enhanced to treat personal sources as if they were
regular GCS folders, in order to sort them properly.
(-delete, -renameTo:): implemented method, required for the
corresponding web methods.
(-ownerInContext:) adapted method to personal sources.
* SoObjects/Contacts/SOGoContactFolders.m (-appendPersonalSource):
overriden method for returning LDAP-based user addresbook sources.
(-newFolderWithName:andNameInContainer:): idem
(-renameLDAPAddressBook:withDisplayName:): new method that enables
the renaming of LDAP-based user addresbook sources.
(-removeLDAPAddressBook:): new method that enables
the removal of LDAP-based user addresbook sources.
2012-01-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/SOGoParentFolder.m (-appendPersonalSources): made
method public so that it can be easily overriden in subclasses.
* SoObjects/SOGo/SOGoUser.m (-authenticationSource): new method
that returned the SOGoSource instance that successfully recognized
the user represented by the current instance.
* SoObjects/SOGo/SOGoUserManager.m
(_fillContactInfosForUser:withUIDorEmail:inDomain:): we now set
the identifier of the source that authenticated the specified user
as the "SOGoSource" entry of the returned dictionary.
2012-01-03 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/Appointments/SOGoAptMailNotification.m (-setupValues):
@ -175,6 +409,109 @@
* UI/WebServerResources/UIxFilterEditor.js (ensureFieldValidity):
a field value is always considered invalid when empty.
2011-12-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/LDAPSourceSchema.[hm]: new class module enabling
schema auto-discovery.
* UI/WebServerResources/UIxContactEditor.js
(validateContactEditor): the birth date is validated slightly
differently, by enabling empty and 2-digit years as well as single
digits months and days.
* UI/Contacts/UIxContactView.m (-defaultAction, -dealloc): retain
and release the "card" ivar.
(_formattedURL:): the url should be displayed only if it is
non-nil AND non-empty.
(-vcardAction): removed useless method.
* UI/Contacts/UIxContactEditor.m (init): removed the "snapshot",
"preferredEmail", "card", "photosURL" and "contactCategories" ivars.
(-ldifRecord): new getter that proxy the invocation to the client
object, but by taking the contactEmail and contactFN url
parameters. Replaces the "-snapshot" getter, since the LDIF record
is now directly edited.
(-addressBooksList): the client object container class is no
longer taken into account when fetching the current user's permissions.
(-supportCategories, -supportPhotos): new getters that enables the
categories and photo tabs.
(-setJsonContactCategories:, -jsonContactCategories): now make
use of the special "vcardcategories" parameter found in the
contact LDIF record.
* SoObjects/SOGo/SQLSource.m (_lookupContactEntry:considerEmail:):
enhanced to copy the "c_XX" fields to unprefixed equivalents.
* SoObjects/Contacts/NSString+LDIF.m (mustEncodeLDIFValue): new
method, replacing "_isLDIFSafe" in a clearly public manner.
* SoObjects/SOGo/LDAPSource.m (-[NGLdapEntry _asDictionary]): new
utility method to convert an entry into a "SOGo LDIF record".
(-[NGLdapAttribute _asArrayOrString]): new utility method to
convert an LDAP attribute into a string or an array of strings
when the attribute has one or more values.
(-initFromUDSource:inDomain:): handle the new "modifiers",
"mapping" and "objectClasses" configuration keys, used when the
source instance is used as an addressbook. All LDAP fields are now
converted to lowercase.
(_searchAttributes): removed method as the special "*" attribute
is not costly enough to justify its existence, thereby reducing
code complexity.
(-lookupContactEntry:, -lookupContactEntryWithUIDorEmail:)
(-lookupLoginByDN:): merged common code in the new
-_lookupLDAPEntry: method, that accepts an EOQualifier as argument.
(--addContactEntry:withID:, -updateContactEntry: and
removeContactEntryWithID:): new methods for editing addressbook
sources.
* SoObjects/Contacts/SOGoContactSourceFolder.m (-source): new
getter for the "source" ivar.
(-lookupName:inContext:acquire:): accept the creation of new LDIF
entries via web methods ending with "AsContact".
(-saveLDIFEntry:, -deleteLDIFEntry:): new proxy methods for the
new SOGoSource -addContactEntry:withID:, -updateContactEntry: and
removeContactEntryWithID: methods, enabling the creation,
modification and deletion of LDAP contacts.
(-aclsForUser:): implemented method based on the array returned by
-[<SOGoSource> modifiers].
* SoObjects/Contacts/SOGoContactLDIFEntry.m (-vCard): the vcard is
now generated automatically from the LDIF record of the entry,
using the new method provided by NGVCard+SOGo.
(-aclsForUser:): new overriden method similar to the
implementation from SOGoContentObject.
* SoObjects/Contacts/SOGoContactGCSEntry.m (-setLDIFRecord)
(-ldifRecord, -hasPhoto): new accessors required by the
SOGoContactObject protocol.
(-lookupName:inContext:acquire:): return the only photo element
when the "photo" key is requested, if present in the card.
(-save): now returns an NSException, instead of void.
* SoObjects/Contacts/SOGoContactEntryPhoto.m
(+entryPhotoWithID:inContainer:, -setPhotoID:): removed methods,
since there can only be one PHOTO element per contact.
(-photo): simplified thanks to the constraint mentionned above.
* SoObjects/Contacts/NSDictionary+LDIF.m (-ldifRecordAsString):
new method implementing the code previously found in
SOGo/NSDictionary+Utilities.m, in order to produce a textual
representation of an LDIF record.
* SoObjects/Contacts/NSDictionary+LDIF.[hm]: new category module.
* SoObjects/Contacts/NGVCard+SOGo.m (-asLDIFRecord): new method
implementing the conversion code previously found in
UIxContactEditor, in order to produce an "LDIF record" in the form
of an NSDictionary matching the inetOrgPerson and
mozillaAbPersonAlpha object classes.
(-updateFromLDIFRecord:) reciprocal method to "-asLDIFRecord",
with conversion code moved from UIxContactEditor.
* SoObjects/Contacts/SOGoFolder+CardDAV.m (_isValidFilter:): make
use of the lowercase instance of the string, which was erroneously
ignored previously.
2011-12-29 Ludovic Marcotte <lmarcotte@inverse.ca.>
* SoObjects/SOGo/SOGoSQLUserProfile.m (_sqlJsonRepresentation:):

View File

@ -39,6 +39,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreTypes.m \
MAPIStorePropertySelectors.m \
MAPIStoreSamDBUtils.m \
MAPIStoreUserContext.m \
\
SOGoMAPIVolatileMessage.m \
SOGoMAPIFSFolder.m \
@ -102,17 +103,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreNotesFolder.m \
MAPIStoreNotesMessage.m \
\
MAPIStoreCommonViewsContext.m \
MAPIStoreDeferredActionsContext.m \
MAPIStoreFallbackContext.m \
MAPIStoreFreebusyContext.m \
MAPIStoreJournalContext.m \
MAPIStoreRemindersContext.m \
MAPIStoreScheduleContext.m \
MAPIStoreSearchContext.m \
MAPIStoreShortcutsContext.m \
MAPIStoreSpoolerContext.m \
MAPIStoreViewsContext.m \
\
NSArray+MAPIStore.m \
NSData+MAPIStore.m \
@ -172,12 +163,12 @@ LIBMAPISTORE_CFLAGS = $(shell pkg-config libmapistore --cflags) -DSAMBA_PREFIX="
LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy
$(MAPISTORESOGO)_INSTALL_DIR = $(DESTDIR)/$(SAMBA_LIB_DIR)/mapistore_backends
$(MAPISTORESOGO)_LDFLAGS += \
$(MAPISTORESOGO)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/ -lSOGo \
$(LIBMAPI_LIBS) \
$(LIBMAPISTORE_LIBS)
$(SOGOBACKEND)_LDFLAGS += \
$(SOGOBACKEND)_LIB_DIRS += \
-L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ -lOGoContentStore \
-L../SoObjects/SOGo/SOGo.framework/ -lSOGo \
$(LIBMAPI_LIBS) \

View File

@ -25,16 +25,16 @@
#import <NGObjWeb/SoApplication.h>
@class MAPIStoreContext;
@class MAPIStoreUserContext;
@interface MAPIApplication : SoApplication
{
MAPIStoreContext *mapiContext;
MAPIStoreUserContext *userContext;
}
- (id) authenticatorInContext: (id) context;
- (void) setMAPIStoreContext: (MAPIStoreContext *) newMAPIStoreContext;
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
@end

View File

@ -27,7 +27,7 @@
#import <Appointments/iCalEntityObject+SOGo.h>
#import "MAPIStoreContext.h"
#import "MAPIStoreUserContext.h"
#import "MAPIApplication.h"
@ -67,20 +67,16 @@ MAPIApplication *MAPIApp = nil;
return MAPIApp;
}
- (void) dealloc
- (void) setUserContext: (MAPIStoreUserContext *) newContext
{
[mapiContext release];
[super dealloc];
}
- (void) setMAPIStoreContext: (MAPIStoreContext *) newMAPIStoreContext
{
ASSIGN (mapiContext, newMAPIStoreContext);
/* user contexts must not be retained here ad their holder (mapistore)
contexts must be active when any operation occurs. */
userContext = newContext;
}
- (id) authenticatorInContext: (id) context
{
return [mapiContext authenticator];
return [userContext authenticator];
}
@end

View File

@ -638,11 +638,19 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSInteger offset;
if ([event isRecurrent])
dateValue = [event firstRecurrenceStartDate];
else
dateValue = [event startDate];
if ([event isAllDay])
{
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
@ -882,16 +890,18 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSInteger offset;
if ([event isRecurrent])
dateValue = [event firstRecurrenceStartDate];
else
dateValue = [event startDate];
dateValue
= [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: (NSInteger) [event
durationAsTimeInterval]];
offset = [event durationAsTimeInterval];
if ([event isAllDay])
offset -= [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];

View File

@ -100,7 +100,7 @@
mapistoreMsg = talloc_zero (memCtx, struct mapistore_message);
mapping = [[self context] mapping];
mapping = [self mapping];
attMessage = [self openEmbeddedMessage];
if (attMessage)

View File

@ -21,24 +21,39 @@
*/
#import <Foundation/NSString.h>
#import <Appointments/SOGoAppointmentFolders.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreCalendarFolder.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreCalendarContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
static Class MAPIStoreCalendarFolderK;
@implementation MAPIStoreCalendarContext
+ (void) initialize
{
MAPIStoreCalendarFolderK = [MAPIStoreCalendarFolder class];
}
+ (NSString *) MAPIModuleName
{
return @"calendar";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (enum mapistore_context_role) MAPIModuleRole
{
baseFolder = [MAPIStoreCalendarFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
return MAPISTORE_CALENDAR_ROLE;
}
- (Class) MAPIStoreFolderClass
{
return MAPIStoreCalendarFolderK;
}
@end

View File

@ -24,6 +24,7 @@
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import <SOGo/SOGoPermissions.h>
#import <Appointments/SOGoAppointmentFolder.h>
@ -42,37 +43,6 @@
@implementation MAPIStoreCalendarFolder
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
SOGoUserFolder *userFolder;
SOGoAppointmentFolders *parentFolder;
WOContext *woContext;
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
woContext = [newContext woContext];
userFolder = [SOGoUserFolder objectWithName: [newURL user]
inContainer: MAPIApp];
[parentContainersBag addObject: userFolder];
[woContext setClientObject: userFolder];
parentFolder = [userFolder lookupName: @"Calendar"
inContext: woContext
acquire: NO];
[parentContainersBag addObject: parentFolder];
[woContext setClientObject: parentFolder];
sogoObject = [parentFolder lookupName: @"personal"
inContext: woContext
acquire: NO];
[sogoObject retain];
}
return self;
}
- (MAPIStoreMessageTable *) messageTable
{
[self synchroniseCache];
@ -132,6 +102,8 @@
[roles addObject: SOGoCalendarRole_ConfidentialViewer];
}
// [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles];
return roles;
}
@ -150,9 +122,11 @@
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
rights |= RightsReadItems;
rights |= RightsReadItems | 0x1800;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}

View File

@ -56,6 +56,7 @@
#import "MAPIStoreMapping.h"
#import "MAPIStoreRecurrenceUtils.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSDate+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@ -106,14 +107,16 @@
{
iCalEvent *event;
MAPIStoreContext *context;
MAPIStoreUserContext *userContext;
if (!appointmentWrapper)
{
event = [sogoObject component: NO secure: YES];
context = [self context];
userContext = [self userContext];
ASSIGN (appointmentWrapper,
[MAPIStoreAppointmentWrapper wrapperWithICalEvent: event
andUser: [context ownerUser]
andUser: [userContext sogoUser]
andSenderEmail: nil
inTimeZone: [self ownerTimeZone]
withConnectionInfo: [context connectionInfo]]);
@ -207,7 +210,8 @@
- (int) getPidLidAppointmentSubType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [[self appointmentWrapper] getPidLidAppointmentSubType: data inMemCtx: memCtx];
return [[self appointmentWrapper] getPidLidAppointmentSubType: data
inMemCtx: memCtx];
}
- (int) getPidLidBusyStatus: (void **) data // TODO
@ -550,7 +554,7 @@
existingCName = [[container sogoObject] resourceNameForEventUID: uid];
if (existingCName)
{
mapping = [[self context] mapping];
mapping = [self mapping];
/* dissociate the object url from the old object's id */
existingURL = [NSString stringWithFormat: @"%@%@",
@ -567,7 +571,7 @@
[mapping registerURL: existingURL withID: objectId];
/* reinstantiate the old sogo object and attach it to self */
woContext = [[self context] woContext];
woContext = [[self userContext] woContext];
existingObject = [[container sogoObject] lookupName: existingCName
inContext: woContext
acquire: NO];
@ -653,6 +657,7 @@
iCalEvent *newEvent;
iCalPerson *userPerson;
NSUInteger responseStatus = 0;
NSInteger tzOffset;
SOGoUser *activeUser, *ownerUser;
id value;
@ -684,7 +689,7 @@
vCalendar = [iCalCalendar parseSingleFromSource: content];
newEvent = [[vCalendar events] objectAtIndex: 0];
ownerUser = [[self context] ownerUser];
ownerUser = [[self userContext] sogoUser];
userPerson = [newEvent userAsAttendee: ownerUser];
[newEvent setTimeStampAsDate: now];
@ -747,10 +752,11 @@
if (value)
[newEvent setLocation: value];
isAllDay = [[properties
objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)]
boolValue];
isAllDay = [newEvent isAllDay];
value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)];
if (value)
isAllDay = [value boolValue];
if (!isAllDay)
{
tzName = [[self ownerTimeZone] name];
@ -767,7 +773,14 @@
{
start = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtstart"];
if (isAllDay)
[start setDate: value];
{
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[start setTimeZone: nil];
[start setDate: value];
}
else
{
[start setTimeZone: tz];
@ -776,14 +789,21 @@
}
/* end */
value = [properties objectForKey: MAPIPropertyKey(PR_END_DATE)];
value = [properties objectForKey: MAPIPropertyKey (PR_END_DATE)];
if (!value)
value = [properties objectForKey: MAPIPropertyKey(PidLidAppointmentEndWhole)];
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)];
if (value)
{
end = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtend"];
if (isAllDay)
[end setDate: value];
{
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[end setTimeZone: nil];
[end setDate: value];
}
else
{
[end setTimeZone: tz];
@ -840,13 +860,14 @@
if (value)
{
value = [[NSString alloc] initWithData: value
encoding: NSUTF8StringEncoding];
encoding: NSUTF8StringEncoding];
[value autorelease];
value = [value htmlToText];
}
}
if (value)
[newEvent setComment: value];
if (value && [value length] == 0)
value = nil;
[newEvent setComment: value];
/* recurrence */
value = [properties

View File

@ -1,32 +0,0 @@
/* MAPIStoreCommonViewsContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTORECOMMONVIEWSCONTEXT_H
#define MAPISTORECOMMONVIEWSCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreCommonViewsContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTORECOMMONVIEWSCONTEXT_H */

View File

@ -1,34 +0,0 @@
/* MAPIStoreCommonViewsContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreCommonViewsContext.h"
@implementation MAPIStoreCommonViewsContext
+ (NSString *) MAPIModuleName
{
return @"common-views";
}
@end

View File

@ -22,23 +22,38 @@
#import <Foundation/NSString.h>
#import <Contacts/SOGoContactFolders.h>
#import "MAPIStoreContactsFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreContactsContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
static Class MAPIStoreContactsFolderK;
@implementation MAPIStoreContactsContext
+ (void) initialize
{
MAPIStoreContactsFolderK = [MAPIStoreContactsFolder class];
}
+ (NSString *) MAPIModuleName
{
return @"contacts";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (enum mapistore_context_role) MAPIModuleRole
{
baseFolder = [MAPIStoreContactsFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
return MAPISTORE_CONTACTS_ROLE;
}
- (Class) MAPIStoreFolderClass
{
return MAPIStoreContactsFolderK;
}
@end

View File

@ -39,37 +39,6 @@
@implementation MAPIStoreContactsFolder
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
SOGoUserFolder *userFolder;
SOGoContactFolders *parentFolder;
WOContext *woContext;
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
woContext = [newContext woContext];
userFolder = [SOGoUserFolder objectWithName: [newURL user]
inContainer: MAPIApp];
[parentContainersBag addObject: userFolder];
[woContext setClientObject: userFolder];
parentFolder = [userFolder lookupName: @"Contacts"
inContext: woContext
acquire: NO];
[parentContainersBag addObject: parentFolder];
[woContext setClientObject: parentFolder];
sogoObject = [parentFolder lookupName: @"personal"
inContext: woContext
acquire: NO];
[sogoObject retain];
}
return self;
}
- (MAPIStoreMessageTable *) messageTable
{
[self synchroniseCache];

View File

@ -47,28 +47,28 @@
@class MAPIStoreAttachment;
@class MAPIStoreAttachmentTable;
@class MAPIStoreFolder;
@class MAPIStoreMapping;
@class MAPIStoreMessage;
@class MAPIStoreTable;
@class MAPIStoreUserContext;
@interface MAPIStoreContext : NSObject
{
struct mapistore_context *mstoreCtx;
struct mapistore_connection_info *connInfo;
SOGoUser *activeUser;
SOGoUser *ownerUser;
MAPIStoreUserContext *userContext;
NSURL *contextUrl;
MAPIStoreMapping *mapping;
MAPIStoreAuthenticator *authenticator;
WOContext *woContext;
MAPIStoreFolder *baseFolder;
}
+ (struct mapistore_contexts_list *) listAllContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx;
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx;
+ (int) openContext: (MAPIStoreContext **) contextPtr
withURI: (const char *) newUri
connectionInfo: (struct mapistore_connection_info *) newConnInfo
@ -78,20 +78,12 @@
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
andTDBIndexing: (struct tdb_wrap *) indexingTdb;
- (void) setAuthenticator: (MAPIStoreAuthenticator *) newAuthenticator;
- (MAPIStoreAuthenticator *) authenticator;
- (NSURL *) url;
- (struct mapistore_connection_info *) connectionInfo;
- (WOContext *) woContext;
- (MAPIStoreMapping *) mapping;
- (void) setupRequest;
- (void) tearDownRequest;
- (MAPIStoreUserContext *) userContext;
- (SOGoUser *) activeUser;
- (SOGoUser *) ownerUser;
// - (id) lookupObject: (NSString *) objectURLString;
@ -112,7 +104,11 @@
/* subclass methods */
+ (NSString *) MAPIModuleName;
- (void) setupBaseFolder: (NSURL *) newURL;
- (Class) MAPIStoreFolderClass;
/* the top-most parent of the context folder: SOGoMailAccount,
SOGoCalendarFolders, ... */
- (id) rootSOGoFolder;
@end

View File

@ -25,9 +25,7 @@
#import <Foundation/NSURL.h>
#import <Foundation/NSThread.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoUser.h>
@ -35,10 +33,8 @@
#import "SOGoMAPIFSFolder.h"
#import "SOGoMAPIFSMessage.h"
#import "MAPIApplication.h"
#import "MAPIStoreAttachment.h"
// #import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreAuthenticator.h"
#import "MAPIStoreFolder.h"
#import "MAPIStoreFolderTable.h"
#import "MAPIStoreMapping.h"
@ -47,6 +43,7 @@
#import "MAPIStoreFAIMessage.h"
#import "MAPIStoreFAIMessageTable.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSArray+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -69,7 +66,7 @@
/* sogo://username:password@{contacts,calendar,tasks,journal,notes,mail}/dossier/id */
static Class NSDataK, NSStringK, MAPIStoreFAIMessageK;
static Class NSExceptionK;
static NSMutableDictionary *contextClassMapping;
@ -80,9 +77,7 @@ static NSMutableDictionary *contextClassMapping;
NSUInteger count, max;
NSString *moduleName;
NSDataK = [NSData class];
NSStringK = [NSString class];
MAPIStoreFAIMessageK = [MAPIStoreFAIMessage class];
NSExceptionK = [NSException class];
contextClassMapping = [NSMutableDictionary new];
classes = GSObjCAllSubclassesOfClass (self);
@ -101,44 +96,56 @@ static NSMutableDictionary *contextClassMapping;
}
}
static inline enum mapistore_error
_prepareContextClass (Class contextClass,
struct mapistore_connection_info *connInfo,
struct tdb_wrap *indexingTdb, NSURL *url,
MAPIStoreContext **contextP)
+ (struct mapistore_contexts_list *) listAllContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreContext *context;
MAPIStoreAuthenticator *authenticator;
enum mapistore_error rc;
struct mapistore_contexts_list *list, *current;
NSArray *classes;
Class currentClass;
NSUInteger count, max;
MAPIStoreUserContext *userContext;
context = [[contextClass alloc] initFromURL: url
withConnectionInfo: connInfo
andTDBIndexing: indexingTdb];
if (context)
list = NULL;
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexingTdb];
[userContext activateWithUser: [userContext sogoUser]];
classes = GSObjCAllSubclassesOfClass (self);
max = [classes count];
for (count = 0; count < max; count++)
{
[context autorelease];
authenticator = [MAPIStoreAuthenticator new];
[authenticator setUsername: [url user]];
[authenticator setPassword: [url password]];
[context setAuthenticator: authenticator];
[authenticator release];
[context setupRequest];
[context setupBaseFolder: url];
[context tearDownRequest];
if (context->baseFolder && [context->baseFolder sogoObject])
{
*contextP = context;
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_DENIED;
currentClass = [classes objectAtIndex: count];
current = [currentClass listContextsForUser: userName
withTDBIndexing: indexingTdb
inMemCtx: memCtx];
if (current)
DLIST_CONCATENATE(list, current, void);
}
else
rc = MAPISTORE_ERROR;
return rc;
return list;
}
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
return NULL;
}
static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
NSString *urlString;
NSURL *completeURL;
urlString = [NSString stringWithFormat: @"sogo://%@",
[NSString stringWithUTF8String: uri]];
if (![urlString hasSuffix: @"/"])
urlString = [urlString stringByAppendingString: @"/"];
completeURL = [NSURL URLWithString: [urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
return completeURL;
}
+ (int) openContext: (MAPIStoreContext **) contextPtr
@ -148,7 +155,7 @@ _prepareContextClass (Class contextClass,
{
MAPIStoreContext *context;
Class contextClass;
NSString *module, *completeURLString, *urlString;
NSString *module;
NSURL *baseURL;
int rc = MAPISTORE_ERR_NOT_FOUND;
@ -156,41 +163,31 @@ _prepareContextClass (Class contextClass,
context = nil;
urlString = [NSString stringWithUTF8String: newUri];
if (urlString)
baseURL = CompleteURLFromMapistoreURI (newUri);
if (baseURL)
{
completeURLString = [@"sogo://" stringByAppendingString: urlString];
if (![completeURLString hasSuffix: @"/"])
completeURLString = [completeURLString stringByAppendingString: @"/"];
baseURL = [NSURL URLWithString: [completeURLString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
if (baseURL)
module = [baseURL host];
if (module)
{
module = [baseURL host];
if (module)
contextClass = [contextClassMapping objectForKey: module];
if (contextClass)
{
contextClass = [contextClassMapping objectForKey: module];
if (contextClass)
context = [[contextClass alloc] initFromURL: baseURL
withConnectionInfo: newConnInfo
andTDBIndexing: indexingTdb];
if (context)
{
rc = _prepareContextClass (contextClass,
newConnInfo, indexingTdb,
baseURL, &context);
if (rc == MAPISTORE_SUCCESS)
{
*contextPtr = context;
mapistore_mgmt_backend_register_user (newConnInfo,
"SOGo",
[[[context authenticator] username] UTF8String]);
}
[context autorelease];
rc = MAPISTORE_SUCCESS;
*contextPtr = context;
}
else
NSLog (@"ERROR: unrecognized module name '%@'", module);
}
else
NSLog (@"ERROR: unrecognized module name '%@'", module);
}
else
NSLog (@"ERROR: url could not be parsed");
}
else
NSLog (@"ERROR: url is an invalid UTF-8 string");
NSLog (@"ERROR: url could not be parsed");
return rc;
}
@ -199,9 +196,8 @@ _prepareContextClass (Class contextClass,
{
if ((self = [super init]))
{
woContext = [WOContext contextWithRequest: nil];
[woContext retain];
baseFolder = nil;
activeUser = nil;
userContext = nil;
contextUrl = nil;
}
@ -216,6 +212,26 @@ _prepareContextClass (Class contextClass,
if ((self = [self init]))
{
ASSIGN (contextUrl, newUrl);
username = [newUrl user];
if ([username length] == 0)
{
[self errorWithFormat:
@"attempt to instantiate a context with an empty owner"];
[self release];
return nil;
}
ASSIGN (userContext,
[MAPIStoreUserContext userContextWithUsername: username
andTDBIndexing: indexingTdb]);
mapistore_mgmt_backend_register_user (newConnInfo,
"SOGo",
[username UTF8String]);
connInfo = newConnInfo;
username = [NSString stringWithUTF8String: newConnInfo->username];
ASSIGN (activeUser, [SOGoUser userWithLogin: username]);
if (!activeUser)
@ -225,29 +241,6 @@ _prepareContextClass (Class contextClass,
[self release];
return nil;
}
[woContext setActiveUser: activeUser];
username = [newUrl user];
if ([username length] == 0)
{
[self errorWithFormat:
@"attempt to instantiate a context with an empty owner"];
[self release];
return nil;
}
ASSIGN (ownerUser, [SOGoUser userWithLogin: username]);
if (!ownerUser)
{
[self errorWithFormat:
@"attempt to instantiate a context without a valid owner"];
[self release];
return nil;
}
ASSIGN (mapping, [MAPIStoreMapping mappingForUsername: username
withIndexing: indexingTdb]);
[mapping increaseUseCount];
ASSIGN (contextUrl, newUrl);
mstoreCtx = newConnInfo->mstore_ctx;
connInfo = newConnInfo;
}
return self;
@ -256,36 +249,17 @@ _prepareContextClass (Class contextClass,
- (void) dealloc
{
mapistore_mgmt_backend_unregister_user ([self connectionInfo], "SOGo",
[[[self authenticator] username]
[[userContext username]
UTF8String]);
[baseFolder release];
[woContext release];
[authenticator release];
[mapping decreaseUseCount];
[mapping release];
[contextUrl release];
[userContext release];
[super dealloc];
}
- (WOContext *) woContext
- (MAPIStoreUserContext *) userContext
{
return woContext;
}
- (MAPIStoreMapping *) mapping
{
return mapping;
}
- (void) setAuthenticator: (MAPIStoreAuthenticator *) newAuthenticator
{
ASSIGN (authenticator, newAuthenticator);
}
- (MAPIStoreAuthenticator *) authenticator
{
return authenticator;
return userContext;
}
- (NSURL *) url
@ -298,34 +272,11 @@ _prepareContextClass (Class contextClass,
return connInfo;
}
- (void) setupRequest
{
NSMutableDictionary *info;
[MAPIApp setMAPIStoreContext: self];
info = [[NSThread currentThread] threadDictionary];
[info setObject: woContext forKey: @"WOContext"];
}
- (void) tearDownRequest
{
NSMutableDictionary *info;
info = [[NSThread currentThread] threadDictionary];
[info removeObjectForKey: @"WOContext"];
[MAPIApp setMAPIStoreContext: nil];
}
- (SOGoUser *) activeUser
{
return activeUser;
}
- (SOGoUser *) ownerUser
{
return ownerUser;
}
// - (void) logRestriction: (struct mapi_SRestriction *) res
// withState: (MAPIRestrictionState) state
// {
@ -345,7 +296,7 @@ _prepareContextClass (Class contextClass,
// TDB_DATA key, dbuf;
url = [contextUrl absoluteString];
objectURL = [mapping urlFromID: fmid];
objectURL = [[userContext mapping] urlFromID: fmid];
if (objectURL)
{
if ([objectURL hasPrefix: url])
@ -383,15 +334,64 @@ _prepareContextClass (Class contextClass,
return rc;
}
- (void) ensureContextFolder
{
}
- (int) getRootFolder: (MAPIStoreFolder **) folderPtr
withFID: (uint64_t) newFid
{
enum mapistore_error rc;
MAPIStoreMapping *mapping;
MAPIStoreFolder *baseFolder;
SOGoFolder *currentFolder;
WOContext *woContext;
NSString *path;
NSArray *pathComponents;
NSUInteger count, max;
mapping = [userContext mapping];
if (![mapping urlFromID: newFid])
[mapping registerURL: [contextUrl absoluteString]
withID: newFid];
*folderPtr = baseFolder;
return (baseFolder) ? MAPISTORE_SUCCESS: MAPISTORE_ERROR;
[userContext activateWithUser: activeUser];
woContext = [userContext woContext];
[self ensureContextFolder];
currentFolder = [self rootSOGoFolder];
path = [contextUrl path];
if ([path hasPrefix: @"/"])
path = [path substringFromIndex: 1];
if ([path hasSuffix: @"/"])
path = [path substringToIndex: [path length] - 1];
pathComponents = [path componentsSeparatedByString: @"/"];
max = [pathComponents count];
for (count = 0; currentFolder && count < max; count++)
{
[woContext setClientObject: currentFolder];
currentFolder
= [currentFolder lookupName: [pathComponents objectAtIndex: count]
inContext: woContext
acquire: NO];
if ([currentFolder isKindOfClass: NSExceptionK])
currentFolder = nil;
}
if (currentFolder)
{
baseFolder = [[self MAPIStoreFolderClass]
mapiStoreObjectWithSOGoObject: currentFolder
inContainer: nil];
[baseFolder setContext: self];
*folderPtr = baseFolder;
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
/* utils */
@ -426,6 +426,7 @@ _prepareContextClass (Class contextClass,
inFolderURL: (NSString *) folderURL
{
NSString *childURL, *owner;
MAPIStoreMapping *mapping;
uint64_t mappingId;
uint32_t contextId;
void *rootObject;
@ -434,6 +435,7 @@ _prepareContextClass (Class contextClass,
childURL = [NSString stringWithFormat: @"%@%@", folderURL, key];
else
childURL = folderURL;
mapping = [userContext mapping];
mappingId = [mapping idFromURL: childURL];
if (mappingId == NSNotFound)
{
@ -442,11 +444,10 @@ _prepareContextClass (Class contextClass,
[mapping registerURL: childURL withID: mappingId];
contextId = 0;
// FIXME: + 7 to skip the BOM or what?
mapistore_search_context_by_uri (mstoreCtx, [folderURL UTF8String] + 7,
mapistore_search_context_by_uri (connInfo->mstore_ctx, [folderURL UTF8String] + 7,
&contextId, &rootObject);
owner = [ownerUser login];
mapistore_indexing_record_add_mid (mstoreCtx, contextId,
owner = [userContext username];
mapistore_indexing_record_add_mid (connInfo->mstore_ctx, contextId,
[owner UTF8String], mappingId);
}
@ -473,9 +474,18 @@ _prepareContextClass (Class contextClass,
return nil;
}
- (void) setupBaseFolder: (NSURL *) newURL
- (Class) MAPIStoreFolderClass
{
[self subclassResponsibility: _cmd];
return nil;
}
- (id) rootSOGoFolder
{
[self subclassResponsibility: _cmd];
return nil;
}
@end

View File

@ -1,32 +0,0 @@
/* MAPIStoreDeferredActionsContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTOREDEFERREDACTIONSCONTEXT_H
#define MAPISTOREDEFERREDACTIONSCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreDeferredActionsContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTOREDEFERREDACTIONSCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreDeferredActionsContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreDeferredActionsContext.h"
@implementation MAPIStoreDeferredActionsContext
+ (NSString *) MAPIModuleName
{
return @"deferred-actions";
}
@end

View File

@ -22,6 +22,7 @@
#import "MAPIStoreActiveTables.h"
#import "MAPIStoreContext.h"
#import "MAPIStoreUserContext.h"
#import "NSObject+MAPIStore.h"
#import "MAPIStoreFAIMessage.h"
@ -51,9 +52,11 @@
{
enum mapistore_error rc;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]])
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser])
rc = [super saveMessage];
else
rc = MAPISTORE_ERR_DENIED;

View File

@ -30,10 +30,14 @@
#import "MAPIStoreFSFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
#import "SOGoMAPIFSFolder.h"
#import "MAPIStoreFSBaseContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
static Class MAPIStoreFSFolderK;
@implementation MAPIStoreFSBaseContext
@ -48,12 +52,28 @@ static Class MAPIStoreFSFolderK;
return nil;
}
- (void) setupBaseFolder: (NSURL *) newURL
- (Class) MAPIStoreFolderClass
{
[self logWithFormat: @"invoked %s", __PRETTY_FUNCTION__];
baseFolder = [MAPIStoreFSFolderK baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
return MAPIStoreFSFolderK;
}
- (void) ensureContextFolder
{
SOGoMAPIFSFolder *contextFolder;
contextFolder = [SOGoMAPIFSFolder folderWithURL: contextUrl
andTableType: MAPISTORE_MESSAGE_TABLE];
[contextFolder ensureDirectory];
}
- (id) rootSOGoFolder
{
NSString *urlString;
urlString = [NSString stringWithFormat: @"sogo://%@@%@/",
[userContext username], [isa MAPIModuleName]];
return [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: urlString]
andTableType: MAPISTORE_MESSAGE_TABLE];
}
@end

View File

@ -34,6 +34,7 @@
#import "MAPIStoreFSMessage.h"
#import "MAPIStoreFSMessageTable.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "SOGoMAPIFSFolder.h"
#import "SOGoMAPIFSMessage.h"
@ -64,20 +65,6 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
EOKeyValueQualifierK = [EOKeyValueQualifier class];
}
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
sogoObject = [SOGoMAPIFSFolder folderWithURL: newURL
andTableType: MAPISTORE_MESSAGE_TABLE];
[sogoObject retain];
}
return self;
}
- (MAPIStoreMessageTable *) messageTable
{
return [MAPIStoreFSMessageTable tableForContainer: self];
@ -126,8 +113,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
andSortOrderings: (NSArray *) sortOrderings
{
NSArray *keys;
SOGoUser *ownerUser;
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanReadMessages])
keys = [(SOGoMAPIFSFolder *) sogoObject
toOneRelationshipKeysMatchingQualifier: qualifier
@ -295,4 +284,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
return [self _testRoleForActiveUser: MAPIStoreRightCreateSubfolders];
}
- (BOOL) supportsSubFolders
{
return YES;
}
@end

View File

@ -20,11 +20,16 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import "MAPIStoreFSFolder.h"
#import <Foundation/NSURL.h>
#import "MAPIStoreFallbackContext.h"
#import "NSString+MAPIStore.h"
#import "SOGoMAPIFSFolder.h"
#undef DEBUG
#include <mapistore/mapistore.h>
@implementation MAPIStoreFallbackContext
@ -33,10 +38,48 @@
return @"fallback";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
baseFolder = [MAPIStoreFSFolder baseFolderWithURL: newURL inContext: self];
[baseFolder retain];
struct mapistore_contexts_list *firstContext = NULL, *context;
SOGoMAPIFSFolder *root;
NSArray *names;
NSUInteger count, max;
NSString *baseURL, *url, *name;
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [baseURL asUnicodeInMemCtx: context];
context->name = "Fallback";
context->main_folder = true;
context->role = MAPISTORE_FALLBACK_ROLE;
context->tag = "tag";
DLIST_ADD_END (firstContext, context, void);
/* Maybe emsmdbp_provisioning should be fixed in order to only take the uri
returned above to avoid deleting its entries... */
root = [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: baseURL]
andTableType: MAPISTORE_MESSAGE_TABLE];
names = [root toManyRelationshipKeys];
max = [names count];
for (count = 0; count < max; count++)
{
name = [names objectAtIndex: count];
url = [NSString stringWithFormat: @"%@%@/", baseURL, name];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [url asUnicodeInMemCtx: context];
context->name = [name asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_FALLBACK_ROLE;
context->tag = "tag";
DLIST_ADD_END (firstContext, context, void);
}
return firstContext;
}
@end

View File

@ -25,12 +25,9 @@
#import <Foundation/NSObject.h>
#import "MAPIStoreTable.h"
@class NSArray;
@class NSMutableArray;
@class NSNumber;
@class NSURL;
@class EOQualifier;
@ -48,7 +45,6 @@
@interface MAPIStoreFolder : MAPIStoreObject
{
NSURL *folderURL;
MAPIStoreContext *context;
NSArray *messageKeys;
NSArray *faiMessageKeys;
@ -59,10 +55,7 @@
SOGoMAPIFSMessage *propsMessage;
}
+ (id) baseFolderWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext;
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext;
- (void) setContext: (MAPIStoreContext *) newContext;
- (NSArray *) activeMessageTables;
- (NSArray *) activeFAIMessageTables;
@ -103,9 +96,9 @@
- (int) createFolder: (MAPIStoreFolder **) childFolderPtr
withRow: (struct SRow *) aRow
andFID: (uint64_t) fid;
- (int) deleteFolderWithFID: (uint64_t) fid;
- (int) deleteFolder;
- (int) getChildCount: (uint32_t *) rowCount
ofTableType: (uint8_t) tableType;
ofTableType: (enum mapistore_table_type) tableType;
- (int) createMessage: (MAPIStoreMessage **) messagePtr
withMID: (uint64_t) mid
@ -128,12 +121,12 @@
- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
inTableType: (uint8_t) tableType
inTableType: (enum mapistore_table_type) tableType
inMemCtx: (TALLOC_CTX *) mem_ctx;
- (int) getTable: (MAPIStoreTable **) tablePtr
andRowCount: (uint32_t *) count
tableType: (uint8_t) tableType
tableType: (enum mapistore_table_type) tableType
andHandleId: (uint32_t) handleId;
- (int) modifyPermissions: (struct PermissionData *) permissions
@ -150,7 +143,7 @@
andSortOrderings: (NSArray *) sortOrderings;
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
andCN: (NSNumber **) cnNbr
inTableType: (uint8_t) tableType;
inTableType: (enum mapistore_table_type) tableType;
- (NSString *) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID;
@ -167,7 +160,10 @@
- (BOOL) subscriberCanDeleteMessages;
- (BOOL) subscriberCanCreateSubFolders;
- (BOOL) supportsSubFolders; /* capability */
/* subclass helpers */
- (void) setupVersionsMessage;
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount

View File

@ -43,6 +43,7 @@
#import "MAPIStorePermissionsTable.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@ -71,17 +72,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreFolderTableK = [MAPIStoreFolderTable class];
}
+ (id) baseFolderWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
id newFolder;
newFolder = [[self alloc] initWithURL: newURL inContext: newContext];
[newFolder autorelease];
return newFolder;
}
- (id) init
{
if ((self = [super init]))
@ -90,7 +80,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
faiMessageKeys = nil;
folderKeys = nil;
faiFolder = nil;
folderURL = nil;
context = nil;
propsFolder = nil;
@ -100,54 +89,72 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return self;
}
/* from context */
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
if ((self = [self init]))
{
context = newContext;
ASSIGN (folderURL, newURL);
ASSIGN (faiFolder,
[SOGoMAPIFSFolder folderWithURL: newURL
andTableType: MAPISTORE_FAI_TABLE]);
ASSIGN (propsFolder,
[SOGoMAPIFSFolder folderWithURL: newURL
andTableType: MAPISTORE_FOLDER_TABLE]);
ASSIGN (propsMessage,
[SOGoMAPIFSMessage objectWithName: @"properties.plist"
inContainer: propsFolder]);
}
return self;
}
/* from parent folder */
- (id) initWithSOGoObject: (id) newSOGoObject
inContainer: (MAPIStoreObject *) newContainer
- (void) _setupAuxiliaryObjects
{
NSURL *propsURL;
NSString *urlString;
if ((self = [super initWithSOGoObject: newSOGoObject inContainer: newContainer]))
urlString = [[self url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
propsURL = [NSURL URLWithString: urlString];
[self logWithFormat: @"_setupAuxiliaryObjects: %@", propsURL];
ASSIGN (faiFolder,
[SOGoMAPIFSFolder folderWithURL: propsURL
andTableType: MAPISTORE_FAI_TABLE]);
ASSIGN (propsFolder,
[SOGoMAPIFSFolder folderWithURL: propsURL
andTableType: MAPISTORE_FOLDER_TABLE]);
ASSIGN (propsMessage,
[SOGoMAPIFSMessage objectWithName: @"properties.plist"
inContainer: propsFolder]);
[self setupVersionsMessage];
}
- (id) initWithSOGoObject: (id) newSOGoObject
inContainer: (MAPIStoreObject *) newContainer
{
/* The instantiation of auxiliary folders is postponed when newContainer is
nil since there is no way to deduce the parent url. When setContext: is
invoked, it becomes possible again. */
if ((self = [super initWithSOGoObject: newSOGoObject
inContainer: newContainer])
&& newContainer)
{
urlString = [[self url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
propsURL = [NSURL URLWithString: urlString];
ASSIGN (faiFolder,
[SOGoMAPIFSFolder folderWithURL: propsURL
andTableType: MAPISTORE_FAI_TABLE]);
ASSIGN (propsFolder,
[SOGoMAPIFSFolder folderWithURL: propsURL
andTableType: MAPISTORE_FOLDER_TABLE]);
ASSIGN (propsMessage,
[SOGoMAPIFSMessage objectWithName: @"properties.plist"
inContainer: propsFolder]);
[self _setupAuxiliaryObjects];
}
return self;
}
- (void) setContext: (MAPIStoreContext *) newContext
{
ASSIGN (context, newContext);
if (newContext)
[self _setupAuxiliaryObjects];
}
- (MAPIStoreContext *) context
{
if (!context)
[self setContext: [container context]];
return context;
}
- (void) dealloc
{
[propsMessage release];
[propsFolder release];
[messageKeys release];
[faiMessageKeys release];
[folderKeys release];
[faiFolder release];
[context release];
[super dealloc];
}
/* backend interface */
- (SOGoMAPIFSMessage *) propertiesMessage
{
return propsMessage;
@ -185,7 +192,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if ([[self folderKeys] containsObject: folderKey])
{
woContext = [[self context] woContext];
woContext = [[self userContext] woContext];
sogoFolder = [sogoObject lookupName: folderKey
inContext: woContext
acquire: NO];
@ -237,7 +244,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
acquire: NO];
if (msgObject && ![msgObject isKindOfClass: NSExceptionK])
{
[msgObject setContext: [[self context] woContext]];
[msgObject setContext: [[self userContext] woContext]];
messageClass = [msgObject mapistoreMessageClass];
childMessage
= [messageClass mapiStoreObjectWithSOGoObject: msgObject
@ -310,7 +317,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
mapping = [[self context] mapping];
mapping = [self mapping];
childURL = [mapping urlFromID: fid];
if (childURL)
{
@ -333,13 +340,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
NSString *baseURL, *childURL, *folderKey;
MAPIStoreFolder *childFolder;
SOGoUser *ownerUser;
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanCreateSubFolders])
{
mapping = [[self context] mapping];
mapping = [self mapping];
childURL = [mapping urlFromID: fid];
if (childURL)
rc = MAPISTORE_ERR_EXIST;
@ -375,15 +384,17 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return rc;
}
- (int) deleteFolderWithFID: (uint64_t) fid
- (int) deleteFolder
{
[self logWithFormat: @"UNIMPLEMENTED METHOD '%s' (%d)", __FUNCTION__, __LINE__];
[propsMessage delete];
[propsFolder delete];
[faiFolder delete];
return MAPISTORE_ERROR;
return MAPISTORE_SUCCESS;
}
- (int) getChildCount: (uint32_t *) rowCount
ofTableType: (uint8_t) tableType
ofTableType: (enum mapistore_table_type) tableType
{
NSArray *keys;
int rc = MAPISTORE_SUCCESS;
@ -415,16 +426,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *messageURL;
MAPIStoreMapping *mapping;
MAPIStoreMessage *message;
SOGoUser *ownerUser;
int rc = MAPISTORE_ERR_NOT_FOUND;
mapping = [[self context] mapping];
mapping = [self mapping];
messageURL = [mapping urlFromID: mid];
if (messageURL)
{
message = [self lookupMessageByURL: messageURL];
if (message)
{
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| (readWrite && [message subscriberCanModifyMessage])
|| (!readWrite && [message subscriberCanReadMessage]))
{
@ -447,15 +460,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMessage *message;
NSString *baseURL, *childURL;
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
[self logWithFormat: @"METHOD '%s' -- mid: 0x%.16llx associated: %d",
__FUNCTION__, mid, isAssociated];
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| (!isAssociated && [self subscriberCanCreateMessages]))
{
mapping = [[self context] mapping];
mapping = [self mapping];
if ([mapping urlFromID: mid])
rc = MAPISTORE_ERR_EXIST;
else
@ -491,20 +507,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSArray *activeTables;
NSUInteger count, max;
id msgObject;
SOGoUser *ownerUser;
struct mapistore_connection_info *connInfo;
struct mapistore_object_notification_parameters *notif_parameters;
int rc;
[self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags];
mapping = [[self context] mapping];
mapping = [self mapping];
childURL = [mapping urlFromID: mid];
if (childURL)
{
message = [self lookupMessageByURL: childURL];
if (message)
{
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| (![message isKindOfClass: MAPIStoreFAIMessageK]
&& [self subscriberCanDeleteMessages]))
{
@ -685,16 +704,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSMutableArray *oldMessageURLs;
NSString *oldMessageURL;
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
struct Binary_r *targetChangeKey;
if (wantCopy || [[context activeUser] isEqual: [context ownerUser]])
ownerUser = [[self userContext] sogoUser];
if (wantCopy || [[context activeUser] isEqual: ownerUser])
{
if ([sourceFolder isKindOfClass: isa]
|| [self isKindOfClass: [sourceFolder class]])
[self logWithFormat: @"%s: this class could probably implement"
@" a specialized/optimized version", __FUNCTION__];
oldMessageURLs = [NSMutableArray arrayWithCapacity: midCount];
mapping = [[self context] mapping];
mapping = [self mapping];
for (count = 0; rc == MAPISTORE_SUCCESS && count < midCount; count++)
{
oldMessageURL = [mapping urlFromID: srcMids[count]];
@ -753,6 +775,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[aclFolder setRoles: roles forUser: user];
}
- (void) setupVersionsMessage
{
}
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount
@ -849,7 +875,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
talloc_free(notif_parameters);
// table notification
mapping = [[self context] mapping];
mapping = [self mapping];
for (count = 0; count < midCount; count++)
{
messageURL = [mapping urlFromID: targetMids[count]];
@ -863,7 +889,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
inTableType: (uint8_t) tableType
inTableType: (enum mapistore_table_type) tableType
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc;
@ -879,7 +905,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inTableType: tableType];
if (keys)
{
mapping = [[self context] mapping];
mapping = [self mapping];
max = [keys count];
@ -920,7 +946,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (int) getTable: (MAPIStoreTable **) tablePtr
andRowCount: (uint32_t *) countPtr
tableType: (uint8_t) tableType
tableType: (enum mapistore_table_type) tableType
andHandleId: (uint32_t) handleId
{
int rc = MAPISTORE_SUCCESS;
@ -976,27 +1002,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[propsCopy release];
}
- (void) dealloc
{
[propsMessage release];
[propsFolder release];
[folderURL release];
[messageKeys release];
[faiMessageKeys release];
[folderKeys release];
[faiFolder release];
[super dealloc];
}
- (MAPIStoreContext *) context
{
if (!context)
context = [container context];
return context;
}
- (NSArray *) messageKeys
{
if (!messageKeys)
@ -1076,7 +1081,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
andType: MAPISTORE_FAI_TABLE];
}
- (void) _cleanupTableCaches: (uint8_t) tableType
- (void) _cleanupTableCaches: (enum mapistore_table_type) tableType
{
NSArray *tables;
NSUInteger count, max;
@ -1132,16 +1137,20 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
uint32_t access = 0;
SOGoUser *ownerUser;
BOOL userIsOwner;
userIsOwner = [[context activeUser] isEqual: [context ownerUser]];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner || [self subscriberCanModifyMessages])
access |= 0x01;
if (userIsOwner || [self subscriberCanReadMessages])
access |= 0x02;
if (userIsOwner || [self subscriberCanDeleteMessages])
access |= 0x04;
if (userIsOwner || [self subscriberCanCreateSubFolders])
if ((userIsOwner || [self subscriberCanCreateSubFolders])
&& [self supportsSubFolders])
access |= 0x08;
if (userIsOwner || [self subscriberCanCreateMessages])
access |= 0x10;
@ -1284,7 +1293,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
else
newMessage = [self createMessage];
[newMessage setIsNew: YES];
woContext = [[self context] woContext];
woContext = [[self userContext] woContext];
[[newMessage sogoObject] setContext: woContext];
return newMessage;
@ -1304,10 +1313,14 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
NSString *url;
if (folderURL)
url = [folderURL absoluteString];
else
if (container)
url = [NSString stringWithFormat: @"%@/", [super url]];
else
{
url = [[context url] absoluteString];
if (![url hasSuffix: @"/"])
url = [NSString stringWithFormat: @"%@/", url];
}
return url;
}
@ -1511,10 +1524,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
uint64_t objectId;
if (folderURL)
objectId = [self idForObjectWithKey: nil];
else
if (container)
objectId = [super objectId];
else
objectId = [self idForObjectWithKey: nil];
return objectId;
}
@ -1552,7 +1565,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
andCN: (NSNumber **) cnNbrs
inTableType: (uint8_t) tableType
inTableType: (enum mapistore_table_type) tableType
{
return nil;
}
@ -1595,4 +1608,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return NO;
}
- (BOOL) supportsSubFolders
{
return NO;
}
@end

View File

@ -1,32 +0,0 @@
/* MAPIStoreFreebusyContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTOREFREEBUSYCONTEXT_H
#define MAPISTOREFREEBUSYCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreFreebusyContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTOREFREEBUSYCONTEXT_H */

View File

@ -20,10 +20,22 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <SOGo/SOGoGCSFolder.h>
#import <SOGo/SOGoParentFolder.h>
#import "MAPIStoreUserContext.h"
#import "NSString+MAPIStore.h"
#import "MAPIStoreGCSBaseContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
#include <dlinklist.h>
@implementation MAPIStoreGCSBaseContext
+ (NSString *) MAPIModuleName
@ -31,4 +43,59 @@
return nil;
}
+ (enum mapistore_context_role) MAPIModuleRole
{
return -1;
}
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *firstContext = NULL, *context;
NSString *moduleName, *baseUrl, *url, *nameInContainer;
NSArray *subfolders;
MAPIStoreUserContext *userContext;
SOGoParentFolder *parentFolder;
NSUInteger count, max;
SOGoGCSFolder *currentFolder;
moduleName = [self MAPIModuleName];
if (moduleName)
{
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexingTdb];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
baseUrl = [NSString stringWithFormat: @"sogo://%@@%@/",
userName, moduleName];
subfolders = [parentFolder subFolders];
max = [subfolders count];
for (count = 0; count < max; count++)
{
currentFolder = [subfolders objectAtIndex: count];
if ([[currentFolder ownerInContext: nil] isEqualToString: userName])
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
nameInContainer = [currentFolder nameInContainer];
url = [NSString stringWithFormat: @"%@%@", baseUrl, nameInContainer];
context->url = [url asUnicodeInMemCtx: context];
context->name = [[currentFolder displayName]
asUnicodeInMemCtx: context];
context->main_folder = [nameInContainer isEqualToString: @"personal"];
context->role = [self MAPIModuleRole];
context->tag = "tag";
DLIST_ADD_END (firstContext, context, void);
}
}
}
return firstContext;
}
- (id) rootSOGoFolder
{
return [[userContext rootFolders] objectForKey: [isa MAPIModuleName]];
}
@end

View File

@ -22,6 +22,7 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import <EOControl/EOFetchSpecification.h>
@ -29,11 +30,13 @@
#import <GDLContentStore/GCSFolder.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoGCSFolder.h>
#import <SOGo/SOGoParentFolder.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUser.h>
#import "MAPIStoreContext.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -43,38 +46,28 @@
#undef DEBUG
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
@implementation MAPIStoreGCSFolder
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
activeUserRoles = nil;
}
return self;
}
- (id) initWithSOGoObject: (id) newSOGoObject
inContainer: (MAPIStoreObject *) newContainer
{
if ((self = [super initWithSOGoObject: newSOGoObject inContainer: newContainer]))
{
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
activeUserRoles = nil;
}
return self;
}
- (void) setupVersionsMessage
{
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
}
- (void) dealloc
{
[versionsMessage release];
@ -82,10 +75,58 @@
[super dealloc];
}
- (int) deleteFolder
{
int rc;
NSException *error;
NSString *name;
name = [self nameInContainer];
if ([name isEqualToString: @"personal"])
rc = MAPISTORE_ERR_DENIED;
else
{
[[sogoObject container] removeSubFolder: name];
error = [(SOGoGCSFolder *) sogoObject delete];
if (error)
rc = MAPISTORE_ERROR;
else
{
if (![versionsMessage delete])
rc = MAPISTORE_SUCCESS;
else
rc = MAPISTORE_ERROR;
}
}
return (rc == MAPISTORE_SUCCESS) ? [super deleteFolder] : rc;
}
- (void) addProperties: (NSDictionary *) newProperties
{
NSString *newDisplayName;
NSMutableDictionary *propsCopy;
NSNumber *key;
key = MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE);
newDisplayName = [newProperties objectForKey: key];
if (newDisplayName)
{
[sogoObject renameTo: newDisplayName];
propsCopy = [newProperties mutableCopy];
[propsCopy removeObjectForKey: key];
[propsCopy autorelease];
newProperties = propsCopy;
}
[super addProperties: newProperties];
}
- (NSArray *) messageKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
static NSArray *fields = nil;
SOGoUser *ownerUser;
NSArray *records;
NSMutableArray *qualifierArray;
EOQualifier *fetchQualifier, *aclQualifier;
@ -98,7 +139,8 @@
initWithObjects: @"c_name", @"c_version", nil];
qualifierArray = [NSMutableArray new];
if (![[context activeUser] isEqual: [context ownerUser]])
ownerUser = [[self userContext] sogoUser];
if (![[context activeUser] isEqual: ownerUser])
{
aclQualifier = [self aclQualifier];
if (aclQualifier)
@ -528,12 +570,14 @@
- (NSArray *) activeUserRoles
{
SOGoUser *activeUser;
WOContext *woContext;
if (!activeUserRoles)
{
activeUser = [[self context] activeUser];
woContext = [[self userContext] woContext];
activeUserRoles = [activeUser rolesForObject: sogoObject
inContext: [context woContext]];
inContext: woContext];
[activeUserRoles retain];
}

View File

@ -30,6 +30,7 @@
#import "MAPIStoreContext.h"
#import "MAPIStoreGCSFolder.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSData+MAPIStore.h"
#import "MAPIStoreGCSMessage.h"
@ -56,15 +57,17 @@
MAPIStoreContext *context;
WOContext *woContext;
SoSecurityManager *sm;
MAPIStoreUserContext *userContext;
uint32_t access;
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]])
userContext = [self userContext];
if ([[context activeUser] isEqual: [userContext sogoUser]])
access = 0x03;
else
{
sm = [SoSecurityManager sharedSecurityManager];
woContext = [context woContext];
woContext = [userContext woContext];
access = 0;
if (![sm validatePermission: SoPerm_ChangeImagesAndFiles
@ -89,18 +92,19 @@
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreContext *context;
MAPIStoreUserContext *userContext;
WOContext *woContext;
SoSecurityManager *sm;
uint32_t accessLvl;
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]])
userContext = [self userContext];
if ([[context activeUser] isEqual: [userContext sogoUser]])
accessLvl = 1;
else
{
sm = [SoSecurityManager sharedSecurityManager];
woContext = [context woContext];
woContext = [userContext woContext];
if (![sm validatePermission: SoPerm_ChangeImagesAndFiles
onObject: sogoObject
inContext: woContext])

View File

@ -58,7 +58,7 @@
NSCalendarDate *dateValue;
int32_t longDate;
translatedRes = talloc (NULL, struct mapi_SPropertyRestriction);
translatedRes = talloc (memCtx, struct mapi_SPropertyRestriction);
translatedRes->ulPropTag = (res->ulPropTag & 0xffff0000) | PT_LONG;
translatedRes->relop = res->relop;
dateValue = NSObjectFromMAPISPropValue (&res->lpProp);

View File

@ -1,32 +0,0 @@
/* MAPIStoreJournalContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTOREJOURNALCONTEXT_H
#define MAPISTOREJOURNALCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreJournalContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTOREJOURNALCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreJournalContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreJournalContext.h"
@implementation MAPIStoreJournalContext
+ (NSString *) MAPIModuleName
{
return @"journal";
}
@end

View File

@ -28,20 +28,6 @@
@interface MAPIStoreMailContext : MAPIStoreContext
@end
@interface MAPIStoreInboxContext : MAPIStoreMailContext
@end
@interface MAPIStoreSentItemsContext : MAPIStoreMailContext
@end
@interface MAPIStoreDraftsContext : MAPIStoreMailContext
@end
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreDeletedItemsContext : MAPIStoreFSBaseContext
@end
@interface MAPIStoreOutboxContext : MAPIStoreMailContext
@end

View File

@ -20,94 +20,125 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailFolder.h>
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
#import "NSString+MAPIStore.h"
#import "MAPIStoreMailContext.h"
#include <dlinklist.h>
#undef DEBUG
#include <mapistore/mapistore.h>
static Class MAPIStoreMailFolderK;
@implementation MAPIStoreMailContext
+ (NSString *) MAPIModuleName
+ (void) initialize
{
return nil;
MAPIStoreMailFolderK = [MAPIStoreMailFolder class];
}
@end
@implementation MAPIStoreInboxContext
+ (NSString *) MAPIModuleName
{
return @"inbox";
return @"mail";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
baseFolder = [MAPIStoreInboxFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
struct mapistore_contexts_list *firstContext = NULL, *context;
NSString *urlBase, *stringData, *currentName, *inboxName, *draftsName, *sentName, *trashName;
NSMutableArray *secondaryFolders;
enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE,
MAPISTORE_DRAFTS_ROLE,
MAPISTORE_SENTITEMS_ROLE};
NSString *folderName[3];
NSUInteger count, max;
SOGoMailAccount *accountFolder;
MAPIStoreUserContext *userContext;
WOContext *woContext;
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexingTdb];
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
woContext = [userContext woContext];
inboxName = @"folderINBOX";
folderName[0] = inboxName;
draftsName = [NSString stringWithFormat: @"folder%@",
[accountFolder draftsFolderNameInContext: woContext]];
folderName[1] = draftsName;
sentName = [NSString stringWithFormat: @"folder%@",
[accountFolder sentFolderNameInContext: woContext]];
folderName[2] = sentName;
trashName = [NSString stringWithFormat: @"folder%@",
[accountFolder trashFolderNameInContext: woContext]];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", userName, userName];
for (count = 0; count < 3; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
stringData = [NSString stringWithFormat: @"%@%@", urlBase,
folderName[count]];
context->url = [stringData asUnicodeInMemCtx: context];
/* remove "folder" prefix */
stringData = [folderName[count] substringFromIndex: 6];
context->name = [stringData asUnicodeInMemCtx: context];
context->main_folder = true;
context->role = role[count];
context->tag = "tag";
DLIST_ADD_END (firstContext, context, void);
}
secondaryFolders = [[accountFolder toManyRelationshipKeysWithNamespaces: NO]
mutableCopy];
[secondaryFolders autorelease];
[secondaryFolders removeObject: inboxName];
[secondaryFolders removeObject: draftsName];
[secondaryFolders removeObject: draftsName];
[secondaryFolders removeObject: sentName];
[secondaryFolders removeObject: trashName];
max = [secondaryFolders count];
for (count = 0; count < max; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
currentName = [secondaryFolders objectAtIndex: count];
stringData = [NSString stringWithFormat: @"%@%@", urlBase, currentName];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [currentName substringFromIndex: 6];
context->name = [stringData asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
context->tag = "tag";
DLIST_ADD_END (firstContext, context, void);
}
return firstContext;
}
@end
@implementation MAPIStoreSentItemsContext
+ (NSString *) MAPIModuleName
- (Class) MAPIStoreFolderClass
{
return @"sent-items";
return MAPIStoreMailFolderK;
}
- (void) setupBaseFolder: (NSURL *) newURL
- (id) rootSOGoFolder
{
baseFolder = [MAPIStoreSentItemsFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
return [[userContext rootFolders] objectForKey: @"mail"];
}
@end
@implementation MAPIStoreDraftsContext
+ (NSString *) MAPIModuleName
{
return @"drafts";
}
- (void) setupBaseFolder: (NSURL *) newURL
{
baseFolder = [MAPIStoreDraftsFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
}
@end
#import "MAPIStoreFSFolder.h"
@implementation MAPIStoreDeletedItemsContext
+ (NSString *) MAPIModuleName
{
return @"deleted-items";
}
- (void) setupBaseFolder: (NSURL *) newURL
{
baseFolder = [MAPIStoreFSFolder baseFolderWithURL: newURL inContext: self];
[baseFolder retain];
}
// - (void) setupBaseFolder: (NSURL *) newURL
// {
// baseFolder = [MAPIStoreDeletedItemsFolder baseFolderWithURL: newURL
// inContext: self];
// [baseFolder retain];
// }
@end
@implementation MAPIStoreOutboxContext
+ (NSString *) MAPIModuleName
@ -115,11 +146,35 @@
return @"outbox";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
baseFolder = [MAPIStoreOutboxFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
struct mapistore_contexts_list *context;
NSString *url, *folderName;
SOGoMailAccount *accountFolder;
MAPIStoreUserContext *userContext;
WOContext *woContext;
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexingTdb];
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
woContext = [userContext woContext];
folderName = [NSString stringWithFormat: @"folder%@",
[accountFolder draftsFolderNameInContext: woContext]];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", userName,
userName, folderName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [url asUnicodeInMemCtx: context];
/* TODO: use a localized version of this display name */
context->name = [@"Outbox" asUnicodeInMemCtx: context];
context->main_folder = true;
context->role = MAPISTORE_OUTBOX_ROLE;
context->tag = "tag";
context->prev = context;
return context;
}
@end

View File

@ -39,11 +39,6 @@
SOGoMAPIFSMessage *versionsMessage;
}
/* subclasses */
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) account
inContext: (WOContext *) woContext;
/* synchronisation & versioning */
- (BOOL) synchroniseCache;
- (NSNumber *) modseqFromMessageChangeNumber: (NSNumber *) changeNum;
@ -56,23 +51,4 @@
@end
@interface MAPIStoreInboxFolder : MAPIStoreMailFolder
{
BOOL usesAltNameSpace;
}
@end
@interface MAPIStoreSentItemsFolder : MAPIStoreMailFolder
@end
@interface MAPIStoreDraftsFolder : MAPIStoreMailFolder
@end
// @interface MAPIStoreDeletedItemsFolder : MAPIStoreFFolder
// @end
@interface MAPIStoreOutboxFolder : MAPIStoreMailFolder
@end
#endif /* MAPISTOREMAILFOLDER_H */

View File

@ -77,71 +77,21 @@ static Class SOGoMailFolderK;
[MAPIStoreAppointmentWrapper class];
}
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
- (id) init
{
SOGoUserFolder *userFolder;
SOGoMailAccounts *accountsFolder;
SOGoMailAccount *accountFolder;
SOGoFolder *currentContainer;
WOContext *woContext;
if ((self = [super initWithURL: newURL
inContext: newContext]))
if ((self = [super init]))
{
woContext = [newContext woContext];
userFolder = [SOGoUserFolder objectWithName: [newURL user]
inContainer: MAPIApp];
[parentContainersBag addObject: userFolder];
[woContext setClientObject: userFolder];
accountsFolder = [userFolder lookupName: @"Mail"
inContext: woContext
acquire: NO];
[parentContainersBag addObject: accountsFolder];
[woContext setClientObject: accountsFolder];
accountFolder = [accountsFolder lookupName: @"0"
inContext: woContext
acquire: NO];
[[accountFolder imap4Connection]
enableExtension: @"QRESYNC"];
[parentContainersBag addObject: accountFolder];
[woContext setClientObject: accountFolder];
sogoObject = [self specialFolderFromAccount: accountFolder
inContext: woContext];
[sogoObject retain];
currentContainer = [sogoObject container];
while (currentContainer != (SOGoFolder *) accountFolder)
{
[parentContainersBag addObject: currentContainer];
currentContainer = [currentContainer container];
}
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
versionsMessage = nil;
}
return self;
}
- (id) initWithSOGoObject: (id) newSOGoObject
inContainer: (MAPIStoreObject *) newContainer
- (void) setupVersionsMessage
{
// NSString *urlString;
if ((self = [super initWithSOGoObject: newSOGoObject inContainer: newContainer]))
{
// urlString = [[self url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
}
return self;
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
}
- (void) dealloc
@ -150,12 +100,25 @@ static Class SOGoMailFolderK;
[super dealloc];
}
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
inContext: (WOContext *) woContext
{
[self subclassResponsibility: _cmd];
return nil;
- (void) addProperties: (NSDictionary *) newProperties
{
NSString *newDisplayName;
NSMutableDictionary *propsCopy;
NSNumber *key;
key = MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE);
newDisplayName = [newProperties objectForKey: key];
if (newDisplayName)
{
[(SOGoMailFolder *) sogoObject renameTo: newDisplayName];
propsCopy = [newProperties mutableCopy];
[propsCopy removeObjectForKey: key];
[propsCopy autorelease];
newProperties = propsCopy;
}
[super addProperties: newProperties];
}
- (MAPIStoreMessageTable *) messageTable
@ -166,7 +129,6 @@ static Class SOGoMailFolderK;
- (NSString *) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID
inContainer: (id) subfolderParent
{
NSString *folderName, *nameInContainer;
SOGoMailFolder *newFolder;
@ -188,7 +150,7 @@ static Class SOGoMailFolderK;
nameInContainer = [NSString stringWithFormat: @"folder%@",
[folderName asCSSIdentifier]];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: subfolderParent];
inContainer: sogoObject];
if (![newFolder create])
nameInContainer = nil;
}
@ -196,13 +158,6 @@ static Class SOGoMailFolderK;
return nameInContainer;
}
- (NSString *) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID
{
return [self createFolder: aRow withFID: newFID
inContainer: sogoObject];
}
- (int) getPrContentUnread: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -848,7 +803,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
/* sample: 1 OK [COPYUID 1311899334 1:3 11:13] Completed */
max = [line length];
uniString = NSZoneMalloc (NULL, max * sizeof (unichar) + 1);
uniString = NSZoneMalloc (NULL, sizeof (unichar) * (max + 1));
[line getCharacters: uniString];
uniString[max] = 0;
@ -896,7 +851,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
wantCopy: wantCopy];
/* Conversion of mids to IMAP uids */
mapping = [[self context] mapping];
mapping = [self mapping];
uids = [NSMutableArray arrayWithCapacity: midCount];
oldMessageURLs = [NSMutableArray arrayWithCapacity: midCount];
for (count = 0; count < midCount; count++)
@ -1025,6 +980,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
if (rights & RightsCreateSubfolders)
[roles addObject: SOGoRole_FolderCreator];
// [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles];
return roles;
}
@ -1051,172 +1008,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@end
@implementation MAPIStoreInboxFolder : MAPIStoreMailFolder
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
NSDictionary *list, *response;
NGImap4Client *client;
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
client = [[(SOGoMailFolder *) sogoObject imap4Connection] client];
list = [client list: @"" pattern: @"INBOX"];
response = [[list objectForKey: @"RawResponse"] objectForKey: @"list"];
usesAltNameSpace = [[response objectForKey: @"flags"] containsObject: @"noinferiors"];
}
return self;
}
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
inContext: (WOContext *) woContext
{
return [accountFolder inboxFolderInContext: woContext];
}
- (NSString *) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID
{
id subfolderParent;
if (usesAltNameSpace)
subfolderParent = [(SOGoMailFolder *) sogoObject mailAccountFolder];
else
subfolderParent = sogoObject;
return [self createFolder: aRow withFID: newFID
inContainer: subfolderParent];
}
- (NSMutableString *) _imapFolderNameRepresentation: (NSString *) subfolderName
{
NSMutableString *representation;
if (usesAltNameSpace)
{
/* with "altnamespace", the subfolders are NEVER subfolders of INBOX... */;
if (![subfolderName hasPrefix: @"folder"])
abort ();
representation
= [NSMutableString stringWithString:
[subfolderName substringFromIndex: 6]];
}
else
representation = [super _imapFolderNameRepresentation: subfolderName];
return representation;
}
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
NSMutableArray *subfolderKeys;
SOGoMailAccount *account;
if (usesAltNameSpace)
{
if (qualifier)
[self errorWithFormat: @"qualifier is not used for folders"];
if (sortOrderings)
[self errorWithFormat: @"sort orderings are not used for folders"];
account = [(SOGoMailFolder *) sogoObject mailAccountFolder];
subfolderKeys
= [[account toManyRelationshipKeysWithNamespaces: NO]
mutableCopy];
[subfolderKeys removeObject: @"folderINBOX"];
[self _cleanupSubfolderKeys: subfolderKeys];
}
else
subfolderKeys = [[super folderKeysMatchingQualifier: qualifier
andSortOrderings: sortOrderings]
mutableCopy];
/* TODO: remove special folders */
[subfolderKeys autorelease];
return subfolderKeys;
}
- (id) lookupFolder: (NSString *) childKey
{
MAPIStoreMailFolder *childFolder = nil;
SOGoMailAccount *account;
SOGoMailFolder *sogoFolder;
WOContext *woContext;
if (usesAltNameSpace)
{
if ([[self folderKeys] containsObject: childKey])
{
woContext = [[self context] woContext];
account = [(SOGoMailFolder *) sogoObject mailAccountFolder];
sogoFolder = [account lookupName: childKey inContext: woContext
acquire: NO];
[sogoFolder setContext: woContext];
childFolder = [MAPIStoreMailFolder mapiStoreObjectWithSOGoObject: sogoFolder
inContainer: self];
}
}
else
childFolder = [super lookupFolder: childKey];
return childFolder;
}
@end
@implementation MAPIStoreSentItemsFolder : MAPIStoreMailFolder
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
inContext: (WOContext *) woContext
{
return [accountFolder sentFolderInContext: woContext];
}
@end
@implementation MAPIStoreDraftsFolder : MAPIStoreMailFolder
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
inContext: (WOContext *) woContext
{
return [accountFolder draftsFolderInContext: woContext];
}
@end
// @implementation MAPIStoreDeletedItemsFolder : MAPIStoreMailFolder
// - (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
// inContext: (WOContext *) woContext
// {
// return [accountFolder trashFolderInContext: woContext];
// }
// @end
//
//
//
@implementation MAPIStoreOutboxFolder : MAPIStoreMailFolder
- (SOGoMailFolder *) specialFolderFromAccount: (SOGoMailAccount *) accountFolder
inContext: (WOContext *) woContext
{
return [accountFolder draftsFolderInContext: woContext];
}
@end

View File

@ -62,7 +62,7 @@
@class iCalCalendar, iCalEvent;
static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK;
static Class NSExceptionK;
@interface NSString (MAPIStoreMIME)
@ -105,8 +105,6 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK;
+ (void) initialize
{
NSExceptionK = [NSException class];
MAPIStoreSentItemsFolderK = [MAPIStoreSentItemsFolder class];
MAPIStoreDraftsFolderK = [MAPIStoreDraftsFolder class];
}
- (id) init
@ -582,9 +580,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
if ([container isKindOfClass: MAPIStoreSentItemsFolderK]
|| [container isKindOfClass: MAPIStoreDraftsFolderK])
v |= MSGFLAG_FROMME;
// if ([container isKindOfClass: MAPIStoreSentItemsFolderK]
// || [container isKindOfClass: MAPIStoreDraftsFolderK])
// v |= MSGFLAG_FROMME;
if ([flags containsObject: @"seen"])
v |= MSGFLAG_READ;
if ([[self attachmentKeys]

View File

@ -326,7 +326,7 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
- (int) getRow: (struct mapistore_property_data **) dataP
withRowID: (uint32_t) rowId
andQueryType: (enum table_query_type) queryType
andQueryType: (enum mapistore_query_type) queryType
inMemCtx: (TALLOC_CTX *) memCtx
{
if (!fetchedCoreInfos)

View File

@ -813,7 +813,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts,
if (error)
[self logWithFormat: @"an error occurred: '%@'", error];
mapping = [[self context] mapping];
mapping = [self mapping];
[mapping unregisterURLWithID: [self objectId]];
[self setIsNew: NO];
[properties removeAllObjects];
@ -851,7 +851,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts,
newIdString = [[flag componentsSeparatedByString: @" "]
objectAtIndex: 2];
mid = [self objectId];
mapping = [[self context] mapping];
mapping = [self mapping];
[mapping unregisterURLWithID: mid];
[sogoObject setNameInContainer: [NSString stringWithFormat: @"%@.eml", newIdString]];
[mapping registerURL: [self url] withID: mid];

View File

@ -39,6 +39,7 @@
#import "MAPIStorePropertySelectors.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -286,10 +287,11 @@ rtf2html (NSData *compressedRTF)
{
enum mapistore_error rc;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanModifyMessage])
rc = [super addPropertiesFromRow: aRow];
else
@ -432,9 +434,11 @@ rtf2html (NSData *compressedRTF)
uint64_t folderId;
struct mapistore_context *mstoreCtx;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
if ([[context activeUser] isEqual: [context ownerUser]]
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| ((isNew
&& [(MAPIStoreFolder *) container subscriberCanCreateMessages])
|| (!isNew && [self subscriberCanModifyMessage])))
@ -560,9 +564,11 @@ rtf2html (NSData *compressedRTF)
uint32_t access = 0;
BOOL userIsOwner;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
userIsOwner = [[context activeUser] isEqual: [context ownerUser]];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner || [self subscriberCanModifyMessage])
access |= 0x01;
if (userIsOwner || [self subscriberCanReadMessage])
@ -587,9 +593,11 @@ rtf2html (NSData *compressedRTF)
uint32_t access = 0;
BOOL userIsOwner;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
userIsOwner = [[context activeUser] isEqual: [context ownerUser]];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner || [self subscriberCanModifyMessage])
access = 0x01;
else
@ -862,14 +870,15 @@ rtf2html (NSData *compressedRTF)
- (NSArray *) activeUserRoles
{
MAPIStoreContext *context;
MAPIStoreUserContext *userContext;
if (!activeUserRoles)
{
context = [self context];
userContext = [self userContext];
activeUserRoles = [[context activeUser]
rolesForObject: sogoObject
inContext: [context woContext]];
inContext: [userContext woContext]];
[activeUserRoles retain];
}

View File

@ -27,6 +27,9 @@
#import "MAPIStoreNotesContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
@implementation MAPIStoreNotesContext
+ (NSString *) MAPIModuleName
@ -34,11 +37,22 @@
return @"notes";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withTDBIndexing: (struct tdb_wrap *) indexingTdb
inMemCtx: (TALLOC_CTX *) memCtx
{
baseFolder = [MAPIStoreNotesFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
struct mapistore_contexts_list *context;
context = talloc_zero(memCtx, struct mapistore_contexts_list);
context->url = talloc_asprintf (context, "sogo://%s@notes/",
[userName UTF8String]);
// context->name = "Notes personnelles";
context->main_folder = true;
context->role = MAPISTORE_NOTES_ROLE;
context->tag = "tag";
context->prev = context;
return context;
}
@end

View File

@ -35,8 +35,11 @@
@class EOQualifier;
@class MAPIStoreContext;
@class MAPIStoreFolder;
@class MAPIStoreMapping;
@class MAPIStoreTable;
@class MAPIStoreUserContext;
@interface MAPIStoreObject : NSObject
{
@ -71,7 +74,9 @@
- (id) sogoObject;
- (MAPIStoreObject *) container;
- (id) context;
- (MAPIStoreContext *) context;
- (MAPIStoreUserContext *) userContext;
- (MAPIStoreMapping *) mapping;
- (void) cleanupCaches;

View File

@ -30,6 +30,7 @@
#import "MAPIStoreFolder.h"
#import "MAPIStorePropertySelectors.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSDate+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@ -170,11 +171,21 @@ static Class NSExceptionK, MAPIStoreFolderK;
return [sogoObject nameInContainer];
}
- (id) context
- (MAPIStoreContext *) context
{
return [container context];
}
- (MAPIStoreUserContext *) userContext
{
return [[self context] userContext];
}
- (MAPIStoreMapping *) mapping
{
return [[self userContext] mapping];
}
- (void) cleanupCaches
{
}
@ -217,7 +228,7 @@ static Class NSExceptionK, MAPIStoreFolderK;
NSTimeZone *tz;
WOContext *woContext;
woContext = [[self context] woContext];
woContext = [[self userContext] woContext];
owner = [sogoObject ownerInContext: woContext];
ud = [[SOGoUser userWithLogin: owner] userDefaults];
tz = [ud timeZone];

View File

@ -1,32 +0,0 @@
/* MAPIStoreRemindersContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTOREREMINDERSCONTEXT_H
#define MAPISTOREREMINDERSCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreRemindersContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTOREREMINDERSCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreRemindersContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreRemindersContext.h"
@implementation MAPIStoreRemindersContext
+ (NSString *) MAPIModuleName
{
return @"reminders";
}
@end

View File

@ -43,17 +43,16 @@
#import "MAPIStoreTable.h"
#import "NSObject+MAPIStore.h"
#undef DEBUG
#include <stdbool.h>
#include <talloc.h>
#include <gen_ndr/exchange.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
static Class MAPIStoreContextK = Nil;
static enum mapistore_error
sogo_backend_unexpected_error()
{
NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO OBJECT");
abort();
return MAPISTORE_SUCCESS;
}
@ -85,7 +84,7 @@ sogo_backend_init (void)
[SOGoSystemDefaults sharedSystemDefaults];
// /* We force the plugin to base its configuration on the SOGo tree. */
/* We force the plugin to base its configuration on the SOGo tree. */
ud = [NSUserDefaults standardUserDefaults];
[ud registerDefaults: [ud persistentDomainForName: @"sogod"]];
@ -102,6 +101,8 @@ sogo_backend_init (void)
[[SOGoCache sharedCache] disableRequestsCache];
[[SOGoCache sharedCache] disableLocalCache];
MAPIStoreContextK = NSClassFromString (@"MAPIStoreContext");
[pool release];
return MAPISTORE_SUCCESS;
@ -122,7 +123,6 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
const char *uri, void **context_object)
{
NSAutoreleasePool *pool;
Class MAPIStoreContextK;
MAPIStoreContext *context;
int rc;
@ -130,7 +130,6 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
pool = [NSAutoreleasePool new];
MAPIStoreContextK = NSClassFromString (@"MAPIStoreContext");
if (MAPIStoreContextK)
{
rc = [MAPIStoreContextK openContext: &context
@ -148,6 +147,35 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
return rc;
}
static enum mapistore_error
sogo_backend_list_contexts(const char *username, struct tdb_wrap *indexingTdb,
TALLOC_CTX *mem_ctx,
struct mapistore_contexts_list **contexts_listp)
{
NSAutoreleasePool *pool;
NSString *userName;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
pool = [NSAutoreleasePool new];
if (MAPIStoreContextK)
{
userName = [NSString stringWithUTF8String: username];
*contexts_listp = [MAPIStoreContextK listAllContextsForUser: userName
withTDBIndexing: indexingTdb
inMemCtx: mem_ctx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERROR;
[pool release];
return rc;
}
// andFID: fid
// uint64_t fid,
// void **private_data)
@ -305,7 +333,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
*/
static enum mapistore_error
sogo_folder_delete_folder(void *folder_object, uint64_t fid)
sogo_folder_delete(void *folder_object)
{
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
@ -319,7 +347,7 @@ sogo_folder_delete_folder(void *folder_object, uint64_t fid)
wrapper = folder_object;
folder = wrapper->MAPIStoreSOGoObject;
pool = [NSAutoreleasePool new];
rc = [folder deleteFolderWithFID: fid];
rc = [folder deleteFolder];
[pool release];
}
else
@ -331,7 +359,7 @@ sogo_folder_delete_folder(void *folder_object, uint64_t fid)
}
static enum mapistore_error
sogo_folder_get_child_count(void *folder_object, uint8_t table_type, uint32_t *child_count)
sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table_type, uint32_t *child_count)
{
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
@ -494,7 +522,7 @@ sogo_folder_move_copy_messages(void *folder_object,
static enum mapistore_error
sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
uint8_t table_type, uint64_t change_num,
enum mapistore_table_type table_type, uint64_t change_num,
struct I8Array_r **fmidsp, uint64_t *cnp)
{
struct MAPIStoreTallocWrapper *wrapper;
@ -526,7 +554,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
static enum mapistore_error
sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
uint8_t table_type, uint32_t handle_id,
enum mapistore_table_type table_type, uint32_t handle_id,
void **table_object, uint32_t *row_count)
{
struct MAPIStoreTallocWrapper *wrapper;
@ -974,7 +1002,7 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
static enum mapistore_error
sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
enum table_query_type query_type, uint32_t row_id,
enum mapistore_query_type query_type, uint32_t row_id,
struct mapistore_property_data **data)
{
struct MAPIStoreTallocWrapper *wrapper;
@ -1003,7 +1031,7 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
static enum mapistore_error
sogo_table_get_row_count (void *table_object,
enum table_query_type query_type,
enum mapistore_query_type query_type,
uint32_t *row_countp)
{
struct MAPIStoreTallocWrapper *wrapper;
@ -1211,11 +1239,12 @@ int mapistore_init_backend(void)
backend.backend.namespace = "sogo://";
backend.backend.init = sogo_backend_init;
backend.backend.create_context = sogo_backend_create_context;
backend.backend.list_contexts = sogo_backend_list_contexts;
backend.context.get_path = sogo_context_get_path;
backend.context.get_root_folder = sogo_context_get_root_folder;
backend.folder.open_folder = sogo_folder_open_folder;
backend.folder.create_folder = sogo_folder_create_folder;
backend.folder.delete_folder = sogo_folder_delete_folder;
backend.folder.delete = sogo_folder_delete;
backend.folder.open_message = sogo_folder_open_message;
backend.folder.create_message = sogo_folder_create_message;
backend.folder.delete_message = sogo_folder_delete_message;

View File

@ -1,32 +0,0 @@
/* MAPIStoreScheduleContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTORESCHEDULECONTEXT_H
#define MAPISTORESCHEDULECONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreScheduleContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTORESCHEDULECONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreScheduleContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreScheduleContext.h"
@implementation MAPIStoreScheduleContext
+ (NSString *) MAPIModuleName
{
return @"schedule";
}
@end

View File

@ -1,32 +0,0 @@
/* MAPIStoreSearchContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTORESEARCHCONTEXT_H
#define MAPISTORESEARCHCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreSearchContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTORESEARCHCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreSearchContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreSearchContext.h"
@implementation MAPIStoreSearchContext
+ (NSString *) MAPIModuleName
{
return @"search";
}
@end

View File

@ -1,32 +0,0 @@
/* MAPIStoreShortcutsContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTORESHORTCUTSCONTEXT_H
#define MAPISTORESHORTCUTSCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreShortcutsContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTORESHORTCUTSCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreShortcutsContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreShortcutsContext.h"
@implementation MAPIStoreShortcutsContext
+ (NSString *) MAPIModuleName
{
return @"shortcuts";
}
@end

View File

@ -27,6 +27,9 @@
#import <Foundation/NSObject.h>
#undef DEBUG
#include <mapistore/mapistore.h>
#define SENSITIVITY_NONE 0
#define SENSITIVITY_PERSONAL 1
#define SENSITIVITY_PRIVATE 2
@ -62,7 +65,7 @@ typedef enum {
uint32_t currentRow;
MAPIStoreObject *currentChild;
uint8_t tableType; /* mapistore */
enum mapistore_table_type tableType; /* mapistore */
/* proof of concept */
uint16_t columnsCount;
@ -75,13 +78,13 @@ typedef enum {
- (id) initForContainer: (MAPIStoreObject *) newContainer;
- (id) container;
- (uint8_t) tableType;
- (enum mapistore_table_type) tableType;
- (void) setHandleId: (uint32_t) newHandleId;
- (void) destroyHandle: (uint32_t) handleId;
- (id) childAtRowID: (uint32_t) rowId
forQueryType: (enum table_query_type) queryType;
forQueryType: (enum mapistore_query_type) queryType;
- (void) cleanupCaches;
@ -92,10 +95,10 @@ typedef enum {
withCount: (uint16_t) newColumCount;
- (int) getRow: (struct mapistore_property_data **) dataP
withRowID: (uint32_t) rowId
andQueryType: (enum table_query_type) queryType
andQueryType: (enum mapistore_query_type) queryType
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getRowCount: (uint32_t *) countP
withQueryType: (enum table_query_type) queryType;
withQueryType: (enum mapistore_query_type) queryType;
- (void) notifyChangesForChild: (MAPIStoreObject *) child;

View File

@ -337,7 +337,7 @@ static Class NSDataK, NSStringK;
return container;
}
- (uint8_t) tableType
- (enum mapistore_table_type) tableType
{
return tableType;
}
@ -351,7 +351,7 @@ static Class NSDataK, NSStringK;
- (void) destroyHandle: (uint32_t) tableHandleId
{
if (handleId == tableHandleId)
if (tableHandleId && (handleId == tableHandleId))
[[MAPIStoreActiveTables activeTables] unregisterTable: self];
}
@ -765,7 +765,7 @@ static Class NSDataK, NSStringK;
}
- (id) childAtRowID: (uint32_t) rowId
forQueryType: (enum table_query_type) queryType
forQueryType: (enum mapistore_query_type) queryType
{
id child;
NSArray *children, *restrictedChildren;
@ -833,7 +833,7 @@ static Class NSDataK, NSStringK;
- (int) getRow: (struct mapistore_property_data **) dataP
withRowID: (uint32_t) rowId
andQueryType: (enum table_query_type) queryType
andQueryType: (enum mapistore_query_type) queryType
inMemCtx: (TALLOC_CTX *) memCtx
{
NSUInteger count;
@ -860,7 +860,7 @@ static Class NSDataK, NSStringK;
}
- (int) getRowCount: (uint32_t *) countP
withQueryType: (enum table_query_type) queryType
withQueryType: (enum mapistore_query_type) queryType
{
NSArray *children;

View File

@ -21,24 +21,38 @@
*/
#import <Foundation/NSString.h>
#import <Appointments/SOGoAppointmentFolders.h>
#import "MAPIStoreTasksFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreTasksContext.h"
#undef DEBUG
#include <mapistore/mapistore.h>
static Class MAPIStoreTasksFolderK;
@implementation MAPIStoreTasksContext
+ (void) initialize
{
MAPIStoreTasksFolderK = [MAPIStoreTasksFolder class];
}
+ (NSString *) MAPIModuleName
{
return @"tasks";
}
- (void) setupBaseFolder: (NSURL *) newURL
+ (enum mapistore_context_role) MAPIModuleRole
{
baseFolder = [MAPIStoreTasksFolder baseFolderWithURL: newURL
inContext: self];
[baseFolder retain];
return MAPISTORE_TASKS_ROLE;
}
- (Class) MAPIStoreFolderClass
{
return MAPIStoreTasksFolderK;
}
@end

View File

@ -42,37 +42,6 @@
@implementation MAPIStoreTasksFolder
- (id) initWithURL: (NSURL *) newURL
inContext: (MAPIStoreContext *) newContext
{
SOGoUserFolder *userFolder;
SOGoAppointmentFolders *parentFolder;
WOContext *woContext;
if ((self = [super initWithURL: newURL
inContext: newContext]))
{
woContext = [newContext woContext];
userFolder = [SOGoUserFolder objectWithName: [newURL user]
inContainer: MAPIApp];
[parentContainersBag addObject: userFolder];
[woContext setClientObject: userFolder];
parentFolder = [userFolder lookupName: @"Calendar"
inContext: woContext
acquire: NO];
[parentContainersBag addObject: parentFolder];
[woContext setClientObject: parentFolder];
sogoObject = [parentFolder lookupName: @"personal"
inContext: woContext
acquire: NO];
[sogoObject retain];
}
return self;
}
- (MAPIStoreMessageTable *) messageTable
{
[self synchroniseCache];

View File

@ -22,8 +22,10 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalCalendar.h>
@ -325,13 +327,11 @@
iCalCalendar *vCalendar;
iCalToDo *vToDo;
id value;
SOGoUserDefaults *ud;
iCalTimeZone *tz;
iCalDateTime *date;
NSString *owner, *status, *priority;
NSString *status, *priority;
NSCalendarDate *now;
NSInteger tzOffset;
owner = [sogoObject ownerInContext: nil];
vToDo = [sogoObject component: YES secure: NO];
vCalendar = [vToDo parent];
[vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"];
@ -366,17 +366,16 @@
[vToDo setTimeStampAsDate: value];
}
ud = [[SOGoUser userWithLogin: owner] userDefaults];
tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]];
[vCalendar addTimeZone: tz];
// start
value = [properties objectForKey: MAPIPropertyKey (PidLidTaskStartDate)];
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"dtstart"];
[date setTimeZone: tz];
[date setDateTime: value];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDate: value];
}
else
{
@ -388,8 +387,11 @@
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"due"];
[date setTimeZone: tz];
[date setDateTime: value];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDate: value];
}
else
{
@ -401,8 +403,11 @@
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"];
[date setTimeZone: tz];
[date setDateTime: value];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDate: value];
}
else
{

View File

@ -148,7 +148,6 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
// #define PT_ERROR 0xa
// #define PT_OBJECT 0xd
// #define PT_I8 0x14
// #define PT_SVREID 0xFB
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];
@ -244,7 +243,6 @@ NSObjectFromSPropValue (const struct SPropValue *value)
// #define PT_ERROR 0xa
// #define PT_OBJECT 0xd
// #define PT_I8 0x14
// #define PT_SVREID 0xFB
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];

View File

@ -0,0 +1,79 @@
/* MAPIStoreUserContext.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2012 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 MAPISTOREUSERCONTEXT_H
#define MAPISTOREUSERCONTEXT_H
#import <Foundation/NSObject.h>
@class NSMutableDictionary;
@class NSString;
@class WOContext;
@class SOGoAppointmentFolders;
@class SOGoContactFolders;
@class SOGoMailAccount;
@class SOGoUser;
@class SOGoUserFolder;
@class MAPIStoreAuthenticator;
@class MAPIStoreMapping;
@interface MAPIStoreUserContext : NSObject
{
NSString *username;
SOGoUser *sogoUser;
SOGoUserFolder *userFolder;
NSMutableArray *containersBag;
NSMutableDictionary *rootFolders;
MAPIStoreMapping *mapping;
WOContext *woContext;
MAPIStoreAuthenticator *authenticator;
}
+ (id) userContextWithUsername: (NSString *) username
andTDBIndexing: (struct tdb_wrap *) indexingTdb;
- (id) initWithUsername: (NSString *) newUsername
andTDBIndexing: (struct tdb_wrap *) indexingTdb;
- (NSString *) username;
- (SOGoUser *) sogoUser;
- (SOGoUserFolder *) userFolder;
- (NSDictionary *) rootFolders;
- (MAPIStoreMapping *) mapping;
/* SOGo hacky magic */
- (void) activateWithUser: (SOGoUser *) activeUser;
- (MAPIStoreAuthenticator *) authenticator;
- (WOContext *) woContext;
@end
#endif /* MAPISTOREUSERCONTEXT_H */

View File

@ -0,0 +1,222 @@
/* MAPIStoreUserContext.m - this file is part of SOGo
*
* Copyright (C) 2012 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/NSDictionary.h>
#import <Foundation/NSMapTable.h>
#import <Foundation/NSThread.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGImap4/NGImap4Connection.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserFolder.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
#import "MAPIApplication.h"
#import "MAPIStoreAuthenticator.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
static NSMapTable *contextsTable = nil;
@implementation MAPIStoreUserContext
+ (void) initialize
{
contextsTable = [NSMapTable mapTableWithStrongToWeakObjects];
[contextsTable retain];
}
+ (id) userContextWithUsername: (NSString *) username
andTDBIndexing: (struct tdb_wrap *) indexingTdb;
{
id userContext;
userContext = [contextsTable objectForKey: username];
if (!userContext)
{
userContext = [[self alloc] initWithUsername: username
andTDBIndexing: indexingTdb];
[userContext autorelease];
[contextsTable setObject: userContext forKey: username];
}
return userContext;
}
- (id) init
{
if ((self = [super init]))
{
username = nil;
sogoUser = nil;
userFolder = nil;
containersBag = [NSMutableArray new];
rootFolders = nil;
mapping = nil;
authenticator = nil;
woContext = [WOContext contextWithRequest: nil];
[woContext retain];
}
return self;
}
- (id) initWithUsername: (NSString *) newUsername
andTDBIndexing: (struct tdb_wrap *) indexingTdb
{
if ((self = [self init]))
{
/* "username" will be retained by table */
username = newUsername;
if (indexingTdb)
ASSIGN (mapping, [MAPIStoreMapping mappingForUsername: username
withIndexing: indexingTdb]);
authenticator = [MAPIStoreAuthenticator new];
[authenticator setUsername: username];
/* TODO: very hackish (IMAP access) */
[authenticator setPassword: username];
}
return self;
}
- (void) dealloc
{
[userFolder release];
[containersBag release];
[rootFolders release];
[authenticator release];
[mapping release];
[sogoUser release];
[contextsTable removeObjectForKey: username];
[super dealloc];
}
- (NSString *) username
{
return username;
}
- (SOGoUser *) sogoUser
{
if (!sogoUser)
ASSIGN (sogoUser, [SOGoUser userWithLogin: username]);
return sogoUser;
}
- (SOGoUserFolder *) userFolder
{
if (!userFolder)
{
userFolder = [SOGoUserFolder objectWithName: username
inContainer: MAPIApp];
[userFolder retain];
}
return userFolder;
}
- (NSDictionary *) rootFolders
{
SOGoMailAccounts *accountsFolder;
id currentFolder;
if (!rootFolders)
{
rootFolders = [NSMutableDictionary new];
[self userFolder];
[woContext setClientObject: userFolder];
/* Calendar */
currentFolder = [userFolder lookupName: @"Calendar"
inContext: woContext
acquire: NO];
[rootFolders setObject: currentFolder
forKey: @"calendar"];
[rootFolders setObject: currentFolder
forKey: @"tasks"];
/* Contacts */
currentFolder = [userFolder lookupName: @"Contacts"
inContext: woContext
acquire: NO];
[rootFolders setObject: currentFolder
forKey: @"contacts"];
/* Mail */
accountsFolder = [userFolder lookupName: @"Mail"
inContext: woContext
acquire: NO];
[containersBag addObject: accountsFolder];
[woContext setClientObject: accountsFolder];
currentFolder = [accountsFolder lookupName: @"0"
inContext: woContext
acquire: NO];
[rootFolders setObject: currentFolder
forKey: @"mail"];
[[currentFolder imap4Connection]
enableExtension: @"QRESYNC"];
}
return rootFolders;
}
- (MAPIStoreMapping *) mapping
{
return mapping;
}
- (WOContext *) woContext
{
return woContext;
}
- (MAPIStoreAuthenticator *) authenticator
{
return authenticator;
}
- (void) activateWithUser: (SOGoUser *) activeUser;
{
NSMutableDictionary *info;
[MAPIApp setUserContext: self];
[woContext setActiveUser: activeUser];
info = [[NSThread currentThread] threadDictionary];
[info setObject: woContext forKey: @"WOContext"];
}
@end

View File

@ -1,32 +0,0 @@
/* MAPIStoreViewsContext.h - this file is part of SOGo
*
* Copyright (C) 2010 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 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 MAPISTOREVIEWSCONTEXT_H
#define MAPISTOREVIEWSCONTEXT_H
#import "MAPIStoreFSBaseContext.h"
@interface MAPIStoreViewsContext : MAPIStoreFSBaseContext
@end
#endif /* MAPISTOREVIEWSCONTEXT_H */

View File

@ -1,36 +0,0 @@
/* MAPIStoreViewsContext.m - this file is part of SOGo
*
* Copyright (C) 2010 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 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 <Foundation/NSString.h>
#import "MAPIStoreMapping.h"
#import "MAPIStoreViewsContext.h"
@implementation MAPIStoreViewsContext
+ (NSString *) MAPIModuleName
{
return @"views";
}
@end

View File

@ -106,6 +106,7 @@ static int MAPIStoreTallocWrapperDestroy (void *data)
*data = [(NSCalendarDate * ) self asFileTimeInMemCtx: memCtx];
break;
case PT_BINARY:
case PT_SVREID:
*data = [(NSData *) self asBinaryInMemCtx: memCtx];
break;
case PT_CLSID:

View File

@ -96,7 +96,7 @@ static NSString *privateDir = nil;
- (id) initWithURL: (NSURL *) url
andTableType: (uint8_t) tableType
{
NSString *path, *tableParticle;
NSString *path, *username, *tableParticle;
if ((self = [self init]))
{
@ -116,9 +116,11 @@ static NSString *privateDir = nil;
path = [url path];
if (![path hasSuffix: @"/"])
path = [NSString stringWithFormat: @"%@/", path];
username = [url user];
directory = [NSString stringWithFormat: @"%@/mapistore/SOGo/%@/%@/%@%@",
privateDir, [url user], tableParticle,
privateDir, username, tableParticle,
[url host], path];
[self setOwner: username];
[self logWithFormat: @"directory: %@", directory];
[directory retain];
ASSIGN (nameInContainer, [path stringByDeletingLastPathComponent]);
@ -312,6 +314,23 @@ static NSString *privateDir = nil;
return [self _fileAttributeForKey: NSFileModificationDate];
}
- (NSException *) delete
{
NSFileManager *fm;
NSException *error;
fm = [NSFileManager defaultManager];
if (![fm removeFileAtPath: directory handler: NULL])
error = [NSException exceptionWithName: @"MAPIStoreIOException"
reason: @"could not delete folder"
userInfo: nil];
else
error = nil;
return error;
}
/* acl */
- (NSString *) defaultUserID
{

View File

@ -141,14 +141,18 @@
- (NSException *) delete
{
NSFileManager *fm;
NSException *error;
fm = [NSFileManager defaultManager];
if (![fm removeFileAtPath: [self completeFilename] handler: NULL])
[NSException raise: @"MAPIStoreIOException"
format: @"could not delete message"];
error = [NSException exceptionWithName: @"MAPIStoreIOException"
reason: @"could not delete message"
userInfo: nil];
else
error = nil;
return nil;
return error;
}
- (id) _fileAttributeForKey: (NSString *) key

View File

@ -460,8 +460,6 @@ _orderedValuesAreVoid (NSArray *orderedValues)
NSMutableArray *orderedValues;
NSUInteger count, max;
result = YES;
keys = [values allKeys];
max = [keys count];
for (count = 0; result && count < max; count++)

View File

@ -46,12 +46,15 @@
- (CardElement *) uniqueChildWithTag: (NSString *) aTag;
- (void) setUniqueChild: (CardElement *) aChild;
- (NSMutableArray *) children;
- (void) addChild: (CardElement *) aChild;
- (void) addChildren: (NSArray *) someChildren;
- (void) removeChild: (CardElement *) aChild;
- (void) removeChildren: (NSArray *) someChildren;
- (NSMutableArray *) children;
- (void) cleanupEmptyChildren;
- (CardElement *) firstChildWithTag: (NSString *) aTag;
- (NSArray *) childrenWithTag: (NSString *) aTag;
- (NSArray *) childrenWithAttribute: (NSString *) anAttribute

View File

@ -142,6 +142,19 @@ static NGCardsSaxHandler *sax = nil;
return nil;
}
- (BOOL) isVoid
{
BOOL isVoid = YES;
NSUInteger count, max;
max = [children count];
for (count = 0; isVoid && count < max; count++)
if (![[children objectAtIndex: count] isVoid])
isVoid = NO;
return isVoid;
}
- (void) addChild: (CardElement *) aChild
{
Class mappedClass;
@ -366,6 +379,23 @@ static NGCardsSaxHandler *sax = nil;
[self addChild: newChild];
}
- (void) cleanupEmptyChildren
{
NSUInteger max;
NSInteger count;
CardElement *child;
max = [children count];
for (count = max - 1; count > -1; count--)
{
child = [children objectAtIndex: count];
if ([child isKindOfClass: [CardGroup class]])
[(CardGroup *) child cleanupEmptyChildren];
if ([child isVoid])
[children removeObjectAtIndex: count];
}
}
- (NSString *) description
{
NSMutableString *str;

View File

@ -8,6 +8,14 @@
* NSString+NGCards.m (-vCardSubvalues): fixed allocation of
parsing buffer to avoid a buffer overflow.
2011-12-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* NGVCard.m (-initWithUid:): initialize "CLASS" and "PROFILE".
* CardGroup.m (-isVoid): overriden method.
(-cleanupEmptyChildren): make use of "isVoid" to detect and remove
empty children.
2011-11-21 Francis Lachapelle <flachapelle@inverse.ca>
* iCalTimeZone.m (+knownTimeZoneNames): ignore files that don't

View File

@ -50,6 +50,8 @@
[self setTag: @"vcard"];
[self setUid: _uid];
[self setVersion: @"3.0"];
[self setVClass: @"PUBLIC"];
[self setProfile: @"VCARD"];
}
return self;

View File

@ -2617,11 +2617,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return @"Appointment";
}
- (NSString *) outlookFolderClass
{
return @"IPF.Appointment";
}
- (BOOL) isActive
{
SOGoUserSettings *settings;

View File

@ -26,6 +26,7 @@
#import <SOGo/SOGoParentFolder.h>
@class NSArray;
@class NSMutableArray;
@class SOGoWebAppointmentFolder;

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 \

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

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 */

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;

View File

@ -1,4 +1,4 @@
/* MAPIStoreSpoolerContext.h - this file is part of SOGo
/* NSDictionary+LDIF.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
@ -6,7 +6,7 @@
*
* 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)
* 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,
@ -20,13 +20,15 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTORESPOOLERCONTEXT_H
#define MAPISTORESPOOLERCONTEXT_H
#ifndef NSDICTIONARY_LDIF_H
#define NSDICTIONARY_LDIF_H
#import "MAPIStoreFSBaseContext.h"
#import <Foundation/NSDictionary.h>
@interface MAPIStoreSpoolerContext : MAPIStoreFSBaseContext
@interface NSDictionary (SOGoLDIF)
- (NSString *) ldifRecordAsString;
@end
#endif /* MAPISTORESPOOLERCONTEXT_H */
#endif /* NSDICTIONARY_LDIF_H */

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

View File

@ -1,4 +1,4 @@
/* MAPIStoreSpoolerContext.m - this file is part of SOGo
/* NSString+LDIF.h - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc
*
@ -6,7 +6,7 @@
*
* 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)
* 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,
@ -20,15 +20,15 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef NSSTRING_LDIF_H
#define NSSTRING_LDIF_H
#import <Foundation/NSString.h>
#import "MAPIStoreSpoolerContext.h"
@interface NSString (SOGoLDIF)
@implementation MAPIStoreSpoolerContext
+ (NSString *) MAPIModuleName
{
return @"spooler-queue";
}
- (BOOL) mustEncodeLDIFValue;
@end
#endif /* NSSTRING_LDIF_H */

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

View File

@ -30,11 +30,6 @@
int photoID;
}
+ (id) entryPhotoWithID: (int) photoId
inContainer: (id) container;
- (void) setPhotoID: (int) newPhotoID;
- (NSString *) davContentType;
@end

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

View File

@ -27,6 +27,10 @@
@interface SOGoContactFolders : SOGoParentFolder
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
withDisplayName: (NSString *) newDisplayName;
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
@end
#endif /* SOGOCONTACTFOLDERS_H */

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
{

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

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
{

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

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 */

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

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

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

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

View File

@ -86,6 +86,8 @@
- (NSException *) expunge;
- (NSException *) renameTo: (NSString *) newName;
- (NSCalendarDate *) mostRecentMessageDate;
/* flags */
@ -94,8 +96,6 @@
/* folder type */
- (NSString *) outlookFolderClass;
- (NSArray *) subfolders;
- (BOOL) isSpecialFolder;

View File

@ -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
{
@ -889,32 +936,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

View File

@ -25,10 +25,4 @@
@implementation SOGoSentFolder
/* folder type */
- (NSString *)outlookFolderClass {
return @"IPF.Sent";
}
@end /* SOGoSentFolder */

View File

@ -25,10 +25,4 @@
@implementation SOGoTrashFolder
/* folder type */
- (NSString *)outlookFolderClass {
return @"IPF.Trash";
}
@end /* SOGoTrashFolder */

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 \

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

View File

@ -1,12 +1,12 @@
/* MAPIStoreFreebusyContext.m - this file is part of SOGo
/* LDAPSourceSchema.h - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
* 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 3, or (at your option)
* 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,
@ -20,21 +20,26 @@
* Boston, MA 02111-1307, USA.
*/
#import <NGObjWeb/WOContext+SoObjects.h>
#ifndef LDAPSOURCESCHEMA_H
#define LDAPSOURCESCHEMA_H
#import <SOGo/SOGoUserFolder.h>
#import <Foundation/NSObject.h>
#import "MAPIApplication.h"
#import "MAPIStoreAuthenticator.h"
#import "MAPIStoreMapping.h"
@class NSMutableDictionary;
@class NGLdapConnection;
#import "MAPIStoreFreebusyContext.h"
@implementation MAPIStoreFreebusyContext
+ (NSString *) MAPIModuleName
@interface LDAPSourceSchema : NSObject
{
return @"freebusy";
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 */

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

View File

@ -35,8 +35,7 @@
- (NSString *) jsonRepresentation;
- (NSString *) keysWithFormat: (NSString *) keyFormat;
// LDIF methods
- (NSString *) userRecordAsLDIFEntry;
- (NSComparisonResult) caseInsensitiveDisplayNameCompare: (NSDictionary *) theDictionary;
@end

Some files were not shown because too many files have changed in this diff Show More