Compare commits

...
89 Commits
Author SHA1 Message Date
Ludovic Marcotte 6f2eae5d67 Bump version to 2.3.2 2015-09-16 14:37:56 -04:00
Ludovic Marcotte 9a7ea26b80 Update ChangeLog 2015-09-16 13:45:28 -04:00
Ludovic Marcotte 38c9a229c0 Update for the release 2015-09-16 13:44:59 -04:00
Francis Lachapelle e75ec09445 Update NEWS file 2015-09-16 13:31:48 -04:00
Francis Lachapelle 58d03eedc3 Update CKEditor to version 4.5.3 2015-09-16 13:29:37 -04:00
Francis Lachapelle 98ad8f1c0b Update NEWS file 2015-09-16 11:52:46 -04:00
Francis Lachapelle 37b817cd68 Fix options availability in Contacts module cont'd 2015-09-16 11:43:22 -04:00
Francis Lachapelle 9fd8f3edef Add verbose output to "sogo-tool remove" command 2015-09-16 11:39:05 -04:00
Ludovic Marcotte ce11aca2bd (fix) update the doc regarding the temporarily dropping rhel/old debian/ubuntu support 2015-09-16 09:44:29 -04:00
Francis Lachapelle 861057f22f Fix options availability in Contacts module
A user can edit/delete a card from a system addressbook if included in
the "modifiers". Enable the delete/move options of the contextual menu
in this case.
Fixes #3342
2015-09-16 09:38:52 -04:00
Francis Lachapelle b910501afa Fix localization of calendar categories
Fixes #3295
2015-09-15 15:59:31 -04:00
extrafu 063f878199 Merge pull request #103 from zentyal/master
Fixes for OpenChange integration
2015-09-14 12:55:03 -04:00
Ludovic Marcotte 6bccd2eea0 (fix) improve spec file regarding disabling OC build 2015-09-14 11:06:54 -04:00
Ludovic Marcotte 652ae763d4 (fix) Start/end shifting by 1 hour due to timezone change on last Sunday of October 2015 (#3344) 2015-09-14 10:55:50 -04:00
Jesús García Sáez 3da6c90bbe Merge pull request #182 from zentyal/ejhernandez/save-tasks
oc-task: Save tasks from Outlook
2015-09-14 12:24:01 +02:00
Enrique J. Hernández 21a6480834 Merge pull request #181 from zentyal/jvalles/underscore-folders
Improve first character check in CSS identifiers
2015-09-14 11:38:26 +02:00
Ludovic Marcotte 42f10e1929 (fix) safe-guard against not-yet-created calendar of local users 2015-09-10 20:07:42 -04:00
Ludovic Marcotte 03b706e1d8 (fix) disable oc builds on el6 for now 2015-09-10 19:44:45 -04:00
Ludovic Marcotte 2be556299e (fix) slight modification for fix #3293 2015-09-10 19:10:50 -04:00
Enrique J. Hernández Blasco b075a306c6 oc-task: Save tasks from Outlook
It was not working because we try to save as component the
full calendar and its parent was nil. We have to save the calendar
itself to save the task in the personal calendar.
2015-09-10 17:26:41 +02:00
Juan Vallés 36d8fa12d3 Improve first character check in CSS identifiers
A CSS identifier can't start with a digit, so when a folder name does,
a '_' character is appended at the beginning of its CSS identifier.

The check for this first character used the `isdigit()` function, which
takes a `char` argument, while `[self objectAtIndex: 0]` returns a
`unichar`, i.e. a 16-bit unsigned integer. This caused some non-digit
characters to pass this check (e.g. Chinese characters), ending up with
an underscore at the beginning of the folder name.
2015-09-10 10:24:50 +02:00
Ludovic Marcotte 07092828fe (fix) improved EAS speed during initial syncing of large mailboxes (#3293) 2015-09-09 10:20:31 -04:00
Ludovic Marcotte 7c0ba7b72b (fix) avoid too-many LIST commands over EAS (#3294) 2015-09-09 10:12:32 -04:00
Ludovic Marcotte 750a629df8 Updated NEWS file regarding PR#102 2015-09-09 08:24:59 -04:00
extrafu 33a1d2c397 Merge pull request #102 from zentyal/master
Changes for sogo-openchange from Zentyal
2015-09-09 08:19:14 -04:00
Enrique J. Hernández 2e75972df6 Merge pull request #177 from zentyal/jag/remove-compile-warnings
Fix some compilation warnings
2015-09-09 10:15:40 +02:00
Javier Amor García 1fdb44b0a7 Fix some compilation warnings
The warnings were introduced in the fix for attachment with used
the filename extended parameter.

Also removed trailing whitespaces.
2015-09-08 15:39:59 +02:00
Jesús García Sáez 3868ce0fb1 Merge pull request #169 from zentyal/ejhernandez/increase-cn-setting-seen-flag
oc-mail: Increase Change Number after modifying seen flag
2015-09-07 18:46:18 +02:00
Jesús García Sáez fc82eb79f6 Merge pull request #175 from zentyal/ejhernandez/versions-msg-reload-if-needed
oc: load versionsMessage on setting up
2015-09-07 16:48:55 +02:00
Jesús García Sáez 9425868365 Merge pull request #176 from zentyal/ejhernandez/set-read-flag-db
Implement setReadFlag for MAPIStoreDBMessage
2015-09-07 16:35:30 +02:00
Enrique J. Hernández Blasco 6280e4ded6 oc: Implement setReadFlag for MAPIStoreDBMessage
This is an utility for testing as I don't see any added value
for real scenario but according to [MS-OXCMSG] all messages
can have PidTagMessageFlags.
2015-09-04 16:16:00 +02:00
Enrique J. Hernández Blasco f19074334c oc: Use enum mapistore_error as returned value for setReadFlag 2015-09-04 16:15:05 +02:00
Enrique J. Hernández Blasco b702e40ebb oc: load versionsMessage on setting up
versionsMessage object could have outdated version in a root folder
in the following case:

* Download latest contents using FXBuffer
  * versionsMessage is updated by synchroniseCache
* OpenMessage from last FXBuffer
  * Setup versions message as root folder
* Get Predecessor Change List from that message

We could just reload if needed the versions message if something
is missing but I don't know if that situation fixes more than this
one.
2015-09-03 23:01:21 +02:00
Enrique J. Hernández 190f27ed7c Merge pull request #174 from zentyal/jag/test-quote-mime-header-value
Test for [NGMimeMessageGenerator generateDataForHeaderField:value:]
2015-09-01 16:15:23 +02:00
Javier Amor García cbc3e3e97d Test for [NGMimeMessageGenerator generateDataForHeaderField:value:]
The NGMimeMessageGenerator can be found in sope
2015-09-01 09:09:54 +02:00
Javier Amor García 361d5ea3a6 Added method [SOGoTest stringFromDiffBetween:and:] 2015-09-01 09:09:54 +02:00
Jesús García Sáez 24e3071e24 Merge pull request #170 from zentyal/jag/attachments-nolatin-filename
sogo-openchange: Support attachments with filename extended parameter
2015-08-26 15:15:15 +02:00
Jesús García Sáez 1f29198495 Merge pull request #172 from zentyal/ejhernandez/save-draft-right-change-key
oc-mail: Return right change key after saving a draft mail
2015-08-26 13:37:42 +02:00
Jesús García Sáez 916442f9cf Merge pull request #171 from zentyal/ejhernandez/restriction-cn-ge
oc-mail: Implement ChangeNumber >= restriction
2015-08-25 13:17:20 +02:00
Enrique J. Hernández Blasco 47859b76d6 oc-mail: Return right change key after saving a draft mail
After saving a draft mail (this is done automatically by Outlook)
a GetProps call is done checking the PidTagChangeKey has been
updated properly. Without this patch, it returned MAPI_E_NOT_FOUND.

With this patch, we addressed that problem and we have updated
the Predecessor Change List metadata for the draft mail with the
change key provided by the client to avoid conflicting messages
whenever it is possible.
2015-08-24 23:42:38 +02:00
Enrique J. Hernández Blasco 3a60b6e38e oc-mail: Implement ChangeNumber >= restriction
And warn when other operator than > or >= is used.

This allows OpenChange to query for change numbers starting from
a given point.
2015-08-24 15:39:05 +02:00
Javier Amor García ae3ac0a09a oc-mail: Support attachments with filename extended parameter
The attachments which used a extended parameter for their filename
('filename*=') where silently dropped.
This was because MAPIStore was only looking for no-extended filename
parameter.
The solution is using the 'filename' from the
SOGOExtension of the NSDictionary interface.
2015-08-24 14:19:47 +02:00
Ludovic Marcotte 27a19ac956 (fix) Session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less 2015-08-21 10:30:47 -04:00
Enrique J. Hernández Blasco 27b9b7bfa7 oc-mail: Increase Change Number after modifying seen flag
It is required when you are using SynchronizeImportReadStateChanges ROP
to update the MetaTagCnsetRead meta property.

See [MS-OXCFXICS] Section 3.2.5.9.4.6

This could lead to sync issues.
2015-08-10 18:38:39 +02:00
Julio J. García Martín 18f758cb0a Merge pull request #159 from Zentyal/ejhernandez/fixes-on-move
Maintain PidTagPredecessorChangeList with client's data
2015-08-04 18:13:19 +02:00
Enrique J. Hernández Blasco 321672e2c3 oc: Update predecessor change list on saving
There were cases where only the change key was updated (GCS) or
others were the change key was updated with wrong info.

This changeset has as goal to update the predecessor change list
and, change key if required, on saving taking into account the latest information
given by the client in high level ROPs such as ImportMessageMove
or SetProperties, and merge it with information provided by the server
backend (IMAP server, SOGo DB) using `synchroniseCache`.

For more details about `PidTagChangeKey` and `PidTagPredecessorChangeList`
property values check [MS-OXCFXICS] Section 2.2.1.2
2015-08-04 08:41:38 +02:00
Enrique J. Hernández Blasco 8d9b54815c oc: Receive new predecessor change list parameter on move copy op
This is to apply new API introduced by 85e2d7c commit in OpenChange
repository.
2015-08-04 08:41:38 +02:00
Enrique J. Hernández Blasco 1dbfc18379 oc: Update to new XID structure definition
From ede986f commit from OpenChange repository.
2015-08-04 08:41:38 +02:00
Ludovic Marcotte 05b330e11b (fix) added changes from PR94 to avoid big merge conflicts 2015-08-03 11:06:30 -04:00
Luc Charland 307876e6c7 cleaned up a few comments 2015-08-03 11:01:33 -04:00
Luc Charland ac6b299988 removed double Name translation in 5 languages 2015-08-03 10:13:23 -04:00
Ludovic Marcotte 234db671ad Removed merged in templates from v3 2015-08-03 10:12:40 -04:00
Luc Charland 2d33b01f31 Removing colons
Conflicts:

	UI/Templates/ContactsUI/UIxContactEditorTemplate.wox
	UI/Templates/ContactsUI/UIxContactFolderLinksTemplate.wox
	UI/Templates/MailerUI/UIxMailMainFrame.wox
	UI/Templates/MainUI/SOGoRootPage.wox
	UI/Templates/PreferencesUI/UIxAccountEditor.wox
	UI/Templates/PreferencesUI/UIxPreferences.wox
	UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox
	UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox
	UI/Templates/SchedulerUI/UIxCalMainView.wox
	UI/Templates/SchedulerUI/UIxCalendarFolderLinksTemplate.wox
	UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox
	UI/Templates/SchedulerUI/UIxTaskViewTemplate.wox
	UI/WebServerResources/angular-material
2015-08-03 10:12:02 -04:00
Luc Charland 490354427d fixed Appointments path 2015-08-03 09:56:14 -04:00
Luc Charland 22ce38808a cleaned up a few comments 2015-08-03 09:55:52 -04:00
Luc Charland 82aca2cfe5 added first draft of verify_translation 2015-08-03 09:55:17 -04:00
Ludovic Marcotte b17488ff25 Updated NEWS file regarding PR93 2015-08-03 09:18:20 -04:00
extrafu ff3557598f Merge pull request #93 from Zentyal/jjgarcia/contribute-back
Changes for sogo-openchange from Zentyal
2015-08-03 09:13:55 -04:00
Julio García 26bd1b30fa Revert "Merge pull request #164 from Zentyal/jgarcia/revert-merge-inverse"
This reverts commit 1404dbdb88, reversing
changes made to 72cbd9a45f.
2015-08-03 09:48:06 +02:00
Enrique J. Hernández 0ce04fd4b6 Merge pull request #165 from Zentyal/jgarcia/uids_login_party_hard
SOGoUser bad initialization on multidomain environment
2015-07-31 18:46:15 +02:00
Jesús García Sáez f3656f7571 Merge pull request #166 from Zentyal/ejhernandez/update-cn-setting-folder-props
oc: Update ChangeNumber after setting folder properties
2015-07-30 14:49:56 +02:00
Enrique J. Hernández Blasco 2aba083147 oc: Update ChangeNumber after setting folder properties
As required by operations like SynchronizationImportHierarchyChanges
a new change number must be generated when a change in a folder
is set. This affects to subfolders.

See [MS-OXCFXICS] Section 3.2.5.9.4.3 for details.
2015-07-30 10:07:55 +02:00
Jesús García Sáez 9414df26c5 getUIDForEmail works on multidomain: returns login
This method is used everywhere to try to retrieve the login of the user
(and normally use the return value to [SOGoUser initwithLogin: ...])

In multidomain environments (with DomainLessLogin = false) there were
several paths (mostly in SOGoAppointmentObject.m) that were trying to
create SOGoUser objects with incorrect login: using only the uid part,
not full email. Then like domain based uid was enabled, these users
had DomainLessLogin set to true and further calls tried to authenticate
only with the uid part (and they should not).

This affects to several methods in:

  * ActiveSync/SOGoActiveSyncDispatcher.m
  * Appointments/SOGoAppointmentFolder.m
  * Appointments/SOGoAppointmentObject.m
  * Appointments/SOGoCalendarComponent.m
  * SOGoSAML2Session.m

Probably a few features related with calendars are now fixed or working
as intended in multidomain environments where the email is used as login
2015-07-29 17:40:56 +02:00
Jesús García Sáez 7496b92da5 Merge pull request #158 from Zentyal/jag/mapistorefolder-getpidtagdisplayname
oc-mail: Added [MAPIStoreFolder getPidTagDisplayName:inMemCtx:]
2015-07-28 18:08:20 +02:00
Jesús García Sáez e38b0ac64f Merge pull request #163 from Zentyal/ejhernandez/subject-fallback
oc-mail: Fallback to PidTagSubject unicode when creating new mail
2015-07-28 17:16:11 +02:00
Julio J. García Martín 1404dbdb88 Merge pull request #164 from Zentyal/jgarcia/revert-merge-inverse
Revert merge from inverse
2015-07-28 12:57:31 +02:00
Jesús García Sáez 3dc8cc78ea Revert merge from inverse
https://github.com/Zentyal/sogo/pull/150

Because the login on web with the use of outlook is broken after
including the DomainLessLogin feature
2015-07-28 12:37:33 +02:00
Jesús García Sáez 72cbd9a45f Merge pull request #162 from Zentyal/ejhernandez/fix-compilation-warn
oc: Fix compilation warning in MAPIStoreContext
2015-07-27 13:41:36 +02:00
Enrique J. Hernández Blasco 10ac445f7c oc-mail: Fallback to PidTagSubject unicode when creating new mail
Some clients such as OpenChange client does not send the following
properties PidTagNormalizedSubject or PidTagSubjectPrefix as
suggested by [MS-OXCMAIL].
2015-07-27 11:18:14 +02:00
Enrique J. Hernández Blasco c5b5a4243d oc: Fix compilation warning in MAPIStoreContext 2015-07-25 09:56:21 +02:00
Ludovic Marcotte 304ffa2099 (fix) SOGoMaximumMessageSubmissionCount should be independant from SOGoMaximumRecipientCount 2015-07-24 11:19:57 -04:00
Francis Lachapelle e4ad255fc2 (fix) chmod 644 UI/MainUI/Slovenian.lproj/Locale 2015-07-23 14:09:27 -04:00
Francis Lachapelle 390a853471 (fix) Display of whitelisted attendees in Firefox
Fixes #3285
2015-07-23 14:07:34 -04:00
Enrique J. Hernández 372247a643 Merge pull request #160 from Zentyal/jgarcia/useless-indexing
oc: remove useless mapistore_indexing call
2015-07-23 08:58:36 +02:00
Jesús García Sáez 7bde181d3f oc: check ret value get_new_folderID
On [MAPIStoreContext idForObjectWithKey: key inFolderUrl: url] check the ret value
of mapistore_indexing_get_new_folderID. This should never happen (oh my...) but
if this happens it will be reported
2015-07-21 19:47:17 +02:00
Jesús García Sáez 1336a1d5a8 oc: remove useless mapistore_indexing call
[mapping registerURL ...] will insert the mappingId in indexing database
there is no need to call, again, mapistore_indexing_record_add_mid
2015-07-21 19:47:17 +02:00
Enrique J. Hernández cf606e3224 Merge pull request #157 from Zentyal/jgarcia/wocontext_broken_like_hell
Fix sharing imap connections between different clients
2015-07-21 18:38:09 +02:00
Jesús García Sáez c9f2fe2f85 oc-folder: user context activation on rootFolders
Several fixes related with userContext activation
2015-07-21 11:08:03 +02:00
Jesús García Sáez 10bc15d41d oc-folder: activate user context when needed
Before creating sogo objects
2015-07-21 11:08:02 +02:00
Jesús García Sáez 393b6d5128 oc-folder: simplify lookupFolder method
use activate and no need to set wocontext, it's already set properly
2015-07-21 11:08:02 +02:00
Jesús García Sáez 68ae978b13 oc-mail: activate user context needed
Before creating new sogo objects
2015-07-21 11:08:02 +02:00
Jesús García Sáez f4e3b98042 Nothing changed: format and hoarding code removed 2015-07-21 11:08:02 +02:00
Jesús García Sáez cfab18e1b8 oc: activate user context on initialization 2015-07-21 11:08:02 +02:00
Javier Amor García 959b4e015d [SOgoMailFolder displayName] decodes IMAP4 2015-07-20 15:19:43 +02:00
Javier Amor García 2ce85f6c5c oc-mail: Added [MAPIStoreFolder getPidTagDisplayName:inMemCtx:]
This getter is necessary to decode folder names
in utf7 encoding.
2015-07-17 18:23:40 +02:00
Jesús García Sáez 7d2f96e96b oc: use activate instead of activateWithUser
100% of the times the user is the one that MAPIStoreUserContext
already has, so no need to have it as an argument.
2015-07-15 11:26:05 +02:00
Jesús García Sáez 3bf7afdfb7 oc: remove and disable userContext after each call
This adds [MAPIStoreUserContext activate] method to use
it instead of activateWithUser.

A cleanup operation is executed after each public function
so there won't be any conflicts with future calls.

In practice, this will deactivate the current user context set on
MAPIApp, this means two things: (1) set nil as current user context
on MAPIApp and (2) remove woContext from current thread dictionary
2015-07-15 11:25:45 +02:00
Jesús García Sáez 503a70118f oc: remove tabs and unused code 2015-07-14 19:19:58 +02:00
Jesús García Sáez 928b6b596e oc: OC_DEBUG inside macros
These macros are used before and after every performed
operation
2015-07-14 19:19:51 +02:00
239 changed files with 5119 additions and 3182 deletions

No files matched your search

+46 -9
View File
@@ -133,6 +133,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
[[o properties] addEntriesFromDictionary: values];
[o save];
@@ -159,7 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSString *nameInCache;
if (theFolderType == ActiveSyncMailFolder)
nameInCache= [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]];
nameInCache = [imapFolderGUIDS objectForKey: [theCollection nameInContainer]];
else
{
NSString *component_name;
@@ -170,7 +171,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
component_name = @"vtodo";
nameInCache= [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]];
nameInCache = [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]];
}
return nameInCache;
@@ -673,7 +674,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSDictionary *component;
NSArray *allComponents;
BOOL updated;
BOOL updated, initialLoadInProgress;
int deleted, return_count;
if (theFolderType == ActiveSyncContactFolder)
@@ -683,7 +684,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
component_name = @"vtodo";
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
initialLoadInProgress = NO;
if ([theSyncKey isEqualToString: @"-1"])
[folderMetadata setObject: davCollectionTagToStore forKey: @"InitialLoadSequence"];
if ([folderMetadata objectForKey: @"InitialLoadSequence"])
{
if ([theSyncKey intValue] < [[folderMetadata objectForKey: @"InitialLoadSequence"] intValue])
initialLoadInProgress = YES;
else
[folderMetadata removeObjectForKey: @"InitialLoadSequence"];
}
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType initialLoad: initialLoadInProgress];
allComponents = [allComponents sortedArrayUsingDescriptors: [NSArray arrayWithObjects: [[NSSortDescriptor alloc] initWithKey: @"c_lastmodified" ascending:YES], nil]];
@@ -847,12 +861,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSMutableArray *allCacheObjects, *sortedBySequence;
SOGoMailObject *mailObject;
NSArray *allMessages;
NSArray *allMessages, *a;
int j, k, return_count;
BOOL found_in_cache;
int j, k, return_count, highestmodseq;
BOOL found_in_cache, initialLoadInProgress;
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
initialLoadInProgress = NO;
if ([theSyncKey isEqualToString: @"-1"])
{
highestmodseq = 0;
a = [[theCollection davCollectionTag] componentsSeparatedByString: @"-"];
[folderMetadata setObject: [a objectAtIndex: 1] forKey: @"InitialLoadSequence"];
}
else
{
a = [theSyncKey componentsSeparatedByString: @"-"];
highestmodseq = [[a objectAtIndex: 1] intValue];
}
if ([folderMetadata objectForKey: @"InitialLoadSequence"])
{
if (highestmodseq < [[folderMetadata objectForKey: @"InitialLoadSequence"] intValue])
initialLoadInProgress = YES;
else
[folderMetadata removeObjectForKey: @"InitialLoadSequence"];
}
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType initialLoad: initialLoadInProgress];
max = [allMessages count];
allCacheObjects = [NSMutableArray array];
@@ -911,7 +948,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSString *lastSequence;
more_available = YES;
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? [NSString stringWithFormat:@"%d", highestmodseq] : [aCacheObject sequence]);
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
DESTROY(pool);
+1
View File
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@interface SOGoActiveSyncDispatcher : NSObject
{
NSURL *folderTableURL;
NSDictionary *imapFolderGUIDS;
id context;
}
+20 -11
View File
@@ -151,12 +151,14 @@ static BOOL debugOn = NO;
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
folderTableURL = nil;
imapFolderGUIDS = nil;
return self;
}
- (void) dealloc
{
RELEASE(folderTableURL);
RELEASE(imapFolderGUIDS);
[super dealloc];
}
@@ -229,23 +231,27 @@ static BOOL debugOn = NO;
SOGoMailAccounts *accountsFolder;
SOGoMailAccount *accountFolder;
SOGoUserFolder *userFolder;
NSDictionary *imapGUIDs;
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
// Get the GUID of the IMAP folder
imapGUIDs = [accountFolder imapFolderGUIDs];
//return [[imapGUIDs allKeysForObject: theIdToTranslate] objectAtIndex: 0];
return [[[imapGUIDs allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
if (!imapFolderGUIDS)
{
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
// Get the GUID of the IMAP folder
imapFolderGUIDS = [accountFolder imapFolderGUIDs];
[imapFolderGUIDS retain];
}
return [[[imapFolderGUIDS allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
}
return theIdToTranslate;
}
//
//
//
@@ -938,6 +944,7 @@ static BOOL debugOn = NO;
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
[o save];
command_count++;
@@ -1023,6 +1030,7 @@ static BOOL debugOn = NO;
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
}
[o save];
@@ -1046,6 +1054,7 @@ static BOOL debugOn = NO;
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
}
[o save];
@@ -1204,7 +1213,7 @@ static BOOL debugOn = NO;
filter = [NSCalendarDate dateFromFilterType: [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"FilterType"] lastObject] textValue]];
syncKey = [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"SyncKey"] lastObject] textValue];
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter];
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter initialLoad: NO];
count = [allMessages count];
+1103
View File
File diff suppressed because it is too large. Load diff
@@ -233,6 +233,7 @@ Installation
This section will guide you through the installation of the native
Microsoft Outlook compatibility layer SOGo offers.
////
Red Hat Enterprise Linux v6 x86_64
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -316,7 +317,7 @@ from this guide.
On Ubuntu 12.04, the Samba init scripts need to be modified to
disable the upstart check. For more details, refer to:
https://wiki.samba.org/index.php/Samba4/InitScript
////
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -395,7 +396,7 @@ samba-tool user setexpiry administrator --noexpiry
----
You might consider changing the realm and domain used, to suit your
enviroment.
environment.
You might also have to
remove `/etc/samba/smb.conf` prior running this command.
@@ -441,7 +442,7 @@ Your Samba 4 configuration file should look like this:
OpenChange Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
Since v2.2, OpenChange stores its metadata in MySQL so you need to have it installed.
First, create the OpenChange MySQL user:
@@ -512,9 +513,11 @@ mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/op
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
----
////
On RHEL, make sure SELinux is disabled:
setenforce 0
////
Next, you can start Samba using the usual command:
@@ -545,9 +548,11 @@ This service runs as a WSGI application under apache (mod_wsgi).
While HTTPS is not required to access this service, it is strongly
recommended.
////
On RHEL-based distributions, the apache configuration required by these
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
`/etc/httpd/conf.d/rpcproxy.conf`.
////
For Debian-based distributions, these files can be found
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
@@ -563,8 +568,10 @@ The OCS Manager and RPC Proxy configuration module can be enabled using:
a2enconf ocsmanager
a2enconf rpcproxy
////
On RHEL-based distributions, make sure the `LoadModule` directive is
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
////
The _reqtimeout_ apache module is known to cause problems when using the
default configuration shipped with Debian-based systems. On such
@@ -580,10 +587,12 @@ To avoid this problem, use a much higher timeout or disable the module:
a2dismod reqtimeout
You should now restart the Apache service and make sure it will start on
boot. On RHEL-based distributions, do:
boot.
////
On RHEL-based distributions, do:
chkconfig httpd on && /etc/init.d/httpd restart
////
On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
@@ -813,7 +822,7 @@ the `openchange_user_cleanup` script distributed with SOGo. The script
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
RHEL).
To reset a user, run the script as root:
`python openchange_user_cleanup username`. See the usage output for additional options.
`openchange_user_cleanup username`. See the usage output for additional options.
* The "Out of Office Assistant" will not currently work. This feature
has not been implemented.
* Creating folders below INBOX (when not normally permitted by the IMAP
+3 -3
View File
@@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.3.1 - July 2015</releaseinfo>
<subtitle>for version 2.3.1</subtitle>
<date>2015-07-23</date>
<releaseinfo>Version 2.3.2 - September 2015</releaseinfo>
<subtitle>for version 2.3.</subtitle>
<date>2015-09-16</date>
<legalnotice>
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
@@ -13,6 +13,6 @@
// TODO have the build system take care of this
:release_version: 2.3.1
:release_version: 2.3.2
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+24
View File
@@ -1,3 +1,27 @@
2.3.2 (2015-09-16)
------------------
Enhancements
- improved EAS speed and memory usage, avoiding many IMAP LIST commands (#3294)
- improved EAS speed during initial syncing of large mailboxes (#3293)
- updated CKEditor to version 4.5.3
Bug fixes
- fixed display of whitelisted attendees in Preferences window on Firefox (#3285)
- non-latin subfolder names are displayed correctly on Outlook (Zentyal)
- fixed several sync issues on environments with multiple users (Zentyal)
- folders from other users will no longer appear on your Outlook (Zentyal)
- use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
- session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less
- less sync issues when setting read flag (Zentyal)
- attachments with non-latin filenames sent by Outlook are now received (Zentyal)
- support attachments from more mail clients (Zentyal)
- avoid conflicting message on saving a draft mail (Zentyal)
- less conflicting messages in Outlook while moving messages between folders (Zentyal)
- start/end shifting by 1 hour due to timezone change on last Sunday of October 2015 (#3344)
- fixed localization of calendar categories with empty profile (#3295)
- fixed options availability in contextual menu of Contacts module (#3342)
2.3.1 (2015-07-23)
------------------
+2 -1
View File
@@ -33,8 +33,9 @@
}
- (id) authenticatorInContext: (id) context;
- (MAPIStoreUserContext *) userContext;
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
- (void) cleanup;
@end
+10
View File
@@ -76,6 +76,11 @@ MAPIApplication *MAPIApp = nil;
return NO;
}
- (MAPIStoreUserContext *) userContext
{
return userContext;
}
- (void) setUserContext: (MAPIStoreUserContext *) newContext
{
/* user contexts must not be retained here ad their holder (mapistore)
@@ -88,4 +93,9 @@ MAPIApplication *MAPIApp = nil;
return [userContext authenticator];
}
- (void) cleanup
{
[userContext deactivate];
}
@end
+1 -5
View File
@@ -63,19 +63,15 @@
SOGoAppointmentObject *newEntry;
NSString *name;
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
[[self userContext] activate];
name = [NSString stringWithFormat: @"%@.ics",
[SOGoObject globallyUniqueObjectId]];
newEntry = [SOGoAppointmentObject objectWithName: name
inContainer: sogoObject];
[newEntry setIsNew: YES];
/* the WOContext is required here for resolving notification pages */
[newEntry setContext: [[self userContext] woContext]];
newMessage = [MAPIStoreCalendarMessage mapiStoreObjectWithSOGoObject: newEntry
inContainer: self];
return newMessage;
}
+4 -3
View File
@@ -494,6 +494,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
folder = [sogoObject container];
/* reinstantiate the old sogo object and attach it to self */
[[self userContext] activate];
woContext = [[self userContext] woContext];
if (isNew)
{
@@ -577,7 +578,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
}
}
- (void) save: (TALLOC_CTX *) memCtx
- (void) save: (TALLOC_CTX *) memCtx
{
// iCalCalendar *vCalendar;
// NSCalendarDate *now;
@@ -634,7 +635,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
withActiveUser: activeUser
inMemCtx: memCtx];
[self _updateAttachedEvents];
[[self userContext] activateWithUser: activeUser];
[[self userContext] activate];
[sogoObject updateContentWithCalendar: calendar
fromRequest: nil];
[self updateVersions];
@@ -670,7 +671,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
return newAttachment;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
return MAPISTORE_SUCCESS;
}
+5 -2
View File
@@ -28,6 +28,7 @@
#import <Contacts/SOGoContactFolders.h>
#import "MAPIApplication.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreContactsContext.h"
#import "MAPIStoreContactsMessage.h"
#import "MAPIStoreContactsMessageTable.h"
@@ -58,10 +59,12 @@
SOGoContactGCSEntry *newEntry;
NSString *name;
[[self userContext] activate];
name = [NSString stringWithFormat: @"%@.vcf",
[SOGoObject globallyUniqueObjectId]];
newEntry = [SOGoContactGCSEntry objectWithName: name
inContainer: sogoObject];
inContainer: sogoObject];
[newEntry setIsNew: YES];
newMessage = [MAPIStoreContactsMessage mapiStoreObjectWithSOGoObject: newEntry
inContainer: self];
@@ -100,7 +103,7 @@
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
+28 -70
View File
@@ -33,7 +33,6 @@
#import <SOGo/SOGoUser.h>
#import "MAPIStoreAttachment.h"
// #import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreFallbackContext.h"
#import "MAPIStoreFolder.h"
#import "MAPIStoreFolderTable.h"
@@ -89,32 +88,31 @@ static NSMutableDictionary *contextClassMapping;
currentClass = [classes objectAtIndex: count];
moduleName = [currentClass MAPIModuleName];
if (moduleName)
{
[contextClassMapping setObject: currentClass
{
[contextClassMapping setObject: currentClass
forKey: moduleName];
NSLog (@" registered class '%@' as handler of '%@' contexts",
NSStringFromClass (currentClass), moduleName);
}
NSLog (@" registered class '%@' as handler of '%@' contexts",
NSStringFromClass (currentClass), moduleName);
}
}
MAPIStoreFallbackContextK = [MAPIStoreFallbackContext class];
}
+ (struct mapistore_contexts_list *) listAllContextsForUser: (NSString *) userName
withIndexing: (struct indexing_context *) indexing
withIndexing: (struct indexing_context *) indexing
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *list, *current;
NSArray *classes;
Class currentClass;
NSUInteger count, max;
MAPIStoreUserContext *userContext;
list = NULL;
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexing];
[userContext activateWithUser: [userContext sogoUser]];
// User context is activated on initialization
[MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexing];
classes = GSObjCAllSubclassesOfClass (self);
max = [classes count];
@@ -122,7 +120,7 @@ static NSMutableDictionary *contextClassMapping;
{
currentClass = [classes objectAtIndex: count];
current = [currentClass listContextsForUser: userName
withIndexing: indexing
withIndexing: indexing
inMemCtx: memCtx];
if (current)
DLIST_CONCATENATE(list, current, void);
@@ -132,7 +130,7 @@ static NSMutableDictionary *contextClassMapping;
}
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
withIndexing: (struct indexing_context *) indexing
withIndexing: (struct indexing_context *) indexing
inMemCtx: (TALLOC_CTX *) memCtx
{
return NULL;
@@ -225,8 +223,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSURL *baseURL;
int rc = MAPISTORE_ERR_NOT_FOUND;
//NSLog (@"METHOD '%s' (%d) -- uri: '%s'", __FUNCTION__, __LINE__, newUri);
context = nil;
baseURL = CompleteURLFromMapistoreURI (newUri);
@@ -298,13 +294,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
ASSIGN (userContext,
[MAPIStoreUserContext userContextWithUsername: username
andTDBIndexing: indexing]);
#if 0
mapistore_mgmt_backend_register_user (newConnInfo,
"SOGo",
[username UTF8String]);
#endif
connInfo = newConnInfo;
username = [NSString stringWithUTF8String: newConnInfo->username];
ASSIGN (activeUser, [SOGoUser userWithLogin: username]);
@@ -322,12 +311,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
- (void) dealloc
{
#if 0
mapistore_mgmt_backend_unregister_user ([self connectionInfo], "SOGo",
[[userContext username]
UTF8String]);
#endif
[contextUrl release];
[userContext release];
[containersBag release];
@@ -355,27 +338,16 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
return activeUser;
}
// - (void) logRestriction: (struct mapi_SRestriction *) res
// withState: (MAPIRestrictionState) state
// {
// NSString *resStr;
// resStr = MAPIStringForRestriction (res);
// [self logWithFormat: @"%@ --> %@", resStr, MAPIStringForRestrictionState (state)];
// }
- (int) getPath: (char **) path
ofFMID: (uint64_t) fmid
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc;
NSString *objectURL, *url;
// TDB_DATA key, dbuf;
url = [contextUrl absoluteString];
// FIXME transform percent escapes but not for user part of the url
//stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
//[xxxx stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
objectURL = [[userContext mapping] urlFromID: fmid];
if (objectURL)
{
@@ -396,14 +368,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
else
{
[self errorWithFormat: @"%s: you should *never* get here", __PRETTY_FUNCTION__];
// /* attempt to populate our mapping dict with data from indexing.tdb */
// key.dptr = (unsigned char *) talloc_asprintf (memCtx, "0x%.16llx",
// (long long unsigned int )fmid);
// key.dsize = strlen ((const char *) key.dptr);
// dbuf = tdb_fetch (memCtx->indexing_list->index_ctx->tdb, key);
// talloc_free (key.dptr);
// uri = talloc_strndup (memCtx, (const char *)dbuf.dptr, dbuf.dsize);
*path = NULL;
rc = MAPISTORE_SUCCESS;
}
@@ -426,7 +390,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSArray *pathComponents;
NSUInteger count, max;
[userContext activateWithUser: activeUser];
[userContext activate];
woContext = [userContext woContext];
[self ensureContextFolder];
@@ -488,7 +452,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
/* utils */
- (NSString *) extractChildNameFromURL: (NSString *) objectURL
andFolderURLAt: (NSString **) folderURL;
andFolderURLAt: (NSString **) folderURL;
{
NSString *childKey;
NSRange lastSlash;
@@ -497,15 +461,15 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
if ([objectURL hasSuffix: @"/"])
objectURL = [objectURL substringToIndex: [objectURL length] - 2];
lastSlash = [objectURL rangeOfString: @"/"
options: NSBackwardsSearch];
options: NSBackwardsSearch];
if (lastSlash.location != NSNotFound)
{
slashPtr = NSMaxRange (lastSlash);
childKey = [objectURL substringFromIndex: slashPtr];
if ([childKey length] == 0)
childKey = nil;
childKey = nil;
if (folderURL)
*folderURL = [objectURL substringToIndex: slashPtr];
*folderURL = [objectURL substringToIndex: slashPtr];
}
else
childKey = nil;
@@ -516,11 +480,10 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
- (uint64_t) idForObjectWithKey: (NSString *) key
inFolderURL: (NSString *) folderURL
{
NSString *childURL, *owner;
NSString *childURL;
MAPIStoreMapping *mapping;
uint64_t mappingId;
uint32_t contextId;
void *rootObject;
enum mapistore_error ret;
if (key)
childURL = [NSString stringWithFormat: @"%@%@", folderURL,
@@ -531,17 +494,13 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
mappingId = [mapping idFromURL: childURL];
if (mappingId == NSNotFound)
{
//[self warnWithFormat: @"no id exist yet for '%@', requesting one...",
// childURL];
mapistore_indexing_get_new_folderID (connInfo->mstore_ctx, &mappingId);
[mapping registerURL: childURL withID: mappingId];
contextId = 0;
mapistore_search_context_by_uri (connInfo->mstore_ctx, [folderURL UTF8String],
&contextId, &rootObject);
owner = [userContext username];
mapistore_indexing_record_add_mid (connInfo->mstore_ctx, contextId,
[owner UTF8String], mappingId);
[self logWithFormat: @"No id exist yet for '%@', requesting one", childURL];
ret = mapistore_indexing_get_new_folderID (connInfo->mstore_ctx, &mappingId);
if (ret == MAPISTORE_SUCCESS)
[mapping registerURL: childURL withID: mappingId];
else
[self errorWithFormat: @"Error trying to get new folder id (%d): %s",
ret, mapistore_errstr (ret)];
}
return mappingId;
@@ -595,15 +554,14 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
memCtx = talloc_zero(NULL, TALLOC_CTX);
newFMIDs = [NSMutableArray arrayWithCapacity: max];
if (mapistore_indexing_get_new_folderIDs (connInfo->mstore_ctx,
memCtx, max, &numbers)
!= MAPISTORE_SUCCESS || numbers->cValues != max)
abort ();
for (count = 0; count < max; count++)
{
newNumber
= [NSString stringWithUnsignedLongLong: numbers->lpui8[count]];
newNumber = [NSString stringWithUnsignedLongLong: numbers->lpui8[count]];
[newFMIDs addObject: newNumber];
}
+14 -8
View File
@@ -161,7 +161,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
else
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
intoNewContainer: nil];
mapping = [self mapping];
if (targetFolder)
@@ -193,6 +193,8 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
SOGoMAPIDBMessage *fsObject;
NSString *newKey;
[[self userContext] activate];
newKey = [NSString stringWithFormat: @"%@.plist",
[SOGoObject globallyUniqueObjectId]];
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
@@ -214,10 +216,13 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanReadMessages])
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
{
[[self userContext] activate];
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
}
else
keys = [NSArray array];
@@ -227,6 +232,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
[[self userContext] activate];
return [dbFolder childKeysOfType: MAPIFolderCacheObject
includeDeleted: NO
matchingQualifier: qualifier
@@ -262,7 +268,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
if ([date laterDate: fileDate] == fileDate)
{
//[self logWithFormat: @"current date: %@", date];
date = fileDate;
}
}
@@ -326,7 +332,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
rights |= RightsFolderContact;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
@@ -361,7 +367,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
subscribed to read an open contained messages in order to enable them to
find the "LocalFreebusy" message */
[sogoObject reloadIfNeeded];
displayName = [[sogoObject properties]
objectForKey: MAPIPropertyKey (PidTagDisplayName)];
+136
View File
@@ -22,6 +22,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
@@ -34,6 +35,7 @@
#import "MAPIStoreDBFolder.h"
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -104,6 +106,105 @@
return objectVersion;
}
- (void) _updatePredecessorChangeList
{
BOOL updated;
enum mapistore_error rc;
NSData *currentChangeList, *changeKey;
NSMutableArray *changeKeys;
NSMutableData *newChangeList;
NSUInteger count, len;
struct SizedXid *changes;
struct SPropValue property;
struct SRow aRow;
struct XID *currentChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t nChanges;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
changeKey = [self getReplicaKeyFromGlobCnt: [self objectVersion]];
currentChangeList = [properties objectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if (!currentChangeList)
{
/* Create a new PredecessorChangeList */
len = [changeKey length];
newChangeList = [NSMutableData dataWithCapacity: len + 1];
[newChangeList appendUInt8: len];
[newChangeList appendData: changeKey];
}
else
{
/* Update current predecessor change list with new change key */
changes = [currentChangeList asSizedXidArrayInMemCtx: localMemCtx
with: &nChanges];
updated = NO;
currentChangeKey = [changeKey asXIDInMemCtx: localMemCtx];
for (count = 0; count < nChanges && !updated; count++)
{
if (GUID_equal(&changes[count].XID.NameSpaceGuid, &currentChangeKey->NameSpaceGuid))
{
NSData *globCnt, *oldGlobCnt;
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
{
if ([globCnt length] != [oldGlobCnt length])
{
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
abort();
}
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
updated = YES;
}
}
}
/* Serialise it */
changeKeys = [NSMutableArray array];
if (!updated)
[changeKeys addObject: changeKey];
for (count = 0; count < nChanges; count++)
{
changeKey = [NSData dataWithXID: &changes[count].XID];
[changeKeys addObject: changeKey];
}
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
newChangeList = [NSMutableData data];
len = [changeKeys count];
for (count = 0; count < len; count++)
{
changeKey = [changeKeys objectAtIndex: count];
[newChangeList appendUInt8: [changeKey length]];
[newChangeList appendData: changeKey];
}
}
if ([newChangeList length] > 0)
{
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [self addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
}
talloc_free (localMemCtx);
}
//
// FIXME: how this can happen?
//
@@ -166,6 +267,9 @@
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
forKey: @"version"];
/* Update PredecessorChangeList accordingly */
[self _updatePredecessorChangeList];
[self logWithFormat: @"%d props in dict", [properties count]];
[sogoObject save];
@@ -209,4 +313,36 @@
return [sogoObject lastModified];
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
/* Modify PidTagMessageFlags from SetMessageReadFlag and
SyncImportReadStateChanges ROPs */
NSNumber *flags;
uint32_t newFlag;
flags = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
if (flags)
{
newFlag = [flags unsignedLongValue];
if (flag & SUPPRESS_RECEIPT)
newFlag |= MSGFLAG_READ;
if (flag & CLEAR_RN_PENDING)
newFlag &= ~MSGFLAG_RN_PENDING;
if (flag & CLEAR_READ_FLAG)
newFlag &= ~MSGFLAG_READ;
if (flag & CLEAR_NRN_PENDING)
newFlag &= ~MSGFLAG_NRN_PENDING;
}
else
{
newFlag = MSGFLAG_READ;
if (flag & CLEAR_READ_FLAG)
newFlag = 0x0;
}
[properties setObject: [NSNumber numberWithUnsignedLong: newFlag]
forKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
return MAPISTORE_SUCCESS;
}
@end
+1
View File
@@ -121,6 +121,7 @@
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) want_copy
inMemCtx: (TALLOC_CTX *) memCtx;
+52 -37
View File
@@ -120,6 +120,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
folderName = [folderURL host];
userContext = [self userContext];
[userContext activate];
[userContext ensureFolderTableExists];
ASSIGN (dbFolder,
@@ -231,30 +232,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (id) lookupFolder: (NSString *) folderKey
{
MAPIStoreFolder *childFolder;
MAPIStoreFolder *childFolder = nil;
SOGoFolder *sogoFolder;
WOContext *woContext;
childFolder = nil;
if ([[self folderKeys] containsObject: folderKey])
{
woContext = [[self userContext] woContext];
/* We activate the user for the context using the root folder
context as there are times where the active user is not
matching with the one stored in the application context
and SOGo object is storing cached data with the wrong user */
[[self userContext] activateWithUser: [woContext activeUser]];
sogoFolder = [sogoObject lookupName: folderKey inContext: woContext
[[self userContext] activate];
sogoFolder = [sogoObject lookupName: folderKey
inContext: nil
acquire: NO];
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
{
[sogoFolder setContext: woContext];
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
inContainer: self];
}
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
inContainer: self];
}
else
childFolder = nil;
return childFolder;
}
@@ -285,6 +275,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (messageKey)
{
[[self userContext] activate];
msgObject = [sogoObject lookupName: messageKey
inContext: nil
acquire: NO];
@@ -314,6 +305,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (messageKey)
{
[[self userContext] activate];
if ([[self faiMessageKeys] containsObject: messageKey])
{
msgObject = [dbFolder lookupName: messageKey
@@ -546,6 +538,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
context = [self context];
ownerUser = [[self userContext] sogoUser];
[[self userContext] activate];
if ([[context activeUser] isEqual: ownerUser]
|| (!isAssociated && [self subscriberCanCreateMessages]))
@@ -649,6 +642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMID: (uint64_t) targetMid
andChangeKey: (struct Binary_r *) targetChangeKey
andPredecessorChangeList: (struct Binary_r *) targetPredecessorChangeList
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -676,15 +670,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
if (targetChangeKey)
if (targetPredecessorChangeList)
{
property.ulPropTag = PidTagChangeKey;
property.value.bin = *targetChangeKey;
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *targetPredecessorChangeList;
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [destMsg addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
goto end;
{
[self errorWithFormat: @"Cannot add PredecessorChangeList on move"];
goto end;
}
}
[destMsg save: memCtx];
if (!wantCopy)
@@ -703,6 +700,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -712,7 +710,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *oldMessageURL;
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
struct Binary_r *targetChangeKey;
struct Binary_r *targetChangeKey, *targetPredecessorChangeList;
//TALLOC_CTX *memCtx;
//memCtx = talloc_zero (NULL, TALLOC_CTX);
@@ -733,14 +731,21 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (oldMessageURL)
{
[oldMessageURLs addObject: oldMessageURL];
if (targetChangeKeys)
targetChangeKey = targetChangeKeys[count];
if (targetChangeKeys && targetPredecessorChangeList)
{
targetChangeKey = targetChangeKeys[count];
targetPredecessorChangeList = targetPredecessorChangeLists[count];
}
else
targetChangeKey = NULL;
{
targetChangeKey = NULL;
targetPredecessorChangeList = NULL;
}
rc = [self _moveCopyMessageWithMID: srcMids[count]
fromFolder: sourceFolder
withMID: targetMids[count]
andChangeKey: targetChangeKey
andPredecessorChangeList: targetPredecessorChangeList
wantCopy: wantCopy
inMemCtx: memCtx];
}
@@ -758,9 +763,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
else
rc = MAPISTORE_ERR_DENIED;
//talloc_free (memCtx);
return rc;
}
@@ -931,7 +936,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSArray *newIDs;
uint64_t idNbr;
bool softDeleted;
baseURL = [self url];
mapping = [self mapping];
@@ -1060,9 +1065,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
static enum MAPITAGS bannedProps[] = { PR_MID, PR_FID, PR_PARENT_FID,
PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY,
PR_CHANGE_KEY, 0x00000000 };
PR_CHANGE_KEY, PidTagChangeNumber, 0x00000000 };
enum MAPITAGS *currentProp;
NSMutableDictionary *propsCopy;
uint64_t cn;
/* TODO: this should no longer be required once mapistore v2 API is in
place, when we can then do this from -dealloc below */
@@ -1080,6 +1086,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
[properties addEntriesFromDictionary: propsCopy];
/* Update change number after setting the properties */
cn = [[self context] getNewChangeNumber];
[properties setObject: [NSNumber numberWithUnsignedLongLong: cn]
forKey: MAPIPropertyKey (PidTagChangeNumber)];
[dbFolder save];
}
@@ -1105,6 +1117,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
[[self userContext] activate];
return [dbFolder childKeysOfType: MAPIFAICacheObject
includeDeleted: NO
matchingQualifier: qualifier
@@ -1213,7 +1226,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
/*
Possible values are:
0x00000001 Modify
0x00000002 Read
0x00000004 Delete
@@ -1244,7 +1257,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
access |= 0x10;
if (userIsOwner)
access |= 0x20;
*data = MAPILongValue (memCtx, access);
return MAPISTORE_SUCCESS;
@@ -1273,7 +1286,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
rights |= RightsCreateSubfolders;
if (userIsOwner)
rights |= RightsFolderOwner | RightsFolderContact;
*data = MAPILongValue (memCtx, rights);
return MAPISTORE_SUCCESS;
@@ -1309,7 +1322,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPIBoolValue (memCtx, [self supportsSubFolders] && [[self folderKeys] count] > 0);
return MAPISTORE_SUCCESS;
}
@@ -1317,7 +1330,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, [[self folderKeys] count]);
return MAPISTORE_SUCCESS;
}
@@ -1419,7 +1432,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[dbObject setIsNew: YES];
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
inContainer: self];
return newMessage;
}
@@ -1428,6 +1441,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMessage *newMessage;
WOContext *woContext;
[[self userContext] activate];
if (isAssociated)
newMessage = [self _createAssociatedMessage];
else
@@ -1627,7 +1642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
permissionUser = nil;
permissionRoles = nil;
if (currentPermission->PermissionDataFlags == ROW_ADD)
isAdd = YES;
else if (currentPermission->PermissionDataFlags == ROW_MODIFY)
@@ -1778,7 +1793,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
[self subclassResponsibility: _cmd];
return nil;
return nil;
}
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
-2
View File
@@ -121,7 +121,6 @@
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: NULL];
[MAPIApp setUserContext: userContext];
moduleName = [self MAPIModuleName];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
nameInContainer = nil;
@@ -134,7 +133,6 @@
moduleName, nameInContainer];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
return mapistoreURI;
}
+2 -1
View File
@@ -42,7 +42,8 @@
/* synchronisation */
- (BOOL) synchroniseCache;
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) newChangeKey;
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl;
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber;
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey;
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
+85 -18
View File
@@ -75,6 +75,7 @@ static Class NSNumberK;
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIInternalCacheObject];
[versionsMessage reloadIfNeeded];
}
- (void) dealloc
@@ -261,7 +262,6 @@ static Class NSNumberK;
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
{
struct XID *xid;
NSString *guid;
@@ -270,19 +270,15 @@ static Class NSNumberK;
NSMutableDictionary *changeList;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->GUID];
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
if (!inChangeListOnly)
{
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
}
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
/* 2. append/update predecessor change list */
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
@@ -296,6 +292,77 @@ static Class NSNumberK;
[changeList setObject: globCnt forKey: guid];
}
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
withOldChangeKey: (NSData *) oldChangeKey
{
NSData *globCnt, *oldGlobCnt;
NSDictionary *changeKeyDict;
NSString *guid;
NSMutableDictionary *changeList;
struct SizedXid *sizedXIDList;
struct XID xid, *givenChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t i, length;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
if (predecessorChangeList)
{
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
}
}
if (oldChangeKey)
{
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
if (givenChangeKey) {
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
if (!changeKeyDict ||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
{
/* The given change key is greater than current one stored in
metadata or it does not exist */
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil]
forKey: @"ChangeKey"];
}
}
}
talloc_free (localMemCtx);
}
- (EOQualifier *) componentQualifier
{
if (!componentQualifier)
@@ -465,8 +532,7 @@ static Class NSNumberK;
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
}
now = [NSCalendarDate date];
@@ -483,12 +549,13 @@ static Class NSNumberK;
}
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) newChangeKey
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl
{
NSMutableDictionary *messages, *messageEntry;
[self synchroniseCache];
if (newChangeKey)
if (oldChangeKey || pcl)
{
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageKey];
@@ -496,8 +563,8 @@ static Class NSNumberK;
[NSException raise: @"MAPIStoreIOException"
format: @"no version record found for message '%@'",
messageKey];
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
inChangeListOnly: YES];
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
withOldChangeKey: oldChangeKey];
[versionsMessage save];
}
}
+6 -3
View File
@@ -209,13 +209,16 @@
- (void) updateVersions
{
NSData *newChangeKey;
/* Update ChangeKey and PredecessorChangeList on message's save */
NSData *newChangeKey, *predecessorChangeList;
newChangeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
predecessorChangeList = [properties objectForKey: MAPIPropertyKey (PR_PREDECESSOR_CHANGE_LIST)];
[(MAPIStoreGCSFolder *) container
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey];
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey
andPredecessorChangeList: predecessorChangeList];
}
@end
+4 -15
View File
@@ -30,6 +30,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "MAPIStoreTypes.h"
#import "MAPIStoreMailMessage.h"
@@ -108,7 +109,7 @@
static char recordBytes[] = {0xd9, 0xd8, 0x11, 0xa3, 0xe2, 0x90, 0x18, 0x41,
0x9e, 0x04, 0x58, 0x46, 0x9d, 0x6d, 0x1b,
0x68};
*data = [[NSData dataWithBytes: recordBytes length: 16]
asBinaryInMemCtx: memCtx];
@@ -117,19 +118,7 @@
- (NSString *) _fileName
{
NSString *fileName;
NSDictionary *parameters;
fileName = [[bodyInfo objectForKey: @"parameterList"]
objectForKey: @"name"];
if (!fileName)
{
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
fileName = [parameters objectForKey: @"filename"];
}
return fileName;
return [bodyInfo filename];
}
- (int) getPidTagAttachLongFilename: (void **) data
@@ -178,7 +167,7 @@
- (int) getPidTagAttachContentId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
{
*data = [[bodyInfo objectForKey: @"bodyId"]
asUnicodeInMemCtx: memCtx];
+1 -3
View File
@@ -67,7 +67,7 @@ MakeDisplayFolderName (NSString *folderName)
NSArray *parts;
NSString *lastFolder;
NSUInteger max;
parts = [folderName componentsSeparatedByString: @"/"];
max = [parts count];
if (max > 1)
@@ -198,7 +198,6 @@ MakeDisplayFolderName (NSString *folderName)
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: NULL];
[MAPIApp setUserContext: userContext];
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
folderName = [NSString stringWithFormat: @"folder%@",
[newFolderName asCSSIdentifier]];
@@ -213,7 +212,6 @@ MakeDisplayFolderName (NSString *folderName)
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
return mapistoreURI;
}
+2
View File
@@ -52,6 +52,8 @@
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey;
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey;
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
+115 -29
View File
@@ -68,6 +68,8 @@
static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#include <gen_ndr/exchange.h>
#undef DEBUG
#include <util/attr.h>
#include <libmapi/libmapi.h>
@@ -109,6 +111,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIInternalCacheObject];
[versionsMessage reloadIfNeeded];
}
- (BOOL) ensureFolderExists
@@ -139,7 +142,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
[[self mapping] updateID: fid withURL: [self url]];
[dbFolder setNameInContainer: newNameInContainer];
[self cleanupCaches];
propsCopy = [newProperties mutableCopy];
[propsCopy removeObjectForKey: key];
[propsCopy autorelease];
@@ -186,10 +189,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
nameInContainer = [NSString stringWithFormat: @"folder%@",
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
/* it may be the operation is interleaved with operations
from other users having cached information in the thread
with the other user, so it'd better activate the user again here... */
[[self userContext] activateWithUser: [[[self userContext] woContext] activeUser]];
[[self userContext] activate];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
@@ -245,7 +245,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
sortOrdering: nil]
count];
*data = MAPILongValue (memCtx, longValue);
return MAPISTORE_SUCCESS;
}
@@ -253,7 +253,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPF.Note" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -265,7 +265,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (!nonDeletedQualifier)
{
deletedQualifier
= [[EOKeyValueQualifier alloc]
= [[EOKeyValueQualifier alloc]
initWithKey: @"FLAGS"
operatorSelector: EOQualifierOperatorContains
value: [NSArray arrayWithObject: @"Deleted"]];
@@ -378,7 +378,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
[self warnWithFormat: @"qualifier is only used for folders with name"];
if (sortOrderings)
[self errorWithFormat: @"sort orderings are not used for folders"];
/* FIXME: Flush any cache before retrieving the hierarchy, this
slows things down but it is safer */
if (!qualifier)
@@ -472,7 +472,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
}
else
supportsSubFolders = YES;
return supportsSubFolders;
}
@@ -519,6 +519,44 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return [modseq1 compare: modseq2];
}
- (void) _updatePredecessorChangeListWith: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
{
NSData *globCnt, *oldGlobCnt;
NSMutableDictionary *changeList;
NSString *guid;
struct SizedXid *sizedXIDList;
struct XID xid;
uint32_t i, length;
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: NULL with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
talloc_free (sizedXIDList);
}
[versionsMessage save];
}
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
{
@@ -529,8 +567,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSMutableDictionary *changeList;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->GUID];
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
/* 1. set change key association */
@@ -641,7 +679,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
fetchResults
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
context: NULL];
for (count = 0; count < max; count++)
{
result = [fetchResults objectAtIndex: count];
@@ -927,8 +965,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return changeNumber;
}
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey
- (NSMutableDictionary *) _messageEntryFromMessageKey: (NSString *) messageKey
{
NSMutableDictionary *messages, *messageEntry;
NSString *messageUid;
@@ -939,7 +976,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
messageEntry = [messages objectForKey: messageUid];
if (!messageEntry)
{
[self warnWithFormat: @"attempting to synchronise to set the change key for "
[self warnWithFormat: @"attempting to synchronise to get the message entry for "
@"this message %@", messageKey];
synced = [self synchroniseCacheForUID: messageUid];
if (synced)
@@ -950,11 +987,57 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
abort ();
}
}
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
return messageEntry;
}
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey
{
[self _setChangeKey: changeKey
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
[versionsMessage save];
}
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey
{
/* Update predecessor change list property given the change key. It
returns if the change key has been added to the list or not */
BOOL added = NO;
NSData *globCnt, *oldGlobCnt;
NSDictionary *messageEntry;
NSMutableDictionary *changeList;
NSString *guid;
struct XID *xid;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
messageEntry = [self _messageEntryFromMessageKey: messageKey];
if (messageEntry)
{
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (changeList)
{
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
{
[changeList setObject: globCnt forKey: guid];
[versionsMessage save];
added = YES;
}
}
else
[self errorWithFormat: @"Missing predecessor change list to update"];
}
return added;
}
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey
{
NSDictionary *messages, *changeKeyDict;
@@ -1178,7 +1261,7 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
count++;
}
*UIDsP = UIDs;
return count;
}
@@ -1220,6 +1303,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
@@ -1234,12 +1318,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
NSDictionary *result;
NSUInteger count;
NSArray *a;
NSData *changeKey;
NSData *changeList;
if (![sourceFolder isKindOfClass: [MAPIStoreMailFolder class]])
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
fromFolder: sourceFolder withMIDs: targetMids
andChangeKeys: targetChangeKeys
andPredecessorChangeLists: targetPredecessorChangeLists
wantCopy: wantCopy
inMemCtx: memCtx];
@@ -1328,11 +1413,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
[self synchroniseCache];
for (count = 0; count < midCount; count++)
{
changeKey = [NSData dataWithBinary: targetChangeKeys[count]];
changeList = [NSData dataWithBinary: targetPredecessorChangeLists[count]];
messageKey = [NSString stringWithFormat: @"%@.eml",
[destUIDs objectAtIndex: count]];
[self setChangeKey: changeKey
forMessageWithKey: messageKey];
[self _updatePredecessorChangeListWith: changeList
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
}
}
@@ -1456,7 +1541,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
[uids addObject: [self messageUIDFromMessageKey: childKey]];
}
result = [client copyUids: uids
result = [client copyUids: uids
toFolder: newFolderIMAPName];
if ([[result objectForKey: @"result"] boolValue])
{
@@ -1495,9 +1580,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
SOGoCacheObject *childObject;
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
globallyUniqueObjectId]
inContainer: sogoObject];
[[[self context] userContext] activate];
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject globallyUniqueObjectId]
inContainer: sogoObject];
return [MAPIStoreMailVolatileMessage
mapiStoreObjectWithSOGoObject: childObject
inContainer: self];
@@ -1573,7 +1659,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@@ -1624,7 +1710,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
}
}
}
client = [[(SOGoMailFolder *) sogoObject imap4Connection] client];
[client select: [sogoObject absoluteImap4Name]];
response = [client fetchUids: [keyAssoc allKeys]
+40 -26
View File
@@ -40,6 +40,7 @@
#import <Mailer/NSData+Mail.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
@@ -196,7 +197,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
count1 = [keys indexOfObject: data1];
data2 = [entry2 objectForKey: @"mimeType"];
count2 = [keys indexOfObject: data2];
if (count1 == count2)
{
data1 = [entry1 objectForKey: @"key"];
@@ -529,7 +530,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -624,7 +625,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v = 0;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
@@ -636,7 +637,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([[self attachmentKeys]
count] > 0)
v |= MSGFLAG_HASATTACH;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -656,7 +657,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
v = 2;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -668,15 +669,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
if ([flags containsObject: @"flagged"])
v = 6;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -755,7 +756,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([ngAddress isKindOfClass: [NGMailAddress class]])
{
cn = [ngAddress displayName];
// If we don't have a displayName, we use the email address instead. This
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
// nor in the recipient field if we reply to the email.
@@ -809,7 +810,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
entryId = MAPIStoreExternalEntryId (cn, email);
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
@@ -966,15 +967,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint32_t v;
NSString *s;
s = [[sogoObject mailHeaders] objectForKey: @"x-priority"];
v = 0x1;
if ([s hasPrefix: @"1"]) v = 0x2;
else if ([s hasPrefix: @"2"]) v = 0x2;
else if ([s hasPrefix: @"4"]) v = 0x0;
else if ([s hasPrefix: @"5"]) v = 0x0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -1163,14 +1164,14 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
if ([headerMimeType isEqualToString: @"text/plain"])
format = EDITOR_FORMAT_PLAINTEXT;
else if ([headerMimeType isEqualToString: @"text/html"])
format = EDITOR_FORMAT_HTML;
else
format = 0; /* EDITOR_FORMAT_DONTKNOW */
*data = MAPILongValue (memCtx, format);
return MAPISTORE_SUCCESS;
@@ -1517,7 +1518,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
p = 0;
recipient->data = talloc_array (msgData, void *, msgData->columns->cValues);
memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *));
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
@@ -1525,7 +1526,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
// PR_7BIT_DISPLAY_NAME_UNICODE
recipient->data[p] = [cn asUnicodeInMemCtx: msgData];
p++;
@@ -1533,7 +1534,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_SMTP_ADDRESS_UNICODE
recipient->data[p] = [email asUnicodeInMemCtx: msgData];
p++;
// PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL)
recipient->data[p] = MAPILongValue (msgData, 0x00060000);
p++;
@@ -1566,12 +1567,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
withPrefix: (NSString *) keyPrefix
{
NSArray *parts;
NSDictionary *parameters;
NSUInteger count, max;
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
if ([[parameters objectForKey: @"filename"] length] > 0)
if ([[bodyInfo filename] length] > 0)
{
if ([keyPrefix length] == 0)
keyPrefix = @"0";
@@ -1614,6 +1612,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
max = [keyParts count];
if (max > 0)
{
[[self userContext] activate];
currentPart = [sogoObject lookupName: [keyParts objectAtIndex: 0]
inContext: nil
acquire: NO];
@@ -1643,15 +1643,29 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
return attachment;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
BOOL modified = NO;
BOOL alreadyRead = NO;
NSString *imapFlag = @"\\Seen";
alreadyRead = [[[sogoObject fetchCoreInfos] objectForKey: @"flags"]
containsObject: @"seen"];
/* TODO: notifications should probably be emitted from here */
if (flag & CLEAR_READ_FLAG)
[sogoObject removeFlags: imapFlag];
{
[sogoObject removeFlags: imapFlag];
modified = alreadyRead;
}
else
[sogoObject addFlags: imapFlag];
{
[sogoObject addFlags: imapFlag];
modified = !alreadyRead;
}
if (modified)
[(MAPIStoreMailFolder *)[self container] synchroniseCache];
return MAPISTORE_SUCCESS;
}
@@ -1692,7 +1706,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
return nil;
}
- (void) save: (TALLOC_CTX *) memCtx
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;
+22 -7
View File
@@ -161,15 +161,30 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
if (modseq)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
{
if (res->relop == RELOP_GT)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
}
else
modseq = [NSNumber numberWithUnsignedLongLong: 0];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
if (res->relop == RELOP_GT || res->relop == RELOP_GE)
{
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
}
else
{
/* Ignore other operations as IMAP only support MODSEQ >= X */
[self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=",
[self operatorFromRestrictionOperator: res->relop]];
rc = MAPIRestrictionStateAlwaysTrue;
}
}
break;
+32 -11
View File
@@ -34,6 +34,7 @@
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSObject+Values.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h>
@@ -285,7 +286,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
version = [properties objectForKey: @"version"];
return (version
? exchange_globcnt ([version unsignedLongLongValue])
? [version unsignedLongLongValue]
: ULLONG_MAX);
}
@@ -771,6 +772,12 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)];
if (subjectData)
[subject appendString: subjectData];
if ([subject length] == 0)
{
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_UNICODE)];
if (subjectData)
[subject appendString: subjectData];
}
[headers setObject: [subject asQPSubjectString: @"utf-8"] forKey: @"subject"];
messageId = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_MESSAGE_ID_UNICODE)];
@@ -1077,6 +1084,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
dd = [activeUser domainDefaults];
from = [[activeUser allEmails] objectAtIndex: 0];
[[self userContext] activate];
woContext = [[self userContext] woContext];
authenticator = [sogoObject authenticatorInContext: woContext];
error = [[SOGoMailer mailerWithDomainDefaults: dd]
@@ -1103,7 +1111,8 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (void) save: (TALLOC_CTX *) memCtx
{
NSString *folderName, *flag, *newIdString, *messageKey;
BOOL updatedMetadata;
NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber;
NSData *changeKey, *messageData;
NGImap4Connection *connection;
NGImap4Client *client;
@@ -1139,21 +1148,33 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[sogoObject setNameInContainer: messageKey];
[mapping registerURL: [self url] withID: mid];
/* synchronise the cache and update the change key with the one provided
by the client. Before doing this, lets issue a unselect/select combo
because of timing issues with Dovecot in obtaining the latest modseq.
Sometimes, Dovecot doesn't return the newly appended UID if we do
a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where
XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */
/* synchronise the cache and update the predecessor change list
with the change key provided by the client. Before doing
this, lets issue a unselect/select combo because of timing
issues with Dovecot in obtaining the latest modseq.
Sometimes, Dovecot doesn't return the newly appended UID if
we do a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)"
command (where XYZ is the HIGHESTMODSEQ+1) immediately after
IMAP APPEND */
[client unselect];
[client select: folderName];
[(MAPIStoreMailFolder *) container synchroniseCache];
changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
if (changeKey)
[(MAPIStoreMailFolder *) container
setChangeKey: changeKey
forMessageWithKey: messageKey];
{
updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey
forMessageWithKey: messageKey];
if (!updatedMetadata)
[self warnWithFormat: @"Predecessor change list not updated with client data"];
}
/* Update version property (PR_CHANGE_KEY indeed) as it is
requested once it is saved */
changeNumber = [(MAPIStoreMailFolder *) container changeNumberForMessageUID: newIdString];
if (changeNumber)
[properties setObject: [NSNumber numberWithUnsignedLongLong: [changeNumber unsignedLongLongValue] >> 16]
forKey: @"version"];
}
}
+1 -1
View File
@@ -63,7 +63,7 @@
withAID: (uint32_t) aid;
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr;
- (int) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
- (NSArray *) activeContainerMessageTables;
+3 -2
View File
@@ -549,11 +549,12 @@ rtf2html (NSData *compressedRTF)
}
[self save: memCtx];
/* We make sure that any change-related properties are removes from the
/* We make sure that any change-related properties are removed from the
properties dictionary, to make sure that related methods will be
invoked the next time they are requested. */
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if ([container isKindOfClass: MAPIStoreFolderK])
{
@@ -918,7 +919,7 @@ rtf2html (NSData *compressedRTF)
return [self getNo: data inMemCtx: memCtx];;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
// [self subclassResponsibility: _cmd];
+37 -117
View File
@@ -61,20 +61,25 @@ static BOOL initialization_done = NO;
if (!initialization_done) { \
OC_DEBUG(5, "[SOGo] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
GSCurrentThread(), getpid()); \
}
} \
OC_DEBUG(5, "[SOGo] --->");
#define NS_CURRENT_THREAD_TRY_UNREGISTER() \
if (__nsrct_thread_registered) { \
GSUnregisterCurrentThread(); \
}
} \
OC_DEBUG(6, "[SOGo] <---");
#define TRYCATCH_START @try {
#define TRYCATCH_END(pool) \
} @catch (NSException * e) { \
enum mapistore_error ret = sogo_backend_handle_objc_exception(e, __PRETTY_FUNCTION__, __LINE__); \
mapiapp_cleanup(); \
[pool release]; \
NS_CURRENT_THREAD_TRY_UNREGISTER(); \
return ret; \
}
} \
mapiapp_cleanup();
static enum mapistore_error
@@ -196,12 +201,28 @@ sogo_backend_init (void)
return MAPISTORE_SUCCESS;
}
/**
\details Cleanup operation to execute after an action has been performed
so there won't be any conflicts with future calls.
In practice this will deactivate the current user context set on MAPIApp
(which is the current WOApplication), this means two things: (1) set nil
as current user context on MAPIApp and (2) remove woContext from current
thread dictionary (this is used on WOContext.m).
*/
static void mapiapp_cleanup(void)
{
Class MAPIApplicationK;
MAPIApplicationK = NSClassFromString (@"MAPIApplication");
if (MAPIApplicationK)
[[MAPIApplicationK application] cleanup];
}
/**
\details Create a connection context to the sogo backend
\param mem_ctx pointer to the memory context
\param uri pointer to the sogo path
\param private_data pointer to the private backend context
\param private_data pointer to the private backend context
*/
static enum mapistore_error
@@ -214,8 +235,6 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -251,8 +270,6 @@ sogo_backend_create_root_folder (const char *username,
NSString *mapistoreUri;
int rc;
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -288,8 +305,6 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
NSString *userName;
int rc;
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -336,8 +351,6 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
wrapper = backend_object;
@@ -370,8 +383,6 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
wrapper = backend_object;
@@ -413,8 +424,6 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
MAPIStoreFolder *folder, *childFolder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -442,7 +451,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
/**
\details Create a folder in the sogo backend
\param private_data pointer to the current sogo context
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
@@ -457,8 +466,6 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder, *childFolder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -500,8 +507,6 @@ sogo_folder_delete(void *folder_object)
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -532,8 +537,6 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -568,8 +571,6 @@ sogo_folder_open_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -610,8 +611,6 @@ sogo_folder_create_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -622,7 +621,7 @@ sogo_folder_create_message(void *folder_object,
TRYCATCH_START
rc = [folder createMessage: &message
withMID: mid
isAssociated: associated];
isAssociated: associated];
if (rc == MAPISTORE_SUCCESS)
*message_object = [message tallocWrapper: mem_ctx];
TRYCATCH_END(pool)
@@ -646,8 +645,6 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -677,6 +674,7 @@ sogo_folder_move_copy_messages(void *folder_object,
uint32_t mid_count,
uint64_t *src_mids, uint64_t *t_mids,
struct Binary_r **target_change_keys,
struct Binary_r **target_predecessor_change_lists,
uint8_t want_copy)
{
MAPIStoreFolder *sourceFolder, *targetFolder;
@@ -684,8 +682,6 @@ sogo_folder_move_copy_messages(void *folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -703,6 +699,7 @@ sogo_folder_move_copy_messages(void *folder_object,
fromFolder: sourceFolder
withMIDs: t_mids
andChangeKeys: target_change_keys
andPredecessorChangeLists: target_predecessor_change_lists
wantCopy: want_copy
inMemCtx: mem_ctx];
TRYCATCH_END(pool)
@@ -728,8 +725,6 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -778,8 +773,6 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
struct MAPIStoreTallocWrapper *wrapper;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -822,8 +815,6 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -861,8 +852,6 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -900,8 +889,6 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -934,8 +921,6 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
MAPIStoreFolder *folder;
int rc;
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
wrapper = folder_object;
@@ -969,8 +954,6 @@ sogo_message_get_message_data(void *message_object,
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1004,8 +987,6 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
MAPIStoreAttachment *attachment;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1017,7 +998,6 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
rc = [message createAttachment: &attachment inAID: aidp];
if (rc == MAPISTORE_SUCCESS)
*attachment_object = [attachment tallocWrapper: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1041,8 +1021,6 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
MAPIStoreAttachment *attachment;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1054,7 +1032,6 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
rc = [message getAttachment: &attachment withAID: aid];
if (rc == MAPISTORE_SUCCESS)
*attachment_object = [attachment tallocWrapper: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1077,8 +1054,6 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
MAPIStoreAttachmentTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1091,7 +1066,6 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
andRowCount: row_count];
if (rc == MAPISTORE_SUCCESS)
*table_object = [table tallocWrapper: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1116,9 +1090,6 @@ sogo_message_modify_recipients (void *message_object,
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1130,7 +1101,6 @@ sogo_message_modify_recipients (void *message_object,
rc = [message modifyRecipientsWithRecipients: recipients
andCount: count
andColumns: columns];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1150,10 +1120,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
enum mapistore_error rc;
if (message_object)
{
@@ -1164,7 +1131,6 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
TRYCATCH_START
rc = [message setReadFlag: flag];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1186,9 +1152,6 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
MAPIStoreMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1198,7 +1161,6 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
TRYCATCH_START
rc = [message saveMessage: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1220,9 +1182,6 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
MAPIStoreMailVolatileMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
wrapper = message_object;
@@ -1232,7 +1191,6 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
TRYCATCH_START
rc = [message submitWithFlags: flags];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1259,9 +1217,6 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
wrapper = attachment_object;
@@ -1301,9 +1256,6 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
wrapper = attachment_object;
@@ -1338,9 +1290,6 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1371,9 +1320,6 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1405,9 +1351,6 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1441,9 +1384,6 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1479,9 +1419,6 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1515,9 +1452,6 @@ sogo_table_get_row_count (void *table_object,
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1549,9 +1483,6 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
MAPIStoreTable *table;
int rc;
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
wrapper = table_object;
@@ -1584,9 +1515,6 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
MAPIStoreObject *propObject;
int rc;
OC_DEBUG(5, "[SOGo]");
if (object)
{
wrapper = object;
@@ -1620,9 +1548,6 @@ sogo_properties_get_properties (void *object,
MAPIStoreObject *propObject;
int rc;
OC_DEBUG(5, "[SOGo]");
if (object)
{
wrapper = object;
@@ -1655,9 +1580,6 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
MAPIStoreObject *propObject;
int rc;
OC_DEBUG(5, "[SOGo]");
if (object)
{
wrapper = object;
@@ -1681,18 +1603,16 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
}
static enum mapistore_error
sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
const char *user,
const char *folder,
const char *message,
sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
const char *user,
const char *folder,
const char *message,
const char *rootURI,
char **uri)
{
NSAutoreleasePool *pool;
NSString *partialURLString, *username, *directory;
OC_DEBUG(5, "[SOGo]");
if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER;
/* This fixes a crash occurring during the instantiation of the
@@ -1738,9 +1658,9 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
*/
int mapistore_init_backend(void)
{
struct mapistore_backend backend;
int ret;
static BOOL registered = NO;
struct mapistore_backend backend;
int ret;
static BOOL registered = NO;
if (registered)
ret = MAPISTORE_SUCCESS;
+4 -2
View File
@@ -31,6 +31,7 @@
#import <Appointments/SOGoTaskObject.h>
#import "MAPIApplication.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreTasksContext.h"
#import "MAPIStoreTasksMessage.h"
#import "MAPIStoreTasksMessageTable.h"
@@ -61,6 +62,7 @@
SOGoTaskObject *newEntry;
NSString *name;
[[[self context] userContext] activate];
name = [NSString stringWithFormat: @"%@.ics",
[SOGoObject globallyUniqueObjectId]];
newEntry = [SOGoTaskObject objectWithName: name
@@ -69,7 +71,7 @@
newMessage = [MAPIStoreTasksMessage mapiStoreObjectWithSOGoObject: newEntry
inContainer: self];
return newMessage;
}
@@ -116,7 +118,7 @@
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
+1 -1
View File
@@ -531,7 +531,7 @@
}
[vToDo setTimeStampAsDate: now];
[sogoObject saveComponent: vCalendar];
[sogoObject saveCalendar: vCalendar];
[self updateVersions];
}
+2
View File
@@ -86,6 +86,8 @@
/* SOGo hacky magic */
- (void) activateWithUser: (SOGoUser *) activeUser;
- (void) activate;
- (void) deactivate;
- (MAPIStoreAuthenticator *) authenticator;
- (WOContext *) woContext;
+35 -7
View File
@@ -39,6 +39,7 @@
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserFolder.h>
#import <SOGo/NSString+Utilities.h>
#import <NGExtensions/NSObject+Logs.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
@@ -158,6 +159,8 @@ static NSMapTable *contextsTable = nil;
if ([userPassword length] == 0)
userPassword = username;
[authenticator setPassword: userPassword];
// Activate the profile on initialization
[self activate];
}
return self;
@@ -214,7 +217,7 @@ static NSMapTable *contextsTable = nil;
if (!userFolder)
{
userFolder = [SOGoUserFolder objectWithName: username
inContainer: MAPIApp];
inContainer: nil];
[userFolder retain];
}
@@ -232,7 +235,8 @@ static NSMapTable *contextsTable = nil;
if (!rootFolders)
{
rootFolders = [NSMutableDictionary new];
[self userFolder];
[self activate];
[self userFolder]; // force lazy initialization
[woContext setClientObject: userFolder];
/* Calendar */
@@ -257,10 +261,10 @@ static NSMapTable *contextsTable = nil;
acquire: NO];
[containersBag addObject: accountsFolder];
[woContext setClientObject: accountsFolder];
currentFolder = [accountsFolder lookupName: @"0"
inContext: woContext
acquire: NO];
[rootFolders setObject: currentFolder
forKey: @"mail"];
connection = [currentFolder imap4Connection];
@@ -268,8 +272,7 @@ static NSMapTable *contextsTable = nil;
/* ensure the folder cache is filled */
[currentFolder toManyRelationshipKeysWithNamespaces: YES];
hierarchy = [connection
cachedHierarchyResultsForURL: [currentFolder imap4URL]];
hierarchy = [connection cachedHierarchyResultsForURL: [currentFolder imap4URL]];
flags = [[hierarchy objectForKey: @"list"] objectForKey: @"/INBOX"];
inboxHasNoInferiors = [flags containsObject: @"noinferiors"];
}
@@ -338,7 +341,7 @@ static NSMapTable *contextsTable = nil;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: folderTableURL];
/* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */
tableName = [[folderTableURL path] lastPathComponent];
if ([channel evaluateExpressionX:
@@ -355,7 +358,7 @@ static NSMapTable *contextsTable = nil;
[channel cancelFetch];
[cm releaseChannel: channel];
[cm releaseChannel: channel];
}
/* SOGo context objects */
@@ -369,6 +372,11 @@ static NSMapTable *contextsTable = nil;
return authenticator;
}
- (void) activate
{
[self activateWithUser: [self sogoUser]];
}
- (void) activateWithUser: (SOGoUser *) activeUser;
{
NSMutableDictionary *info;
@@ -379,4 +387,24 @@ static NSMapTable *contextsTable = nil;
[info setObject: woContext forKey: @"WOContext"];
}
- (void) deactivate
{
NSMutableDictionary *info;
if (self == [MAPIApp userContext])
[MAPIApp setUserContext: nil];
else
[self errorWithFormat: @"Error: Tried to deactivate an user context "
@"not enabled (%@ vs %@)",
[self username], [[MAPIApp userContext] username]];
info = [[NSThread currentThread] threadDictionary];
if (woContext == [info objectForKey: @"WOContext"])
[info removeObjectForKey: @"WOContext"];
else
[self errorWithFormat: @"Error: Tried to deactivate a WOContext "
@"not enabled (%@ vs %@)",
woContext, [info objectForKey: @"WOContext"]];
}
@end
+2
View File
@@ -41,6 +41,8 @@
+ (id) dataWithXID: (const struct XID *) xid;
- (struct XID *) asXIDInMemCtx: (void *) memCtx;
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
with: (uint32_t *) length;
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt;
+40 -6
View File
@@ -22,6 +22,7 @@
#import <NGExtensions/NSObject+Logs.h>
#import "MAPIStoreTypes.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -29,6 +30,7 @@
#undef DEBUG
#include <stdbool.h>
#include <libmapi/libmapi.h>
#include <talloc.h>
#include <util/time.h>
#include <gen_ndr/exchange.h>
@@ -136,11 +138,11 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
NSMutableData *xidData;
struct FlatUID_r flatUID;
_fillFlatUIDWithGUID (&flatUID, &xid->GUID);
_fillFlatUIDWithGUID (&flatUID, &xid->NameSpaceGuid);
xidData = [NSMutableData dataWithCapacity: 16 + xid->Size];
xidData = [NSMutableData dataWithCapacity: 16 + xid->LocalId.length];
[xidData appendBytes: flatUID.ab length: 16];
[xidData appendBytes: xid->Data length: xid->Size];
[xidData appendBytes: xid->LocalId.data length: xid->LocalId.length];
return xidData;
}
@@ -156,12 +158,12 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
{
xid = talloc_zero (memCtx, struct XID);
[self _extractGUID: &xid->GUID];
[self _extractGUID: &xid->NameSpaceGuid];
xid->Size = max - 16;
xid->LocalId.length = max - 16;
bytes = (uint8_t *) [self bytes];
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
xid->LocalId.data = talloc_memdup (xid, (bytes+16), xid->LocalId.length);
}
else
{
@@ -172,6 +174,38 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
return xid;
}
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
with: (uint32_t *) length
{
struct Binary_r bin;
struct SizedXid *sizedXIDArray;
bin.cb = [self length];
bin.lpb = (uint8_t *)[self bytes];
sizedXIDArray = get_SizedXidArray(memCtx, &bin, length);
if (!sizedXIDArray)
{
NSLog (@"Impossible to parse SizedXID array");
return NULL;
}
return sizedXIDArray;
}
- (NSComparisonResult) compare: (NSData *) otherGlobCnt
{
uint64_t globCnt = 0, oGlobCnt = 0;
if ([self length] > 0)
globCnt = *(uint64_t *) [self bytes];
if ([otherGlobCnt length] > 0)
oGlobCnt = *(uint64_t *) [otherGlobCnt bytes];
return MAPICNCompare (globCnt, oGlobCnt, NULL);
}
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt;
{
+36 -4
View File
@@ -161,8 +161,11 @@
minute: [tzStart minuteOfHour] second: 0
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
day: 0 hour: 0 minute: 0
tmpDate = [tmpDate addYear: 0
month: ((pos > 0) ? 0 : 1)
day: 0
hour: 0
minute: 0
second: 0];
/* If the day of the time change is "-XSU", we need to determine whether the
@@ -197,12 +200,41 @@
END:STANDARD
END:VTIMEZONE
The time changes occure on a Sunday, but in March, the 1st is a Sunday itself and in November
The time changes occur on a Sunday, but in March, the 1st is a Sunday itself and in November
the 1st is also a Sunday. If we don't decrement "pos" by one, tmpDate (which is set to March or November 1st
because of "day: 1" will have 14 more days added for March and 7 more days added for November - which will
effectively shift the time change by a whole week.
In Europe/Berlin, we have a different use-case for November. In 2015, November 1st is a Sunday.
The time change in November must occur on October 25th but since tmpDate will be November 1st,
so a Sunday, dateDayOfWeek will be 0 and dayOfWeek will also be 0 we would decrement tmpDate by 14 days,
which is incorrect because it would shift the timezone change one week earlier. We take care about this
one with check if pos is greater or equal than 0 and if so, we don't decrement it.
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
*/
if (dayOfWeek == dateDayOfWeek)
if (dayOfWeek == dateDayOfWeek && pos >= 0)
pos--;
offset = (dayOfWeek - dateDayOfWeek) + (pos * 7);
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python
import sys
import os
import re
DEBUG=False
dir_mappings = {"../UI/Templates":"../UI/Common",
"../UI/Templates/AdministrationUI":"../UI/AdministrationUI",
"../UI/Templates/Appointments":"../SoObjects/Appointments",
"../UI/Templates/ContactsUI":"../UI/Contacts",
"../UI/Templates/MailerUI":"../UI/MailerUI",
"../UI/Templates/MailPartViewers":"../UI/MailPartViewers",
"../UI/Templates/MainUI":"../UI/MainUI",
"../UI/Templates/PreferencesUI":"../UI/PreferencesUI",
"../UI/Templates/SchedulerUI":"../UI/Scheduler"
}
def get_translations(path):
try:
transpath = dir_mappings.get(path, path)
transname = transpath + '/English.lproj/Localizable.strings'
transall = open(transname).read()
except:
transall = ""
return transall
def find_missing_translations(rootdir='.', extention='', recomp=None, greylist=()):
for path, dirs, files in os.walk(rootdir):
filelist = [f for f in files if f[(-1 * len(extention)):] == extention]
if filelist:
for filename in filelist:
if filename in greylist:
print "%s is greylisted -- SKIPPING" % filename
continue
pathname = path + '/' + filename
lines = open(pathname).read().split("\n")
values = [r.groups()[0] for r in [recomp.search(l) for l in lines] if r]
if values:
#- Get the current english translations for the path
transgood = get_translations(path)
if not transgood:
print "No translation file found for %s, skipping %s" % (path, pathname)
continue
notfound = list()
if DEBUG:print pathname
for value in values:
#- Try to find the value from the source file in the translation file
escaped_value = re.escape(value)
found = re.search('(%s|"%s")\s*=\s*"(.*?)";' % (escaped_value, escaped_value), transgood)
if found:
if DEBUG: print "\t", '[%s] FOUND -- "%s"' % found.groups()
else:
notfound.append("-->\t[%s] ==== Not Found ====" % value)
if notfound:
if not DEBUG:print pathname
print "\n".join(notfound)
def main():
#- Only one option...
if len(sys.argv) > 1:
if sys.argv[1] == '-g':
global DEBUG
DEBUG = True
else:
print 'Usage:', sys.argv[0], '[-g]\n\t\t-g: debug will show matching also'
sys.exit(1)
greylist = ('UIxFilterEditor.wox')
#- Get only the label:value from all lines
recomp = re.compile(' label:[^=]*="(.*?)"')
find_missing_translations('../UI', 'wox', recomp, greylist)
#- [self labelForKey: @"Issuer"]
recomp = re.compile('\[self labelForKey: @"(.*?)"\]')
find_missing_translations('../UI', 'm', recomp, ())
main()
@@ -11,16 +11,16 @@ vtodo_class2 = "(مهمة سرية)";
"The event \"%{Summary}\" was created" = "أُنشِئ الحدث \"%{Summary}\"";
"The event \"%{Summary}\" was deleted" = "حُذِفَ الحدث \"%{Summary}\"";
"The event \"%{Summary}\" was updated" = "حُدِّث الحدث \"%{Summary}\"";
"The following attendees(s) were notified:" = "تم ابلاغ المدعو (المدعويين) الأتي أسماءهم:";
"The following attendees(s) were added:" = "تم أضافة المدعو (المدعويين) الأتي أسماءهم:";
"The following attendees(s) were removed:" = "تم مسح المدعو (المدعويين) الأتي أسماءهم:";
"The following attendees(s) were notified" = "تم ابلاغ المدعو (المدعويين) الأتي أسماءهم";
"The following attendees(s) were added" = "تم أضافة المدعو (المدعويين) الأتي أسماءهم";
"The following attendees(s) were removed" = "تم مسح المدعو (المدعويين) الأتي أسماءهم";
/* IMIP messages */
"calendar_label" = "التقويم:";
"startDate_label" = "البداية:";
"endDate_label" = "النهاية:";
"calendar_label" = "التقويم";
"startDate_label" = "البداية";
"endDate_label" = "النهاية";
"due_label" = "تاريخ الاستحقاق:";
"location_label" = "المكان:";
"location_label" = "المكان";
"summary_label" = "الملخص:";
"comment_label" = "التعليق:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Isilpeko egitekoa)";
"The event \"%{Summary}\" was created" = "\"%{Summary}\" ekitaldia sortu da";
"The event \"%{Summary}\" was deleted" = "\"%{Summary}\" ekitaldia ezabatu da";
"The event \"%{Summary}\" was updated" = "\"%{Summary}\" ekitaldia eguneratu da";
"The following attendees(s) were notified:" = "Ondorengo partaidea(k) jakinarazi d(ir)a:";
"The following attendees(s) were added:" = "Ondorengo partaidea(k) gehitu d(ir)a:";
"The following attendees(s) were removed:" = "Ondorengo partaidea(k) ezabatu d(ir)a:";
"The following attendees(s) were notified" = "Ondorengo partaidea(k) jakinarazi d(ir)a";
"The following attendees(s) were added" = "Ondorengo partaidea(k) gehitu d(ir)a";
"The following attendees(s) were removed" = "Ondorengo partaidea(k) ezabatu d(ir)a";
/* IMIP messages */
"calendar_label" = "Egutegia";
"startDate_label" = "Hasi:";
"endDate_label" = "Amaitu:";
"startDate_label" = "Hasi";
"endDate_label" = "Amaitu";
"due_label" = "Epemuga:";
"location_label" = "Kokapena:";
"location_label" = "Kokapena";
"summary_label" = "Laburpena:";
"comment_label" = "Iruzkina:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarefa Confidencial)";
"The event \"%{Summary}\" was created" = "O evento \"%{Summary}\" foi criado";
"The event \"%{Summary}\" was deleted" = "O evento \"%{Summary}\" foi removido";
"The event \"%{Summary}\" was updated" = "O evento \"%{Summary}\" foi atualizado";
"The following attendees(s) were notified:" = "Estes participantes foram notificados:";
"The following attendees(s) were added:" = "Estes participantes foram adicionados:";
"The following attendees(s) were removed:" = "Estes participantes foram removidos:";
"The following attendees(s) were notified" = "Estes participantes foram notificados";
"The following attendees(s) were added" = "Estes participantes foram adicionados";
"The following attendees(s) were removed" = "Estes participantes foram removidos";
/* IMIP messages */
"calendar_label" = "Calendário:";
"startDate_label" = "Início:";
"endDate_label" = "Fim:";
"calendar_label" = "Calendário";
"startDate_label" = "Início";
"endDate_label" = "Fim";
"due_label" = "Data de Vencimento:";
"location_label" = "Local:";
"location_label" = "Local";
"summary_label" = "Resumo:";
"comment_label" = "Comentário:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tasca confidencial)";
"The event \"%{Summary}\" was created" = "Es va crear l'esdeveniment \"%{Summary}\" ";
"The event \"%{Summary}\" was deleted" = "Es va esborrar l'esdeveniment \"%{Summary}\" ";
"The event \"%{Summary}\" was updated" = "Es va modificar l'esdeveniment \"%{Summary}\" ";
"The following attendees(s) were notified:" = "I va notificar als següents participants: ";
"The following attendees(s) were added:" = "Es van agregar els següents participants: ";
"The following attendees(s) were removed:" = "Heu suprimit els assistents següents:";
"The following attendees(s) were notified" = "I va notificar als següents participants ";
"The following attendees(s) were added" = "Es van agregar els següents participants ";
"The following attendees(s) were removed" = "Heu suprimit els assistents següents";
/* IMIP messages */
"calendar_label" = "Calendari:";
"startDate_label" = "Inici:";
"endDate_label" = "Final:";
"calendar_label" = "Calendari";
"startDate_label" = "Inici";
"endDate_label" = "Final";
"due_label" = "Data límit:";
"location_label" = "Lloc:";
"location_label" = "Lloc";
"summary_label" = "Resum:";
"comment_label" = "Comentari:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(機密任務)";
"The event \"%{Summary}\" was created" = "事件 \"%{Summary}\" 已建立";
"The event \"%{Summary}\" was deleted" = "事件\"%{Summary}\" 已刪除";
"The event \"%{Summary}\" was updated" = "事件\"%{Summary}\" 已異動";
"The following attendees(s) were notified:" = "已通知下列出席者:";
"The following attendees(s) were added:" = "已增加下列出席者:";
"The following attendees(s) were removed:" = "已移除下列出席者:";
"The following attendees(s) were notified" = "已通知下列出席者";
"The following attendees(s) were added" = "已增加下列出席者";
"The following attendees(s) were removed" = "已移除下列出席者";
/* IMIP messages */
"calendar_label" = "行事曆:";
"startDate_label" = "開始:";
"endDate_label" = "結束:";
"calendar_label" = "行事曆";
"startDate_label" = "開始";
"endDate_label" = "結束";
"due_label" = "截止日期:";
"location_label" = "地點:";
"location_label" = "地點";
"summary_label" = "事件主題:";
"comment_label" = "備註:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Skrytý úkol)";
"The event \"%{Summary}\" was created" = "Událost \"%{Summary}\" byla vytvořena";
"The event \"%{Summary}\" was deleted" = "Událost \"%{Summary}\" byla smazána";
"The event \"%{Summary}\" was updated" = "Událost \"%{Summary}\" byla upravena";
"The following attendees(s) were notified:" = "Následující účastníci byli upozorněni:";
"The following attendees(s) were added:" = "Následující účastníci byli přidáni:";
"The following attendees(s) were removed:" = "Následující účastníci byli odebráni:";
"The following attendees(s) were notified" = "Následující účastníci byli upozorněni";
"The following attendees(s) were added" = "Následující účastníci byli přidáni";
"The following attendees(s) were removed" = "Následující účastníci byli odebráni";
/* IMIP messages */
"calendar_label" = "Kalendář:";
"startDate_label" = "Začátek:";
"endDate_label" = "Konec:";
"calendar_label" = "Kalendář";
"startDate_label" = "Začátek";
"endDate_label" = "Konec";
"due_label" = "Termín:";
"location_label" = "Místo:";
"location_label" = "Místo";
"summary_label" = "Název:";
"comment_label" = "Komentář:";
@@ -11,16 +11,16 @@ vtodo_class2 = "(Hemmelig opgave)";
"The event \"%{Summary}\" was created" = "Begivenheden \"%{Summary}\" blev oprettet";
"The event \"%{Summary}\" was deleted" = "Begivenheden \"%{Summary}\" blev slettet";
"The event \"%{Summary}\" was updated" = "Begivenheden \"%{Summary}\" blev opdateret";
"The following attendees(s) were notified:" = "Følgende deltager(e) blev underrettet:";
"The following attendees(s) were added:" = "Følgende deltager(e) blev tilføjet:";
"The following attendees(s) were removed:" = "Følgende deltager(e) blev fjernet:";
"The following attendees(s) were notified" = "Følgende deltager(e) blev underrettet";
"The following attendees(s) were added" = "Følgende deltager(e) blev tilføjet";
"The following attendees(s) were removed" = "Følgende deltager(e) blev fjernet";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Start:";
"endDate_label" = "Slut:";
"calendar_label" = "Kalender";
"startDate_label" = "Start";
"endDate_label" = "Slut";
"due_label" = "Forfaldsdato:";
"location_label" = "Sted:";
"location_label" = "Sted";
"summary_label" = "Resumé:";
"comment_label" = "Kommentér:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Vertrouwelijke taak)";
"The event \"%{Summary}\" was created" = "De gebeurtenis \"%{Summary}\" is aangemaakt";
"The event \"%{Summary}\" was deleted" = "De gebeurtenis \"%{Summary}\" is verwijderd";
"The event \"%{Summary}\" was updated" = "De gebeurtenis \"%{Summary}\" is gewijzigd";
"The following attendees(s) were notified:" = "De volgende deelnemers zijn in kennis gesteld:";
"The following attendees(s) were added:" = "De volgende deelnemers zijn toegevoegd:";
"The following attendees(s) were removed:" = "De volgende deelnemers zijn verwijderd:";
"The following attendees(s) were notified" = "De volgende deelnemers zijn in kennis gesteld";
"The following attendees(s) were added" = "De volgende deelnemers zijn toegevoegd";
"The following attendees(s) were removed" = "De volgende deelnemers zijn verwijderd";
/* IMIP messages */
"calendar_label" = "Agenda:";
"startDate_label" = "Start:";
"endDate_label" = "Einde:";
"calendar_label" = "Agenda";
"startDate_label" = "Start";
"endDate_label" = "Einde";
"due_label" = "Vervaldag:";
"location_label" = "Locatie:";
"location_label" = "Locatie";
"summary_label" = "Samenvatting:";
"comment_label" = "Commentaar:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Confidential task)";
"The event \"%{Summary}\" was created" = "The event \"%{Summary}\" was created";
"The event \"%{Summary}\" was deleted" = "The event \"%{Summary}\" was deleted";
"The event \"%{Summary}\" was updated" = "The event \"%{Summary}\" was updated";
"The following attendees(s) were notified:" = "The following attendee(s) were notified:";
"The following attendees(s) were added:" = "The following attendee(s) were added:";
"The following attendees(s) were removed:" = "The following attendee(s) were removed:";
"The following attendees(s) were notified" = "The following attendee(s) were notified";
"The following attendees(s) were added" = "The following attendee(s) were added";
"The following attendees(s) were removed" = "The following attendee(s) were removed";
/* IMIP messages */
"calendar_label" = "Calendar:";
"startDate_label" = "Start:";
"endDate_label" = "End:";
"calendar_label" = "Calendar";
"startDate_label" = "Start";
"endDate_label" = "End";
"due_label" = "Due Date:";
"location_label" = "Location:";
"location_label" = "Location";
"summary_label" = "Summary:";
"comment_label" = "Comment:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Luottamuksellinen tehtävä)";
"The event \"%{Summary}\" was created" = "Tapahtuma \"%{Summary}\" luotiin";
"The event \"%{Summary}\" was deleted" = "Tapahtuma \"%{Summary}\" poistettiin";
"The event \"%{Summary}\" was updated" = "Tapahtuma \"%{Summary}\" päivitettiin";
"The following attendees(s) were notified:" = "Seuraava(t) osallistuja(t) on informoitu:";
"The following attendees(s) were added:" = "Seuraava(t) osalllistuja(t) on lisätty:";
"The following attendees(s) were removed:" = "Seuraava(t) osalllistuja(t) poistettiin:";
"The following attendees(s) were notified" = "Seuraava(t) osallistuja(t) on informoitu";
"The following attendees(s) were added" = "Seuraava(t) osalllistuja(t) on lisätty";
"The following attendees(s) were removed" = "Seuraava(t) osalllistuja(t) poistettiin";
/* IMIP messages */
"calendar_label" = "Kalenteri:";
"startDate_label" = "Alkaa:";
"endDate_label" = "Päättyy:";
"calendar_label" = "Kalenteri";
"startDate_label" = "Alkaa";
"endDate_label" = "Päättyy";
"due_label" = "Määräpäivä:";
"location_label" = "Sijainti:";
"location_label" = "Sijainti";
"summary_label" = "Yhteenveto:";
"comment_label" = "Kommentti:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tâche confidentielle)";
"The event \"%{Summary}\" was created" = "L'événement «%{Summary}» a été créé";
"The event \"%{Summary}\" was deleted" = "L'événement «%{Summary}» a été effacé";
"The event \"%{Summary}\" was updated" = "L'événement «%{Summary}» a été modifié";
"The following attendees(s) were notified:" = "Les invités suivants ont été avisés :";
"The following attendees(s) were added:" = "Les invités suivants ont été ajoutés :";
"The following attendees(s) were removed:" = "Les invités suivants ont été supprimés :";
"The following attendees(s) were notified" = "Les invités suivants ont été avisés ";
"The following attendees(s) were added" = "Les invités suivants ont été ajoutés ";
"The following attendees(s) were removed" = "Les invités suivants ont été supprimés ";
/* IMIP messages */
"calendar_label" = "Agenda :";
"startDate_label" = "Début :";
"endDate_label" = "Fin :";
"calendar_label" = "Agenda ";
"startDate_label" = "Début ";
"endDate_label" = "Fin ";
"due_label" = "Fin prévue :";
"location_label" = "Lieu :";
"location_label" = "Lieu ";
"summary_label" = "Titre :";
"comment_label" = "Description :";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
"The event \"%{Summary}\" was created" = "Der Termin \"%{Summary}\" wurde angelegt";
"The event \"%{Summary}\" was deleted" = "Der Termin \"%{Summary}\" wurde gelöscht";
"The event \"%{Summary}\" was updated" = "Der Termin \"%{Summary}\" wurde geändert";
"The following attendees(s) were notified:" = "Die folgenden Teilnehmer wurden benachrichtigt:";
"The following attendees(s) were added:" = "Die folgenden Teilnehmer wurden hinzugefügt:";
"The following attendees(s) were removed:" = "Die folgenden Teilnehmer wurden entfernt:";
"The following attendees(s) were notified" = "Die folgenden Teilnehmer wurden benachrichtigt";
"The following attendees(s) were added" = "Die folgenden Teilnehmer wurden hinzugefügt";
"The following attendees(s) were removed" = "Die folgenden Teilnehmer wurden entfernt";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Beginn:";
"endDate_label" = "Ende:";
"calendar_label" = "Kalender";
"startDate_label" = "Beginn";
"endDate_label" = "Ende";
"due_label" = "Fälligkeit:";
"location_label" = "Ort:";
"location_label" = "Ort";
"summary_label" = "Zusammenfassung:";
"comment_label" = "Kommentar:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Bizalmas feladat)";
"The event \"%{Summary}\" was created" = "A \"%{Summary}\" esemény létre lett hozva";
"The event \"%{Summary}\" was deleted" = "A \"%{Summary}\" esemény törölve lett";
"The event \"%{Summary}\" was updated" = "A \"%{Summary}\" esemény módosítva lett";
"The following attendees(s) were notified:" = "Az alábbi résztvevők lettek értesítve:";
"The following attendees(s) were added:" = "Az alábbi résztvevők lettek hozzáadva:";
"The following attendees(s) were removed:" = "Az alábbi résztvevők lettek eltávolítva:";
"The following attendees(s) were notified" = "Az alábbi résztvevők lettek értesítve";
"The following attendees(s) were added" = "Az alábbi résztvevők lettek hozzáadva";
"The following attendees(s) were removed" = "Az alábbi résztvevők lettek eltávolítva";
/* IMIP messages */
"calendar_label" = "Naptár:";
"startDate_label" = "Kezdete:";
"endDate_label" = "Vége:";
"calendar_label" = "Naptár";
"startDate_label" = "Kezdete";
"endDate_label" = "Vége";
"due_label" = "Lejárat napja:";
"location_label" = "Hely:";
"location_label" = "Hely";
"summary_label" = "Összegzés:";
"comment_label" = "Megjegyzés:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Verkefni er trúnaðarmál)";
"... from the following event:" = "... af eftirfarandi viðburði:";
/* IMIP messages */
"startDate_label" = "Byrjun:";
"endDate_label" = "Endir:";
"startDate_label" = "Byrjun";
"endDate_label" = "Endir";
"due_label" = "Lokadagur:";
"location_label" = "Staðsetning:";
"location_label" = "Staðsetning";
"summary_label" = "Samantekt:";
"comment_label" = "Athugasemd:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Attività confidenziale)";
"... from the following event:" = "... dal seguente evento:";
/* IMIP messages */
"startDate_label" = "Inizio:";
"endDate_label" = "Fine:";
"startDate_label" = "Inizio";
"endDate_label" = "Fine";
"due_label" = "Scadenza:";
"location_label" = "Luogo:";
"location_label" = "Luogo";
"summary_label" = "Summario:";
"comment_label" = "Commento:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Konfidensiell oppgave)";
"The event \"%{Summary}\" was created" = "Hendelsen \"%{Summary}\" ble opprettet";
"The event \"%{Summary}\" was deleted" = "Hendelsen \"%{Summary}\" ble slettet";
"The event \"%{Summary}\" was updated" = "Hendelsen \"%{Summary}\" ble oppdatert";
"The following attendees(s) were notified:" = "Følgende deltaker(e) ble varslet:";
"The following attendees(s) were added:" = "Følgende deltaker(e) ble lagt til:";
"The following attendees(s) were removed:" = "Følgende deltaker(e) ble fjernet:";
"The following attendees(s) were notified" = "Følgende deltaker(e) ble varslet";
"The following attendees(s) were added" = "Følgende deltaker(e) ble lagt til";
"The following attendees(s) were removed" = "Følgende deltaker(e) ble fjernet";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Start:";
"endDate_label" = "Slutt:";
"calendar_label" = "Kalender";
"startDate_label" = "Start";
"endDate_label" = "Slutt";
"due_label" = "Forfallsdato:";
"location_label" = "Sted:";
"location_label" = "Sted";
"summary_label" = "Sammendrag:";
"comment_label" = "Kommentar:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Konfidensiell oppgave)";
"... from the following event:" = "... fra følgende hendelse:";
/* IMIP messages */
"startDate_label" = "Start:";
"endDate_label" = "End:";
"startDate_label" = "Start";
"endDate_label" = "End";
"due_label" = "Due Date:";
"location_label" = "Location:";
"location_label" = "Location";
"summary_label" = "Summary:";
"comment_label" = "Comment:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Zadanie poufne)";
"The event \"%{Summary}\" was created" = "Utworzono wydarzenie \"%{Summary}\"";
"The event \"%{Summary}\" was deleted" = "Skasowano wydarzenie \"%{Summary}\"";
"The event \"%{Summary}\" was updated" = "Zaktualizowano wydarzenie \"%{Summary}\"";
"The following attendees(s) were notified:" = "Następujący uczestnicy zostali powiadomieni:";
"The following attendees(s) were added:" = "Następujący uczestnicy zostali dodani:";
"The following attendees(s) were removed:" = "Następujący uczestnicy zostali usunięci:";
"The following attendees(s) were notified" = "Następujący uczestnicy zostali powiadomieni";
"The following attendees(s) were added" = "Następujący uczestnicy zostali dodani";
"The following attendees(s) were removed" = "Następujący uczestnicy zostali usunięci";
/* IMIP messages */
"calendar_label" = "Kalendarz:";
"startDate_label" = "Początek:";
"endDate_label" = "Koniec:";
"calendar_label" = "Kalendarz";
"startDate_label" = "Początek";
"endDate_label" = "Koniec";
"due_label" = "Termin:";
"location_label" = "Miejsce:";
"location_label" = "Miejsce";
"summary_label" = "Podsumowanie:";
"comment_label" = "Komentarz:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Конфиденциальная задача)";
"The event \"%{Summary}\" was created" = "Было создано мероприятие \"%{Summary}\"";
"The event \"%{Summary}\" was deleted" = "Мероприятие \"%{Summary}\" было удалено";
"The event \"%{Summary}\" was updated" = "Мероприятие \"%{Summary}\" было обновлено";
"The following attendees(s) were notified:" = "Следующие приглашенные были оповещены:";
"The following attendees(s) were added:" = "Следующие люди были добавлены в список приглашенных:";
"The following attendees(s) were removed:" = "Следующие люди были исключены из списка приглашенных:";
"The following attendees(s) were notified" = "Следующие приглашенные были оповещены";
"The following attendees(s) were added" = "Следующие люди были добавлены в список приглашенных";
"The following attendees(s) were removed" = "Следующие люди были исключены из списка приглашенных";
/* IMIP messages */
"calendar_label" = "Календарь:";
"startDate_label" = "Начало:";
"endDate_label" = "Конец:";
"calendar_label" = "Календарь";
"startDate_label" = "Начало";
"endDate_label" = "Конец";
"due_label" = "Должно быть готово к:";
"location_label" = "Местонахождение:";
"location_label" = "Местонахождение";
"summary_label" = "Краткое содержание:";
"comment_label" = "Комментарий:";
@@ -2980,7 +2980,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
theUser = [SOGoUser userWithLogin: theUID];
aParent = [theUser calendarsFolderInContext: context];
if ([aParent isKindOfClass: [NSException class]])
return nil;
aFolders = [aParent subFolders];
e = [aFolders objectEnumerator];
while ((aFolder = [e nextObject]))
@@ -11,16 +11,16 @@ vtodo_class2 = "(Dôverná úloha)";
"The event \"%{Summary}\" was created" = "Udalosť \"%{Summary}\" bola vytvorená";
"The event \"%{Summary}\" was deleted" = "Udalosť \"%{Summary}\" bola vymazaná";
"The event \"%{Summary}\" was updated" = "Udalosť \"%{Summary}\" bola aktualizovaná";
"The following attendees(s) were notified:" = "Nasledujúci účastník(ci) bol upozornený:";
"The following attendees(s) were added:" = "Nasledujúci účastník(ci) bol pridaný:";
"The following attendees(s) were removed:" = "Nasledujúci účastník(ci) bol odstránený:";
"The following attendees(s) were notified" = "Nasledujúci účastník(ci) bol upozornený";
"The following attendees(s) were added" = "Nasledujúci účastník(ci) bol pridaný";
"The following attendees(s) were removed" = "Nasledujúci účastník(ci) bol odstránený";
/* IMIP messages */
"calendar_label" = "Kalendár:";
"startDate_label" = "Začiatok:";
"endDate_label" = "Koniec:";
"calendar_label" = "Kalendár";
"startDate_label" = "Začiatok";
"endDate_label" = "Koniec";
"due_label" = "Platnosť:";
"location_label" = "Miesto:";
"location_label" = "Miesto";
"summary_label" = "Zhrnutie:";
"comment_label" = "Komentár:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Zaupno opravilo)";
"The event \"%{Summary}\" was created" = "Dogodek \"%{Summary}\" je bil ustvarjen";
"The event \"%{Summary}\" was deleted" = "Dogodek \"%{Summary}\" je bil izbrisan";
"The event \"%{Summary}\" was updated" = "Dogodek \"%{Summary}\" je bil posodobljen";
"The following attendees(s) were notified:" = "Naslednji udeleženci so bili obveščeni:";
"The following attendees(s) were added:" = "Naslednji udeleženci so bili dodani:";
"The following attendees(s) were removed:" = "Naslednji udeleženci so bili odstranjeni:";
"The following attendees(s) were notified" = "Naslednji udeleženci so bili obveščeni";
"The following attendees(s) were added" = "Naslednji udeleženci so bili dodani";
"The following attendees(s) were removed" = "Naslednji udeleženci so bili odstranjeni";
/* IMIP messages */
"calendar_label" = "Koledar:";
"startDate_label" = "Začetek:";
"endDate_label" = "Konec:";
"calendar_label" = "Koledar";
"startDate_label" = "Začetek";
"endDate_label" = "Konec";
"due_label" = "Datum zapadlosti:";
"location_label" = "Mesto:";
"location_label" = "Mesto";
"summary_label" = "Povzetek:";
"comment_label" = "Komentar:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarea confidencial)";
"The event \"%{Summary}\" was created" = "Se creó el evento \"%{Summary}\"";
"The event \"%{Summary}\" was deleted" = "Se borró el evento \"%{Summary}\"";
"The event \"%{Summary}\" was updated" = "Se actualizó la información del evento \"%{Summary}\"";
"The following attendees(s) were notified:" = "Se notificó a los siguientes participantes:";
"The following attendees(s) were added:" = "Se agregaron los siguientes participantes:";
"The following attendees(s) were removed:" = "Se removieron los siguientes participantes:";
"The following attendees(s) were notified" = "Se notificó a los siguientes participantes";
"The following attendees(s) were added" = "Se agregaron los siguientes participantes";
"The following attendees(s) were removed" = "Se removieron los siguientes participantes";
/* IMIP messages */
"calendar_label" = "Calendario:";
"startDate_label" = "Inicio:";
"endDate_label" = "Fin:";
"calendar_label" = "Calendario";
"startDate_label" = "Inicio";
"endDate_label" = "Fin";
"due_label" = "Fecha de finalización:";
"location_label" = "Lugar:";
"location_label" = "Lugar";
"summary_label" = "Resumen:";
"comment_label" = "Comentario:";
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarea confidencial)";
"The event \"%{Summary}\" was created" = "El evento \"%{Summary}\" ha sido creado";
"The event \"%{Summary}\" was deleted" = "El evento \"%{Summary}\" ha sido borrado";
"The event \"%{Summary}\" was updated" = "El evento \"%{Summary}\" ha sido actualizado";
"The following attendees(s) were notified:" = "Los invitados siguientes han sido notificado:";
"The following attendees(s) were added:" = "Los invitados siguientes han sido añadido:";
"The following attendees(s) were removed:" = "Los invitados siguientes han sido quitado:";
"The following attendees(s) were notified" = "Los invitados siguientes han sido notificado";
"The following attendees(s) were added" = "Los invitados siguientes han sido añadido";
"The following attendees(s) were removed" = "Los invitados siguientes han sido quitado";
/* IMIP messages */
"calendar_label" = "Calendario:";
"startDate_label" = "Inicio:";
"endDate_label" = "Fin:";
"calendar_label" = "Calendario";
"startDate_label" = "Inicio";
"endDate_label" = "Fin";
"due_label" = "Fecha Fin:";
"location_label" = "Localización:";
"location_label" = "Localización";
"summary_label" = "Resumen:";
"comment_label" = "Comentario:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Konfidentiell uppgift)";
"... from the following event:" = "... från följande händelse:";
/* IMIP messages */
"startDate_label" = "Startdatum:";
"endDate_label" = "Slutdatum:";
"startDate_label" = "Startdatum";
"endDate_label" = "Slutdatum";
"due_label" = "Datum:";
"location_label" = "Plats:";
"location_label" = "Plats";
"summary_label" = "Sammanfattning:";
"comment_label" = "Kommentar:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Конфіденційне завдання)";
"... from the following event:" = "... з участі в події:";
/* IMIP messages */
"startDate_label" = "Початок:";
"endDate_label" = "Кінець:";
"startDate_label" = "Початок";
"endDate_label" = "Кінець";
"due_label" = "Триватиме до:";
"location_label" = "Місце:";
"location_label" = "Місце";
"summary_label" = "Резюме:";
"comment_label" = "Коментар:";
@@ -25,10 +25,10 @@ vtodo_class2 = "(Tasg gyfrinachol)";
"... from the following event:" = "... from the following event:";
/* IMIP messages */
"startDate_label" = "Start:";
"endDate_label" = "End:";
"startDate_label" = "Start";
"endDate_label" = "End";
"due_label" = "Due Date:";
"location_label" = "Location:";
"location_label" = "Location";
"summary_label" = "Summary:";
"comment_label" = "Comment:";
+2 -1
View File
@@ -98,7 +98,8 @@
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties
matchingSyncToken: (NSString *) syncToken
fromDate: (NSCalendarDate *) theStartDate;
fromDate: (NSCalendarDate *) theStartDate
initialLoad: (BOOL) initialLoadInProgress;
/* flags */
+6 -2
View File
@@ -1553,7 +1553,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
- (NSString *) displayName
{
return [self relativeImap4Name];
return [[self relativeImap4Name] stringByDecodingImap4FolderName];
}
- (NSDictionary *) davIMAPFieldsTable
@@ -2090,6 +2090,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
- (NSArray *) syncTokenFieldsWithProperties: (NSArray *) theProperties
matchingSyncToken: (NSString *) theSyncToken
fromDate: (NSCalendarDate *) theStartDate
initialLoad: (BOOL) initialLoadInProgress
{
EOQualifier *searchQualifier;
NSMutableArray *allTokens;
@@ -2166,6 +2167,9 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
for (i = 0; i < [fetchResults count]; i++)
{
if ([[[fetchResults objectAtIndex: i] objectForKey: @"flags"] containsObject: @"deleted"] && initialLoadInProgress)
continue;
d = [NSDictionary dictionaryWithObject: ([[[fetchResults objectAtIndex: i] objectForKey: @"flags"] containsObject: @"deleted"]) ? [NSNull null] : [[fetchResults objectAtIndex: i] objectForKey: @"modseq"]
forKey: [[[fetchResults objectAtIndex: i] objectForKey: @"uid"] stringValue]];
[allTokens addObject: d];
@@ -2176,7 +2180,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (highestmodseq == 0)
highestmodseq = 1;
if (highestmodseq > 0)
if (highestmodseq > 0 && !initialLoadInProgress)
{
id uid;
+8 -2
View File
@@ -373,6 +373,7 @@ static int cssEscapingCount;
- (NSString *) asCSSIdentifier
{
NSCharacterSet *numericSet;
NSMutableString *cssIdentifier;
unichar currentChar;
int count, max, idx;
@@ -381,10 +382,12 @@ static int cssEscapingCount;
[self _setupCSSEscaping];
cssIdentifier = [NSMutableString string];
numericSet = [NSCharacterSet decimalDigitCharacterSet];
max = [self length];
if (max > 0)
{
if (isdigit([self characterAtIndex: 0]))
if ([numericSet characterIsMember: [self characterAtIndex: 0]])
// A CSS identifier can't start with a digit; we add an underscore
[cssIdentifier appendString: @"_"];
for (count = 0; count < max; count++)
@@ -415,6 +418,7 @@ static int cssEscapingCount;
- (NSString *) fromCSSIdentifier
{
NSCharacterSet *numericSet;
NSMutableString *newString;
NSString *currentString;
int count, length, max, idx;
@@ -423,12 +427,14 @@ static int cssEscapingCount;
if (!cssEscapingStrings)
[self _setupCSSEscaping];
numericSet = [NSCharacterSet decimalDigitCharacterSet];
newString = [NSMutableString string];
max = [self length];
count = 0;
if (max > 0
&& [self characterAtIndex: 0] == '_'
&& isdigit([self characterAtIndex: 1]))
&& [numericSet characterIsMember: [self characterAtIndex: 1]])
{
/* If the identifier starts with an underscore followed by a digit,
we remove the underscore */
-2
View File
@@ -87,8 +87,6 @@
$label5 = ("Later", "#993399");
};
SOGoCalendarCategories = ("Customer", "Calls", "Favorites", "Meeting", "Ideas", "Miscellaneous", "Birthday", "Anniversary", "Vacation", "Travel", "Projects", "Suppliers", "Gifts", "Clients", "Issues", "Business", "Holidays", "Personal", "Status", "Competition", "Follow up", "Public Holiday");
SOGoCalendarCategoriesColors = { "Customer" = "#F0F0F0"; "Calls" = "#F0F0F0"; "Favorites" = "#F0F0F0"; "Meeting" = "#F0F0F0"; "Ideas" = "#F0F0F0"; "Miscellaneous" = "#F0F0F0"; "Birthday" = "#F0F0F0"; "Anniversary" = "#F0F0F0"; "Vacation" = "#F0F0F0"; "Travel" = "#F0F0F0"; "Projects" = "#F0F0F0"; "Suppliers" = "#F0F0F0"; "Gifts" = "#F0F0F0"; "Clients" = "#F0F0F0"; "Issues" = "#F0F0F0"; "Business" = "#F0F0F0"; "Holidays" = "#F0F0F0"; "Personal" = "#F0F0F0"; "Status" = "#F0F0F0"; "Competition" = "#F0F0F0"; "Follow up" = "#F0F0F0"; "Public Holiday" = "#F0F0F0"; };
SOGoSubscriptionFolderFormat = "%{FolderName} (%{UserName} <%{Email}>)";
+2 -2
View File
@@ -128,8 +128,8 @@
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties
matchingSyncToken: (NSString *) syncToken
fromDate: (NSCalendarDate *) theStartDate;
fromDate: (NSCalendarDate *) theStartDate
initialLoad: (BOOL) initialLoadInProgress;
/* multiget helper */
- (WOResponse *) performMultigetInContext: (WOContext *) queryContext
+15 -8
View File
@@ -1151,6 +1151,7 @@ static NSArray *childRecordFields = nil;
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties
matchingSyncToken: (NSString *) syncToken
fromDate: (NSCalendarDate *) theStartDate
initialLoad: (BOOL) initialLoadInProgress
{
/* TODO:
- validation:
@@ -1200,13 +1201,17 @@ static NSArray *childRecordFields = nil;
mRecords = [NSMutableArray arrayWithArray: [self _fetchFields: fields
withQualifier: qualifier
ignoreDeleted: YES]];
qualifier = [EOQualifier qualifierWithQualifierFormat:
@"c_lastmodified > %d and c_deleted == 1",
syncTokenInt];
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_lastmodified", @"c_deleted", nil];
[mRecords addObjectsFromArray: [self _fetchFields: fields
withQualifier: qualifier
ignoreDeleted: NO]];
if (!initialLoadInProgress)
{
qualifier = [EOQualifier qualifierWithQualifierFormat:
@"c_lastmodified > %d and c_deleted == 1",
syncTokenInt];
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_lastmodified", @"c_deleted", nil];
[mRecords addObjectsFromArray: [self _fetchFields: fields
withQualifier: qualifier
ignoreDeleted: NO]];
}
records = mRecords;
}
else
@@ -1499,7 +1504,9 @@ static NSArray *childRecordFields = nil;
properties = [self parseDAVRequestedProperties: propElement];
records = [self syncTokenFieldsWithProperties: properties
matchingSyncToken: syncToken
fromDate: nil];
fromDate: nil
initialLoad: NO];
[self _appendComponentProperties: [properties allKeys]
fromRecords: records
matchingSyncToken: [syncToken intValue]
+18 -4
View File
@@ -394,11 +394,22 @@ static Class NSNullK;
- (NSString *) getUIDForEmail: (NSString *) email
{
NSDictionary *contactInfos;
NSDictionary *info;
SOGoSystemDefaults *sd;
NSString *uid, *domain;
contactInfos = [self contactInfosForUserWithUIDorEmail: email];
info = [self contactInfosForUserWithUIDorEmail: email];
uid = [info objectForKey: @"c_uid"];
return [contactInfos objectForKey: @"c_uid"];
sd = [SOGoSystemDefaults sharedSystemDefaults];
if ([sd enableDomainBasedUID]
&& ![[info objectForKey: @"DomainLessLogin"] boolValue])
{
domain = [info objectForKey: @"c_domain"];
uid = [NSString stringWithFormat: @"%@@%@", uid, domain];
}
return uid;
}
- (BOOL) _sourceChangePasswordForLogin: (NSString *) login
@@ -769,7 +780,10 @@ static Class NSNullK;
NSRange r;
r = [theUID rangeOfString: [NSString stringWithFormat: @"@%@", theDomain]];
theUID = [theUID substringToIndex: r.location];
// We check if the range is ok here since we could be using DomainLessLogin
if (r.location != NSNotFound)
theUID = [theUID substringToIndex: r.location];
}
sogoSources = [[self authenticationSourceIDsInDomain: theDomain] objectEnumerator];
+2
View File
@@ -22,6 +22,8 @@ $(TEST_TOOL)_OBJC_FILES += \
TestSBJsonParser.m \
\
TestNGMimeAddressHeaderFieldGenerator.m \
TestNGMimeMessageGenerator.m \
\
TestNSData+Crypto.m \
TestNSString+Crypto.m \
TestNSString+URLEscaping.m \
+4
View File
@@ -25,6 +25,8 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSValue.h>
@class NSArray;
@@ -52,6 +54,8 @@
- (BOOL) run;
- (NSString*) stringFromDiffBetween: (NSString*) str1
and: (NSString*) str2;
@end
#define test(c) { \
+75
View File
@@ -185,4 +185,79 @@ static NSString *SOGoTestAssertException = @"SOGoTestAssertException";
return YES;
}
/* Helper function for diffForString:andString */
NSString *_stringForCharacterAtIndex(NSUInteger index, NSString *str, NSUInteger length)
{
NSString *chrStr;
unichar chr;
if (index < length)
{
chr = [str characterAtIndex: index];
if (isprint(chr))
{
chrStr = [NSString stringWithFormat: @"%c", chr];
}
else
{
if (chr == 10)
chrStr = @"[NL]";
else if (chr == 0)
chrStr = @"[\0]";
else
chrStr = [NSString stringWithFormat: @"[NP: %u]", chr];
}
}
else
{
chrStr = @"[none]";
}
return chrStr;
}
/*
Returns a string with a very verbose diff of the two strings.
In case the strings are equal it returns an empty string.
Example output for the strings 'flower' and 'flotera':
<begin of example>
0 |f|
1 |l|
2 |o|
3 |w|t|<--
4 |e|
5 |r|
6 |[none]|a|<--
<end of example>
*/
- (NSString*) stringFromDiffBetween: (NSString*) str1
and: (NSString*) str2
{
BOOL differencesFound = NO;
NSString *finalSTR = @"";
NSUInteger i, length1, length2;
NSString *sc1, *sc2;
length1 = [str1 length];
length2 = [str2 length];
for (i = 0; i < length1 || i < length2; i++)
{
sc1 = _stringForCharacterAtIndex(i, str1, length1);
sc2 = _stringForCharacterAtIndex(i, str2, length2);
if ([sc1 isEqualToString: sc2])
finalSTR = [finalSTR stringByAppendingFormat: @"%u |%@|\n", i, sc1];
else
{
finalSTR = [finalSTR stringByAppendingFormat: @"%u |%@|%@|<--\n", i, sc1, sc2];
differencesFound = YES;
}
}
if (!differencesFound)
return @"";
return finalSTR;
}
@end
+134
View File
@@ -0,0 +1,134 @@
/* TestNGMimeMessageGenerator.m - this file is part of SOGo
*
* 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 "SOGoTest.h"
#import <NGMail/NGMimeMessageGenerator.h>
@interface TestNGMimeMessageGenerator : SOGoTest
@end
@implementation TestNGMimeMessageGenerator
- (void) test_generateDataForHeaderField_value
{
NGMimeMessageGenerator *generator;
NSArray *cases = [NSArray arrayWithObjects:
[NSArray arrayWithObjects: @"Message-ID", @"<CADCKkzo+9X1SniJFY3yc7YGafNrmAts419RmcqNkMzd-PBqNbA@mail.gmail.com>", @"<CADCKkzo+9X1SniJFY3yc7YGafNrmAts419RmcqNkMzd-PBqNbA@mail.gmail.com>", nil],
[NSArray arrayWithObjects: @"Content-Type",
@"text/plain; charset=utf-8; format=flowed",
@"text/plain; charset=utf-8; format=flowed",
nil],
[NSArray arrayWithObjects: @"X-FullHeaderOneHebrewOneLatin",
@"עs",
@"=?utf-8?q?=D7=A2s?=",
nil],
[NSArray arrayWithObjects: @"X-FullHeaderOneLatineOneHebrew",
@"sע",
@"=?utf-8?q?s=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"X-FullHeaderOneCharacterHebrew",
@"ע",
@"=?utf-8?q?=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"X-FullHeaderOneCharacterRussian",
@"Б",
@"=?utf-8?q?=D0=91?=",
nil],
[NSArray arrayWithObjects: @"X-FullHeaderParameter",
@"parameter=ע",
@"parameter==?utf-8?q?=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"X-MixedHeaderParameters",
@"plain; parameter=ע; parameter-plain; parameter2=ea",
@"plain;\n parameter==?utf-8?q?=D7=A2?=;\n parameter-plain; parameter2=ea",
nil],
[NSArray arrayWithObjects: @"X-MixedHeaderAndNoParameter",
@"plain; parameter=ע; parameter-plain; ע",
@"plain;\n parameter==?utf-8?q?=D7=A2?=; parameter-plain;\n =?utf-8?q?=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"X-MixedHeaderAndTwoParameter",
@"plain; parameter=ע; parameter-plain; z=ע",
@"plain;\n parameter==?utf-8?q?=D7=A2?=; parameter-plain;\n z==?utf-8?q?=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"X-MixedHeaderExtrablanks",
@"plain; parameter=ע; parameter 2spaces; parameter2=ea",
@"plain;\n \\ parameter==?utf-8?q?=D7=A2?=;\n parameter 2spaces; parameter2=ea",
nil],
[NSArray arrayWithObjects: @"X-Encoded-Unbalanced-Paramter-Quote",
@"text/plain; name=\"ע",
@"text/plain;\n name==?utf-8?q?=22=D7=A2?=",
nil],
[NSArray arrayWithObjects: @"content-type",
@"text/plain; name=\"АБВГДЕЁЖЗИЙ, КЛМНОПРСТУФ y ЦЧШЩЪЫЬЭЮЯ.txt\"",
@"text/plain;\n name=\"=?utf-8?q?=D0=90=D0=91=D0=92=D0=93=D0=94=D0=95=D0=81=D0=96=D0=97=D0=98=D0=99=2C_=D0=9A=D0=9B=D0=9C=D0=9D=D0=9E=D0=9F=D0=A0=D0=A1=D0=A2=D0=A3=D0=A4_y_=D0=A6=D0=A7=D0=A8=D0=A9=D0=AA=D0=AB=D0=AC=D0=AD=D0=AE=D0=AF=2Etxt?=\"",
nil],
[NSArray arrayWithObjects: @"content-disposition",
@"attachment; filename=\"АБВГДЕЁЖЗИЙ, КЛМНОПРСТУФ y ЦЧШЩЪЫЬЭЮЯ.txt\"",
@"attachment;\n filename=\"=?utf-8?q?=D0=90=D0=91=D0=92=D0=93=D0=94=D0=95=D0=81=D0=96=D0=97=D0=98=D0=99=2C_=D0=9A=D0=9B=D0=9C=D0=9D=D0=9E=D0=9F=D0=A0=D0=A1=D0=A2=D0=A3=D0=A4_y_=D0=A6=D0=A7=D0=A8=D0=A9=D0=AA=D0=AB=D0=AC=D0=AD=D0=AE=D0=AF=2Etxt?=\"",
nil],
[NSArray arrayWithObjects: @"content-length", @"2912", @"2912", nil],
[NSArray arrayWithObjects: @"content-transfer-encoding", @"quoted-printable", @"quoted-printable", nil],
nil
];
NSEnumerator *enumerator;
NSArray *testCase;
[NGMimeMessageGenerator initialize];
generator = [[NGMimeMessageGenerator alloc] init];
[generator autorelease];
enumerator = [cases objectEnumerator];
while ((testCase = [enumerator nextObject]) != nil)
{
NSData *result;
NSMutableData *resultWithNulByte;
NSString *header = [testCase objectAtIndex: 0];
NSData *headerData = [testCase objectAtIndex: 1];
NSString *expected = [testCase objectAtIndex: 2];
result = [generator generateDataForHeaderField: header
value: headerData];
if (result == nil)
result = [@"[nil]" dataUsingEncoding: NSUTF8StringEncoding];
resultWithNulByte = [result mutableCopy];
[resultWithNulByte appendBytes: "\0" length: 1];
NSString *resultString = [NSString stringWithCString:[resultWithNulByte bytes]];
BOOL testResult = [resultString isEqualToString: expected];
NSString *diff = [self stringFromDiffBetween: [NSString stringWithString: resultString]
and: [NSString stringWithString: expected]];
NSString *testErrorMsg = [NSString
stringWithFormat: @">> For %@ header received:\n%@[END]\n>> instead of:\n%@[END]\n>> for:\n%@\n>> diff:\n%@\n>> lengthReceived: %u lengthExpected: %u",
header,
resultString,
expected,
headerData,
diff,
[resultString length],
[expected length]
];
testWithMessage(testResult, testErrorMsg);
}
}
@end
+9 -1
View File
@@ -116,13 +116,19 @@ static NSURL *tableURL = nil;
- (void) _removeUserFolders: (NSString *) userId
{
NSArray *folderPaths;
NSString *path;
int count, max;
folderPaths = [self _userFolderPaths: userId];
max = [folderPaths count];
if (max > 0)
for (count = 0; count < max; count++)
[fm deleteFolderAtPath: [folderPaths objectAtIndex: count]];
{
path = [folderPaths objectAtIndex: count];
[fm deleteFolderAtPath: path];
if (verbose)
NSLog (@"Deleting %@", path);
}
else
NSLog (@"No folder returned for user '%@'", userId);
}
@@ -144,6 +150,8 @@ static NSURL *tableURL = nil;
userId];
if ([fc evaluateExpressionX: sql])
NSLog (@"Unable to delete the preference record for '%@'", userId);
else if (verbose)
NSLog (@"Removed preference record for '%@'", userId);
[cm releaseChannel: fc];
}
}
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "لا يوجد إشتراك";
"Preferred" = "المفضل";
"Display:" = "عرض:";
"Display Name:" = "الاسم المعروض:";
"Display" = "عرض";
"Display Name" = "الاسم المعروض";
"Email:" = "البريد الالكتروني:";
"Additional Email:" = "بريد إلكتروني إضافي";
"Phone Number:" = "رقم الهاتف:";
"Phone Number" = "رقم الهاتف";
"Prefers to receive messages formatted as:" = "يفضل تلقي رسائل منسقة على النحو التالي:";
"Screen Name:" = "أسم التعريف:";
"Categories:" = "الفئات:";
"First:" = "الاول:";
"Last:" = "الاخير:";
"Nickname:" = "الاسم الرمزي:";
"Nickname" = "الاسم الرمزي";
"Telephone" = "رقم الهاتف:";
"Work:" = "العمل:";
@@ -103,25 +103,25 @@
"New category" = "فئة جديدة";
/* adresses */
"Title:" = "اللقب:";
"Title" = "اللقب";
"Service:" = "الخدمة:";
"Company:" = "الشركة:";
"Department:" = "الادارة:";
"Organization:" = "الجهة";
"Address:" = "العنوان:";
"City:" = "المدينة:";
"City" = "المدينة";
"State_Province:" = "الولاية / الاقليم / المحافظة:";
"ZIP_Postal Code:" = "الرمز البريدي:";
"Country:" = "الدولة:";
"Country" = "الدولة";
"Web Page:" = "صفحة الانترنت:";
"Work" = "العمل";
"Other Infos" = "معلومات أخرى";
"Note:" = "ملاحظة:";
"Note" = "ملاحظة";
"Timezone:" = "المنطقة الزمنية:";
"Birthday:" = "تاريخ الميلاد:";
"Birthday (yyyy-mm-dd):" = "تاريخ الميلاد (يوم-شهر-سنة):";
"Birthday" = "تاريخ الميلاد";
"Birthday (yyyy-mm-dd)" = "تاريخ الميلاد (يوم-شهر-سنة)";
"Freebusy URL:" = "موقع مشغول /حر:";
"Add as..." = "إضافة إلى ...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "تفاصيل القائمة";
"List name:" = "اسم القائمة/";
"List nickname:" = "اسم القائمة الرمزي:";
"List description:" = "وصف القائمة:";
"List name" = "اسم القائمة/";
"List nickname" = "اسم القائمة الرمزي";
"List description" = "وصف القائمة";
"Members" = "أعضاء";
"Contacts" = "جهات إتصال";
"Add" = "إضافة";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Ez dago harpidetzarako aukerarik";
"Preferred" = "Hobetsitakoa";
"Display:" = "Bistaratzea:";
"Display Name:" = "Erakusteko izena:";
"Display" = "Bistaratzea";
"Display Name" = "Erakusteko izena";
"Email:" = "Emaila:";
"Additional Email:" = "Beste emaila:";
"Phone Number:" = "Telefono zenbakia";
"Phone Number" = "Telefono zenbakia";
"Prefers to receive messages formatted as:" = "Nahiago du mezuak honako formatuan jasotzea:";
"Screen Name:" = "Pantailaren izena";
"Categories:" = "Kategoriak:";
"First:" = "Lehenengoa:";
"Last:" = "Azkena:";
"Nickname:" = "Goitizena:";
"Nickname" = "Goitizena";
"Telephone" = "Telefonoa:";
"Work:" = "Lana:";
@@ -103,25 +103,25 @@
"New category" = "Kategoria berria";
/* adresses */
"Title:" = "Izenburua";
"Title" = "Izenburua";
"Service:" = "Zerbitzua:";
"Company:" = "Enpresa";
"Department:" = "Saila";
"Organization:" = "Saila:";
"Address:" = "Helbidea";
"City:" = "Herria";
"City" = "Herria";
"State_Province:" = "Estatua / Probintzia";
"ZIP_Postal Code:" = "Posta kodea";
"Country:" = "Herrialdea";
"Country" = "Herrialdea";
"Web Page:" = "Web orria";
"Work" = "Lana";
"Other Infos" = "Bestelako informazioak";
"Note:" = "Ohar:";
"Note" = "Ohar";
"Timezone:" = "Ordu-zona:";
"Birthday:" = "Jaiotze data:";
"Birthday (yyyy-mm-dd):" = "Jaiotze data (uuuu-hh-ee):";
"Birthday" = "Jaiotze data";
"Birthday (yyyy-mm-dd)" = "Jaiotze data (uuuu-hh-ee)";
"Freebusy URL:" = "LibreLanpetu URL-a:";
"Add as..." = "Gehitu honela...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Zerrendaren xehetasunak";
"List name:" = "Zerrendaren izena:";
"List nickname:" = "Zerrendaren goitizena:";
"List description:" = "Zerrendaren deskribapena:";
"List name" = "Zerrendaren izena";
"List nickname" = "Zerrendaren goitizena";
"List description" = "Zerrendaren deskribapena";
"Members" = "Kideak";
"Contacts" = "Kontaktuak";
"Add" = "Gehitu";
@@ -76,19 +76,19 @@
"No possible subscription" = "Sem possibilidades de inscrição";
"Preferred" = "Preferido";
"Display:" = "Exibição:";
"Display Name:" = "Exibir Nome:";
"Display" = "Exibição";
"Display Name" = "Exibir Nome";
"Email:" = "Endereço de Email:";
"Additional Email:" = "Email Adicional:";
"Phone Number:" = "Telefone:";
"Phone Number" = "Telefone";
"Prefers to receive messages formatted as:" = "Prefere receber mensagens formatadas como:";
"Screen Name:" = "Nome de Exibição:";
"Categories:" = "Categorias:";
"First:" = "Primeiro Nome:";
"Last:" = "Último Nome:";
"Nickname:" = "Apelido:";
"Nickname" = "Apelido";
"Telephone" = "Telefone";
"Work:" = "Comercial:";
@@ -103,25 +103,25 @@
"New category" = "Nova categoria";
/* adresses */
"Title:" = "Título:";
"Title" = "Título";
"Service:" = "Serviço:";
"Company:" = "Empresa:";
"Department:" = "Departamento";
"Organization:" = "Organização";
"Address:" = "Endereço:";
"City:" = "Cidade:";
"City" = "Cidade";
"State_Province:" = "Estado:";
"ZIP_Postal Code:" = "CEP:";
"Country:" = "País:";
"Country" = "País";
"Web Page:" = "Página Web:";
"Work" = "Comercial";
"Other Infos" = "Outras Informações";
"Note:" = "Notas:";
"Note" = "Notas";
"Timezone:" = "Fuso Horário:";
"Birthday:" = "Aniversário:";
"Birthday (yyyy-mm-dd):" = "Aniversário (yyyy-mm-dd):";
"Birthday" = "Aniversário";
"Birthday (yyyy-mm-dd)" = "Aniversário (yyyy-mm-dd)";
"Freebusy URL:" = "URL Livre/Ocupado:";
"Add as..." = "Adicionar como...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Detalhes da lista";
"List name:" = "Lista nome:";
"List nickname:" = "Lista Apelido:";
"List description:" = "Lista descrição:";
"List name" = "Lista nome";
"List nickname" = "Lista Apelido";
"List description" = "Lista descrição";
"Members" = "Membros";
"Contacts" = "Contatos";
"Add" = "Adicionar";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "La subscripció no és possible";
"Preferred" = "Preferit";
"Display:" = "Nom mostrat:";
"Display Name:" = "Nom:";
"Display" = "Nom mostrat";
"Display Name" = "Nom";
"Email:" = "Correu electrònic:";
"Additional Email:" = "Un altre correu electrònic:";
"Phone Number:" = "Número de telèfon:";
"Phone Number" = "Número de telèfon";
"Prefers to receive messages formatted as:" = "Prefereix rebre missatges amb format:";
"Screen Name:" = "Nom d'usuari:";
"Categories:" = "Categories:";
"First:" = "Nom:";
"Last:" = "Cognoms:";
"Nickname:" = "Àlies:";
"Nickname" = "Àlies";
"Telephone" = "Telèfon";
"Work:" = "Feina:";
@@ -103,25 +103,25 @@
"New category" = "New category";
/* adresses */
"Title:" = "Títol:";
"Title" = "Títol";
"Service:" = "Servei:";
"Company:" = "Companyia:";
"Department:" = "Departament:";
"Organization:" = "Organització:";
"Address:" = "Domicili:";
"City:" = "Ciutat:";
"City" = "Ciutat";
"State_Province:" = "Estat/província/comarca:";
"ZIP_Postal Code:" = "Codi postal:";
"Country:" = "País:";
"Country" = "País";
"Web Page:" = "Web:";
"Work" = "Treball";
"Other Infos" = "Altres dades";
"Note:" = "Nota:";
"Note" = "Nota";
"Timezone:" = "Zona hor.:";
"Birthday:" = "Data de naixement:";
"Birthday (yyyy-mm-dd):" = "Data naixement (yyyy-mm-dd):";
"Birthday" = "Data de naixement";
"Birthday (yyyy-mm-dd)" = "Data naixement (yyyy-mm-dd)";
"Freebusy URL:" = "URL disponibilitat:";
"Add as..." = "Afegir com a...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Detalls de la llista";
"List name:" = "Nom de la llista:";
"List nickname:" = "Àlies de la llista:";
"List description:" = "Descripcció de la llista:";
"List name" = "Nom de la llista";
"List nickname" = "Àlies de la llista";
"List description" = "Descripcció de la llista";
"Members" = "Membres";
"Contacts" = "Contactes";
"Add" = "Afegir";
@@ -76,19 +76,19 @@
"No possible subscription" = "不可訂閱";
"Preferred" = "首選";
"Display:" = "顯示:";
"Display Name:" = "顯示名稱:";
"Display" = "顯示";
"Display Name" = "顯示名稱";
"Email:" = "郵件:";
"Additional Email:" = "添加的郵件:";
"Phone Number:" = "電話號碼:";
"Phone Number" = "電話號碼";
"Prefers to receive messages formatted as:" = "喜愛的接收訊息格式為:";
"Screen Name:" = "顯示名稱:";
"Categories:" = "類别:";
"First:" = "名:";
"Last:" = "姓:";
"Nickname:" = "暱稱:";
"Nickname" = "暱稱";
"Telephone" = "電話";
"Work:" = "辦公:";
@@ -103,25 +103,25 @@
"New category" = "新類別";
/* adresses */
"Title:" = "頭銜:";
"Title" = "頭銜";
"Service:" = "服務:";
"Company:" = "公司:";
"Department:" = "部門:";
"Organization:" = "组織:";
"Address:" = "地址:";
"City:" = "城市:";
"City" = "城市";
"State_Province:" = "州/省:";
"ZIP_Postal Code:" = "ZIP/郵遞區號:";
"Country:" = "國家:";
"Country" = "國家";
"Web Page:" = "網页:";
"Work" = "辦公";
"Other Infos" = "其他資訊";
"Note:" = "備註:";
"Note" = "備註";
"Timezone:" = "時區:";
"Birthday:" = "生日:";
"Birthday (yyyy-mm-dd):" = "生日 (yyyy-mm-dd):";
"Birthday" = "生日";
"Birthday (yyyy-mm-dd)" = "生日 (yyyy-mm-dd)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "新增為...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "列出明细";
"List name:" = "列出名字:";
"List nickname:" = "列出暱稱:";
"List description:" = "列出說明:";
"List name" = "列出名字";
"List nickname" = "列出暱稱";
"List description" = "列出說明";
"Members" = "成員";
"Contacts" = "連絡人";
"Add" = "新增";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Žádné možné odebírání";
"Preferred" = "Upřednostňovaný";
"Display:" = "Zobrazované jméno:";
"Display Name:" = "Zobrazované jméno:";
"Display" = "Zobrazované jméno";
"Display Name" = "Zobrazované jméno";
"Email:" = "E-mail:";
"Additional Email:" = "Další e-mail:";
"Phone Number:" = "Telefonní číslo:";
"Phone Number" = "Telefonní číslo";
"Prefers to receive messages formatted as:" = "Upřednostňovaný formát zpráv:";
"Screen Name:" = "Zobrazované jméno:";
"Categories:" = "Kategorie:";
"First:" = "Křestní jméno:";
"Last:" = "Příjmení:";
"Nickname:" = "Přezdívka:";
"Nickname" = "Přezdívka";
"Telephone" = "Telefon";
"Work:" = "Zaměstnání:";
@@ -103,25 +103,25 @@
"New category" = "Nová kategorie";
/* adresses */
"Title:" = "Pozice:";
"Title" = "Pozice";
"Service:" = "Služba:";
"Company:" = "Společnost:";
"Department:" = "Oddělení:";
"Organization:" = "Organizace:";
"Address:" = "Adresa:";
"City:" = "Město:";
"City" = "Město";
"State_Province:" = "Stát/Provincie:";
"ZIP_Postal Code:" = "PSČ:";
"Country:" = "Země:";
"Country" = "Země";
"Web Page:" = "Web:";
"Work" = "Zaměstnání";
"Other Infos" = "Ostatní informace";
"Note:" = "Poznámka:";
"Note" = "Poznámka";
"Timezone:" = "Časové pásmo:";
"Birthday:" = "Datum narození";
"Birthday (yyyy-mm-dd):" = "Datum narození (yyyy-mm-dd):";
"Birthday" = "Datum narození";
"Birthday (yyyy-mm-dd)" = "Datum narození (yyyy-mm-dd)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Přidat jako...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Skupina";
"List name:" = "Název:";
"List nickname:" = "Zkratka:";
"List description:" = "Popis:";
"List name" = "Název";
"List nickname" = "Zkratka";
"List description" = "Popis";
"Members" = "Členové skupiny";
"Contacts" = "Kontakty";
"Add" = "Přidat";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Intet muligt abonnement";
"Preferred" = "Foretrukket";
"Display:" = "Vis:";
"Display Name:" = "Vist navn:";
"Display" = "Vis";
"Display Name" = "Vist navn";
"Email:" = "E-mail:";
"Additional Email:" = "ekstra e-mails:";
"Phone Number:" = "Telefonnummer:";
"Phone Number" = "Telefonnummer";
"Prefers to receive messages formatted as:" = "Foretrækker at modtage beskeder formateret som:";
"Screen Name:" = "Skærmnavn:";
"Categories:" = "Kategorier:";
"First:" = "Først:";
"Last:" = "Sidst:";
"Nickname:" = "Kaldenavn:";
"Nickname" = "Kaldenavn";
"Telephone" = "Telefon";
"Work:" = "Arbejde:";
@@ -103,25 +103,25 @@
"New category" = "Ny kategori";
/* adresses */
"Title:" = "Titel:";
"Title" = "Titel";
"Service:" = "Service:";
"Company:" = "Firma:";
"Department:" = "Afdeling:";
"Organization:" = "Organisation:";
"Address:" = "Adresse:";
"City:" = "By:";
"City" = "By";
"State_Province:" = "Stat / provins:";
"ZIP_Postal Code:" = "ZIP/Postnr.:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Hjemmeside:";
"Work" = "Arbejde";
"Other Infos" = "Andet info";
"Note:" = "Bemærk:";
"Note" = "Bemærk";
"Timezone:" = "Tidszone:";
"Birthday:" = "Fødselsdag:";
"Birthday (yyyy-mm-dd):" = "Fødselsdag (dd-mm-åååå):";
"Birthday" = "Fødselsdag";
"Birthday (yyyy-mm-dd)" = "Fødselsdag (dd-mm-åååå)";
"Freebusy URL:" = "Ledig/optaget URL:";
"Add as..." = "Tilføj som ...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Liste detaljer";
"List name:" = "Liste navn:";
"List nickname:" = "Liste kaldenavn:";
"List description:" = "Liste beskrivelse:";
"List name" = "Liste navn";
"List nickname" = "Liste kaldenavn";
"List description" = "Liste beskrivelse";
"Members" = "Medlemmer";
"Contacts" = "Kontaktpersoner";
"Add" = "Tilføj";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Abonnement niet mogelijk";
"Preferred" = "Voorkeurs-";
"Display:" = "Weergave:";
"Display Name:" = "Weergavenaam:";
"Display" = "Weergave";
"Display Name" = "Weergavenaam";
"Email:" = "E-mail:";
"Additional Email:" = "Alternatieve e-mail:";
"Phone Number:" = "Telefoon:";
"Phone Number" = "Telefoon";
"Prefers to receive messages formatted as:" = "Geeft voorkeur aan berichten geformatteerd als:";
"Screen Name:" = "Weergavenaam:";
"Categories:" = "Categorieën:";
"First:" = "Voornaam:";
"Last:" = "Achternaam:";
"Nickname:" = "Nickname:";
"Nickname" = "Nickname";
"Telephone" = "Telefoon:";
"Work:" = "Werk:";
@@ -103,25 +103,25 @@
"New category" = "Niewe categorie";
/* adresses */
"Title:" = "Titel:";
"Title" = "Titel";
"Service:" = "Service:";
"Company:" = "Bedrijf:";
"Department:" = "Afdeling:";
"Organization:" = "Organisatie:";
"Address:" = "Adres:";
"City:" = "Plaats:";
"City" = "Plaats";
"State_Province:" = "Provincie:";
"ZIP_Postal Code:" = "Postcode:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Website:";
"Work" = "Werk";
"Other Infos" = "Overige";
"Note:" = "Notitie:";
"Note" = "Notitie";
"Timezone:" = "Tijdzone:";
"Birthday:" = "Geboortedatum:";
"Birthday (yyyy-mm-dd):" = "Geboortedatum (yyyy-mm-dd):";
"Birthday" = "Geboortedatum";
"Birthday (yyyy-mm-dd)" = "Geboortedatum (yyyy-mm-dd)";
"Freebusy URL:" = "Beschikbaarheids-URL (Free/Busy):";
"Add as..." = "Toevoegen als ...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Toon details";
"List name:" = "Lijst-naam:";
"List nickname:" = "Lijst-bijnaam:";
"List description:" = "Beschrijving:";
"List name" = "Lijst-naam";
"List nickname" = "Lijst-bijnaam";
"List description" = "Beschrijving";
"Members" = "Leden";
"Contacts" = "Contactpersonen";
"Add" = "Toevoegen";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "No possible subscription";
"Preferred" = "Preferred";
"Display:" = "Display:";
"Display Name:" = "Display Name:";
"Display" = "Display";
"Display Name" = "Display Name";
"Email:" = "Email:";
"Additional Email:" = "Additional Email:";
"Phone Number:" = "Phone Number:";
"Phone Number" = "Phone Number";
"Prefers to receive messages formatted as:" = "Prefers to receive messages formatted as:";
"Screen Name:" = "Screen Name:";
"Categories:" = "Categories:";
"First:" = "First:";
"Last:" = "Last:";
"Nickname:" = "Nickname:";
"Nickname" = "Nickname";
"Telephone" = "Telephone";
"Work:" = "Work:";
@@ -103,25 +103,25 @@
"New category" = "New category";
/* adresses */
"Title:" = "Title:";
"Title" = "Title";
"Service:" = "Service:";
"Company:" = "Company:";
"Department:" = "Department:";
"Organization:" = "Organization:";
"Address:" = "Address:";
"City:" = "City: ";
"City" = "City ";
"State_Province:" = "State/Province:";
"ZIP_Postal Code:" = "ZIP/Postal Code:";
"Country:" = "Country:";
"Country" = "Country";
"Web Page:" = "Web Page:";
"Work" = "Work";
"Other Infos" = "Other Infos";
"Note:" = "Note:";
"Note" = "Note";
"Timezone:" = "Timezone:";
"Birthday:" = "Birthday:";
"Birthday (yyyy-mm-dd):" = "Birthday (yyyy-mm-dd):";
"Birthday" = "Birthday";
"Birthday (yyyy-mm-dd)" = "Birthday (yyyy-mm-dd)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Add as...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "List details";
"List name:" = "List name:";
"List nickname:" = "List nickname:";
"List description:" = "List description:";
"List name" = "List name";
"List nickname" = "List nickname";
"List description" = "List description";
"Members" = "Members";
"Contacts" = "Contacts";
"Add" = "Add";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Tilaus ei mahdollinen";
"Preferred" = "Ensisijainen";
"Display:" = "Näyttö:";
"Display Name:" = "Näyttönimi:";
"Display" = "Näyttö";
"Display Name" = "Näyttönimi";
"Email:" = "Email:";
"Additional Email:" = "Lisäsähköpostiosoite:";
"Phone Number:" = "Puhelinnumero:";
"Phone Number" = "Puhelinnumero";
"Prefers to receive messages formatted as:" = "Vastaanottaa viestejä muotoiltuna ensisijaisesti:";
"Screen Name:" = "Näytettävä nimi:";
"Categories:" = "Kategoriat:";
"First:" = "Etunimi:";
"Last:" = "Sukunimi:";
"Nickname:" = "Lempinimi:";
"Nickname" = "Lempinimi";
"Telephone" = "Puhelin";
"Work:" = "Työ:";
@@ -103,25 +103,25 @@
"New category" = "Uusi kategoria";
/* adresses */
"Title:" = "Titteli:";
"Title" = "Titteli";
"Service:" = "Palvelu:";
"Company:" = "Yritys:";
"Department:" = "Osasto:";
"Organization:" = "Organisaatio:";
"Address:" = "Osoite:";
"City:" = "Kaupunki: ";
"City" = "Kaupunki ";
"State_Province:" = "Maakunta:";
"ZIP_Postal Code:" = "Postinumero:";
"Country:" = "Maa:";
"Country" = "Maa";
"Web Page:" = "Web sivu:";
"Work" = "Työ";
"Other Infos" = "Muuta tietoa";
"Note:" = "Huomautus:";
"Note" = "Huomautus";
"Timezone:" = "Aikavyöhyke:";
"Birthday:" = "Syntymäpäivä:";
"Birthday (yyyy-mm-dd):" = "Syntymäpäivä (vvvv-kk-pp):";
"Birthday" = "Syntymäpäivä";
"Birthday (yyyy-mm-dd)" = "Syntymäpäivä (vvvv-kk-pp)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Lisää nimellä...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Luettelon tiedot";
"List name:" = "Luettelon nimi:";
"List nickname:" = "Luettelon lempinimi:";
"List description:" = "Luettelon kuvaus:";
"List name" = "Luettelon nimi";
"List nickname" = "Luettelon lempinimi";
"List description" = "Luettelon kuvaus";
"Members" = "Jäsenet";
"Contacts" = "Yhteystiedot";
"Add" = "Lisää";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Aucune inscription possible";
"Preferred" = "Préféré";
"Display:" = "Nom à afficher :";
"Display Name:" = "Nom à afficher :";
"Display" = "Nom à afficher ";
"Display Name" = "Nom à afficher ";
"Email:" = "Adresse électronique :";
"Additional Email:" = "Adresse alternative :";
"Phone Number:" = "Numéro de téléphone :";
"Phone Number" = "Numéro de téléphone ";
"Prefers to receive messages formatted as:" = "Préfère recevoir les messages au format :";
"Screen Name:" = "Pseudo :";
"Categories:" = "Catégories :";
"First:" = "Prénom :";
"Last:" = "Nom :";
"Nickname:" = "Surnom :";
"Nickname" = "Surnom ";
"Telephone" = "Téléphone";
"Work:" = "Travail :";
@@ -103,25 +103,25 @@
"New category" = "Nouvelle catégorie";
/* adresses */
"Title:" = "Fonction :";
"Title" = "Fonction ";
"Service:" = "Service:";
"Company:" = "Company:";
"Department:" = "Service :";
"Organization:" = "Société :";
"Address:" = "Adresse :";
"City:" = "Ville/Localité :";
"City" = "Ville/Localité ";
"State_Province:" = "État/Prov. :";
"ZIP_Postal Code:" = "Code postal :";
"Country:" = "Pays :";
"Country" = "Pays ";
"Web Page:" = "Page Web:";
"Work" = "Professionnelle";
"Other Infos" = "Informations complémentaires";
"Note:" = "Remarques :";
"Note" = "Remarques ";
"Timezone:" = "Fuseau horaire :";
"Birthday:" = "D. naissance:";
"Birthday (yyyy-mm-dd):" = "D. naissance (aaaa-mm-jj):";
"Birthday" = "D. naissance";
"Birthday (yyyy-mm-dd)" = "D. naissance (aaaa-mm-jj)";
"Freebusy URL:" = "Adresse du FreeBusy :";
"Add as..." = "Ajouter...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Détails";
"List name:" = "Liste:";
"List nickname:" = "Surnom:";
"List description:" = "Description:";
"List name" = "Liste";
"List nickname" = "Surnom";
"List description" = "Description";
"Members" = "Membres";
"Contacts" = "Contacts";
"Add" = "Ajouter";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Kein Abonnieren möglich";
"Preferred" = "Bevorzugt";
"Display:" = "Anzeige:";
"Display Name:" = "Anzeigename:";
"Display" = "Anzeige";
"Display Name" = "Anzeigename";
"Email:" = "E-Mail:";
"Additional Email:" = "Zusätzliche E-Mail:";
"Phone Number:" = "Telefon:";
"Phone Number" = "Telefon";
"Prefers to receive messages formatted as:" = "Bevorzugt folgendes Nachrichten-Format:";
"Screen Name:" = "Messenger-Name:";
"Categories:" = "Kategorien:";
"First:" = "Vorname:";
"Last:" = "Nachname:";
"Nickname:" = "Spitzname:";
"Nickname" = "Spitzname";
"Telephone" = "Telefon";
"Work:" = "Dienstlich:";
@@ -103,25 +103,25 @@
"New category" = "Neue Kategorie";
/* adresses */
"Title:" = "Titel:";
"Title" = "Titel";
"Service:" = "Dienst:";
"Company:" = "Firma:";
"Department:" = "Abteilung:";
"Organization:" = "Organisation:";
"Address:" = "Adresse:";
"City:" = "Stadt:";
"City" = "Stadt";
"State_Province:" = "Bundesland:";
"ZIP_Postal Code:" = "PLZ:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Webseite:";
"Work" = "Dienstlich";
"Other Infos" = "Andere Informationen";
"Note:" = "Notizen:";
"Note" = "Notizen";
"Timezone:" = "Zeitzone:";
"Birthday:" = "Geburtsdatum:";
"Birthday (yyyy-mm-dd):" = "Geburtsdatum (JJJJ-MM-TT):";
"Birthday" = "Geburtsdatum";
"Birthday (yyyy-mm-dd)" = "Geburtsdatum (JJJJ-MM-TT)";
"Freebusy URL:" = "Frei/Gebucht URL:";
"Add as..." = "Hinzufügen als ...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Details";
"List name:" = "Listenname:";
"List nickname:" = "Listen-Spitzname:";
"List description:" = "Beschreibung:";
"List name" = "Listenname";
"List nickname" = "Listen-Spitzname";
"List description" = "Beschreibung";
"Members" = "Mitglieder";
"Contacts" = "Kontakte";
"Add" = "Hinzufügen";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Nincs mappa, melyre feliratkozhat";
"Preferred" = "Preferált";
"Display:" = "Megjelenítendő név:";
"Display Name:" = "Megjelenítendő név:";
"Display" = "Megjelenítendő név";
"Display Name" = "Megjelenítendő név";
"Email:" = "Email cím:";
"Additional Email:" = "További email:";
"Phone Number:" = "Telefon:";
"Phone Number" = "Telefon";
"Prefers to receive messages formatted as:" = "Előnyben részesített üzenet formátum:";
"Screen Name:" = "Fedőnév:";
"Categories:" = "Kategóriák:";
"First:" = "Keresztnév:";
"Last:" = "Vezetéknév:";
"Nickname:" = "Becenév:";
"Nickname" = "Becenév";
"Telephone" = "Telefon";
"Work:" = "Munkahely:";
@@ -103,25 +103,25 @@
"New category" = "Új kategória";
/* adresses */
"Title:" = "Cím:";
"Title" = "Cím";
"Service:" = "Szolgáltatás:";
"Company:" = "Vállalat:";
"Department:" = "Részleg:";
"Organization:" = "Szervezet:";
"Address:" = "Cím:";
"City:" = "Város:";
"City" = "Város";
"State_Province:" = "Állam/tartomány:";
"ZIP_Postal Code:" = "Irányítószám:";
"Country:" = "Ország:";
"Country" = "Ország";
"Web Page:" = "Web:";
"Work" = "Munkahely";
"Other Infos" = "Egyéb";
"Note:" = "Megjegyzés:";
"Note" = "Megjegyzés";
"Timezone:" = "Időzóna:";
"Birthday:" = "Születésnap:";
"Birthday (yyyy-mm-dd):" = "Születésnap (éééé-hh-nn):";
"Birthday" = "Születésnap";
"Birthday (yyyy-mm-dd)" = "Születésnap (éééé-hh-nn)";
"Freebusy URL:" = "Foglaltság URL:";
"Add as..." = "Hozzáadás mint...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Lista részletek";
"List name:" = "Lista név:";
"List nickname:" = "Lista becenév:";
"List description:" = "Lista leírás:";
"List name" = "Lista név";
"List nickname" = "Lista becenév";
"List description" = "Lista leírás";
"Members" = "Tagok";
"Contacts" = "Kapcsolatok";
"Add" = "Hozzáad";
+13 -13
View File
@@ -77,19 +77,19 @@
"Preferred" = "Sjálfgefið";
"Card for %@" = "Nafnspjald fyrir %@";
"Display:" = "Birtingarnafn:";
"Display Name:" = "Birt nafn:";
"Display" = "Birtingarnafn";
"Display Name" = "Birt nafn";
"Email:" = "Tölvupóstfang:";
"Additional Email:" = "Auka tölvupóstfang:";
"Phone Number:" = "Símanúmer:";
"Phone Number" = "Símanúmer";
"Prefers to receive messages formatted as:" = "Kýs að taka á móti pósti með sniði:";
"Screen Name:" = "Skjánafn:";
"Categories:" = "Flokkar:";
"First:" = "Fornafn:";
"Last:" = "Eftirnafn:";
"Nickname:" = "Gælunafn:";
"Nickname" = "Gælunafn";
"Telephone" = "Sími";
"Work:" = "Vinnusími:";
@@ -104,25 +104,25 @@
"New category" = "Nýr flokkur";
/* adresses */
"Title:" = "Titill:";
"Title" = "Titill";
"Service:" = "Þjónusta:";
"Company:" = "Fyrirtæki:";
"Department:" = "Deild:";
"Organization:" = "Fyrirtæki/Stofnun:";
"Address:" = "Heimilisfang:";
"City:" = "Borg: ";
"City" = "Borg ";
"State_Province:" = "Hérað/Fylki:";
"ZIP_Postal Code:" = "Póstnúmer:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Vefsíða:";
"Work" = "Vinna";
"Other Infos" = "Aðrar upplýsingar";
"Note:" = "Athugasemd:";
"Note" = "Athugasemd";
"Timezone:" = "Tímabelti:";
"Birthday:" = "Afmælisdagur:";
"Birthday (yyyy-mm-dd):" = "Afmælisdagur (yyyy-mm-dd):";
"Birthday" = "Afmælisdagur";
"Birthday (yyyy-mm-dd)" = "Afmælisdagur (yyyy-mm-dd)";
"Freebusy URL:" = "LaustUpptekið URL";
"Add as..." = "Bæta við sem...";
@@ -185,9 +185,9 @@
/* Lists */
"List details" = "Ítarleg lýsing á lista:";
"List name:" = "Nafn lista:";
"List nickname:" = "Gælunafn lista:";
"List description:" = "Lýsing lista:";
"List name" = "Nafn lista";
"List nickname" = "Gælunafn lista";
"List description" = "Lýsing lista";
"Members" = "Meðlimir";
"Contacts" = "Tengiliðir";
"Add" = "Bæta við";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Nessuna sottoscrizione possibile";
"Preferred" = "Predefinito";
"Display:" = "Nome visualizzato:";
"Display Name:" = "Nome visualizzato:";
"Display" = "Nome visualizzato";
"Display Name" = "Nome visualizzato";
"Email:" = "Email:";
"Additional Email:" = "Email aggiuntiva:";
"Phone Number:" = "Numero di telefono:";
"Phone Number" = "Numero di telefono";
"Prefers to receive messages formatted as:" = "Formato preferito per i messaggi di posta:";
"Screen Name:" = "Nome Instant Messenger:";
"Categories:" = "Categorie:";
"First:" = "Nome:";
"Last:" = "Cognome";
"Nickname:" = "Soprannome:";
"Nickname" = "Soprannome";
"Telephone" = "Telefono";
"Work:" = "Lavoro:";
@@ -103,25 +103,25 @@
"New category" = "Nuova categoria";
/* adresses */
"Title:" = "Titolo:";
"Title" = "Titolo";
"Service:" = "Service:";
"Company:" = "Società:";
"Department:" = "Reparto:";
"Organization:" = "Società:";
"Address:" = "Indirizzo:";
"City:" = "Città:";
"City" = "Città";
"State_Province:" = "Provincia:";
"ZIP_Postal Code:" = "CAP:";
"Country:" = "Nazione:";
"Country" = "Nazione";
"Web Page:" = "Pagina Web:";
"Work" = "Lavoro";
"Other Infos" = "Altre informazioni";
"Note:" = "Note:";
"Note" = "Note";
"Timezone:" = "Fuso orario:";
"Birthday:" = "Data di Nascita:";
"Birthday (yyyy-mm-dd):" = "Data di Nascita (yyyy-mm-dd):";
"Birthday" = "Data di Nascita";
"Birthday (yyyy-mm-dd)" = "Data di Nascita (yyyy-mm-dd)";
"Freebusy URL:" = "Libero-occupato URL:";
"Add as..." = "Aggiungi come...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Dettagli lista";
"List name:" = "Nome lista:";
"List nickname:" = "Soprannome lista:";
"List description:" = "Descrizione lista:";
"List name" = "Nome lista";
"List nickname" = "Soprannome lista";
"List description" = "Descrizione lista";
"Members" = "Membri";
"Contacts" = "Contatti";
"Add" = "Aggiungi";
@@ -76,19 +76,19 @@
"No possible subscription" = "Abonnering er ikke mulig";
"Preferred" = "Foretrukket";
"Display:" = "Vise:";
"Display Name:" = "Visningsnavn:";
"Display" = "Vise";
"Display Name" = "Visningsnavn";
"Email:" = "E-post:";
"Additional Email:" = "Ytterlige e-post:";
"Phone Number:" = "Telefonnummer:";
"Phone Number" = "Telefonnummer";
"Prefers to receive messages formatted as:" = "Foretrekker å motta melding formatert som:";
"Screen Name:" = "Skjermnavn:";
"Categories:" = "Kategorier:";
"First:" = "Fornavn:";
"Last:" = "Etternavn:";
"Nickname:" = "Kallenavn:";
"Nickname" = "Kallenavn";
"Telephone" = "Telefonnummer";
"Work:" = "Arbeid:";
@@ -103,25 +103,25 @@
"New category" = "Ny kategori";
/* adresses */
"Title:" = "Tittel:";
"Title" = "Tittel";
"Service:" = "Funksjon:";
"Company:" = "Foretak:";
"Department:" = "Avdeling:";
"Organization:" = "Organisasjon:";
"Address:" = "Adresse:";
"City:" = "Poststed: ";
"City" = "Poststed ";
"State_Province:" = "Landsdel:";
"ZIP_Postal Code:" = "Postnummer:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Nettside:";
"Work" = "Arbeid";
"Other Infos" = "Øvrig informasjon";
"Note:" = "Anmerkning:";
"Note" = "Anmerkning";
"Timezone:" = "Tidssone:";
"Birthday:" = "Fødselsdag:";
"Birthday (yyyy-mm-dd):" = "Fødselsdag (åååå-mm-dd):";
"Birthday" = "Fødselsdag";
"Birthday (yyyy-mm-dd)" = "Fødselsdag (åååå-mm-dd)";
"Freebusy URL:" = "Ledigopptatt URL:";
"Add as..." = "Legg til som...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Informasjon om mailinglisten";
"List name:" = "Navn på mailingliste:";
"List nickname:" = "Kallenavn til mailingliste:";
"List description:" = "Beskrivelse av mailingliste:";
"List name" = "Navn på mailingliste";
"List nickname" = "Kallenavn til mailingliste";
"List description" = "Beskrivelse av mailingliste";
"Members" = "Medlemmer";
"Contacts" = "Kontakter";
"Add" = "Legg til";
@@ -77,19 +77,19 @@
"Preferred" = "Foretrukket";
"Card for %@" = "Adressekort for %@";
"Display:" = "Vise:";
"Display Name:" = "Visningsnamn:";
"Display" = "Vise";
"Display Name" = "Visningsnamn";
"Email:" = "E-post:";
"Additional Email:" = "Ytterlige e-post:";
"Phone Number:" = "Telefonnummer:";
"Phone Number" = "Telefonnummer";
"Prefers to receive messages formatted as:" = "Foretrekker å motta melding formatert som:";
"Screen Name:" = "Skjermnavn:";
"Categories:" = "Katagorier:";
"First:" = "Fornavn:";
"Last:" = "Etternavn:";
"Nickname:" = "Kallenavn:";
"Nickname" = "Kallenavn";
"Telephone" = "Telefonnummer";
"Work:" = "Arbeid:";
@@ -104,25 +104,25 @@
"New category" = "Ny katagori";
/* adresses */
"Title:" = "Tittel:";
"Title" = "Tittel";
"Service:" = "Funksjon:";
"Company:" = "Foretak:";
"Department:" = "Avdelning:";
"Organization:" = "Organisation:";
"Address:" = "Adresse:";
"City:" = "Poststed: ";
"City" = "Poststed ";
"State_Province:" = "Landsdel:";
"ZIP_Postal Code:" = "Postnummer:";
"Country:" = "Land:";
"Country" = "Land";
"Web Page:" = "Webside:";
"Work" = "Arbeid";
"Other Infos" = "Øvrig";
"Note:" = "Anmerkning:";
"Note" = "Anmerkning";
"Timezone:" = "Tidssone:";
"Birthday:" = "Fødselsdag:";
"Birthday (yyyy-mm-dd):" = "Fødselsdag (yyyy-mm-dd):";
"Birthday" = "Fødselsdag";
"Birthday (yyyy-mm-dd)" = "Fødselsdag (yyyy-mm-dd)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Legg til som...";
@@ -185,9 +185,9 @@
/* Lists */
"List details" = "Informasjon om mailinglisten";
"List name:" = "Navn på mailingliste:";
"List nickname:" = "Kallenavn til mailingliste:";
"List description:" = "Beskrivelse:";
"List name" = "Navn på mailingliste";
"List nickname" = "Kallenavn til mailingliste";
"List description" = "Beskrivelse";
"Members" = "Medlemmer";
"Contacts" = "Kontakter";
"Add" = "Legg til";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Brak możliwej subskrypcji";
"Preferred" = "Preferowane";
"Display:" = "Wyświetl:";
"Display Name:" = "Nazwa wyświetlana:";
"Display" = "Wyświetl";
"Display Name" = "Nazwa wyświetlana";
"Email:" = "E-mail:";
"Additional Email:" = "Dodatkowy E-mail:";
"Phone Number:" = "Numer telefonu:";
"Phone Number" = "Numer telefonu";
"Prefers to receive messages formatted as:" = "Preferuje wiadomości w formacie:";
"Screen Name:" = "Nazwa ekranowa:";
"Categories:" = "Kategorie:";
"First:" = "Imię:";
"Last:" = "Nazwisko:";
"Nickname:" = "Pseudonim:";
"Nickname" = "Pseudonim";
"Telephone" = "Telefon";
"Work:" = "Praca:";
@@ -103,25 +103,25 @@
"New category" = "Nowa kategoria";
/* adresses */
"Title:" = "Tytuł:";
"Title" = "Tytuł";
"Service:" = "Usługa:";
"Company:" = "Firma:";
"Department:" = "Oddział:";
"Organization:" = "Organizacja:";
"Address:" = "Adres:";
"City:" = "Miejscowość:";
"City" = "Miejscowość";
"State_Province:" = "Województwo:";
"ZIP_Postal Code:" = "Kod pocztowy:";
"Country:" = "Kraj:";
"Country" = "Kraj";
"Web Page:" = "Strona WWW:";
"Work" = "Praca";
"Other Infos" = "Inne informacje";
"Note:" = "Uwagi:";
"Note" = "Uwagi";
"Timezone:" = "Strefa czasowa:";
"Birthday:" = "Urodziny:";
"Birthday (yyyy-mm-dd):" = "Urodziny (yyyy-mm-dd):";
"Birthday" = "Urodziny";
"Birthday (yyyy-mm-dd)" = "Urodziny (yyyy-mm-dd)";
"Freebusy URL:" = "URL statusu wolny-zajęty:";
"Add as..." = "Dodaj jako";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Szczegóły listy";
"List name:" = "Nazwa listy:";
"List nickname:" = "Nick listy:";
"List description:" = "Opis listy:";
"List name" = "Nazwa listy";
"List nickname" = "Nick listy";
"List description" = "Opis listy";
"Members" = "Członkowie";
"Contacts" = "Kontakty";
"Add" = "Dodaj";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Нет возможных подписок";
"Preferred" = "Избранные";
"Display:" = "Показывать:";
"Display Name:" = "Отображаемое имя:";
"Display" = "Показывать";
"Display Name" = "Отображаемое имя";
"Email:" = "E-mail:";
"Additional Email:" = "Дополнительный E-mail:";
"Phone Number:" = "Номер телефона:";
"Phone Number" = "Номер телефона";
"Prefers to receive messages formatted as:" = "Предпочитает принимать сообщения, отформатированные следующим образом:";
"Screen Name:" = "Имя показа:";
"Categories:" = "Категории:";
"First:" = "Имя:";
"Last:" = "Последнее:";
"Nickname:" = "Ник:";
"Nickname" = "Ник";
"Telephone" = "Телефон";
"Work:" = "Рабочий телефон:";
@@ -103,25 +103,25 @@
"New category" = "Новые категории";
/* adresses */
"Title:" = "Звание:";
"Title" = "Звание";
"Service:" = "Сервис:";
"Company:" = "Компания:";
"Department:" = "Отдел:";
"Organization:" = "Организация:";
"Address:" = "Адрес:";
"City:" = "Город:";
"City" = "Город";
"State_Province:" = "Область/штат:";
"ZIP_Postal Code:" = "ZIP/Postal Code:";
"Country:" = "Страна:";
"Country" = "Страна";
"Web Page:" = "Веб-страница:";
"Work" = "Работа";
"Other Infos" = "Другая информация";
"Note:" = "Примечание:";
"Note" = "Примечание";
"Timezone:" = "Часовой пояс:";
"Birthday:" = "День рождения";
"Birthday (yyyy-mm-dd):" = "День рождения (ГГГГ-ММ-ДД):";
"Birthday" = "День рождения";
"Birthday (yyyy-mm-dd)" = "День рождения (ГГГГ-ММ-ДД)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Добавить как...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Подробности списка";
"List name:" = "Имя списка:";
"List nickname:" = "Псевдоним списка:";
"List description:" = "Описание списка:";
"List name" = "Имя списка";
"List nickname" = "Псевдоним списка";
"List description" = "Описание списка";
"Members" = "Члены";
"Contacts" = "Контакты";
"Add" = "Добавить";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Žiadne možnosti odberu";
"Preferred" = "Preferovaný";
"Display:" = "Zobraz:";
"Display Name:" = "Zobrazované meno:";
"Display" = "Zobraz";
"Display Name" = "Zobrazované meno";
"Email:" = "Email:";
"Additional Email:" = "Další email:";
"Phone Number:" = "Telefónne číslo:";
"Phone Number" = "Telefónne číslo";
"Prefers to receive messages formatted as:" = "Preferuje prijímať správy formátované ako:";
"Screen Name:" = "Zobrazované meno:";
"Categories:" = "Kategórie:";
"First:" = "Meno:";
"Last:" = "Priezvisko:";
"Nickname:" = "Prezývka:";
"Nickname" = "Prezývka";
"Telephone" = "Telefón";
"Work:" = "Do práce:";
@@ -103,25 +103,25 @@
"New category" = "Nová kategória";
/* adresses */
"Title:" = "Názov:";
"Title" = "Názov";
"Service:" = "Služba:";
"Company:" = "Spoločnosť:";
"Department:" = "Oddelenie:";
"Organization:" = "Organizácia:";
"Address:" = "Adresa:";
"City:" = "Mesto:";
"City" = "Mesto";
"State_Province:" = "Štát:";
"ZIP_Postal Code:" = "Poštové smerové číslo:";
"Country:" = "Krajina:";
"Country" = "Krajina";
"Web Page:" = "WWW stránka:";
"Work" = "Práca";
"Other Infos" = "Ostatné informácie";
"Note:" = "Poznámky:";
"Note" = "Poznámky";
"Timezone:" = "Časová zóna:";
"Birthday:" = "Narodeniny:";
"Birthday (yyyy-mm-dd):" = "Narodeniny (dd-mm-yyyy):";
"Birthday" = "Narodeniny";
"Birthday (yyyy-mm-dd)" = "Narodeniny (dd-mm-yyyy)";
"Freebusy URL:" = "URL voľný alebo obsadený:";
"Add as..." = "Pridaj ako...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Detaily zoznamu";
"List name:" = "Meno zoznamu:";
"List nickname:" = "Prezývka zoznamu:";
"List description:" = "Popis zoznamu:";
"List name" = "Meno zoznamu";
"List nickname" = "Prezývka zoznamu";
"List description" = "Popis zoznamu";
"Members" = "Členovia";
"Contacts" = "Kontakty";
"Add" = "Pridaj";
+13 -13
View File
@@ -76,19 +76,19 @@
"No possible subscription" = "Naročnina ni mogoča";
"Preferred" = "Željeno";
"Display:" = "Prikaz:";
"Display Name:" = "Prikazno ime:";
"Display" = "Prikaz";
"Display Name" = "Prikazno ime";
"Email:" = "E-pošta:";
"Additional Email:" = "Dodatna e-pošta:";
"Phone Number:" = "Telefonska številka:";
"Phone Number" = "Telefonska številka";
"Prefers to receive messages formatted as:" = "Željen format za prejeta sporočila:";
"Screen Name:" = "Ime na zaslonu:";
"Categories:" = "Kategorije:";
"First:" = "Prvo:";
"Last:" = "Zadnje:";
"Nickname:" = "Vzdevek:";
"Nickname" = "Vzdevek";
"Telephone" = "Telefon";
"Work:" = "Služba:";
@@ -103,25 +103,25 @@
"New category" = "Nova kategorija";
/* adresses */
"Title:" = "Naslov:";
"Title" = "Naslov";
"Service:" = "Storitev:";
"Company:" = "Podjetje:";
"Department:" = "Oddelek:";
"Organization:" = "Organizacija:";
"Address:" = "Naslov:";
"City:" = "Mesto:";
"City" = "Mesto";
"State_Province:" = "Država/Provinca:";
"ZIP_Postal Code:" = "ZIP/Poštna številka:";
"Country:" = "Država:";
"Country" = "Država";
"Web Page:" = "Spletna stran:";
"Work" = "Delo";
"Other Infos" = "Ostali podatki";
"Note:" = "Opomba:";
"Note" = "Opomba";
"Timezone:" = "Časovni pas:";
"Birthday:" = "Rojstni dan:";
"Birthday (yyyy-mm-dd):" = "Rojstni dan (llll-mm-dd):";
"Birthday" = "Rojstni dan";
"Birthday (yyyy-mm-dd)" = "Rojstni dan (llll-mm-dd)";
"Freebusy URL:" = "Freebusy URL:";
"Add as..." = "Dodaj kot...";
@@ -186,9 +186,9 @@
/* Lists */
"List details" = "Podrobnosti seznama";
"List name:" = "Ime iz seznama:";
"List nickname:" = "Vzdevek iz seznama:";
"List description:" = "Opis iz seznama:";
"List name" = "Ime iz seznama";
"List nickname" = "Vzdevek iz seznama";
"List description" = "Opis iz seznama";
"Members" = "Člani";
"Contacts" = "Stiki";
"Add" = "Dodaj";
Loaded 100 of 239 files, more files were not shown because too many files have changed in this diff. Show more