Compare commits
66
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd9b5e18b6 | ||
|
|
5c017c19fc | ||
|
|
dec152e8e5 | ||
|
|
4922e6004d | ||
|
|
b91972d1dc | ||
|
|
5c3cdda186 | ||
|
|
4b19e64071 | ||
|
|
b6dee056ca | ||
|
|
6830d6d930 | ||
|
|
366ad44cd1 | ||
|
|
9430f40101 | ||
|
|
b7c2d8ae95 | ||
|
|
f03e7a6604 | ||
|
|
4e7a3ce5fa | ||
|
|
61c542cb95 | ||
|
|
d2640e1501 | ||
|
|
20b91cc7bf | ||
|
|
b05f7a5beb | ||
|
|
3a61b7bae4 | ||
|
|
7c6c78d13b | ||
|
|
7db109525d | ||
|
|
d0d93a297b | ||
|
|
936c38c43e | ||
|
|
7da7bdc1bf | ||
|
|
1e101ef01a | ||
|
|
3171257ef4 | ||
|
|
2c8d65843f | ||
|
|
62b16f4ef3 | ||
|
|
b86b1afdb9 | ||
|
|
8e047aaa9c | ||
|
|
dc2cc14d25 | ||
|
|
3f1a43cc13 | ||
|
|
67d0d95869 | ||
|
|
d16bf7c1a7 | ||
|
|
b527099907 | ||
|
|
72aab7f83f | ||
|
|
dfecce7381 | ||
|
|
82798ccb99 | ||
|
|
3809c002ed | ||
|
|
d9b4abc2f1 | ||
|
|
c1b0fd53dc | ||
|
|
c0a22ead1d | ||
|
|
d8e37cd7d8 | ||
|
|
7540cc3e33 | ||
|
|
d92b0341fb | ||
|
|
5e84f2817f | ||
|
|
c61eca27a1 | ||
|
|
96d88de564 | ||
|
|
90e11d76f6 | ||
|
|
3dd8bddc0e | ||
|
|
95f11f6d0d | ||
|
|
1ec53a063c | ||
|
|
cab5846e37 | ||
|
|
76f80c507c | ||
|
|
afed233131 | ||
|
|
b04b66fd79 | ||
|
|
13f2ac9cbb | ||
|
|
7dc333e790 | ||
|
|
cc62576fef | ||
|
|
a1d07c59af | ||
|
|
0a37652dd6 | ||
|
|
725dea5f6f | ||
|
|
76dd53b461 | ||
|
|
020c895925 | ||
|
|
f4963df50f | ||
|
|
7160d94e91 |
No files matched your search
+13
-28
@@ -1,33 +1,18 @@
|
||||
config.make
|
||||
tags
|
||||
*._*
|
||||
*.css
|
||||
*.pyc
|
||||
*.sax
|
||||
*.swp
|
||||
*.wox/
|
||||
*/*/*.SOGo/
|
||||
*/*/*/obj/
|
||||
*/*/obj/
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
*._*
|
||||
*/*/obj/
|
||||
*/*/*/obj/
|
||||
*/*/*.SOGo/
|
||||
*.sax
|
||||
*.wox/
|
||||
*.swp
|
||||
SoObjects/SOGo/SOGo.framework/
|
||||
SoObjects/SOGo/derived_src/
|
||||
Tests/*/config.py
|
||||
UI/WebServerResources/.bowerrc
|
||||
UI/WebServerResources/.sass-cache/
|
||||
UI/WebServerResources/bower_components/
|
||||
UI/WebServerResources/css/
|
||||
UI/WebServerResources/css/styles.css
|
||||
UI/WebServerResources/css/styles.css.map
|
||||
UI/WebServerResources/js/Common.js*
|
||||
UI/WebServerResources/js/Contacts.js*
|
||||
UI/WebServerResources/js/Mailer.js*
|
||||
UI/WebServerResources/js/Preferences.js*
|
||||
UI/WebServerResources/js/Scheduler.js*
|
||||
UI/WebServerResources/js/vendor/
|
||||
UI/WebServerResources/node_modules/
|
||||
UI/WebServerResources/scss/.sass-cache/
|
||||
config.make
|
||||
doc
|
||||
tags
|
||||
*.pyc
|
||||
._*
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "UI/WebServerResources/angular-material"]
|
||||
path = UI/WebServerResources/angular-material
|
||||
url = https://github.com/angular/material
|
||||
+5655
File diff suppressed because it is too large.
Load diff
@@ -1,157 +0,0 @@
|
||||
https://wiki.inverse.ca/focus/SOGo/CodingStyle
|
||||
https://wiki.inverse.ca/focus/SOGo/D%C3%A9veloppement
|
||||
https://wiki.inverse.ca/focus/PacketFence/Devel/BestPractices
|
||||
|
||||
UI and UX
|
||||
---------
|
||||
|
||||
* http://www.google.com/design/spec/material-design/
|
||||
* http://goodui.org/
|
||||
* Try Repeating Your Primary Action instead of showing it just once.
|
||||
* Try Distinct Clickable/Selected Styles instead of blurring them.
|
||||
* Try Undos instead of prompting for confirmation.
|
||||
* Try More Contrast instead of similarity.
|
||||
* Try Exposing Options instead of hiding them.
|
||||
* Try Showing State instead of being state agnostic.
|
||||
* Try Direct Manipulation instead of contextless menus.
|
||||
* Try Exposing Fields instead of creating extra pages.
|
||||
* Try Transitions instead of showing changes instantly.
|
||||
* Try Fewer Borders instead of wasting attention.
|
||||
* Try Designing For Zero Data instead of just data heavy cases.
|
||||
* Try Consistency instead of making people relearn.
|
||||
* Try Conventions instead of reinventing the wheel.
|
||||
* Try Visual Hierarchy instead of dullness.
|
||||
* Try Grouping Related Items instead of disordering.
|
||||
* Try Inline Validation instead of delaying errors.
|
||||
* Try Forgiving Inputs instead of being strict with data.
|
||||
* Try Bigger Click Areas instead of tiny ones.
|
||||
* Try Faster Load Times instead of making people wait.
|
||||
* Try Keyboard Shortcuts instead of buttons only.
|
||||
* Try Upfront Progress instead of starting with a blank.
|
||||
* Try Softer Prompts instead of modal windows.
|
||||
* Try Multifunctional Controls instead of more parts.
|
||||
* Try Icon Labels instead of opening for interpretation.
|
||||
* http://designmodo.com/create-style-guides/
|
||||
* http://uxmyths.com/
|
||||
|
||||
Frameworks & Tools
|
||||
------------------
|
||||
|
||||
GNUstep
|
||||
~~~~~~~
|
||||
|
||||
SOPE
|
||||
~~~~
|
||||
|
||||
AngularJS
|
||||
~~~~~~~~~
|
||||
|
||||
* https://angularjs.org/
|
||||
* http://angular-ui.github.io/ui-router/
|
||||
* https://www.airpair.com/angularjs/posts/angularjs-tutorial
|
||||
|
||||
Angular Material
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* https://material.angularjs.org/
|
||||
|
||||
Lo-Dash
|
||||
~~~~~~~
|
||||
|
||||
* http://lodash.com/
|
||||
* http://underscorejs.org/
|
||||
|
||||
Code Style
|
||||
----------
|
||||
|
||||
Objective-C
|
||||
~~~~~~~~~~~
|
||||
|
||||
* To document the Web APIs, we follow the http://apidocjs.com/[APIDOC] standards.
|
||||
|
||||
apidoc -f ".*\\.m" -i UI -o Documentation/JSON-API
|
||||
|
||||
HTML
|
||||
~~~~
|
||||
|
||||
* Localize your strings:
|
||||
|
||||
<var:string label:value="I'm localized!"/>
|
||||
|
||||
* Localize your attributes:
|
||||
|
||||
<input type="text" label:placeholder="I'm localized!"/>
|
||||
|
||||
* Reuse existing localized strings as much as possible. Otherwise don't forget to update the English Localizable.strings file of the appropriate module.
|
||||
|
||||
JavaScript
|
||||
~~~~~~~~~~
|
||||
|
||||
* http://eslint.org/
|
||||
* https://github.com/toddmotto/angularjs-styleguide
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CODING.md
|
||||
|
||||
* We conform to https://github.com/airbnb/javascript[Airbnb coding standards]. Use https://github.com/jscs-dev/node-jscs[jscs] with the 'airbnb' preset to validate your code style:
|
||||
|
||||
jscs -p airbnb *.js
|
||||
|
||||
* For documentation, we follow the http://usejsdoc.org/[JSDoc3] standards:
|
||||
|
||||
jsdoc UI/WebServerResources/js/{Appointments,Common,Contacts,Mailer}/*.js -d Documentation/JavaScript-API
|
||||
|
||||
Models (facades)
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
////
|
||||
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/
|
||||
////
|
||||
* Move business logic into models and share them.
|
||||
* Keep it simple, separate server interaction and error handling from the model. That way model only handle data processing and code is easier to maintain.
|
||||
|
||||
SASS/CSS
|
||||
~~~~~~~~
|
||||
|
||||
* http://componentcss.com/
|
||||
* https://github.com/styleguide/css
|
||||
* https://smacss.com/
|
||||
|
||||
* For documentation, we follow http://sassdoc.com/[SassDoc] annotations.
|
||||
* We need the SASS files of Angular Material to build our CSS. The git repository of Angular Material is included as a submodule of SOGo:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
* FlexBox compatibility http://caniuse.com/#feat=flexbox
|
||||
|
||||
Fonts
|
||||
^^^^^
|
||||
|
||||
* We build a custom icons font using the online app https://icomoon.io/app/#/select[icomoon].
|
||||
* http://www.carrois.com/fira-4-0/
|
||||
* Material Design Iconic Font http://zavoloklom.github.io/material-design-iconic-font/icons.html
|
||||
|
||||
Version Control
|
||||
---------------
|
||||
|
||||
* https://devcharm.com/articles/46/improve-your-git-workflow/
|
||||
* Each commit should cover only one thing;
|
||||
* Begin the commit message with a single short (less than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description;
|
||||
* When fixing a bug, commit to the devel branch as well as the maintenance branch of the latest release version (named maintenance/x.y). When a ticket is associated to the bug, add to the description a line saying *Fixes #1234*.
|
||||
* `git pull` may introduce http://stackoverflow.com/questions/15316601/in-what-cases-could-git-pull-be-harmful[inconsistencies and problems]. Replace it with the following alias:
|
||||
|
||||
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
* https://github.com/angular/protractor
|
||||
* http://karma-runner.github.io/
|
||||
|
||||
JSON API
|
||||
~~~~~~~~
|
||||
|
||||
One practical way to test the JSON API is to use `curl`. To do so, you need to enable `SOGoTrustProxyAuthentication` and configure HTTP authentifcation in Apache. You can pipe the result to [jq](http://stedolan.github.io/jq/) to nicely format and filter the output:
|
||||
|
||||
curl -u username:password http://localhost/SOGo/so/username/Calendar/calendarslist | jq '.'
|
||||
|
||||
curl -u username:password -H 'Content-Type: application/json' -d '{}' http://localhost/SOGo/so/francis/Calendar/personal/71B6-54904400-1-7C308500.ics/save
|
||||
@@ -1,13 +1,3 @@
|
||||
2.3.x (2015-MM-DD)
|
||||
------------------
|
||||
|
||||
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)
|
||||
|
||||
2.3.1 (2015-07-23)
|
||||
------------------
|
||||
|
||||
@@ -19,6 +9,7 @@ Enhancements
|
||||
- added create-folder subcommand to sogo-tool to create contact and calendar folders
|
||||
- group mail addresses can be used as recipient in Outlook
|
||||
- added 'ActiveSync' module constraints
|
||||
- updated CKEditor to version 4.5.1
|
||||
- added Slovenian translation - thanks to Jens Riecken
|
||||
- added Chinese (Taiwan) translation
|
||||
|
||||
|
||||
@@ -33,9 +33,8 @@
|
||||
}
|
||||
|
||||
- (id) authenticatorInContext: (id) context;
|
||||
- (MAPIStoreUserContext *) userContext;
|
||||
|
||||
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
|
||||
- (void) cleanup;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -76,11 +76,6 @@ MAPIApplication *MAPIApp = nil;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (MAPIStoreUserContext *) userContext
|
||||
{
|
||||
return userContext;
|
||||
}
|
||||
|
||||
- (void) setUserContext: (MAPIStoreUserContext *) newContext
|
||||
{
|
||||
/* user contexts must not be retained here ad their holder (mapistore)
|
||||
@@ -93,9 +88,4 @@ MAPIApplication *MAPIApp = nil;
|
||||
return [userContext authenticator];
|
||||
}
|
||||
|
||||
- (void) cleanup
|
||||
{
|
||||
[userContext deactivate];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -63,15 +63,19 @@
|
||||
SOGoAppointmentObject *newEntry;
|
||||
NSString *name;
|
||||
|
||||
[[self userContext] activate];
|
||||
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,7 +494,6 @@ 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)
|
||||
{
|
||||
@@ -578,7 +577,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
// iCalCalendar *vCalendar;
|
||||
// NSCalendarDate *now;
|
||||
@@ -635,7 +634,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
withActiveUser: activeUser
|
||||
inMemCtx: memCtx];
|
||||
[self _updateAttachedEvents];
|
||||
[[self userContext] activate];
|
||||
[[self userContext] activateWithUser: activeUser];
|
||||
[sogoObject updateContentWithCalendar: calendar
|
||||
fromRequest: nil];
|
||||
[self updateVersions];
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#import <Contacts/SOGoContactFolders.h>
|
||||
|
||||
#import "MAPIApplication.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "MAPIStoreContactsContext.h"
|
||||
#import "MAPIStoreContactsMessage.h"
|
||||
#import "MAPIStoreContactsMessageTable.h"
|
||||
@@ -59,12 +58,10 @@
|
||||
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];
|
||||
@@ -103,7 +100,7 @@
|
||||
rights |= RightsReadItems;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
|
||||
#import "MAPIStoreAttachment.h"
|
||||
// #import "MAPIStoreAttachmentTable.h"
|
||||
#import "MAPIStoreFallbackContext.h"
|
||||
#import "MAPIStoreFolder.h"
|
||||
#import "MAPIStoreFolderTable.h"
|
||||
@@ -88,31 +89,32 @@ 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;
|
||||
|
||||
// User context is activated on initialization
|
||||
[MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: indexing];
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: indexing];
|
||||
[userContext activateWithUser: [userContext sogoUser]];
|
||||
|
||||
classes = GSObjCAllSubclassesOfClass (self);
|
||||
max = [classes count];
|
||||
@@ -120,7 +122,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);
|
||||
@@ -130,7 +132,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;
|
||||
@@ -223,6 +225,8 @@ 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);
|
||||
@@ -294,6 +298,13 @@ 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]);
|
||||
@@ -311,6 +322,12 @@ 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];
|
||||
@@ -338,16 +355,27 @@ 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
|
||||
//[xxxx stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
//stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
objectURL = [[userContext mapping] urlFromID: fmid];
|
||||
if (objectURL)
|
||||
{
|
||||
@@ -368,6 +396,14 @@ 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;
|
||||
}
|
||||
@@ -390,7 +426,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
NSArray *pathComponents;
|
||||
NSUInteger count, max;
|
||||
|
||||
[userContext activate];
|
||||
[userContext activateWithUser: activeUser];
|
||||
woContext = [userContext woContext];
|
||||
|
||||
[self ensureContextFolder];
|
||||
@@ -452,7 +488,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
/* utils */
|
||||
|
||||
- (NSString *) extractChildNameFromURL: (NSString *) objectURL
|
||||
andFolderURLAt: (NSString **) folderURL;
|
||||
andFolderURLAt: (NSString **) folderURL;
|
||||
{
|
||||
NSString *childKey;
|
||||
NSRange lastSlash;
|
||||
@@ -461,15 +497,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;
|
||||
@@ -480,10 +516,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
- (uint64_t) idForObjectWithKey: (NSString *) key
|
||||
inFolderURL: (NSString *) folderURL
|
||||
{
|
||||
NSString *childURL;
|
||||
NSString *childURL, *owner;
|
||||
MAPIStoreMapping *mapping;
|
||||
uint64_t mappingId;
|
||||
enum mapistore_error ret;
|
||||
uint32_t contextId;
|
||||
void *rootObject;
|
||||
|
||||
if (key)
|
||||
childURL = [NSString stringWithFormat: @"%@%@", folderURL,
|
||||
@@ -494,13 +531,17 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
mappingId = [mapping idFromURL: childURL];
|
||||
if (mappingId == NSNotFound)
|
||||
{
|
||||
[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)];
|
||||
//[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);
|
||||
}
|
||||
|
||||
return mappingId;
|
||||
@@ -554,14 +595,15 @@ 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];
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
else
|
||||
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
|
||||
intoNewContainer: nil];
|
||||
|
||||
|
||||
mapping = [self mapping];
|
||||
|
||||
if (targetFolder)
|
||||
@@ -193,8 +193,6 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
SOGoMAPIDBMessage *fsObject;
|
||||
NSString *newKey;
|
||||
|
||||
[[self userContext] activate];
|
||||
|
||||
newKey = [NSString stringWithFormat: @"%@.plist",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
|
||||
@@ -216,13 +214,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
if ([[context activeUser] isEqual: ownerUser]
|
||||
|| [self subscriberCanReadMessages])
|
||||
{
|
||||
[[self userContext] activate];
|
||||
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
}
|
||||
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
else
|
||||
keys = [NSArray array];
|
||||
|
||||
@@ -232,7 +227,6 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
[[self userContext] activate];
|
||||
return [dbFolder childKeysOfType: MAPIFolderCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
@@ -268,7 +262,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
if ([date laterDate: fileDate] == fileDate)
|
||||
{
|
||||
//[self logWithFormat: @"current date: %@", date];
|
||||
|
||||
|
||||
date = fileDate;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +326,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
rights |= RightsFolderContact;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
@@ -367,7 +361,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)];
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
folderName = [folderURL host];
|
||||
|
||||
userContext = [self userContext];
|
||||
[userContext activate];
|
||||
[userContext ensureFolderTableExists];
|
||||
|
||||
ASSIGN (dbFolder,
|
||||
@@ -232,19 +231,30 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
- (id) lookupFolder: (NSString *) folderKey
|
||||
{
|
||||
MAPIStoreFolder *childFolder = nil;
|
||||
MAPIStoreFolder *childFolder;
|
||||
SOGoFolder *sogoFolder;
|
||||
WOContext *woContext;
|
||||
|
||||
childFolder = nil;
|
||||
if ([[self folderKeys] containsObject: folderKey])
|
||||
{
|
||||
[[self userContext] activate];
|
||||
sogoFolder = [sogoObject lookupName: folderKey
|
||||
inContext: nil
|
||||
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
|
||||
acquire: NO];
|
||||
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
|
||||
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
|
||||
inContainer: self];
|
||||
{
|
||||
[sogoFolder setContext: woContext];
|
||||
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
|
||||
inContainer: self];
|
||||
}
|
||||
}
|
||||
else
|
||||
childFolder = nil;
|
||||
|
||||
return childFolder;
|
||||
}
|
||||
@@ -275,7 +285,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
if (messageKey)
|
||||
{
|
||||
[[self userContext] activate];
|
||||
msgObject = [sogoObject lookupName: messageKey
|
||||
inContext: nil
|
||||
acquire: NO];
|
||||
@@ -305,7 +314,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
if (messageKey)
|
||||
{
|
||||
[[self userContext] activate];
|
||||
if ([[self faiMessageKeys] containsObject: messageKey])
|
||||
{
|
||||
msgObject = [dbFolder lookupName: messageKey
|
||||
@@ -538,7 +546,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
context = [self context];
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
[[self userContext] activate];
|
||||
|
||||
if ([[context activeUser] isEqual: ownerUser]
|
||||
|| (!isAssociated && [self subscriberCanCreateMessages]))
|
||||
@@ -751,9 +758,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
}
|
||||
else
|
||||
rc = MAPISTORE_ERR_DENIED;
|
||||
|
||||
|
||||
//talloc_free (memCtx);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -924,7 +931,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
NSArray *newIDs;
|
||||
uint64_t idNbr;
|
||||
bool softDeleted;
|
||||
|
||||
|
||||
baseURL = [self url];
|
||||
|
||||
mapping = [self mapping];
|
||||
@@ -1053,10 +1060,9 @@ 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, PidTagChangeNumber, 0x00000000 };
|
||||
PR_CHANGE_KEY, 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 */
|
||||
@@ -1074,12 +1080,6 @@ 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,7 +1105,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
[[self userContext] activate];
|
||||
return [dbFolder childKeysOfType: MAPIFAICacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
@@ -1214,7 +1213,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
/*
|
||||
Possible values are:
|
||||
|
||||
|
||||
0x00000001 Modify
|
||||
0x00000002 Read
|
||||
0x00000004 Delete
|
||||
@@ -1245,7 +1244,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
access |= 0x10;
|
||||
if (userIsOwner)
|
||||
access |= 0x20;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, access);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1274,7 +1273,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
rights |= RightsCreateSubfolders;
|
||||
if (userIsOwner)
|
||||
rights |= RightsFolderOwner | RightsFolderContact;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, rights);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1310,7 +1309,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = MAPIBoolValue (memCtx, [self supportsSubFolders] && [[self folderKeys] count] > 0);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1318,7 +1317,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = MAPILongValue (memCtx, [[self folderKeys] count]);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1420,7 +1419,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
[dbObject setIsNew: YES];
|
||||
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
|
||||
inContainer: self];
|
||||
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
@@ -1429,8 +1428,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
MAPIStoreMessage *newMessage;
|
||||
WOContext *woContext;
|
||||
|
||||
[[self userContext] activate];
|
||||
|
||||
if (isAssociated)
|
||||
newMessage = [self _createAssociatedMessage];
|
||||
else
|
||||
@@ -1630,7 +1627,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
permissionUser = nil;
|
||||
permissionRoles = nil;
|
||||
|
||||
|
||||
if (currentPermission->PermissionDataFlags == ROW_ADD)
|
||||
isAdd = YES;
|
||||
else if (currentPermission->PermissionDataFlags == ROW_MODIFY)
|
||||
@@ -1781,7 +1778,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: NULL];
|
||||
[MAPIApp setUserContext: userContext];
|
||||
moduleName = [self MAPIModuleName];
|
||||
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
|
||||
nameInContainer = nil;
|
||||
@@ -133,6 +134,7 @@
|
||||
moduleName, nameInContainer];
|
||||
else
|
||||
mapistoreURI = nil;
|
||||
[MAPIApp setUserContext: nil];
|
||||
|
||||
return mapistoreURI;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
NSArray *parts;
|
||||
NSString *lastFolder;
|
||||
NSUInteger max;
|
||||
|
||||
|
||||
parts = [folderName componentsSeparatedByString: @"/"];
|
||||
max = [parts count];
|
||||
if (max > 1)
|
||||
@@ -198,6 +198,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: NULL];
|
||||
[MAPIApp setUserContext: userContext];
|
||||
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
|
||||
folderName = [NSString stringWithFormat: @"folder%@",
|
||||
[newFolderName asCSSIdentifier]];
|
||||
@@ -212,6 +213,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
|
||||
else
|
||||
mapistoreURI = nil;
|
||||
[MAPIApp setUserContext: nil];
|
||||
|
||||
return mapistoreURI;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,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,7 +186,10 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
nameInContainer = [NSString stringWithFormat: @"folder%@",
|
||||
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
|
||||
|
||||
[[self userContext] activate];
|
||||
/* 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]];
|
||||
|
||||
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
|
||||
inContainer: sogoObject];
|
||||
@@ -242,7 +245,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
sortOrdering: nil]
|
||||
count];
|
||||
*data = MAPILongValue (memCtx, longValue);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -250,7 +253,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = [@"IPF.Note" asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -262,7 +265,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
if (!nonDeletedQualifier)
|
||||
{
|
||||
deletedQualifier
|
||||
= [[EOKeyValueQualifier alloc]
|
||||
= [[EOKeyValueQualifier alloc]
|
||||
initWithKey: @"FLAGS"
|
||||
operatorSelector: EOQualifierOperatorContains
|
||||
value: [NSArray arrayWithObject: @"Deleted"]];
|
||||
@@ -375,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)
|
||||
@@ -469,7 +472,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
}
|
||||
else
|
||||
supportsSubFolders = YES;
|
||||
|
||||
|
||||
return supportsSubFolders;
|
||||
}
|
||||
|
||||
@@ -638,7 +641,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
fetchResults
|
||||
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
|
||||
context: NULL];
|
||||
|
||||
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
result = [fetchResults objectAtIndex: count];
|
||||
@@ -948,7 +951,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
}
|
||||
}
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
|
||||
|
||||
[versionsMessage save];
|
||||
}
|
||||
|
||||
@@ -1175,7 +1178,7 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
|
||||
count++;
|
||||
}
|
||||
*UIDsP = UIDs;
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1453,7 +1456,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])
|
||||
{
|
||||
@@ -1492,10 +1495,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
{
|
||||
SOGoCacheObject *childObject;
|
||||
|
||||
[[[self context] userContext] activate];
|
||||
|
||||
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject globallyUniqueObjectId]
|
||||
inContainer: sogoObject];
|
||||
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
|
||||
globallyUniqueObjectId]
|
||||
inContainer: sogoObject];
|
||||
return [MAPIStoreMailVolatileMessage
|
||||
mapiStoreObjectWithSOGoObject: childObject
|
||||
inContainer: self];
|
||||
@@ -1571,7 +1573,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
@@ -1622,7 +1624,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client = [[(SOGoMailFolder *) sogoObject imap4Connection] client];
|
||||
[client select: [sogoObject absoluteImap4Name]];
|
||||
response = [client fetchUids: [keyAssoc allKeys]
|
||||
|
||||
@@ -1614,8 +1614,6 @@ _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];
|
||||
|
||||
@@ -771,12 +771,6 @@ 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)];
|
||||
@@ -1083,7 +1077,6 @@ 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]
|
||||
|
||||
+116
-34
@@ -61,25 +61,20 @@ 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
|
||||
@@ -201,28 +196,12 @@ 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
|
||||
@@ -235,6 +214,8 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreContext *context;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
NS_CURRENT_THREAD_REGISTER();
|
||||
pool = [NSAutoreleasePool new];
|
||||
|
||||
@@ -270,6 +251,8 @@ sogo_backend_create_root_folder (const char *username,
|
||||
NSString *mapistoreUri;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
NS_CURRENT_THREAD_REGISTER();
|
||||
pool = [NSAutoreleasePool new];
|
||||
|
||||
@@ -305,6 +288,8 @@ 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];
|
||||
|
||||
@@ -351,6 +336,8 @@ 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;
|
||||
@@ -383,6 +370,8 @@ 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;
|
||||
@@ -424,6 +413,8 @@ 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;
|
||||
@@ -451,7 +442,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
|
||||
@@ -466,6 +457,8 @@ 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;
|
||||
@@ -507,6 +500,8 @@ sogo_folder_delete(void *folder_object)
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -537,6 +532,8 @@ 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;
|
||||
@@ -571,6 +568,8 @@ sogo_folder_open_message(void *folder_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -611,6 +610,8 @@ sogo_folder_create_message(void *folder_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -621,7 +622,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)
|
||||
@@ -645,6 +646,8 @@ 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;
|
||||
@@ -681,6 +684,8 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -723,6 +728,8 @@ 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;
|
||||
@@ -771,6 +778,8 @@ 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;
|
||||
@@ -813,6 +822,8 @@ 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;
|
||||
@@ -850,6 +861,8 @@ 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;
|
||||
@@ -887,6 +900,8 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -919,6 +934,8 @@ 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;
|
||||
@@ -952,6 +969,8 @@ sogo_message_get_message_data(void *message_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -985,6 +1004,8 @@ 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;
|
||||
@@ -996,6 +1017,7 @@ 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];
|
||||
@@ -1019,6 +1041,8 @@ 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;
|
||||
@@ -1030,6 +1054,7 @@ 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];
|
||||
@@ -1052,6 +1077,8 @@ 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;
|
||||
@@ -1064,6 +1091,7 @@ 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];
|
||||
@@ -1088,6 +1116,9 @@ sogo_message_modify_recipients (void *message_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1099,6 +1130,7 @@ sogo_message_modify_recipients (void *message_object,
|
||||
rc = [message modifyRecipientsWithRecipients: recipients
|
||||
andCount: count
|
||||
andColumns: columns];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1120,6 +1152,9 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1129,6 +1164,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message setReadFlag: flag];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1150,6 +1186,9 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1159,6 +1198,7 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message saveMessage: mem_ctx];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1180,6 +1220,9 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
|
||||
MAPIStoreMailVolatileMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1189,6 +1232,7 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message submitWithFlags: flags];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1215,6 +1259,9 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
|
||||
MAPIStoreEmbeddedMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (attachment_object)
|
||||
{
|
||||
wrapper = attachment_object;
|
||||
@@ -1254,6 +1301,9 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
|
||||
MAPIStoreEmbeddedMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (attachment_object)
|
||||
{
|
||||
wrapper = attachment_object;
|
||||
@@ -1288,6 +1338,9 @@ 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;
|
||||
@@ -1318,6 +1371,9 @@ 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;
|
||||
@@ -1349,6 +1405,9 @@ 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;
|
||||
@@ -1382,6 +1441,9 @@ 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;
|
||||
@@ -1417,6 +1479,9 @@ 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;
|
||||
@@ -1450,6 +1515,9 @@ sogo_table_get_row_count (void *table_object,
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1481,6 +1549,9 @@ 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;
|
||||
@@ -1513,6 +1584,9 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1546,6 +1620,9 @@ sogo_properties_get_properties (void *object,
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1578,6 +1655,9 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1601,16 +1681,18 @@ 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
|
||||
@@ -1656,9 +1738,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;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#import <Appointments/SOGoTaskObject.h>
|
||||
|
||||
#import "MAPIApplication.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "MAPIStoreTasksContext.h"
|
||||
#import "MAPIStoreTasksMessage.h"
|
||||
#import "MAPIStoreTasksMessageTable.h"
|
||||
@@ -62,7 +61,6 @@
|
||||
SOGoTaskObject *newEntry;
|
||||
NSString *name;
|
||||
|
||||
[[[self context] userContext] activate];
|
||||
name = [NSString stringWithFormat: @"%@.ics",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
newEntry = [SOGoTaskObject objectWithName: name
|
||||
@@ -71,7 +69,7 @@
|
||||
newMessage = [MAPIStoreTasksMessage mapiStoreObjectWithSOGoObject: newEntry
|
||||
inContainer: self];
|
||||
|
||||
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
@@ -118,7 +116,7 @@
|
||||
rights |= RightsReadItems;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,6 @@
|
||||
|
||||
/* SOGo hacky magic */
|
||||
- (void) activateWithUser: (SOGoUser *) activeUser;
|
||||
- (void) activate;
|
||||
- (void) deactivate;
|
||||
- (MAPIStoreAuthenticator *) authenticator;
|
||||
- (WOContext *) woContext;
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#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>
|
||||
|
||||
@@ -159,8 +158,6 @@ static NSMapTable *contextsTable = nil;
|
||||
if ([userPassword length] == 0)
|
||||
userPassword = username;
|
||||
[authenticator setPassword: userPassword];
|
||||
// Activate the profile on initialization
|
||||
[self activate];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -217,7 +214,7 @@ static NSMapTable *contextsTable = nil;
|
||||
if (!userFolder)
|
||||
{
|
||||
userFolder = [SOGoUserFolder objectWithName: username
|
||||
inContainer: nil];
|
||||
inContainer: MAPIApp];
|
||||
[userFolder retain];
|
||||
}
|
||||
|
||||
@@ -235,8 +232,7 @@ static NSMapTable *contextsTable = nil;
|
||||
if (!rootFolders)
|
||||
{
|
||||
rootFolders = [NSMutableDictionary new];
|
||||
[self activate];
|
||||
[self userFolder]; // force lazy initialization
|
||||
[self userFolder];
|
||||
[woContext setClientObject: userFolder];
|
||||
|
||||
/* Calendar */
|
||||
@@ -261,10 +257,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];
|
||||
@@ -272,7 +268,8 @@ 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"];
|
||||
}
|
||||
@@ -341,7 +338,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:
|
||||
@@ -358,7 +355,7 @@ static NSMapTable *contextsTable = nil;
|
||||
[channel cancelFetch];
|
||||
|
||||
|
||||
[cm releaseChannel: channel];
|
||||
[cm releaseChannel: channel];
|
||||
}
|
||||
|
||||
/* SOGo context objects */
|
||||
@@ -372,11 +369,6 @@ static NSMapTable *contextsTable = nil;
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
- (void) activate
|
||||
{
|
||||
[self activateWithUser: [self sogoUser]];
|
||||
}
|
||||
|
||||
- (void) activateWithUser: (SOGoUser *) activeUser;
|
||||
{
|
||||
NSMutableDictionary *info;
|
||||
@@ -387,24 +379,4 @@ 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
|
||||
@@ -1,27 +0,0 @@
|
||||
[](http://www.sogo.nu/)
|
||||
|
||||
Share your calendars, address books and mails in your community with a completely free and open source solution.
|
||||
|
||||
Let your Mozilla Thunderbird/Lightning, Microsoft Outlook, Apple iCal/iPhone, Android and BlackBerry users collaborate using a modern platform.
|
||||
|
||||
## What is SOGo?
|
||||
|
||||
SOGo is [fully supported](http://www.sogo.nu/support/commercial_support.html) and [trusted](http://www.sogo.nu/tour/testimonials.html) groupware server with a focus on scalability and open standards. SOGo is released under the GNU GPL/LGPL v2 and above.
|
||||
|
||||
SOGo provides a rich AJAX-based Web interface and supports multiple native clients through the use of standard protocols such as CalDAV, CardDAV and GroupDAV.
|
||||
|
||||
SOGo is the missing component of your infrastructure; it sits in the middle of your servers to offer your users an uniform and complete interface to access their information. It has been deployed in production environments where thousands of users are involved.
|
||||
|
||||
[](http://www.sogo.nu/)
|
||||
|
||||
[Learn more...](http://www.sogo.nu/about/overview.html)
|
||||
|
||||
## Microsoft Outlook Compatible
|
||||
|
||||
SOGo offers native Microsoft Outlook compatibility using the [OpenChange](http://www.openchange.org/) backend developed by [Inverse](http://www.inverse.ca/). This means Microsoft Outlook 2003, 2007, 2010 and 2013 can talk directly to SOGo – just like if it was a Microsoft Exchange server. **No plugins are required in Outlook to make this work**.
|
||||
|
||||
The following screencast shows Outlook 2010 connected to SOGo as if it was an Exchange server, along the Web interface of SOGo.
|
||||
|
||||
[](http://www.youtube.com/watch?v=1hcBSB4Kxww)
|
||||
|
||||
[](https://github.com/inverse-inc/sogo/) [](https://www.ohloh.net/p/sogo) [](http://twitter.com/scalableogo) [](http://sourceforge.net/projects/sogo-zeg) [](https://freecode.com/projects/sogo-inverse) [](http://www.linkedin.com/groups/SOGo-Groupware-4164805)
|
||||
@@ -1,6 +1,8 @@
|
||||
/* iCalByDayMask.h - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2010-2015 Inverse inc.
|
||||
* Copyright (C) 2010 Wolfgang Sourdeau
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -53,8 +55,6 @@ typedef iCalWeekOccurrence iCalWeekOccurrences[7];
|
||||
- (id) initWithDays: (iCalWeekOccurrences) theDays;
|
||||
+ (id) byDayMaskWithRuleString: (NSString *) byDayRule;
|
||||
- (id) initWithRuleString: (NSString *) byDayRule;
|
||||
+ (id) byDayMaskWithDaysAndOccurrences: (NSArray *) values;
|
||||
- (id) initWithDaysAndOccurrences: (NSArray *) values;
|
||||
|
||||
- (BOOL) occursOnDay: (iCalWeekDay) weekDay;
|
||||
- (BOOL) occursOnDay: (iCalWeekDay) weekDay
|
||||
@@ -71,7 +71,6 @@ typedef iCalWeekOccurrence iCalWeekOccurrences[7];
|
||||
|
||||
- (NSString *) asRuleString;
|
||||
- (NSString *) asRuleStringWithIntegers;
|
||||
- (NSArray *) asRuleArray;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+20
-159
@@ -1,6 +1,8 @@
|
||||
/* iCalByDayMask.m - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2010-2015 Inverse inc.
|
||||
* Copyright (C) 2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,9 +21,7 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import "iCalByDayMask.h"
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
+ (id) byDayMaskWithDays: (iCalWeekOccurrences) theDays
|
||||
{
|
||||
id o;
|
||||
|
||||
|
||||
o = [[self alloc] initWithDays: theDays];
|
||||
AUTORELEASE(o);
|
||||
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
{
|
||||
id o;
|
||||
iCalWeekOccurrences d;
|
||||
|
||||
|
||||
d[iCalWeekDaySunday] = 0;
|
||||
d[iCalWeekDayMonday] = iCalWeekOccurrenceAll;
|
||||
d[iCalWeekDayTuesday] = iCalWeekOccurrenceAll;
|
||||
@@ -72,7 +72,7 @@
|
||||
d[iCalWeekDaySaturday] = 0;
|
||||
o = [[self alloc] initWithDays: d];
|
||||
AUTORELEASE(o);
|
||||
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
if (self)
|
||||
{
|
||||
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
|
||||
|
||||
|
||||
if ([byDayRule length] > 0)
|
||||
{
|
||||
values = [byDayRule componentsSeparatedByString: @","];
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
[value getCharacters: chars
|
||||
range: NSMakeRange(valueLength - 2, 2)];
|
||||
|
||||
|
||||
switch (chars[0])
|
||||
{
|
||||
case 'M': day = iCalWeekDayMonday;
|
||||
@@ -142,7 +142,7 @@
|
||||
day = iCalWeekDaySunday;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (day != iCalWeekDayUnknown)
|
||||
{
|
||||
c = [value characterAtIndex: 0];
|
||||
@@ -157,15 +157,15 @@
|
||||
digitStart = 1;
|
||||
c = [value characterAtIndex: 1];
|
||||
}
|
||||
|
||||
|
||||
i = digitStart;
|
||||
|
||||
|
||||
while (i < valueLength && isdigit(c))
|
||||
{
|
||||
i++;
|
||||
c = [value characterAtIndex: i];
|
||||
}
|
||||
|
||||
|
||||
if (i != digitStart)
|
||||
order = [[value substringWithRange: NSMakeRange(digitStart, (i - digitStart))] intValue];
|
||||
|
||||
@@ -186,123 +186,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) byDayMaskWithDaysAndOccurrences: (NSArray *) values
|
||||
{
|
||||
id o;
|
||||
|
||||
o = [[self alloc] initWithDaysAndOccurrences: values];
|
||||
AUTORELEASE(o);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (id) initWithDaysAndOccurrences: (NSArray *) values
|
||||
{
|
||||
unsigned int count, max;
|
||||
NSString *value;
|
||||
unichar c, chars[2];
|
||||
unsigned int valueLength, i, digitStart, order;
|
||||
iCalWeekDay day;
|
||||
id mask;
|
||||
BOOL reverse;
|
||||
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
|
||||
|
||||
max = [values count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
mask = [values objectAtIndex: count];
|
||||
if (![mask isKindOfClass: [NSDictionary class]])
|
||||
continue;
|
||||
value = [[mask objectForKey: @"day"] uppercaseString];
|
||||
valueLength = [value length];
|
||||
if (valueLength > 1)
|
||||
{
|
||||
day = iCalWeekDayUnknown;
|
||||
reverse = NO;
|
||||
digitStart = 0;
|
||||
order = 0;
|
||||
|
||||
[value getCharacters: chars
|
||||
range: NSMakeRange(0, valueLength)];
|
||||
|
||||
switch (chars[0])
|
||||
{
|
||||
case 'M': day = iCalWeekDayMonday;
|
||||
break;
|
||||
case 'W': day = iCalWeekDayWednesday;
|
||||
break;
|
||||
case 'F': day = iCalWeekDayFriday;
|
||||
break;
|
||||
case 'T':
|
||||
if (chars[1] == 'U')
|
||||
day = iCalWeekDayTuesday;
|
||||
else if (chars[1] == 'H')
|
||||
day = iCalWeekDayThursday;
|
||||
break;
|
||||
case 'S':
|
||||
if (chars[1] == 'A')
|
||||
day = iCalWeekDaySaturday;
|
||||
else if (chars[1] == 'U')
|
||||
day = iCalWeekDaySunday;
|
||||
break;
|
||||
}
|
||||
|
||||
if (day != iCalWeekDayUnknown)
|
||||
{
|
||||
value = [mask objectForKey: @"occurrence"];
|
||||
valueLength = [value length];
|
||||
if (valueLength > 0)
|
||||
{
|
||||
c = [value characterAtIndex: 0];
|
||||
if (c == '-')
|
||||
{
|
||||
digitStart = 1;
|
||||
reverse = YES;
|
||||
}
|
||||
else if (c == '+')
|
||||
{
|
||||
digitStart = 1;
|
||||
}
|
||||
|
||||
i = digitStart;
|
||||
while (i < valueLength)
|
||||
{
|
||||
c = [value characterAtIndex: i];
|
||||
i++;
|
||||
if (!isdigit(c))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != digitStart)
|
||||
order = [[value substringWithRange: NSMakeRange(digitStart, (i - digitStart))] intValue];
|
||||
}
|
||||
|
||||
if (order > 0 && order < 6)
|
||||
{
|
||||
order = pow (2, order - 1);
|
||||
if (reverse)
|
||||
order = order << 5;
|
||||
days[day] |= order;
|
||||
//NSLog(@"*** iCalByDayMask [%i] %@ : day = %i, order = %i, result = %i", count, byDayRule, day, order, days[day]);
|
||||
}
|
||||
else
|
||||
{
|
||||
days[day] = iCalWeekOccurrenceAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -330,7 +214,7 @@
|
||||
withWeekNumber: (int) week
|
||||
{
|
||||
unsigned int absWeek, order;
|
||||
|
||||
|
||||
absWeek = abs (week);
|
||||
order = 0;
|
||||
if (absWeek > 0 && absWeek < 6)
|
||||
@@ -339,7 +223,7 @@
|
||||
if (week < 0)
|
||||
order = order << 5;
|
||||
}
|
||||
|
||||
|
||||
return ((days[weekDay] & order) > 0);
|
||||
}
|
||||
|
||||
@@ -365,7 +249,7 @@
|
||||
if (days[i])
|
||||
day = i;
|
||||
}
|
||||
|
||||
|
||||
return day;
|
||||
}
|
||||
|
||||
@@ -376,10 +260,10 @@
|
||||
|
||||
occurrence = 0;
|
||||
day = [self firstDay];
|
||||
|
||||
|
||||
if (day > -1 && days[day] != iCalWeekOccurrenceAll)
|
||||
occurrence = [self _iCalWeekOccurrenceIntValue: days[day]];
|
||||
|
||||
|
||||
return occurrence;
|
||||
}
|
||||
|
||||
@@ -439,7 +323,7 @@
|
||||
[rules addObject: rule];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return [rules componentsJoinedByString: @","];
|
||||
}
|
||||
|
||||
@@ -460,27 +344,4 @@
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSArray *) asRuleArray
|
||||
{
|
||||
NSMutableArray *rules;
|
||||
NSMutableDictionary *rule;
|
||||
int i;
|
||||
|
||||
rules = [NSMutableArray array];
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (days[i])
|
||||
{
|
||||
rule = [NSMutableDictionary dictionary];
|
||||
if (days[i] != iCalWeekOccurrenceAll)
|
||||
[rule setObject: [NSNumber numberWithInt: [self _iCalWeekOccurrenceIntValue: days[i]]]
|
||||
forKey: @"occurrence"];
|
||||
[rule setObject: iCalWeekDayString[i]
|
||||
forKey: @"day"];
|
||||
[rules addObject: rule];
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
@end /* iCalByDayMask */
|
||||
@@ -94,8 +94,8 @@ typedef enum
|
||||
- (void) increaseSequence;
|
||||
|
||||
/* url can either be set as NSString or NSURL */
|
||||
- (void) setAttach: (NSArray *) _value;
|
||||
- (NSArray *) attach;
|
||||
- (void) setAttach: (id) _value;
|
||||
- (NSURL *) attach;
|
||||
- (void) setUrl: (id) _value;
|
||||
- (NSURL *) url;
|
||||
|
||||
|
||||
@@ -400,49 +400,32 @@
|
||||
return [self childrenWithTag: @"valarm"];
|
||||
}
|
||||
|
||||
- (void) setAttach: (NSArray *) _value
|
||||
- (void) setAttach: (id) _value
|
||||
{
|
||||
NSString *aString;
|
||||
id anObject;
|
||||
int count, max;
|
||||
|
||||
max = [_value count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
anObject = [_value objectAtIndex: count];
|
||||
if ([anObject isKindOfClass: [NSURL class]])
|
||||
{
|
||||
aString = [anObject absoluteString];
|
||||
}
|
||||
else
|
||||
aString = anObject;
|
||||
[self addChild: [CardElement simpleElementWithTag: @"attach" value: aString]];
|
||||
}
|
||||
if ([_value isKindOfClass: [NSString class]])
|
||||
aString = _value;
|
||||
else if ([_value isKindOfClass: [NSURL class]])
|
||||
aString = [_value absoluteString];
|
||||
else
|
||||
aString = @"";
|
||||
|
||||
[[self uniqueChildWithTag: @"attach"] setSingleValue: aString forKey: @""];
|
||||
}
|
||||
|
||||
- (NSArray *) attach
|
||||
- (NSURL *) attach
|
||||
{
|
||||
NSArray *elements;
|
||||
NSMutableArray *attachUrls;
|
||||
NSString *stringAttach;
|
||||
NSURL *url;
|
||||
int count, max;
|
||||
|
||||
elements = [self childrenWithTag: @"attach"];
|
||||
max = [elements count];
|
||||
attachUrls = [NSMutableArray arrayWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
stringAttach = [[elements objectAtIndex: count] flattenedValuesForKey: @""];
|
||||
url = [NSURL URLWithString: stringAttach];
|
||||
stringAttach = [[self uniqueChildWithTag: @"attach"] flattenedValuesForKey: @""];
|
||||
url = [NSURL URLWithString: stringAttach];
|
||||
|
||||
if (!url && [stringAttach length] > 0)
|
||||
url = [NSURL URLWithString: [NSString stringWithFormat: @"http://%@", stringAttach]];
|
||||
|
||||
[attachUrls addObject: [url absoluteString]];
|
||||
}
|
||||
if (!url && [stringAttach length] > 0)
|
||||
url = [NSURL URLWithString: [NSString stringWithFormat: @"http://%@", stringAttach]];
|
||||
|
||||
return attachUrls;
|
||||
return url;
|
||||
}
|
||||
|
||||
- (void) setUrl: (id) _value
|
||||
|
||||
@@ -44,8 +44,6 @@ typedef enum {
|
||||
|
||||
@interface iCalPerson : CardElement
|
||||
|
||||
+ (NSString *) descriptionForParticipationStatus: (iCalPersonPartStat) _status;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void)setCn:(NSString *)_s;
|
||||
|
||||
+34
-45
@@ -25,48 +25,6 @@
|
||||
|
||||
@implementation iCalPerson
|
||||
|
||||
+ (NSString *) descriptionForParticipationStatus: (iCalPersonPartStat) _status
|
||||
{
|
||||
NSString *stat;
|
||||
|
||||
switch (_status) {
|
||||
case iCalPersonPartStatUndefined:
|
||||
stat = @"";
|
||||
break;
|
||||
case iCalPersonPartStatAccepted:
|
||||
stat = @"ACCEPTED";
|
||||
break;
|
||||
case iCalPersonPartStatDeclined:
|
||||
stat = @"DECLINED";
|
||||
break;
|
||||
case iCalPersonPartStatTentative:
|
||||
stat = @"TENTATIVE";
|
||||
break;
|
||||
case iCalPersonPartStatDelegated:
|
||||
stat = @"DELEGATED";
|
||||
break;
|
||||
case iCalPersonPartStatCompleted:
|
||||
stat = @"COMPLETED";
|
||||
break;
|
||||
case iCalPersonPartStatInProcess:
|
||||
stat = @"IN-PROCESS";
|
||||
break;
|
||||
case iCalPersonPartStatExperimental:
|
||||
case iCalPersonPartStatOther:
|
||||
// [NSException raise:NSInternalInconsistencyException
|
||||
// format:@"Attempt to set meaningless "
|
||||
// @"participationStatus (%d)!", _status];
|
||||
stat = nil; /* keep compiler happy */
|
||||
break;
|
||||
default:
|
||||
stat = @"NEEDS-ACTION";
|
||||
break;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setCn: (NSString *) _s
|
||||
@@ -174,13 +132,44 @@
|
||||
{
|
||||
NSString *stat;
|
||||
|
||||
stat = [iCalPerson descriptionForParticipationStatus: _status];
|
||||
|
||||
switch (_status) {
|
||||
case iCalPersonPartStatUndefined:
|
||||
stat = @"";
|
||||
break;
|
||||
case iCalPersonPartStatAccepted:
|
||||
stat = @"ACCEPTED";
|
||||
break;
|
||||
case iCalPersonPartStatDeclined:
|
||||
stat = @"DECLINED";
|
||||
break;
|
||||
case iCalPersonPartStatTentative:
|
||||
stat = @"TENTATIVE";
|
||||
break;
|
||||
case iCalPersonPartStatDelegated:
|
||||
stat = @"DELEGATED";
|
||||
break;
|
||||
case iCalPersonPartStatCompleted:
|
||||
stat = @"COMPLETED";
|
||||
break;
|
||||
case iCalPersonPartStatInProcess:
|
||||
stat = @"IN-PROCESS";
|
||||
break;
|
||||
case iCalPersonPartStatExperimental:
|
||||
case iCalPersonPartStatOther:
|
||||
// [NSException raise:NSInternalInconsistencyException
|
||||
// format:@"Attempt to set meaningless "
|
||||
// @"participationStatus (%d)!", _status];
|
||||
stat = nil; /* keep compiler happy */
|
||||
break;
|
||||
default:
|
||||
stat = @"NEEDS-ACTION";
|
||||
break;
|
||||
}
|
||||
if (stat)
|
||||
[self setPartStat:stat];
|
||||
}
|
||||
|
||||
- (iCalPersonPartStat) participationStatus {
|
||||
- (iCalPersonPartStat)participationStatus {
|
||||
NSString *stat;
|
||||
|
||||
stat = [[self partStat] uppercaseString];
|
||||
|
||||
@@ -75,7 +75,6 @@ extern NSString *iCalWeekDayString[];
|
||||
- (void) setFrequency: (iCalRecurrenceFrequency) _frequency;
|
||||
- (iCalRecurrenceFrequency) frequency;
|
||||
- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value;
|
||||
- (NSString *) frequencyForValue: (iCalRecurrenceFrequency) freq;
|
||||
|
||||
- (void) setRepeatInterval: (int) _repeatInterval;
|
||||
- (int) repeatInterval;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalTimeZone.m - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2006-2015 Inverse inc.
|
||||
* Copyright (C) 2006-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -147,8 +147,7 @@ static NSArray *knownTimeZones;
|
||||
if (ext.location != NSNotFound)
|
||||
{
|
||||
zone = [zone substringToIndex: ext.location];
|
||||
if (![timeZoneNames containsObject: zone])
|
||||
[timeZoneNames addObject: zone];
|
||||
[timeZoneNames addObject: zone];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
- (NSString *) percentComplete;
|
||||
|
||||
- (void) setDue: (NSCalendarDate *) _date;
|
||||
- (void) setAllDayDue: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) due;
|
||||
|
||||
- (void) setCompleted: (NSCalendarDate *) _date;
|
||||
|
||||
@@ -65,12 +65,6 @@
|
||||
setDateTime: newDueDate];
|
||||
}
|
||||
|
||||
- (void) setAllDayDue: (NSCalendarDate *) newDueDate
|
||||
{
|
||||
[(iCalDateTime *) [self uniqueChildWithTag: @"due"]
|
||||
setDate: newDueDate];
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) due
|
||||
{
|
||||
return [(iCalDateTime *) [self uniqueChildWithTag: @"due"]
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
|
||||
- (NSCalendarDate *) nextAlarmDate;
|
||||
|
||||
- (NSDictionary *) asDictionary;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __NGCards_iCalTrigger_H__ */
|
||||
@@ -20,9 +20,7 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import "iCalEvent.h"
|
||||
#import "iCalTrigger.h"
|
||||
@@ -54,78 +52,6 @@
|
||||
return [self value: 0 ofAttribute: @"related"];
|
||||
}
|
||||
|
||||
- (NSDictionary *) asDictionary
|
||||
{
|
||||
NSDictionary *data;
|
||||
NSString *duration, *relation, *reference, *quantity, *unit;
|
||||
NSUInteger i;
|
||||
unichar c;
|
||||
|
||||
data = nil;
|
||||
if (![[self valueType] length] ||
|
||||
[[self valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
|
||||
{
|
||||
relation = [[self relationType] uppercaseString];
|
||||
duration = [self flattenedValuesForKey: @""];
|
||||
i = 0;
|
||||
c = [duration characterAtIndex: i];
|
||||
if (c == '-')
|
||||
{
|
||||
reference = @"BEFORE";
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
reference = @"AFTER";
|
||||
}
|
||||
c = [duration characterAtIndex: i];
|
||||
if (c == 'P')
|
||||
{
|
||||
quantity = @"";
|
||||
unit = @"";
|
||||
// Parse duration -- ignore first character (P)
|
||||
for (i++; i < [duration length]; i++)
|
||||
{
|
||||
c = [duration characterAtIndex: i];
|
||||
if (c == 't' || c == 'T')
|
||||
// time -- ignore character
|
||||
continue;
|
||||
else if (isdigit (c))
|
||||
quantity = [quantity stringByAppendingFormat: @"%c", c];
|
||||
else
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'D': /* day */
|
||||
unit = @"DAYS";
|
||||
break;
|
||||
case 'H': /* hour */
|
||||
unit = @"HOURS";
|
||||
break;
|
||||
case 'M': /* min */
|
||||
unit = @"MINUTES";
|
||||
break;
|
||||
case 'W': /* week */
|
||||
unit = @"WEEKS";
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Cannot process duration unit: '%c'", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
relation, @"relation",
|
||||
reference, @"reference",
|
||||
[NSNumber numberWithInt: [quantity intValue]], @"quantity",
|
||||
unit, @"unit",
|
||||
nil];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) nextAlarmDate
|
||||
{
|
||||
NSCalendarDate *relationDate, *nextAlarmDate;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/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" = "Комментарий:";
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ typedef enum {
|
||||
NSMutableDictionary *uidToFilename;
|
||||
NSMutableDictionary *aclMatrix;
|
||||
NSMutableArray *stripFields;
|
||||
NSString *baseCalDAVURL, *basePublicCalDAVURL;
|
||||
int davCalendarStartTimeLimit;
|
||||
int davTimeLimitSeconds;
|
||||
int davTimeHalfLimitSeconds;
|
||||
@@ -74,7 +73,6 @@ typedef enum {
|
||||
}
|
||||
|
||||
- (BOOL) isActive;
|
||||
- (BOOL) isWebCalendar;
|
||||
|
||||
- (NSString *) calendarColor;
|
||||
- (void) setCalendarColor: (NSString *) newColor;
|
||||
@@ -131,13 +129,6 @@ typedef enum {
|
||||
- (NSString *) baseURLForAptWithUID: (NSString *) _uid
|
||||
inContext: (id) _ctx;
|
||||
|
||||
- (NSString *) calDavURL;
|
||||
- (NSString *) webDavICSURL;
|
||||
- (NSString *) webDavXMLURL;
|
||||
- (NSString *) publicCalDavURL;
|
||||
- (NSString *) publicWebDavICSURL;
|
||||
- (NSString *) publicWebDavXMLURL;
|
||||
|
||||
/* folder management */
|
||||
|
||||
- (id) lookupHomeFolderForUID: (NSString *) _uid
|
||||
@@ -166,6 +157,12 @@ typedef enum {
|
||||
- (BOOL) showCalendarTasks;
|
||||
- (void) setShowCalendarTasks: (BOOL) new;
|
||||
|
||||
- (NSString *) syncTag;
|
||||
- (void) setSyncTag: (NSString *) newSyncTag;
|
||||
|
||||
- (BOOL) synchronizeCalendar;
|
||||
- (void) setSynchronizeCalendar: (BOOL) new;
|
||||
|
||||
- (BOOL) includeInFreeBusy;
|
||||
- (void) setIncludeInFreeBusy: (BOOL) newInclude;
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
#import "SOGoAppointmentFolders.h"
|
||||
#import "SOGoFreeBusyObject.h"
|
||||
#import "SOGoTaskObject.h"
|
||||
#import "SOGoWebAppointmentFolder.h";
|
||||
|
||||
#import "SOGoAppointmentFolder.h"
|
||||
|
||||
@@ -333,15 +332,13 @@ static Class iCalEventK = nil;
|
||||
memset (userCanAccessObjectsClassifiedAs, NO,
|
||||
iCalAccessClassCount * sizeof (BOOL));
|
||||
|
||||
davCalendarStartTimeLimit = [[user domainDefaults] davCalendarStartTimeLimit];
|
||||
davCalendarStartTimeLimit
|
||||
= [[user domainDefaults] davCalendarStartTimeLimit];
|
||||
davTimeLimitSeconds = davCalendarStartTimeLimit * 86400;
|
||||
/* 86400 / 2 = 43200. We hardcode that value in order to avoid
|
||||
integer and float confusion. */
|
||||
davTimeHalfLimitSeconds = davCalendarStartTimeLimit * 43200;
|
||||
componentSet = nil;
|
||||
|
||||
baseCalDAVURL = nil;
|
||||
basePublicCalDAVURL = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -353,8 +350,6 @@ static Class iCalEventK = nil;
|
||||
[stripFields release];
|
||||
[uidToFilename release];
|
||||
[componentSet release];
|
||||
[baseCalDAVURL release];
|
||||
[basePublicCalDAVURL release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -437,6 +432,61 @@ static Class iCalEventK = nil;
|
||||
inCategory: @"FolderShowTasks"];
|
||||
}
|
||||
|
||||
- (NSString *) syncTag
|
||||
{
|
||||
NSString *syncTag;
|
||||
|
||||
syncTag = [self folderPropertyValueInCategory: @"FolderSyncTags"];
|
||||
if (!syncTag)
|
||||
syncTag = @"";
|
||||
|
||||
return syncTag;
|
||||
}
|
||||
|
||||
- (void) setSyncTag: (NSString *) newSyncTag
|
||||
{
|
||||
// Check for duplicated tags
|
||||
SOGoUserSettings *settings;
|
||||
NSDictionary *syncTags;
|
||||
NSArray *values;
|
||||
|
||||
if ([newSyncTag length])
|
||||
{
|
||||
settings = [[context activeUser] userSettings];
|
||||
syncTags = [[settings objectForKey: @"Calendar"]
|
||||
objectForKey: @"FolderSyncTags"];
|
||||
values = [syncTags allValues];
|
||||
if (![values containsObject: newSyncTag])
|
||||
[self setFolderPropertyValue: newSyncTag
|
||||
inCategory: @"FolderSyncTags"];
|
||||
}
|
||||
else
|
||||
[self setFolderPropertyValue: nil
|
||||
inCategory: @"FolderSyncTags"];
|
||||
}
|
||||
|
||||
- (BOOL) synchronizeCalendar
|
||||
{
|
||||
NSNumber *synchronize;
|
||||
|
||||
synchronize = [self folderPropertyValueInCategory: @"FolderSynchronize"];
|
||||
|
||||
return [synchronize boolValue];
|
||||
}
|
||||
|
||||
- (void) setSynchronizeCalendar: (BOOL) new
|
||||
{
|
||||
NSNumber *synchronize;
|
||||
|
||||
if (new)
|
||||
synchronize = [NSNumber numberWithBool: YES];
|
||||
else
|
||||
synchronize = nil;
|
||||
|
||||
[self setFolderPropertyValue: synchronize
|
||||
inCategory: @"FolderSynchronize"];
|
||||
}
|
||||
|
||||
//
|
||||
// If the user is the owner of the calendar, by default we include the freebusy information.
|
||||
//
|
||||
@@ -2819,70 +2869,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
return [url stringByAppendingString:_uid];
|
||||
}
|
||||
|
||||
- (NSString *) _baseCalDAVURL
|
||||
{
|
||||
NSString *davURL;
|
||||
|
||||
if (!baseCalDAVURL)
|
||||
{
|
||||
davURL = [[self realDavURL] absoluteString];
|
||||
if ([davURL hasSuffix: @"/"])
|
||||
baseCalDAVURL = [davURL substringToIndex: [davURL length] - 1];
|
||||
else
|
||||
baseCalDAVURL = davURL;
|
||||
[baseCalDAVURL retain];
|
||||
}
|
||||
|
||||
return baseCalDAVURL;
|
||||
}
|
||||
|
||||
- (NSString *) _basePublicCalDAVURL
|
||||
{
|
||||
NSString *davURL;
|
||||
|
||||
if (!basePublicCalDAVURL)
|
||||
{
|
||||
davURL = [[self publicDavURL] absoluteString];
|
||||
if ([davURL hasSuffix: @"/"])
|
||||
basePublicCalDAVURL = [davURL substringToIndex: [davURL length] - 1];
|
||||
else
|
||||
basePublicCalDAVURL = davURL;
|
||||
[basePublicCalDAVURL retain];
|
||||
}
|
||||
|
||||
return basePublicCalDAVURL;
|
||||
}
|
||||
|
||||
- (NSString *) calDavURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@/", [self _baseCalDAVURL]];
|
||||
}
|
||||
|
||||
- (NSString *) webDavICSURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@.ics", [self _baseCalDAVURL]];
|
||||
}
|
||||
|
||||
- (NSString *) webDavXMLURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@.xml", [self _baseCalDAVURL]];
|
||||
}
|
||||
|
||||
- (NSString *) publicCalDavURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@/", [self _basePublicCalDAVURL]];
|
||||
}
|
||||
|
||||
- (NSString *) publicWebDavICSURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@.ics", [self _basePublicCalDAVURL]];
|
||||
}
|
||||
|
||||
- (NSString *) publicWebDavXMLURL
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@.xml", [self _basePublicCalDAVURL]];
|
||||
}
|
||||
|
||||
/* folder management */
|
||||
- (BOOL) create
|
||||
{
|
||||
@@ -2928,6 +2914,12 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
|
||||
refArray = [moduleSettings objectForKey: @"InactiveFolders"];
|
||||
[refArray removeObject: nameInContainer];
|
||||
|
||||
refDict = [moduleSettings objectForKey: @"FolderSyncTags"];
|
||||
[refDict removeObjectForKey: reference];
|
||||
|
||||
refDict = [moduleSettings objectForKey: @"FolderSynchronize"];
|
||||
[refDict removeObjectForKey: reference];
|
||||
|
||||
[super removeFolderSettings: moduleSettings
|
||||
withReference: reference];
|
||||
@@ -3140,11 +3132,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
return (![inactiveFolders containsObject: nameInContainer]);
|
||||
}
|
||||
|
||||
- (BOOL) isWebCalendar
|
||||
{
|
||||
return ([self isKindOfClass: [SOGoWebAppointmentFolder class]]);
|
||||
}
|
||||
|
||||
- (NSString *) importComponent: (iCalEntityObject *) event
|
||||
timezone: (iCalTimeZone *) timezone
|
||||
{
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#import <NGCards/iCalEventChanges.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalRecurrenceCalculator.h>
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
|
||||
@@ -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:";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalEntityObject+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -26,7 +26,6 @@
|
||||
@class iCalAlarm;
|
||||
@class NSMutableDictionary;
|
||||
@class SOGoUser;
|
||||
@class WOContext;
|
||||
|
||||
extern NSCalendarDate *iCalDistantFuture;
|
||||
extern NSNumber *iCalDistantFutureNumber;
|
||||
@@ -35,15 +34,12 @@ extern NSNumber *iCalDistantFutureNumber;
|
||||
|
||||
+ (void) initializeSOGoExtensions;
|
||||
|
||||
- (NSDictionary *) attributesInContext: (WOContext *) context;
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
- (BOOL) userIsAttendee: (SOGoUser *) user;
|
||||
- (BOOL) userIsOrganizer: (SOGoUser *) user;
|
||||
|
||||
- (iCalPerson *) userAsAttendee: (SOGoUser *) user;
|
||||
|
||||
- (NSArray *) attendeeUIDs;
|
||||
- (BOOL) isStillRelevant;
|
||||
|
||||
- (id) itipEntryWithMethod: (NSString *) method;
|
||||
@@ -51,13 +47,7 @@ extern NSNumber *iCalDistantFutureNumber;
|
||||
- (NSArray *) attendeesWithoutUser: (SOGoUser *) user;
|
||||
|
||||
- (int) priorityNumber;
|
||||
- (NSDictionary *) createdBy;
|
||||
|
||||
- (NSCalendarDate *) dateFromString: (NSString *) dateString
|
||||
inContext: (WOContext *) context;
|
||||
- (void) adjustDate: (NSCalendarDate **) date
|
||||
withTimeString: (NSString *) timeString
|
||||
inContext: (WOContext *) context;
|
||||
- (NSString *) createdBy;
|
||||
|
||||
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date
|
||||
withOffset: (int) offset
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalEntityObject+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -20,24 +20,19 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/iCalRepeatableEntityObject.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import "SOGoAppointmentFolder.h"
|
||||
|
||||
@@ -45,13 +40,11 @@
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/SOGoSource.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
|
||||
#import "iCalPerson+SOGo.h"
|
||||
#import "iCalAlarm+SOGo.h"
|
||||
|
||||
#import "iCalCalendar+SOGo.h"
|
||||
#import "iCalEntityObject+SOGo.h"
|
||||
|
||||
@@ -70,336 +63,6 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [UIxAppointmentEditor viewAction]
|
||||
* @see [UIxTaskEditor viewAction]
|
||||
*/
|
||||
- (NSDictionary *) attributesInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *elements;
|
||||
NSMutableArray *attendees;
|
||||
NSDictionary *contactData;
|
||||
NSMutableDictionary *data, *organizerData, *attendeeData;
|
||||
NSEnumerator *attendeesList;
|
||||
NSString *uid, *domain, *sentBy;
|
||||
NSObject <SOGoSource> *source;
|
||||
SOGoUserManager *um;
|
||||
iCalPerson *organizer, *currentAttendee;
|
||||
id value;
|
||||
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
|
||||
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[[self tag] lowercaseString], @"component",
|
||||
[self summary], @"summary",
|
||||
nil];
|
||||
|
||||
value = [self priority];
|
||||
if ([value length]) [data setObject: value forKey: @"priority"];
|
||||
|
||||
value = [self location];
|
||||
if ([value length]) [data setObject: value forKey: @"location"];
|
||||
|
||||
value = [self comment];
|
||||
if ([value length]) [data setObject: value forKey: @"comment"];
|
||||
|
||||
value = [self accessClass];
|
||||
if ([value length]) [data setObject: [value lowercaseString] forKey: @"classification"];
|
||||
|
||||
value = [self status];
|
||||
if ([value length]) [data setObject: [value lowercaseString] forKey: @"status"];
|
||||
|
||||
value = [self createdBy];
|
||||
if (value) [data setObject: value forKey: @"createdBy"];
|
||||
|
||||
// Categories
|
||||
elements = [self categories];
|
||||
if ([elements count])
|
||||
[data setObject: elements forKey: @"categories"];
|
||||
|
||||
// Send appointment notifications when the custom tag is *not* set
|
||||
value = [self firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"];
|
||||
[data setObject: [NSNumber numberWithBool: (value? 0:1)] forKey: @"sendAppointmentNotifications"];
|
||||
|
||||
// Organizer
|
||||
organizer = [self organizer];
|
||||
if ([[organizer email] length])
|
||||
{
|
||||
organizerData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[organizer rfc822Email], @"email",
|
||||
[organizer cnWithoutQuotes], @"name",
|
||||
nil];
|
||||
uid = [organizer uid];
|
||||
if ([uid length]) [organizerData setObject: uid forKey: @"uid"];
|
||||
sentBy = [organizer sentBy];
|
||||
if ([sentBy length]) [organizerData setObject: sentBy forKey: @"sentBy"];
|
||||
[data setObject: organizerData forKey: @"organizer"];
|
||||
}
|
||||
|
||||
// Attendees
|
||||
attendees = [NSMutableArray array];
|
||||
attendeesList = [[self attendees] objectEnumerator];
|
||||
while ((currentAttendee = [attendeesList nextObject]))
|
||||
{
|
||||
attendeeData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[currentAttendee rfc822Email], @"email",
|
||||
[currentAttendee cnWithoutQuotes], @"name",
|
||||
nil];
|
||||
if ((uid = [currentAttendee uid]))
|
||||
{
|
||||
[attendeeData setObject: uid forKey: @"uid"];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search for attendee in global contacts sources that are associated with a MS Exchange server
|
||||
domain = [[context activeUser] domain];
|
||||
elements = [um fetchContactsMatching: [currentAttendee rfc822Email] inDomain: domain];
|
||||
if ([elements count] == 1)
|
||||
{
|
||||
contactData = [elements lastObject];
|
||||
source = [contactData objectForKey: @"source"];
|
||||
if ([source conformsToProtocol: @protocol (SOGoDNSource)] &&
|
||||
[[(NSObject <SOGoDNSource>*) source MSExchangeHostname] length])
|
||||
{
|
||||
uid = [NSString stringWithFormat: @"%@:%@", [[context activeUser] login],
|
||||
[contactData valueForKey: @"c_uid"]];
|
||||
[attendeeData setObject: uid forKey: @"uid"];
|
||||
}
|
||||
}
|
||||
}
|
||||
[attendeeData setObject: [[currentAttendee partStat] lowercaseString] forKey: @"status"];
|
||||
[attendeeData setObject: [[currentAttendee role] lowercaseString] forKey: @"role"];
|
||||
if ([[currentAttendee delegatedTo] length])
|
||||
[attendeeData setObject: [[currentAttendee delegatedTo] rfc822Email] forKey: @"delegatedTo"];
|
||||
if ([[currentAttendee delegatedFrom] length])
|
||||
[attendeeData setObject: [[currentAttendee delegatedFrom] rfc822Email] forKey: @"delegatedFrom"];
|
||||
|
||||
[attendees addObject: attendeeData];
|
||||
}
|
||||
if ([attendees count])
|
||||
[data setObject: attendees forKey: @"attendees"];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// From [UIxDatePicker takeValuesFromRequest:inContext:]
|
||||
- (NSCalendarDate *) dateFromString: (NSString *) dateString
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSInteger dateTZOffset, userTZOffset;
|
||||
NSTimeZone *systemTZ, *userTZ;
|
||||
SOGoUserDefaults *ud;
|
||||
NSCalendarDate *date;
|
||||
|
||||
date = [NSCalendarDate dateWithString: dateString
|
||||
calendarFormat: @"%Y-%m-%d"];
|
||||
if (!date)
|
||||
[self warnWithFormat: @"Could not parse dateString: '%@'", dateString];
|
||||
|
||||
// We must adjust the date timezone because "dateWithString:..." uses the
|
||||
// system timezone, which can be different from the user's. */
|
||||
ud = [[context activeUser] userDefaults];
|
||||
systemTZ = [date timeZone];
|
||||
dateTZOffset = [systemTZ secondsFromGMTForDate: date];
|
||||
userTZ = [ud timeZone];
|
||||
userTZOffset = [userTZ secondsFromGMTForDate: date];
|
||||
if (dateTZOffset != userTZOffset)
|
||||
date = [date dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: (dateTZOffset - userTZOffset)];
|
||||
[date setTimeZone: userTZ];
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
// From [UIxTimeDatePicker takeValuesFromRequest:inContext:]
|
||||
- (void) adjustDate: (NSCalendarDate **) date
|
||||
withTimeString: (NSString *) timeString
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
unsigned _year, _month, _day, _hour, _minute;
|
||||
SOGoUserDefaults *ud;
|
||||
NSArray *_time;
|
||||
|
||||
_year = [*date yearOfCommonEra];
|
||||
_month = [*date monthOfYear];
|
||||
_day = [*date dayOfMonth];
|
||||
_time = [timeString componentsSeparatedByString: @":"];
|
||||
_hour = [[_time objectAtIndex: 0] intValue];
|
||||
_minute = [[_time objectAtIndex: 1] intValue];
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
*date = [NSCalendarDate dateWithYear: _year month: _month day: _day
|
||||
hour: _hour minute: _minute second: 0
|
||||
timeZone: [ud timeZone]];
|
||||
}
|
||||
|
||||
- (void) _setAttendees: (NSArray *) attendees
|
||||
{
|
||||
NSMutableArray *newAttendees;
|
||||
NSUInteger count, max;
|
||||
NSString *currentEmail;
|
||||
iCalPerson *currentAttendee;
|
||||
NSString *role, *partstat;
|
||||
NSDictionary *currentData;
|
||||
|
||||
if (attendees)
|
||||
{
|
||||
newAttendees = [NSMutableArray array];
|
||||
max = [attendees count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentData = [attendees objectAtIndex: count];
|
||||
currentEmail = [currentData objectForKey: @"email"];
|
||||
if ([currentEmail length] > 0)
|
||||
{
|
||||
role = [[currentData objectForKey: @"role"] uppercaseString];
|
||||
if (!role)
|
||||
role = @"REQ-PARTICIPANT";
|
||||
if ([role isEqualToString: @"NON-PARTICIPANT"])
|
||||
partstat = @"";
|
||||
else
|
||||
{
|
||||
partstat = [[currentData objectForKey: @"partstat"] uppercaseString];
|
||||
if (!partstat)
|
||||
partstat = @"NEEDS-ACTION";
|
||||
}
|
||||
currentAttendee = [self findAttendeeWithEmail: currentEmail];
|
||||
if (!currentAttendee)
|
||||
{
|
||||
currentAttendee = [iCalPerson elementWithTag: @"attendee"];
|
||||
[currentAttendee setCn: [currentData objectForKey: @"name"]];
|
||||
[currentAttendee setEmail: currentEmail];
|
||||
}
|
||||
[currentAttendee
|
||||
setRsvp: ([role isEqualToString: @"NON-PARTICIPANT"]
|
||||
? @"FALSE"
|
||||
: @"TRUE")];
|
||||
[currentAttendee setRole: role];
|
||||
[currentAttendee setPartStat: partstat];
|
||||
[newAttendees addObject: currentAttendee];
|
||||
}
|
||||
}
|
||||
[self setAttendees: newAttendees];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _appendAttendeesToEmailAlarm: (iCalAlarm *) alarm
|
||||
{
|
||||
NSArray *attendees;
|
||||
NSMutableArray *aAttendees;
|
||||
int count, max;
|
||||
iCalPerson *currentAttendee, *aAttendee;
|
||||
|
||||
attendees = [self attendees];
|
||||
max = [attendees count];
|
||||
aAttendees = [NSMutableArray arrayWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentAttendee = [attendees objectAtIndex: count];
|
||||
aAttendee = [iCalPerson elementWithTag: @"attendee"];
|
||||
[aAttendee setCn: [currentAttendee cn]];
|
||||
[aAttendee setEmail: [currentAttendee rfc822Email]];
|
||||
[aAttendees addObject: aAttendee];
|
||||
}
|
||||
[alarm setAttendees: aAttendees];
|
||||
}
|
||||
|
||||
- (void) _setAlarm: (NSDictionary *) alarm
|
||||
forOwner: (NSString *) owner
|
||||
{
|
||||
iCalAlarm *anAlarm;
|
||||
NSString *reminderAction, *reminderUnit, *reminderQuantity, *reminderReference, *reminderRelation;
|
||||
BOOL reminderEmailAttendees, reminderEmailOrganizer;
|
||||
|
||||
reminderAction = [alarm objectForKey: @"action"];
|
||||
reminderUnit = [alarm objectForKey: @"unit"];
|
||||
reminderQuantity = [alarm objectForKey: @"quantity"];
|
||||
reminderReference = [alarm objectForKey: @"reference"];
|
||||
reminderRelation = [alarm objectForKey: @"relation"];
|
||||
reminderEmailAttendees = [[alarm objectForKey: @"attendees"] boolValue];
|
||||
reminderEmailOrganizer = [[alarm objectForKey: @"organizer"] boolValue];
|
||||
anAlarm = [iCalAlarm alarmForEvent: self
|
||||
owner: owner
|
||||
action: reminderAction
|
||||
unit: reminderUnit
|
||||
quantity: reminderQuantity
|
||||
reference: reminderReference
|
||||
reminderRelation: reminderRelation
|
||||
emailAttendees: reminderEmailAttendees
|
||||
emailOrganizer: reminderEmailOrganizer];
|
||||
|
||||
// If there was an unsupported alarm defined in the event, it will be deleted.
|
||||
[self removeAllAlarms];
|
||||
if (anAlarm)
|
||||
{
|
||||
[self addToAlarms: anAlarm];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [UIxAppointmentEditor saveAction]
|
||||
*/
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSString *owner;
|
||||
id o, sendAppointmentNotifications;
|
||||
|
||||
o = [data objectForKey: @"summary"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
[self setSummary: o];
|
||||
|
||||
o = [data objectForKey: @"priority"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
[self setPriority: [NSString stringWithFormat: @"%d", [o intValue]]];
|
||||
|
||||
o = [data objectForKey: @"location"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
[self setLocation: o];
|
||||
|
||||
o = [data objectForKey: @"comment"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
[self setComment: [o stringByReplacingString: @"\r\n" withString: @"\n"]];
|
||||
|
||||
o = [data objectForKey: @"classification"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
[self setAccessClass: [o uppercaseString]];
|
||||
|
||||
o = [data objectForKey: @"status"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
[self setStatus: [o uppercaseString]];
|
||||
|
||||
o = [data objectForKey: @"categories"];
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[self setCategories: o];
|
||||
|
||||
o = [data objectForKey: @"sendAppointmentNotifications"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
{
|
||||
sendAppointmentNotifications = [self firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"];
|
||||
if (!sendAppointmentNotifications && ![o boolValue])
|
||||
[self addChild: [CardElement simpleElementWithTag: @"X-SOGo-Send-Appointment-Notifications" value: @"NO"]];
|
||||
else if (sendAppointmentNotifications && [o boolValue])
|
||||
[self removeChild: sendAppointmentNotifications];
|
||||
}
|
||||
|
||||
o = [data objectForKey: @"attendees"];
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[self _setAttendees: o];
|
||||
|
||||
o = [data objectForKey: @"alarm"];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
owner = [data objectForKey: @"owner"];
|
||||
[self _setAlarm: o forOwner: owner];
|
||||
}
|
||||
|
||||
// Other attributes depend on the client object and therefore are set in [UIxComponentEditor setAttributes:]:
|
||||
// - organizer & "created-by"
|
||||
// - timestamps (creation/modification)
|
||||
}
|
||||
|
||||
- (BOOL) userIsAttendee: (SOGoUser *) user
|
||||
{
|
||||
NSEnumerator *attendees;
|
||||
@@ -450,11 +113,10 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
|
||||
if ([mail length])
|
||||
return [user hasEmail: mail];
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
- (NSArray *) attendeeUIDs
|
||||
{
|
||||
NSEnumerator *attendees;
|
||||
@@ -474,7 +136,6 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
|
||||
return uids;
|
||||
}
|
||||
*/
|
||||
|
||||
#warning this method should be implemented in a category of iCalToDo
|
||||
- (BOOL) isStillRelevant
|
||||
@@ -491,11 +152,11 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
|
||||
NSArray *events;
|
||||
int i, count;
|
||||
|
||||
|
||||
newCalendar = [parent mutableCopy];
|
||||
[newCalendar autorelease];
|
||||
[newCalendar setMethod: method];
|
||||
|
||||
|
||||
events = [newCalendar childrenWithTag: tag];
|
||||
count = [events count];
|
||||
if (count > 1)
|
||||
@@ -589,39 +250,19 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
return priorityNumber;
|
||||
}
|
||||
|
||||
- (NSDictionary *) createdBy
|
||||
- (NSString *) createdBy
|
||||
{
|
||||
NSString *created_by, *created_by_name, *login;
|
||||
NSDictionary *createdByData;
|
||||
SOGoUser *user;
|
||||
NSString *created_by;
|
||||
|
||||
created_by_name = nil;
|
||||
createdByData = nil;
|
||||
created_by = [[self firstChildWithTag: @"X-SOGo-Component-Created-By"] flattenedValuesForKey: @""];
|
||||
|
||||
|
||||
// We consider "SENT-BY" in case our custom header isn't found
|
||||
if (![created_by length])
|
||||
{
|
||||
// We consider "SENT-BY" in case our custom header isn't found
|
||||
created_by = [[self organizer] sentBy];
|
||||
}
|
||||
|
||||
if ([created_by length])
|
||||
{
|
||||
login = [[SOGoUserManager sharedUserManager] getUIDForEmail: created_by];
|
||||
if (login)
|
||||
{
|
||||
user = [SOGoUser userWithLogin: login];
|
||||
if (user)
|
||||
created_by_name = [user cn];
|
||||
}
|
||||
|
||||
createdByData = [NSDictionary dictionaryWithObjectsAndKeys: created_by, @"email",
|
||||
created_by_name, @"name",
|
||||
nil];
|
||||
}
|
||||
|
||||
return createdByData;
|
||||
;
|
||||
return created_by;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -708,20 +349,20 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
NSCalendarDate *start, *end;
|
||||
NGCalendarDateRange *range;
|
||||
NSMutableArray *alarms;
|
||||
|
||||
|
||||
alarms = [NSMutableArray array];
|
||||
start = [NSCalendarDate date];
|
||||
end = [start addYear:1 month:0 day:0 hour:0 minute:0 second:0];
|
||||
range = [NGCalendarDateRange calendarDateRangeWithStartDate: start
|
||||
endDate: end];
|
||||
|
||||
|
||||
// Always check if container is defined. If not, that means this method
|
||||
// call was reentrant.
|
||||
if (theContainer)
|
||||
{
|
||||
NSTimeInterval now;
|
||||
int i, v, delta, c_startdate, c_nextalarm;
|
||||
|
||||
|
||||
//
|
||||
// Here is the logic:
|
||||
//
|
||||
@@ -736,12 +377,12 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
// If we don't have a match, we pick the event for which its trigger is the closest to the c_nextalarm.
|
||||
//
|
||||
nextAlarmDate = nil;
|
||||
|
||||
|
||||
[theContainer flattenCycleRecord: (id)row
|
||||
forRange: range
|
||||
intoArray: alarms
|
||||
withCalendar: [self parent]];
|
||||
|
||||
|
||||
// We pickup the closest one from now. We remove the actual reminder (ie., 15 mins before - plus 1 minute for roundups)
|
||||
// so we don't pickup the same alarm over and over. This could happen if our alarm popups and the user clicks on "Cancel".
|
||||
// In case of a repetitive event, we want to pickup the next one (next day for example), and not the one that has just
|
||||
@@ -753,11 +394,11 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
c_startdate = [[[alarms objectAtIndex: i] objectForKey: @"c_startdate"] intValue];
|
||||
c_nextalarm = [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue];
|
||||
delta = (c_startdate - now - (c_startdate - c_nextalarm)) - 60;
|
||||
|
||||
|
||||
// If value is not initialized, we grab it right away
|
||||
if (!v && delta > 0)
|
||||
v = delta;
|
||||
|
||||
|
||||
// If we found a smaller delta than before, use it.
|
||||
if (v > 0 && delta > 0 && delta <= v)
|
||||
{
|
||||
@@ -768,10 +409,10 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
o = [[self parent] eventWithRecurrenceID: [[alarms objectAtIndex: i] objectForKey: @"c_recurrence_id"]];
|
||||
else
|
||||
o = [[self parent] todoWithRecurrenceID: [[alarms objectAtIndex: i] objectForKey: @"c_recurrence_id"]];
|
||||
|
||||
|
||||
if (!o)
|
||||
o = self;
|
||||
|
||||
|
||||
if ([[o alarms] count])
|
||||
{
|
||||
anAlarm = [self firstDisplayOrAudioAlarm];
|
||||
@@ -781,7 +422,7 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
if (!webstatus
|
||||
|| ([webstatus caseInsensitiveCompare: @"TRIGGERED"]
|
||||
!= NSOrderedSame))
|
||||
|
||||
|
||||
v = delta;
|
||||
nextAlarmDate = [NSDate dateWithTimeIntervalSince1970: [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue]];
|
||||
}
|
||||
@@ -795,7 +436,7 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
} // if (theContainer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ([nextAlarmDate isNotNull])
|
||||
[row setObject: [NSNumber numberWithInt: [nextAlarmDate timeIntervalSince1970]]
|
||||
forKey: @"c_nextalarm"];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalEvent+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -28,7 +28,7 @@
|
||||
@interface iCalEvent (SOGoExtensions)
|
||||
|
||||
- (BOOL) isStillRelevant;
|
||||
- (NSTimeInterval) occurenceInterval;
|
||||
- (unsigned int) occurenceInterval;
|
||||
- (void) updateRecurrenceRulesUntilDate: (NSCalendarDate *) previousEndDate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalEvent+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -22,14 +22,12 @@
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
@@ -38,12 +36,6 @@
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import <SoObjects/SOGo/SOGoUser.h>
|
||||
#import <SoObjects/SOGo/SOGoUserDefaults.h>
|
||||
#import <SoObjects/SOGo/WOContext+SOGo.h>
|
||||
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
|
||||
#import "SOGoAppointmentFolder.h"
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
@@ -55,7 +47,7 @@
|
||||
{
|
||||
NSCalendarDate *now, *lastRecurrence;
|
||||
BOOL isStillRelevent;
|
||||
|
||||
|
||||
now = [NSCalendarDate calendarDate];
|
||||
|
||||
if ([self isRecurrent])
|
||||
@@ -65,7 +57,7 @@
|
||||
}
|
||||
else
|
||||
isStillRelevent = ([[self endDate] earlierDate: now] == now);
|
||||
|
||||
|
||||
return isStillRelevent;
|
||||
}
|
||||
|
||||
@@ -122,8 +114,8 @@
|
||||
row = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||
|
||||
[row setObject: @"vevent" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
@@ -176,11 +168,11 @@
|
||||
forAllDay: isAllDay]
|
||||
forKey: @"c_enddate"];
|
||||
}
|
||||
|
||||
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
NSCalendarDate *date;
|
||||
|
||||
|
||||
date = [self lastPossibleRecurrenceStartDate];
|
||||
if (!date)
|
||||
{
|
||||
@@ -202,7 +194,7 @@
|
||||
if ([status isNotNull])
|
||||
{
|
||||
int code = 1;
|
||||
|
||||
|
||||
if ([status isEqualToString: @"TENTATIVE"])
|
||||
code = 2;
|
||||
else if ([status isEqualToString: @"CANCELLED"])
|
||||
@@ -222,12 +214,12 @@
|
||||
if (organizer)
|
||||
{
|
||||
NSString *email;
|
||||
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
@@ -235,7 +227,7 @@
|
||||
{
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if (i)
|
||||
@@ -271,7 +263,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the "until dates" of the recurrence rules of the event
|
||||
* Shift the "until dates" of the recurrence rules of the event
|
||||
* with respect to the previous end date of the event.
|
||||
* @param previousEndDate the previous end date of the event
|
||||
*/
|
||||
@@ -320,137 +312,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [iCalRepeatableEntityObject+SOGo attributes]
|
||||
* @see [iCalEntityObject+SOGo attributes]
|
||||
* @see [UIxAppointmentEditor viewAction]
|
||||
*/
|
||||
- (NSDictionary *) attributesInContext: (WOContext *) context
|
||||
{
|
||||
BOOL isAllDay;
|
||||
NSCalendarDate *eventStartDate, *eventEndDate;
|
||||
NSMutableDictionary *data;
|
||||
NSTimeZone *timeZone;
|
||||
SOGoUserDefaults *ud;
|
||||
|
||||
isAllDay = [self isAllDay];
|
||||
ud = [[context activeUser] userDefaults];
|
||||
timeZone = [ud timeZone];
|
||||
eventStartDate = [self startDate];
|
||||
eventEndDate = [self endDate];
|
||||
|
||||
if (!isAllDay)
|
||||
{
|
||||
[eventStartDate setTimeZone: timeZone];
|
||||
[eventEndDate setTimeZone: timeZone];
|
||||
}
|
||||
|
||||
data = [NSMutableDictionary dictionaryWithDictionary: [super attributesInContext: context]];
|
||||
|
||||
[data setObject: [eventStartDate iso8601DateString] forKey: @"startDate"];
|
||||
[data setObject: [eventEndDate iso8601DateString] forKey: @"endDate"];
|
||||
|
||||
[data setObject: [NSNumber numberWithBool: isAllDay] forKey: @"isAllDay"];
|
||||
[data setObject: [NSNumber numberWithBool: ![self isOpaque]] forKey: @"isTransparent"];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [iCalRepeatableEntityObject+SOGo setAttributes:inContext:]
|
||||
* @see [iCalEntityObject+SOGo setAttributes:inContext:]
|
||||
* @see [UIxAppointmentEditor saveAction]
|
||||
*/
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSCalendarDate *aptStartDate, *aptEndDate, *allDayStartDate;
|
||||
NSTimeZone *timeZone;
|
||||
NSInteger offset, nbrDays;
|
||||
iCalDateTime *startDate;
|
||||
iCalTimeZone *tz;
|
||||
SOGoUserDefaults *ud;
|
||||
BOOL isAllDay;
|
||||
id o;
|
||||
|
||||
[super setAttributes: data inContext: context];
|
||||
|
||||
aptStartDate = aptEndDate = nil;
|
||||
|
||||
// Handle start/end dates
|
||||
o = [data objectForKey: @"startDate"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
aptStartDate = [self dateFromString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"startTime"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
[self adjustDate: &aptStartDate withTimeString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"endDate"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
aptEndDate = [self dateFromString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"endTime"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
[self adjustDate: &aptEndDate withTimeString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"isTransparent"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
[self setTransparency: ([o boolValue]? @"TRANSPARENT" : @"OPAQUE")];
|
||||
|
||||
isAllDay = [[data objectForKey: @"isAllDay"] boolValue];
|
||||
|
||||
if (aptStartDate && aptEndDate)
|
||||
{
|
||||
if (isAllDay)
|
||||
{
|
||||
nbrDays = ((float) abs ([aptEndDate timeIntervalSinceDate: aptStartDate]) / 86400) + 1;
|
||||
// Convert all-day start date to GMT (floating date)
|
||||
ud = [[context activeUser] userDefaults];
|
||||
timeZone = [ud timeZone];
|
||||
offset = [timeZone secondsFromGMTForDate: aptStartDate];
|
||||
allDayStartDate = [aptStartDate dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
[self setAllDayWithStartDate: allDayStartDate
|
||||
duration: nbrDays];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setStartDate: aptStartDate];
|
||||
[self setEndDate: aptEndDate];
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAllDay)
|
||||
{
|
||||
// Make sure there's a vTimeZone associated to the event unless it
|
||||
// is an all-day event.
|
||||
startDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
|
||||
if (![startDate timeZone])
|
||||
{
|
||||
ud = [[context activeUser] userDefaults];
|
||||
tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]];
|
||||
if ([[self parent] addTimeZone: tz])
|
||||
{
|
||||
[startDate setTimeZone: tz];
|
||||
[(iCalDateTime *)[self uniqueChildWithTag: @"dtend"] setTimeZone: tz];
|
||||
}
|
||||
}
|
||||
}
|
||||
else // if (![[self clientObject] isNew])
|
||||
{
|
||||
// Remove the vTimeZone when dealing with an all-day event.
|
||||
startDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
|
||||
tz = [startDate timeZone];
|
||||
if (tz)
|
||||
{
|
||||
[startDate setTimeZone: nil];
|
||||
[(iCalDateTime *)[self uniqueChildWithTag: @"dtend"] setTimeZone: nil];
|
||||
[[self parent] removeChild: tz];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalRepeatableEntityObject+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalRepeatableEntityObject+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -25,10 +25,8 @@
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
#import <NGCards/iCalRecurrenceCalculator.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
@@ -37,12 +35,6 @@
|
||||
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
|
||||
#import <SoObjects/SOGo/SOGoUser.h>
|
||||
#import <SoObjects/SOGo/SOGoUserDefaults.h>
|
||||
#import <SoObjects/SOGo/WOContext+SOGo.h>
|
||||
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
@implementation iCalRepeatableEntityObject (SOGoExtensions)
|
||||
@@ -77,152 +69,6 @@
|
||||
return ma;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [iCalEntityObject+SOGo attributes]
|
||||
* @see [iCalEvent+SOGo attributes]
|
||||
* @see [UIxAppointmentEditor viewAction]
|
||||
*/
|
||||
- (NSDictionary *) attributesInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *rules;
|
||||
NSCalendarDate *untilDate;
|
||||
NSMutableDictionary *data, *repeat;
|
||||
NSString *frequency;
|
||||
NSTimeZone *timeZone;
|
||||
SOGoUserDefaults *ud;
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
data = [NSMutableDictionary dictionaryWithDictionary: [super attributesInContext: context]];
|
||||
|
||||
rules = [self recurrenceRules];
|
||||
if ([rules count] > 0)
|
||||
{
|
||||
rule = [rules objectAtIndex: 0];
|
||||
frequency = [rule frequencyForValue: [rule frequency]];
|
||||
|
||||
repeat = [NSMutableDictionary dictionary];
|
||||
[repeat setObject: [frequency lowercaseString] forKey: @"frequency"];
|
||||
[repeat setObject: [NSNumber numberWithInt: [rule repeatInterval]] forKey: @"interval"];
|
||||
if ([rule repeatCount])
|
||||
[repeat setObject: [NSNumber numberWithInt: [rule repeatCount]] forKey: @"count"];
|
||||
if ((untilDate = [rule untilDate]))
|
||||
{
|
||||
ud = [[context activeUser] userDefaults];
|
||||
timeZone = [ud timeZone];
|
||||
[untilDate setTimeZone: timeZone];
|
||||
[repeat setObject: [untilDate iso8601DateString] forKey: @"until"];
|
||||
}
|
||||
if ([[rule byDay] length])
|
||||
[repeat setObject: [[rule byDayMask] asRuleArray] forKey: @"days"];
|
||||
if ([[rule byMonthDay] count])
|
||||
[repeat setObject: [rule byMonthDay] forKey: @"monthdays"];
|
||||
if ([[rule byMonth] count])
|
||||
[repeat setObject: [rule byMonth] forKey: @"months"];
|
||||
[data setObject: repeat forKey: @"repeat"];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [iCalEntityObject+SOGo setAttributes:inContext:]
|
||||
* @see [UIxAppointmentEditor saveAction]
|
||||
*/
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
iCalRecurrenceFrequency frequency;
|
||||
NSCalendarDate *date;
|
||||
SOGoUserDefaults *ud;
|
||||
id repeat, o;
|
||||
|
||||
[super setAttributes: data inContext: context];
|
||||
|
||||
if ([self recurrenceId])
|
||||
// Occurrence of a recurrent object can't have a recurrence rule
|
||||
return;
|
||||
|
||||
repeat = [data objectForKey: @"repeat"];
|
||||
if ([repeat isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
rule = [iCalRecurrenceRule new];
|
||||
[rule setInterval: @"1"];
|
||||
|
||||
frequency = NSNotFound;
|
||||
o = [repeat objectForKey: @"frequency"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
{
|
||||
frequency = [rule valueForFrequency: o];
|
||||
if ((NSUInteger) frequency == NSNotFound)
|
||||
{
|
||||
if ([o caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame)
|
||||
{
|
||||
frequency = iCalRecurrenceFrequenceWeekly;
|
||||
[rule setInterval: @"2"];
|
||||
}
|
||||
else if ([o caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame)
|
||||
{
|
||||
frequency = iCalRecurrenceFrequenceDaily;
|
||||
[rule setByDayMask: [iCalByDayMask byDayMaskWithWeekDays]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
o = [repeat objectForKey: @"interval"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
[rule setInterval: [NSString stringWithFormat: @"%i", [o intValue]]];
|
||||
|
||||
o = [repeat objectForKey: @"count"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
[rule setRepeatCount: [o intValue]];
|
||||
|
||||
o = [repeat objectForKey: @"until"];
|
||||
if ([o isKindOfClass: [NSString class]])
|
||||
{
|
||||
date = [NSCalendarDate dateWithString: o
|
||||
calendarFormat: @"%Y-%m-%d"];
|
||||
if (date)
|
||||
{
|
||||
// Adjust timezone
|
||||
ud = [[context activeUser] userDefaults];
|
||||
date = [NSCalendarDate dateWithYear: [date yearOfCommonEra]
|
||||
month: [date monthOfYear]
|
||||
day: [date dayOfMonth]
|
||||
hour: 0 minute: 0 second: 0
|
||||
timeZone: [ud timeZone]];
|
||||
[rule setUntilDate: date];
|
||||
}
|
||||
}
|
||||
|
||||
o = [repeat objectForKey: @"days"];
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[rule setByDayMask: [iCalByDayMask byDayMaskWithDaysAndOccurrences: o]];
|
||||
|
||||
o = [repeat objectForKey: @"monthdays"];
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[rule setValues: o atIndex: 0 forKey: @"bymonthday"];
|
||||
|
||||
o = [repeat objectForKey: @"months"];
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[rule setValues: o atIndex: 0 forKey: @"bymonth"];
|
||||
}
|
||||
|
||||
if ((NSUInteger) frequency != NSNotFound)
|
||||
{
|
||||
[rule setFrequency: frequency];
|
||||
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
|
||||
}
|
||||
|
||||
[rule release];
|
||||
}
|
||||
}
|
||||
else if ([self hasRecurrenceRules])
|
||||
{
|
||||
[self removeAllRecurrenceRules];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *) cycleInfo
|
||||
{
|
||||
NSArray *rules;
|
||||
@@ -237,7 +83,7 @@
|
||||
rules = [self _indexedRules: [self recurrenceRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"rules"];
|
||||
|
||||
|
||||
rules = [self _indexedRules: [self exceptionRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"exRules"];
|
||||
@@ -276,7 +122,7 @@
|
||||
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start
|
||||
endDate: end];
|
||||
}
|
||||
|
||||
|
||||
return firstRange;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,19 +27,10 @@
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
||||
#import <SoObjects/SOGo/WOContext+SOGo.h>
|
||||
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
@@ -47,179 +38,6 @@
|
||||
|
||||
@implementation iCalToDo (SOGoExtensions)
|
||||
|
||||
- (NSDictionary *) attributesInContext: (WOContext *) context
|
||||
{
|
||||
BOOL isAllDayStartDate, isAllDayDueDate;
|
||||
NSCalendarDate *startDate, *dueDate, *completedDate;
|
||||
NSMutableDictionary *data;
|
||||
NSTimeZone *timeZone;
|
||||
SOGoUserDefaults *ud;
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
timeZone = [ud timeZone];
|
||||
|
||||
startDate = [self startDate];
|
||||
isAllDayStartDate = [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"] isAllDay];
|
||||
if (!isAllDayStartDate)
|
||||
[startDate setTimeZone: timeZone];
|
||||
|
||||
dueDate = [self due];
|
||||
isAllDayDueDate = [(iCalDateTime *) [self uniqueChildWithTag: @"due"] isAllDay];
|
||||
if (!isAllDayDueDate)
|
||||
[dueDate setTimeZone: timeZone];
|
||||
|
||||
completedDate = [self completed];
|
||||
[completedDate setTimeZone: timeZone];
|
||||
|
||||
data = [NSMutableDictionary dictionaryWithDictionary: [super attributesInContext: context]];
|
||||
|
||||
if (startDate)
|
||||
[data setObject: [startDate iso8601DateString] forKey: @"startDate"];
|
||||
if (dueDate)
|
||||
[data setObject: [dueDate iso8601DateString] forKey: @"dueDate"];
|
||||
if (completedDate)
|
||||
[data setObject: [completedDate iso8601DateString] forKey: @"completedDate"];
|
||||
|
||||
if ([[self percentComplete] length])
|
||||
[data setObject: [NSNumber numberWithInt: [[self percentComplete] intValue]] forKey: @"percentComplete"];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see [iCalRepeatableEntityObject+SOGo setAttributes:inContext:]
|
||||
* @see [iCalEntityObject+SOGo setAttributes:inContext:]
|
||||
* @see [UIxAppointmentEditor saveAction]
|
||||
*/
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
BOOL isAllDayStartDate, isAllDayDueDate;
|
||||
NSCalendarDate *startDate, *dueDate, *completedDate;
|
||||
NSInteger percent;
|
||||
SOGoUserDefaults *ud;
|
||||
iCalDateTime *todoStartDate, *todoDueDate;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
[super setAttributes: data inContext: context];
|
||||
|
||||
startDate = dueDate = completedDate = nil;
|
||||
|
||||
// Handle start date
|
||||
isAllDayStartDate = YES;
|
||||
o = [data objectForKey: @"startDate"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
startDate = [self dateFromString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"startTime"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
{
|
||||
isAllDayStartDate = NO;
|
||||
[self adjustDate: &startDate withTimeString: o inContext: context];
|
||||
}
|
||||
|
||||
if (startDate)
|
||||
[self setStartDate: startDate];
|
||||
else
|
||||
{
|
||||
[self setStartDate: nil];
|
||||
[self removeAllAlarms];
|
||||
}
|
||||
|
||||
// Handle due date
|
||||
isAllDayDueDate = YES;
|
||||
o = [data objectForKey: @"dueDate"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
dueDate = [self dateFromString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"dueTime"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
{
|
||||
isAllDayDueDate = NO;
|
||||
[self adjustDate: &dueDate withTimeString: o inContext: context];
|
||||
}
|
||||
|
||||
if (dueDate)
|
||||
if (isAllDayDueDate)
|
||||
[self setAllDayDue: dueDate];
|
||||
else
|
||||
[self setDue: dueDate];
|
||||
else
|
||||
[self setDue: nil];
|
||||
|
||||
// Handle time zone
|
||||
todoStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
|
||||
todoDueDate = (iCalDateTime *)[self uniqueChildWithTag: @"due"];
|
||||
tz = [todoStartDate timeZone];
|
||||
if (!tz)
|
||||
tz = [todoDueDate timeZone];
|
||||
|
||||
if (isAllDayStartDate && isAllDayDueDate)
|
||||
{
|
||||
if (tz)
|
||||
[[self parent] removeChild: tz];
|
||||
[todoStartDate setTimeZone: nil];
|
||||
[todoDueDate setTimeZone: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!tz)
|
||||
{
|
||||
ud = [[context activeUser] userDefaults];
|
||||
tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]];
|
||||
}
|
||||
if (tz)
|
||||
{
|
||||
[[self parent] addTimeZone: tz];
|
||||
if (todoStartDate)
|
||||
{
|
||||
if (isAllDayStartDate)
|
||||
[todoStartDate setTimeZone: nil];
|
||||
else if (![todoStartDate timeZone])
|
||||
[todoStartDate setTimeZone: tz];
|
||||
}
|
||||
if (todoDueDate)
|
||||
{
|
||||
if (isAllDayDueDate)
|
||||
[todoDueDate setTimeZone: nil];
|
||||
else if (![todoDueDate timeZone])
|
||||
[todoDueDate setTimeZone: tz];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle completed date
|
||||
o = [data objectForKey: @"completedDate"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
completedDate = [self dateFromString: o inContext: context];
|
||||
|
||||
o = [data objectForKey: @"completedTime"];
|
||||
if ([o isKindOfClass: [NSString class]] && [o length])
|
||||
[self adjustDate: &completedDate withTimeString: o inContext: context];
|
||||
|
||||
o = [self status];
|
||||
if ([o length])
|
||||
{
|
||||
if ([o isEqualToString: @"COMPLETED"] && completedDate)
|
||||
// As specified in RFC5545, the COMPLETED property must use UTC time
|
||||
[self setCompleted: completedDate];
|
||||
else
|
||||
[self setCompleted: nil];
|
||||
}
|
||||
|
||||
// Percent complete
|
||||
o = [data objectForKey: @"percentComplete"];
|
||||
if ([o isKindOfClass: [NSNumber class]])
|
||||
{
|
||||
percent = [o intValue];
|
||||
if (percent >= 0 && percent <= 100)
|
||||
[self setPercentComplete: [NSString stringWithFormat: @"%i", percent]];
|
||||
}
|
||||
else
|
||||
[self setPercentComplete: @""];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
|
||||
container: (id) theContainer
|
||||
{
|
||||
@@ -235,7 +53,7 @@
|
||||
iCalAccessClass accessClass;
|
||||
|
||||
/* extract values */
|
||||
|
||||
|
||||
startDate = [self startDate];
|
||||
dueDate = [self due];
|
||||
uid = [self uid];
|
||||
@@ -260,7 +78,7 @@
|
||||
|
||||
[row setObject: @"vtodo" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
@@ -278,7 +96,7 @@
|
||||
[row setObject: title forKey: @"c_title"];
|
||||
if ([location isNotNull]) [row setObject: location forKey: @"c_location"];
|
||||
if ([sequence isNotNull]) [row setObject: sequence forKey: @"c_sequence"];
|
||||
|
||||
|
||||
if ([startDate isNotNull])
|
||||
date = [self quickRecordDateAsNumber: startDate
|
||||
withOffset: 0 forAllDay: NO];
|
||||
@@ -328,12 +146,12 @@
|
||||
if (organizer)
|
||||
{
|
||||
NSString *email;
|
||||
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
@@ -341,7 +159,7 @@
|
||||
{
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if(i != 0)
|
||||
@@ -353,7 +171,7 @@
|
||||
|
||||
/* handle alarms */
|
||||
[self updateNextAlarmDateInRow: row forContainer: theContainer];
|
||||
|
||||
|
||||
categories = [self categories];
|
||||
if ([categories count] > 0)
|
||||
[row setObject: [categories componentsJoinedByString: @","]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NGVCard+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -187,59 +187,29 @@ convention:
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void) addElementWithTag: (NSString *) elementTag
|
||||
ofType: (NSString *) type
|
||||
withValue: (id) value
|
||||
{
|
||||
NSArray *allValues;
|
||||
NSEnumerator *list;
|
||||
CardElement *element;
|
||||
|
||||
// value is either an array or a string
|
||||
if ([value isKindOfClass: [NSString class]])
|
||||
allValues = [NSArray arrayWithObject: value];
|
||||
else
|
||||
allValues = value;
|
||||
|
||||
// Add all values as separate elements
|
||||
list = [allValues objectEnumerator];
|
||||
while ((value = [list nextObject]))
|
||||
{
|
||||
element = [CardElement simpleElementWithTag: elementTag
|
||||
singleType: type
|
||||
value: value];
|
||||
[self addChild: element];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _setPhoneValues: (NSDictionary *) ldifRecord
|
||||
{
|
||||
[self addElementWithTag: @"tel"
|
||||
ofType: @"work"
|
||||
withValue: [ldifRecord objectForKey: @"telephonenumber"]];
|
||||
[self addElementWithTag: @"tel"
|
||||
ofType: @"home"
|
||||
withValue: [ldifRecord objectForKey: @"homephone"]];
|
||||
[self addElementWithTag: @"tel"
|
||||
ofType: @"cell"
|
||||
withValue: [ldifRecord objectForKey: @"mobile"]];
|
||||
[self addElementWithTag: @"tel"
|
||||
ofType: @"fax"
|
||||
withValue: [ldifRecord objectForKey: @"facsimiletelephonenumber"]];
|
||||
[self addElementWithTag: @"tel"
|
||||
ofType: @"pager"
|
||||
withValue: [ldifRecord objectForKey: @"pager"]];
|
||||
CardElement *phone;
|
||||
|
||||
phone = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[phone setSingleValue: [ldifRecord objectForKey: @"telephonenumber"] forKey: @""];
|
||||
phone = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[phone setSingleValue: [ldifRecord objectForKey: @"homephone"] forKey: @""];
|
||||
phone = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[phone setSingleValue: [ldifRecord objectForKey: @"mobile"] forKey: @""];
|
||||
phone = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[phone setSingleValue: [ldifRecord objectForKey: @"facsimiletelephonenumber"]
|
||||
forKey: @""];
|
||||
phone = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[phone setSingleValue: [ldifRecord objectForKey: @"pager"] forKey: @""];
|
||||
}
|
||||
|
||||
- (void) _setEmails: (NSDictionary *) ldifRecord
|
||||
{
|
||||
CardElement *homeMail;
|
||||
CardElement *mail, *homeMail;
|
||||
|
||||
// Emails from the configured mail fields of the source have already been extracted in
|
||||
// [LDAPSource _fillEmailsOfEntry:intoLDIFRecord:]
|
||||
[self addElementWithTag: @"email"
|
||||
ofType: @"work"
|
||||
withValue: [ldifRecord objectForKey: @"c_emails"]];
|
||||
mail = [self elementWithTag: @"email" ofType: @"work"];
|
||||
[mail setSingleValue: [ldifRecord objectForKey: @"mail"] forKey: @""];
|
||||
homeMail = [self elementWithTag: @"email" ofType: @"home"];
|
||||
[homeMail setSingleValue: [ldifRecord objectForKey: @"mozillasecondemail"] forKey: @""];
|
||||
[[self uniqueChildWithTag: @"x-mozilla-html"]
|
||||
|
||||
@@ -209,26 +209,10 @@ static NSArray *folderListingFields = nil;
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize keys of dictionary representing a contact.
|
||||
* @param contactRecord a dictionary with pairs from the quick table
|
||||
* @see [UIxContactView dataAction]
|
||||
*/
|
||||
- (void) fixupContactRecord: (NSMutableDictionary *) contactRecord
|
||||
{
|
||||
NSString *data;
|
||||
|
||||
// c_categories => categories
|
||||
data = [contactRecord objectForKey: @"c_categories"];
|
||||
if ([data length])
|
||||
[contactRecord setObject: data forKey: @"categories"];
|
||||
|
||||
// c_name => id
|
||||
data = [contactRecord objectForKey: @"c_name"];
|
||||
if ([data length])
|
||||
[contactRecord setObject: data forKey: @"id"];
|
||||
|
||||
// c_cn => fn
|
||||
data = [contactRecord objectForKey: @"c_cn"];
|
||||
if (![data length])
|
||||
{
|
||||
@@ -240,34 +224,17 @@ static NSArray *folderListingFields = nil;
|
||||
else
|
||||
{
|
||||
data = [contactRecord objectForKey: @"c_o"];
|
||||
[contactRecord setObject: data forKey: @"c_cn"];
|
||||
[contactRecord setObject: data forKey: @"c_cn"];
|
||||
}
|
||||
}
|
||||
|
||||
// c_screenname => X-AIM
|
||||
if (![contactRecord objectForKey: @"c_mail"])
|
||||
[contactRecord setObject: @"" forKey: @"c_mail"];
|
||||
if (![contactRecord objectForKey: @"c_screenname"])
|
||||
[contactRecord setObject: @"" forKey: @"c_screenname"];
|
||||
|
||||
// c_mail => emails[]
|
||||
data = [contactRecord objectForKey: @"c_mail"];
|
||||
if ([data length])
|
||||
{
|
||||
NSDictionary *email;
|
||||
email = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
|
||||
[contactRecord setObject: [NSArray arrayWithObject: email] forKey: @"emails"];
|
||||
}
|
||||
else
|
||||
[contactRecord setObject: @"" forKey: @"c_mail"];
|
||||
|
||||
// c_telephonenumber => phones
|
||||
data = [contactRecord objectForKey: @"c_telephonenumber"];
|
||||
if ([data length])
|
||||
{
|
||||
NSDictionary *phonenumber;
|
||||
phonenumber = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
|
||||
[contactRecord setObject: [NSArray arrayWithObject: phonenumber] forKey: @"phones"];
|
||||
}
|
||||
else
|
||||
if (![contactRecord objectForKey: @"c_o"])
|
||||
[contactRecord setObject: @"" forKey: @"c_o"];
|
||||
if (![contactRecord objectForKey: @"c_telephonenumber"])
|
||||
[contactRecord setObject: @"" forKey: @"c_telephonenumber"];
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
[vcard setProdID: [NSString
|
||||
stringWithFormat: @"-//Inverse inc./SOGo %@//EN",
|
||||
SOGoVersion]];
|
||||
[vcard updateFromLDIFRecord: [self ldifRecord]];
|
||||
[vcard updateFromLDIFRecord: [self simplifiedLDIFRecord]];
|
||||
|
||||
return vcard;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
- (NSDictionary *) simplifiedLDIFRecord;
|
||||
|
||||
- (NSException *) save;
|
||||
- (NSException *) delete;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SOGoContactSourceFolder.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2015 Inverse inc.
|
||||
* Copyright (C) 2006-2013 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -217,11 +217,6 @@
|
||||
return [source removeContactEntryWithID: [ldifEntry nameInContainer]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize keys of dictionary representing a contact.
|
||||
* @param oldRecord a dictionary with pairs from the source folder (LDAP or SQL)
|
||||
* @see [SOGoContactGCSFolder _fixupContactRecord]
|
||||
*/
|
||||
- (NSDictionary *) _flattenedRecord: (NSDictionary *) oldRecord
|
||||
{
|
||||
NSMutableDictionary *newRecord;
|
||||
@@ -231,54 +226,26 @@
|
||||
newRecord = [NSMutableDictionary dictionaryWithCapacity: 8];
|
||||
[newRecord setObject: [oldRecord objectForKey: @"c_uid"]
|
||||
forKey: @"c_uid"];
|
||||
|
||||
// c_name => id
|
||||
[newRecord setObject: [oldRecord objectForKey: @"c_name"]
|
||||
forKey: @"c_name"];
|
||||
[newRecord setObject: [oldRecord objectForKey: @"c_name"]
|
||||
forKey: @"id"];
|
||||
|
||||
// displayname || c_cn => fn
|
||||
data = [oldRecord objectForKey: @"displayname"];
|
||||
if (!data)
|
||||
data = [oldRecord objectForKey: @"c_cn"];
|
||||
if (data)
|
||||
[newRecord setObject: data forKey: @"fn"];
|
||||
else
|
||||
if (!data)
|
||||
data = @"";
|
||||
[newRecord setObject: data forKey: @"c_cn"];
|
||||
|
||||
// mail => emails[]
|
||||
data = [oldRecord objectForKey: @"c_emails"];
|
||||
if (data)
|
||||
data = [oldRecord objectForKey: @"mail"];
|
||||
if (!data)
|
||||
data = @"";
|
||||
else if ([data isKindOfClass: [NSArray class]])
|
||||
{
|
||||
if ([data isKindOfClass: [NSArray class]])
|
||||
{
|
||||
if ([data count] > 0)
|
||||
{
|
||||
NSEnumerator *emails;
|
||||
NSMutableArray *recordEmails;
|
||||
NSString *email;
|
||||
emails = [(NSArray *)data objectEnumerator];
|
||||
recordEmails = [NSMutableArray arrayWithCapacity: [data count]];
|
||||
while ((email = [emails nextObject]))
|
||||
{
|
||||
[recordEmails addObject: [NSDictionary dictionaryWithObject: email forKey: @"value"]];
|
||||
}
|
||||
[newRecord setObject: recordEmails forKey: @"emails"];
|
||||
}
|
||||
}
|
||||
else if (data)
|
||||
{
|
||||
NSDictionary *email;
|
||||
email = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
|
||||
[newRecord setObject: [NSArray arrayWithObject: email] forKey: @"emails"];
|
||||
}
|
||||
if ([data count] > 0)
|
||||
data = [data objectAtIndex: 0];
|
||||
else
|
||||
data = @"";
|
||||
}
|
||||
else
|
||||
data = @"";
|
||||
[newRecord setObject: data forKey: @"c_mail"];
|
||||
|
||||
data = [oldRecord objectForKey: @"nsaimid"];
|
||||
@@ -288,28 +255,25 @@
|
||||
data = @"";
|
||||
[newRecord setObject: data forKey: @"c_screenname"];
|
||||
|
||||
// o => org
|
||||
data = [oldRecord objectForKey: @"o"];
|
||||
if (data)
|
||||
[newRecord setObject: data forKey: @"org"];
|
||||
else
|
||||
if (!data)
|
||||
data = @"";
|
||||
[newRecord setObject: data forKey: @"c_o"];
|
||||
|
||||
// telephonenumber || cellphone || homephone => phones[]
|
||||
data = [oldRecord objectForKey: @"telephonenumber"];
|
||||
if (![data length])
|
||||
data = [oldRecord objectForKey: @"cellphone"];
|
||||
if (![data length])
|
||||
data = [oldRecord objectForKey: @"homephone"];
|
||||
if (data)
|
||||
{
|
||||
NSDictionary *phonenumber;
|
||||
phonenumber = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
|
||||
[newRecord setObject: [NSArray arrayWithObject: phonenumber] forKey: @"phones"];
|
||||
}
|
||||
else
|
||||
if (![data length])
|
||||
data = @"";
|
||||
else if ([data isKindOfClass: [NSArray class]])
|
||||
{
|
||||
if ([data count] > 0)
|
||||
data = [data objectAtIndex: 0];
|
||||
else
|
||||
data = @"";
|
||||
}
|
||||
[newRecord setObject: data forKey: @"c_telephonenumber"];
|
||||
|
||||
// Custom attribute for group-lookups. See LDAPSource.m where
|
||||
@@ -326,13 +290,9 @@
|
||||
[newRecord setObject: @"vcard" forKey: @"c_component"];
|
||||
}
|
||||
|
||||
// c_info => note
|
||||
data = [oldRecord objectForKey: @"c_info"];
|
||||
if ([data length] > 0)
|
||||
{
|
||||
[newRecord setObject: data forKey: @"note"];
|
||||
[newRecord setObject: data forKey: @"contactInfo"];
|
||||
}
|
||||
[newRecord setObject: data forKey: @"contactInfo"];
|
||||
|
||||
recordSource = [oldRecord objectForKey: @"source"];
|
||||
if ([recordSource conformsToProtocol: @protocol (SOGoDNSource)] &&
|
||||
|
||||
@@ -63,12 +63,10 @@
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
#import <SOGo/SOGoMailer.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#import <NGCards/NGVCard.h>
|
||||
|
||||
#import <Contacts/SOGoContactFolder.h>
|
||||
#import <Contacts/SOGoContactFolders.h>
|
||||
#import <Contacts/SOGoContactGCSEntry.h>
|
||||
|
||||
@@ -315,19 +313,19 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
// newHeaders come from Web form; convert priority to MIME header representation
|
||||
priority = [newHeaders objectForKey: @"priority"];
|
||||
if (!priority || [priority intValue] == 3)
|
||||
if (!priority || [priority isEqualToString: @"NORMAL"])
|
||||
{
|
||||
[headers removeObjectForKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority intValue] == 1)
|
||||
else if ([priority isEqualToString: @"HIGHEST"])
|
||||
{
|
||||
[headers setObject: @"1 (Highest)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority intValue] == 2)
|
||||
else if ([priority isEqualToString: @"HIGH"])
|
||||
{
|
||||
[headers setObject: @"2 (High)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority intValue] == 4)
|
||||
else if ([priority isEqualToString: @"LOW"])
|
||||
{
|
||||
[headers setObject: @"4 (Low)" forKey: @"X-Priority"];
|
||||
}
|
||||
@@ -357,7 +355,7 @@ static NSString *userAgent = nil;
|
||||
else
|
||||
{
|
||||
receipt = [newHeaders objectForKey: @"receipt"];
|
||||
if ([receipt boolValue])
|
||||
if ([receipt isEqualToString: @"true"])
|
||||
{
|
||||
[headers setObject: receipt forKey: @"receipt"];
|
||||
pureSender = [[newHeaders objectForKey: @"from"] pureEMailAddress];
|
||||
@@ -643,6 +641,7 @@ static NSString *userAgent = nil;
|
||||
[imap4URL release];
|
||||
imap4URL = nil;
|
||||
}
|
||||
[self storeInfo];
|
||||
}
|
||||
else
|
||||
error = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
|
||||
@@ -928,6 +927,8 @@ static NSString *userAgent = nil;
|
||||
|
||||
[self setText: [sourceMail contentForEditing]];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
|
||||
[self storeInfo];
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1006,11 +1007,11 @@ static NSString *userAgent = nil;
|
||||
withMetadata: attachment];
|
||||
}
|
||||
|
||||
[self storeInfo];
|
||||
|
||||
// Save the message to the IMAP store so the user can eventually view the attached file(s)
|
||||
// from the Web interface
|
||||
[self save];
|
||||
|
||||
[self storeInfo];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
@@ -1596,16 +1597,17 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
NSString *s, *dateString;
|
||||
NGMutableHashMap *map;
|
||||
id emails, from, replyTo;
|
||||
NSArray *emails;
|
||||
id from, replyTo;
|
||||
|
||||
map = [[[NGMutableHashMap alloc] initWithCapacity:16] autorelease];
|
||||
|
||||
/* add recipients */
|
||||
if ((emails = [headers objectForKey: @"to"]) != nil && [emails isKindOfClass: [NSArray class]])
|
||||
if ((emails = [headers objectForKey: @"to"]) != nil)
|
||||
[map setObjects: [self _quoteSpecialsInArray: emails] forKey: @"to"];
|
||||
if ((emails = [headers objectForKey: @"cc"]) != nil && [emails isKindOfClass: [NSArray class]])
|
||||
if ((emails = [headers objectForKey: @"cc"]) != nil)
|
||||
[map setObjects: [self _quoteSpecialsInArray: emails] forKey: @"cc"];
|
||||
if ((emails = [headers objectForKey: @"bcc"]) != nil && [emails isKindOfClass: [NSArray class]])
|
||||
if ((emails = [headers objectForKey: @"bcc"]) != nil)
|
||||
[map setObjects: [self _quoteSpecialsInArray: emails] forKey: @"bcc"];
|
||||
|
||||
/* add senders */
|
||||
|
||||
@@ -300,7 +300,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
quota = quota * [(NSNumber*)[inboxQuota objectForKey: @"maxQuota"] intValue];
|
||||
inboxQuota = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithLong: (long)(quota+0.5)], @"maxQuota",
|
||||
[NSNumber numberWithLong: [[inboxQuota objectForKey: @"usedSpace"] longLongValue]], @"usedSpace",
|
||||
[inboxQuota objectForKey: @"usedSpace"], @"usedSpace",
|
||||
nil];
|
||||
}
|
||||
}
|
||||
@@ -400,147 +400,56 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
{
|
||||
NSString *folderType;
|
||||
|
||||
if ([folderName isEqualToString: inboxFolderName])
|
||||
if ([folderName isEqualToString: [NSString stringWithFormat: @"/%@", inboxFolderName]])
|
||||
folderType = @"inbox";
|
||||
else if ([folderName isEqualToString: [self draftsFolderNameInContext: context]])
|
||||
else if ([folderName isEqualToString: [NSString stringWithFormat: @"/%@", [self draftsFolderNameInContext: context]]])
|
||||
folderType = @"draft";
|
||||
else if ([folderName isEqualToString: [self sentFolderNameInContext: context]])
|
||||
else if ([folderName isEqualToString: [NSString stringWithFormat: @"/%@", [self sentFolderNameInContext: context]]])
|
||||
folderType = @"sent";
|
||||
else if ([folderName isEqualToString: [self trashFolderNameInContext: context]])
|
||||
else if ([folderName isEqualToString: [NSString stringWithFormat: @"/%@", [self trashFolderNameInContext: context]]])
|
||||
folderType = @"trash";
|
||||
else if ([folderName isEqualToString: otherUsersFolderName])
|
||||
folderType = @"otherUsers";
|
||||
else if ([folderName isEqualToString: sharedFoldersName])
|
||||
folderType = @"shared";
|
||||
else
|
||||
folderType = @"folder";
|
||||
|
||||
return folderType;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) _insertFolder: (NSString *) folderPath
|
||||
foldersList: (NSMutableArray *) theFolders
|
||||
- (NSString *) _parentForFolder: (NSString *) folderName
|
||||
foldersList: (NSArray *) theFolders
|
||||
{
|
||||
NSArray *pathComponents;
|
||||
NSMutableArray *folders;
|
||||
NSMutableDictionary *currentFolder, *parentFolder, *folder;
|
||||
NSString *currentFolderName, *currentPath, *fullName, *folderType;
|
||||
SOGoUserManager *userManager;
|
||||
int i, j, count;
|
||||
BOOL last, isOtherUsersFolder, parentIsOtherUsersFolder;
|
||||
NSString *s;
|
||||
int i;
|
||||
|
||||
parentFolder = nil;
|
||||
parentIsOtherUsersFolder = NO;
|
||||
pathComponents = [folderPath pathComponents];
|
||||
count = [pathComponents count];
|
||||
pathComponents = [folderName pathComponents];
|
||||
s = [[[pathComponents subarrayWithRange: NSMakeRange(0,[pathComponents count]-1)] componentsJoinedByString: @"/"] substringFromIndex: 1];
|
||||
|
||||
// Make sure all ancestors exist.
|
||||
// The variable folderPath is something like '/INBOX/Junk' so pathComponents becomes ('/', 'INBOX', 'Junk').
|
||||
// That's why we always ignore the first element
|
||||
for (i = 1; i < count; i++)
|
||||
for (i = 0; i < [theFolders count]; i++)
|
||||
{
|
||||
last = ((count - i) == 1);
|
||||
folder = nil;
|
||||
currentPath = [[[pathComponents subarrayWithRange: NSMakeRange(0,i+1)] componentsJoinedByString: @"/"] substringFromIndex: 2];
|
||||
|
||||
// Search for the current path in the children of the parent folder.
|
||||
// For the first iteration, take the parent folder passed as argument.
|
||||
if (parentFolder)
|
||||
{
|
||||
folders = [parentFolder objectForKey: @"children"];
|
||||
}
|
||||
else
|
||||
{
|
||||
folders = theFolders;
|
||||
}
|
||||
|
||||
for (j = 0; j < [folders count]; j++)
|
||||
{
|
||||
currentFolder = [folders objectAtIndex: j];
|
||||
if ([currentPath isEqualToString: [currentFolder objectForKey: @"path"]])
|
||||
{
|
||||
folder = currentFolder;
|
||||
// Make sure all branches are ready to receive children
|
||||
if (!last && ![folder objectForKey: @"children"])
|
||||
{
|
||||
[folder setObject: [NSMutableArray array] forKey: @"children"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the current folder is the "Other users" folder (shared mailboxes)
|
||||
currentFolderName = [[pathComponents objectAtIndex: i] stringByDecodingImap4FolderName];
|
||||
if (otherUsersFolderName
|
||||
&& [currentFolderName caseInsensitiveCompare: otherUsersFolderName] == NSOrderedSame)
|
||||
{
|
||||
isOtherUsersFolder = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
isOtherUsersFolder = NO;
|
||||
}
|
||||
|
||||
if (folder == nil)
|
||||
{
|
||||
// Folder was not found; create it and add it to the folders list
|
||||
|
||||
if (parentIsOtherUsersFolder)
|
||||
{
|
||||
// Parent folder is the "Other users" folder; translate the user's mailbox name
|
||||
// to the full name of the person
|
||||
userManager = [SOGoUserManager sharedUserManager];
|
||||
fullName = [userManager getCNForUID: currentFolderName];
|
||||
if (fullName)
|
||||
currentFolderName = fullName;
|
||||
}
|
||||
else if (isOtherUsersFolder)
|
||||
{
|
||||
currentFolderName = [self labelForKey: @"OtherUsersFolderName"];
|
||||
}
|
||||
else if (sharedFoldersName
|
||||
&& [currentFolderName caseInsensitiveCompare: sharedFoldersName] == NSOrderedSame)
|
||||
{
|
||||
currentFolderName = [self labelForKey: @"SharedFoldersName"];
|
||||
}
|
||||
|
||||
if (last)
|
||||
folderType = [self _folderType: currentPath];
|
||||
else
|
||||
folderType = @"additional";
|
||||
|
||||
folder = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
currentPath, @"path",
|
||||
folderType, @"type",
|
||||
currentFolderName, @"name",
|
||||
[NSMutableArray array], @"children",
|
||||
nil];
|
||||
// Either add this new folder to its parent or the list of root folders
|
||||
[folders addObject: folder];
|
||||
}
|
||||
|
||||
parentFolder = folder;
|
||||
parentIsOtherUsersFolder = isOtherUsersFolder;
|
||||
if ([s isEqualToString: [theFolders objectAtIndex: i]])
|
||||
return s;
|
||||
}
|
||||
|
||||
return parentFolder;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// Return a tree representation of the mailboxes
|
||||
//
|
||||
//
|
||||
- (NSArray *) allFoldersMetadata
|
||||
{
|
||||
NSString *currentFolder;
|
||||
NSMutableArray *folders;
|
||||
NSString *currentFolder, *currentDecodedFolder, *currentDisplayName, *currentFolderType, *login, *fullName, *parent;
|
||||
NSMutableArray *pathComponents, *folders;
|
||||
SOGoUserManager *userManager;
|
||||
NSEnumerator *rawFolders;
|
||||
NSDictionary *folderData;
|
||||
NSAutoreleasePool *pool;
|
||||
NSArray *allFolderPaths;
|
||||
|
||||
allFolderPaths = [self allFolderPaths];
|
||||
rawFolders = [allFolderPaths objectEnumerator];
|
||||
folders = [NSMutableArray array];
|
||||
|
||||
folders = [NSMutableArray array];
|
||||
while ((currentFolder = [rawFolders nextObject]))
|
||||
{
|
||||
// Using a local pool to avoid using too many file descriptors. This could
|
||||
@@ -549,10 +458,55 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
// lots of LDAP connections during its execution.
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Insert folder into folders tree
|
||||
[self _insertFolder: currentFolder
|
||||
foldersList: folders];
|
||||
currentDecodedFolder = [currentFolder stringByDecodingImap4FolderName];
|
||||
currentFolderType = [self _folderType: currentFolder];
|
||||
|
||||
// We translate the "Other Users" and "Shared Folders" namespaces.
|
||||
// While we're at it, we also translate the user's mailbox names
|
||||
// to the full name of the person.
|
||||
if (otherUsersFolderName && [currentDecodedFolder hasPrefix: [NSString stringWithFormat: @"/%@", otherUsersFolderName]])
|
||||
{
|
||||
// We have a string like /Other Users/lmarcotte/... under Cyrus, but we could
|
||||
// also have something like /shared under Dovecot. So we swap the username only
|
||||
// if we have one, of course.
|
||||
pathComponents = [NSMutableArray arrayWithArray: [currentDecodedFolder pathComponents]];
|
||||
|
||||
if ([pathComponents count] > 2)
|
||||
{
|
||||
login = [pathComponents objectAtIndex: 2];
|
||||
userManager = [SOGoUserManager sharedUserManager];
|
||||
fullName = [userManager getCNForUID: login];
|
||||
[pathComponents removeObjectsInRange: NSMakeRange(0,3)];
|
||||
|
||||
currentDisplayName = [NSString stringWithFormat: @"/%@/%@/%@",
|
||||
[self labelForKey: @"OtherUsersFolderName"],
|
||||
(fullName != nil ? fullName : login),
|
||||
[pathComponents componentsJoinedByString: @"/"]];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDisplayName = [NSString stringWithFormat: @"/%@%@",
|
||||
[self labelForKey: @"OtherUsersFolderName"],
|
||||
[currentDecodedFolder substringFromIndex:
|
||||
[otherUsersFolderName length]+1]];
|
||||
}
|
||||
}
|
||||
else if (sharedFoldersName && [currentDecodedFolder hasPrefix: [NSString stringWithFormat: @"/%@", sharedFoldersName]])
|
||||
currentDisplayName = [NSString stringWithFormat: @"/%@%@", [self labelForKey: @"SharedFoldersName"],
|
||||
[currentDecodedFolder substringFromIndex: [sharedFoldersName length]+1]];
|
||||
else
|
||||
currentDisplayName = currentDecodedFolder;
|
||||
|
||||
parent = [self _parentForFolder: currentFolder foldersList: allFolderPaths];
|
||||
|
||||
folderData = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
currentFolder, @"path",
|
||||
currentFolderType, @"type",
|
||||
currentDisplayName, @"displayName",
|
||||
parent, @"parent",
|
||||
nil];
|
||||
[folders addObject: folderData];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
@@ -735,7 +689,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
|
||||
|
||||
e = [folderList objectEnumerator];
|
||||
|
||||
|
||||
while ((object = [e nextObject]))
|
||||
{
|
||||
if (hasAnnotatemore)
|
||||
@@ -845,12 +799,12 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
accounts = [user mailAccounts];
|
||||
accountIdx = [nameInContainer intValue];
|
||||
account = [accounts objectAtIndex: accountIdx];
|
||||
folderName = [[account objectForKey: @"specialMailboxes"]
|
||||
folderName = [[account objectForKey: @"mailboxes"]
|
||||
objectForKey: purpose];
|
||||
if (!folderName && accountIdx > 0)
|
||||
{
|
||||
account = [accounts objectAtIndex: 0];
|
||||
folderName = [[account objectForKey: @"specialMailboxes"]
|
||||
folderName = [[account objectForKey: @"mailboxes"]
|
||||
objectForKey: purpose];
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
- (NSArray *) toManyRelationshipKeys;
|
||||
|
||||
- (NSDictionary *) statusForFlags: (NSArray *) flags;
|
||||
- (unsigned int) unseenCount;
|
||||
|
||||
- (NSException *) deleteUIDs: (NSArray *) uids
|
||||
useTrashFolder: (BOOL *) withTrash
|
||||
@@ -97,8 +96,8 @@
|
||||
|
||||
- (NSString *) davCollectionTag;
|
||||
|
||||
- (NSArray *) syncTokenFieldsWithProperties: (NSArray *) theProperties
|
||||
matchingSyncToken: (NSString *) theSyncToken
|
||||
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties
|
||||
matchingSyncToken: (NSString *) syncToken
|
||||
fromDate: (NSCalendarDate *) theStartDate;
|
||||
|
||||
/* flags */
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
@@ -65,7 +64,6 @@
|
||||
#import "EOQualifier+MailDAV.h"
|
||||
#import "SOGoMailObject.h"
|
||||
#import "SOGoMailAccount.h"
|
||||
#import "SOGoMailAccounts.h"
|
||||
#import "SOGoMailManager.h"
|
||||
#import "SOGoMailFolder.h"
|
||||
#import "SOGoTrashFolder.h"
|
||||
@@ -803,33 +801,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
return status;
|
||||
}
|
||||
|
||||
- (unsigned int) unseenCount
|
||||
{
|
||||
NSDictionary *imapResult;
|
||||
NGImap4Connection *connection;
|
||||
NGImap4Client *client;
|
||||
EOQualifier *searchQualifier;
|
||||
NSArray *searchResult;
|
||||
unsigned int unseen;
|
||||
|
||||
connection = [self imap4Connection];
|
||||
client = [connection client];
|
||||
|
||||
if ([connection selectFolder: [self imap4URL]])
|
||||
{
|
||||
searchQualifier
|
||||
= [EOQualifier qualifierWithQualifierFormat: @"flags = %@ AND not flags = %@",
|
||||
@"unseen", @"deleted"];
|
||||
imapResult = [client searchWithQualifier: searchQualifier];
|
||||
searchResult = [[imapResult objectForKey: @"RawResponse"] objectForKey: @"search"];
|
||||
unseen = [searchResult count];
|
||||
}
|
||||
else
|
||||
unseen = 0;
|
||||
|
||||
return unseen;
|
||||
}
|
||||
|
||||
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q
|
||||
sortOrdering: (id) _so
|
||||
{
|
||||
@@ -1582,7 +1553,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
|
||||
- (NSString *) displayName
|
||||
{
|
||||
return [[self relativeImap4Name] stringByDecodingImap4FolderName];
|
||||
return [self relativeImap4Name];
|
||||
}
|
||||
|
||||
- (NSDictionary *) davIMAPFieldsTable
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2013-2015 Inverse inc.
|
||||
Copyright (C) 2013 Inverse inc.
|
||||
|
||||
This file is part of SOGo.
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
- (NSString *) color;
|
||||
|
||||
+ (NSArray *) labelsFromDefaults: (NSDictionary *) theDefaults
|
||||
component: (id) theComponent;
|
||||
component: (UIxComponent *) theComponent;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2007-2015 Inverse inc.
|
||||
Copyright (C) 2007-2013 Inverse inc.
|
||||
|
||||
This file is part of SOGo.
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
|
||||
+ (NSArray *) labelsFromDefaults: (NSDictionary *) theDefaults
|
||||
component: (id) theComponent
|
||||
component: (UIxComponent *) theComponent
|
||||
{
|
||||
NSMutableArray *allLabels, *allKeys;
|
||||
NSString *key, *name;
|
||||
@@ -81,6 +81,7 @@
|
||||
key = [allKeys objectAtIndex: i];
|
||||
values = [theDefaults objectForKey: key];
|
||||
name = [theComponent commonLabelForKey: [values objectAtIndex: 0]];
|
||||
|
||||
label = [[self alloc] initWithName: key
|
||||
label: name
|
||||
color: [values objectAtIndex: 1]];
|
||||
|
||||
@@ -766,7 +766,6 @@ static BOOL debugSoParts = NO;
|
||||
[part objectForKey: @"subtype"]];
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
// We might end up here because of MUA that actually strips the
|
||||
// Content-Disposition (and thus, the filename) when mails containing
|
||||
// attachments have been forwarded. Thunderbird (2.x) does just that
|
||||
@@ -778,7 +777,7 @@ static BOOL debugSoParts = NO;
|
||||
filename = [NSString stringWithFormat: @"unknown_%@", path];
|
||||
else if ([mimeType isEqualToString: @"message/rfc822"])
|
||||
filename = [NSString stringWithFormat: @"email_%@.eml", path];
|
||||
}
|
||||
|
||||
|
||||
if (filename)
|
||||
{
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* CardElement+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CARDELEMENT_SOGO_H
|
||||
#define CARDELEMENT_SOGO_H
|
||||
|
||||
#import <NGCards/CardElement.h>
|
||||
|
||||
@interface CardElement (SOGoExtensions)
|
||||
|
||||
- (NSString *) jsonRepresentation;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* CARDELEMENT_SOGO_H */
|
||||
@@ -1,54 +0,0 @@
|
||||
/* CardElement+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import "NSDictionary+Utilities.h"
|
||||
|
||||
#import "CardElement+SOGo.h"
|
||||
|
||||
|
||||
@implementation CardElement (SOGoExtensions)
|
||||
|
||||
/**
|
||||
* Return the JSON representation of the element as a dictionary with two keys:
|
||||
* - type: the type of the card element, if it exists;
|
||||
* - value: the value of the card element.
|
||||
* @return a JSON string representation of the element.
|
||||
*/
|
||||
- (NSString *) jsonRepresentation
|
||||
{
|
||||
NSString *v;
|
||||
NSMutableDictionary *attrs;
|
||||
|
||||
attrs = [NSMutableDictionary dictionary];
|
||||
|
||||
v = [self value: 0 ofAttribute: @"type"];
|
||||
if ([v length])
|
||||
[attrs setObject: v
|
||||
forKey: @"type"];
|
||||
[attrs setObject: [self flattenedValuesForKey: @""]
|
||||
forKey: @"value"];
|
||||
|
||||
return [attrs jsonRepresentation];
|
||||
}
|
||||
|
||||
@end /* NGVCard */
|
||||
@@ -72,7 +72,6 @@ SOGo_HEADER_FILES = \
|
||||
SOGoGroup.h \
|
||||
SOGoUser.h \
|
||||
\
|
||||
CardElement+SOGo.h \
|
||||
DOMNode+SOGo.h \
|
||||
\
|
||||
WORequest+SOGo.h \
|
||||
@@ -86,7 +85,7 @@ all::
|
||||
@touch SOGoBuild.m
|
||||
|
||||
SOGo_OBJC_FILES = \
|
||||
SOGoBuild.m \
|
||||
SOGoBuild.m \
|
||||
SOGoProductLoader.m \
|
||||
\
|
||||
BSONCodec.m \
|
||||
@@ -151,7 +150,6 @@ SOGo_OBJC_FILES = \
|
||||
SOGoGroup.m \
|
||||
SOGoUser.m \
|
||||
\
|
||||
CardElement+SOGo.m \
|
||||
DOMNode+SOGo.m \
|
||||
\
|
||||
WORequest+SOGo.m \
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
- (NSString *) shortDateString;
|
||||
- (NSString *) rfc822DateString;
|
||||
- (NSString *) iso8601DateString;
|
||||
|
||||
+ (id) distantFuture;
|
||||
+ (id) distantPast;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
|
||||
#import "NSCalendarDate+SOGo.h"
|
||||
@@ -115,34 +113,6 @@ static NSString *rfc822Months[] = {@"", @"Jan", @"Feb", @"Mar", @"Apr",
|
||||
timeZoneShift];
|
||||
}
|
||||
|
||||
- (NSString *) iso8601DateString
|
||||
{
|
||||
char buf[22];
|
||||
int timeZoneHourShift, timeZoneMinuteShift, tzSeconds;
|
||||
NSNumber *day, *month, *year, *hour, *minute;
|
||||
|
||||
day = [NSNumber numberWithInt: [self dayOfMonth]];
|
||||
month = [NSNumber numberWithInt: [self monthOfYear]];
|
||||
year = [NSNumber numberWithInt: [self yearOfCommonEra]];
|
||||
hour = [NSNumber numberWithInt: [self hourOfDay]];
|
||||
minute = [NSNumber numberWithInt: [self minuteOfHour]];
|
||||
|
||||
tzSeconds = [[self timeZone] secondsFromGMT];
|
||||
timeZoneHourShift = (tzSeconds / 3600);
|
||||
tzSeconds -= timeZoneHourShift * 3600;
|
||||
timeZoneMinuteShift = tzSeconds / 60;
|
||||
|
||||
sprintf(buf, "%04d-%02d-%02dT%02d:%02d%+.2d:%02d",
|
||||
[year intValue],
|
||||
[month intValue],
|
||||
[day intValue],
|
||||
[hour intValue],
|
||||
[minute intValue],
|
||||
timeZoneHourShift,
|
||||
timeZoneMinuteShift);
|
||||
|
||||
return [NSString stringWithCString:buf];
|
||||
}
|
||||
|
||||
#define secondsOfDistantFuture 1073741823.0
|
||||
#define secondsOfDistantPast -1073741823.0
|
||||
|
||||
@@ -51,8 +51,6 @@
|
||||
SOGoTimeFormat = "%H:%M";
|
||||
SOGoFirstDayOfWeek = 0;
|
||||
SOGoFirstWeekOfYear = "January1";
|
||||
SOGoShortDateFormat = "%d-%b-%y";
|
||||
SOGoLongDateFormat = "%A, %B %d, %Y";
|
||||
|
||||
SOGoIMAPServer = "localhost";
|
||||
SOGoMailDomain = "localhost";
|
||||
@@ -69,8 +67,6 @@
|
||||
SOGoSentFolderName = "Sent";
|
||||
SOGoDraftsFolderName = "Drafts";
|
||||
SOGoTrashFolderName = "Trash";
|
||||
SOGoMailComposeMessageType = "html";
|
||||
SOGoMailDisplayRemoteInlineImages = "never";
|
||||
|
||||
SOGoMailAutoSave = "5";
|
||||
|
||||
@@ -78,10 +74,8 @@
|
||||
SOGoCalendarEventsDefaultClassification = "PUBLIC";
|
||||
SOGoCalendarTasksDefaultClassification = "PUBLIC";
|
||||
SOGoCalendarDefaultReminder = "NONE";
|
||||
SOGoDefaultCalendar = "selected";
|
||||
SOGoFreeBusyDefaultInterval = ( 7, 7 );
|
||||
|
||||
SOGoSelectedAddressBook = "personal";
|
||||
SOGoFreeBusyDefaultInterval = ( 7, 7 );
|
||||
|
||||
SOGoSearchMinimumWordLength = 2;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* SOGoDefaultsSource.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* SOGoDefaultsSource.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1203,7 +1203,7 @@ static NSArray *childRecordFields = nil;
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"c_lastmodified > %d and c_deleted == 1",
|
||||
syncTokenInt];
|
||||
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_deleted", nil];
|
||||
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_lastmodified", @"c_deleted", nil];
|
||||
[mRecords addObjectsFromArray: [self _fetchFields: fields
|
||||
withQualifier: qualifier
|
||||
ignoreDeleted: NO]];
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* SOGoSQLUserProfile.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* SOGoSQLUserProfile.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
- (NSString *) cn;
|
||||
|
||||
- (SOGoDateFormatter *) dateFormatterInContext: (WOContext *) context;
|
||||
- (NSDictionary *) currentDay;
|
||||
|
||||
/* defaults */
|
||||
- (SOGoUserDefaults *) userDefaults;
|
||||
|
||||
@@ -394,39 +394,6 @@
|
||||
return dateFormatter;
|
||||
}
|
||||
|
||||
- (NSDictionary *) currentDay
|
||||
{
|
||||
NSCalendarDate *now;
|
||||
NSDictionary *description, *abbr;
|
||||
NSDictionary *locale;
|
||||
SOGoUserDefaults *ud;
|
||||
WOResourceManager *resMgr;
|
||||
NSUInteger seconds;
|
||||
|
||||
now = [NSCalendarDate calendarDate];
|
||||
ud = [self userDefaults];
|
||||
resMgr = [[WOApplication application] resourceManager];
|
||||
locale = [resMgr localeForLanguageNamed: [ud language]];
|
||||
|
||||
[now setTimeZone: [ud timeZone]];
|
||||
seconds = [now hourOfDay]*3600 + [now minuteOfHour]*60 + [now secondOfMinute];
|
||||
|
||||
abbr = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[now descriptionWithCalendarFormat: @"%a" locale: locale], @"weekday",
|
||||
[now descriptionWithCalendarFormat: @"%b" locale: locale], @"month",
|
||||
nil];
|
||||
description = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[now descriptionWithCalendarFormat: @"%A" locale: locale], @"weekday",
|
||||
[now descriptionWithCalendarFormat: @"%B" locale: locale], @"month",
|
||||
[now descriptionWithCalendarFormat: @"%d" locale: locale], @"day",
|
||||
[now descriptionWithCalendarFormat: @"%Y" locale: locale], @"year",
|
||||
abbr, @"abbr",
|
||||
[NSNumber numberWithInt: (24*3600 - seconds)], @"secondsBeforeTomorrow",
|
||||
nil];
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
- (SOGoUserDefaults *) userDefaults
|
||||
{
|
||||
if (!_defaults)
|
||||
@@ -627,10 +594,10 @@
|
||||
{
|
||||
NSString *fullName, *replyTo, *imapLogin, *imapServer, *cImapServer, *signature,
|
||||
*encryption, *scheme, *action, *query, *customEmail, *defaultEmail, *sieveServer;
|
||||
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts, *mailSettings;
|
||||
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
|
||||
NSNumber *port;
|
||||
NSMutableArray *identities;
|
||||
NSArray *mails, *delegates;
|
||||
NSArray *mails;
|
||||
NSURL *url, *cUrl;
|
||||
unsigned int count, max, default_identity;
|
||||
NSInteger defaultPort;
|
||||
@@ -819,34 +786,11 @@
|
||||
forKey: @"Sent"];
|
||||
[mailboxes setObject: [_defaults trashFolderName]
|
||||
forKey: @"Trash"];
|
||||
[mailAccount setObject: mailboxes forKey: @"specialMailboxes"];
|
||||
[mailAccount setObject: mailboxes forKey: @"mailboxes"];
|
||||
[mailboxes release];
|
||||
|
||||
[mailAccounts addObject: mailAccount];
|
||||
[mailAccount release];
|
||||
|
||||
/* delegates */
|
||||
mailSettings = [[self userSettings] objectForKey: @"Mail"];
|
||||
delegates = [mailSettings objectForKey: @"DelegateTo"];
|
||||
if (!delegates)
|
||||
delegates = [NSArray array];
|
||||
else
|
||||
{
|
||||
NSMutableArray *allDelegates;
|
||||
SOGoUser *delegate;
|
||||
|
||||
allDelegates = [NSMutableArray array];
|
||||
for (count = 0; count < [delegates count]; count++)
|
||||
{
|
||||
delegate = [SOGoUser userWithLogin: [delegates objectAtIndex: count]];
|
||||
[allDelegates addObject: [NSDictionary dictionaryWithObjectsAndKeys: [delegates objectAtIndex: count], @"uid",
|
||||
[delegate cn], @"cn",
|
||||
[delegate systemEmail], @"c_email", nil]];
|
||||
}
|
||||
|
||||
delegates = allDelegates;
|
||||
}
|
||||
[mailAccount setObject: delegates forKey: @"delegates"];
|
||||
}
|
||||
|
||||
- (NSArray *) mailAccounts
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SOGoUserDefaults.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2015 Inverse inc.
|
||||
* Copyright (C) 2011-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SOGoUserDefaults.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009-2015 Inverse inc.
|
||||
* Copyright (C) 2009-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -394,22 +394,11 @@ static Class NSNullK;
|
||||
|
||||
- (NSString *) getUIDForEmail: (NSString *) email
|
||||
{
|
||||
NSDictionary *info;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *uid, *domain;
|
||||
NSDictionary *contactInfos;
|
||||
|
||||
info = [self contactInfosForUserWithUIDorEmail: email];
|
||||
uid = [info objectForKey: @"c_uid"];
|
||||
contactInfos = [self contactInfosForUserWithUIDorEmail: email];
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID]
|
||||
&& ![[info objectForKey: @"DomainLessLogin"] boolValue])
|
||||
{
|
||||
domain = [info objectForKey: @"c_domain"];
|
||||
uid = [NSString stringWithFormat: @"%@@%@", uid, domain];
|
||||
}
|
||||
|
||||
return uid;
|
||||
return [contactInfos objectForKey: @"c_uid"];
|
||||
}
|
||||
|
||||
- (BOOL) _sourceChangePasswordForLogin: (NSString *) login
|
||||
@@ -449,6 +438,8 @@ static Class NSNullK;
|
||||
NSEnumerator *authIDs;
|
||||
NSString *currentID;
|
||||
BOOL checkOK;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSRange r;
|
||||
|
||||
checkOK = NO;
|
||||
|
||||
|
||||
Loaded 100 of 1205 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user