Merge to 2.0.3
commit
4dc7790015
10
.tx/config
10
.tx/config
|
@ -21,6 +21,7 @@ trans.nn_NO = UI/MailerUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
|
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ trans.nn_NO = UI/PreferencesUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
|
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ trans.nn_NO = UI/Scheduler/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
|
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -90,6 +93,7 @@ trans.nn_NO = UI/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
|
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -113,6 +117,7 @@ trans.nn_NO = UI/MainUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
|
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -136,6 +141,7 @@ trans.nn_NO = UI/Common/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
|
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -159,6 +165,7 @@ trans.nn_NO = UI/AdministrationUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
|
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -182,6 +189,7 @@ trans.nn_NO = SoObjects/Appointments/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
|
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
|
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -205,6 +213,7 @@ trans.nn_NO = SoObjects/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
||||||
|
@ -228,5 +237,6 @@ trans.nn_NO = UI/MailPartViewers/NorwegianNynorsk.lproj/Localizable.strings
|
||||||
trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
||||||
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
||||||
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
||||||
|
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
|
||||||
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
|
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
|
||||||
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
|
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
51
NEWS
51
NEWS
|
@ -1,3 +1,54 @@
|
||||||
|
2.0.3 (2012-12-06)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
New features
|
||||||
|
- support for SAML2 for single sign-on, with the help of the lasso library
|
||||||
|
- added support for the "AUTHENTICATE" command and SASL mechanisms
|
||||||
|
- added domain default SieveHostFieldName
|
||||||
|
- added a search field for tasks
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
- search the contacts for the organization attribute
|
||||||
|
- in HTML mode, optionally place answer after the quoted text
|
||||||
|
- improved memory usage of "sogo-tool restore"
|
||||||
|
- fixed invitations status in OSX iCal.app/Calendar.app (cleanup RSVP attribute)
|
||||||
|
- now uses "imap4flags" instead of the deprecated "imapflags"
|
||||||
|
- added Slovak translation - thanks to Martin Pastor
|
||||||
|
- updated translations
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
- fixed LDIF import with categories
|
||||||
|
- imported events now keep their UID when possible
|
||||||
|
- fixed importation of multiple calendars
|
||||||
|
- fixed modification date when drag'n'droping events
|
||||||
|
- fixed missing 'from' header in Outlook
|
||||||
|
- fixed invitations in Outlook
|
||||||
|
- fixed JavaScript regexp for Firefox
|
||||||
|
- fixed JavaScript syntax for IE7
|
||||||
|
- fixed all-day event display in day/week view
|
||||||
|
- fixed parsing of alarm
|
||||||
|
- fixed Sieve server URL fallback
|
||||||
|
- fixed Debian cronjob (spool directory cleanup)
|
||||||
|
|
||||||
|
2.0.2a (2012-11-15)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
- improved user rights editor in calendar module
|
||||||
|
- disable alarms for newly subsribed calendars
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
- fixed typos in Spanish (Spain) translation
|
||||||
|
- fixed display of raw source for tasks
|
||||||
|
- fixed title display of cards with a photo
|
||||||
|
- fixed null address in reply-to header of messages
|
||||||
|
- fixed scrolling for calendar/addressbooks lists
|
||||||
|
- fixed display of invitations on BlackBerry devices
|
||||||
|
- fixed sogo-tool rename-user for MySQL database
|
||||||
|
- fixed corrupted attachments in Webmail
|
||||||
|
- fixed parsing of URLs that can throw an exception
|
||||||
|
- fixed password encoding in user sources
|
||||||
|
|
||||||
2.0.2 (2012-10-24)
|
2.0.2 (2012-10-24)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ libOGoContentStore_LIBRARIES_DEPEND_UPON += \
|
||||||
-lNGExtensions \
|
-lNGExtensions \
|
||||||
-lEOControl \
|
-lEOControl \
|
||||||
-lSaxObjC \
|
-lSaxObjC \
|
||||||
-lgnustep-base \
|
$(BASE_LIBS)
|
||||||
-lobjc
|
|
||||||
|
|
||||||
ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE -I../SoObjects
|
ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE -I../SoObjects
|
||||||
|
|
||||||
|
@ -29,4 +28,5 @@ test_quick_extract_TOOL_LIBS += \
|
||||||
-lNGCards \
|
-lNGCards \
|
||||||
-lGDLContentStore \
|
-lGDLContentStore \
|
||||||
-lGDLAccess \
|
-lGDLAccess \
|
||||||
-lOGoContentStore
|
-lOGoContentStore \
|
||||||
|
$(BASE_LIBS)
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
- (NSData *) mimeAttachTag;
|
- (NSData *) mimeAttachTag;
|
||||||
|
|
||||||
/* move & copy operations */
|
/* move & copy operations */
|
||||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment;
|
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
/* subclasses */
|
/* subclasses */
|
||||||
- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage;
|
- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage;
|
||||||
|
|
|
@ -152,13 +152,13 @@
|
||||||
return ULLONG_MAX;
|
return ULLONG_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment
|
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
{
|
{
|
||||||
void *attachMethod;
|
void *attachMethod;
|
||||||
enum mapistore_error error;
|
enum mapistore_error error;
|
||||||
MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage;
|
MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage;
|
||||||
|
|
||||||
[self copyPropertiesToObject: newAttachment];
|
[self copyPropertiesToObject: newAttachment inMemCtx: memCtx];
|
||||||
|
|
||||||
attachMethod = NULL;
|
attachMethod = NULL;
|
||||||
error = [self getProperty: &attachMethod
|
error = [self getProperty: &attachMethod
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
{
|
{
|
||||||
embeddedMessage = [self openEmbeddedMessage];
|
embeddedMessage = [self openEmbeddedMessage];
|
||||||
newEmbeddedMessage = [newAttachment createEmbeddedMessage];
|
newEmbeddedMessage = [newAttachment createEmbeddedMessage];
|
||||||
[embeddedMessage copyToMessage: newEmbeddedMessage];
|
[embeddedMessage copyToMessage: newEmbeddedMessage inMemCtx: memCtx];
|
||||||
}
|
}
|
||||||
talloc_free (attachMethod);
|
talloc_free (attachMethod);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@
|
||||||
SOGoAppointmentObject *newEntry;
|
SOGoAppointmentObject *newEntry;
|
||||||
NSString *name;
|
NSString *name;
|
||||||
|
|
||||||
|
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||||
|
|
||||||
name = [NSString stringWithFormat: @"%@.ics",
|
name = [NSString stringWithFormat: @"%@.ics",
|
||||||
[SOGoObject globallyUniqueObjectId]];
|
[SOGoObject globallyUniqueObjectId]];
|
||||||
newEntry = [SOGoAppointmentObject objectWithName: name
|
newEntry = [SOGoAppointmentObject objectWithName: name
|
||||||
|
|
|
@ -337,7 +337,18 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||||
|
|
||||||
- (BOOL) subscriberCanReadMessages
|
- (BOOL) subscriberCanReadMessages
|
||||||
{
|
{
|
||||||
return [self _testRoleForActiveUser: MAPIStoreRightReadItems];
|
NSString *displayName;
|
||||||
|
|
||||||
|
/* when this folder is the "Freebusy Data" folder, we need to allow
|
||||||
|
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)];
|
||||||
|
|
||||||
|
return ([displayName isEqualToString: @"Freebusy Data"]
|
||||||
|
|| [self _testRoleForActiveUser: MAPIStoreRightReadItems]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) subscriberCanDeleteMessages
|
- (BOOL) subscriberCanDeleteMessages
|
||||||
|
|
|
@ -123,7 +123,8 @@
|
||||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||||
withMIDs: (uint64_t *) targetMids
|
withMIDs: (uint64_t *) targetMids
|
||||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||||
wantCopy: (uint8_t) want_copy;
|
wantCopy: (uint8_t) want_copy
|
||||||
|
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder
|
- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder
|
||||||
withNewName: (NSString *) newFolderName
|
withNewName: (NSString *) newFolderName
|
||||||
|
|
|
@ -180,6 +180,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
|
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||||
|
|
||||||
// [messageKeys release];
|
// [messageKeys release];
|
||||||
// [faiMessageKeys release];
|
// [faiMessageKeys release];
|
||||||
// [folderKeys release];
|
// [folderKeys release];
|
||||||
|
@ -656,19 +658,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int) moveCopyMessageWithMID: (uint64_t) srcMid
|
// private method
|
||||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
- (int) _moveCopyMessageWithMID: (uint64_t) srcMid
|
||||||
withMID: (uint64_t) targetMid
|
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||||
andChangeKey: (struct Binary_r *) targetChangeKey
|
withMID: (uint64_t) targetMid
|
||||||
wantCopy: (uint8_t) wantCopy
|
andChangeKey: (struct Binary_r *) targetChangeKey
|
||||||
|
wantCopy: (uint8_t) wantCopy
|
||||||
|
inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
MAPIStoreMessage *sourceMsg, *destMsg;
|
MAPIStoreMessage *sourceMsg, *destMsg;
|
||||||
TALLOC_CTX *memCtx;
|
//TALLOC_CTX *memCtx;
|
||||||
struct SRow aRow;
|
struct SRow aRow;
|
||||||
struct SPropValue property;
|
struct SPropValue property;
|
||||||
|
|
||||||
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
[self logWithFormat: @"-moveCopyMessageWithMID: 0x%.16llx .. withMID: 0x%.16llx .. wantCopy: %d", srcMid, targetMid, wantCopy];
|
||||||
|
|
||||||
|
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||||
rc = [sourceFolder openMessage: &sourceMsg
|
rc = [sourceFolder openMessage: &sourceMsg
|
||||||
withMID: srcMid
|
withMID: srcMid
|
||||||
forWriting: NO
|
forWriting: NO
|
||||||
|
@ -681,7 +687,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
if (rc != MAPISTORE_SUCCESS)
|
if (rc != MAPISTORE_SUCCESS)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
[sourceMsg copyToMessage: destMsg];
|
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
|
||||||
|
|
||||||
if (targetChangeKey)
|
if (targetChangeKey)
|
||||||
{
|
{
|
||||||
|
@ -698,7 +704,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
|
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
|
||||||
|
|
||||||
end:
|
end:
|
||||||
talloc_free (memCtx);
|
//talloc_free (memCtx);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -709,6 +715,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
withMIDs: (uint64_t *) targetMids
|
withMIDs: (uint64_t *) targetMids
|
||||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||||
wantCopy: (uint8_t) wantCopy
|
wantCopy: (uint8_t) wantCopy
|
||||||
|
inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
{
|
{
|
||||||
int rc = MAPISTORE_SUCCESS;
|
int rc = MAPISTORE_SUCCESS;
|
||||||
NSUInteger count;
|
NSUInteger count;
|
||||||
|
@ -717,6 +724,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
MAPIStoreMapping *mapping;
|
MAPIStoreMapping *mapping;
|
||||||
SOGoUser *ownerUser;
|
SOGoUser *ownerUser;
|
||||||
struct Binary_r *targetChangeKey;
|
struct Binary_r *targetChangeKey;
|
||||||
|
//TALLOC_CTX *memCtx;
|
||||||
|
|
||||||
|
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||||
|
|
||||||
ownerUser = [[self userContext] sogoUser];
|
ownerUser = [[self userContext] sogoUser];
|
||||||
|
|
||||||
|
@ -738,11 +748,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
targetChangeKey = targetChangeKeys[count];
|
targetChangeKey = targetChangeKeys[count];
|
||||||
else
|
else
|
||||||
targetChangeKey = NULL;
|
targetChangeKey = NULL;
|
||||||
rc = [self moveCopyMessageWithMID: srcMids[count]
|
rc = [self _moveCopyMessageWithMID: srcMids[count]
|
||||||
fromFolder: sourceFolder
|
fromFolder: sourceFolder
|
||||||
withMID: targetMids[count]
|
withMID: targetMids[count]
|
||||||
andChangeKey: targetChangeKey
|
andChangeKey: targetChangeKey
|
||||||
wantCopy: wantCopy];
|
wantCopy: wantCopy
|
||||||
|
inMemCtx: memCtx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||||
|
@ -765,7 +776,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = MAPISTORE_ERR_DENIED;
|
rc = MAPISTORE_ERR_DENIED;
|
||||||
|
|
||||||
|
//talloc_free (memCtx);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,6 +798,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
NSUInteger count, max;
|
NSUInteger count, max;
|
||||||
NSString *childKey;
|
NSString *childKey;
|
||||||
uint64_t fmid;
|
uint64_t fmid;
|
||||||
|
TALLOC_CTX *memCtx;
|
||||||
|
|
||||||
|
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||||
|
|
||||||
/* TODO: one possible issue with this algorithm is that moved messages will
|
/* TODO: one possible issue with this algorithm is that moved messages will
|
||||||
lack a version number and will all be assigned a new one, even though
|
lack a version number and will all be assigned a new one, even though
|
||||||
|
@ -807,7 +823,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
if (rc == MAPISTORE_SUCCESS)
|
if (rc == MAPISTORE_SUCCESS)
|
||||||
{
|
{
|
||||||
newFolder = [targetFolder lookupFolder: childKey];
|
newFolder = [targetFolder lookupFolder: childKey];
|
||||||
[self copyPropertiesToObject: newFolder];
|
[self copyPropertiesToObject: newFolder inMemCtx: memCtx];
|
||||||
|
|
||||||
pool = [NSAutoreleasePool new];
|
pool = [NSAutoreleasePool new];
|
||||||
children = [self messageKeys];
|
children = [self messageKeys];
|
||||||
|
@ -818,7 +834,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
message = [self lookupMessage: childKey];
|
message = [self lookupMessage: childKey];
|
||||||
targetMessage = [newFolder createMessage: NO];
|
targetMessage = [newFolder createMessage: NO];
|
||||||
[targetMessage setIsNew: YES];
|
[targetMessage setIsNew: YES];
|
||||||
[message copyToMessage: targetMessage];
|
[message copyToMessage: targetMessage inMemCtx: memCtx];
|
||||||
if (isMove)
|
if (isMove)
|
||||||
{
|
{
|
||||||
fmid = [mapping idFromURL: [message url]];
|
fmid = [mapping idFromURL: [message url]];
|
||||||
|
@ -839,7 +855,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
message = [self lookupFAIMessage: childKey];
|
message = [self lookupFAIMessage: childKey];
|
||||||
targetMessage = [newFolder createMessage: YES];
|
targetMessage = [newFolder createMessage: YES];
|
||||||
[targetMessage setIsNew: YES];
|
[targetMessage setIsNew: YES];
|
||||||
[message copyToMessage: targetMessage];
|
[message copyToMessage: targetMessage inMemCtx: memCtx];
|
||||||
if (isMove)
|
if (isMove)
|
||||||
{
|
{
|
||||||
fmid = [mapping idFromURL: [message url]];
|
fmid = [mapping idFromURL: [message url]];
|
||||||
|
@ -882,6 +898,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||||
else
|
else
|
||||||
rc = MAPISTORE_ERR_DENIED;
|
rc = MAPISTORE_ERR_DENIED;
|
||||||
|
|
||||||
|
talloc_free (memCtx);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -929,6 +929,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||||
withMIDs: (uint64_t *) targetMids
|
withMIDs: (uint64_t *) targetMids
|
||||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||||
wantCopy: (uint8_t) wantCopy
|
wantCopy: (uint8_t) wantCopy
|
||||||
|
inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
|
|
||||||
{
|
{
|
||||||
NGImap4Connection *connection;
|
NGImap4Connection *connection;
|
||||||
NGImap4Client *client;
|
NGImap4Client *client;
|
||||||
|
@ -946,7 +948,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||||
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
|
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
|
||||||
fromFolder: sourceFolder withMIDs: targetMids
|
fromFolder: sourceFolder withMIDs: targetMids
|
||||||
andChangeKeys: targetChangeKeys
|
andChangeKeys: targetChangeKeys
|
||||||
wantCopy: wantCopy];
|
wantCopy: wantCopy
|
||||||
|
inMemCtx: memCtx];
|
||||||
|
|
||||||
/* Conversion of mids to IMAP uids */
|
/* Conversion of mids to IMAP uids */
|
||||||
mapping = [self mapping];
|
mapping = [self mapping];
|
||||||
|
|
|
@ -569,7 +569,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||||
}
|
}
|
||||||
|
|
||||||
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
|
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
|
||||||
if (list)
|
if ([list count])
|
||||||
[headers setObjects: list forKey: @"from"];
|
[headers setObjects: list forKey: @"from"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
- (NSArray *) activeUserRoles;
|
- (NSArray *) activeUserRoles;
|
||||||
|
|
||||||
/* move & copy internal ops */
|
/* move & copy internal ops */
|
||||||
- (void) copyToMessage: (MAPIStoreMessage *) newMessage;
|
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
/* subclasses */
|
/* subclasses */
|
||||||
- (void) save;
|
- (void) save;
|
||||||
|
|
|
@ -139,6 +139,8 @@ rtf2html (NSData *compressedRTF)
|
||||||
|
|
||||||
- (id) init
|
- (id) init
|
||||||
{
|
{
|
||||||
|
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
|
||||||
|
|
||||||
if ((self = [super init]))
|
if ((self = [super init]))
|
||||||
{
|
{
|
||||||
attachmentParts = [NSMutableDictionary new];
|
attachmentParts = [NSMutableDictionary new];
|
||||||
|
@ -151,6 +153,7 @@ rtf2html (NSData *compressedRTF)
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
|
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
|
||||||
[activeUserRoles release];
|
[activeUserRoles release];
|
||||||
[attachmentKeys release];
|
[attachmentKeys release];
|
||||||
[attachmentParts release];
|
[attachmentParts release];
|
||||||
|
@ -437,17 +440,19 @@ rtf2html (NSData *compressedRTF)
|
||||||
andType: MAPISTORE_MESSAGE_TABLE];
|
andType: MAPISTORE_MESSAGE_TABLE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) copyToMessage: (MAPIStoreMessage *) newMessage
|
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
{
|
{
|
||||||
TALLOC_CTX *memCtx;
|
//TALLOC_CTX *memCtx;
|
||||||
struct mapistore_message *messageData;
|
struct mapistore_message *messageData;
|
||||||
NSArray *keys;
|
NSArray *keys;
|
||||||
NSUInteger count, max;
|
NSUInteger count, max;
|
||||||
NSString *key;
|
NSString *key;
|
||||||
MAPIStoreAttachment *attachment, *newAttachment;
|
MAPIStoreAttachment *attachment, *newAttachment;
|
||||||
|
|
||||||
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
|
||||||
|
|
||||||
|
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||||
|
|
||||||
/* message headers and recipients */
|
/* message headers and recipients */
|
||||||
[self getMessageData: &messageData inMemCtx: memCtx];
|
[self getMessageData: &messageData inMemCtx: memCtx];
|
||||||
|
@ -456,7 +461,7 @@ rtf2html (NSData *compressedRTF)
|
||||||
andColumns: messageData->columns];
|
andColumns: messageData->columns];
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
[self copyPropertiesToObject: newMessage];
|
[self copyPropertiesToObject: newMessage inMemCtx: memCtx];
|
||||||
|
|
||||||
/* attachments */
|
/* attachments */
|
||||||
keys = [self attachmentKeys];
|
keys = [self attachmentKeys];
|
||||||
|
@ -466,10 +471,10 @@ rtf2html (NSData *compressedRTF)
|
||||||
key = [keys objectAtIndex: count];
|
key = [keys objectAtIndex: count];
|
||||||
attachment = [self lookupAttachment: key];
|
attachment = [self lookupAttachment: key];
|
||||||
newAttachment = [newMessage createAttachment];
|
newAttachment = [newMessage createAttachment];
|
||||||
[attachment copyToAttachment: newAttachment];
|
[attachment copyToAttachment: newAttachment inMemCtx: memCtx];
|
||||||
}
|
}
|
||||||
|
|
||||||
talloc_free (memCtx);
|
//talloc_free (memCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (enum mapistore_error) saveMessage
|
- (enum mapistore_error) saveMessage
|
||||||
|
@ -485,6 +490,8 @@ rtf2html (NSData *compressedRTF)
|
||||||
BOOL userIsOwner;
|
BOOL userIsOwner;
|
||||||
MAPIStoreMessage *mainMessage;
|
MAPIStoreMessage *mainMessage;
|
||||||
|
|
||||||
|
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||||
|
|
||||||
context = [self context];
|
context = [self context];
|
||||||
ownerUser = [[self userContext] sogoUser];
|
ownerUser = [[self userContext] sogoUser];
|
||||||
userIsOwner = [[context activeUser] isEqual: ownerUser];
|
userIsOwner = [[context activeUser] isEqual: ownerUser];
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
/* move and copy operations */
|
/* move and copy operations */
|
||||||
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject;
|
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject inMemCtx: (TALLOC_CTX *) memCtx;
|
||||||
|
|
||||||
/* subclasses */
|
/* subclasses */
|
||||||
- (NSString *) nameInContainer;
|
- (NSString *) nameInContainer;
|
||||||
|
|
|
@ -317,9 +317,9 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move and copy operations */
|
/* move and copy operations */
|
||||||
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject
|
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
{
|
{
|
||||||
TALLOC_CTX *memCtx;
|
//TALLOC_CTX *memCtx;
|
||||||
struct SPropTagArray *availableProps;
|
struct SPropTagArray *availableProps;
|
||||||
struct SRow row;
|
struct SRow row;
|
||||||
enum MAPITAGS propTag;
|
enum MAPITAGS propTag;
|
||||||
|
@ -328,7 +328,7 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
||||||
enum mapistore_error error;
|
enum mapistore_error error;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||||
|
|
||||||
[self getAvailableProperties: &availableProps inMemCtx: memCtx];
|
[self getAvailableProperties: &availableProps inMemCtx: memCtx];
|
||||||
|
|
||||||
|
@ -369,8 +369,7 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
||||||
}
|
}
|
||||||
[newObject addPropertiesFromRow: &row];
|
[newObject addPropertiesFromRow: &row];
|
||||||
|
|
||||||
talloc_free (memCtx);
|
//talloc_free (memCtx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* subclasses */
|
/* subclasses */
|
||||||
|
|
|
@ -95,6 +95,7 @@ sogo_backend_init (void)
|
||||||
defaults using the system encoding rather than honouring
|
defaults using the system encoding rather than honouring
|
||||||
the encoding specified in the file. */
|
the encoding specified in the file. */
|
||||||
putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding");
|
putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding");
|
||||||
|
//putenv ("NSZombieEnabled=YES");
|
||||||
|
|
||||||
[NSProcessInfo initializeWithArguments: argv
|
[NSProcessInfo initializeWithArguments: argv
|
||||||
count: 1
|
count: 1
|
||||||
|
@ -567,6 +568,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
|
||||||
static enum mapistore_error
|
static enum mapistore_error
|
||||||
sogo_folder_move_copy_messages(void *folder_object,
|
sogo_folder_move_copy_messages(void *folder_object,
|
||||||
void *source_folder_object,
|
void *source_folder_object,
|
||||||
|
TALLOC_CTX *mem_ctx,
|
||||||
uint32_t mid_count,
|
uint32_t mid_count,
|
||||||
uint64_t *src_mids, uint64_t *t_mids,
|
uint64_t *src_mids, uint64_t *t_mids,
|
||||||
struct Binary_r **target_change_keys,
|
struct Binary_r **target_change_keys,
|
||||||
|
@ -594,7 +596,8 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||||
fromFolder: sourceFolder
|
fromFolder: sourceFolder
|
||||||
withMIDs: t_mids
|
withMIDs: t_mids
|
||||||
andChangeKeys: target_change_keys
|
andChangeKeys: target_change_keys
|
||||||
wantCopy: want_copy];
|
wantCopy: want_copy
|
||||||
|
inMemCtx: mem_ctx];
|
||||||
[pool release];
|
[pool release];
|
||||||
GSUnregisterCurrentThread ();
|
GSUnregisterCurrentThread ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ MAPIStoreTallocWrapperDestroy (void *data)
|
||||||
GSRegisterCurrentThread ();
|
GSRegisterCurrentThread ();
|
||||||
pool = [NSAutoreleasePool new];
|
pool = [NSAutoreleasePool new];
|
||||||
wrapper = data;
|
wrapper = data;
|
||||||
// NSLog (@"destroying wrapped object (wrapper: %p; object: %p)...\n", wrapper, wrapper->MAPIStoreSOGoObject);
|
//NSLog (@"destroying wrapped object (wrapper: %p; object: %p)...\n", wrapper, wrapper->MAPIStoreSOGoObject);
|
||||||
|
NSLog (@"destroying wrapped object (wrapper: %p)", wrapper);
|
||||||
[wrapper->instance release];
|
[wrapper->instance release];
|
||||||
[pool release];
|
[pool release];
|
||||||
GSUnregisterCurrentThread ();
|
GSUnregisterCurrentThread ();
|
||||||
|
@ -66,7 +67,7 @@ MAPIStoreTallocWrapperDestroy (void *data)
|
||||||
talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy);
|
talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy);
|
||||||
wrapper->instance = self;
|
wrapper->instance = self;
|
||||||
[self retain];
|
[self retain];
|
||||||
// NSLog (@"returning wrapper: %p; object: %p", wrapper, self);
|
NSLog (@"returning wrapper: %p; object: %p", wrapper, self);
|
||||||
|
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,15 +351,12 @@ static GCSStringFormatter *stringFormatter = nil;
|
||||||
- (NSString *) _selectedFields: (NSArray *) fields
|
- (NSString *) _selectedFields: (NSArray *) fields
|
||||||
requirement: (GCSTableRequirement) requirement
|
requirement: (GCSTableRequirement) requirement
|
||||||
{
|
{
|
||||||
NSMutableString *selectedFields;
|
NSString *selectedFields;
|
||||||
|
|
||||||
selectedFields = [NSMutableString string];
|
|
||||||
|
|
||||||
if (requirement == bothTableRequired
|
if (requirement == bothTableRequired && [fields containsObject: @"c_name"])
|
||||||
&& [fields containsObject: @"c_name"])
|
selectedFields = [self _dottedFields: fields];
|
||||||
[selectedFields appendString: [self _dottedFields: fields]];
|
|
||||||
else
|
else
|
||||||
[selectedFields appendString: [fields componentsJoinedByString: @", "]];
|
selectedFields = [fields componentsJoinedByString: @", "];
|
||||||
|
|
||||||
return selectedFields;
|
return selectedFields;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,14 @@
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) updateCPathInFolderInfo: (NSString *) tableName
|
||||||
|
withCPath2: (NSString *) c_path2
|
||||||
|
{
|
||||||
|
[self subclassResponsibility: _cmd];
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -205,6 +213,17 @@
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) updateCPathInFolderInfo: (NSString *) tableName
|
||||||
|
withCPath2: (NSString *) c_path2
|
||||||
|
{
|
||||||
|
static NSString *sqlFolderFormat
|
||||||
|
= (@"UPDATE %@"
|
||||||
|
@" SET c_path = '/'||c_path1||'/'||c_path2||'/'||c_path3||'/'||c_path4"
|
||||||
|
@" WHERE c_path2 = '%@'");
|
||||||
|
|
||||||
|
return [NSString stringWithFormat: sqlFolderFormat, tableName, c_path2];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -299,6 +318,17 @@
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) updateCPathInFolderInfo: (NSString *) tableName
|
||||||
|
withCPath2: (NSString *) c_path2
|
||||||
|
{
|
||||||
|
static NSString *sqlFolderFormat
|
||||||
|
= (@"UPDATE %@"
|
||||||
|
@" SET c_path = CONCAT('/', c_path1, '/', c_path2, '/', c_path3, '/', c_path4)"
|
||||||
|
@" WHERE c_path2 = '%@'");
|
||||||
|
|
||||||
|
return [NSString stringWithFormat: sqlFolderFormat, tableName, c_path2];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -392,4 +422,15 @@
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) updateCPathInFolderInfo: (NSString *) tableName
|
||||||
|
withCPath2: (NSString *) c_path2
|
||||||
|
{
|
||||||
|
static NSString *sqlFolderFormat
|
||||||
|
= (@"UPDATE %@"
|
||||||
|
@" SET c_path = '/'||c_path1||'/'||c_path2||'/'||c_path3||'/'||c_path4"
|
||||||
|
@" WHERE c_path2 = '%@'");
|
||||||
|
|
||||||
|
return [NSString stringWithFormat: sqlFolderFormat, tableName, c_path2];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -8,11 +8,12 @@ ADDITIONAL_INCLUDE_DIRS += -I. -I..
|
||||||
|
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
|
BASE_LIBS := $(shell gnustep-config --base-libs)
|
||||||
|
|
||||||
libGDLContentStore_LIBRARIES_DEPEND_UPON += \
|
libGDLContentStore_LIBRARIES_DEPEND_UPON += \
|
||||||
-lGDLAccess \
|
-lGDLAccess \
|
||||||
-lNGExtensions -lEOControl \
|
-lNGExtensions -lEOControl \
|
||||||
-lgnustep-base -lobjc
|
$(BASE_LIBS)
|
||||||
|
|
||||||
GDLContentStore_LIBRARIES_DEPEND_UPON += \
|
GDLContentStore_LIBRARIES_DEPEND_UPON += \
|
||||||
-framework GDLAccess \
|
-framework GDLAccess \
|
||||||
|
@ -25,7 +26,7 @@ GCS_TOOL_LIBS += \
|
||||||
-lGDLContentStore -lGDLAccess \
|
-lGDLContentStore -lGDLAccess \
|
||||||
-lNGExtensions -lEOControl \
|
-lNGExtensions -lEOControl \
|
||||||
-lDOM -lSaxObjC \
|
-lDOM -lSaxObjC \
|
||||||
-lgnustep-base
|
$(BASE_LIBS)
|
||||||
else
|
else
|
||||||
GCS_TOOL_LIBS += \
|
GCS_TOOL_LIBS += \
|
||||||
-framework GDLContentStore -framework GDLAccess \
|
-framework GDLContentStore -framework GDLAccess \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* CardElement.h - this file is part of SOPE
|
/* CardElement.h - this file is part of SOPE
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* CardElement.m - this file is part of SOPE
|
/* CardElement.m - this file is part of SOPE
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
@ -424,16 +424,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOL
|
static inline BOOL
|
||||||
_subValuesAreVoid (NSArray *subValues)
|
_subValuesAreVoid (id subValues)
|
||||||
{
|
{
|
||||||
BOOL result = YES;
|
BOOL result = YES;
|
||||||
NSUInteger count, max;
|
NSUInteger count, max;
|
||||||
|
|
||||||
result = YES;
|
result = YES;
|
||||||
|
|
||||||
max = [subValues count];
|
if ([subValues isKindOfClass: [NSArray class]])
|
||||||
for (count = 0; result && count < max; count++)
|
{
|
||||||
result = ([[subValues objectAtIndex: count] length] == 0);
|
max = [subValues count];
|
||||||
|
for (count = 0; result && count < max; count++)
|
||||||
|
result = ([[subValues objectAtIndex: count] length] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,8 @@
|
||||||
- (void) replaceThisElement: (CardElement *) oldElement
|
- (void) replaceThisElement: (CardElement *) oldElement
|
||||||
withThisOne: (CardElement *) newElement;
|
withThisOne: (CardElement *) newElement;
|
||||||
|
|
||||||
|
- (NSArray *) orderOfElements;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif /* CARDGROUP_H */
|
#endif /* CARDGROUP_H */
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* CardGroup.m - this file is part of SOPE
|
/* CardGroup.m - this file is part of SOPE
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
@ -454,4 +454,9 @@ static NGCardsSaxHandler *sax = nil;
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) orderOfElements
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* CardVersitRenderer.m - this file is part of SOPE
|
/* CardVersitRenderer.m - this file is part of SOPE
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
@ -107,6 +107,7 @@
|
||||||
CardElement *currentChild;
|
CardElement *currentChild;
|
||||||
NSMutableString *rendering;
|
NSMutableString *rendering;
|
||||||
NSString *groupTag;
|
NSString *groupTag;
|
||||||
|
NSArray *order;
|
||||||
|
|
||||||
rendering = [NSMutableString string];
|
rendering = [NSMutableString string];
|
||||||
|
|
||||||
|
@ -120,7 +121,36 @@
|
||||||
|
|
||||||
groupTag = [groupTag uppercaseString];
|
groupTag = [groupTag uppercaseString];
|
||||||
[rendering appendFormat: @"BEGIN:%@\r\n", groupTag];
|
[rendering appendFormat: @"BEGIN:%@\r\n", groupTag];
|
||||||
children = [[aGroup children] objectEnumerator];
|
|
||||||
|
// We reorder the group elemments, if necessary
|
||||||
|
order = [aGroup orderOfElements];
|
||||||
|
|
||||||
|
if (order)
|
||||||
|
{
|
||||||
|
NSMutableArray *orderedElements, *originalElements;
|
||||||
|
NSArray *currentChildren;
|
||||||
|
int i, c;
|
||||||
|
|
||||||
|
originalElements = [NSMutableArray arrayWithArray: [aGroup children]];
|
||||||
|
orderedElements = [NSMutableArray array];
|
||||||
|
c = [order count];
|
||||||
|
|
||||||
|
for (i = 0; i < c; i++)
|
||||||
|
{
|
||||||
|
currentChildren = [aGroup childrenWithTag: [order objectAtIndex: i]];
|
||||||
|
[orderedElements addObjectsFromArray: currentChildren];
|
||||||
|
[originalElements removeObjectsInArray: currentChildren];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We add the remaining, unordered elements
|
||||||
|
[orderedElements addObjectsFromArray: originalElements];
|
||||||
|
children = [orderedElements objectEnumerator];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
children = [[aGroup children] objectEnumerator];
|
||||||
|
}
|
||||||
|
|
||||||
while ((currentChild = [children nextObject]))
|
while ((currentChild = [children nextObject]))
|
||||||
[rendering appendString: [self render: currentChild]];
|
[rendering appendString: [self render: currentChild]];
|
||||||
[rendering appendFormat: @"END:%@\r\n", groupTag];
|
[rendering appendFormat: @"END:%@\r\n", groupTag];
|
||||||
|
|
|
@ -17,11 +17,13 @@ ADDITIONAL_INCLUDE_DIRS += \
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
|
|
||||||
|
BASE_LIBS := $(shell gnustep-config --base-libs)
|
||||||
|
|
||||||
libNGCards_LIBRARIES_DEPEND_UPON += \
|
libNGCards_LIBRARIES_DEPEND_UPON += \
|
||||||
-lNGExtensions \
|
-lNGExtensions \
|
||||||
-lEOControl \
|
-lEOControl \
|
||||||
-lSaxObjC \
|
-lSaxObjC \
|
||||||
-lgnustep-base -lobjc -lm
|
$(BASE_LIBS)
|
||||||
|
|
||||||
NGCards_LIBRARIES_DEPEND_UPON += \
|
NGCards_LIBRARIES_DEPEND_UPON += \
|
||||||
-framework NGExtensions -framework EOControl \
|
-framework NGExtensions -framework EOControl \
|
||||||
|
|
|
@ -38,18 +38,6 @@
|
||||||
@class iCalTimeZone;
|
@class iCalTimeZone;
|
||||||
|
|
||||||
@interface iCalCalendar : CardGroup
|
@interface iCalCalendar : CardGroup
|
||||||
// {
|
|
||||||
// NSString *version;
|
|
||||||
// NSString *calscale;
|
|
||||||
// NSString *prodId;
|
|
||||||
// NSString *method;
|
|
||||||
|
|
||||||
// NSMutableArray *todos;
|
|
||||||
// NSMutableArray *events;
|
|
||||||
// NSMutableArray *journals;
|
|
||||||
// NSMutableArray *freeBusys;
|
|
||||||
// NSMutableDictionary *timezones;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* accessors */
|
/* accessors */
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,13 @@
|
||||||
return [super versitString];
|
return [super versitString];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) orderOfElements
|
||||||
|
{
|
||||||
|
return [NSArray arrayWithObjects: @"prodid", @"version", @"method", @"calscale",
|
||||||
|
@"vtimezone", @"vevent", @"vtodo", @"vjournal", @"vfreebusy", nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ical typing */
|
/* ical typing */
|
||||||
|
|
||||||
- (NSString *) entityName
|
- (NSString *) entityName
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
@class iCalRecurrenceRule;
|
@class iCalRecurrenceRule;
|
||||||
|
|
||||||
@interface iCalTimeZonePeriod : CardGroup
|
@interface iCalTimeZonePeriod : CardGroup
|
||||||
|
{
|
||||||
|
NSCalendarDate *startDate;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *) startDate;
|
- (NSCalendarDate *) startDate;
|
||||||
- (iCalRecurrenceRule *) recurrenceRule;
|
- (iCalRecurrenceRule *) recurrenceRule;
|
||||||
|
|
|
@ -103,10 +103,21 @@
|
||||||
// return dayOfWeek;
|
// return dayOfWeek;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[startDate release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *) startDate
|
- (NSCalendarDate *) startDate
|
||||||
{
|
{
|
||||||
return [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]
|
if (!startDate)
|
||||||
dateTime];
|
{
|
||||||
|
startDate = [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]
|
||||||
|
dateTime];
|
||||||
|
[startDate retain];
|
||||||
|
}
|
||||||
|
return startDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (iCalRecurrenceRule *) recurrenceRule
|
- (iCalRecurrenceRule *) recurrenceRule
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
NSTimeInterval anInterval;
|
NSTimeInterval anInterval;
|
||||||
id grandParent;
|
id grandParent;
|
||||||
|
|
||||||
|
nextAlarmDate = nil;
|
||||||
triggerValue = [[self valueType] uppercaseString];
|
triggerValue = [[self valueType] uppercaseString];
|
||||||
if ([triggerValue length] == 0)
|
if ([triggerValue length] == 0)
|
||||||
triggerValue = @"DURATION";
|
triggerValue = @"DURATION";
|
||||||
|
@ -88,8 +89,6 @@
|
||||||
}
|
}
|
||||||
else if ([triggerValue isEqualToString: @"DATE-TIME"])
|
else if ([triggerValue isEqualToString: @"DATE-TIME"])
|
||||||
nextAlarmDate = [[self flattenedValuesForKey: @""] asCalendarDate];
|
nextAlarmDate = [[self flattenedValuesForKey: @""] asCalendarDate];
|
||||||
else
|
|
||||||
nextAlarmDate = nil;
|
|
||||||
|
|
||||||
return nextAlarmDate;
|
return nextAlarmDate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,11 @@ import sys
|
||||||
|
|
||||||
imaphost = '127.0.0.1'
|
imaphost = '127.0.0.1'
|
||||||
imapport = 143
|
imapport = 143
|
||||||
|
|
||||||
sambaprivate = '/var/lib/samba/private'
|
sambaprivate = '/var/lib/samba/private'
|
||||||
mapistorefolder = "%s/mapistore" % (sambaprivate)
|
mapistorefolder = "%s/mapistore" % (sambaprivate)
|
||||||
sogoDefaultsFile = "/home/sogo/GNUstep/Defaults/.GNUstepDefaults"
|
sogoSysDefaultsFile = "/etc/sogo/sogo.conf"
|
||||||
|
sogoUserDefaultsFile = "/home/sogo/GNUstep/Defaults/.GNUstepDefaults"
|
||||||
|
|
||||||
# - takes a username and optionally its password
|
# - takes a username and optionally its password
|
||||||
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
|
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
|
||||||
|
@ -23,7 +25,7 @@ sogoDefaultsFile = "/home/sogo/GNUstep/Defaults/.GNUstepDefaults"
|
||||||
# - Delete the socfs_ table for the username.
|
# - Delete the socfs_ table for the username.
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print """
|
print """
|
||||||
%s [-i imaphost] ] [-p imapport] [-s sambaprivate] username [password]
|
%s [-i imaphost] ] [-p imapport] [-s sambaprivate] username [password]
|
||||||
-i imaphost IMAP host to connect to [%s]
|
-i imaphost IMAP host to connect to [%s]
|
||||||
-p imappost IMAP port to use [%d]
|
-p imappost IMAP port to use [%d]
|
||||||
|
@ -31,60 +33,59 @@ def usage():
|
||||||
""" % (os.path.basename(sys.argv[0]), imaphost, imapport, sambaprivate)
|
""" % (os.path.basename(sys.argv[0]), imaphost, imapport, sambaprivate)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global sambaprivate
|
global sambaprivate
|
||||||
global mapistorefolder
|
global mapistorefolder
|
||||||
global imaphost
|
global imaphost
|
||||||
global imapport
|
global imapport
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "i:p:s:")
|
opts, args = getopt.getopt(sys.argv[1:], "i:p:s:")
|
||||||
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
||||||
print str(err)
|
print str(err)
|
||||||
usage()
|
usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
for o, a in opts:
|
for o, a in opts:
|
||||||
if o == "-i":
|
if o == "-i":
|
||||||
imaphost = a
|
imaphost = a
|
||||||
elif o == "-p":
|
elif o == "-p":
|
||||||
imapport = a
|
imapport = a
|
||||||
elif o == "-s":
|
elif o == "-s":
|
||||||
sambaprivate = a
|
sambaprivate = a
|
||||||
mapistorefolder = "%s/mapistore" % (sambaprivate)
|
mapistorefolder = "%s/mapistore" % (sambaprivate)
|
||||||
else:
|
else:
|
||||||
assert False, "unhandled option"
|
assert False, "unhandled option"
|
||||||
|
|
||||||
argslen = len(args)
|
argslen = len(args)
|
||||||
if (argslen == 2):
|
if (argslen == 2):
|
||||||
username = args[0]
|
username = args[0]
|
||||||
userpass = args[1]
|
userpass = args[1]
|
||||||
elif (argslen == 1):
|
elif (argslen == 1):
|
||||||
username = args[0]
|
username = args[0]
|
||||||
userpass = username
|
userpass = username
|
||||||
print "Using username as password"
|
print "Using username as password"
|
||||||
else:
|
else:
|
||||||
usage()
|
usage()
|
||||||
print "Specify a user (and optionally the password)"
|
print "Specify a user (and optionally the password)"
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# cleanup starts here
|
# cleanup starts here
|
||||||
try:
|
try:
|
||||||
imapCleanup(imaphost, imapport, username, userpass)
|
imapCleanup(imaphost, imapport, username, userpass)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "Error during imapCleanup, continuing: %s" % str(e)
|
print "Error during imapCleanup, continuing: %s" % str(e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mapistoreCleanup(mapistorefolder, username)
|
mapistoreCleanup(mapistorefolder, username)
|
||||||
except (shutil.Error, OSError) as e:
|
except (shutil.Error, OSError) as e:
|
||||||
print "Error during mapistoreCleanup, continuing: %s" % str(e)
|
print "Error during mapistoreCleanup, continuing: %s" % str(e)
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# pass
|
# pass
|
||||||
# #ldbCleanup(sambaprivate, username)
|
# #ldbCleanup(sambaprivate, username)
|
||||||
# except ldb.LdbError as e:
|
# except ldb.LdbError as e:
|
||||||
# print "Error during ldbCleanup, continuing: %s" % str(e)
|
# print "Error during ldbCleanup, continuing: %s" % str(e)
|
||||||
|
|
||||||
sqlCleanup(username)
|
|
||||||
|
|
||||||
|
sqlCleanup(username)
|
||||||
|
|
||||||
def extractmb(si):
|
def extractmb(si):
|
||||||
inparen = False
|
inparen = False
|
||||||
|
@ -133,8 +134,7 @@ def cleanupmb(mb, client):
|
||||||
else:
|
else:
|
||||||
print "mailbox '%s' coult NOT be deleted (code = '%s')" % (mb, code)
|
print "mailbox '%s' coult NOT be deleted (code = '%s')" % (mb, code)
|
||||||
|
|
||||||
def imapCleanup(imaphost, imapport, username, userpass) :
|
def imapCleanup(imaphost, imapport, username, userpass):
|
||||||
|
|
||||||
client = imaplib.IMAP4(imaphost, imapport)
|
client = imaplib.IMAP4(imaphost, imapport)
|
||||||
(code, data) = client.login(username, userpass)
|
(code, data) = client.login(username, userpass)
|
||||||
if code != "OK":
|
if code != "OK":
|
||||||
|
@ -142,83 +142,113 @@ def imapCleanup(imaphost, imapport, username, userpass) :
|
||||||
|
|
||||||
print "Logged in as '%s'" % username
|
print "Logged in as '%s'" % username
|
||||||
|
|
||||||
for foldername in [ "Sync Issues", "Junk E-mail" ]:
|
for foldername in ("Sync Issues", "Junk E-mail"):
|
||||||
(code, data) = client.list(foldername, "%")
|
(code, data) = client.list(foldername, "%")
|
||||||
if code == "OK":
|
if code == "OK":
|
||||||
for si in data:
|
for si in data:
|
||||||
if si is not None:
|
if si is not None:
|
||||||
print si
|
|
||||||
continue
|
|
||||||
mb = extractmb(si)
|
mb = extractmb(si)
|
||||||
cleanupmb(mb, client)
|
cleanupmb(mb, client)
|
||||||
client.logout()
|
client.logout()
|
||||||
|
|
||||||
def mapistoreCleanup(mapistorefolder, username):
|
def mapistoreCleanup(mapistorefolder, username):
|
||||||
|
|
||||||
# delete the user's folder under the mapistore and under mapistore/SOGo
|
# delete the user's folder under the mapistore and under mapistore/SOGo
|
||||||
shutil.rmtree("%s/%s" % (mapistorefolder, username), ignore_errors=True)
|
shutil.rmtree("%s/%s" % (mapistorefolder, username), ignore_errors=True)
|
||||||
shutil.rmtree("%s/SOGo/%s" % (mapistorefolder, username), ignore_errors=True)
|
shutil.rmtree("%s/SOGo/%s" % (mapistorefolder, username), ignore_errors=True)
|
||||||
|
|
||||||
# NOTYET
|
# NOTYET
|
||||||
#def ldbCleanup(sambaprivate, username):
|
#def ldbCleanup(sambaprivate, username):
|
||||||
# conn = ldb.Ldb("%s/openchange.ldb" % (sambaprivate))
|
# conn = ldb.Ldb("%s/openchange.ldb" % (sambaprivate))
|
||||||
#### entries = conn.search(None, expression="(|(cn=%s)(MAPIStoreURI=sogo://%s:*)(MAPIStoreURI=sogo://%s@*))" % (username,username,username),
|
#### entries = conn.search(None, expression="(|(cn=%s)(MAPIStoreURI=sogo://%s:*)(MAPIStoreURI=sogo://%s@*))" % (username,username,username),
|
||||||
# entries = conn.search(None, expression="cn=%s" % (username),
|
# entries = conn.search(None, expression="cn=%s" % (username),
|
||||||
# scope=ldb.SCOPE_SUBTREE)
|
# scope=ldb.SCOPE_SUBTREE)
|
||||||
# for entry in entries:
|
# for entry in entries:
|
||||||
# print "Deleting %s" % (entry.dn)
|
# print "Deleting %s" % (entry.dn)
|
||||||
# conn.delete(entry.dn)
|
# conn.delete(entry.dn)
|
||||||
|
|
||||||
def mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
def mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
||||||
import MySQLdb
|
import MySQLdb
|
||||||
|
|
||||||
conn= MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
|
conn= MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
|
||||||
c=conn.cursor()
|
c=conn.cursor()
|
||||||
tablename="socfs_%s" % (username)
|
tablename="socfs_%s" % (username)
|
||||||
c.execute("TRUNCATE TABLE %s" % tablename)
|
c.execute("TRUNCATE TABLE %s" % tablename)
|
||||||
print "Table %s emptied"
|
print "Table %s emptied"
|
||||||
|
|
||||||
|
|
||||||
def postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
def postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
||||||
import pg
|
import pg
|
||||||
conn = pg.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, dbname=dbname)
|
conn = pg.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, dbname=dbname)
|
||||||
tablename = "socfs_%s" % username
|
tablename = "socfs_%s" % username
|
||||||
conn.query("DELETE FROM %s" % tablename)
|
conn.query("DELETE FROM %s" % tablename)
|
||||||
print "table '%s' emptied" % tablename
|
print "table '%s' emptied" % tablename
|
||||||
|
|
||||||
def getOCSFolderInfoURL():
|
def getOCSFolderInfoURL():
|
||||||
global sogoDefaultsFile
|
global sogoSysDefaultsFile, sogoUserDefaultsFile
|
||||||
sogoDefaults = plistlib.readPlist(sogoDefaultsFile)
|
|
||||||
try:
|
|
||||||
OCSFolderInfoURL = sogoDefaults['sogod']['OCSFolderInfoURL']
|
|
||||||
except KeyError:
|
|
||||||
OCSFolderInfoURL = ""
|
OCSFolderInfoURL = ""
|
||||||
|
|
||||||
return OCSFolderInfoURL
|
# read defaults from /etc/sogo/sogo.conf
|
||||||
|
if os.path.exists(sogoSysDefaultsFile):
|
||||||
|
sogoDefaults = plistlib.readPlist(sogoSysDefaultsFile)
|
||||||
|
if "OCSFolderInfoURL" in sogoDefaults:
|
||||||
|
OCSFolderInfoURL = sogoDefaults["OCSFolderInfoURL"]
|
||||||
|
|
||||||
|
# defaults from user directory must have precedence
|
||||||
|
if os.path.exists(sogoUserDefaultsFile):
|
||||||
|
sogoDefaults = plistlib.readPlist(sogoUserDefaultsFile)
|
||||||
|
if "sogod" in sogoDefaults and "OCSFolderInfoURL" in sogoDefaults["sogod"]:
|
||||||
|
OCSFolderInfoURL = sogoDefaults['sogod']['OCSFolderInfoURL']
|
||||||
|
|
||||||
|
return OCSFolderInfoURL
|
||||||
|
|
||||||
|
def asCSSIdentifier(inputString):
|
||||||
|
cssEscapingCharMap = {"_" : "_U_",
|
||||||
|
"." : "_D_",
|
||||||
|
"#" : "_H_",
|
||||||
|
"@" : "_A_",
|
||||||
|
"*" : "_S_",
|
||||||
|
":" : "_C_",
|
||||||
|
"," : "_CO_",
|
||||||
|
" " : "_SP_",
|
||||||
|
"'" : "_SQ_",
|
||||||
|
"&" : "_AM_",
|
||||||
|
"+" : "_P_"}
|
||||||
|
|
||||||
|
newChars = []
|
||||||
|
|
||||||
|
for c in inputString:
|
||||||
|
if c in cssEscapingCharMap:
|
||||||
|
newChars.append(cssEscapingCharMap[c])
|
||||||
|
else:
|
||||||
|
newChars.append(c)
|
||||||
|
|
||||||
|
return "".join(newChars)
|
||||||
|
|
||||||
def sqlCleanup(username):
|
def sqlCleanup(username):
|
||||||
OCSFolderInfoURL = getOCSFolderInfoURL()
|
OCSFolderInfoURL = getOCSFolderInfoURL()
|
||||||
if (OCSFolderInfoURL is None):
|
if OCSFolderInfoURL is None:
|
||||||
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the socfs_%s table should be truncated manually" % (username))
|
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the socfs_%s table should be truncated manually" % (username))
|
||||||
|
|
||||||
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
|
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
|
||||||
m = re.search("(.+)://(.+):(.+)@(.+):(\d+)/(.+)/(.+)", OCSFolderInfoURL)
|
m = re.search("(.+)://(.+):(.+)@(.+):(\d+)/(.+)/(.+)", OCSFolderInfoURL)
|
||||||
|
|
||||||
proto = m.group(1)
|
proto = m.group(1)
|
||||||
dbuser = m.group(2)
|
dbuser = m.group(2)
|
||||||
dbpass = m.group(3)
|
dbpass = m.group(3)
|
||||||
dbhost = m.group(4)
|
dbhost = m.group(4)
|
||||||
dbport = m.group(5)
|
dbport = m.group(5)
|
||||||
dbname = m.group(6)
|
dbname = m.group(6)
|
||||||
# 7 is folderinfo table
|
# 7 is folderinfo table
|
||||||
|
|
||||||
if (proto == "postgresql"):
|
encodedUserName = asCSSIdentifier(username)
|
||||||
postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username)
|
|
||||||
elif (proto == "mysql"):
|
|
||||||
mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username)
|
|
||||||
else:
|
|
||||||
raise Exception("Unknown sql proto: " % (proto))
|
|
||||||
|
|
||||||
|
if (proto == "postgresql"):
|
||||||
|
postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, encodedUserName)
|
||||||
|
elif (proto == "mysql"):
|
||||||
|
mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, encodedUserName)
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown sql proto: " % (proto))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -28,22 +28,22 @@ $plugins
|
||||||
= array(
|
= array(
|
||||||
"sogo-connector@inverse.ca"
|
"sogo-connector@inverse.ca"
|
||||||
=> array( "application" => "thunderbird",
|
=> array( "application" => "thunderbird",
|
||||||
"version" => "10.0.3",
|
"version" => "17.0.2",
|
||||||
"filename" => "sogo-connector-10.0.3.xpi" ),
|
"filename" => "sogo-connector-17.0.2.xpi" ),
|
||||||
"sogo-integrator@inverse.ca"
|
"sogo-integrator@inverse.ca"
|
||||||
=> array( "application" => "thunderbird",
|
=> array( "application" => "thunderbird",
|
||||||
"version" => "10.0.3",
|
"version" => "17.0.2",
|
||||||
"filename" => "sogo-integrator-10.0.3.xpi" ),
|
"filename" => "sogo-integrator-17.0.2.xpi" ),
|
||||||
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
|
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
|
||||||
=> array( "application" => "thunderbird",
|
=> array( "application" => "thunderbird",
|
||||||
"version" => "1.2.3",
|
"version" => "1.9",
|
||||||
"filename" => "lightning.xpi" )
|
"filename" => "lightning-1.9.xpi" )
|
||||||
);
|
);
|
||||||
|
|
||||||
$applications
|
$applications
|
||||||
= array( "thunderbird" => "<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
|
= array( "thunderbird" => "<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
|
||||||
<em:minVersion>10.0</em:minVersion>
|
<em:minVersion>17.0</em:minVersion>
|
||||||
<em:maxVersion>10.*</em:maxVersion>" );
|
<em:maxVersion>17.*</em:maxVersion>" );
|
||||||
|
|
||||||
$pluginname = $_GET["plugin"];
|
$pluginname = $_GET["plugin"];
|
||||||
$plugin =& $plugins[$pluginname];
|
$plugin =& $plugins[$pluginname];
|
||||||
|
|
|
@ -8,23 +8,15 @@ vtodo_class1 = "(Tarefa Privada)";
|
||||||
vtodo_class2 = "(Tarefa Confidencial)";
|
vtodo_class2 = "(Tarefa Confidencial)";
|
||||||
|
|
||||||
/* Receipts */
|
/* Receipts */
|
||||||
"Title:" = "Título:";
|
"The event \"%{Summary}\" was created" = "O evento \"%{Summary}\" foi criado";
|
||||||
"Start:" = "Início:";
|
"The event \"%{Summary}\" was deleted" = "O evento \"%{Summary}\" foi removido";
|
||||||
"End:" = "Fim:";
|
"The event \"%{Summary}\" was updated" = "O evento \"%{Summary}\" foi atualizado";
|
||||||
|
"The following attendees(s) were notified:" = "Estes participantes foram notificados:";
|
||||||
"Receipt: users invited to a meeting" = "Recepção: usuários convidados para uma reunião";
|
"The following attendees(s) were added:" = "Estes participantes foram adicionados:";
|
||||||
"You have invited the following attendees(s):" = "Você convidou o(s) seguinte(s) participante(s):";
|
"The following attendees(s) were removed:" = "Estes participantes foram removidos:";
|
||||||
"... to attend the following event:" = ".. para participar do seguinte evento:";
|
|
||||||
|
|
||||||
"Receipt: invitation updated" = "Recepção: Convite atualizado";
|
|
||||||
"The following attendees(s):" = "O(s) seguinte(s) participante(s):";
|
|
||||||
"... have been notified of the changes to the following event:" = "... foi notificado das alterações do seguinte evento:";
|
|
||||||
|
|
||||||
"Receipt: attendees removed from an event" = "Recepção: participantes removidos de um evento";
|
|
||||||
"You have removed the following attendees(s):" = "Você removeu o(s) seguinte(s) participante(s): ";
|
|
||||||
"... from the following event:" = "... do seguinte evento:";
|
|
||||||
|
|
||||||
/* IMIP messages */
|
/* IMIP messages */
|
||||||
|
"calendar_label" = "Calendário:";
|
||||||
"startDate_label" = "Início:";
|
"startDate_label" = "Início:";
|
||||||
"endDate_label" = "Fim:";
|
"endDate_label" = "Fim:";
|
||||||
"due_label" = "Data de Vencimento:";
|
"due_label" = "Data de Vencimento:";
|
||||||
|
@ -35,14 +27,19 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
||||||
/* Invitation */
|
/* Invitation */
|
||||||
"Event Invitation: \"%{Summary}\"" = "Convite do Evento: \"%{Summary}\"";
|
"Event Invitation: \"%{Summary}\"" = "Convite do Evento: \"%{Summary}\"";
|
||||||
"(sent by %{SentBy}) " = "(enviado por %{SentBy}) ";
|
"(sent by %{SentBy}) " = "(enviado por %{SentBy}) ";
|
||||||
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}convidou você para %{Summary}.\n\nInicio: %{StartDate}\nFim: %{EndDate}\nDescrição: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} convidou você para %{Summary}.\n\nInício: %{StartDate} as %{StartTime}\nFim: %{EndDate} as %{EndTime}\nDescrição: %{Description}";
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} convidou você para %{Summary}.\n\nInício: %{StartDate} as %{StartTime}\nFim: %{EndDate} as %{EndTime}\nDescrição: %{Description}";
|
||||||
|
|
||||||
/* Deletion */
|
/* Deletion */
|
||||||
"Event Cancelled: \"%{Summary}\"" = "Evento Cancelado: \"%{Summary}\"";
|
"Event Cancelled: \"%{Summary}\"" = "Evento Cancelado: \"%{Summary}\"";
|
||||||
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||||
|
= "%{Organizer} %{SentByText}cancelou este evento: %{Summary}.\n\nInicio: %{StartDate}\nFim: %{EndDate}\nDescrição: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||||
= "%{Organizer} %{SentByText} cancelou este evento: %{Summary}.\n\nInício: %{StartDate} as %{StartTime}\nFim: %{EndDate} as %{EndTime}\nDescrição: %{Description}";
|
= "%{Organizer} %{SentByText} cancelou este evento: %{Summary}.\n\nInício: %{StartDate} as %{StartTime}\nFim: %{EndDate} as %{EndTime}\nDescrição: %{Description}";
|
||||||
|
|
||||||
/* Update */
|
/* Update */
|
||||||
|
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||||
|
= "O compromisso \"%{Summary}\" de %{OldStartDate} mudou";
|
||||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||||
= "O Compromisso \"%{Summary}\" de %{OldStartDate} as %{OldStartTime} mudou";
|
= "O Compromisso \"%{Summary}\" de %{OldStartDate} as %{OldStartTime} mudou";
|
||||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||||
|
@ -51,6 +48,10 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
||||||
= "Por favor, aceitar ou recusar as alterações.";
|
= "Por favor, aceitar ou recusar as alterações.";
|
||||||
|
|
||||||
/* Reply */
|
/* Reply */
|
||||||
|
"Accepted invitation: \"%{Summary}\"" = "Convite aceito: \"%{Summary}\"";
|
||||||
|
"Declined invitation: \"%{Summary}\"" = "Convite recusado: \"%{Summary}\"";
|
||||||
|
"Delegated invitation: \"%{Summary}\"" = "Convite delegado: \"%{Summary}\"";
|
||||||
|
"Not yet decided on invitation: \"%{Summary}\"" = "Convite ainda não decidido: \"%{Summary}\"";
|
||||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||||
= "%{Attendee} %{SentByText}foi aceitado seu convite ao evento.";
|
= "%{Attendee} %{SentByText}foi aceitado seu convite ao evento.";
|
||||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||||
|
@ -61,4 +62,5 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
||||||
= "%{Attendee} %{SentByText}foi ainda não decidiu seu convite ao evento.";
|
= "%{Attendee} %{SentByText}foi ainda não decidiu seu convite ao evento.";
|
||||||
|
|
||||||
/* Resources */
|
/* Resources */
|
||||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Número máximo de reservas simultâneas (%{NumberOfSimultaneousBookings}) alcançadas para o recurso \"%{Cn} %{SystemEmail}\".";
|
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Não foi possível acessar o recurso: \"%{Cn} %{SystemEmail}\"";
|
||||||
|
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "O número máximo de reservas simultaneas (%{NumberOfSimultaneousBookings}) acabou para o recurso \"%{Cn} %{SystemEmail}\". O evento conflitante é \"%{EventTitle}\", e inicia em %{StartDate}.";
|
||||||
|
|
|
@ -53,7 +53,7 @@ Appointments_RESOURCE_FILES += \
|
||||||
\
|
\
|
||||||
MSExchangeFreeBusySOAPRequest.wo
|
MSExchangeFreeBusySOAPRequest.wo
|
||||||
|
|
||||||
Appointments_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
Appointments_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||||
|
|
||||||
Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||||
|
|
||||||
|
|
|
@ -28,14 +28,14 @@ vtodo_class2 = "(Zadanie poufne)";
|
||||||
"Event Invitation: \"%{Summary}\"" = "Zaproszenie na wydarzenie: \"%{Summary}\"";
|
"Event Invitation: \"%{Summary}\"" = "Zaproszenie na wydarzenie: \"%{Summary}\"";
|
||||||
"(sent by %{SentBy}) " = "(wysłane przez %{SentBy}) ";
|
"(sent by %{SentBy}) " = "(wysłane przez %{SentBy}) ";
|
||||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}zaprosił Cię na %{Summary}.⏎ ⏎ Początek: %{StartDate}⏎ Koniec: %{EndDate}⏎ Opis: %{Description}";
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}zaprosił Cię na %{Summary}.⏎ ⏎ Początek: %{StartDate}⏎ Koniec: %{EndDate}⏎ Opis: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}zaprosił cię na %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}";
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}zaprosił cię na %{Summary}.\n\nPoczątek: %{StartDate} o %{StartTime}\nKoniec: %{EndDate} o %{EndTime}\nOpis: %{Description}";
|
||||||
|
|
||||||
/* Deletion */
|
/* Deletion */
|
||||||
"Event Cancelled: \"%{Summary}\"" = "Wydarzenie anulowane: \"%{Summary}\"";
|
"Event Cancelled: \"%{Summary}\"" = "Wydarzenie anulowane: \"%{Summary}\"";
|
||||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||||
= "%{Organizer} %{SentByText} anulował(a) to wydarzenie: %{Summary}.⏎⏎ Początek: %{StartDate}⏎ Koniec: %{EndDate}⏎ Opis: %{Description}";
|
= "%{Organizer} %{SentByText} anulował(a) to wydarzenie: %{Summary}.⏎⏎ Początek: %{StartDate}⏎ Koniec: %{EndDate}⏎ Opis: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||||
= "%{Organizer} %{SentByText}anulował(a) to wydarzenie: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}";
|
= "%{Organizer} %{SentByText}anulował(a) to wydarzenie: %{Summary}.\n\nPoczątek: %{StartDate} o %{StartTime}\nKoniec: %{EndDate} o %{EndTime}\nOpis: %{Description}";
|
||||||
|
|
||||||
/* Update */
|
/* Update */
|
||||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||||
|
|
|
@ -2885,11 +2885,26 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
timezone: (iCalTimeZone *) timezone
|
timezone: (iCalTimeZone *) timezone
|
||||||
{
|
{
|
||||||
SOGoAppointmentObject *object;
|
SOGoAppointmentObject *object;
|
||||||
NSString *uid;
|
|
||||||
NSMutableString *content;
|
NSMutableString *content;
|
||||||
|
NSString *uid;
|
||||||
|
|
||||||
uid = [self globallyUniqueObjectId];
|
uid = [self globallyUniqueObjectId];
|
||||||
[event setUid: uid];
|
[event setUid: uid];
|
||||||
|
|
||||||
|
// We first look if there's an event with the same UID in our calendar. If not,
|
||||||
|
// let's reuse what is in the event, otherwise generate a new GUID and use it.
|
||||||
|
uid = [event uid];
|
||||||
|
|
||||||
|
object = [self lookupName: uid
|
||||||
|
inContext: context
|
||||||
|
acquire: NO];
|
||||||
|
|
||||||
|
if (object && ![object isKindOfClass: [NSException class]])
|
||||||
|
{
|
||||||
|
uid = [self globallyUniqueObjectId];
|
||||||
|
[event setUid: uid];
|
||||||
|
}
|
||||||
|
|
||||||
object = [SOGoAppointmentObject objectWithName: uid
|
object = [SOGoAppointmentObject objectWithName: uid
|
||||||
inContainer: self];
|
inContainer: self];
|
||||||
[object setIsNew: YES];
|
[object setIsNew: YES];
|
||||||
|
@ -3024,7 +3039,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
acquire: NO];
|
acquire: NO];
|
||||||
if (master)
|
if (master)
|
||||||
{
|
{
|
||||||
// Associate the occurrence to the master event
|
// Associate the occurrence to the master event and skip the actual import process
|
||||||
masterCalendar = [master calendar: NO secure: NO];
|
masterCalendar = [master calendar: NO secure: NO];
|
||||||
[masterCalendar addToEvents: event];
|
[masterCalendar addToEvents: event];
|
||||||
if (timezone)
|
if (timezone)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/* SOGoAppointmentFolderICS.m - this file is part of SOGo
|
/* SOGoAppointmentFolderICS.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010 Inverse inc.
|
* Copyright (C) 2010-2012 Inverse inc.
|
||||||
*
|
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
|
||||||
*
|
*
|
||||||
* This file is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,6 +20,7 @@
|
||||||
|
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
|
|
||||||
|
#import <NGCards/CardElement.h>
|
||||||
#import <NGCards/iCalCalendar.h>
|
#import <NGCards/iCalCalendar.h>
|
||||||
|
|
||||||
#import "SOGoAppointmentFolderICS.h"
|
#import "SOGoAppointmentFolderICS.h"
|
||||||
|
@ -30,7 +29,19 @@
|
||||||
|
|
||||||
- (NSString *) contentAsString
|
- (NSString *) contentAsString
|
||||||
{
|
{
|
||||||
return [[self contentCalendar] versitString];
|
iCalCalendar *cal;
|
||||||
|
CardElement *e;
|
||||||
|
NSString *s;
|
||||||
|
|
||||||
|
cal = [self contentCalendar];
|
||||||
|
|
||||||
|
e = [CardElement simpleElementWithTag: @"x-wr-calname"
|
||||||
|
value: [self displayName]];
|
||||||
|
[cal addChild: e];
|
||||||
|
s = [cal versitString];
|
||||||
|
[cal removeChild: e];
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) davContentType
|
- (NSString *) davContentType
|
||||||
|
|
|
@ -410,14 +410,6 @@
|
||||||
previousObject: oldEvent
|
previousObject: oldEvent
|
||||||
toAttendees: updateAttendees
|
toAttendees: updateAttendees
|
||||||
withType: @"calendar:invitation-update"];
|
withType: @"calendar:invitation-update"];
|
||||||
|
|
||||||
#if 0
|
|
||||||
// DELETE CODE
|
|
||||||
[self sendReceiptEmailForObject: newEvent
|
|
||||||
addedAttendees: nil
|
|
||||||
deletedAttendees: nil
|
|
||||||
updatedAttendees: updateAttendees];
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -968,6 +960,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
[otherAttendee setDelegatedTo: [attendee delegatedTo]];
|
[otherAttendee setDelegatedTo: [attendee delegatedTo]];
|
||||||
[otherAttendee setDelegatedFrom: [attendee delegatedFrom]];
|
[otherAttendee setDelegatedFrom: [attendee delegatedFrom]];
|
||||||
|
|
||||||
|
// Remove the RSVP attribute, as an action from the attendee
|
||||||
|
// was actually performed, and this confuses iCal (bug #1850)
|
||||||
|
[[otherAttendee attributes] removeObjectForKey: @"RSVP"];
|
||||||
|
|
||||||
// If one has accepted / declined an invitation on behalf of
|
// If one has accepted / declined an invitation on behalf of
|
||||||
// the attendee, we add the user to the SENT-BY attribute.
|
// the attendee, we add the user to the SENT-BY attribute.
|
||||||
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
||||||
|
@ -999,7 +995,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This method is invoked from the SOGo Web interface.
|
// This method is invoked from the SOGo Web interface or from the DAV interface.
|
||||||
//
|
//
|
||||||
// - theOwnerUser is owner of the calendar where the attendee
|
// - theOwnerUser is owner of the calendar where the attendee
|
||||||
// participation state has changed.
|
// participation state has changed.
|
||||||
|
@ -1063,6 +1059,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
|| [currentStatus caseInsensitiveCompare: newStatus]
|
|| [currentStatus caseInsensitiveCompare: newStatus]
|
||||||
!= NSOrderedSame)
|
!= NSOrderedSame)
|
||||||
{
|
{
|
||||||
|
NSMutableArray *delegates;
|
||||||
|
NSString *delegatedUID;
|
||||||
|
|
||||||
|
delegatedUID = nil;
|
||||||
[attendee setPartStat: newStatus];
|
[attendee setPartStat: newStatus];
|
||||||
|
|
||||||
// If one has accepted / declined an invitation on behalf of
|
// If one has accepted / declined an invitation on behalf of
|
||||||
|
@ -1087,9 +1087,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
|
|
||||||
[attendee setDelegatedTo: [delegate email]];
|
[attendee setDelegatedTo: [delegate email]];
|
||||||
|
|
||||||
NSString *delegatedUID = nil;
|
|
||||||
NSMutableArray *delegates;
|
|
||||||
|
|
||||||
if (removeDelegate)
|
if (removeDelegate)
|
||||||
{
|
{
|
||||||
delegates = [NSMutableArray array];
|
delegates = [NSMutableArray array];
|
||||||
|
@ -1123,13 +1120,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
previousObject: nil
|
previousObject: nil
|
||||||
toAttendees: delegates
|
toAttendees: delegates
|
||||||
withType: @"calendar:cancellation"];
|
withType: @"calendar:cancellation"];
|
||||||
#if 0
|
} // if (removeDelegate)
|
||||||
// DELETE CODE
|
|
||||||
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
|
||||||
forObject: event
|
|
||||||
to: delegates];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addDelegate)
|
if (addDelegate)
|
||||||
{
|
{
|
||||||
|
@ -1148,12 +1139,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
previousObject: nil
|
previousObject: nil
|
||||||
toAttendees: delegates
|
toAttendees: delegates
|
||||||
withType: @"calendar:invitation"];
|
withType: @"calendar:invitation"];
|
||||||
#if 0
|
} // if (addDelegate)
|
||||||
// DELETE CODE
|
|
||||||
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
|
||||||
forObject: event to: delegates];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the current user isn't the organizer of the event
|
// If the current user isn't the organizer of the event
|
||||||
// that has just been updated, we update the event and
|
// that has just been updated, we update the event and
|
||||||
|
@ -1161,10 +1147,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
if (!(ex || [event userIsOrganizer: ownerUser]))
|
if (!(ex || [event userIsOrganizer: ownerUser]))
|
||||||
{
|
{
|
||||||
if ([[attendee rsvp] isEqualToString: @"true"]
|
if ([event isStillRelevant])
|
||||||
&& [event isStillRelevant])
|
|
||||||
[self sendResponseToOrganizer: event
|
[self sendResponseToOrganizer: event
|
||||||
from: ownerUser];
|
from: ownerUser];
|
||||||
|
|
||||||
organizerUID = [[event organizer] uid];
|
organizerUID = [[event organizer] uid];
|
||||||
|
|
||||||
|
@ -1372,22 +1357,22 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
reason: @"delegate is a group"];
|
reason: @"delegate is a group"];
|
||||||
}
|
}
|
||||||
if (ex == nil)
|
if (ex == nil)
|
||||||
ex = [self _handleAttendee: attendee
|
{
|
||||||
withDelegate: delegate
|
// Remove the RSVP attribute, as an action from the attendee
|
||||||
ownerUser: ownerUser
|
// was actually performed, and this confuses iCal (bug #1850)
|
||||||
statusChange: _status
|
[[attendee attributes] removeObjectForKey: @"RSVP"];
|
||||||
inEvent: event];
|
ex = [self _handleAttendee: attendee
|
||||||
|
withDelegate: delegate
|
||||||
|
ownerUser: ownerUser
|
||||||
|
statusChange: _status
|
||||||
|
inEvent: event];
|
||||||
|
}
|
||||||
if (ex == nil)
|
if (ex == nil)
|
||||||
{
|
{
|
||||||
// We generate the updated iCalendar file and we save it in
|
// We generate the updated iCalendar file and we save it in
|
||||||
// the database. We do this ONLY when using SOGo from the
|
// the database. We do this ONLY when using SOGo from the
|
||||||
// Web interface. Over DAV, it'll be handled directly in
|
// Web interface. Over DAV, it'll be handled directly in
|
||||||
// PUTAction:
|
// PUTAction:
|
||||||
|
|
||||||
/* FIXME: this is a hack caused by the fact that
|
|
||||||
updateContentWithCalendar:fromRequest: invokes
|
|
||||||
changeParticipationStatusblabla, while the latter was
|
|
||||||
actually designed to be invoked by web methods only */
|
|
||||||
if (![context request] || [[context request] handledByDefaultHandler])
|
if (![context request] || [[context request] handledByDefaultHandler])
|
||||||
ex = [self saveContentString: [calendar versitString]];
|
ex = [self saveContentString: [calendar versitString]];
|
||||||
}
|
}
|
||||||
|
@ -1944,6 +1929,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
return [NSException exceptionWithHTTPStatus:403
|
return [NSException exceptionWithHTTPStatus:403
|
||||||
reason: @"sequences don't match"];
|
reason: @"sequences don't match"];
|
||||||
|
|
||||||
|
// Remove the RSVP attribute, as an action from the attendee
|
||||||
|
// was actually performed, and this confuses iCal (bug #1850)
|
||||||
|
[[attendee attributes] removeObjectForKey: @"RSVP"];
|
||||||
|
|
||||||
delegate = nil;
|
delegate = nil;
|
||||||
delegateEmail = [attendee delegatedTo];
|
delegateEmail = [attendee delegatedTo];
|
||||||
|
|
|
@ -725,7 +725,8 @@
|
||||||
header = [NSString stringWithFormat: @"text/calendar; method=%@;"
|
header = [NSString stringWithFormat: @"text/calendar; method=%@;"
|
||||||
@" charset=\"%@\"",
|
@" charset=\"%@\"",
|
||||||
[(iCalCalendar *) [object parent] method], charset];
|
[(iCalCalendar *) [object parent] method], charset];
|
||||||
headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
|
headerMap = [NGMutableHashMap hashMapWithCapacity: 3];
|
||||||
|
[headerMap setObject: @"urn:content-classes:calendarmessage" forKey: @"Content-Class"];
|
||||||
[headerMap setObject: header forKey: @"content-type"];
|
[headerMap setObject: header forKey: @"content-type"];
|
||||||
[headerMap setObject: @"quoted-printable"
|
[headerMap setObject: @"quoted-printable"
|
||||||
forKey: @"content-transfer-encoding"];
|
forKey: @"content-transfer-encoding"];
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
- (NSArray *) davCalendarUserAddressSet;
|
- (NSArray *) davCalendarUserAddressSet;
|
||||||
- (NSArray *) davCalendarHomeSet;
|
- (NSArray *) davCalendarHomeSet;
|
||||||
|
- (NSArray *) davCalendarScheduleInboxURL;
|
||||||
- (NSArray *) davCalendarScheduleOutboxURL;
|
- (NSArray *) davCalendarScheduleOutboxURL;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
"Personal Calendar" = "Osobný kalendár";
|
||||||
|
vevent_class0 = "(Verejná udalosť)";
|
||||||
|
vevent_class1 = "(Súkromná udalosť)";
|
||||||
|
vevent_class2 = "(Dôverná udalosť)";
|
||||||
|
|
||||||
|
vtodo_class0 = "(Verejná úloha)";
|
||||||
|
vtodo_class1 = "(Súkromná úloha)";
|
||||||
|
vtodo_class2 = "(Dôverná úloha)";
|
||||||
|
|
||||||
|
/* Receipts */
|
||||||
|
"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ý:";
|
||||||
|
|
||||||
|
/* IMIP messages */
|
||||||
|
"calendar_label" = "Kalendár:";
|
||||||
|
"startDate_label" = "Začiatok:";
|
||||||
|
"endDate_label" = "Koniec:";
|
||||||
|
"due_label" = "Platnosť:";
|
||||||
|
"location_label" = "Miesto:";
|
||||||
|
"summary_label" = "Zhrnutie:";
|
||||||
|
"comment_label" = "Komentár:";
|
||||||
|
|
||||||
|
/* Invitation */
|
||||||
|
"Event Invitation: \"%{Summary}\"" = "Pozvánka na udalosť: \"%{Summary}\"";
|
||||||
|
"(sent by %{SentBy}) " = "(odoslané %{SentBy})";
|
||||||
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}Vás pozval na %{Summary}.⏎ ⏎ Začiatok: %{StartDate}⏎ Koniec: %{EndDate}⏎ Podrobnosti: %{Description}";
|
||||||
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}has invited you to %{Summary}.⏎ ⏎ Start: %{StartDate} at %{StartTime}⏎ End: %{EndDate} at %{EndTime}⏎ Description: %{Description}";
|
||||||
|
|
||||||
|
/* Deletion */
|
||||||
|
"Event Cancelled: \"%{Summary}\"" = "Udalosť zrušená: \"%{Summary}\"";
|
||||||
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||||
|
= "%{Organizer} %{SentByText}zrušil túto udalosť: %{Summary}.⏎ ⏎ Začiatok: %{StartDate}⏎ Koniec: %{EndDate}⏎ Podrobnosti: %{Description}";
|
||||||
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||||
|
= "%{Organizer} %{SentByText}zrušil túto udalosť: %{Summary}.⏎ ⏎\nZačiatok: %{StartDate} o %{StartTime}⏎ Koniec: %{EndDate} o %{EndTime}⏎ \nPopis: %{Description}";
|
||||||
|
|
||||||
|
/* Update */
|
||||||
|
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||||
|
= "Stretnutie \"%{Summary}\" z %{OldStartDate} bolo zmenené";
|
||||||
|
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||||
|
= "Stretnutie \"%{Summary}\" z %{OldStartDate} o %{OldStartTime} bola zmenená";
|
||||||
|
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||||
|
= "Nasledujúce parametre boli zmenené v \"%{Summary}\" stretnutie:";
|
||||||
|
"Please accept or decline those changes."
|
||||||
|
= "Prosím prijmite alebo odmietnite tieto zmeny.";
|
||||||
|
|
||||||
|
/* Reply */
|
||||||
|
"Accepted invitation: \"%{Summary}\"" = "Prijatá pozvánka: \"%{Summary}\"";
|
||||||
|
"Declined invitation: \"%{Summary}\"" = "Zamietnutá pozvánka: \"%{Summary}\"";
|
||||||
|
"Delegated invitation: \"%{Summary}\"" = "Delegovaná pozvánka: \"%{Summary}\"";
|
||||||
|
"Not yet decided on invitation: \"%{Summary}\"" = "Doteraz nerozhodnutá pozvánka: \"%{Summary}\"";
|
||||||
|
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||||
|
= "%{Attendee} %{SentByText}prijal Vašu pozvánku.";
|
||||||
|
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||||
|
= "%{Attendee} %{SentByText}odmietol Vašu pozvánku.";
|
||||||
|
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||||
|
= "%{Attendee} %{SentByText}delegoval pozvánku na %{Delegate}.";
|
||||||
|
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||||
|
= "%{Attendee} %{SentByText}zatiaľ nerozhodol o Vašej pozvánke.";
|
||||||
|
|
||||||
|
/* Resources */
|
||||||
|
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Zdroj nedostupný: \"%{Cn} %{SystemEmail}\"";
|
||||||
|
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maximálny počet súčasných rezervácií (%{NumberOfSimultaneousBookings}) prekročil zdroje \"%{Cn} %{SystemEmail}\". Konfliktná udalosť je \"%{EventTitle}\", začínajúca %{StartDate}.";
|
|
@ -25,13 +25,13 @@ vtodo_class2 = "(Tarea confidencial)";
|
||||||
"comment_label" = "Comentario:";
|
"comment_label" = "Comentario:";
|
||||||
|
|
||||||
/* Invitation */
|
/* Invitation */
|
||||||
"Event Invitation: \"%{Summary}\"" = "Invitación al evento: \"% {Summary}\"";
|
"Event Invitation: \"%{Summary}\"" = "Invitación al evento: \"%{Summary}\"";
|
||||||
"(sent by %{SentBy}) " = "(enviado por %{SentBy}) ";
|
"(sent by %{SentBy}) " = "(enviado por %{SentBy}) ";
|
||||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}le ha invitado a %{Summary}.\n\nInicio: %{StartDate}\nFin: %{EndDate}\nDescripción: %{Description}";
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}le ha invitado a %{Summary}.\n\nInicio: %{StartDate}\nFin: %{EndDate}\nDescripción: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}le ha invitado a %{Summary}.\n\nInicio: %{StartDate} a las %{StartTime}\nFin: %{EndDate} a las %{EndTime}\nDescripción: %{Description}";
|
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}le ha invitado a %{Summary}.\n\nInicio: %{StartDate} a las %{StartTime}\nFin: %{EndDate} a las %{EndTime}\nDescripción: %{Description}";
|
||||||
|
|
||||||
/* Deletion */
|
/* Deletion */
|
||||||
"Event Cancelled: \"%{Summary}\"" = "Evento Cancelado: \"% {Summary}\"";
|
"Event Cancelled: \"%{Summary}\"" = "Evento Cancelado: \"%{Summary}\"";
|
||||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||||
= "%{Organizer} %{SentByText}ha cancelado este evento: %{Summary}.\n\nInicio: %{StartDate}\nFin: %{EndDate}\nDescripción: %{Description}";
|
= "%{Organizer} %{SentByText}ha cancelado este evento: %{Summary}.\n\nInicio: %{StartDate}\nFin: %{EndDate}\nDescripción: %{Description}";
|
||||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||||
|
|
|
@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
|
||||||
Contacts_RESOURCE_FILES += \
|
Contacts_RESOURCE_FILES += \
|
||||||
product.plist \
|
product.plist \
|
||||||
|
|
||||||
Contacts_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
Contacts_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||||
|
|
||||||
Contacts_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
Contacts_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||||
|
|
||||||
|
|
|
@ -216,18 +216,19 @@ convention:
|
||||||
|
|
||||||
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord
|
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord
|
||||||
{
|
{
|
||||||
CardElement *element;
|
|
||||||
NSArray *units;
|
|
||||||
NSInteger year, yearOfToday, month, day;
|
NSInteger year, yearOfToday, month, day;
|
||||||
|
CardElement *element;
|
||||||
NSCalendarDate *now;
|
NSCalendarDate *now;
|
||||||
|
NSArray *units;
|
||||||
NSString *ou;
|
NSString *ou;
|
||||||
|
id o;
|
||||||
|
|
||||||
[self setNWithFamily: [ldifRecord objectForKey: @"sn"]
|
[self setNWithFamily: [ldifRecord objectForKey: @"sn"]
|
||||||
given: [ldifRecord objectForKey: @"givenname"]
|
given: [ldifRecord objectForKey: @"givenname"]
|
||||||
additional: nil prefixes: nil suffixes: nil];
|
additional: nil prefixes: nil suffixes: nil];
|
||||||
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
|
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
|
||||||
[self setFn: [ldifRecord objectForKey: @"displayname"]];
|
[self setFn: [ldifRecord objectForKey: @"displayname"]];
|
||||||
[self setTitle: [ldifRecord objectForKey: @"title"]];
|
[self setTitle: [ldifRecord objectForKey: @"title"]];
|
||||||
|
|
||||||
element = [self _elementWithTag: @"adr" ofType: @"home"];
|
element = [self _elementWithTag: @"adr" ofType: @"home"];
|
||||||
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet2"]
|
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet2"]
|
||||||
|
@ -303,7 +304,15 @@ convention:
|
||||||
forKey: @""];
|
forKey: @""];
|
||||||
|
|
||||||
[self setNote: [ldifRecord objectForKey: @"description"]];
|
[self setNote: [ldifRecord objectForKey: @"description"]];
|
||||||
[self setCategories: [ldifRecord objectForKey: @"vcardcategories"]];
|
|
||||||
|
o = [ldifRecord objectForKey: @"vcardcategories"];
|
||||||
|
|
||||||
|
// We can either have an array (from SOGo's web gui) or a
|
||||||
|
// string (from a LDIF import) as the value here.
|
||||||
|
if ([o isKindOfClass: [NSArray class]])
|
||||||
|
[self setCategories: o];
|
||||||
|
else
|
||||||
|
[self setCategories: [o componentsSeparatedByString: @","]];
|
||||||
|
|
||||||
[self cleanupEmptyChildren];
|
[self cleanupEmptyChildren];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* NSDictionary+LDIF.m - this file is part of SOGo
|
/* NSDictionary+LDIF.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Inverse inc
|
* Copyright (C) 2011-2012 Inverse inc
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
|
|
@ -191,6 +191,10 @@ static NSArray *folderListingFields = nil;
|
||||||
qs = [NSString stringWithFormat:
|
qs = [NSString stringWithFormat:
|
||||||
@"(c_categories isCaseInsensitiveLike: '%%%@%%')",
|
@"(c_categories isCaseInsensitiveLike: '%%%@%%')",
|
||||||
filter];
|
filter];
|
||||||
|
else if ([criteria isEqualToString: @"organization"])
|
||||||
|
qs = [NSString stringWithFormat:
|
||||||
|
@"(c_o isCaseInsensitiveLike: '%%%@%%')",
|
||||||
|
filter];
|
||||||
else
|
else
|
||||||
qs = @"(1 == 0)";
|
qs = @"(1 == 0)";
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* SOGoContactLDIFEntry.m - this file is part of SOGo
|
/* SOGoContactLDIFEntry.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2011 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
* Ludovic Marcotte <lmarcotte@inverse.ca>
|
* Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
"Personal Address Book" = "Osobné kontakty";
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2007-2010 Inverse inc.
|
Copyright (C) 2007-2012 Inverse inc.
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of SOGo.
|
This file is part of SOGo.
|
||||||
|
@ -269,7 +269,7 @@ static NSString *userAgent = nil;
|
||||||
{
|
{
|
||||||
id headerValue;
|
id headerValue;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
NSString *messageID, *priority, *pureSender,*replyTo;
|
NSString *messageID, *priority, *pureSender, *replyTo;
|
||||||
|
|
||||||
for (count = 0; count < 8; count++)
|
for (count = 0; count < 8; count++)
|
||||||
{
|
{
|
||||||
|
@ -314,8 +314,8 @@ static NSString *userAgent = nil;
|
||||||
if ([replyTo length] > 0)
|
if ([replyTo length] > 0)
|
||||||
{
|
{
|
||||||
[headers setObject: replyTo forKey: @"reply-to"];
|
[headers setObject: replyTo forKey: @"reply-to"];
|
||||||
[headers removeObjectForKey: @"replyTo"];
|
|
||||||
}
|
}
|
||||||
|
[headers removeObjectForKey: @"replyTo"];
|
||||||
|
|
||||||
if ([[newHeaders objectForKey: @"receipt"] isEqualToString: @"true"])
|
if ([[newHeaders objectForKey: @"receipt"] isEqualToString: @"true"])
|
||||||
{
|
{
|
||||||
|
@ -804,8 +804,8 @@ static NSString *userAgent = nil;
|
||||||
- (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail
|
- (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail
|
||||||
{
|
{
|
||||||
NSDictionary *info, *attachment;
|
NSDictionary *info, *attachment;
|
||||||
|
NSString *signature, *nl;
|
||||||
SOGoUserDefaults *ud;
|
SOGoUserDefaults *ud;
|
||||||
NSString *signature;
|
|
||||||
|
|
||||||
[sourceMail fetchCoreInfos];
|
[sourceMail fetchCoreInfos];
|
||||||
|
|
||||||
|
@ -831,11 +831,14 @@ static NSString *userAgent = nil;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: use subject for filename?
|
// TODO: use subject for filename?
|
||||||
// error = [newDraft saveAttachment:content withName:@"forward.eml"];
|
// error = [newDraft saveAttachment:content withName:@"forward.eml"];
|
||||||
signature = [[self mailAccountFolder] signature];
|
signature = [[self mailAccountFolder] signature];
|
||||||
if ([signature length])
|
if ([signature length])
|
||||||
[self setText: [NSString stringWithFormat: @"\n-- \n%@", signature]];
|
{
|
||||||
|
nl = (isHTML ? @"<br/>" : @"\n");
|
||||||
|
[self setText: [NSString stringWithFormat: @"%@-- %@%@", nl, nl, signature]];
|
||||||
|
}
|
||||||
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
|
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[sourceMail filenameForForward], @"filename",
|
[sourceMail filenameForForward], @"filename",
|
||||||
@"message/rfc822", @"mimetype",
|
@"message/rfc822", @"mimetype",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* SOGoMailForward.m - this file is part of SOGo
|
/* SOGoMailForward.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007 Inverse inc.
|
* Copyright (C) 2007-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
@ -226,11 +226,15 @@
|
||||||
|
|
||||||
- (NSString *) signature
|
- (NSString *) signature
|
||||||
{
|
{
|
||||||
NSString *signature, *mailSignature;
|
NSString *signature, *mailSignature, *nl;
|
||||||
|
|
||||||
signature = [[sourceMail mailAccountFolder] signature];
|
signature = [[sourceMail mailAccountFolder] signature];
|
||||||
|
|
||||||
if ([signature length])
|
if ([signature length])
|
||||||
mailSignature = [NSString stringWithFormat: @"-- \n%@", signature];
|
{
|
||||||
|
nl = (htmlComposition ? @"<br/>" : @"\n");
|
||||||
|
mailSignature = [NSString stringWithFormat: @"-- %@%@", nl, signature];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
mailSignature = @"";
|
mailSignature = @"";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
-------- Pôvodná správa --------
|
||||||
|
Predmet: <#subject/>
|
||||||
|
Dátum: <#date/>
|
||||||
|
Od: <#from/>
|
||||||
|
<#hasReplyTo>Odpoveď na: <#replyTo/></#hasReplyTo><#hasOrganization>Organizácia: <#organization/></#hasOrganization>Komu: <#to/>
|
||||||
|
<#hasCc>Kópia: <#cc/></#hasCc><#hasNewsGroups>Diskusné skupiny: <#newsgroups/></#hasNewsGroups><#hasReferences>Odkazy: <#references/></#hasReferences>
|
||||||
|
|
||||||
|
<#messageBody/>
|
||||||
|
|
||||||
|
<#signature/>
|
|
@ -0,0 +1,79 @@
|
||||||
|
subject: WOString {
|
||||||
|
value = subject;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
date: WOString {
|
||||||
|
value = date;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
from: WOString {
|
||||||
|
value = from;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
newLine: WOString {
|
||||||
|
value = newLine;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasReplyTo: WOConditional {
|
||||||
|
condition = hasReplyTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyTo: WOString {
|
||||||
|
value = replyTo;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasOrganization: WOConditional {
|
||||||
|
condition = hasOrganization;
|
||||||
|
}
|
||||||
|
|
||||||
|
organization: WOString {
|
||||||
|
value = organization;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
to: WOString {
|
||||||
|
value = to;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCc: WOConditional {
|
||||||
|
condition = hasCc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc: WOString {
|
||||||
|
value = cc;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNewsGroups: WOConditional {
|
||||||
|
condition = hasNewsGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
newsgroups: WOString {
|
||||||
|
value = newsgroups;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasReferences: WOConditional {
|
||||||
|
condition = hasReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
references: WOString {
|
||||||
|
value = references;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBody: WOString {
|
||||||
|
value = messageBody;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature: WOString {
|
||||||
|
value = signature;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<#signaturePlacementOnTop>
|
||||||
|
|
||||||
|
|
||||||
|
<#signature/>
|
||||||
|
</#signaturePlacementOnTop>
|
||||||
|
<#outlookMode>-------- Pôvodná správa --------
|
||||||
|
Predmet: <#subject/>
|
||||||
|
Dátum: <#date/>
|
||||||
|
Od: <#from/>
|
||||||
|
<#hasReplyTo>Odpoveď pre: <#replyTo/></#hasReplyTo><#hasOrganization>Organizácia: <#organization/></#hasOrganization>Komu: <#to/>
|
||||||
|
<#hasCc>Kópia: <#cc/></#hasCc><#hasNewsGroups>Diskusné skupiny: <#newsgroups/></#hasNewsGroups><#hasReferences>Odkazy: <#references/></#hasReferences></#outlookMode>
|
||||||
|
<#standardMode> <#date/>, <#from/> napísal:</#standardMode>
|
||||||
|
|
||||||
|
<#messageBody/>
|
||||||
|
|
||||||
|
|
||||||
|
<#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom>
|
|
@ -0,0 +1,106 @@
|
||||||
|
outlookMode: WOConditional {
|
||||||
|
condition = outlookMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
standardMode: WOConditional {
|
||||||
|
condition = outlookMode;
|
||||||
|
negate = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
subject: WOString {
|
||||||
|
value = subject;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
date: WOString {
|
||||||
|
value = date;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
from: WOString {
|
||||||
|
value = from;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
newLine: WOString {
|
||||||
|
value = newLine;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasReplyTo: WOConditional {
|
||||||
|
condition = hasReplyTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyTo: WOString {
|
||||||
|
value = replyTo;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasOrganization: WOConditional {
|
||||||
|
condition = hasOrganization;
|
||||||
|
}
|
||||||
|
|
||||||
|
organization: WOString {
|
||||||
|
value = organization;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
to: WOString {
|
||||||
|
value = to;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCc: WOConditional {
|
||||||
|
condition = hasCc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc: WOString {
|
||||||
|
value = cc;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNewsGroups: WOConditional {
|
||||||
|
condition = hasNewsGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
newsgroups: WOString {
|
||||||
|
value = newsgroups;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasReferences: WOConditional {
|
||||||
|
condition = hasReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
references: WOString {
|
||||||
|
value = references;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBody: WOString {
|
||||||
|
value = messageBody;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature: WOString {
|
||||||
|
value = signature;
|
||||||
|
escapeHTML = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyPlacementOnTop: WOConditional {
|
||||||
|
condition = replyPlacementOnTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyPlacementOnBottom: WOConditional {
|
||||||
|
condition = replyPlacementOnTop;
|
||||||
|
negate = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
signaturePlacementOnTop: WOConditional {
|
||||||
|
condition = signaturePlacementOnTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
signaturePlacementOnBottom: WOConditional {
|
||||||
|
condition = signaturePlacementOnTop;
|
||||||
|
negate = YES;
|
||||||
|
}
|
|
@ -142,6 +142,16 @@ SOGo_RESOURCE_FILES = \
|
||||||
SOGoDefaults.plist \
|
SOGoDefaults.plist \
|
||||||
DAVReportMap.plist
|
DAVReportMap.plist
|
||||||
|
|
||||||
|
ifeq ($(saml2_config), yes)
|
||||||
|
SOGo_HEADER_FILES += SOGoSAML2Session.h SOGoSAML2Exceptions.h
|
||||||
|
SOGo_OBJC_FILES += SOGoSAML2Session.m SOGoSAML2Exceptions.m
|
||||||
|
SOGo_RESOURCE_FILES += SOGoSAML2Metadata.xml
|
||||||
|
|
||||||
|
SOGoSAML2Exceptions.h SOGoSAML2Exceptions.m: gen-saml2-exceptions.py
|
||||||
|
$(ECHO_CREATING) ./gen-saml2-exceptions.py $(LASSO_CFLAGS) $(END_ECHO)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ldap_config),yes)
|
ifeq ($(ldap_config),yes)
|
||||||
|
|
||||||
LIBRARY_NAME += \
|
LIBRARY_NAME += \
|
||||||
|
|
|
@ -24,7 +24,8 @@ SOGo_LIBRARIES_DEPEND_UPON += \
|
||||||
-lNGStreams -lNGExtensions -lEOControl \
|
-lNGStreams -lNGExtensions -lEOControl \
|
||||||
-lDOM -lSaxObjC \
|
-lDOM -lSaxObjC \
|
||||||
-lNGLdap -lSBJson \
|
-lNGLdap -lSBJson \
|
||||||
-lGDLContentStore -lgnustep-base -lobjc -ldl
|
-lGDLContentStore \
|
||||||
|
$(BASE_LIBS)
|
||||||
|
|
||||||
ifeq ($(HAS_LIBRARY_gnutls),yes)
|
ifeq ($(HAS_LIBRARY_gnutls),yes)
|
||||||
ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1
|
ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1
|
||||||
|
@ -36,6 +37,11 @@ SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAS_LIBRARY_lasso), yes)
|
||||||
|
ADDITIONAL_CPPFLAGS += $(LASSO_CFLAGS)
|
||||||
|
SOGo_LIBRARIES_DEPEND_UPON += $(LASSO_LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(findstring openbsd, $(GNUSTEP_HOST_OS)), openbsd)
|
ifeq ($(findstring openbsd, $(GNUSTEP_HOST_OS)), openbsd)
|
||||||
SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
|
SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
|
||||||
else
|
else
|
||||||
|
|
|
@ -62,8 +62,11 @@
|
||||||
NSString *IDField; // the first part of a user DN
|
NSString *IDField; // the first part of a user DN
|
||||||
NSString *CNField;
|
NSString *CNField;
|
||||||
NSString *UIDField;
|
NSString *UIDField;
|
||||||
NSArray *mailFields, *searchFields;
|
NSArray *mailFields;
|
||||||
NSString *IMAPHostField, *IMAPLoginField;
|
NSArray *searchFields;
|
||||||
|
NSString *IMAPHostField;
|
||||||
|
NSString *IMAPLoginField;
|
||||||
|
NSString *SieveHostField;
|
||||||
NSArray *bindFields;
|
NSArray *bindFields;
|
||||||
|
|
||||||
BOOL listRequiresDot;
|
BOOL listRequiresDot;
|
||||||
|
@ -110,6 +113,7 @@
|
||||||
searchFields: (NSArray *) newSearchFields
|
searchFields: (NSArray *) newSearchFields
|
||||||
IMAPHostField: (NSString *) newIMAPHostField
|
IMAPHostField: (NSString *) newIMAPHostField
|
||||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||||
|
SieveHostField: (NSString *) newSieveHostField
|
||||||
bindFields: (id) newBindFields
|
bindFields: (id) newBindFields
|
||||||
kindField: (NSString *) newKindField
|
kindField: (NSString *) newKindField
|
||||||
andMultipleBookingsField: (NSString *) newMultipleBookingsField;
|
andMultipleBookingsField: (NSString *) newMultipleBookingsField;
|
||||||
|
|
|
@ -107,10 +107,11 @@ static Class NSStringK;
|
||||||
[searchFields retain];
|
[searchFields retain];
|
||||||
IMAPHostField = nil;
|
IMAPHostField = nil;
|
||||||
IMAPLoginField = nil;
|
IMAPLoginField = nil;
|
||||||
|
SieveHostField = nil;
|
||||||
bindFields = nil;
|
bindFields = nil;
|
||||||
_scope = @"sub";
|
_scope = @"sub";
|
||||||
_filter = nil;
|
_filter = nil;
|
||||||
_userPasswordAlgorithm = nil;
|
_userPasswordAlgorithm = nil;
|
||||||
listRequiresDot = YES;
|
listRequiresDot = YES;
|
||||||
|
|
||||||
searchAttributes = nil;
|
searchAttributes = nil;
|
||||||
|
@ -149,6 +150,7 @@ static Class NSStringK;
|
||||||
[searchFields release];
|
[searchFields release];
|
||||||
[IMAPHostField release];
|
[IMAPHostField release];
|
||||||
[IMAPLoginField release];
|
[IMAPLoginField release];
|
||||||
|
[SieveHostField release];
|
||||||
[bindFields release];
|
[bindFields release];
|
||||||
[_filter release];
|
[_filter release];
|
||||||
[_userPasswordAlgorithm release];
|
[_userPasswordAlgorithm release];
|
||||||
|
@ -194,6 +196,7 @@ static Class NSStringK;
|
||||||
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
||||||
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
||||||
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
||||||
|
SieveHostField: [udSource objectForKey: @"SieveHostFieldName"]
|
||||||
bindFields: [udSource objectForKey: @"bindFields"]
|
bindFields: [udSource objectForKey: @"bindFields"]
|
||||||
kindField: [udSource objectForKey: @"KindFieldName"]
|
kindField: [udSource objectForKey: @"KindFieldName"]
|
||||||
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
|
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
|
||||||
|
@ -311,6 +314,7 @@ static Class NSStringK;
|
||||||
searchFields: (NSArray *) newSearchFields
|
searchFields: (NSArray *) newSearchFields
|
||||||
IMAPHostField: (NSString *) newIMAPHostField
|
IMAPHostField: (NSString *) newIMAPHostField
|
||||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||||
|
SieveHostField: (NSString *) newSieveHostField
|
||||||
bindFields: (id) newBindFields
|
bindFields: (id) newBindFields
|
||||||
kindField: (NSString *) newKindField
|
kindField: (NSString *) newKindField
|
||||||
andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
|
@ -326,6 +330,8 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
ASSIGN(IMAPHostField, [newIMAPHostField lowercaseString]);
|
ASSIGN(IMAPHostField, [newIMAPHostField lowercaseString]);
|
||||||
if (newIMAPLoginField)
|
if (newIMAPLoginField)
|
||||||
ASSIGN(IMAPLoginField, [newIMAPLoginField lowercaseString]);
|
ASSIGN(IMAPLoginField, [newIMAPLoginField lowercaseString]);
|
||||||
|
if (newSieveHostField)
|
||||||
|
ASSIGN(SieveHostField, [newSieveHostField lowercaseString]);
|
||||||
if (newMailFields)
|
if (newMailFields)
|
||||||
ASSIGN(mailFields, newMailFields);
|
ASSIGN(mailFields, newMailFields);
|
||||||
if (newSearchFields)
|
if (newSearchFields)
|
||||||
|
@ -586,7 +592,10 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
||||||
|
|
||||||
if (pass == nil)
|
if (pass == nil)
|
||||||
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
{
|
||||||
|
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
||||||
}
|
}
|
||||||
|
@ -629,24 +638,34 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
NGLdapModification *mod;
|
NGLdapModification *mod;
|
||||||
NGLdapAttribute *attr;
|
NGLdapAttribute *attr;
|
||||||
NSArray *changes;
|
NSArray *changes;
|
||||||
|
NSString* encryptedPass;
|
||||||
|
|
||||||
attr = [[NGLdapAttribute alloc] initWithAttributeName: @"userPassword"];
|
attr = [[NGLdapAttribute alloc] initWithAttributeName: @"userPassword"];
|
||||||
if ([_userPasswordAlgorithm isEqualToString: @"none"])
|
if ([_userPasswordAlgorithm isEqualToString: @"none"])
|
||||||
[attr addStringValue: newPassword];
|
{
|
||||||
else
|
encryptedPass = newPassword;
|
||||||
[attr addStringValue: [self _encryptPassword: newPassword]];
|
}
|
||||||
|
else
|
||||||
mod = [NGLdapModification replaceModification: attr];
|
{
|
||||||
changes = [NSArray arrayWithObject: mod];
|
encryptedPass = [self _encryptPassword: newPassword];
|
||||||
*perr = PolicyNoError;
|
}
|
||||||
|
if(encryptedPass != nil)
|
||||||
|
{
|
||||||
|
[attr addStringValue: encryptedPass];
|
||||||
|
mod = [NGLdapModification replaceModification: attr];
|
||||||
|
changes = [NSArray arrayWithObject: mod];
|
||||||
|
*perr = PolicyNoError;
|
||||||
|
|
||||||
if ([bindConnection bindWithMethod: @"simple"
|
if ([bindConnection bindWithMethod: @"simple"
|
||||||
binddn: userDN
|
binddn: userDN
|
||||||
credentials: oldPassword])
|
credentials: oldPassword])
|
||||||
didChange = [bindConnection modifyEntryWithDN: userDN
|
{
|
||||||
changes: changes];
|
didChange = [bindConnection modifyEntryWithDN: userDN
|
||||||
else
|
changes: changes];
|
||||||
didChange = NO;
|
}
|
||||||
|
else
|
||||||
|
didChange = NO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
didChange = [bindConnection changePasswordAtDn: userDN
|
didChange = [bindConnection changePasswordAtDn: userDN
|
||||||
|
@ -835,6 +854,13 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
if ([ldapValue length] > 0)
|
if ([ldapValue length] > 0)
|
||||||
[ldifRecord setObject: ldapValue forKey: @"c_imaplogin"];
|
[ldifRecord setObject: ldapValue forKey: @"c_imaplogin"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SieveHostField)
|
||||||
|
{
|
||||||
|
ldapValue = [[ldapEntry attributeWithName: SieveHostField] stringValueAtIndex: 0];
|
||||||
|
if ([ldapValue length] > 0)
|
||||||
|
[ldifRecord setObject: ldapValue forKey: @"c_sievehostname"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) _fillConstraints: (NGLdapEntry *) ldapEntry
|
- (void) _fillConstraints: (NGLdapEntry *) ldapEntry
|
||||||
|
@ -1596,6 +1622,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||||
searchFields: nil
|
searchFields: nil
|
||||||
IMAPHostField: nil
|
IMAPHostField: nil
|
||||||
IMAPLoginField: nil
|
IMAPLoginField: nil
|
||||||
|
SieveHostField: nil
|
||||||
bindFields: nil
|
bindFields: nil
|
||||||
kindField: nil
|
kindField: nil
|
||||||
andMultipleBookingsField: nil];
|
andMultipleBookingsField: nil];
|
||||||
|
|
|
@ -56,7 +56,7 @@ typedef enum {
|
||||||
- (NSString *) asSHA1String;
|
- (NSString *) asSHA1String;
|
||||||
- (NSString *) asMD5String;
|
- (NSString *) asMD5String;
|
||||||
|
|
||||||
+ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme;
|
+ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,7 @@
|
||||||
{
|
{
|
||||||
NSString *scheme;
|
NSString *scheme;
|
||||||
NSString *pass;
|
NSString *pass;
|
||||||
NSArray *schemeComps;
|
NSArray *encodingAndScheme;
|
||||||
keyEncoding encoding;
|
|
||||||
|
|
||||||
NSRange range;
|
NSRange range;
|
||||||
int selflen, len;
|
int selflen, len;
|
||||||
|
@ -88,32 +87,11 @@
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
scheme = defaultScheme;
|
scheme = defaultScheme;
|
||||||
|
|
||||||
encoding = [NSString getDefaultEncodingForScheme: scheme];
|
encodingAndScheme = [NSString getDefaultEncodingForScheme: scheme];
|
||||||
|
|
||||||
// get the encoding which may be part of the scheme
|
|
||||||
// e.g. ssha.hex forces a hex encoded ssha scheme
|
|
||||||
// possible is "b64" or "hex"
|
|
||||||
schemeComps = [scheme componentsSeparatedByString: @"."];
|
|
||||||
if ([schemeComps count] == 2)
|
|
||||||
{
|
|
||||||
NSString *stringEncoding;
|
|
||||||
// scheme without encoding string is the first item
|
|
||||||
scheme = [schemeComps objectAtIndex: 0];
|
|
||||||
// encoding string is second item
|
|
||||||
stringEncoding = [schemeComps objectAtIndex: 1];
|
|
||||||
if ([stringEncoding caseInsensitiveCompare: @"hex"] == NSOrderedSame)
|
|
||||||
{
|
|
||||||
encoding = encHex;
|
|
||||||
}
|
|
||||||
else if ([stringEncoding caseInsensitiveCompare: @"b64"] == NSOrderedSame ||
|
|
||||||
[stringEncoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
|
|
||||||
{
|
|
||||||
encoding = encBase64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pass = [self substringWithRange: range];
|
pass = [self substringWithRange: range];
|
||||||
return [NSArray arrayWithObjects: scheme, pass, [NSNumber numberWithInt: encoding], nil];
|
// return array with [scheme, password, encoding]
|
||||||
|
return [NSArray arrayWithObjects: [encodingAndScheme objectAtIndex: 1], pass, [encodingAndScheme objectAtIndex: 0], nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -147,7 +125,7 @@
|
||||||
if (encoding == encHex)
|
if (encoding == encHex)
|
||||||
{
|
{
|
||||||
decodedData = [NSData decodeDataFromHexString: pass];
|
decodedData = [NSData decodeDataFromHexString: pass];
|
||||||
|
|
||||||
if(decodedData == nil)
|
if(decodedData == nil)
|
||||||
{
|
{
|
||||||
decodedData = [NSData data];
|
decodedData = [NSData data];
|
||||||
|
@ -208,8 +186,10 @@
|
||||||
*
|
*
|
||||||
* @param passwordScheme The scheme to use
|
* @param passwordScheme The scheme to use
|
||||||
* @param theSalt The binary data of the salt
|
* @param theSalt The binary data of the salt
|
||||||
* @param userEncoding The encoding (plain, hex, base64) to be used
|
* @param userEncoding The encoding (plain, hex, base64) to be used. If set to
|
||||||
* @return If successful, the encrypted and encoded NSString of the format {scheme}pass, or nil if the scheme did not exists or an error occured
|
* encDefault, the encoding will be detected from scheme name.
|
||||||
|
* @return If successful, the encrypted and encoded NSString of the format {scheme}pass,
|
||||||
|
* or nil if the scheme did not exists or an error occured.
|
||||||
*/
|
*/
|
||||||
- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
|
- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
|
||||||
withSalt: (NSData *) theSalt
|
withSalt: (NSData *) theSalt
|
||||||
|
@ -217,6 +197,22 @@
|
||||||
{
|
{
|
||||||
keyEncoding dataEncoding;
|
keyEncoding dataEncoding;
|
||||||
NSData* cryptedData;
|
NSData* cryptedData;
|
||||||
|
|
||||||
|
// use default encoding scheme, when set to default
|
||||||
|
if (userEncoding == encDefault)
|
||||||
|
{
|
||||||
|
// the encoding needs to be detected before crypting,
|
||||||
|
// to get the plain scheme (without encoding identifier)
|
||||||
|
NSArray* encodingAndScheme;
|
||||||
|
encodingAndScheme = [NSString getDefaultEncodingForScheme: passwordScheme];
|
||||||
|
dataEncoding = [[encodingAndScheme objectAtIndex: 0] intValue];
|
||||||
|
passwordScheme = [encodingAndScheme objectAtIndex: 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataEncoding = userEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
// convert NSString to NSData and apply encryption scheme
|
// convert NSString to NSData and apply encryption scheme
|
||||||
cryptedData = [self dataUsingEncoding: NSUTF8StringEncoding];
|
cryptedData = [self dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
cryptedData = [cryptedData asCryptedPassUsingScheme: passwordScheme withSalt: theSalt];
|
cryptedData = [cryptedData asCryptedPassUsingScheme: passwordScheme withSalt: theSalt];
|
||||||
|
@ -224,12 +220,6 @@
|
||||||
if (cryptedData == nil)
|
if (cryptedData == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// use default encoding scheme, when set to default
|
|
||||||
if (userEncoding == encDefault)
|
|
||||||
dataEncoding = [NSString getDefaultEncodingForScheme: passwordScheme];
|
|
||||||
else
|
|
||||||
dataEncoding = userEncoding;
|
|
||||||
|
|
||||||
if (dataEncoding == encHex)
|
if (dataEncoding == encHex)
|
||||||
{
|
{
|
||||||
// hex encoding
|
// hex encoding
|
||||||
|
@ -250,19 +240,49 @@
|
||||||
/**
|
/**
|
||||||
* Returns the encoding for a specified scheme
|
* Returns the encoding for a specified scheme
|
||||||
*
|
*
|
||||||
* @param passwordScheme The scheme for which to get the encoding.
|
* @param passwordScheme The scheme for which to get the encoding. Can be "scheme.encoding" in which case the encoding is returned
|
||||||
* @see keyEncoding
|
* @see keyEncoding
|
||||||
* @return returns the encoding, if unknown returns encPlain
|
* @return returns NSArray with elements {NSNumber encoding, NSString* scheme} where scheme is the 'real' scheme without the ".encoding" part.
|
||||||
|
* 'encoding' is stored as NSNumber in the array. If the encoding was not detected, encPlain is used for encoding.
|
||||||
*/
|
*/
|
||||||
+ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme
|
+ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme
|
||||||
{
|
{
|
||||||
|
NSArray *schemeComps;
|
||||||
|
NSString *trueScheme;
|
||||||
|
keyEncoding encoding = encPlain;
|
||||||
|
|
||||||
|
// get the encoding which may be part of the scheme
|
||||||
|
// e.g. ssha.hex forces a hex encoded ssha scheme
|
||||||
|
// possible is "b64" or "hex"
|
||||||
|
schemeComps = [passwordScheme componentsSeparatedByString: @"."];
|
||||||
|
if ([schemeComps count] == 2)
|
||||||
|
{
|
||||||
|
trueScheme = [schemeComps objectAtIndex: 0];
|
||||||
|
NSString *stringEncoding;
|
||||||
|
// encoding string is second item
|
||||||
|
stringEncoding = [schemeComps objectAtIndex: 1];
|
||||||
|
if ([stringEncoding caseInsensitiveCompare: @"hex"] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
encoding = encHex;
|
||||||
|
}
|
||||||
|
else if ([stringEncoding caseInsensitiveCompare: @"b64"] == NSOrderedSame ||
|
||||||
|
[stringEncoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
encoding = encBase64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trueScheme = passwordScheme;
|
||||||
|
}
|
||||||
|
|
||||||
// in order to keep backwards-compatibility, hex encoding is used for sha1 here
|
// in order to keep backwards-compatibility, hex encoding is used for sha1 here
|
||||||
if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
|
if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
|
||||||
[passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
|
[passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
|
||||||
[passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame ||
|
[passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame ||
|
||||||
[passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
|
[passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
|
||||||
{
|
{
|
||||||
return encHex;
|
encoding = encHex;
|
||||||
}
|
}
|
||||||
else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame ||
|
else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame ||
|
||||||
[passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame ||
|
[passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame ||
|
||||||
|
@ -272,9 +292,9 @@
|
||||||
[passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame ||
|
[passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame ||
|
||||||
[passwordScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame)
|
[passwordScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame)
|
||||||
{
|
{
|
||||||
return encBase64;
|
encoding = encBase64;
|
||||||
}
|
}
|
||||||
return encPlain;
|
return [NSArray arrayWithObjects: [NSNumber numberWithInt: encoding], trueScheme, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -134,15 +134,16 @@ static int cssEscapingCount;
|
||||||
start--;
|
start--;
|
||||||
start++;
|
start++;
|
||||||
|
|
||||||
|
length = [self length];
|
||||||
// In [UIxMailPartTextViewer flatContentAsString], we first escape HTML entities and then
|
// In [UIxMailPartTextViewer flatContentAsString], we first escape HTML entities and then
|
||||||
// add URLs. Therefore, the brackets (inequality signs <>) have been encoded at this point.
|
// add URLs. Therefore, the brackets (inequality signs <>) have been encoded at this point.
|
||||||
if ([[self substringWithRange: NSMakeRange (start, 4)] compare: @"<"] == NSOrderedSame)
|
if (length > (start + 4)
|
||||||
|
&& [[self substringWithRange: NSMakeRange (start, 4)] compare: @"<"] == NSOrderedSame)
|
||||||
start += 4;
|
start += 4;
|
||||||
|
|
||||||
length = [self length] - start;
|
length -= start;
|
||||||
workRange = NSMakeRange (start, length);
|
|
||||||
workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
|
workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
|
||||||
options: NSLiteralSearch range: workRange];
|
options: NSLiteralSearch range: NSMakeRange (start, length)];
|
||||||
if (workRange.location != NSNotFound)
|
if (workRange.location != NSNotFound)
|
||||||
length = workRange.location - start;
|
length = workRange.location - start;
|
||||||
while
|
while
|
||||||
|
|
|
@ -111,6 +111,11 @@
|
||||||
- (void) setCASPGTId: (NSString *) pgtId
|
- (void) setCASPGTId: (NSString *) pgtId
|
||||||
forPGTIOU: (NSString *) pgtIou;
|
forPGTIOU: (NSString *) pgtIou;
|
||||||
|
|
||||||
|
// SAML2 support
|
||||||
|
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
|
||||||
|
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
||||||
|
forIdentifier: (NSString *) identifier;
|
||||||
|
|
||||||
//
|
//
|
||||||
// ACL caching support
|
// ACL caching support
|
||||||
//
|
//
|
||||||
|
|
|
@ -520,6 +520,27 @@ static memcached_st *handle = NULL;
|
||||||
forKey: [NSString stringWithFormat: @"cas-pgtiou:%@", pgtIou]];
|
forKey: [NSString stringWithFormat: @"cas-pgtiou:%@", pgtIou]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAML2 support
|
||||||
|
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier
|
||||||
|
{
|
||||||
|
NSString *key, *jsonString;
|
||||||
|
|
||||||
|
key = [NSString stringWithFormat: @"saml2-login:%@", identifier];
|
||||||
|
jsonString = [self valueForKey: key];
|
||||||
|
|
||||||
|
return [jsonString objectFromJSONString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
||||||
|
forIdentifier: (NSString *) identifier
|
||||||
|
{
|
||||||
|
NSString *key;
|
||||||
|
|
||||||
|
key = [NSString stringWithFormat: @"saml2-login:%@", identifier];
|
||||||
|
|
||||||
|
[self setValue: [dump jsonRepresentation] forKey: key];
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ACL caching code
|
// ACL caching code
|
||||||
//
|
//
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
SOGoSupportedLanguages = ( "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
|
SOGoSupportedLanguages = ( "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
|
||||||
"SpanishSpain", "SpanishArgentina", "French", "German",
|
"SpanishSpain", "SpanishArgentina", "French", "German",
|
||||||
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
||||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian",
|
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",
|
||||||
"Ukrainian", "Swedish" );
|
"Ukrainian", "Swedish" );
|
||||||
|
|
||||||
SOGoTimeZone = "UTC";
|
SOGoTimeZone = "UTC";
|
||||||
|
|
|
@ -205,7 +205,7 @@
|
||||||
mailingMechanism = nil;
|
mailingMechanism = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mailingMechanism;
|
return [mailingMechanism lowercaseString];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *) mailPollingIntervals
|
- (NSArray *) mailPollingIntervals
|
||||||
|
@ -220,7 +220,7 @@
|
||||||
|
|
||||||
- (NSString *) smtpAuthenticationType
|
- (NSString *) smtpAuthenticationType
|
||||||
{
|
{
|
||||||
return [self stringForKey: @"SOGoSMTPAuthenticationType"];
|
return [[self stringForKey: @"SOGoSMTPAuthenticationType"] lowercaseString];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) mailSpoolPath
|
- (NSString *) mailSpoolPath
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* SOGoGCSFolder.m - this file is part of SOGo
|
/* SOGoGCSFolder.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004-2005 SKYRIX Software AG
|
* Copyright (C) 2004-2005 SKYRIX Software AG
|
||||||
* Copyright (C) 2006-2010 Inverse inc.
|
* Copyright (C) 2006-2012 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
@ -835,7 +835,7 @@ static NSArray *childRecordFields = nil;
|
||||||
- (BOOL) subscribeUserOrGroup: (NSString *) theIdentifier
|
- (BOOL) subscribeUserOrGroup: (NSString *) theIdentifier
|
||||||
reallyDo: (BOOL) reallyDo
|
reallyDo: (BOOL) reallyDo
|
||||||
{
|
{
|
||||||
NSMutableDictionary *moduleSettings;
|
NSMutableDictionary *moduleSettings, *folderShowAlarms;
|
||||||
NSMutableArray *folderSubscription;
|
NSMutableArray *folderSubscription;
|
||||||
NSString *subscriptionPointer;
|
NSString *subscriptionPointer;
|
||||||
NSMutableArray *allUsers;
|
NSMutableArray *allUsers;
|
||||||
|
@ -886,6 +886,8 @@ static NSArray *childRecordFields = nil;
|
||||||
folderSubscription
|
folderSubscription
|
||||||
= [moduleSettings objectForKey: @"SubscribedFolders"];
|
= [moduleSettings objectForKey: @"SubscribedFolders"];
|
||||||
subscriptionPointer = [self folderReference];
|
subscriptionPointer = [self folderReference];
|
||||||
|
|
||||||
|
folderShowAlarms = [moduleSettings objectForKey: @"FolderShowAlarms"];
|
||||||
|
|
||||||
if (reallyDo)
|
if (reallyDo)
|
||||||
{
|
{
|
||||||
|
@ -897,14 +899,26 @@ static NSArray *childRecordFields = nil;
|
||||||
forKey: @"SubscribedFolders"];
|
forKey: @"SubscribedFolders"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(folderShowAlarms
|
||||||
|
&& [folderShowAlarms isKindOfClass: [NSMutableDictionary class]]))
|
||||||
|
{
|
||||||
|
folderShowAlarms = [NSMutableDictionary dictionary];
|
||||||
|
[moduleSettings setObject: folderShowAlarms
|
||||||
|
forKey: @"FolderShowAlarms"];
|
||||||
|
}
|
||||||
|
|
||||||
[folderSubscription addObjectUniquely: subscriptionPointer];
|
[folderSubscription addObjectUniquely: subscriptionPointer];
|
||||||
|
|
||||||
|
// By default, we disable alarms on subscribed calendars
|
||||||
|
[folderShowAlarms setObject: [NSNumber numberWithBool: NO]
|
||||||
|
forKey: subscriptionPointer];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[self removeFolderSettings: moduleSettings
|
[self removeFolderSettings: moduleSettings
|
||||||
withReference: subscriptionPointer];
|
withReference: subscriptionPointer];
|
||||||
[folderSubscription removeObject: subscriptionPointer];
|
[folderSubscription removeObject: subscriptionPointer];
|
||||||
|
[folderShowAlarms removeObjectForKey: subscriptionPointer];
|
||||||
}
|
}
|
||||||
|
|
||||||
[us synchronize];
|
[us synchronize];
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
#import <NGLdap/NGLdapAttribute.h>
|
#import <NGLdap/NGLdapAttribute.h>
|
||||||
#import <NGLdap/NGLdapEntry.h>
|
#import <NGLdap/NGLdapEntry.h>
|
||||||
|
|
||||||
|
#define CHECK_CLASS(o) ({ \
|
||||||
|
if ([o isKindOfClass: [NSString class]]) \
|
||||||
|
o = [NSArray arrayWithObject: o]; \
|
||||||
|
})
|
||||||
|
|
||||||
@implementation SOGoGroup
|
@implementation SOGoGroup
|
||||||
|
|
||||||
- (id) initWithIdentifier: (NSString *) theID
|
- (id) initWithIdentifier: (NSString *) theID
|
||||||
|
@ -232,14 +237,17 @@
|
||||||
// Fetch "members" - we get DNs
|
// Fetch "members" - we get DNs
|
||||||
d = [_entry asDictionary];
|
d = [_entry asDictionary];
|
||||||
o = [d objectForKey: @"member"];
|
o = [d objectForKey: @"member"];
|
||||||
|
CHECK_CLASS(o);
|
||||||
if (o) [dns addObjectsFromArray: o];
|
if (o) [dns addObjectsFromArray: o];
|
||||||
|
|
||||||
// Fetch "uniqueMembers" - we get DNs
|
// Fetch "uniqueMembers" - we get DNs
|
||||||
o = [d objectForKey: @"uniquemember"];
|
o = [d objectForKey: @"uniquemember"];
|
||||||
|
CHECK_CLASS(o);
|
||||||
if (o) [dns addObjectsFromArray: o];
|
if (o) [dns addObjectsFromArray: o];
|
||||||
|
|
||||||
// Fetch "memberUid" - we get UID (like login names)
|
// Fetch "memberUid" - we get UID (like login names)
|
||||||
o = [d objectForKey: @"memberuid"];
|
o = [d objectForKey: @"memberuid"];
|
||||||
|
CHECK_CLASS(o);
|
||||||
if (o) [uids addObjectsFromArray: o];
|
if (o) [uids addObjectsFromArray: o];
|
||||||
|
|
||||||
c = [dns count] + [uids count];
|
c = [dns count] + [uids count];
|
||||||
|
|
|
@ -1236,7 +1236,7 @@
|
||||||
- (SOGoWebDAVValue *) davCurrentUserPrincipal
|
- (SOGoWebDAVValue *) davCurrentUserPrincipal
|
||||||
{
|
{
|
||||||
NSDictionary *userHREF;
|
NSDictionary *userHREF;
|
||||||
NSString *login;
|
NSString *login, *s;
|
||||||
SOGoUser *activeUser;
|
SOGoUser *activeUser;
|
||||||
SOGoWebDAVValue *davCurrentUserPrincipal;
|
SOGoWebDAVValue *davCurrentUserPrincipal;
|
||||||
|
|
||||||
|
@ -1246,7 +1246,8 @@
|
||||||
davCurrentUserPrincipal = nil;
|
davCurrentUserPrincipal = nil;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, [self davURLAsString]);
|
s = [NSString stringWithFormat: @"/SOGo/dav/%@", login];
|
||||||
|
userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, s);
|
||||||
davCurrentUserPrincipal
|
davCurrentUserPrincipal
|
||||||
= [davElementWithContent (@"current-user-principal",
|
= [davElementWithContent (@"current-user-principal",
|
||||||
XMLNS_WEBDAV,
|
XMLNS_WEBDAV,
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* SOGoSAML2Session.h - this file is part of SOGo
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Inverse inc.
|
||||||
|
*
|
||||||
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOGOSAML2SESSION_H
|
||||||
|
#define SOGOSAML2SESSION_H
|
||||||
|
|
||||||
|
/* implementation of the SAML2 protocol as required for a client:
|
||||||
|
https://www.oasis-open.org/standards#samlv2.0 */
|
||||||
|
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
|
||||||
|
#include <lasso/lasso.h>
|
||||||
|
|
||||||
|
@class NSString;
|
||||||
|
|
||||||
|
@interface SOGoSAML2Session : NSObject
|
||||||
|
{
|
||||||
|
LassoLogin *lassoLogin;
|
||||||
|
|
||||||
|
NSString *login;
|
||||||
|
NSString *identifier;
|
||||||
|
NSString *assertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *) metadataInContext: (WOContext *) context;
|
||||||
|
+ (NSString *) authenticationURLInContext: (WOContext *) context;
|
||||||
|
|
||||||
|
+ (SOGoSAML2Session *) SAML2SessionInContext: (WOContext *) context;
|
||||||
|
|
||||||
|
+ (SOGoSAML2Session *) SAML2SessionWithIdentifier: (NSString *) newIdentifier
|
||||||
|
inContext: (WOContext *) context;
|
||||||
|
|
||||||
|
- (void) processAuthnResponse: (NSString *) authnResponse;
|
||||||
|
|
||||||
|
- (NSString *) login;
|
||||||
|
- (NSString *) identifier;
|
||||||
|
- (NSString *) assertion;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif /* SOGOSAML2SESSION_H */
|
|
@ -0,0 +1,424 @@
|
||||||
|
/* SOGoSAML2Session.m - this file is part of SOGo
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Inverse inc.
|
||||||
|
*
|
||||||
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <lasso/lasso.h>
|
||||||
|
#include <lasso/xml/misc_text_node.h>
|
||||||
|
#include <lasso/xml/saml-2.0/saml2_attribute.h>
|
||||||
|
#include <lasso/xml/saml-2.0/saml2_attribute_statement.h>
|
||||||
|
#include <lasso/xml/saml-2.0/saml2_attribute_value.h>
|
||||||
|
#include <lasso/xml/saml-2.0/samlp2_authn_request.h>
|
||||||
|
#include <lasso/xml/saml-2.0/samlp2_response.h>
|
||||||
|
|
||||||
|
#import <Foundation/NSBundle.h>
|
||||||
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <Foundation/NSException.h>
|
||||||
|
#import <Foundation/NSMapTable.h>
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSURL.h>
|
||||||
|
|
||||||
|
#import <NGObjWeb/WOApplication.h>
|
||||||
|
#import <NGObjWeb/WORequest.h>
|
||||||
|
#import <NGObjWeb/WOContext.h>
|
||||||
|
#import <NGObjWeb/WOResponse.h>
|
||||||
|
|
||||||
|
#import "SOGoCache.h"
|
||||||
|
#import "SOGoSAML2Exceptions.h"
|
||||||
|
#import "SOGoSystemDefaults.h"
|
||||||
|
|
||||||
|
#import "SOGoSAML2Session.h"
|
||||||
|
|
||||||
|
@interface WOContext (SOGoSAML2Extension)
|
||||||
|
|
||||||
|
- (NSString *) SAML2ServerURLString;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation WOContext (SOGoSAML2Extension)
|
||||||
|
|
||||||
|
- (NSString *) SAML2ServerURLString
|
||||||
|
{
|
||||||
|
NSString *appName;
|
||||||
|
NSURL *serverURL;
|
||||||
|
|
||||||
|
appName = [[WOApplication application] name];
|
||||||
|
serverURL = [NSURL URLWithString: [NSString stringWithFormat: @"/%@",
|
||||||
|
appName]
|
||||||
|
relativeToURL: [self serverURL]];
|
||||||
|
|
||||||
|
return [serverURL absoluteString];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SOGoSAML2Session
|
||||||
|
|
||||||
|
static NSMapTable *serverTable = nil;
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if (!serverTable)
|
||||||
|
{
|
||||||
|
serverTable = [NSMapTable mapTableWithStrongToWeakObjects];
|
||||||
|
[serverTable retain];
|
||||||
|
}
|
||||||
|
lasso_init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LassoServer *
|
||||||
|
LassoServerInContext (WOContext *context)
|
||||||
|
{
|
||||||
|
NSString *urlString, *metadata, *filename, *keyContent, *certContent,
|
||||||
|
*idpKeyFilename, *idpCertFilename;
|
||||||
|
LassoServer *server;
|
||||||
|
SOGoSystemDefaults *sd;
|
||||||
|
|
||||||
|
urlString = [context SAML2ServerURLString];
|
||||||
|
server = NSMapGet (serverTable, urlString);
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||||
|
|
||||||
|
filename = [sd SAML2PrivateKeyLocation];
|
||||||
|
if (!filename)
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"'SAML2PrivateKeyLocation' not set"];
|
||||||
|
keyContent = [NSString stringWithContentsOfFile: filename];
|
||||||
|
if (!keyContent)
|
||||||
|
[NSException raise: NSGenericException
|
||||||
|
format: @"private key file '%@' could not be read",
|
||||||
|
filename];
|
||||||
|
|
||||||
|
filename = [sd SAML2CertificateLocation];
|
||||||
|
if (!filename)
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"'SAML2CertificateLocation' not set"];
|
||||||
|
certContent = [NSString stringWithContentsOfFile: filename];
|
||||||
|
if (!certContent)
|
||||||
|
[NSException raise: NSGenericException
|
||||||
|
format: @"certificate file '%@' could not be read",
|
||||||
|
filename];
|
||||||
|
|
||||||
|
metadata = [SOGoSAML2Session metadataInContext: context];
|
||||||
|
/* FIXME: enable key password in config ? */
|
||||||
|
server = lasso_server_new_from_buffers ([metadata UTF8String],
|
||||||
|
[keyContent UTF8String],
|
||||||
|
NULL,
|
||||||
|
[certContent UTF8String]);
|
||||||
|
|
||||||
|
filename = [sd SAML2IdpMetadataLocation];
|
||||||
|
idpKeyFilename = [sd SAML2IdpPublicKeyLocation];
|
||||||
|
idpCertFilename = [sd SAML2IdpCertificateLocation];
|
||||||
|
lasso_server_add_provider (server, LASSO_PROVIDER_ROLE_IDP,
|
||||||
|
[filename UTF8String],
|
||||||
|
[idpKeyFilename UTF8String],
|
||||||
|
[idpCertFilename UTF8String]);
|
||||||
|
NSMapInsert (serverTable, urlString, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *) authenticationURLInContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
lasso_error_t rc;
|
||||||
|
LassoServer *server;
|
||||||
|
LassoLogin *tempLogin;
|
||||||
|
LassoSamlp2AuthnRequest *request;
|
||||||
|
NSString *url;
|
||||||
|
GList *providers;
|
||||||
|
|
||||||
|
server = LassoServerInContext (context);
|
||||||
|
tempLogin = lasso_login_new (server);
|
||||||
|
|
||||||
|
providers = g_hash_table_get_keys (server->providers);
|
||||||
|
rc = lasso_login_init_authn_request (tempLogin, providers->data, LASSO_HTTP_METHOD_REDIRECT);
|
||||||
|
if (rc)
|
||||||
|
[NSException raiseSAML2Exception: rc];
|
||||||
|
|
||||||
|
request = LASSO_SAMLP2_AUTHN_REQUEST (LASSO_PROFILE (tempLogin)->request);
|
||||||
|
if (request->NameIDPolicy->Format) {
|
||||||
|
g_free (request->NameIDPolicy->Format);
|
||||||
|
}
|
||||||
|
request->NameIDPolicy->Format = g_strdup(LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT);
|
||||||
|
request->NameIDPolicy->AllowCreate = 1;
|
||||||
|
request->ForceAuthn = TRUE;
|
||||||
|
request->IsPassive = FALSE;
|
||||||
|
if (request->ProtocolBinding) {
|
||||||
|
g_free (request->ProtocolBinding);
|
||||||
|
}
|
||||||
|
// request->NameIDPolicy = strdup (LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED);
|
||||||
|
// request->consent = strdup (LASSO_LIB_CONSENT_OBTAINED);
|
||||||
|
rc = lasso_login_build_authn_request_msg (tempLogin);
|
||||||
|
if (rc)
|
||||||
|
[NSException raiseSAML2Exception: rc];
|
||||||
|
|
||||||
|
url = [NSString stringWithUTF8String: LASSO_PROFILE (tempLogin)->msg_url];
|
||||||
|
|
||||||
|
g_object_unref (tempLogin);
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *) metadataInContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
NSString *metadata, *serverURLString, *filename;
|
||||||
|
NSBundle *bundle;
|
||||||
|
|
||||||
|
bundle = [NSBundle bundleForClass: self];
|
||||||
|
filename = [bundle pathForResource: @"SOGoSAML2Metadata" ofType: @"xml"];
|
||||||
|
if (filename)
|
||||||
|
{
|
||||||
|
serverURLString = [context SAML2ServerURLString];
|
||||||
|
metadata = [[NSString stringWithContentsOfFile: filename]
|
||||||
|
stringByReplacingString: @"%{base_url}"
|
||||||
|
withString: serverURLString];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
metadata = nil;
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
lassoLogin = NULL;
|
||||||
|
login = nil;
|
||||||
|
identifier = nil;
|
||||||
|
assertion = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) _updateDataFromLogin
|
||||||
|
{
|
||||||
|
// LassoSamlp2Response *response;
|
||||||
|
LassoSaml2Assertion *saml2Assertion;
|
||||||
|
GList *statementList, *attributeList;
|
||||||
|
LassoSaml2AttributeStatement *statement;
|
||||||
|
LassoSaml2Attribute *attribute;
|
||||||
|
LassoSaml2AttributeValue *value;
|
||||||
|
LassoMiscTextNode *textNode;
|
||||||
|
LassoSaml2NameID *nameIdentifier;
|
||||||
|
gchar *dump;
|
||||||
|
|
||||||
|
saml2Assertion
|
||||||
|
= LASSO_SAML2_ASSERTION (lasso_login_get_assertion (lassoLogin));
|
||||||
|
if (saml2Assertion)
|
||||||
|
{
|
||||||
|
/* deduce user login */
|
||||||
|
[login release];
|
||||||
|
login = nil;
|
||||||
|
|
||||||
|
statementList = saml2Assertion->AttributeStatement;
|
||||||
|
while (!login && statementList)
|
||||||
|
{
|
||||||
|
statement = LASSO_SAML2_ATTRIBUTE_STATEMENT (statementList->data);
|
||||||
|
attributeList = statement->Attribute;
|
||||||
|
while (!login && attributeList)
|
||||||
|
{
|
||||||
|
attribute = LASSO_SAML2_ATTRIBUTE (attributeList->data);
|
||||||
|
if (strcmp (attribute->Name, "uid") == 0)
|
||||||
|
{
|
||||||
|
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||||
|
textNode = value->any->data;
|
||||||
|
login = [NSString stringWithUTF8String: textNode->content];
|
||||||
|
[login retain];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
attributeList = attributeList->next;
|
||||||
|
}
|
||||||
|
statementList = statementList->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* serialize assertion */
|
||||||
|
[assertion release];
|
||||||
|
dump = lasso_node_export_to_xml (LASSO_NODE (saml2Assertion));
|
||||||
|
if (dump)
|
||||||
|
{
|
||||||
|
assertion = [NSString stringWithUTF8String: dump];
|
||||||
|
[assertion retain];
|
||||||
|
g_free (dump);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assertion = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameIdentifier
|
||||||
|
= LASSO_SAML2_NAME_ID (LASSO_PROFILE (lassoLogin)->nameIdentifier);
|
||||||
|
if (nameIdentifier)
|
||||||
|
{
|
||||||
|
/* deduce session id */
|
||||||
|
[identifier release];
|
||||||
|
identifier = [NSString stringWithUTF8String: nameIdentifier->content];
|
||||||
|
[identifier retain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) _initWithDump: (NSDictionary *) saml2Dump
|
||||||
|
inContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
// lasso_error_t rc;
|
||||||
|
LassoServer *server;
|
||||||
|
LassoProfile *profile;
|
||||||
|
const gchar *dump;
|
||||||
|
|
||||||
|
if ((self = [self init]))
|
||||||
|
{
|
||||||
|
server = LassoServerInContext (context);
|
||||||
|
lassoLogin = lasso_login_new (server);
|
||||||
|
if (saml2Dump)
|
||||||
|
{
|
||||||
|
profile = LASSO_PROFILE (lassoLogin);
|
||||||
|
ASSIGN (login, [saml2Dump objectForKey: @"login"]);
|
||||||
|
ASSIGN (identifier, [saml2Dump objectForKey: @"identifier"]);
|
||||||
|
ASSIGN (assertion, [saml2Dump objectForKey: @"assertion"]);
|
||||||
|
dump = [[saml2Dump objectForKey: @"identity"] UTF8String];
|
||||||
|
if (dump)
|
||||||
|
lasso_profile_set_identity_from_dump (profile, dump);
|
||||||
|
dump = [[saml2Dump objectForKey: @"session"] UTF8String];
|
||||||
|
if (dump)
|
||||||
|
lasso_profile_set_session_from_dump (profile, dump);
|
||||||
|
lasso_login_accept_sso (lassoLogin);
|
||||||
|
// if (rc)
|
||||||
|
// [NSException raiseSAML2Exception: rc];
|
||||||
|
[self _updateDataFromLogin];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
if (lassoLogin)
|
||||||
|
g_object_unref (lassoLogin);
|
||||||
|
[login release];
|
||||||
|
[identifier release];
|
||||||
|
[assertion release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SOGoSAML2Session *) _SAML2SessionWithDump: (NSDictionary *) saml2Dump
|
||||||
|
inContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
SOGoSAML2Session *newSession;
|
||||||
|
|
||||||
|
newSession = [[self alloc] _initWithDump: saml2Dump inContext: context];
|
||||||
|
[newSession autorelease];
|
||||||
|
|
||||||
|
return newSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SOGoSAML2Session *) SAML2SessionInContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
return [self _SAML2SessionWithDump: nil inContext: context];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SOGoSAML2Session *) SAML2SessionWithIdentifier: (NSString *) identifier
|
||||||
|
inContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
SOGoSAML2Session *session = nil;
|
||||||
|
NSDictionary *saml2Dump;
|
||||||
|
|
||||||
|
if (identifier)
|
||||||
|
{
|
||||||
|
saml2Dump = [[SOGoCache sharedCache]
|
||||||
|
saml2LoginDumpsForIdentifier: identifier];
|
||||||
|
if (saml2Dump)
|
||||||
|
session = [self _SAML2SessionWithDump: saml2Dump
|
||||||
|
inContext: context];
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) login
|
||||||
|
{
|
||||||
|
return login;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) identifier
|
||||||
|
{
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) assertion
|
||||||
|
{
|
||||||
|
return assertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) processAuthnResponse: (NSString *) authnResponse
|
||||||
|
{
|
||||||
|
lasso_error_t rc;
|
||||||
|
gchar *responseData, *dump;
|
||||||
|
LassoProfile *profile;
|
||||||
|
LassoIdentity *identity;
|
||||||
|
LassoSession *session;
|
||||||
|
NSString *nsDump;
|
||||||
|
NSMutableDictionary *saml2Dump;
|
||||||
|
|
||||||
|
responseData = strdup ([authnResponse UTF8String]);
|
||||||
|
|
||||||
|
rc = lasso_login_process_authn_response_msg (lassoLogin, responseData);
|
||||||
|
if (rc)
|
||||||
|
[NSException raiseSAML2Exception: rc];
|
||||||
|
|
||||||
|
rc = lasso_login_accept_sso (lassoLogin);
|
||||||
|
if (rc)
|
||||||
|
[NSException raiseSAML2Exception: rc];
|
||||||
|
|
||||||
|
[self _updateDataFromLogin];
|
||||||
|
|
||||||
|
saml2Dump = [NSMutableDictionary dictionary];
|
||||||
|
[saml2Dump setObject: login forKey: @"login"];
|
||||||
|
[saml2Dump setObject: identifier forKey: @"identifier"];
|
||||||
|
[saml2Dump setObject: assertion forKey: @"assertion"];
|
||||||
|
|
||||||
|
profile = LASSO_PROFILE (lassoLogin);
|
||||||
|
|
||||||
|
session = lasso_profile_get_session (profile);
|
||||||
|
if (session)
|
||||||
|
{
|
||||||
|
dump = lasso_session_dump (session);
|
||||||
|
nsDump = [NSString stringWithUTF8String: dump];
|
||||||
|
[saml2Dump setObject: nsDump forKey: @"session"];
|
||||||
|
lasso_session_destroy (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
identity = lasso_profile_get_identity (profile);
|
||||||
|
if (identity)
|
||||||
|
{
|
||||||
|
dump = lasso_identity_dump (identity);
|
||||||
|
nsDump = [NSString stringWithUTF8String: dump];
|
||||||
|
[saml2Dump setObject: nsDump forKey: @"identity"];
|
||||||
|
lasso_identity_destroy (identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[SOGoCache sharedCache] setSaml2LoginDumps: saml2Dump
|
||||||
|
forIdentifier: identifier];
|
||||||
|
free (responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -43,6 +43,7 @@
|
||||||
login: (NSString **) theLogin
|
login: (NSString **) theLogin
|
||||||
domain: (NSString **) theDomain
|
domain: (NSString **) theDomain
|
||||||
password: (NSString **) thePassword;
|
password: (NSString **) thePassword;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include "SOGoCache.h"
|
#include "SOGoCache.h"
|
||||||
|
|
||||||
|
#import <NGObjWeb/WOCookie.h>
|
||||||
|
|
||||||
#import <Foundation/NSArray.h>
|
#import <Foundation/NSArray.h>
|
||||||
#import <Foundation/NSCalendarDate.h>
|
#import <Foundation/NSCalendarDate.h>
|
||||||
#import <Foundation/NSData.h>
|
#import <Foundation/NSData.h>
|
||||||
|
|
|
@ -51,7 +51,7 @@ static NSMutableDictionary *fieldTypes = nil;
|
||||||
static NSDictionary *sieveFields = nil;
|
static NSDictionary *sieveFields = nil;
|
||||||
static NSDictionary *sieveFlags = nil;
|
static NSDictionary *sieveFlags = nil;
|
||||||
static NSDictionary *operatorRequirements = nil;
|
static NSDictionary *operatorRequirements = nil;
|
||||||
static NSDictionary *methodRequirements = nil;
|
static NSMutableDictionary *methodRequirements = nil;
|
||||||
static NSString *sieveScriptName = @"sogo";
|
static NSString *sieveScriptName = @"sogo";
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,16 +188,16 @@ static NSString *sieveScriptName = @"sogo";
|
||||||
if (!methodRequirements)
|
if (!methodRequirements)
|
||||||
{
|
{
|
||||||
methodRequirements
|
methodRequirements
|
||||||
= [NSDictionary dictionaryWithObjectsAndKeys:
|
= [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||||
@"imapflags", @"addflag",
|
@"imapflags", @"addflag",
|
||||||
@"imapflags", @"removeflag",
|
@"imapflags", @"removeflag",
|
||||||
@"imapflags", @"flag",
|
@"imapflags", @"flag",
|
||||||
@"vacation", @"vacation",
|
@"vacation", @"vacation",
|
||||||
@"notify", @"notify",
|
@"notify", @"notify",
|
||||||
@"fileinto", @"fileinto",
|
@"fileinto", @"fileinto",
|
||||||
@"reject", @"reject",
|
@"reject", @"reject",
|
||||||
@"regex", @"regex",
|
@"regex", @"regex",
|
||||||
nil];
|
nil];
|
||||||
[methodRequirements retain];
|
[methodRequirements retain];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -615,8 +615,8 @@ static NSString *sieveScriptName = @"sogo";
|
||||||
SOGoUserDefaults *ud;
|
SOGoUserDefaults *ud;
|
||||||
SOGoDomainDefaults *dd;
|
SOGoDomainDefaults *dd;
|
||||||
NGSieveClient *client;
|
NGSieveClient *client;
|
||||||
NSString *filterScript, *v, *sieveServer;
|
NSString *filterScript, *v, *sieveServer, *sieveScheme, *sieveQuery, *imapServer;
|
||||||
NSURL *url;
|
NSURL *url, *cUrl;
|
||||||
|
|
||||||
int sievePort;
|
int sievePort;
|
||||||
BOOL b, connected;
|
BOOL b, connected;
|
||||||
|
@ -631,6 +631,115 @@ static NSString *sieveScriptName = @"sogo";
|
||||||
connected = YES;
|
connected = YES;
|
||||||
b = NO;
|
b = NO;
|
||||||
|
|
||||||
|
|
||||||
|
// We connect to our Sieve server and check capabilities, in order
|
||||||
|
// to generate the right script, based on capabilities
|
||||||
|
//
|
||||||
|
// sieveServer might have the following format:
|
||||||
|
//
|
||||||
|
// sieve://localhost
|
||||||
|
// sieve://localhost:2000
|
||||||
|
// sieve://localhost:2000/?tls=YES
|
||||||
|
//
|
||||||
|
// Values such as "localhost" or "localhost:2000" are NOT supported.
|
||||||
|
//
|
||||||
|
// We first try to get the user's preferred Sieve server
|
||||||
|
sieveServer = [[[user mailAccounts] objectAtIndex: 0] objectForKey: @"sieveServerName"];
|
||||||
|
imapServer = [[[user mailAccounts] objectAtIndex: 0] objectForKey: @"serverName"];
|
||||||
|
|
||||||
|
cUrl = [NSURL URLWithString: (sieveServer ? sieveServer : @"")];
|
||||||
|
|
||||||
|
if ([dd sieveServer] && [[dd sieveServer] length] > 0)
|
||||||
|
url = [NSURL URLWithString: [dd sieveServer]];
|
||||||
|
else
|
||||||
|
url = [NSURL URLWithString: @"localhost"];
|
||||||
|
|
||||||
|
if ([cUrl host])
|
||||||
|
sieveServer = [cUrl host];
|
||||||
|
if (!sieveServer && [url host])
|
||||||
|
sieveServer = [url host];
|
||||||
|
if (!sieveServer && [dd sieveServer])
|
||||||
|
sieveServer = [dd sieveServer];
|
||||||
|
if (!sieveServer && imapServer)
|
||||||
|
sieveServer = [[NSURL URLWithString: imapServer] host];
|
||||||
|
if (!sieveServer)
|
||||||
|
sieveServer = @"localhost";
|
||||||
|
|
||||||
|
sieveScheme = [cUrl scheme] ? [cUrl scheme] : [url scheme];
|
||||||
|
if (!sieveScheme)
|
||||||
|
sieveScheme = @"sieve";
|
||||||
|
|
||||||
|
if ([cUrl port])
|
||||||
|
sievePort = [[cUrl port] intValue];
|
||||||
|
else
|
||||||
|
if ([url port])
|
||||||
|
sievePort = [[url port] intValue];
|
||||||
|
else
|
||||||
|
sievePort = 2000;
|
||||||
|
|
||||||
|
sieveQuery = [cUrl query] ? [cUrl query] : [url query];
|
||||||
|
if (sieveQuery)
|
||||||
|
sieveQuery = [NSString stringWithFormat: @"/?%@", sieveQuery];
|
||||||
|
else
|
||||||
|
sieveQuery = @"";
|
||||||
|
|
||||||
|
url = [NSURL URLWithString: [NSString stringWithFormat: @"%@://%@:%d%@",
|
||||||
|
sieveScheme, sieveServer, sievePort, sieveQuery]];
|
||||||
|
|
||||||
|
client = [[NGSieveClient alloc] initWithURL: url];
|
||||||
|
|
||||||
|
if (!client) {
|
||||||
|
NSLog(@"Sieve connection failed on %@", [url description]);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thePassword) {
|
||||||
|
[client closeConnection];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
result = [client login: theLogin authname: theAuthName password: thePassword];
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
connected = NO;
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
|
||||||
|
if (!connected)
|
||||||
|
{
|
||||||
|
NSLog(@"Sieve connection failed on %@", [url description]);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![[result valueForKey:@"result"] boolValue]) {
|
||||||
|
NSLog(@"failure. Attempting with a renewed password (no authname supported)");
|
||||||
|
thePassword = [theAccount imap4PasswordRenewed: YES];
|
||||||
|
result = [client login: theLogin password: thePassword];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![[result valueForKey:@"result"] boolValue]) {
|
||||||
|
NSLog(@"Could not login '%@' on Sieve server: %@: %@",
|
||||||
|
theLogin, client, result);
|
||||||
|
[client closeConnection];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We adjust the "methodRequirements" based on the server's
|
||||||
|
// capabilities. Cyrus exposes "imapflags" while Dovecot (and
|
||||||
|
// potentially others) expose "imap4flags" as specified in RFC5332
|
||||||
|
if ([client hasCapability: @"imap4flags"])
|
||||||
|
{
|
||||||
|
[methodRequirements setObject: @"imap4flags" forKey: @"addflag"];
|
||||||
|
[methodRequirements setObject: @"imap4flags" forKey: @"removeflag"];
|
||||||
|
[methodRequirements setObject: @"imap4flags" forKey: @"flag"];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now let's generate the script
|
||||||
|
//
|
||||||
script = [NSMutableString string];
|
script = [NSMutableString string];
|
||||||
|
|
||||||
// We first handle filters
|
// We first handle filters
|
||||||
|
@ -646,6 +755,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"Sieve generation failure: %@", [self lastScriptError]);
|
NSLog(@"Sieve generation failure: %@", [self lastScriptError]);
|
||||||
|
[client closeConnection];
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,87 +836,6 @@ static NSString *sieveScriptName = @"sogo";
|
||||||
[script insertString: header atIndex: 0];
|
[script insertString: header atIndex: 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We connect to our Sieve server and upload the script.
|
|
||||||
//
|
|
||||||
// sieveServer might have the following format:
|
|
||||||
//
|
|
||||||
// sieve://localhost
|
|
||||||
// sieve://localhost:2000
|
|
||||||
// sieve://localhost:2000/?tls=YES
|
|
||||||
//
|
|
||||||
// Values such as "localhost" or "localhost:2000" are NOT supported.
|
|
||||||
//
|
|
||||||
sieveServer = [dd sieveServer];
|
|
||||||
sievePort = 2000;
|
|
||||||
url = nil;
|
|
||||||
|
|
||||||
if (!sieveServer)
|
|
||||||
{
|
|
||||||
NSString *s;
|
|
||||||
|
|
||||||
s = [dd imapServer];
|
|
||||||
|
|
||||||
if (s)
|
|
||||||
{
|
|
||||||
NSURL *url;
|
|
||||||
|
|
||||||
url = [NSURL URLWithString: s];
|
|
||||||
|
|
||||||
if ([url host])
|
|
||||||
sieveServer = [url host];
|
|
||||||
else
|
|
||||||
sieveServer = s;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sieveServer = @"localhost";
|
|
||||||
|
|
||||||
url = [NSURL URLWithString: [NSString stringWithFormat: @"%@:%d", sieveServer, sievePort]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
url = [NSURL URLWithString: sieveServer];
|
|
||||||
}
|
|
||||||
|
|
||||||
client = [[NGSieveClient alloc] initWithURL: url];
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
NSLog(@"Sieve connection failed on %@", [url description]);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!thePassword) {
|
|
||||||
[client closeConnection];
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_DURING
|
|
||||||
{
|
|
||||||
result = [client login: theLogin authname: theAuthName password: thePassword];
|
|
||||||
}
|
|
||||||
NS_HANDLER
|
|
||||||
{
|
|
||||||
connected = NO;
|
|
||||||
}
|
|
||||||
NS_ENDHANDLER
|
|
||||||
|
|
||||||
if (!connected)
|
|
||||||
{
|
|
||||||
NSLog(@"Sieve connection failed on %@", [url description]);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![[result valueForKey:@"result"] boolValue]) {
|
|
||||||
NSLog(@"failure. Attempting with a renewed password (no authname supported)");
|
|
||||||
thePassword = [theAccount imap4PasswordRenewed: YES];
|
|
||||||
result = [client login: theLogin password: thePassword];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![[result valueForKey:@"result"] boolValue]) {
|
|
||||||
NSLog(@"Could not login '%@' on Sieve server: %@: %@",
|
|
||||||
theLogin, client, result);
|
|
||||||
[client closeConnection];
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We ensure to deactive the current active script since it could prevent
|
/* We ensure to deactive the current active script since it could prevent
|
||||||
its deletion from the server. */
|
its deletion from the server. */
|
||||||
|
|
|
@ -76,6 +76,13 @@
|
||||||
- (NSString *) CASServiceURL;
|
- (NSString *) CASServiceURL;
|
||||||
- (BOOL) CASLogoutEnabled;
|
- (BOOL) CASLogoutEnabled;
|
||||||
|
|
||||||
|
- (NSString *) SAML2PrivateKeyLocation;
|
||||||
|
- (NSString *) SAML2CertificateLocation;
|
||||||
|
- (NSString *) SAML2IdpMetadataLocation;
|
||||||
|
- (NSString *) SAML2IdpPublicKeyLocation;
|
||||||
|
- (NSString *) SAML2IdpCertificateLocation;
|
||||||
|
- (BOOL) SAML2LogoutEnabled;
|
||||||
|
|
||||||
- (BOOL) enablePublicAccess;
|
- (BOOL) enablePublicAccess;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -379,7 +379,15 @@ _injectConfigurationFromFile (NSUserDefaults *ud,
|
||||||
|
|
||||||
- (NSArray *) supportedLanguages
|
- (NSArray *) supportedLanguages
|
||||||
{
|
{
|
||||||
return [self stringArrayForKey: @"SOGoSupportedLanguages"];
|
static NSArray *supportedLanguages = nil;
|
||||||
|
|
||||||
|
if (!supportedLanguages)
|
||||||
|
{
|
||||||
|
supportedLanguages = [self stringArrayForKey: @"SOGoSupportedLanguages"];
|
||||||
|
[supportedLanguages retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
return supportedLanguages;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) userCanChangePassword
|
- (BOOL) userCanChangePassword
|
||||||
|
@ -417,6 +425,37 @@ _injectConfigurationFromFile (NSUserDefaults *ud,
|
||||||
return [self boolForKey: @"SOGoCASLogoutEnabled"];
|
return [self boolForKey: @"SOGoCASLogoutEnabled"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SAML2 support */
|
||||||
|
- (NSString *) SAML2PrivateKeyLocation
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoSAML2PrivateKeyLocation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) SAML2CertificateLocation;
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoSAML2CertificateLocation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) SAML2IdpMetadataLocation
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoSAML2IdpMetadataLocation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) SAML2IdpPublicKeyLocation
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoSAML2IdpPublicKeyLocation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) SAML2IdpCertificateLocation
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoSAML2IdpCertificateLocation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) SAML2LogoutEnabled
|
||||||
|
{
|
||||||
|
return [self boolForKey: @"SOGoSAML2LogoutEnabled"];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL) enablePublicAccess
|
- (BOOL) enablePublicAccess
|
||||||
{
|
{
|
||||||
return [self boolForKey: @"SOGoEnablePublicAccess"];
|
return [self boolForKey: @"SOGoEnablePublicAccess"];
|
||||||
|
|
|
@ -576,13 +576,13 @@
|
||||||
|
|
||||||
- (void) _appendSystemMailAccount
|
- (void) _appendSystemMailAccount
|
||||||
{
|
{
|
||||||
NSString *fullName, *replyTo, *imapLogin, *imapServer, *signature,
|
NSString *fullName, *replyTo, *imapLogin, *imapServer, *cImapServer, *signature,
|
||||||
*encryption, *scheme, *action, *query, *customEmail;
|
*encryption, *scheme, *action, *query, *customEmail, *sieveServer;
|
||||||
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
|
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
|
||||||
NSNumber *port;
|
NSNumber *port;
|
||||||
NSMutableArray *identities;
|
NSMutableArray *identities;
|
||||||
NSArray *mails;
|
NSArray *mails;
|
||||||
NSURL *url;
|
NSURL *url, *cUrl;
|
||||||
unsigned int count, max;
|
unsigned int count, max;
|
||||||
NSInteger defaultPort;
|
NSInteger defaultPort;
|
||||||
|
|
||||||
|
@ -606,16 +606,22 @@
|
||||||
// imaps://localhost:143/?tls=YES
|
// imaps://localhost:143/?tls=YES
|
||||||
// imaps://localhost/?tls=YES
|
// imaps://localhost/?tls=YES
|
||||||
|
|
||||||
imapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
cImapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
||||||
if (!imapServer)
|
imapServer = [[self domainDefaults] imapServer];
|
||||||
imapServer = [[self domainDefaults] imapServer];
|
cUrl = [NSURL URLWithString: (cImapServer ? cImapServer : @"")];
|
||||||
url = [NSURL URLWithString: imapServer];
|
url = [NSURL URLWithString: imapServer];
|
||||||
if ([url host])
|
if([cUrl host])
|
||||||
imapServer = [url host];
|
imapServer = [cUrl host];
|
||||||
|
else
|
||||||
|
if(cImapServer)
|
||||||
|
imapServer = cImapServer;
|
||||||
|
else
|
||||||
|
if([url host])
|
||||||
|
imapServer = [url host];
|
||||||
[mailAccount setObject: imapServer forKey: @"serverName"];
|
[mailAccount setObject: imapServer forKey: @"serverName"];
|
||||||
|
|
||||||
// 3. port & encryption
|
// 3. port & encryption
|
||||||
scheme = [url scheme];
|
scheme = [cUrl scheme] ? [cUrl scheme] : [url scheme];
|
||||||
if (scheme
|
if (scheme
|
||||||
&& [scheme caseInsensitiveCompare: @"imaps"] == NSOrderedSame)
|
&& [scheme caseInsensitiveCompare: @"imaps"] == NSOrderedSame)
|
||||||
{
|
{
|
||||||
|
@ -624,19 +630,28 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
query = [url query];
|
query = [cUrl query] ? [cUrl query] : [url query];
|
||||||
if (query && [query caseInsensitiveCompare: @"tls=YES"] == NSOrderedSame)
|
if (query && [query caseInsensitiveCompare: @"tls=YES"] == NSOrderedSame)
|
||||||
encryption = @"tls";
|
encryption = @"tls";
|
||||||
else
|
else
|
||||||
encryption = @"none";
|
encryption = @"none";
|
||||||
defaultPort = 143;
|
defaultPort = 143;
|
||||||
}
|
}
|
||||||
port = [url port];
|
port = [cUrl port] ? [cUrl port] : [url port];
|
||||||
if ([port intValue] == 0) /* port is nil or intValue == 0 */
|
if ([port intValue] == 0) /* port is nil or intValue == 0 */
|
||||||
port = [NSNumber numberWithInt: defaultPort];
|
port = [NSNumber numberWithInt: defaultPort];
|
||||||
[mailAccount setObject: port forKey: @"port"];
|
[mailAccount setObject: port forKey: @"port"];
|
||||||
[mailAccount setObject: encryption forKey: @"encryption"];
|
[mailAccount setObject: encryption forKey: @"encryption"];
|
||||||
|
|
||||||
|
// Sieve server
|
||||||
|
sieveServer = [self _fetchFieldForUser: @"c_sievehostname"];
|
||||||
|
|
||||||
|
if (sieveServer)
|
||||||
|
{
|
||||||
|
[mailAccount setObject: sieveServer forKey: @"sieveServerName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* identities */
|
/* identities */
|
||||||
identities = [NSMutableArray new];
|
identities = [NSMutableArray new];
|
||||||
mails = [self allEmails];
|
mails = [self allEmails];
|
||||||
|
|
|
@ -35,6 +35,9 @@ extern NSString *SOGoWeekStartFirst4DayWeek;
|
||||||
extern NSString *SOGoWeekStartFirstFullWeek;
|
extern NSString *SOGoWeekStartFirstFullWeek;
|
||||||
|
|
||||||
@interface SOGoUserDefaults : SOGoDefaultsSource
|
@interface SOGoUserDefaults : SOGoDefaultsSource
|
||||||
|
{
|
||||||
|
NSString *userLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
+ (SOGoUserDefaults *) defaultsForUser: (NSString *) userId
|
+ (SOGoUserDefaults *) defaultsForUser: (NSString *) userId
|
||||||
inDomain: (NSString *) domainId;
|
inDomain: (NSString *) domainId;
|
||||||
|
@ -115,6 +118,9 @@ extern NSString *SOGoWeekStartFirstFullWeek;
|
||||||
- (void) setMailComposeMessageType: (NSString *) newValue;
|
- (void) setMailComposeMessageType: (NSString *) newValue;
|
||||||
- (NSString *) mailComposeMessageType;
|
- (NSString *) mailComposeMessageType;
|
||||||
|
|
||||||
|
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||||
|
- (NSString *) mailDisplayRemoteInlineImages;
|
||||||
|
|
||||||
- (void) setMailMessageForwarding: (NSString *) newValue;
|
- (void) setMailMessageForwarding: (NSString *) newValue;
|
||||||
- (NSString *) mailMessageForwarding;
|
- (NSString *) mailMessageForwarding;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#import <Foundation/NSArray.h>
|
#import <Foundation/NSArray.h>
|
||||||
#import <Foundation/NSDictionary.h>
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <Foundation/NSSet.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#import <Foundation/NSTimeZone.h>
|
#import <Foundation/NSTimeZone.h>
|
||||||
|
|
||||||
|
@ -91,6 +92,22 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
||||||
return ud;
|
return ud;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
userLanguage = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[userLanguage release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL) _migrateLastModule
|
- (BOOL) _migrateLastModule
|
||||||
{
|
{
|
||||||
BOOL rc;
|
BOOL rc;
|
||||||
|
@ -355,21 +372,25 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
||||||
|
|
||||||
- (NSString *) language
|
- (NSString *) language
|
||||||
{
|
{
|
||||||
NSString *language;
|
|
||||||
NSArray *supportedLanguages;
|
NSArray *supportedLanguages;
|
||||||
|
|
||||||
/* see SOGoDomainDefaults for the meaning of this */
|
|
||||||
language = [source objectForKey: @"SOGoLanguage"];
|
|
||||||
if (!(language && [language isKindOfClass: [NSString class]]))
|
|
||||||
language = [(SOGoDomainDefaults *) parentSource language];
|
|
||||||
|
|
||||||
/* make sure the language is part of the supported languages */
|
|
||||||
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
|
|
||||||
supportedLanguages];
|
|
||||||
if (![supportedLanguages containsObject: language])
|
|
||||||
language = [parentSource stringForKey: @"SOGoLanguage"];
|
|
||||||
|
|
||||||
return language;
|
if (!userLanguage)
|
||||||
|
{
|
||||||
|
/* see SOGoDomainDefaults for the meaning of this */
|
||||||
|
userLanguage = [source objectForKey: @"SOGoLanguage"];
|
||||||
|
if (!(userLanguage && [userLanguage isKindOfClass: [NSString class]]))
|
||||||
|
userLanguage = [(SOGoDomainDefaults *) parentSource language];
|
||||||
|
|
||||||
|
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||||
|
supportedLanguages];
|
||||||
|
|
||||||
|
/* make sure the language is part of the supported languages */
|
||||||
|
if (![supportedLanguages containsObject: userLanguage])
|
||||||
|
userLanguage = [parentSource stringForKey: @"SOGoLanguage"];
|
||||||
|
[userLanguage retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
return userLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setMailShowSubscribedFoldersOnly: (BOOL) newValue
|
- (void) setMailShowSubscribedFoldersOnly: (BOOL) newValue
|
||||||
|
@ -472,6 +493,16 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
||||||
return [self stringForKey: @"SOGoMailComposeMessageType"];
|
return [self stringForKey: @"SOGoMailComposeMessageType"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||||
|
{
|
||||||
|
[self setObject: newValue forKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) mailDisplayRemoteInlineImages;
|
||||||
|
{
|
||||||
|
return [self stringForKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) setMailMessageForwarding: (NSString *) newValue
|
- (void) setMailMessageForwarding: (NSString *) newValue
|
||||||
{
|
{
|
||||||
[self setObject: newValue forKey: @"SOGoMailMessageForwarding"];
|
[self setObject: newValue forKey: @"SOGoMailMessageForwarding"];
|
||||||
|
|
|
@ -595,7 +595,7 @@ static Class NSNullK;
|
||||||
withUIDorEmail: (NSString *) uid
|
withUIDorEmail: (NSString *) uid
|
||||||
inDomain: (NSString *) domain
|
inDomain: (NSString *) domain
|
||||||
{
|
{
|
||||||
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin;
|
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin, *c_sievehostname;
|
||||||
NSObject <SOGoSource> *currentSource;
|
NSObject <SOGoSource> *currentSource;
|
||||||
NSEnumerator *sogoSources;
|
NSEnumerator *sogoSources;
|
||||||
NSDictionary *userEntry;
|
NSDictionary *userEntry;
|
||||||
|
@ -610,6 +610,7 @@ static Class NSNullK;
|
||||||
c_domain = nil;
|
c_domain = nil;
|
||||||
c_imaphostname = nil;
|
c_imaphostname = nil;
|
||||||
c_imaplogin = nil;
|
c_imaplogin = nil;
|
||||||
|
c_sievehostname = nil;
|
||||||
|
|
||||||
[currentUser setObject: [NSNumber numberWithBool: YES]
|
[currentUser setObject: [NSNumber numberWithBool: YES]
|
||||||
forKey: @"CalendarAccess"];
|
forKey: @"CalendarAccess"];
|
||||||
|
@ -640,6 +641,8 @@ static Class NSNullK;
|
||||||
c_imaphostname = [userEntry objectForKey: @"c_imaphostname"];
|
c_imaphostname = [userEntry objectForKey: @"c_imaphostname"];
|
||||||
if (!c_imaplogin)
|
if (!c_imaplogin)
|
||||||
c_imaplogin = [userEntry objectForKey: @"c_imaplogin"];
|
c_imaplogin = [userEntry objectForKey: @"c_imaplogin"];
|
||||||
|
if (!c_sievehostname)
|
||||||
|
c_sievehostname = [userEntry objectForKey: @"c_sievehostname"];
|
||||||
access = [[userEntry objectForKey: @"CalendarAccess"] boolValue];
|
access = [[userEntry objectForKey: @"CalendarAccess"] boolValue];
|
||||||
if (!access)
|
if (!access)
|
||||||
[currentUser setObject: [NSNumber numberWithBool: NO]
|
[currentUser setObject: [NSNumber numberWithBool: NO]
|
||||||
|
@ -675,6 +678,8 @@ static Class NSNullK;
|
||||||
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
||||||
if (c_imaplogin)
|
if (c_imaplogin)
|
||||||
[currentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
|
[currentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
|
||||||
|
if (c_sievehostname)
|
||||||
|
[currentUser setObject: c_sievehostname forKey: @"c_sievehostname"];
|
||||||
|
|
||||||
[currentUser setObject: emails forKey: @"emails"];
|
[currentUser setObject: emails forKey: @"emails"];
|
||||||
[currentUser setObject: cn forKey: @"cn"];
|
[currentUser setObject: cn forKey: @"cn"];
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
|
|
||||||
@class NSString;
|
@class NSString;
|
||||||
|
|
||||||
|
@class WOContext;
|
||||||
|
@class WOCookie;
|
||||||
|
|
||||||
@class SOGoUser;
|
@class SOGoUser;
|
||||||
|
|
||||||
@interface SOGoWebAuthenticator : SoCookieAuthenticator <SOGoAuthenticator>
|
@interface SOGoWebAuthenticator : SoCookieAuthenticator <SOGoAuthenticator>
|
||||||
|
@ -45,6 +48,10 @@
|
||||||
expire: (int *) _expire
|
expire: (int *) _expire
|
||||||
grace: (int *) _grace;
|
grace: (int *) _grace;
|
||||||
|
|
||||||
|
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||||
|
andPassword: (NSString *) password
|
||||||
|
inContext: (WOContext *) context;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif /* _SOGOWEBAUTHENTICATOR_H_ */
|
#endif /* _SOGOWEBAUTHENTICATOR_H_ */
|
||||||
|
|
|
@ -32,9 +32,12 @@
|
||||||
#import <NGObjWeb/WOCookie.h>
|
#import <NGObjWeb/WOCookie.h>
|
||||||
#import <NGObjWeb/WORequest.h>
|
#import <NGObjWeb/WORequest.h>
|
||||||
#import <NGObjWeb/WOResponse.h>
|
#import <NGObjWeb/WOResponse.h>
|
||||||
|
#import <NGExtensions/NGBase64Coding.h>
|
||||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||||
|
#import <NGExtensions/NSData+gzip.h>
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
#import <NGExtensions/NSNull+misc.h>
|
#import <NGExtensions/NSNull+misc.h>
|
||||||
|
#import <NGExtensions/NSString+Ext.h>
|
||||||
#import <NGLdap/NGLdapConnection.h>
|
#import <NGLdap/NGLdapConnection.h>
|
||||||
|
|
||||||
#import <MainUI/SOGoRootPage.h>
|
#import <MainUI/SOGoRootPage.h>
|
||||||
|
@ -47,7 +50,9 @@
|
||||||
#import "SOGoSystemDefaults.h"
|
#import "SOGoSystemDefaults.h"
|
||||||
#import "SOGoUser.h"
|
#import "SOGoUser.h"
|
||||||
#import "SOGoUserManager.h"
|
#import "SOGoUserManager.h"
|
||||||
|
#if defined(SAML2_CONFIG)
|
||||||
|
#import "SOGoSAML2Session.h"
|
||||||
|
#endif
|
||||||
#import "SOGoWebAuthenticator.h"
|
#import "SOGoWebAuthenticator.h"
|
||||||
|
|
||||||
@implementation SOGoWebAuthenticator
|
@implementation SOGoWebAuthenticator
|
||||||
|
@ -107,11 +112,13 @@
|
||||||
{
|
{
|
||||||
SOGoCASSession *session;
|
SOGoCASSession *session;
|
||||||
SOGoSystemDefaults *sd;
|
SOGoSystemDefaults *sd;
|
||||||
|
NSString *authenticationType;
|
||||||
BOOL rc;
|
BOOL rc;
|
||||||
|
|
||||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||||
|
|
||||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
authenticationType = [sd authenticationType];
|
||||||
|
if ([authenticationType isEqualToString: @"cas"])
|
||||||
{
|
{
|
||||||
session = [SOGoCASSession CASSessionWithIdentifier: _pwd fromProxy: NO];
|
session = [SOGoCASSession CASSessionWithIdentifier: _pwd fromProxy: NO];
|
||||||
if (session)
|
if (session)
|
||||||
|
@ -119,6 +126,18 @@
|
||||||
else
|
else
|
||||||
rc = NO;
|
rc = NO;
|
||||||
}
|
}
|
||||||
|
#if defined(SAML2_CONFIG)
|
||||||
|
else if ([authenticationType isEqualToString: @"saml2"])
|
||||||
|
{
|
||||||
|
SOGoSAML2Session *saml2Session;
|
||||||
|
WOContext *context;
|
||||||
|
|
||||||
|
context = [[WOApplication application] context];
|
||||||
|
saml2Session = [SOGoSAML2Session SAML2SessionWithIdentifier: _pwd
|
||||||
|
inContext: context];
|
||||||
|
rc = [[saml2Session login] isEqualToString: _login];
|
||||||
|
}
|
||||||
|
#endif /* SAML2_CONFIG */
|
||||||
else
|
else
|
||||||
rc = [[SOGoUserManager sharedUserManager] checkLogin: _login
|
rc = [[SOGoUserManager sharedUserManager] checkLogin: _login
|
||||||
password: _pwd
|
password: _pwd
|
||||||
|
@ -225,16 +244,18 @@
|
||||||
forURL: (NSURL *) server
|
forURL: (NSURL *) server
|
||||||
forceRenew: (BOOL) renew
|
forceRenew: (BOOL) renew
|
||||||
{
|
{
|
||||||
NSString *password, *service, *scheme;
|
NSString *authType, *password;
|
||||||
SOGoCASSession *session;
|
|
||||||
SOGoSystemDefaults *sd;
|
|
||||||
|
|
||||||
password = [self passwordInContext: context];
|
password = [self passwordInContext: context];
|
||||||
if ([password length])
|
if ([password length])
|
||||||
{
|
{
|
||||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
authType = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
authenticationType];
|
||||||
|
if ([authType isEqualToString: @"cas"])
|
||||||
{
|
{
|
||||||
|
SOGoCASSession *session;
|
||||||
|
NSString *service, *scheme;
|
||||||
|
|
||||||
session = [SOGoCASSession CASSessionWithIdentifier: password
|
session = [SOGoCASSession CASSessionWithIdentifier: password
|
||||||
fromProxy: NO];
|
fromProxy: NO];
|
||||||
|
|
||||||
|
@ -252,6 +273,23 @@
|
||||||
if ([password length] || renew)
|
if ([password length] || renew)
|
||||||
[session updateCache];
|
[session updateCache];
|
||||||
}
|
}
|
||||||
|
#if defined(SAML2_CONFIG)
|
||||||
|
else if ([authType isEqualToString: @"saml2"])
|
||||||
|
{
|
||||||
|
SOGoSAML2Session *session;
|
||||||
|
WOContext *context;
|
||||||
|
NSData *assertion;
|
||||||
|
|
||||||
|
context = [[WOApplication application] context];
|
||||||
|
session = [SOGoSAML2Session SAML2SessionWithIdentifier: password
|
||||||
|
inContext: context];
|
||||||
|
assertion = [[session assertion]
|
||||||
|
dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
|
password = [[[assertion compress] stringByEncodingBase64]
|
||||||
|
stringByReplacingString: @"\n"
|
||||||
|
withString: @""];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return password;
|
return password;
|
||||||
|
@ -314,4 +352,44 @@
|
||||||
[response addCookie: authCookie];
|
[response addCookie: authCookie];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||||
|
andPassword: (NSString *) password
|
||||||
|
inContext: (WOContext *) context
|
||||||
|
{
|
||||||
|
WOCookie *authCookie;
|
||||||
|
NSString *cookieValue, *cookieString, *appName, *sessionKey, *userKey, *securedPassword;
|
||||||
|
|
||||||
|
//
|
||||||
|
// We create a new cookie - thus we create a new session
|
||||||
|
// associated to the user. For security, we generate:
|
||||||
|
//
|
||||||
|
// A- a session key
|
||||||
|
// B- a user key
|
||||||
|
//
|
||||||
|
// In memcached, the session key will be associated to the user's password
|
||||||
|
// which will be XOR'ed with the user key.
|
||||||
|
//
|
||||||
|
sessionKey = [SOGoSession generateKeyForLength: 16];
|
||||||
|
userKey = [SOGoSession generateKeyForLength: 64];
|
||||||
|
|
||||||
|
NSString *value = [NSString stringWithFormat: @"%@:%@", username, password];
|
||||||
|
securedPassword = [SOGoSession securedValue: value usingKey: userKey];
|
||||||
|
|
||||||
|
|
||||||
|
[SOGoSession setValue: securedPassword forSessionKey: sessionKey];
|
||||||
|
|
||||||
|
//cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||||
|
// username, password];
|
||||||
|
cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||||
|
userKey, sessionKey];
|
||||||
|
cookieValue = [NSString stringWithFormat: @"basic %@",
|
||||||
|
[cookieString stringByEncodingBase64]];
|
||||||
|
authCookie = [WOCookie cookieWithName: [self cookieNameInContext: context]
|
||||||
|
value: cookieValue];
|
||||||
|
appName = [[context request] applicationName];
|
||||||
|
[authCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||||
|
|
||||||
|
return authCookie;
|
||||||
|
}
|
||||||
|
|
||||||
@end /* SOGoWebAuthenticator */
|
@end /* SOGoWebAuthenticator */
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
NSArray *_mailFields;
|
NSArray *_mailFields;
|
||||||
NSString *_imapLoginField;
|
NSString *_imapLoginField;
|
||||||
NSString *_imapHostField;
|
NSString *_imapHostField;
|
||||||
|
NSString *_sieveHostField;
|
||||||
NSString *_userPasswordAlgorithm;
|
NSString *_userPasswordAlgorithm;
|
||||||
NSURL *_viewURL;
|
NSURL *_viewURL;
|
||||||
BOOL _prependPasswordScheme;
|
BOOL _prependPasswordScheme;
|
||||||
|
|
|
@ -98,6 +98,7 @@
|
||||||
_kindField = nil;
|
_kindField = nil;
|
||||||
_multipleBookingsField = nil;
|
_multipleBookingsField = nil;
|
||||||
_imapHostField = nil;
|
_imapHostField = nil;
|
||||||
|
_sieveHostField = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -115,6 +116,7 @@
|
||||||
[_multipleBookingsField release];
|
[_multipleBookingsField release];
|
||||||
[_domainField release];
|
[_domainField release];
|
||||||
[_imapHostField release];
|
[_imapHostField release];
|
||||||
|
[_sieveHostField release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
@ -131,6 +133,7 @@
|
||||||
ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]);
|
ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]);
|
||||||
ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]);
|
ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]);
|
||||||
ASSIGN(_imapHostField, [udSource objectForKey: @"IMAPHostFieldName"]);
|
ASSIGN(_imapHostField, [udSource objectForKey: @"IMAPHostFieldName"]);
|
||||||
|
ASSIGN(_sieveHostField, [udSource objectForKey: @"SieveHostFieldName"]);
|
||||||
ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]);
|
ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]);
|
||||||
ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]);
|
ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]);
|
||||||
ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]);
|
ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]);
|
||||||
|
@ -187,7 +190,10 @@
|
||||||
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
||||||
|
|
||||||
if (pass == nil)
|
if (pass == nil)
|
||||||
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
{
|
||||||
|
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
if (_prependPasswordScheme)
|
if (_prependPasswordScheme)
|
||||||
result = [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
result = [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
||||||
|
@ -308,18 +314,20 @@
|
||||||
NSString *sqlstr;
|
NSString *sqlstr;
|
||||||
BOOL didChange;
|
BOOL didChange;
|
||||||
BOOL isOldPwdOk;
|
BOOL isOldPwdOk;
|
||||||
|
|
||||||
isOldPwdOk = NO;
|
isOldPwdOk = NO;
|
||||||
didChange = NO;
|
didChange = NO;
|
||||||
|
|
||||||
// Verify current password
|
// Verify current password
|
||||||
isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0];
|
isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0];
|
||||||
|
|
||||||
if (isOldPwdOk)
|
if (isOldPwdOk)
|
||||||
{
|
{
|
||||||
// Encrypt new password
|
// Encrypt new password
|
||||||
NSString *encryptedPassword = [self _encryptPassword: newPassword];
|
NSString *encryptedPassword = [self _encryptPassword: newPassword];
|
||||||
|
if(encryptedPassword == nil)
|
||||||
|
return NO;
|
||||||
|
|
||||||
// Save new password
|
// Save new password
|
||||||
login = [login stringByReplacingString: @"'" withString: @"''"];
|
login = [login stringByReplacingString: @"'" withString: @"''"];
|
||||||
cm = [GCSChannelManager defaultChannelManager];
|
cm = [GCSChannelManager defaultChannelManager];
|
||||||
|
@ -519,6 +527,13 @@
|
||||||
[response setObject: value forKey: @"c_imaphostname"];
|
[response setObject: value forKey: @"c_imaphostname"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_sieveHostField)
|
||||||
|
{
|
||||||
|
value = [response objectForKey: _sieveHostField];
|
||||||
|
if ([value isNotNull])
|
||||||
|
[response setObject: value forKey: @"c_sievehostname"];
|
||||||
|
}
|
||||||
|
|
||||||
// We check if the user can authenticate
|
// We check if the user can authenticate
|
||||||
if (_authenticationFilter)
|
if (_authenticationFilter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
include_dirs = []
|
||||||
|
|
||||||
|
output = "-"
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
m_template = """/* %(module)s.m (auto-generated) */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSValue.h>
|
||||||
|
|
||||||
|
#import "%(module)s.h"
|
||||||
|
|
||||||
|
%(exception_init)s
|
||||||
|
|
||||||
|
static NSMutableDictionary *exceptionTable = nil;
|
||||||
|
|
||||||
|
@implementation NSException (SOGoSAML2Extension)
|
||||||
|
|
||||||
|
static void
|
||||||
|
InitExceptionTable ()
|
||||||
|
{
|
||||||
|
exceptionTable = [NSMutableDictionary new];
|
||||||
|
%(exception_table_init)s
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) raiseSAML2Exception: (lasso_error_t) lassoError
|
||||||
|
{
|
||||||
|
NSString *exceptionName, *reason;
|
||||||
|
|
||||||
|
if (!exceptionTable)
|
||||||
|
InitExceptionTable ();
|
||||||
|
|
||||||
|
exceptionName = [exceptionTable objectForKey: [NSNumber numberWithInt: lassoError]];
|
||||||
|
if (!exceptionName)
|
||||||
|
exceptionName = NSGenericException;
|
||||||
|
|
||||||
|
reason = [NSString stringWithUTF8String: lasso_strerror (lassoError)];
|
||||||
|
if (!reason)
|
||||||
|
reason = @"unspecified";
|
||||||
|
|
||||||
|
[self raise: exceptionName format: @"%%@", reason];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
"""
|
||||||
|
|
||||||
|
h_template = """/* %(module)s.h (auto-generated) */
|
||||||
|
|
||||||
|
#ifndef %(h_exclusion)s
|
||||||
|
#define %(h_exclusion)s 1
|
||||||
|
|
||||||
|
#include <lasso/errors.h>
|
||||||
|
#import <Foundation/NSException.h>
|
||||||
|
|
||||||
|
@class NSString;
|
||||||
|
|
||||||
|
%(exception_decls)s
|
||||||
|
|
||||||
|
@interface NSException (SOGoSAML2Extension)
|
||||||
|
|
||||||
|
+ (void) raiseSAML2Exception: (lasso_error_t) lassoError;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif /* %(h_exclusion)s */
|
||||||
|
"""
|
||||||
|
|
||||||
|
def ParseErrorsHLine(line):
|
||||||
|
result = None
|
||||||
|
if line.startswith("#define LASSO_"):
|
||||||
|
next_space = line.find(" ", 19)
|
||||||
|
result = line[8:next_space]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def ParseIncludeDirs(args):
|
||||||
|
dirs = ["/usr/include", "/usr/local/include"]
|
||||||
|
ignore = True
|
||||||
|
for arg in args:
|
||||||
|
if ignore:
|
||||||
|
if arg == "-I":
|
||||||
|
ignore = False
|
||||||
|
elif arg.startswith("-I"):
|
||||||
|
dirs.append(arg[2:])
|
||||||
|
else:
|
||||||
|
dirs.append(arg)
|
||||||
|
ignore = True
|
||||||
|
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
def FindHFile(args, filename):
|
||||||
|
found = None
|
||||||
|
|
||||||
|
include_dirs = ParseIncludeDirs(args)
|
||||||
|
for dirname in include_dirs:
|
||||||
|
full_filename = "%s/%s" % (dirname, filename)
|
||||||
|
if os.path.exists(full_filename):
|
||||||
|
found = full_filename
|
||||||
|
|
||||||
|
if found is None:
|
||||||
|
raise Exception, "'%s' not found in include dirs" % filename
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
def ErrorCodeToName(name):
|
||||||
|
parts = name.split("_")
|
||||||
|
cap_parts = [part.capitalize() for part in parts]
|
||||||
|
|
||||||
|
return "".join(cap_parts)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
errors_filename = FindHFile(sys.argv, os.path.join("lasso", "errors.h"))
|
||||||
|
|
||||||
|
inf = open(errors_filename)
|
||||||
|
error_codes = {}
|
||||||
|
line = inf.readline()
|
||||||
|
while line != "":
|
||||||
|
error_code = ParseErrorsHLine(line)
|
||||||
|
if error_code:
|
||||||
|
error_codes[error_code] = ErrorCodeToName(error_code)
|
||||||
|
line = inf.readline()
|
||||||
|
inf.close()
|
||||||
|
|
||||||
|
exception_decls = []
|
||||||
|
exception_init = []
|
||||||
|
exception_table_init = []
|
||||||
|
|
||||||
|
exc_table_format \
|
||||||
|
= (" [exceptionTable setObject: %s\n"
|
||||||
|
" forKey: [NSNumber numberWithInt: %s]];")
|
||||||
|
for error_code in error_codes:
|
||||||
|
name = error_codes[error_code];
|
||||||
|
exception_init.append("NSString * const %s = @\"%s\";" % (name, name))
|
||||||
|
exception_decls.append("extern NSString * const %s;" % name)
|
||||||
|
exception_table_init.append(exc_table_format % (name, error_code))
|
||||||
|
|
||||||
|
module = "SOGoSAML2Exceptions"
|
||||||
|
outvars = {"module": module,
|
||||||
|
"h_exclusion": "%s_H" % module.upper(),
|
||||||
|
"exception_decls": "\n".join(exception_decls),
|
||||||
|
"exception_init": "\n".join(exception_init),
|
||||||
|
"exception_table_init": "\n".join(exception_table_init)}
|
||||||
|
|
||||||
|
outf = open("%s.m" % module, "w+")
|
||||||
|
outf.write(m_template % outvars)
|
||||||
|
outf.close()
|
||||||
|
|
||||||
|
outf = open("%s.h" % module, "w+")
|
||||||
|
outf.write(h_template % outvars)
|
||||||
|
outf.close()
|
|
@ -13,7 +13,7 @@ import sogoLogin
|
||||||
SOGoSupportedLanguages = [ "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
|
SOGoSupportedLanguages = [ "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
|
||||||
"SpanishSpain", "SpanishArgentina", "French", "German",
|
"SpanishSpain", "SpanishArgentina", "French", "German",
|
||||||
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
||||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian",
|
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",
|
||||||
"Ukrainian", "Swedish" ];
|
"Ukrainian", "Swedish" ];
|
||||||
daysBetweenResponseList=[1,2,3,5,7,14,21,30]
|
daysBetweenResponseList=[1,2,3,5,7,14,21,30]
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,8 @@ class DAVAclTest(unittest.TestCase):
|
||||||
return versitStruct
|
return versitStruct
|
||||||
|
|
||||||
event_template = """BEGIN:VCALENDAR
|
event_template = """BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
|
||||||
PRODID:-//Inverse//Event Generator//EN
|
PRODID:-//Inverse//Event Generator//EN
|
||||||
|
VERSION:2.0
|
||||||
BEGIN:VEVENT
|
BEGIN:VEVENT
|
||||||
SEQUENCE:0
|
SEQUENCE:0
|
||||||
TRANSP:OPAQUE
|
TRANSP:OPAQUE
|
||||||
|
|
|
@ -38,10 +38,9 @@ ADDITIONAL_LIB_DIRS += \
|
||||||
-Wl,-rpath,../../SoObjects/SOGo/SOGo.framework/Versions/Current -Wl,-rpath,../../SOPE/NGCards/obj -Wl,-rpath,../../SOPE/GDLContentStore/obj -Wl,-rpath,../../OGoContentStore/obj
|
-Wl,-rpath,../../SoObjects/SOGo/SOGo.framework/Versions/Current -Wl,-rpath,../../SOPE/NGCards/obj -Wl,-rpath,../../SOPE/GDLContentStore/obj -Wl,-rpath,../../OGoContentStore/obj
|
||||||
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed
|
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed
|
||||||
|
|
||||||
check ::
|
|
||||||
./obj/sogo-tests
|
|
||||||
|
|
||||||
-include GNUmakefile.preamble
|
-include GNUmakefile.preamble
|
||||||
include $(GNUSTEP_MAKEFILES)/test-tool.make
|
include $(GNUSTEP_MAKEFILES)/test-tool.make
|
||||||
-include GNUmakefile.postamble
|
-include GNUmakefile.postamble
|
||||||
|
|
||||||
|
check ::
|
||||||
|
./obj/sogo-tests
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#import <GDLContentStore/GCSChannelManager.h>
|
#import <GDLContentStore/GCSChannelManager.h>
|
||||||
#import <GDLContentStore/GCSFolder.h>
|
#import <GDLContentStore/GCSFolder.h>
|
||||||
#import <GDLContentStore/GCSFolderManager.h>
|
#import <GDLContentStore/GCSFolderManager.h>
|
||||||
|
#import <GDLContentStore/GCSSpecialQueries.h>
|
||||||
#import <GDLContentStore/NSURL+GCS.h>
|
#import <GDLContentStore/NSURL+GCS.h>
|
||||||
|
|
||||||
#import <SOGo/NSString+Utilities.h>
|
#import <SOGo/NSString+Utilities.h>
|
||||||
|
@ -113,6 +114,7 @@
|
||||||
BOOL rc = NO;
|
BOOL rc = NO;
|
||||||
GCSFolderManager *fm;
|
GCSFolderManager *fm;
|
||||||
GCSChannelManager *cm;
|
GCSChannelManager *cm;
|
||||||
|
GCSSpecialQueries *specialQueries;
|
||||||
NSURL *folderLocation;
|
NSURL *folderLocation;
|
||||||
EOAdaptorContext *ac;
|
EOAdaptorContext *ac;
|
||||||
EOAdaptorChannel *fc;
|
EOAdaptorChannel *fc;
|
||||||
|
@ -125,6 +127,7 @@
|
||||||
folderLocation = [fm folderInfoLocation];
|
folderLocation = [fm folderInfoLocation];
|
||||||
fc = [cm acquireOpenChannelForURL: folderLocation];
|
fc = [cm acquireOpenChannelForURL: folderLocation];
|
||||||
ac = [fc adaptorContext];
|
ac = [fc adaptorContext];
|
||||||
|
specialQueries = [fc specialQueries];
|
||||||
sqlFromUserID = [fromUserID asSafeSQLString];
|
sqlFromUserID = [fromUserID asSafeSQLString];
|
||||||
sqlToUserID = [toUserID asSafeSQLString];
|
sqlToUserID = [toUserID asSafeSQLString];
|
||||||
|
|
||||||
|
@ -137,15 +140,16 @@
|
||||||
if (!sqlError)
|
if (!sqlError)
|
||||||
{
|
{
|
||||||
sql
|
sql
|
||||||
= [NSString stringWithFormat: @"UPDATE %@"
|
= [specialQueries updateCPathInFolderInfo: [folderLocation gcsTableName]
|
||||||
@" SET c_path = '/'||c_path1||'/'||c_path2||'/'||c_path3||'/'||c_path4"
|
withCPath2: sqlToUserID];
|
||||||
@" WHERE c_path2 = '%@'",
|
|
||||||
[folderLocation gcsTableName], sqlToUserID];
|
|
||||||
sqlError = [fc evaluateExpressionX: sql];
|
sqlError = [fc evaluateExpressionX: sql];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sqlError)
|
if (sqlError)
|
||||||
[ac rollbackTransaction];
|
{
|
||||||
|
[ac rollbackTransaction];
|
||||||
|
NSLog([sqlError reason]);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rc = [ac commitTransaction];
|
rc = [ac commitTransaction];
|
||||||
|
|
||||||
|
@ -195,7 +199,10 @@
|
||||||
[profileLocation gcsTableName], sqlToUserID, sqlFromUserID];
|
[profileLocation gcsTableName], sqlToUserID, sqlFromUserID];
|
||||||
sqlError = [fc evaluateExpressionX: sql];
|
sqlError = [fc evaluateExpressionX: sql];
|
||||||
if (sqlError)
|
if (sqlError)
|
||||||
[ac rollbackTransaction];
|
{
|
||||||
|
[ac rollbackTransaction];
|
||||||
|
NSLog([sqlError reason]);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rc = [ac commitTransaction];
|
rc = [ac commitTransaction];
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Foundation/NSArray.h>
|
#import <Foundation/NSArray.h>
|
||||||
|
#import <Foundation/NSAutoreleasePool.h>
|
||||||
#import <Foundation/NSError.h>
|
#import <Foundation/NSError.h>
|
||||||
#import <Foundation/NSFileManager.h>
|
#import <Foundation/NSFileManager.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
|
@ -346,6 +347,7 @@ typedef enum SOGoToolRestoreMode {
|
||||||
- (BOOL) restoreRecords: (NSArray *) records
|
- (BOOL) restoreRecords: (NSArray *) records
|
||||||
ofFolder: (GCSFolder *) gcsFolder
|
ofFolder: (GCSFolder *) gcsFolder
|
||||||
{
|
{
|
||||||
|
NSAutoreleasePool *pool;
|
||||||
NSDictionary *existingRecords, *currentRecord;
|
NSDictionary *existingRecords, *currentRecord;
|
||||||
NSString *cName, *cContent;
|
NSString *cName, *cContent;
|
||||||
int count, max;
|
int count, max;
|
||||||
|
@ -354,12 +356,18 @@ typedef enum SOGoToolRestoreMode {
|
||||||
|
|
||||||
if (records)
|
if (records)
|
||||||
{
|
{
|
||||||
|
existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder];
|
||||||
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
version = 0;
|
version = 0;
|
||||||
rc = YES;
|
rc = YES;
|
||||||
existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder];
|
|
||||||
max = [records count];
|
max = [records count];
|
||||||
for (count = 0; count < max; count++)
|
for (count = 0; count < max; count++)
|
||||||
{
|
{
|
||||||
|
if (count > 0 && count%100 == 0)
|
||||||
|
{
|
||||||
|
DESTROY(pool);
|
||||||
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
}
|
||||||
currentRecord = [records objectAtIndex: count];
|
currentRecord = [records objectAtIndex: count];
|
||||||
cName = [currentRecord objectForKey: @"c_name"];
|
cName = [currentRecord objectForKey: @"c_name"];
|
||||||
if (![existingRecords objectForKey: cName])
|
if (![existingRecords objectForKey: cName])
|
||||||
|
@ -370,6 +378,7 @@ typedef enum SOGoToolRestoreMode {
|
||||||
baseVersion: &version];
|
baseVersion: &version];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DESTROY(pool);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ BUNDLE_NAME = AdministrationUI
|
||||||
|
|
||||||
AdministrationUI_PRINCIPAL_CLASS = AdministrationUIProduct
|
AdministrationUI_PRINCIPAL_CLASS = AdministrationUIProduct
|
||||||
|
|
||||||
AdministrationUI_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Italian NorwegianBokmal NorwegianNynorsk Polish Russian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
AdministrationUI_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||||
|
|
||||||
AdministrationUI_OBJC_FILES = \
|
AdministrationUI_OBJC_FILES = \
|
||||||
AdministrationUIProduct.m \
|
AdministrationUIProduct.m \
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* this file is in UTF-8 format! */
|
||||||
|
|
||||||
|
"Help" = "Pomoc";
|
||||||
|
"Close" = "Zavrieť";
|
||||||
|
|
||||||
|
"Modules" = "Moduly";
|
||||||
|
|
||||||
|
/* Modules short names */
|
||||||
|
"ACLs" = "ACL";
|
||||||
|
|
||||||
|
/* Modules titles */
|
||||||
|
"ACLs_title" = "Spravovanie ACL zložiek uzívateľov";
|
||||||
|
|
||||||
|
/* Modules descriptions */
|
||||||
|
"ACLs_description" = "<p>Administrácia kontroly prístupových práv (ACL) dovoluje spravovať ACLs kalendárov a adresárov pre všetkých užívateľov.</p><p>Pre úpravu ACL zložky užívateľa, napíšte meno užívateľa v kolonke hľadaj hore v okne a dvojklikom potvrďte výber zložky.</p>";
|
|
@ -6,7 +6,7 @@ BUNDLE_NAME = CommonUI
|
||||||
|
|
||||||
CommonUI_PRINCIPAL_CLASS = CommonUIProduct
|
CommonUI_PRINCIPAL_CLASS = CommonUIProduct
|
||||||
|
|
||||||
CommonUI_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
CommonUI_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||||
|
|
||||||
CommonUI_OBJC_FILES += \
|
CommonUI_OBJC_FILES += \
|
||||||
CommonUIProduct.m \
|
CommonUIProduct.m \
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"Owner:" = "Właściciel:";
|
"Owner:" = "Właściciel:";
|
||||||
"Publish the Free/Busy information" = "Opublikuj informację wolny/zajęty";
|
"Publish the Free/Busy information" = "Opublikuj informację wolny/zajęty";
|
||||||
|
|
||||||
"Add..." = "Dodaj...";
|
"Add..." = "Dodaj";
|
||||||
"Remove" = "Usuń";
|
"Remove" = "Usuń";
|
||||||
|
|
||||||
"Subscribe User" = "Subskrybuj użytkownika";
|
"Subscribe User" = "Subskrybuj użytkownika";
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
||||||
= "Dowolny użytkownik systemu będzie miał dostęp do Twojej skrzynki \"%{0}\". Naprawdę ufasz im wszystkim?";
|
= "Dowolny użytkownik systemu będzie miał dostęp do Twojej skrzynki \"%{0}\". Naprawdę ufasz im wszystkim?";
|
||||||
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
||||||
= "Dowolny użytkownik systemu będzie miał dostęp do Twojego kalendarza \"%{0}\". Naprawdę ufasz im wszystkim?";
|
= "Dowolny użytkownik systemu będzie miał dostęp do Twojego kalendarza \"%{0}\". Naprawdę ufasz im wszystkim?";
|
||||||
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||||
= "Twój kalendarz \"%{0}\" będzie publiczne dostępny dla każdego w Internecie. Czy te informacje napewno mają być tak upublicznione?";
|
= "Twój kalendarz \"%{0}\" będzie publiczne dostępny dla każdego w Internecie. Czy te informacje napewno mają być tak upublicznione?";
|
||||||
|
@ -52,14 +52,14 @@
|
||||||
|
|
||||||
/* generic.js */
|
/* generic.js */
|
||||||
"Unable to subscribe to that folder!"
|
"Unable to subscribe to that folder!"
|
||||||
= "Nie można subskrybować tego foldera!";
|
= "Nie można subskrybować tego folderu!";
|
||||||
"You cannot subscribe to a folder that you own!"
|
"You cannot subscribe to a folder that you own!"
|
||||||
= "Nie możesz subskrybować foldera, który jest twoją własnością!";
|
= "Nie możesz subskrybować folderu, który jest twoją własnością!";
|
||||||
"Unable to unsubscribe from that folder!"
|
"Unable to unsubscribe from that folder!"
|
||||||
= "Nie można wyłączyć subskrypcji tego foldera!";
|
= "Nie można wyłączyć subskrypcji tego folderu!";
|
||||||
"You cannot unsubscribe from a folder that you own!"
|
"You cannot unsubscribe from a folder that you own!"
|
||||||
= "Nie możesz wyłączyć subskrypcji foldera, który jest twoją własnością!";
|
= "Nie możesz wyłączyć subskrypcji folderu, który jest twoją własnością!";
|
||||||
"Unable to rename that folder!" = "Nie można zmienić nazwy tego foldera!";
|
"Unable to rename that folder!" = "Nie można zmienić nazwy tego folderu!";
|
||||||
"You have already subscribed to that folder!"
|
"You have already subscribed to that folder!"
|
||||||
= "Już subskrybujesz ten folder!";
|
= "Już subskrybujesz ten folder!";
|
||||||
"The user rights cannot be edited for this object!"
|
"The user rights cannot be edited for this object!"
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
"delegate is a participant" = "Delegat jest już uczestnikiem.";
|
"delegate is a participant" = "Delegat jest już uczestnikiem.";
|
||||||
"delegate is a group" = "Wskazany adres jest grupą. Możesz oddelegować tylko pojedynczną osobę.";
|
"delegate is a group" = "Wskazany adres jest grupą. Możesz oddelegować tylko pojedynczną osobę.";
|
||||||
|
|
||||||
"Snooze for " = "Drzemka przez";
|
"Snooze for " = "Drzemka przez ";
|
||||||
"5 minutes" = "5 minut";
|
"5 minutes" = "5 minut";
|
||||||
"10 minutes" = "10 minut";
|
"10 minutes" = "10 minut";
|
||||||
"15 minutes" = "15 minut";
|
"15 minutes" = "15 minut";
|
||||||
|
@ -106,4 +106,4 @@
|
||||||
"a2_Wednesday" = "Śr";
|
"a2_Wednesday" = "Śr";
|
||||||
"a2_Thursday" = "Cz";
|
"a2_Thursday" = "Cz";
|
||||||
"a2_Friday" = "Pi";
|
"a2_Friday" = "Pi";
|
||||||
"a2_Saturday" = "So";
|
"a2_Saturday" = "So";
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* this file is in UTF-8 format! */
|
||||||
|
|
||||||
|
/* toolbars */
|
||||||
|
"Save" = "Uložiť";
|
||||||
|
"Close" = "Zavrieť";
|
||||||
|
"Edit User Rights" = "Upraviť uživateľské práva";
|
||||||
|
|
||||||
|
"Home" = "Domov";
|
||||||
|
"Calendar" = "Kalendár";
|
||||||
|
"Address Book" = "Adresár";
|
||||||
|
"Mail" = "Pošta";
|
||||||
|
"Preferences" = "Predvoľby";
|
||||||
|
"Administration" = "Správa";
|
||||||
|
"Disconnect" = "Odpojiť";
|
||||||
|
"Right Administration" = "Administrácia práv";
|
||||||
|
"Log Console (dev.)" = "Log konzola (vývoj)";
|
||||||
|
|
||||||
|
"User" = "Užívateľ";
|
||||||
|
|
||||||
|
"Help" = "Pomoc";
|
||||||
|
|
||||||
|
"noJavascriptError" = "Sogo vyžaduje pre spustenie JavaScript. Uistite sa, že táto možnosť je k dispozícii a aktivovaná v prehliadači.";
|
||||||
|
"noJavascriptRetry" = "Opakovať";
|
||||||
|
|
||||||
|
"Owner:" = "Vlastník:";
|
||||||
|
"Publish the Free/Busy information" = "Publikovanie Free / Busy informácií";
|
||||||
|
|
||||||
|
"Add..." = "Pridať...";
|
||||||
|
"Remove" = "Odstrániť";
|
||||||
|
|
||||||
|
"Subscribe User" = "Prihlásiť užívateľa k odberu";
|
||||||
|
|
||||||
|
"Any Authenticated User" = "Všetkým prihláseným užívateľom";
|
||||||
|
"Public Access" = "Verejný prístup";
|
||||||
|
"Any user not listed above" = "Každý užívateľ, ktorý nie je uvedený vyššie";
|
||||||
|
"Anybody accessing this resource from the public area" = "Každý, kto prístupuje k tomuto zdroju z verejného priestoru";
|
||||||
|
|
||||||
|
"Sorry, the user rights can not be configured for that object." = "Je nám ľúto, užívateľské práva nie je možné konfigurovať pre daný objekt.";
|
||||||
|
|
||||||
|
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
||||||
|
= "Ktorýkoľvek užívateľ tohoto systému bude môcť vidieť Vašu emailovú shránku \"%{0}\". Ste si istý že veríte všetkým užívateľom?";
|
||||||
|
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
||||||
|
= "Ktorýkoľvek užívateľ tohoto systému bude môcť vidieť Váš kalendár \"%{0}\". Ste si istý že veríte všetkým užívateľom?";
|
||||||
|
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||||
|
= "Potencionálne ktokoľvek na internete bude môcť vidieť Váš kalendár \"%{0}\", napriek tomu že nemá účet v tomto systéme. Sú tieto informácie vhodné pre verejnosť?";
|
||||||
|
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
|
||||||
|
= "Ktorýkoľvek užívateľ tohoto systému bude môcť vidieť Váš adresár \"%{0}\". Ste si istý že veríte všetkým užívateľom?";
|
||||||
|
"Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||||
|
= "Potencionálne ktokoľvek na internete bude môcť vidieť Váš adresár \"%{0}\", napriek tomu že nemá účet v tomto systéme. Sú tieto informácie vhodné pre verejnosť?";
|
||||||
|
"Give Access" = "Daj prístup";
|
||||||
|
"Keep Private" = "Nechaj súkromné";
|
||||||
|
|
||||||
|
/* generic.js */
|
||||||
|
"Unable to subscribe to that folder!"
|
||||||
|
= "Nedá sa prihlásiť k odberu tejto zložky!";
|
||||||
|
"You cannot subscribe to a folder that you own!"
|
||||||
|
= "Nemôžete sa prihlásiť k odberu zložky, ktorú vlastnite!";
|
||||||
|
"Unable to unsubscribe from that folder!"
|
||||||
|
= "Nedá sa odhlásiť z tejto zložky!";
|
||||||
|
"You cannot unsubscribe from a folder that you own!"
|
||||||
|
= "Nemôžete sa odhlásiť zo zložky, ktorú vlastnite!";
|
||||||
|
"Unable to rename that folder!" = "Nemožno premenovať túto zložku!";
|
||||||
|
"You have already subscribed to that folder!"
|
||||||
|
= "Už ste prihlásení k odberu tejto zložky!";
|
||||||
|
"The user rights cannot be edited for this object!"
|
||||||
|
= "Užívateľské práva nemožno upraviť pre tento objekt!";
|
||||||
|
"A folder by that name already exists." = "Zložka s týmto názvom už existuje.";
|
||||||
|
"You cannot create a list in a shared address book."
|
||||||
|
= "Nemôžete vytvoriť zoznam v zdieľanom adresári.";
|
||||||
|
"Warning" = "Varovanie";
|
||||||
|
|
||||||
|
"You are not allowed to access this module or this system. Please contact your system administrator."
|
||||||
|
= "Nemate dovolený prístup k tomuto modulu alebo tento systém. Obráťte sa na správcu systému.";
|
||||||
|
"You don't have the required privileges to perform the operation."
|
||||||
|
= "Nemáte potrebné oprávnenia na vykonanie operácie.";
|
||||||
|
|
||||||
|
"noEmailForDelegation" = "Musíte zadať adresu, na ktorú chcete delegovať vaše pozvanie.";
|
||||||
|
"delegate is organizer" = "Delegát je organizátorom. Zadajte prosím iného delegáta.";
|
||||||
|
"delegate is a participant" = "Delegát je už účastníkom.";
|
||||||
|
"delegate is a group" = "Zadaná adresa zodpovedá skupine. Môžete ju delegovať len na jedinečnú osobu.";
|
||||||
|
|
||||||
|
"Snooze for " = "Odložiť";
|
||||||
|
"5 minutes" = "5 minút";
|
||||||
|
"10 minutes" = "10 minút";
|
||||||
|
"15 minutes" = "15 minút";
|
||||||
|
"30 minutes" = "30 minút";
|
||||||
|
"45 minutes" = "45 minút";
|
||||||
|
"1 hour" = "1 hodinu";
|
||||||
|
|
||||||
|
|
||||||
|
/* common buttons */
|
||||||
|
"OK" = "OK";
|
||||||
|
"Cancel" = "Zrušiť";
|
||||||
|
"Yes" = "Áno";
|
||||||
|
"No" = "Nie";
|
||||||
|
|
||||||
|
/* alarms */
|
||||||
|
"Reminder:" = "Pripomienka:";
|
||||||
|
"Start:" = "Štart:";
|
||||||
|
"Due Date:" = "Splatnosť:";
|
||||||
|
"Location:" = "Umiestnenie:";
|
||||||
|
|
||||||
|
"a2_Sunday" = "Ne";
|
||||||
|
"a2_Monday" = "Po";
|
||||||
|
"a2_Tuesday" = "Ut";
|
||||||
|
"a2_Wednesday" = "St";
|
||||||
|
"a2_Thursday" = "Št";
|
||||||
|
"a2_Friday" = "Pi";
|
||||||
|
"a2_Saturday" = "So";
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue