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.pt_BR = UI/MailerUI/BrazilianPortuguese.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.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.pt_BR = UI/PreferencesUI/BrazilianPortuguese.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.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.pt_BR = UI/Scheduler/BrazilianPortuguese.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.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.pt_BR = UI/Contacts/BrazilianPortuguese.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.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.pt_BR = UI/MainUI/BrazilianPortuguese.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.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.pt_BR = UI/Common/BrazilianPortuguese.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.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.pt_BR = UI/AdministrationUI/BrazilianPortuguese.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.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.pt_BR = SoObjects/Appointments/BrazilianPortuguese.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.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.pt_BR = SoObjects/Contacts/BrazilianPortuguese.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.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.pt_BR = UI/MailPartViewers/BrazilianPortuguese.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.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)
|
||||
------------------
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ libOGoContentStore_LIBRARIES_DEPEND_UPON += \
|
|||
-lNGExtensions \
|
||||
-lEOControl \
|
||||
-lSaxObjC \
|
||||
-lgnustep-base \
|
||||
-lobjc
|
||||
$(BASE_LIBS)
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE -I../SoObjects
|
||||
|
||||
|
@ -29,4 +28,5 @@ test_quick_extract_TOOL_LIBS += \
|
|||
-lNGCards \
|
||||
-lGDLContentStore \
|
||||
-lGDLAccess \
|
||||
-lOGoContentStore
|
||||
-lOGoContentStore \
|
||||
$(BASE_LIBS)
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
- (NSData *) mimeAttachTag;
|
||||
|
||||
/* move & copy operations */
|
||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment;
|
||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
/* subclasses */
|
||||
- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage;
|
||||
|
|
|
@ -152,13 +152,13 @@
|
|||
return ULLONG_MAX;
|
||||
}
|
||||
|
||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment
|
||||
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
void *attachMethod;
|
||||
enum mapistore_error error;
|
||||
MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage;
|
||||
|
||||
[self copyPropertiesToObject: newAttachment];
|
||||
[self copyPropertiesToObject: newAttachment inMemCtx: memCtx];
|
||||
|
||||
attachMethod = NULL;
|
||||
error = [self getProperty: &attachMethod
|
||||
|
@ -170,7 +170,7 @@
|
|||
{
|
||||
embeddedMessage = [self openEmbeddedMessage];
|
||||
newEmbeddedMessage = [newAttachment createEmbeddedMessage];
|
||||
[embeddedMessage copyToMessage: newEmbeddedMessage];
|
||||
[embeddedMessage copyToMessage: newEmbeddedMessage inMemCtx: memCtx];
|
||||
}
|
||||
talloc_free (attachMethod);
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@
|
|||
SOGoAppointmentObject *newEntry;
|
||||
NSString *name;
|
||||
|
||||
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||
|
||||
name = [NSString stringWithFormat: @"%@.ics",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
newEntry = [SOGoAppointmentObject objectWithName: name
|
||||
|
|
|
@ -337,7 +337,18 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
|||
|
||||
- (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
|
||||
|
|
|
@ -123,7 +123,8 @@
|
|||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
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
|
||||
withNewName: (NSString *) newFolderName
|
||||
|
|
|
@ -180,6 +180,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||
|
||||
// [messageKeys release];
|
||||
// [faiMessageKeys release];
|
||||
// [folderKeys release];
|
||||
|
@ -656,19 +658,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
return rc;
|
||||
}
|
||||
|
||||
- (int) moveCopyMessageWithMID: (uint64_t) srcMid
|
||||
// private method
|
||||
- (int) _moveCopyMessageWithMID: (uint64_t) srcMid
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMID: (uint64_t) targetMid
|
||||
andChangeKey: (struct Binary_r *) targetChangeKey
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
int rc;
|
||||
MAPIStoreMessage *sourceMsg, *destMsg;
|
||||
TALLOC_CTX *memCtx;
|
||||
//TALLOC_CTX *memCtx;
|
||||
struct SRow aRow;
|
||||
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
|
||||
withMID: srcMid
|
||||
forWriting: NO
|
||||
|
@ -681,7 +687,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
if (rc != MAPISTORE_SUCCESS)
|
||||
goto end;
|
||||
|
||||
[sourceMsg copyToMessage: destMsg];
|
||||
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
|
||||
|
||||
if (targetChangeKey)
|
||||
{
|
||||
|
@ -698,7 +704,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
|
||||
|
||||
end:
|
||||
talloc_free (memCtx);
|
||||
//talloc_free (memCtx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -709,6 +715,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
int rc = MAPISTORE_SUCCESS;
|
||||
NSUInteger count;
|
||||
|
@ -717,6 +724,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
MAPIStoreMapping *mapping;
|
||||
SOGoUser *ownerUser;
|
||||
struct Binary_r *targetChangeKey;
|
||||
//TALLOC_CTX *memCtx;
|
||||
|
||||
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
|
||||
|
@ -738,11 +748,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
targetChangeKey = targetChangeKeys[count];
|
||||
else
|
||||
targetChangeKey = NULL;
|
||||
rc = [self moveCopyMessageWithMID: srcMids[count]
|
||||
rc = [self _moveCopyMessageWithMID: srcMids[count]
|
||||
fromFolder: sourceFolder
|
||||
withMID: targetMids[count]
|
||||
andChangeKey: targetChangeKey
|
||||
wantCopy: wantCopy];
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
}
|
||||
else
|
||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||
|
@ -766,6 +777,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
else
|
||||
rc = MAPISTORE_ERR_DENIED;
|
||||
|
||||
//talloc_free (memCtx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -785,6 +798,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
NSUInteger count, max;
|
||||
NSString *childKey;
|
||||
uint64_t fmid;
|
||||
TALLOC_CTX *memCtx;
|
||||
|
||||
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
|
||||
/* 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
|
||||
|
@ -807,7 +823,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
if (rc == MAPISTORE_SUCCESS)
|
||||
{
|
||||
newFolder = [targetFolder lookupFolder: childKey];
|
||||
[self copyPropertiesToObject: newFolder];
|
||||
[self copyPropertiesToObject: newFolder inMemCtx: memCtx];
|
||||
|
||||
pool = [NSAutoreleasePool new];
|
||||
children = [self messageKeys];
|
||||
|
@ -818,7 +834,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
message = [self lookupMessage: childKey];
|
||||
targetMessage = [newFolder createMessage: NO];
|
||||
[targetMessage setIsNew: YES];
|
||||
[message copyToMessage: targetMessage];
|
||||
[message copyToMessage: targetMessage inMemCtx: memCtx];
|
||||
if (isMove)
|
||||
{
|
||||
fmid = [mapping idFromURL: [message url]];
|
||||
|
@ -839,7 +855,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
message = [self lookupFAIMessage: childKey];
|
||||
targetMessage = [newFolder createMessage: YES];
|
||||
[targetMessage setIsNew: YES];
|
||||
[message copyToMessage: targetMessage];
|
||||
[message copyToMessage: targetMessage inMemCtx: memCtx];
|
||||
if (isMove)
|
||||
{
|
||||
fmid = [mapping idFromURL: [message url]];
|
||||
|
@ -882,6 +898,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
|||
else
|
||||
rc = MAPISTORE_ERR_DENIED;
|
||||
|
||||
talloc_free (memCtx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -929,6 +929,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
|||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
|
||||
{
|
||||
NGImap4Connection *connection;
|
||||
NGImap4Client *client;
|
||||
|
@ -946,7 +948,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
|||
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
|
||||
fromFolder: sourceFolder withMIDs: targetMids
|
||||
andChangeKeys: targetChangeKeys
|
||||
wantCopy: wantCopy];
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
|
||||
/* Conversion of mids to IMAP uids */
|
||||
mapping = [self mapping];
|
||||
|
|
|
@ -569,7 +569,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
|||
}
|
||||
|
||||
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
|
||||
if (list)
|
||||
if ([list count])
|
||||
[headers setObjects: list forKey: @"from"];
|
||||
}
|
||||
else
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
- (NSArray *) activeUserRoles;
|
||||
|
||||
/* move & copy internal ops */
|
||||
- (void) copyToMessage: (MAPIStoreMessage *) newMessage;
|
||||
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
/* subclasses */
|
||||
- (void) save;
|
||||
|
|
|
@ -139,6 +139,8 @@ rtf2html (NSData *compressedRTF)
|
|||
|
||||
- (id) init
|
||||
{
|
||||
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
|
||||
|
||||
if ((self = [super init]))
|
||||
{
|
||||
attachmentParts = [NSMutableDictionary new];
|
||||
|
@ -151,6 +153,7 @@ rtf2html (NSData *compressedRTF)
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
|
||||
[activeUserRoles release];
|
||||
[attachmentKeys release];
|
||||
[attachmentParts release];
|
||||
|
@ -437,17 +440,19 @@ rtf2html (NSData *compressedRTF)
|
|||
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;
|
||||
NSArray *keys;
|
||||
NSUInteger count, max;
|
||||
NSString *key;
|
||||
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 */
|
||||
[self getMessageData: &messageData inMemCtx: memCtx];
|
||||
|
@ -456,7 +461,7 @@ rtf2html (NSData *compressedRTF)
|
|||
andColumns: messageData->columns];
|
||||
|
||||
/* properties */
|
||||
[self copyPropertiesToObject: newMessage];
|
||||
[self copyPropertiesToObject: newMessage inMemCtx: memCtx];
|
||||
|
||||
/* attachments */
|
||||
keys = [self attachmentKeys];
|
||||
|
@ -466,10 +471,10 @@ rtf2html (NSData *compressedRTF)
|
|||
key = [keys objectAtIndex: count];
|
||||
attachment = [self lookupAttachment: key];
|
||||
newAttachment = [newMessage createAttachment];
|
||||
[attachment copyToAttachment: newAttachment];
|
||||
[attachment copyToAttachment: newAttachment inMemCtx: memCtx];
|
||||
}
|
||||
|
||||
talloc_free (memCtx);
|
||||
//talloc_free (memCtx);
|
||||
}
|
||||
|
||||
- (enum mapistore_error) saveMessage
|
||||
|
@ -485,6 +490,8 @@ rtf2html (NSData *compressedRTF)
|
|||
BOOL userIsOwner;
|
||||
MAPIStoreMessage *mainMessage;
|
||||
|
||||
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||
|
||||
context = [self context];
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
userIsOwner = [[context activeUser] isEqual: ownerUser];
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
/* move and copy operations */
|
||||
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject;
|
||||
- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
/* subclasses */
|
||||
- (NSString *) nameInContainer;
|
||||
|
|
|
@ -317,9 +317,9 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
|||
}
|
||||
|
||||
/* 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 SRow row;
|
||||
enum MAPITAGS propTag;
|
||||
|
@ -328,7 +328,7 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
|||
enum mapistore_error error;
|
||||
void *data;
|
||||
|
||||
memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
|
||||
[self getAvailableProperties: &availableProps inMemCtx: memCtx];
|
||||
|
||||
|
@ -369,8 +369,7 @@ static Class NSExceptionK, MAPIStoreFolderK;
|
|||
}
|
||||
[newObject addPropertiesFromRow: &row];
|
||||
|
||||
talloc_free (memCtx);
|
||||
|
||||
//talloc_free (memCtx);
|
||||
}
|
||||
|
||||
/* subclasses */
|
||||
|
|
|
@ -95,6 +95,7 @@ sogo_backend_init (void)
|
|||
defaults using the system encoding rather than honouring
|
||||
the encoding specified in the file. */
|
||||
putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding");
|
||||
//putenv ("NSZombieEnabled=YES");
|
||||
|
||||
[NSProcessInfo initializeWithArguments: argv
|
||||
count: 1
|
||||
|
@ -567,6 +568,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
|
|||
static enum mapistore_error
|
||||
sogo_folder_move_copy_messages(void *folder_object,
|
||||
void *source_folder_object,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32_t mid_count,
|
||||
uint64_t *src_mids, uint64_t *t_mids,
|
||||
struct Binary_r **target_change_keys,
|
||||
|
@ -594,7 +596,8 @@ sogo_folder_move_copy_messages(void *folder_object,
|
|||
fromFolder: sourceFolder
|
||||
withMIDs: t_mids
|
||||
andChangeKeys: target_change_keys
|
||||
wantCopy: want_copy];
|
||||
wantCopy: want_copy
|
||||
inMemCtx: mem_ctx];
|
||||
[pool release];
|
||||
GSUnregisterCurrentThread ();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ MAPIStoreTallocWrapperDestroy (void *data)
|
|||
GSRegisterCurrentThread ();
|
||||
pool = [NSAutoreleasePool new];
|
||||
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];
|
||||
[pool release];
|
||||
GSUnregisterCurrentThread ();
|
||||
|
@ -66,7 +67,7 @@ MAPIStoreTallocWrapperDestroy (void *data)
|
|||
talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy);
|
||||
wrapper->instance = self;
|
||||
[self retain];
|
||||
// NSLog (@"returning wrapper: %p; object: %p", wrapper, self);
|
||||
NSLog (@"returning wrapper: %p; object: %p", wrapper, self);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
|
|
@ -351,15 +351,12 @@ static GCSStringFormatter *stringFormatter = nil;
|
|||
- (NSString *) _selectedFields: (NSArray *) fields
|
||||
requirement: (GCSTableRequirement) requirement
|
||||
{
|
||||
NSMutableString *selectedFields;
|
||||
NSString *selectedFields;
|
||||
|
||||
selectedFields = [NSMutableString string];
|
||||
|
||||
if (requirement == bothTableRequired
|
||||
&& [fields containsObject: @"c_name"])
|
||||
[selectedFields appendString: [self _dottedFields: fields]];
|
||||
if (requirement == bothTableRequired && [fields containsObject: @"c_name"])
|
||||
selectedFields = [self _dottedFields: fields];
|
||||
else
|
||||
[selectedFields appendString: [fields componentsJoinedByString: @", "]];
|
||||
selectedFields = [fields componentsJoinedByString: @", "];
|
||||
|
||||
return selectedFields;
|
||||
}
|
||||
|
|
|
@ -110,6 +110,14 @@
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *) updateCPathInFolderInfo: (NSString *) tableName
|
||||
withCPath2: (NSString *) c_path2
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
@ -205,6 +213,17 @@
|
|||
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
|
||||
|
||||
//
|
||||
|
@ -299,6 +318,17 @@
|
|||
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
|
||||
|
||||
//
|
||||
|
@ -392,4 +422,15 @@
|
|||
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
|
||||
|
|
|
@ -8,11 +8,12 @@ ADDITIONAL_INCLUDE_DIRS += -I. -I..
|
|||
|
||||
|
||||
# dependencies
|
||||
BASE_LIBS := $(shell gnustep-config --base-libs)
|
||||
|
||||
libGDLContentStore_LIBRARIES_DEPEND_UPON += \
|
||||
-lGDLAccess \
|
||||
-lNGExtensions -lEOControl \
|
||||
-lgnustep-base -lobjc
|
||||
$(BASE_LIBS)
|
||||
|
||||
GDLContentStore_LIBRARIES_DEPEND_UPON += \
|
||||
-framework GDLAccess \
|
||||
|
@ -25,7 +26,7 @@ GCS_TOOL_LIBS += \
|
|||
-lGDLContentStore -lGDLAccess \
|
||||
-lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC \
|
||||
-lgnustep-base
|
||||
$(BASE_LIBS)
|
||||
else
|
||||
GCS_TOOL_LIBS += \
|
||||
-framework GDLContentStore -framework GDLAccess \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
@ -424,16 +424,19 @@
|
|||
}
|
||||
|
||||
static inline BOOL
|
||||
_subValuesAreVoid (NSArray *subValues)
|
||||
_subValuesAreVoid (id subValues)
|
||||
{
|
||||
BOOL result = YES;
|
||||
NSUInteger count, max;
|
||||
|
||||
result = YES;
|
||||
|
||||
if ([subValues isKindOfClass: [NSArray class]])
|
||||
{
|
||||
max = [subValues count];
|
||||
for (count = 0; result && count < max; count++)
|
||||
result = ([[subValues objectAtIndex: count] length] == 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@
|
|||
- (void) replaceThisElement: (CardElement *) oldElement
|
||||
withThisOne: (CardElement *) newElement;
|
||||
|
||||
- (NSArray *) orderOfElements;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* CARDGROUP_H */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
@ -454,4 +454,9 @@ static NGCardsSaxHandler *sax = nil;
|
|||
return new;
|
||||
}
|
||||
|
||||
- (NSArray *) orderOfElements
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
@ -107,6 +107,7 @@
|
|||
CardElement *currentChild;
|
||||
NSMutableString *rendering;
|
||||
NSString *groupTag;
|
||||
NSArray *order;
|
||||
|
||||
rendering = [NSMutableString string];
|
||||
|
||||
|
@ -120,7 +121,36 @@
|
|||
|
||||
groupTag = [groupTag uppercaseString];
|
||||
[rendering appendFormat: @"BEGIN:%@\r\n", groupTag];
|
||||
|
||||
// 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]))
|
||||
[rendering appendString: [self render: currentChild]];
|
||||
[rendering appendFormat: @"END:%@\r\n", groupTag];
|
||||
|
|
|
@ -17,11 +17,13 @@ ADDITIONAL_INCLUDE_DIRS += \
|
|||
|
||||
# dependencies
|
||||
|
||||
BASE_LIBS := $(shell gnustep-config --base-libs)
|
||||
|
||||
libNGCards_LIBRARIES_DEPEND_UPON += \
|
||||
-lNGExtensions \
|
||||
-lEOControl \
|
||||
-lSaxObjC \
|
||||
-lgnustep-base -lobjc -lm
|
||||
$(BASE_LIBS)
|
||||
|
||||
NGCards_LIBRARIES_DEPEND_UPON += \
|
||||
-framework NGExtensions -framework EOControl \
|
||||
|
|
|
@ -38,18 +38,6 @@
|
|||
@class iCalTimeZone;
|
||||
|
||||
@interface iCalCalendar : CardGroup
|
||||
// {
|
||||
// NSString *version;
|
||||
// NSString *calscale;
|
||||
// NSString *prodId;
|
||||
// NSString *method;
|
||||
|
||||
// NSMutableArray *todos;
|
||||
// NSMutableArray *events;
|
||||
// NSMutableArray *journals;
|
||||
// NSMutableArray *freeBusys;
|
||||
// NSMutableDictionary *timezones;
|
||||
// }
|
||||
|
||||
/* accessors */
|
||||
|
||||
|
|
|
@ -210,6 +210,13 @@
|
|||
return [super versitString];
|
||||
}
|
||||
|
||||
- (NSArray *) orderOfElements
|
||||
{
|
||||
return [NSArray arrayWithObjects: @"prodid", @"version", @"method", @"calscale",
|
||||
@"vtimezone", @"vevent", @"vtodo", @"vjournal", @"vfreebusy", nil];
|
||||
}
|
||||
|
||||
|
||||
/* ical typing */
|
||||
|
||||
- (NSString *) entityName
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
@class iCalRecurrenceRule;
|
||||
|
||||
@interface iCalTimeZonePeriod : CardGroup
|
||||
{
|
||||
NSCalendarDate *startDate;
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) startDate;
|
||||
- (iCalRecurrenceRule *) recurrenceRule;
|
||||
|
|
|
@ -103,10 +103,21 @@
|
|||
// return dayOfWeek;
|
||||
// }
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[startDate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) startDate
|
||||
{
|
||||
return [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]
|
||||
if (!startDate)
|
||||
{
|
||||
startDate = [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]
|
||||
dateTime];
|
||||
[startDate retain];
|
||||
}
|
||||
return startDate;
|
||||
}
|
||||
|
||||
- (iCalRecurrenceRule *) recurrenceRule
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
NSTimeInterval anInterval;
|
||||
id grandParent;
|
||||
|
||||
nextAlarmDate = nil;
|
||||
triggerValue = [[self valueType] uppercaseString];
|
||||
if ([triggerValue length] == 0)
|
||||
triggerValue = @"DURATION";
|
||||
|
@ -88,8 +89,6 @@
|
|||
}
|
||||
else if ([triggerValue isEqualToString: @"DATE-TIME"])
|
||||
nextAlarmDate = [[self flattenedValuesForKey: @""] asCalendarDate];
|
||||
else
|
||||
nextAlarmDate = nil;
|
||||
|
||||
return nextAlarmDate;
|
||||
}
|
||||
|
|
|
@ -12,9 +12,11 @@ import sys
|
|||
|
||||
imaphost = '127.0.0.1'
|
||||
imapport = 143
|
||||
|
||||
sambaprivate = '/var/lib/samba/private'
|
||||
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
|
||||
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
|
||||
|
@ -77,15 +79,14 @@ def main():
|
|||
except (shutil.Error, OSError) as e:
|
||||
print "Error during mapistoreCleanup, continuing: %s" % str(e)
|
||||
|
||||
# try:
|
||||
# pass
|
||||
# #ldbCleanup(sambaprivate, username)
|
||||
# except ldb.LdbError as e:
|
||||
# print "Error during ldbCleanup, continuing: %s" % str(e)
|
||||
# try:
|
||||
# pass
|
||||
# #ldbCleanup(sambaprivate, username)
|
||||
# except ldb.LdbError as e:
|
||||
# print "Error during ldbCleanup, continuing: %s" % str(e)
|
||||
|
||||
sqlCleanup(username)
|
||||
|
||||
|
||||
def extractmb(si):
|
||||
inparen = False
|
||||
inquote = False
|
||||
|
@ -133,8 +134,7 @@ def cleanupmb(mb, client):
|
|||
else:
|
||||
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)
|
||||
(code, data) = client.login(username, userpass)
|
||||
if code != "OK":
|
||||
|
@ -142,32 +142,29 @@ def imapCleanup(imaphost, imapport, username, userpass) :
|
|||
|
||||
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, "%")
|
||||
if code == "OK":
|
||||
for si in data:
|
||||
if si is not None:
|
||||
print si
|
||||
continue
|
||||
mb = extractmb(si)
|
||||
cleanupmb(mb, client)
|
||||
client.logout()
|
||||
|
||||
def mapistoreCleanup(mapistorefolder, username):
|
||||
|
||||
# delete the user's folder under the mapistore and under mapistore/SOGo
|
||||
shutil.rmtree("%s/%s" % (mapistorefolder, username), ignore_errors=True)
|
||||
shutil.rmtree("%s/SOGo/%s" % (mapistorefolder, username), ignore_errors=True)
|
||||
|
||||
# NOTYET
|
||||
#def ldbCleanup(sambaprivate, username):
|
||||
# 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" % (username),
|
||||
# scope=ldb.SCOPE_SUBTREE)
|
||||
# for entry in entries:
|
||||
# print "Deleting %s" % (entry.dn)
|
||||
# conn.delete(entry.dn)
|
||||
# NOTYET
|
||||
#def ldbCleanup(sambaprivate, username):
|
||||
# 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" % (username),
|
||||
# scope=ldb.SCOPE_SUBTREE)
|
||||
# for entry in entries:
|
||||
# print "Deleting %s" % (entry.dn)
|
||||
# conn.delete(entry.dn)
|
||||
|
||||
def mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
||||
import MySQLdb
|
||||
|
@ -187,18 +184,50 @@ def postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
|
|||
print "table '%s' emptied" % tablename
|
||||
|
||||
def getOCSFolderInfoURL():
|
||||
global sogoDefaultsFile
|
||||
sogoDefaults = plistlib.readPlist(sogoDefaultsFile)
|
||||
try:
|
||||
OCSFolderInfoURL = sogoDefaults['sogod']['OCSFolderInfoURL']
|
||||
except KeyError:
|
||||
global sogoSysDefaultsFile, sogoUserDefaultsFile
|
||||
|
||||
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):
|
||||
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))
|
||||
|
||||
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
|
||||
|
@ -212,13 +241,14 @@ def sqlCleanup(username):
|
|||
dbname = m.group(6)
|
||||
# 7 is folderinfo table
|
||||
|
||||
encodedUserName = asCSSIdentifier(username)
|
||||
|
||||
if (proto == "postgresql"):
|
||||
postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username)
|
||||
postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, encodedUserName)
|
||||
elif (proto == "mysql"):
|
||||
mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username)
|
||||
mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, encodedUserName)
|
||||
else:
|
||||
raise Exception("Unknown sql proto: " % (proto))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -28,22 +28,22 @@ $plugins
|
|||
= array(
|
||||
"sogo-connector@inverse.ca"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "10.0.3",
|
||||
"filename" => "sogo-connector-10.0.3.xpi" ),
|
||||
"version" => "17.0.2",
|
||||
"filename" => "sogo-connector-17.0.2.xpi" ),
|
||||
"sogo-integrator@inverse.ca"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "10.0.3",
|
||||
"filename" => "sogo-integrator-10.0.3.xpi" ),
|
||||
"version" => "17.0.2",
|
||||
"filename" => "sogo-integrator-17.0.2.xpi" ),
|
||||
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "1.2.3",
|
||||
"filename" => "lightning.xpi" )
|
||||
"version" => "1.9",
|
||||
"filename" => "lightning-1.9.xpi" )
|
||||
);
|
||||
|
||||
$applications
|
||||
= array( "thunderbird" => "<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
|
||||
<em:minVersion>10.0</em:minVersion>
|
||||
<em:maxVersion>10.*</em:maxVersion>" );
|
||||
<em:minVersion>17.0</em:minVersion>
|
||||
<em:maxVersion>17.*</em:maxVersion>" );
|
||||
|
||||
$pluginname = $_GET["plugin"];
|
||||
$plugin =& $plugins[$pluginname];
|
||||
|
|
|
@ -8,23 +8,15 @@ vtodo_class1 = "(Tarefa Privada)";
|
|||
vtodo_class2 = "(Tarefa Confidencial)";
|
||||
|
||||
/* Receipts */
|
||||
"Title:" = "Título:";
|
||||
"Start:" = "Início:";
|
||||
"End:" = "Fim:";
|
||||
|
||||
"Receipt: users invited to a meeting" = "Recepção: usuários convidados para uma reunião";
|
||||
"You have invited the following attendees(s):" = "Você convidou o(s) seguinte(s) participante(s):";
|
||||
"... 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:";
|
||||
"The event \"%{Summary}\" was created" = "O evento \"%{Summary}\" foi criado";
|
||||
"The event \"%{Summary}\" was deleted" = "O evento \"%{Summary}\" foi removido";
|
||||
"The event \"%{Summary}\" was updated" = "O evento \"%{Summary}\" foi atualizado";
|
||||
"The following attendees(s) were notified:" = "Estes participantes foram notificados:";
|
||||
"The following attendees(s) were added:" = "Estes participantes foram adicionados:";
|
||||
"The following attendees(s) were removed:" = "Estes participantes foram removidos:";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendário:";
|
||||
"startDate_label" = "Início:";
|
||||
"endDate_label" = "Fim:";
|
||||
"due_label" = "Data de Vencimento:";
|
||||
|
@ -35,14 +27,19 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
|||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "Convite do Evento: \"%{Summary}\"";
|
||||
"(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}";
|
||||
|
||||
/* Deletion */
|
||||
"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} cancelou este evento: %{Summary}.\n\nInício: %{StartDate} as %{StartTime}\nFim: %{EndDate} as %{EndTime}\nDescrição: %{Description}";
|
||||
|
||||
/* 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"
|
||||
= "O Compromisso \"%{Summary}\" de %{OldStartDate} as %{OldStartTime} mudou";
|
||||
"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.";
|
||||
|
||||
/* 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}foi aceitado seu convite ao evento.";
|
||||
"%{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.";
|
||||
|
||||
/* 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
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -28,14 +28,14 @@ vtodo_class2 = "(Zadanie poufne)";
|
|||
"Event Invitation: \"%{Summary}\"" = "Zaproszenie na wydarzenie: \"%{Summary}\"";
|
||||
"(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} 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 */
|
||||
"Event Cancelled: \"%{Summary}\"" = "Wydarzenie anulowane: \"%{Summary}\"";
|
||||
"%{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}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 */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
|
|
|
@ -2885,11 +2885,26 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
timezone: (iCalTimeZone *) timezone
|
||||
{
|
||||
SOGoAppointmentObject *object;
|
||||
NSString *uid;
|
||||
NSMutableString *content;
|
||||
NSString *uid;
|
||||
|
||||
uid = [self globallyUniqueObjectId];
|
||||
[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
|
||||
inContainer: self];
|
||||
[object setIsNew: YES];
|
||||
|
@ -3024,7 +3039,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
acquire: NO];
|
||||
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 addToEvents: event];
|
||||
if (timezone)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* SOGoAppointmentFolderICS.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2010-2012 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,6 +20,7 @@
|
|||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/CardElement.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
|
||||
#import "SOGoAppointmentFolderICS.h"
|
||||
|
@ -30,7 +29,19 @@
|
|||
|
||||
- (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
|
||||
|
|
|
@ -410,14 +410,6 @@
|
|||
previousObject: oldEvent
|
||||
toAttendees: updateAttendees
|
||||
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 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
|
||||
// the attendee, we add the user to the SENT-BY attribute.
|
||||
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
|
||||
// participation state has changed.
|
||||
|
@ -1063,6 +1059,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
|| [currentStatus caseInsensitiveCompare: newStatus]
|
||||
!= NSOrderedSame)
|
||||
{
|
||||
NSMutableArray *delegates;
|
||||
NSString *delegatedUID;
|
||||
|
||||
delegatedUID = nil;
|
||||
[attendee setPartStat: newStatus];
|
||||
|
||||
// If one has accepted / declined an invitation on behalf of
|
||||
|
@ -1087,9 +1087,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
|
||||
[attendee setDelegatedTo: [delegate email]];
|
||||
|
||||
NSString *delegatedUID = nil;
|
||||
NSMutableArray *delegates;
|
||||
|
||||
if (removeDelegate)
|
||||
{
|
||||
delegates = [NSMutableArray array];
|
||||
|
@ -1123,13 +1120,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
previousObject: nil
|
||||
toAttendees: delegates
|
||||
withType: @"calendar:cancellation"];
|
||||
#if 0
|
||||
// DELETE CODE
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
||||
forObject: event
|
||||
to: delegates];
|
||||
#endif
|
||||
}
|
||||
} // if (removeDelegate)
|
||||
|
||||
if (addDelegate)
|
||||
{
|
||||
|
@ -1148,12 +1139,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
previousObject: nil
|
||||
toAttendees: delegates
|
||||
withType: @"calendar:invitation"];
|
||||
#if 0
|
||||
// DELETE CODE
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
||||
forObject: event to: delegates];
|
||||
#endif
|
||||
}
|
||||
} // if (addDelegate)
|
||||
|
||||
// If the current user isn't the organizer of the event
|
||||
// that has just been updated, we update the event and
|
||||
|
@ -1161,8 +1147,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
ownerUser = [SOGoUser userWithLogin: owner];
|
||||
if (!(ex || [event userIsOrganizer: ownerUser]))
|
||||
{
|
||||
if ([[attendee rsvp] isEqualToString: @"true"]
|
||||
&& [event isStillRelevant])
|
||||
if ([event isStillRelevant])
|
||||
[self sendResponseToOrganizer: event
|
||||
from: ownerUser];
|
||||
|
||||
|
@ -1372,22 +1357,22 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
reason: @"delegate is a group"];
|
||||
}
|
||||
if (ex == nil)
|
||||
{
|
||||
// Remove the RSVP attribute, as an action from the attendee
|
||||
// was actually performed, and this confuses iCal (bug #1850)
|
||||
[[attendee attributes] removeObjectForKey: @"RSVP"];
|
||||
ex = [self _handleAttendee: attendee
|
||||
withDelegate: delegate
|
||||
ownerUser: ownerUser
|
||||
statusChange: _status
|
||||
inEvent: event];
|
||||
}
|
||||
if (ex == nil)
|
||||
{
|
||||
// We generate the updated iCalendar file and we save it in
|
||||
// the database. We do this ONLY when using SOGo from the
|
||||
// Web interface. Over DAV, it'll be handled directly in
|
||||
// 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])
|
||||
ex = [self saveContentString: [calendar versitString]];
|
||||
}
|
||||
|
@ -1944,6 +1929,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
|||
return [NSException exceptionWithHTTPStatus:403
|
||||
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;
|
||||
delegateEmail = [attendee delegatedTo];
|
||||
|
|
|
@ -725,7 +725,8 @@
|
|||
header = [NSString stringWithFormat: @"text/calendar; 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: @"quoted-printable"
|
||||
forKey: @"content-transfer-encoding"];
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
- (NSArray *) davCalendarUserAddressSet;
|
||||
- (NSArray *) davCalendarHomeSet;
|
||||
- (NSArray *) davCalendarScheduleInboxURL;
|
||||
- (NSArray *) davCalendarScheduleOutboxURL;
|
||||
|
||||
@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:";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "Invitación al evento: \"% {Summary}\"";
|
||||
"Event Invitation: \"%{Summary}\"" = "Invitación al evento: \"%{Summary}\"";
|
||||
"(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} 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 */
|
||||
"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}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}"
|
||||
|
|
|
@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
|
|||
Contacts_RESOURCE_FILES += \
|
||||
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
|
||||
|
||||
|
|
|
@ -216,11 +216,12 @@ convention:
|
|||
|
||||
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord
|
||||
{
|
||||
CardElement *element;
|
||||
NSArray *units;
|
||||
NSInteger year, yearOfToday, month, day;
|
||||
CardElement *element;
|
||||
NSCalendarDate *now;
|
||||
NSArray *units;
|
||||
NSString *ou;
|
||||
id o;
|
||||
|
||||
[self setNWithFamily: [ldifRecord objectForKey: @"sn"]
|
||||
given: [ldifRecord objectForKey: @"givenname"]
|
||||
|
@ -303,7 +304,15 @@ convention:
|
|||
forKey: @""];
|
||||
|
||||
[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];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
|
|
@ -191,6 +191,10 @@ static NSArray *folderListingFields = nil;
|
|||
qs = [NSString stringWithFormat:
|
||||
@"(c_categories isCaseInsensitiveLike: '%%%@%%')",
|
||||
filter];
|
||||
else if ([criteria isEqualToString: @"organization"])
|
||||
qs = [NSString stringWithFormat:
|
||||
@"(c_o isCaseInsensitiveLike: '%%%@%%')",
|
||||
filter];
|
||||
else
|
||||
qs = @"(1 == 0)";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
* 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
|
||||
|
||||
This file is part of SOGo.
|
||||
|
@ -269,7 +269,7 @@ static NSString *userAgent = nil;
|
|||
{
|
||||
id headerValue;
|
||||
unsigned int count;
|
||||
NSString *messageID, *priority, *pureSender,*replyTo;
|
||||
NSString *messageID, *priority, *pureSender, *replyTo;
|
||||
|
||||
for (count = 0; count < 8; count++)
|
||||
{
|
||||
|
@ -314,8 +314,8 @@ static NSString *userAgent = nil;
|
|||
if ([replyTo length] > 0)
|
||||
{
|
||||
[headers setObject: replyTo forKey: @"reply-to"];
|
||||
[headers removeObjectForKey: @"replyTo"];
|
||||
}
|
||||
[headers removeObjectForKey: @"replyTo"];
|
||||
|
||||
if ([[newHeaders objectForKey: @"receipt"] isEqualToString: @"true"])
|
||||
{
|
||||
|
@ -804,8 +804,8 @@ static NSString *userAgent = nil;
|
|||
- (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail
|
||||
{
|
||||
NSDictionary *info, *attachment;
|
||||
NSString *signature, *nl;
|
||||
SOGoUserDefaults *ud;
|
||||
NSString *signature;
|
||||
|
||||
[sourceMail fetchCoreInfos];
|
||||
|
||||
|
@ -832,10 +832,13 @@ static NSString *userAgent = nil;
|
|||
else
|
||||
{
|
||||
// TODO: use subject for filename?
|
||||
// error = [newDraft saveAttachment:content withName:@"forward.eml"];
|
||||
// error = [newDraft saveAttachment:content withName:@"forward.eml"];
|
||||
signature = [[self mailAccountFolder] signature];
|
||||
if ([signature length])
|
||||
[self setText: [NSString stringWithFormat: @"\n-- \n%@", signature]];
|
||||
{
|
||||
nl = (isHTML ? @"<br/>" : @"\n");
|
||||
[self setText: [NSString stringWithFormat: @"%@-- %@%@", nl, nl, signature]];
|
||||
}
|
||||
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[sourceMail filenameForForward], @"filename",
|
||||
@"message/rfc822", @"mimetype",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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>
|
||||
*
|
||||
|
@ -226,11 +226,15 @@
|
|||
|
||||
- (NSString *) signature
|
||||
{
|
||||
NSString *signature, *mailSignature;
|
||||
NSString *signature, *mailSignature, *nl;
|
||||
|
||||
signature = [[sourceMail mailAccountFolder] signature];
|
||||
|
||||
if ([signature length])
|
||||
mailSignature = [NSString stringWithFormat: @"-- \n%@", signature];
|
||||
{
|
||||
nl = (htmlComposition ? @"<br/>" : @"\n");
|
||||
mailSignature = [NSString stringWithFormat: @"-- %@%@", nl, signature];
|
||||
}
|
||||
else
|
||||
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 \
|
||||
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)
|
||||
|
||||
LIBRARY_NAME += \
|
||||
|
|
|
@ -24,7 +24,8 @@ SOGo_LIBRARIES_DEPEND_UPON += \
|
|||
-lNGStreams -lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC \
|
||||
-lNGLdap -lSBJson \
|
||||
-lGDLContentStore -lgnustep-base -lobjc -ldl
|
||||
-lGDLContentStore \
|
||||
$(BASE_LIBS)
|
||||
|
||||
ifeq ($(HAS_LIBRARY_gnutls),yes)
|
||||
ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1
|
||||
|
@ -36,6 +37,11 @@ SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
|
|||
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)
|
||||
SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
|
||||
else
|
||||
|
|
|
@ -62,8 +62,11 @@
|
|||
NSString *IDField; // the first part of a user DN
|
||||
NSString *CNField;
|
||||
NSString *UIDField;
|
||||
NSArray *mailFields, *searchFields;
|
||||
NSString *IMAPHostField, *IMAPLoginField;
|
||||
NSArray *mailFields;
|
||||
NSArray *searchFields;
|
||||
NSString *IMAPHostField;
|
||||
NSString *IMAPLoginField;
|
||||
NSString *SieveHostField;
|
||||
NSArray *bindFields;
|
||||
|
||||
BOOL listRequiresDot;
|
||||
|
@ -110,6 +113,7 @@
|
|||
searchFields: (NSArray *) newSearchFields
|
||||
IMAPHostField: (NSString *) newIMAPHostField
|
||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||
SieveHostField: (NSString *) newSieveHostField
|
||||
bindFields: (id) newBindFields
|
||||
kindField: (NSString *) newKindField
|
||||
andMultipleBookingsField: (NSString *) newMultipleBookingsField;
|
||||
|
|
|
@ -107,6 +107,7 @@ static Class NSStringK;
|
|||
[searchFields retain];
|
||||
IMAPHostField = nil;
|
||||
IMAPLoginField = nil;
|
||||
SieveHostField = nil;
|
||||
bindFields = nil;
|
||||
_scope = @"sub";
|
||||
_filter = nil;
|
||||
|
@ -149,6 +150,7 @@ static Class NSStringK;
|
|||
[searchFields release];
|
||||
[IMAPHostField release];
|
||||
[IMAPLoginField release];
|
||||
[SieveHostField release];
|
||||
[bindFields release];
|
||||
[_filter release];
|
||||
[_userPasswordAlgorithm release];
|
||||
|
@ -194,6 +196,7 @@ static Class NSStringK;
|
|||
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
||||
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
||||
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
||||
SieveHostField: [udSource objectForKey: @"SieveHostFieldName"]
|
||||
bindFields: [udSource objectForKey: @"bindFields"]
|
||||
kindField: [udSource objectForKey: @"KindFieldName"]
|
||||
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
|
||||
|
@ -311,6 +314,7 @@ static Class NSStringK;
|
|||
searchFields: (NSArray *) newSearchFields
|
||||
IMAPHostField: (NSString *) newIMAPHostField
|
||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||
SieveHostField: (NSString *) newSieveHostField
|
||||
bindFields: (id) newBindFields
|
||||
kindField: (NSString *) newKindField
|
||||
andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
|
@ -326,6 +330,8 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
|||
ASSIGN(IMAPHostField, [newIMAPHostField lowercaseString]);
|
||||
if (newIMAPLoginField)
|
||||
ASSIGN(IMAPLoginField, [newIMAPLoginField lowercaseString]);
|
||||
if (newSieveHostField)
|
||||
ASSIGN(SieveHostField, [newSieveHostField lowercaseString]);
|
||||
if (newMailFields)
|
||||
ASSIGN(mailFields, newMailFields);
|
||||
if (newSearchFields)
|
||||
|
@ -586,7 +592,10 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
|||
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
||||
|
||||
if (pass == nil)
|
||||
{
|
||||
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
||||
}
|
||||
|
@ -629,13 +638,20 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
|||
NGLdapModification *mod;
|
||||
NGLdapAttribute *attr;
|
||||
NSArray *changes;
|
||||
NSString* encryptedPass;
|
||||
|
||||
attr = [[NGLdapAttribute alloc] initWithAttributeName: @"userPassword"];
|
||||
if ([_userPasswordAlgorithm isEqualToString: @"none"])
|
||||
[attr addStringValue: newPassword];
|
||||
{
|
||||
encryptedPass = newPassword;
|
||||
}
|
||||
else
|
||||
[attr addStringValue: [self _encryptPassword: newPassword]];
|
||||
|
||||
{
|
||||
encryptedPass = [self _encryptPassword: newPassword];
|
||||
}
|
||||
if(encryptedPass != nil)
|
||||
{
|
||||
[attr addStringValue: encryptedPass];
|
||||
mod = [NGLdapModification replaceModification: attr];
|
||||
changes = [NSArray arrayWithObject: mod];
|
||||
*perr = PolicyNoError;
|
||||
|
@ -643,11 +659,14 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
|||
if ([bindConnection bindWithMethod: @"simple"
|
||||
binddn: userDN
|
||||
credentials: oldPassword])
|
||||
{
|
||||
didChange = [bindConnection modifyEntryWithDN: userDN
|
||||
changes: changes];
|
||||
}
|
||||
else
|
||||
didChange = NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
didChange = [bindConnection changePasswordAtDn: userDN
|
||||
oldPassword: oldPassword
|
||||
|
@ -835,6 +854,13 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
|||
if ([ldapValue length] > 0)
|
||||
[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
|
||||
|
@ -1596,6 +1622,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
|||
searchFields: nil
|
||||
IMAPHostField: nil
|
||||
IMAPLoginField: nil
|
||||
SieveHostField: nil
|
||||
bindFields: nil
|
||||
kindField: nil
|
||||
andMultipleBookingsField: nil];
|
||||
|
|
|
@ -56,7 +56,7 @@ typedef enum {
|
|||
- (NSString *) asSHA1String;
|
||||
- (NSString *) asMD5String;
|
||||
|
||||
+ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme;
|
||||
+ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -71,8 +71,7 @@
|
|||
{
|
||||
NSString *scheme;
|
||||
NSString *pass;
|
||||
NSArray *schemeComps;
|
||||
keyEncoding encoding;
|
||||
NSArray *encodingAndScheme;
|
||||
|
||||
NSRange range;
|
||||
int selflen, len;
|
||||
|
@ -88,32 +87,11 @@
|
|||
if (len == 0)
|
||||
scheme = defaultScheme;
|
||||
|
||||
encoding = [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;
|
||||
}
|
||||
}
|
||||
encodingAndScheme = [NSString getDefaultEncodingForScheme: scheme];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,8 +186,10 @@
|
|||
*
|
||||
* @param passwordScheme The scheme to use
|
||||
* @param theSalt The binary data of the salt
|
||||
* @param userEncoding The encoding (plain, hex, base64) to be used
|
||||
* @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
|
||||
* @param userEncoding The encoding (plain, hex, base64) to be used. If set to
|
||||
* 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
|
||||
withSalt: (NSData *) theSalt
|
||||
|
@ -217,6 +197,22 @@
|
|||
{
|
||||
keyEncoding dataEncoding;
|
||||
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
|
||||
cryptedData = [self dataUsingEncoding: NSUTF8StringEncoding];
|
||||
cryptedData = [cryptedData asCryptedPassUsingScheme: passwordScheme withSalt: theSalt];
|
||||
|
@ -224,12 +220,6 @@
|
|||
if (cryptedData == nil)
|
||||
return nil;
|
||||
|
||||
// use default encoding scheme, when set to default
|
||||
if (userEncoding == encDefault)
|
||||
dataEncoding = [NSString getDefaultEncodingForScheme: passwordScheme];
|
||||
else
|
||||
dataEncoding = userEncoding;
|
||||
|
||||
if (dataEncoding == encHex)
|
||||
{
|
||||
// hex encoding
|
||||
|
@ -250,19 +240,49 @@
|
|||
/**
|
||||
* 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
|
||||
* @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
|
||||
if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
|
||||
[passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
|
||||
[passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame ||
|
||||
[passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
|
||||
{
|
||||
return encHex;
|
||||
encoding = encHex;
|
||||
}
|
||||
else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame ||
|
||||
[passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame ||
|
||||
|
@ -272,9 +292,9 @@
|
|||
[passwordScheme caseInsensitiveCompare: @"sha512"] == 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++;
|
||||
|
||||
length = [self length];
|
||||
// In [UIxMailPartTextViewer flatContentAsString], we first escape HTML entities and then
|
||||
// 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;
|
||||
|
||||
length = [self length] - start;
|
||||
workRange = NSMakeRange (start, length);
|
||||
length -= start;
|
||||
workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
|
||||
options: NSLiteralSearch range: workRange];
|
||||
options: NSLiteralSearch range: NSMakeRange (start, length)];
|
||||
if (workRange.location != NSNotFound)
|
||||
length = workRange.location - start;
|
||||
while
|
||||
|
|
|
@ -111,6 +111,11 @@
|
|||
- (void) setCASPGTId: (NSString *) pgtId
|
||||
forPGTIOU: (NSString *) pgtIou;
|
||||
|
||||
// SAML2 support
|
||||
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
|
||||
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
||||
forIdentifier: (NSString *) identifier;
|
||||
|
||||
//
|
||||
// ACL caching support
|
||||
//
|
||||
|
|
|
@ -520,6 +520,27 @@ static memcached_st *handle = NULL;
|
|||
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
|
||||
//
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
SOGoSupportedLanguages = ( "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
|
||||
"SpanishSpain", "SpanishArgentina", "French", "German",
|
||||
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian",
|
||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",
|
||||
"Ukrainian", "Swedish" );
|
||||
|
||||
SOGoTimeZone = "UTC";
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
mailingMechanism = nil;
|
||||
}
|
||||
|
||||
return mailingMechanism;
|
||||
return [mailingMechanism lowercaseString];
|
||||
}
|
||||
|
||||
- (NSArray *) mailPollingIntervals
|
||||
|
@ -220,7 +220,7 @@
|
|||
|
||||
- (NSString *) smtpAuthenticationType
|
||||
{
|
||||
return [self stringForKey: @"SOGoSMTPAuthenticationType"];
|
||||
return [[self stringForKey: @"SOGoSMTPAuthenticationType"] lowercaseString];
|
||||
}
|
||||
|
||||
- (NSString *) mailSpoolPath
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* SOGoGCSFolder.m - this file is part of SOGo
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
|
@ -835,7 +835,7 @@ static NSArray *childRecordFields = nil;
|
|||
- (BOOL) subscribeUserOrGroup: (NSString *) theIdentifier
|
||||
reallyDo: (BOOL) reallyDo
|
||||
{
|
||||
NSMutableDictionary *moduleSettings;
|
||||
NSMutableDictionary *moduleSettings, *folderShowAlarms;
|
||||
NSMutableArray *folderSubscription;
|
||||
NSString *subscriptionPointer;
|
||||
NSMutableArray *allUsers;
|
||||
|
@ -887,6 +887,8 @@ static NSArray *childRecordFields = nil;
|
|||
= [moduleSettings objectForKey: @"SubscribedFolders"];
|
||||
subscriptionPointer = [self folderReference];
|
||||
|
||||
folderShowAlarms = [moduleSettings objectForKey: @"FolderShowAlarms"];
|
||||
|
||||
if (reallyDo)
|
||||
{
|
||||
if (!(folderSubscription
|
||||
|
@ -897,14 +899,26 @@ static NSArray *childRecordFields = nil;
|
|||
forKey: @"SubscribedFolders"];
|
||||
}
|
||||
|
||||
if (!(folderShowAlarms
|
||||
&& [folderShowAlarms isKindOfClass: [NSMutableDictionary class]]))
|
||||
{
|
||||
folderShowAlarms = [NSMutableDictionary dictionary];
|
||||
[moduleSettings setObject: folderShowAlarms
|
||||
forKey: @"FolderShowAlarms"];
|
||||
}
|
||||
|
||||
[folderSubscription addObjectUniquely: subscriptionPointer];
|
||||
|
||||
// By default, we disable alarms on subscribed calendars
|
||||
[folderShowAlarms setObject: [NSNumber numberWithBool: NO]
|
||||
forKey: subscriptionPointer];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self removeFolderSettings: moduleSettings
|
||||
withReference: subscriptionPointer];
|
||||
[folderSubscription removeObject: subscriptionPointer];
|
||||
|
||||
[folderShowAlarms removeObjectForKey: subscriptionPointer];
|
||||
}
|
||||
|
||||
[us synchronize];
|
||||
|
|
|
@ -69,6 +69,11 @@
|
|||
#import <NGLdap/NGLdapAttribute.h>
|
||||
#import <NGLdap/NGLdapEntry.h>
|
||||
|
||||
#define CHECK_CLASS(o) ({ \
|
||||
if ([o isKindOfClass: [NSString class]]) \
|
||||
o = [NSArray arrayWithObject: o]; \
|
||||
})
|
||||
|
||||
@implementation SOGoGroup
|
||||
|
||||
- (id) initWithIdentifier: (NSString *) theID
|
||||
|
@ -232,14 +237,17 @@
|
|||
// Fetch "members" - we get DNs
|
||||
d = [_entry asDictionary];
|
||||
o = [d objectForKey: @"member"];
|
||||
CHECK_CLASS(o);
|
||||
if (o) [dns addObjectsFromArray: o];
|
||||
|
||||
// Fetch "uniqueMembers" - we get DNs
|
||||
o = [d objectForKey: @"uniquemember"];
|
||||
CHECK_CLASS(o);
|
||||
if (o) [dns addObjectsFromArray: o];
|
||||
|
||||
// Fetch "memberUid" - we get UID (like login names)
|
||||
o = [d objectForKey: @"memberuid"];
|
||||
CHECK_CLASS(o);
|
||||
if (o) [uids addObjectsFromArray: o];
|
||||
|
||||
c = [dns count] + [uids count];
|
||||
|
|
|
@ -1236,7 +1236,7 @@
|
|||
- (SOGoWebDAVValue *) davCurrentUserPrincipal
|
||||
{
|
||||
NSDictionary *userHREF;
|
||||
NSString *login;
|
||||
NSString *login, *s;
|
||||
SOGoUser *activeUser;
|
||||
SOGoWebDAVValue *davCurrentUserPrincipal;
|
||||
|
||||
|
@ -1246,7 +1246,8 @@
|
|||
davCurrentUserPrincipal = nil;
|
||||
else
|
||||
{
|
||||
userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, [self davURLAsString]);
|
||||
s = [NSString stringWithFormat: @"/SOGo/dav/%@", login];
|
||||
userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, s);
|
||||
davCurrentUserPrincipal
|
||||
= [davElementWithContent (@"current-user-principal",
|
||||
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
|
||||
domain: (NSString **) theDomain
|
||||
password: (NSString **) thePassword;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "SOGoCache.h"
|
||||
|
||||
#import <NGObjWeb/WOCookie.h>
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSData.h>
|
||||
|
|
|
@ -51,7 +51,7 @@ static NSMutableDictionary *fieldTypes = nil;
|
|||
static NSDictionary *sieveFields = nil;
|
||||
static NSDictionary *sieveFlags = nil;
|
||||
static NSDictionary *operatorRequirements = nil;
|
||||
static NSDictionary *methodRequirements = nil;
|
||||
static NSMutableDictionary *methodRequirements = nil;
|
||||
static NSString *sieveScriptName = @"sogo";
|
||||
|
||||
|
||||
|
@ -188,7 +188,7 @@ static NSString *sieveScriptName = @"sogo";
|
|||
if (!methodRequirements)
|
||||
{
|
||||
methodRequirements
|
||||
= [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
= [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
@"imapflags", @"addflag",
|
||||
@"imapflags", @"removeflag",
|
||||
@"imapflags", @"flag",
|
||||
|
@ -615,8 +615,8 @@ static NSString *sieveScriptName = @"sogo";
|
|||
SOGoUserDefaults *ud;
|
||||
SOGoDomainDefaults *dd;
|
||||
NGSieveClient *client;
|
||||
NSString *filterScript, *v, *sieveServer;
|
||||
NSURL *url;
|
||||
NSString *filterScript, *v, *sieveServer, *sieveScheme, *sieveQuery, *imapServer;
|
||||
NSURL *url, *cUrl;
|
||||
|
||||
int sievePort;
|
||||
BOOL b, connected;
|
||||
|
@ -631,6 +631,115 @@ static NSString *sieveScriptName = @"sogo";
|
|||
connected = YES;
|
||||
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];
|
||||
|
||||
// We first handle filters
|
||||
|
@ -646,6 +755,7 @@ static NSString *sieveScriptName = @"sogo";
|
|||
else
|
||||
{
|
||||
NSLog(@"Sieve generation failure: %@", [self lastScriptError]);
|
||||
[client closeConnection];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -726,87 +836,6 @@ static NSString *sieveScriptName = @"sogo";
|
|||
[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
|
||||
its deletion from the server. */
|
||||
|
|
|
@ -76,6 +76,13 @@
|
|||
- (NSString *) CASServiceURL;
|
||||
- (BOOL) CASLogoutEnabled;
|
||||
|
||||
- (NSString *) SAML2PrivateKeyLocation;
|
||||
- (NSString *) SAML2CertificateLocation;
|
||||
- (NSString *) SAML2IdpMetadataLocation;
|
||||
- (NSString *) SAML2IdpPublicKeyLocation;
|
||||
- (NSString *) SAML2IdpCertificateLocation;
|
||||
- (BOOL) SAML2LogoutEnabled;
|
||||
|
||||
- (BOOL) enablePublicAccess;
|
||||
|
||||
@end
|
||||
|
|
|
@ -379,7 +379,15 @@ _injectConfigurationFromFile (NSUserDefaults *ud,
|
|||
|
||||
- (NSArray *) supportedLanguages
|
||||
{
|
||||
return [self stringArrayForKey: @"SOGoSupportedLanguages"];
|
||||
static NSArray *supportedLanguages = nil;
|
||||
|
||||
if (!supportedLanguages)
|
||||
{
|
||||
supportedLanguages = [self stringArrayForKey: @"SOGoSupportedLanguages"];
|
||||
[supportedLanguages retain];
|
||||
}
|
||||
|
||||
return supportedLanguages;
|
||||
}
|
||||
|
||||
- (BOOL) userCanChangePassword
|
||||
|
@ -417,6 +425,37 @@ _injectConfigurationFromFile (NSUserDefaults *ud,
|
|||
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
|
||||
{
|
||||
return [self boolForKey: @"SOGoEnablePublicAccess"];
|
||||
|
|
|
@ -576,13 +576,13 @@
|
|||
|
||||
- (void) _appendSystemMailAccount
|
||||
{
|
||||
NSString *fullName, *replyTo, *imapLogin, *imapServer, *signature,
|
||||
*encryption, *scheme, *action, *query, *customEmail;
|
||||
NSString *fullName, *replyTo, *imapLogin, *imapServer, *cImapServer, *signature,
|
||||
*encryption, *scheme, *action, *query, *customEmail, *sieveServer;
|
||||
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
|
||||
NSNumber *port;
|
||||
NSMutableArray *identities;
|
||||
NSArray *mails;
|
||||
NSURL *url;
|
||||
NSURL *url, *cUrl;
|
||||
unsigned int count, max;
|
||||
NSInteger defaultPort;
|
||||
|
||||
|
@ -606,16 +606,22 @@
|
|||
// imaps://localhost:143/?tls=YES
|
||||
// imaps://localhost/?tls=YES
|
||||
|
||||
imapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
||||
if (!imapServer)
|
||||
cImapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
||||
imapServer = [[self domainDefaults] imapServer];
|
||||
cUrl = [NSURL URLWithString: (cImapServer ? cImapServer : @"")];
|
||||
url = [NSURL URLWithString: imapServer];
|
||||
if ([url host])
|
||||
if([cUrl host])
|
||||
imapServer = [cUrl host];
|
||||
else
|
||||
if(cImapServer)
|
||||
imapServer = cImapServer;
|
||||
else
|
||||
if([url host])
|
||||
imapServer = [url host];
|
||||
[mailAccount setObject: imapServer forKey: @"serverName"];
|
||||
|
||||
// 3. port & encryption
|
||||
scheme = [url scheme];
|
||||
scheme = [cUrl scheme] ? [cUrl scheme] : [url scheme];
|
||||
if (scheme
|
||||
&& [scheme caseInsensitiveCompare: @"imaps"] == NSOrderedSame)
|
||||
{
|
||||
|
@ -624,19 +630,28 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
query = [url query];
|
||||
query = [cUrl query] ? [cUrl query] : [url query];
|
||||
if (query && [query caseInsensitiveCompare: @"tls=YES"] == NSOrderedSame)
|
||||
encryption = @"tls";
|
||||
else
|
||||
encryption = @"none";
|
||||
defaultPort = 143;
|
||||
}
|
||||
port = [url port];
|
||||
port = [cUrl port] ? [cUrl port] : [url port];
|
||||
if ([port intValue] == 0) /* port is nil or intValue == 0 */
|
||||
port = [NSNumber numberWithInt: defaultPort];
|
||||
[mailAccount setObject: port forKey: @"port"];
|
||||
[mailAccount setObject: encryption forKey: @"encryption"];
|
||||
|
||||
// Sieve server
|
||||
sieveServer = [self _fetchFieldForUser: @"c_sievehostname"];
|
||||
|
||||
if (sieveServer)
|
||||
{
|
||||
[mailAccount setObject: sieveServer forKey: @"sieveServerName"];
|
||||
}
|
||||
|
||||
|
||||
/* identities */
|
||||
identities = [NSMutableArray new];
|
||||
mails = [self allEmails];
|
||||
|
|
|
@ -35,6 +35,9 @@ extern NSString *SOGoWeekStartFirst4DayWeek;
|
|||
extern NSString *SOGoWeekStartFirstFullWeek;
|
||||
|
||||
@interface SOGoUserDefaults : SOGoDefaultsSource
|
||||
{
|
||||
NSString *userLanguage;
|
||||
}
|
||||
|
||||
+ (SOGoUserDefaults *) defaultsForUser: (NSString *) userId
|
||||
inDomain: (NSString *) domainId;
|
||||
|
@ -115,6 +118,9 @@ extern NSString *SOGoWeekStartFirstFullWeek;
|
|||
- (void) setMailComposeMessageType: (NSString *) newValue;
|
||||
- (NSString *) mailComposeMessageType;
|
||||
|
||||
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||
- (NSString *) mailDisplayRemoteInlineImages;
|
||||
|
||||
- (void) setMailMessageForwarding: (NSString *) newValue;
|
||||
- (NSString *) mailMessageForwarding;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSSet.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
|
@ -91,6 +92,22 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
|||
return ud;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
userLanguage = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[userLanguage release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) _migrateLastModule
|
||||
{
|
||||
BOOL rc;
|
||||
|
@ -355,21 +372,25 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
|||
|
||||
- (NSString *) language
|
||||
{
|
||||
NSString *language;
|
||||
NSArray *supportedLanguages;
|
||||
|
||||
if (!userLanguage)
|
||||
{
|
||||
/* see SOGoDomainDefaults for the meaning of this */
|
||||
language = [source objectForKey: @"SOGoLanguage"];
|
||||
if (!(language && [language isKindOfClass: [NSString class]]))
|
||||
language = [(SOGoDomainDefaults *) parentSource language];
|
||||
userLanguage = [source objectForKey: @"SOGoLanguage"];
|
||||
if (!(userLanguage && [userLanguage isKindOfClass: [NSString class]]))
|
||||
userLanguage = [(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;
|
||||
/* 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
|
||||
|
@ -472,6 +493,16 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
|||
return [self stringForKey: @"SOGoMailComposeMessageType"];
|
||||
}
|
||||
|
||||
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||
{
|
||||
[self setObject: newValue forKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||
}
|
||||
|
||||
- (NSString *) mailDisplayRemoteInlineImages;
|
||||
{
|
||||
return [self stringForKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||
}
|
||||
|
||||
- (void) setMailMessageForwarding: (NSString *) newValue
|
||||
{
|
||||
[self setObject: newValue forKey: @"SOGoMailMessageForwarding"];
|
||||
|
|
|
@ -595,7 +595,7 @@ static Class NSNullK;
|
|||
withUIDorEmail: (NSString *) uid
|
||||
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;
|
||||
NSEnumerator *sogoSources;
|
||||
NSDictionary *userEntry;
|
||||
|
@ -610,6 +610,7 @@ static Class NSNullK;
|
|||
c_domain = nil;
|
||||
c_imaphostname = nil;
|
||||
c_imaplogin = nil;
|
||||
c_sievehostname = nil;
|
||||
|
||||
[currentUser setObject: [NSNumber numberWithBool: YES]
|
||||
forKey: @"CalendarAccess"];
|
||||
|
@ -640,6 +641,8 @@ static Class NSNullK;
|
|||
c_imaphostname = [userEntry objectForKey: @"c_imaphostname"];
|
||||
if (!c_imaplogin)
|
||||
c_imaplogin = [userEntry objectForKey: @"c_imaplogin"];
|
||||
if (!c_sievehostname)
|
||||
c_sievehostname = [userEntry objectForKey: @"c_sievehostname"];
|
||||
access = [[userEntry objectForKey: @"CalendarAccess"] boolValue];
|
||||
if (!access)
|
||||
[currentUser setObject: [NSNumber numberWithBool: NO]
|
||||
|
@ -675,6 +678,8 @@ static Class NSNullK;
|
|||
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
||||
if (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: cn forKey: @"cn"];
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
|
||||
@class NSString;
|
||||
|
||||
@class WOContext;
|
||||
@class WOCookie;
|
||||
|
||||
@class SOGoUser;
|
||||
|
||||
@interface SOGoWebAuthenticator : SoCookieAuthenticator <SOGoAuthenticator>
|
||||
|
@ -45,6 +48,10 @@
|
|||
expire: (int *) _expire
|
||||
grace: (int *) _grace;
|
||||
|
||||
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||
andPassword: (NSString *) password
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _SOGOWEBAUTHENTICATOR_H_ */
|
||||
|
|
|
@ -32,9 +32,12 @@
|
|||
#import <NGObjWeb/WOCookie.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSData+gzip.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSString+Ext.h>
|
||||
#import <NGLdap/NGLdapConnection.h>
|
||||
|
||||
#import <MainUI/SOGoRootPage.h>
|
||||
|
@ -47,7 +50,9 @@
|
|||
#import "SOGoSystemDefaults.h"
|
||||
#import "SOGoUser.h"
|
||||
#import "SOGoUserManager.h"
|
||||
|
||||
#if defined(SAML2_CONFIG)
|
||||
#import "SOGoSAML2Session.h"
|
||||
#endif
|
||||
#import "SOGoWebAuthenticator.h"
|
||||
|
||||
@implementation SOGoWebAuthenticator
|
||||
|
@ -107,11 +112,13 @@
|
|||
{
|
||||
SOGoCASSession *session;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *authenticationType;
|
||||
BOOL rc;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
||||
authenticationType = [sd authenticationType];
|
||||
if ([authenticationType isEqualToString: @"cas"])
|
||||
{
|
||||
session = [SOGoCASSession CASSessionWithIdentifier: _pwd fromProxy: NO];
|
||||
if (session)
|
||||
|
@ -119,6 +126,18 @@
|
|||
else
|
||||
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
|
||||
rc = [[SOGoUserManager sharedUserManager] checkLogin: _login
|
||||
password: _pwd
|
||||
|
@ -225,16 +244,18 @@
|
|||
forURL: (NSURL *) server
|
||||
forceRenew: (BOOL) renew
|
||||
{
|
||||
NSString *password, *service, *scheme;
|
||||
SOGoCASSession *session;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *authType, *password;
|
||||
|
||||
password = [self passwordInContext: context];
|
||||
if ([password length])
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
||||
authType = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
authenticationType];
|
||||
if ([authType isEqualToString: @"cas"])
|
||||
{
|
||||
SOGoCASSession *session;
|
||||
NSString *service, *scheme;
|
||||
|
||||
session = [SOGoCASSession CASSessionWithIdentifier: password
|
||||
fromProxy: NO];
|
||||
|
||||
|
@ -252,6 +273,23 @@
|
|||
if ([password length] || renew)
|
||||
[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;
|
||||
|
@ -314,4 +352,44 @@
|
|||
[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 */
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
NSArray *_mailFields;
|
||||
NSString *_imapLoginField;
|
||||
NSString *_imapHostField;
|
||||
NSString *_sieveHostField;
|
||||
NSString *_userPasswordAlgorithm;
|
||||
NSURL *_viewURL;
|
||||
BOOL _prependPasswordScheme;
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
_kindField = nil;
|
||||
_multipleBookingsField = nil;
|
||||
_imapHostField = nil;
|
||||
_sieveHostField = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -115,6 +116,7 @@
|
|||
[_multipleBookingsField release];
|
||||
[_domainField release];
|
||||
[_imapHostField release];
|
||||
[_sieveHostField release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -131,6 +133,7 @@
|
|||
ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]);
|
||||
ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]);
|
||||
ASSIGN(_imapHostField, [udSource objectForKey: @"IMAPHostFieldName"]);
|
||||
ASSIGN(_sieveHostField, [udSource objectForKey: @"SieveHostFieldName"]);
|
||||
ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]);
|
||||
ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]);
|
||||
ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]);
|
||||
|
@ -187,7 +190,10 @@
|
|||
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
|
||||
|
||||
if (pass == nil)
|
||||
{
|
||||
[self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (_prependPasswordScheme)
|
||||
result = [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
|
||||
|
@ -319,6 +325,8 @@
|
|||
{
|
||||
// Encrypt new password
|
||||
NSString *encryptedPassword = [self _encryptPassword: newPassword];
|
||||
if(encryptedPassword == nil)
|
||||
return NO;
|
||||
|
||||
// Save new password
|
||||
login = [login stringByReplacingString: @"'" withString: @"''"];
|
||||
|
@ -519,6 +527,13 @@
|
|||
[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
|
||||
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",
|
||||
"SpanishSpain", "SpanishArgentina", "French", "German",
|
||||
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
|
||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian",
|
||||
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",
|
||||
"Ukrainian", "Swedish" ];
|
||||
daysBetweenResponseList=[1,2,3,5,7,14,21,30]
|
||||
|
||||
|
|
|
@ -208,8 +208,8 @@ class DAVAclTest(unittest.TestCase):
|
|||
return versitStruct
|
||||
|
||||
event_template = """BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//Inverse//Event Generator//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
SEQUENCE:0
|
||||
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
|
||||
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed
|
||||
|
||||
check ::
|
||||
./obj/sogo-tests
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/test-tool.make
|
||||
-include GNUmakefile.postamble
|
||||
|
||||
check ::
|
||||
./obj/sogo-tests
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#import <GDLContentStore/GCSChannelManager.h>
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
#import <GDLContentStore/GCSSpecialQueries.h>
|
||||
#import <GDLContentStore/NSURL+GCS.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
|
@ -113,6 +114,7 @@
|
|||
BOOL rc = NO;
|
||||
GCSFolderManager *fm;
|
||||
GCSChannelManager *cm;
|
||||
GCSSpecialQueries *specialQueries;
|
||||
NSURL *folderLocation;
|
||||
EOAdaptorContext *ac;
|
||||
EOAdaptorChannel *fc;
|
||||
|
@ -125,6 +127,7 @@
|
|||
folderLocation = [fm folderInfoLocation];
|
||||
fc = [cm acquireOpenChannelForURL: folderLocation];
|
||||
ac = [fc adaptorContext];
|
||||
specialQueries = [fc specialQueries];
|
||||
sqlFromUserID = [fromUserID asSafeSQLString];
|
||||
sqlToUserID = [toUserID asSafeSQLString];
|
||||
|
||||
|
@ -137,15 +140,16 @@
|
|||
if (!sqlError)
|
||||
{
|
||||
sql
|
||||
= [NSString stringWithFormat: @"UPDATE %@"
|
||||
@" SET c_path = '/'||c_path1||'/'||c_path2||'/'||c_path3||'/'||c_path4"
|
||||
@" WHERE c_path2 = '%@'",
|
||||
[folderLocation gcsTableName], sqlToUserID];
|
||||
= [specialQueries updateCPathInFolderInfo: [folderLocation gcsTableName]
|
||||
withCPath2: sqlToUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
}
|
||||
|
||||
if (sqlError)
|
||||
{
|
||||
[ac rollbackTransaction];
|
||||
NSLog([sqlError reason]);
|
||||
}
|
||||
else
|
||||
rc = [ac commitTransaction];
|
||||
|
||||
|
@ -195,7 +199,10 @@
|
|||
[profileLocation gcsTableName], sqlToUserID, sqlFromUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
if (sqlError)
|
||||
{
|
||||
[ac rollbackTransaction];
|
||||
NSLog([sqlError reason]);
|
||||
}
|
||||
else
|
||||
rc = [ac commitTransaction];
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSError.h>
|
||||
#import <Foundation/NSFileManager.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
@ -346,6 +347,7 @@ typedef enum SOGoToolRestoreMode {
|
|||
- (BOOL) restoreRecords: (NSArray *) records
|
||||
ofFolder: (GCSFolder *) gcsFolder
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSDictionary *existingRecords, *currentRecord;
|
||||
NSString *cName, *cContent;
|
||||
int count, max;
|
||||
|
@ -354,12 +356,18 @@ typedef enum SOGoToolRestoreMode {
|
|||
|
||||
if (records)
|
||||
{
|
||||
existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder];
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
version = 0;
|
||||
rc = YES;
|
||||
existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder];
|
||||
max = [records count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
if (count > 0 && count%100 == 0)
|
||||
{
|
||||
DESTROY(pool);
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
currentRecord = [records objectAtIndex: count];
|
||||
cName = [currentRecord objectForKey: @"c_name"];
|
||||
if (![existingRecords objectForKey: cName])
|
||||
|
@ -370,6 +378,7 @@ typedef enum SOGoToolRestoreMode {
|
|||
baseVersion: &version];
|
||||
}
|
||||
}
|
||||
DESTROY(pool);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@ BUNDLE_NAME = AdministrationUI
|
|||
|
||||
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 = \
|
||||
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_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 += \
|
||||
CommonUIProduct.m \
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"Owner:" = "Właściciel:";
|
||||
"Publish the Free/Busy information" = "Opublikuj informację wolny/zajęty";
|
||||
|
||||
"Add..." = "Dodaj...";
|
||||
"Add..." = "Dodaj";
|
||||
"Remove" = "Usuń";
|
||||
|
||||
"Subscribe User" = "Subskrybuj użytkownika";
|
||||
|
@ -52,14 +52,14 @@
|
|||
|
||||
/* generic.js */
|
||||
"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!"
|
||||
= "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!"
|
||||
= "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!"
|
||||
= "Nie możesz wyłączyć subskrypcji foldera, który jest twoją własnością!";
|
||||
"Unable to rename that folder!" = "Nie można zmienić nazwy tego foldera!";
|
||||
= "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 folderu!";
|
||||
"You have already subscribed to that folder!"
|
||||
= "Już subskrybujesz ten folder!";
|
||||
"The user rights cannot be edited for this object!"
|
||||
|
@ -79,7 +79,7 @@
|
|||
"delegate is a participant" = "Delegat jest już uczestnikiem.";
|
||||
"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";
|
||||
"10 minutes" = "10 minut";
|
||||
"15 minutes" = "15 minut";
|
||||
|
|
|
@ -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