merge of '7766ae8ec61d9568e049bfa9fb16f7452250a88a'

and 'fa4c79494b368a1d150b33a70179a532c2f71dcd'

Monotone-Parent: 7766ae8ec61d9568e049bfa9fb16f7452250a88a
Monotone-Parent: fa4c79494b368a1d150b33a70179a532c2f71dcd
Monotone-Revision: 069a26b1da4cd9cb430bcfa41dc9eb96e0cc8778

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2010-08-19T17:46:13
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2010-08-19 17:46:13 +00:00
40 changed files with 688 additions and 109 deletions
+41
View File
@@ -1,3 +1,44 @@
2010-08-19 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/WebServerResources/UIxReminderEditor.js
(initialiseFormValues): added code to configure the "actionList"
if present (email alarms enabled).
(onEditorOkClick): modify the parent's reminderAction,
reminderEmailOrganizer, reminderEmailAttendees when email alarms
are available. "reminderAction" is conditionally set to "display"
otherwise.
* UI/Scheduler/UIxReminderEditor.m (-emailAlarmsEnabled): new accessor.
* SoObjects/Appointments/SOGoCalendarComponent.m
(-saveComponent:): invoke SOGoEMailAlarmsManager to register any
email alarms in the saved component.
(-PUTAction:): new super method to perform the same as the above.
(-prepareDelete): new super method. Invoke SOGoEMailAlarmsManager
to unregister any email alarms in the deleted component.
* UI/Scheduler/UIxComponentEditor.m (-init): added the
"reminderAction", "reminderEmailOrganizer" and
"reminderEmailAttendees" ivars.
(_loadEMailAlarm:) new setup method for setting up parameters that
are specific to email alarms.
(_appendAttendees:toEmailAlarm:,_appendOrganizerToEmailAlarm:):
new method for adding "attendees" to email alarms.
(-emailAlarmsEnabled): new accessor.
* SoObjects/Appointments/SOGoAppointmentObject.m (-prepareDelete):
we now invoke -[super prepareDelete] since SOGoCalendarComponent
now implements the method.
(-DELETEAction:): invoke -prepareDelete instead of
-prepareDeleteOccurence: since we want -[super prepareDelete] to
be invoked from here too.
* Main/SOGo.m (-_checkMandatoryTables): added code to create the
alarms table if email alarms are enabled.
* SoObjects/SOGo/SOGoSystemDefaults.m (-enableEMailAlarms): new
method for the "SOGoEnableEMailAlarms" user default.
2010-08-19 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/generic.js (showPromptDialog): new
+9
View File
@@ -30,6 +30,8 @@
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <GDLContentStore/GCSAlarmsFolder.h>
#import <NGObjWeb/SoClassSecurityInfo.h>
#import <NGObjWeb/WOContext.h>
@@ -201,6 +203,7 @@ static BOOL debugLeaks;
- (BOOL) _checkMandatoryTables
{
GCSChannelManager *cm;
GCSFolderManager *fm;
NSString *urlStrings[] = {@"SOGoProfileURL", @"OCSFolderInfoURL", nil};
NSString **urlString;
NSString *value;
@@ -227,6 +230,12 @@ static BOOL debugLeaks;
}
}
if (ok && [defaults enableEMailAlarms])
{
fm = [GCSFolderManager defaultFolderManager];
[[fm alarmsFolder] createFolderIfNotExists];
}
return ok;
}
+15
View File
@@ -1,3 +1,18 @@
2010-08-19 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* GCSSpecialQueries.m (-createEMailAlarmsFolderWithName:): new sql
helper methods
(emailAlarmsAttributeTypes:): new helper method that returns the
types pertaining to the adaptor.
* GCSFolderManager.m (-alarmsFolder): new helper method.
* GCSAlarmsFolder.[hm]: new class module for handling alarm
references.
* GCSFolder.m (-_channelManager): made method private.
(-folderManager): removed method.
2010-06-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* GCSFolderManager.m
-3
View File
@@ -94,9 +94,6 @@
- (NSURL *) aclLocation;
- (NSString *) folderTypeName;
- (GCSFolderManager *) folderManager;
- (GCSChannelManager *) channelManager;
- (NSString *) storeTableName;
- (NSString *) quickTableName;
- (NSString *) aclTableName;
+14 -18
View File
@@ -192,11 +192,8 @@ static NSArray *contentFieldNames = nil;
return folderTypeName;
}
- (GCSFolderManager *)folderManager {
return folderManager;
}
- (GCSChannelManager *)channelManager {
return [[self folderManager] channelManager];
- (GCSChannelManager *)_channelManager {
return [folderManager channelManager];
}
- (NSString *)storeTableName {
@@ -216,28 +213,28 @@ static NSArray *contentFieldNames = nil;
/* channels */
- (EOAdaptorChannel *)acquireStoreChannel {
return [[self channelManager] acquireOpenChannelForURL:[self location]];
return [[self _channelManager] acquireOpenChannelForURL:[self location]];
}
- (EOAdaptorChannel *)acquireQuickChannel {
return [[self channelManager] acquireOpenChannelForURL:[self quickLocation]];
return [[self _channelManager] acquireOpenChannelForURL:[self quickLocation]];
}
- (EOAdaptorChannel *)acquireAclChannel {
return [[self channelManager] acquireOpenChannelForURL:[self aclLocation]];
return [[self _channelManager] acquireOpenChannelForURL:[self aclLocation]];
}
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
[[self channelManager] releaseChannel:_channel];
[[self _channelManager] releaseChannel:_channel];
if (debugOn) [self debugWithFormat:@"released channel: %@", _channel];
}
- (BOOL)canConnectStore {
return [[self channelManager] canConnect:[self location]];
return [[self _channelManager] canConnect:[self location]];
}
- (BOOL)canConnectQuick {
return [[self channelManager] canConnect:[self quickLocation]];
return [[self _channelManager] canConnect:[self quickLocation]];
}
- (BOOL)canConnectAcl {
return [[self channelManager] canConnect:[self quickLocation]];
return [[self _channelManager] canConnect:[self quickLocation]];
}
/* errors */
@@ -278,12 +275,12 @@ static NSArray *contentFieldNames = nil;
/* operations */
- (NSArray *)subFolderNames {
return [[self folderManager] listSubFoldersAtPath:[self path]
recursive:NO];
return [folderManager listSubFoldersAtPath:[self path]
recursive:NO];
}
- (NSArray *)allSubFolderNames {
return [[self folderManager] listSubFoldersAtPath:[self path]
recursive:YES];
return [folderManager listSubFoldersAtPath:[self path]
recursive:YES];
}
- (GCSTableRequirement) _tableRequirementForFields: (NSArray *) fields
@@ -515,7 +512,6 @@ static NSArray *contentFieldNames = nil;
{
[self errorWithFormat:@"%s: cannot execute quick-fetch SQL '%@': %@",
__PRETTY_FUNCTION__, sql, error];
[self releaseChannel: channel];
results = nil;
}
else
@@ -529,8 +525,8 @@ static NSArray *contentFieldNames = nil;
/* release channels */
[self releaseChannel: channel];
}
[self releaseChannel: channel];
// NSLog(@"/running query");
}
else
+4 -1
View File
@@ -32,7 +32,7 @@
*/
@class NSString, NSArray, NSURL, NSDictionary, NSException;
@class GCSChannelManager, GCSFolder, GCSFolderType;
@class GCSChannelManager, GCSAlarmsFolder, GCSFolder, GCSFolderType;
@interface GCSFolderManager : NSObject
{
@@ -70,6 +70,9 @@
- (NSException *)createFolderOfType:(NSString *)_type withName:(NSString *)_name atPath:(NSString *)_path;
- (NSException *)deleteFolderAtPath:(NSString *)_path;
/* alarms */
- (GCSAlarmsFolder *)alarmsFolder;
/* folder types */
- (GCSFolderType *)folderTypeWithName:(NSString *)_name;
+10 -3
View File
@@ -37,13 +37,15 @@
#import <NGExtensions/NGResourceLocator.h>
#import <unistd.h>
#import "GCSFolderManager.h"
#import "GCSChannelManager.h"
#import "GCSFolderType.h"
#import "EOAdaptorChannel+GCS.h"
#import "GCSAlarmsFolder.h"
#import "GCSFolder.h"
#import "GCSFolderType.h"
#import "GCSSpecialQueries.h"
#import "NSURL+GCS.h"
#import "EOAdaptorChannel+GCS.h"
#import "GCSFolderManager.h"
/*
Required database schema:
@@ -323,6 +325,11 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
return [folder autorelease];
}
- (GCSAlarmsFolder *) alarmsFolder
{
return [GCSAlarmsFolder alarmsFolderWithFolderManager: self];
}
/* path SQL */
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
+3
View File
@@ -31,6 +31,9 @@
@interface GCSSpecialQueries : NSObject
- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName;
- (NSDictionary *) emailAlarmsAttributeTypes;
- (NSString *) createFolderTableWithName: (NSString *) tableName;
- (NSString *) createFolderACLTableWithName: (NSString *) tableName;
+110
View File
@@ -77,6 +77,20 @@
@implementation GCSSpecialQueries
- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName
{
[self subclassResponsibility: _cmd];
return nil;
}
- (NSDictionary *) emailAlarmsAttributeTypes
{
[self subclassResponsibility: _cmd];
return nil;
}
- (NSString *) createFolderTableWithName: (NSString *) tableName
{
[self subclassResponsibility: _cmd];
@@ -95,6 +109,38 @@
@implementation GCSPostgreSQLSpecialQueries
- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) NOT NULL,"
@" c_name VARCHAR(255) NOT NULL,"
@" c_uid VARCHAR(255) NOT NULL,"
@" c_recurrence_id INT NULL,"
@" c_alarm_number INT NOT NULL,"
@" c_alarm_date INT NOT NULL)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
- (NSDictionary *) emailAlarmsAttributeTypes
{
static NSMutableDictionary *types = nil;
if (!types)
{
types = [NSMutableDictionary new];
[types setObject: @"varchar" forKey: @"c_path"];
[types setObject: @"varchar" forKey: @"c_name"];
[types setObject: @"varchar" forKey: @"c_uid"];
[types setObject: @"int" forKey: @"c_recurrence_id"];
[types setObject: @"int" forKey: @"c_alarm_number"];
[types setObject: @"int" forKey: @"c_alarm_date"];
}
return types;
}
- (NSString *) createFolderTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
@@ -126,6 +172,38 @@
@implementation GCSMySQLSpecialQueries
- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) NOT NULL,"
@" c_name VARCHAR(255) NOT NULL,"
@" c_uid VARCHAR(255) NOT NULL,"
@" c_recurrence_id INT NULL,"
@" c_alarm_number INT NOT NULL,"
@" c_alarm_date INT NOT NULL)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
- (NSDictionary *) emailAlarmsAttributeTypes
{
static NSMutableDictionary *types = nil;
if (!types)
{
types = [NSMutableDictionary new];
[types setObject: @"varchar" forKey: @"c_path"];
[types setObject: @"varchar" forKey: @"c_name"];
[types setObject: @"varchar" forKey: @"c_uid"];
[types setObject: @"int" forKey: @"c_recurrence_id"];
[types setObject: @"int" forKey: @"c_alarm_number"];
[types setObject: @"int" forKey: @"c_alarm_date"];
}
return types;
}
- (NSString *) createFolderTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
@@ -157,6 +235,38 @@
@implementation GCSOracleSpecialQueries
- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR2(255) NOT NULL,"
@" c_name VARCHAR2(255) NOT NULL,"
@" c_uid VARCHAR2(255) NOT NULL,"
@" c_recurrence_id INTEGER NULL,"
@" c_alarm_number INTEGER NOT NULL,"
@" c_alarm_date INTEGER NOT NULL)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
- (NSDictionary *) emailAlarmsAttributeTypes
{
static NSMutableDictionary *types = nil;
if (!types)
{
types = [NSMutableDictionary new];
[types setObject: @"varchar2" forKey: @"c_path"];
[types setObject: @"varchar2" forKey: @"c_name"];
[types setObject: @"varchar2" forKey: @"c_uid"];
[types setObject: @"integer" forKey: @"c_recurrence_id"];
[types setObject: @"integer" forKey: @"c_alarm_number"];
[types setObject: @"integer" forKey: @"c_alarm_date"];
}
return types;
}
- (NSString *) createFolderTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
+2
View File
@@ -24,6 +24,7 @@ libGDLContentStore_HEADER_FILES += \
NSURL+GCS.h \
EOAdaptorChannel+GCS.h \
\
GCSAlarmsFolder.h \
GCSContext.h \
GCSFieldInfo.h \
GCSFolder.h \
@@ -39,6 +40,7 @@ libGDLContentStore_OBJC_FILES += \
EOAdaptorChannel+GCS.m \
EOQualifier+GCS.m \
\
GCSAlarmsFolder.m \
GCSContext.m \
GCSFieldInfo.m \
GCSFolder.m \
+5
View File
@@ -1,3 +1,8 @@
2010-08-19 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalAlarm.m (-setComment, -setSummary, -setAction)
(-setAttendees): new accessors.
2010-08-13 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalAlarm.m (-nextAlarmDate): new utility method split from the
+9
View File
@@ -41,6 +41,15 @@
- (void) setRecurrenceRule: (NSString *) _recurrenceRule;
- (NSString *) recurrenceRule;
- (void) setSummary: (NSString *) summary;
- (NSString *) summary;
- (void) setComment: (NSString *) comment;
- (NSString *) comment;
- (void) setAttendees: (NSArray *) attendees;
- (NSArray *) attendees;
- (void) removeAllAttendees;
- (NSCalendarDate *) nextAlarmDate;
@end
+51 -20
View File
@@ -19,6 +19,7 @@
02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
@@ -44,8 +45,12 @@
tagClass = [iCalAttachment class];
else if ([classTag isEqualToString: @"RRULE"])
tagClass = [iCalRecurrenceRule class];
else if ([classTag isEqualToString: @"ATTENDEE"])
tagClass = [iCalPerson class];
else if ([classTag isEqualToString: @"ACTION"]
|| [classTag isEqualToString: @"COMMENT"])
|| [classTag isEqualToString: @"COMMENT"]
|| [classTag isEqualToString: @"DESCRIPTION"]
|| [classTag isEqualToString: @"SUMMARY"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
@@ -75,21 +80,10 @@
return (iCalAttachment *) [self uniqueChildWithTag: @"attach"];
}
- (void) setComment: (NSString *) _value
{
[[self uniqueChildWithTag: @"comment"] setValue: 0
to: _value];
}
- (NSString *) comment
{
return [[self uniqueChildWithTag: @"comment"] value: 0];
}
- (void) setAction: (NSString *) _value
{
[[self uniqueChildWithTag: @"action"] setValue: 0
to: _value];
to: _value];
}
- (NSString *) action
@@ -97,12 +91,50 @@
return [[self uniqueChildWithTag: @"action"] value: 0];
}
- (void) setSummary: (NSString *) _value
{
[[self uniqueChildWithTag: @"summary"] setValue: 0
to: _value];
}
- (NSString *) summary
{
return [[self uniqueChildWithTag: @"summary"] value: 0];
}
- (void) setComment: (NSString *) _value
{
[[self uniqueChildWithTag: @"description"] setValue: 0
to: _value];
}
- (NSString *) comment
{
return [[self uniqueChildWithTag: @"description"] value: 0];
}
- (void) setRecurrenceRule: (NSString *) _recurrenceRule
{
[[self uniqueChildWithTag: @"rrule"] setValue: 0
to: _recurrenceRule];
}
- (void) setAttendees: (NSArray *) attendees
{
[self removeAllAttendees];
[self addChildren: attendees];
}
- (NSArray *) attendees
{
return [self childrenWithTag: @"attendee"];
}
- (void) removeAllAttendees
{
[children removeObjectsInArray: [self attendees]];
}
- (NSString *) recurrenceRule
{
return [[self uniqueChildWithTag: @"rrule"] value: 0];
@@ -110,7 +142,6 @@
- (NSCalendarDate *) nextAlarmDate
{
Class parentClass;
iCalTrigger *aTrigger;
NSCalendarDate *relationDate, *nextAlarmDate;
NSString *relation;
@@ -121,19 +152,19 @@
nextAlarmDate = nil;
parentClass = [parent class];
if ([parentClass isKindOfClass: [iCalEvent class]]
|| [parentClass isKindOfClass: [iCalToDo class]])
if ([parent isKindOfClass: [iCalEvent class]]
|| [parent isKindOfClass: [iCalToDo class]])
{
aTrigger = [self trigger];
if ([[aTrigger valueType] caseInsensitiveCompare: @"DURATION"])
if ([[aTrigger valueType] caseInsensitiveCompare: @"DURATION"]
== NSOrderedSame)
{
relation = [aTrigger relationType];
anInterval = [[aTrigger value] durationAsTimeInterval];
if ([relation caseInsensitiveCompare: @"END"] == NSOrderedSame)
{
if ([parentClass isKindOfClass: [iCalEvent class]])
if ([parent isKindOfClass: [iCalEvent class]])
relationDate = [(iCalEvent *) parent endDate];
else
relationDate = [(iCalToDo *) parent due];
@@ -148,7 +179,7 @@
}
else
[self warnWithFormat: @"alarms not handled for elements of class '%@'",
NSStringFromClass (parentClass)];
NSStringFromClass ([parent class])];
return nextAlarmDate;
}
+2
View File
@@ -42,6 +42,8 @@ Appointments_OBJC_FILES = \
SOGoAptMailICalReply.m \
SOGoAptMailUpdate.m \
SOGoAptMailReceipt.m \
\
SOGoEMailAlarmsManager.m
Appointments_RESOURCE_FILES += \
Version \
+17 -15
View File
@@ -608,7 +608,7 @@
// participation state has changed.
// - uid is the actual UID of the user for whom we must
// update the calendar event (with the participation change)
// - delegate is the delegated attendee if any
// - delegate is the delegate attendee if any
//
// This method is called multiple times, in order to update the
// status of the attendee in calendars for the particular event UID.
@@ -668,7 +668,7 @@
else
otherDelegate = NO;
/* we handle the addition/deletion of delegated users */
/* we handle the addition/deletion of delegate users */
addDelegate = NO;
removeDelegate = NO;
if (delegate)
@@ -696,7 +696,7 @@
{
[event removeFromAttendees: otherDelegate];
// Verify if the delegate was already delegated
// Verify if the delegate was already delegate
delegateEmail = [otherDelegate delegatedTo];
if ([delegateEmail length])
delegateEmail = [delegateEmail rfc822Email];
@@ -777,31 +777,31 @@
if ([delegateEmail length])
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
else
otherDelegate = NO;
otherDelegate = nil;
/* We handle the addition/deletion of delegated users */
/* We handle the addition/deletion of delegate users */
addDelegate = NO;
removeDelegate = NO;
if (delegate)
{
if (otherDelegate)
{
// There was already a delegated
// There was already a delegate
if (![delegate hasSameEmailAddress: otherDelegate])
{
// The delegated has changed
// The delegate has changed
removeDelegate = YES;
addDelegate = YES;
}
}
else
// There was no previous delegated
// There was no previous delegate
addDelegate = YES;
}
else
{
if (otherDelegate)
// The user has removed the delegated
// The user has removed the delegate
removeDelegate = YES;
}
@@ -846,7 +846,7 @@
delegatedUID = [otherDelegate uid];
if (delegatedUID)
// Delegated attendee is a local user; remove event from his calendar
// Delegate attendee is a local user; remove event from his calendar
[self _removeEventFromUID: delegatedUID
owner: [theOwnerUser login]
withRecurrenceId: [event recurrenceId]];
@@ -880,7 +880,7 @@
[event addToAttendees: delegate];
if (delegatedUID)
// Delegated attendee is a local user; add event to his calendar
// Delegate attendee is a local user; add event to his calendar
[self _addOrUpdateEvent: event
forUID: delegatedUID
owner: [theOwnerUser login]];
@@ -1217,7 +1217,7 @@
{
[self prepareDeleteOccurence: nil];
return nil;
return [super prepareDelete];
}
/* message type */
@@ -1260,6 +1260,7 @@
return partStats;
}
#warning parseSingleFromSource is invoked far too many times: maybe we should use an additional ivar to store the new iCalendar
- (void) _setupResponseCalendarInRequest: (WORequest *) rq
{
iCalCalendar *calendar, *putCalendar;
@@ -1412,7 +1413,7 @@
//
- (id) DELETEAction: (WOContext *) _ctx
{
[self prepareDeleteOccurence: nil];
[self prepareDelete];
return [super DELETEAction: _ctx];
}
@@ -1428,10 +1429,10 @@
NSArray *roles;
WORequest *rq;
id response;
rq = [_ctx request];
roles = [[context activeUser] rolesForObject: self inContext: context];
//
// We check if we gave only the "Respond To" right and someone is actually
// responding to one of our invitation. In this case, _setupResponseCalendarInRequest
@@ -1469,6 +1470,7 @@
BOOL scheduling;
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
event = [[calendar events] objectAtIndex: 0];
ownerUser = [SOGoUser userWithLogin: owner];
scheduling = [self _shouldScheduleEvent: [event organizer]];
@@ -60,6 +60,7 @@
#import "SOGoAptMailICalReply.h"
#import "SOGoAptMailNotification.h"
#import "SOGoAptMailReceipt.h"
#import "SOGoEMailAlarmsManager.h"
#import "iCalEntityObject+SOGo.h"
#import "iCalPerson+SOGo.h"
#import "iCalRepeatableEntityObject+SOGo.h"
@@ -590,6 +591,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject
{
NSString *newiCalString, *newUid;
SOGoEMailAlarmsManager *eaMgr;
if (!isNew
&& [newObject isRecurrent])
@@ -611,6 +613,10 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
[newObject setUid: newUid];
}
eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager];
[eaMgr handleAlarmsInCalendar: [newObject parent]
fromComponent: self];
newiCalString = [[newObject parent] versitString];
[self saveContentString: newiCalString];
@@ -1157,6 +1163,32 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
return [self component: YES secure: NO];
}
#warning alarms: we don not handle occurrences
- (NSException *) prepareDelete
{
SOGoEMailAlarmsManager *eaMgr;
eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager];
[eaMgr deleteAlarmsFromComponent: self];
return nil;
}
- (id) PUTAction: (WOContext *) localContext
{
SOGoEMailAlarmsManager *eaMgr;
WORequest *rq;
iCalCalendar *putCalendar;
rq = [localContext request];
putCalendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager];
[eaMgr handleAlarmsInCalendar: putCalendar
fromComponent: self];
return [super PUTAction: localContext];
}
// /* Overriding this method dramatically speeds up PROPFIND request, but may
// otherwise be a bad idea... Wait and see. */
// - (NSDictionary*) valuesForKeys: (NSArray*)keys
+2
View File
@@ -42,6 +42,8 @@
- (BOOL) isCalendarDAVAccessEnabled;
- (BOOL) isAddressBookDAVAccessEnabled;
- (BOOL) enableEMailAlarms;
- (NSString *) faviconRelativeURL;
- (NSString *) zipPath;
- (int) port;
+5
View File
@@ -221,6 +221,11 @@ BootstrapNSUserDefaults ()
return [self boolForKey: @"SOGoAddressBookDAVAccessEnabled"];
}
- (BOOL) enableEMailAlarms
{
return [self boolForKey: @"SOGoEnableEMailAlarms"];
}
- (NSString *) faviconRelativeURL
{
return [self stringForKey: @"SOGoFaviconRelativeURL"];
+8 -1
View File
@@ -25,7 +25,14 @@ $(SOGO_SLAPD_SOCKD)_OBJC_FILES += \
SOGoSockDScanner.m \
SOGoSockDOperation.m \
TOOL_NAME = $(SOGO_TOOL) $(SOGO_SLAPD_SOCKD)
SOGO_EALARMS_NOTIFY = sogo-ealarms-notify
$(SOGO_EALARMS_NOTIFY)_INSTALL_DIR = $(SOGO_ADMIN_TOOLS)
$(SOGO_EALARMS_NOTIFY)_OBJC_FILES += \
sogo-ealarms-notify.m \
\
SOGoEAlarmsNotifier.m
TOOL_NAME = $(SOGO_TOOL) $(SOGO_SLAPD_SOCKD) $(SOGO_EALARMS_NOTIFY)
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/tool.make
@@ -406,6 +406,12 @@
"reminder_END" = "fim do evento";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "konci události";
"Reminder Details" = "Podrobnosti připomenutí";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "the event ends";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "the event ends";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -402,10 +402,16 @@
"reminder_DAYS" = "jours";
"reminder_BEFORE" = "avant";
"reminder_AFTER" = "après";
"reminder_START" = "l'événement débute";
"reminder_END" = "l'événement se termine";
"reminder_START" = "le début de 'événement";
"reminder_END" = "la fin de l'événement";
"Reminder Details" = "Détails du rappel";
"Choose a Reminder Action" = "Choisir une action pour le rappel";
"Show an Alert" = "Afficher une alerte";
"Send an E-mail" = "Envoyer un courrier";
"Email Organizer" = "À l'organisateur";
"Email Attendees" = "Aux invités";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "der Termin endet";
"Reminder Details" = "Erinnerungsdetails";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "az esemény végződik";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "the event ends";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "końcem wydarzenia";
"Reminder Details" = "Szczegóły przypomnienia";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "конца события";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "the event ends";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "händelserna slutar";
"Reminder Details" = "Påminnelsedetaljer";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
+3
View File
@@ -72,6 +72,9 @@
NSString *reminderUnit;
NSString *reminderRelation;
NSString *reminderReference;
NSString *reminderAction;
BOOL reminderEmailOrganizer;
BOOL reminderEmailAttendees;
/* ugly */
NSString *repeat;
+142 -14
View File
@@ -62,6 +62,7 @@
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoSystemDefaults.h>
#import "../../Main/SOGo.h"
@@ -180,6 +181,9 @@ iRANGE(2);
reminderUnit = nil;
reminderRelation = nil;
reminderReference = nil;
reminderAction = nil;
reminderEmailOrganizer = NO;
reminderEmailAttendees = NO;
repeatType = nil;
repeat1 = nil;
repeat2 = nil;
@@ -462,8 +466,44 @@ iRANGE(2);
}
}
- (void) _loadEMailAlarm: (iCalAlarm *) anAlarm
{
NSArray *attendees;
iCalPerson *aAttendee;
SOGoUser *owner;
NSString *ownerId, *email;
int count, max;
attendees = [anAlarm attendees];
reminderEmailOrganizer = NO;
reminderEmailAttendees = NO;
ownerId = [[self clientObject] ownerInContext: nil];
owner = [SOGoUser userWithLogin: ownerId];
email = [[owner defaultIdentity] objectForKey: @"email"];
max = [attendees count];
for (count = 0;
!(reminderEmailOrganizer && reminderEmailAttendees)
&& count < max;
count++)
{
aAttendee = [attendees objectAtIndex: count];
if ([[aAttendee rfc822Email] isEqualToString: email])
reminderEmailOrganizer = YES;
else
reminderEmailAttendees = YES;
}
}
- (void) _loadAlarms
{
iCalAlarm *anAlarm;
iCalTrigger *aTrigger;
NSString *duration, *quantity;
unichar c;
unsigned int i;
if ([component hasAlarms])
{
// We currently have the following limitations for alarms:
@@ -471,21 +511,17 @@ iRANGE(2);
// - the alarm's action must be of type DISPLAY;
// - the alarm's trigger value type must be DURATION.
iCalAlarm *anAlarm;
iCalTrigger *aTrigger;
NSString *duration, *quantity;
unichar c;
unsigned int i;
anAlarm = [[component alarms] objectAtIndex: 0];
aTrigger = [anAlarm trigger];
if ([[anAlarm action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame &&
[[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
ASSIGN (reminderAction, [[anAlarm action] lowercaseString]);
if (([reminderAction isEqualToString: @"display"]
|| [reminderAction isEqualToString: @"email"])
&& [[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
{
duration = [aTrigger value];
i = [reminderValues indexOfObject: duration];
if (i == NSNotFound)
if (i == NSNotFound || [reminderAction isEqualToString: @"email"])
{
// Custom alarm
ASSIGN (reminder, @"CUSTOM");
@@ -537,6 +573,9 @@ iRANGE(2);
}
if ([quantity length])
ASSIGN (reminderQuantity, quantity);
if ([reminderAction isEqualToString: @"email"])
[self _loadEMailAlarm: anAlarm];
}
}
else
@@ -1046,6 +1085,36 @@ iRANGE(2);
return text;
}
- (void) setReminderAction: (NSString *) newValue
{
ASSIGN (reminderAction, newValue);
}
- (NSString *) reminderAction
{
return reminderAction;
}
- (void) setReminderEmailOrganizer: (NSString *) newValue
{
reminderEmailOrganizer = [newValue isEqualToString: @"true"];
}
- (NSString *) reminderEmailOrganizer
{
return (reminderEmailOrganizer ? @"true" : @"false");
}
- (void) setReminderEmailAttendees: (NSString *) newValue
{
reminderEmailAttendees = [newValue isEqualToString: @"true"];
}
- (NSString *) reminderEmailAttendees
{
return (reminderEmailAttendees ? @"true" : @"false");
}
- (NSString *) repeat
{
return repeat;
@@ -1983,6 +2052,41 @@ RANGE(2);
}
}
- (void) _appendAttendees: (NSArray *) attendees
toEmailAlarm: (iCalAlarm *) alarm
{
NSMutableArray *aAttendees;
int count, max;
iCalPerson *currentAttendee, *aAttendee;
max = [attendees count];
aAttendees = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
currentAttendee = [attendees objectAtIndex: count];
aAttendee = [iCalPerson elementWithTag: @"attendee"];
[aAttendee setCn: [currentAttendee cn]];
[aAttendee setEmail: [currentAttendee rfc822Email]];
[aAttendees addObject: aAttendee];
}
[alarm setAttendees: aAttendees];
}
- (void) _appendOrganizerToEmailAlarm: (iCalAlarm *) alarm
{
NSString *uid;
NSDictionary *ownerIdentity;
iCalPerson *aAttendee;
uid = [[self clientObject] ownerInContext: context];
ownerIdentity = [[SOGoUser userWithLogin: uid roles: nil]
defaultIdentity];
aAttendee = [iCalPerson elementWithTag: @"attendee"];
[aAttendee setCn: [ownerIdentity objectForKey: @"fullName"]];
[aAttendee setEmail: [ownerIdentity objectForKey: @"email"]];
[alarm addChild: aAttendee];
}
- (void) takeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext *) _ctx
{
@@ -2020,23 +2124,36 @@ RANGE(2);
iCalAlarm *anAlarm;
NSString *aValue;
unsigned int index;
anAlarm = [iCalAlarm new];
index = [reminderItems indexOfObject: reminder];
aValue = [reminderValues objectAtIndex: index];
aTrigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[aTrigger setValueType: @"DURATION"];
anAlarm = [iCalAlarm new];
[anAlarm setAction: @"DISPLAY"];
[anAlarm setTrigger: aTrigger];
aValue = [reminderValues objectAtIndex: index];
if ([aValue length]) {
// Predefined alarm
[anAlarm setAction: @"DISPLAY"];
[aTrigger setValue: aValue];
}
else {
// Custom alarm
[anAlarm setAction: [reminderAction uppercaseString]];
if ([reminderAction isEqualToString: @"email"])
{
[anAlarm removeAllAttendees];
if (reminderEmailAttendees)
[self _appendAttendees: [component attendees]
toEmailAlarm: anAlarm];
if (reminderEmailOrganizer)
[self _appendOrganizerToEmailAlarm: anAlarm];
[anAlarm setSummary: [component summary]];
[anAlarm setComment: [component comment]];
}
if ([reminderReference caseInsensitiveCompare: @"BEFORE"] == NSOrderedSame)
aValue = [NSString stringWithString: @"-P"];
else
@@ -2277,6 +2394,17 @@ RANGE(2);
return [self getEventRWType] != 0;
}
- (NSString *) emailAlarmsEnabled
{
SOGoSystemDefaults *sd;
sd = [SOGoSystemDefaults sharedSystemDefaults];
return ([sd enableEMailAlarms]
? @"true"
: @"false");
}
- (BOOL) userHasRSVP
{
return ([self getEventRWType] == 1);
+10 -1
View File
@@ -23,7 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Common/UIxPageFrame.h>
#import <SOGo/SOGoSystemDefaults.h>
#import "UIxReminderEditor.h"
@@ -90,4 +90,13 @@
return text;
}
- (BOOL) emailAlarmsEnabled
{
SOGoSystemDefaults *sd;
sd = [SOGoSystemDefaults sharedSystemDefaults];
return [sd enableEMailAlarms];
}
@end
@@ -406,6 +406,12 @@
"reminder_END" = "кінця події";
"Reminder Details" = "Деталі нагадування";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -406,6 +406,12 @@
"reminder_END" = "the event ends";
"Reminder Details" = "Reminder Details";
"Choose a Reminder Action" = "Choose a Reminder Action";
"Show an Alert" = "Show an Alert";
"Send an E-mail" = "Send an E-mail";
"Email Organizer" = "Email Organizer";
"Email Attendees" = "Email Attendees";
"zoom_400" = "400%";
"zoom_200" = "200%";
"zoom_100" = "100%";
@@ -21,6 +21,7 @@
const:negate="YES">false</var:if>;
var attendees = <var:string value="jsonAttendees" const:escapeHTML="NO"/>;
var ownerLogin = '<var:string value="ownerLogin"/>';
var emailAlarmsEnabled = <var:string value="emailAlarmsEnabled"/>;
<var:if condition="eventIsReadOnly" const:negate="YES"
><var:if condition="hasOrganizer">var organizer = <var:string value="jsonOrganizer" const:escapeHTML="NO"/>;</var:if
>var owners = <var:string value="calendarOwnerList.jsonRepresentation" const:escapeHTML="NO"/>;</var:if
@@ -161,6 +162,15 @@
<input type="hidden" name="reminderReference"
id="reminderReference"
var:value="reminderReference"/>
<input type="hidden" name="reminderAction"
id="reminderAction"
var:value="reminderAction"/>
<input type="hidden" name="reminderEmailOrganizer"
id="reminderEmailOrganizer"
var:value="reminderEmailOrganizer"/>
<input type="hidden" name="reminderEmailAttendees"
id="reminderEmailAttendees"
var:value="reminderEmailAttendees"/>
</div>
</form>
</var:if>
@@ -328,6 +338,16 @@
id="reminderReference"
var:value="reminderReference"/>
<input type="hidden" name="reminderAction"
id="reminderAction"
var:value="reminderAction"/>
<input type="hidden" name="reminderEmailOrganizer"
id="reminderEmailOrganizer"
var:value="reminderEmailOrganizer"/>
<input type="hidden" name="reminderEmailAttendees"
id="reminderEmailAttendees"
var:value="reminderEmailAttendees"/>
<div id="windowButtons">
<var:if condition="userHasRSVP"><a id="okButton" href="#" class="button actionButton"
><span><var:string label:value="OK"/></span></a></var:if>
+38 -26
View File
@@ -12,32 +12,44 @@
const:popup="YES">
<form name="reminder_form" id="reminder_form" href="editReminder">
<div id="reminder_pattern">
<span class="caption"><var:string label:value="Reminder Details"/></span>
<table class="frame">
<tr><td>
<input type="text" id="quantityField"
class="textField"
size="2"
/><var:popup list="unitsList" const:id="unitsList" item="item"
string="itemText" var:value="item" selection="minutes"
/><var:popup list="referencesList" const:id="referencesList" item="item"
string="itemText" var:value="item" selection="BEFORE"
/>
</td></tr>
<tr><td>
<var:popup list="relationsList" const:id="relationsList" item="item"
string="itemText" var:value="item" selection="START"
/>
</td></tr>
</table>
</div>
<div id="windowButtons">
<a id="okButton" href="#" class="button actionButton"
><span><var:string label:value="OK"/></span></a>
<a id="cancelButton" href="#" class="button"
><span><var:string label:value="Cancel"/></span></a>
<div>
<fieldset>
<legend><var:string label:value="Reminder Details"/></legend>
<input type="text" id="quantityField"
class="textField"
size="2"
/><var:popup list="unitsList" const:id="unitsList" item="item"
string="itemText" var:value="item" selection="minutes"
/><var:popup list="referencesList" const:id="referencesList" item="item"
string="itemText" var:value="item" selection="BEFORE"
/><br/>
<var:popup list="relationsList" const:id="relationsList" item="item"
string="itemText" var:value="item" selection="START"
/>
</fieldset>
<var:if condition="emailAlarmsEnabled">
<fieldset>
<legend><var:string label:value="Choose a Reminder Action"/></legend>
<select const:name="actionList" const:id="actionList">
<option const:value="display"><var:string label:value="Show an Alert"/></option>
<option const:value="email"><var:string label:value="Send an E-mail"/></option>
</select><br/>
<label><input type="checkbox" const:disabled="1"
const:name="emailOrganizer" const:id="emailOrganizer"/>
<var:string label:value="Email Organizer"/></label><br/>
<label><input type="checkbox" const:disabled="1"
const:name="emailAttendees" const:id="emailAttendees"/>
<var:string label:value="Email Attendees"/></label>
</fieldset>
</var:if>
<div id="windowButtons">
<a id="okButton" href="#" class="button actionButton"
><span><var:string label:value="OK"/></span></a>
<a id="cancelButton" href="#" class="button"
><span><var:string label:value="Cancel"/></span></a>
</div>
</div>
</form>
+7 -4
View File
@@ -373,10 +373,13 @@ function onPopupReminderWindow(event) {
if (event) {
if (ComponentEditor.reminderWindow && ComponentEditor.reminderWindow.open && !ComponentEditor.reminderWindow.closed)
ComponentEditor.reminderWindow.focus();
else
ComponentEditor.reminderWindow = window.open(ApplicationBaseURL + "editReminder",
sanitizeWindowName(activeCalendar + activeComponent + "Reminder"),
"width=250,height=150");
else {
var height = (emailAlarmsEnabled ? 215 : 150);
ComponentEditor.reminderWindow
= window.open(ApplicationBaseURL + "editReminder",
sanitizeWindowName(activeCalendar + activeComponent + "Reminder"),
"width=255,height=" + height);
}
}
}
else if (reminderHref)
+43 -1
View File
@@ -6,7 +6,6 @@ function initializeWindowButtons() {
cancelButton.observe("click", onEditorCancelClick, false);
}
function initializeFormValues() {
if (parent$("reminderUnit").value.length > 0) {
$("quantityField").value = parent$("reminderQuantity").value;
@@ -14,6 +13,33 @@ function initializeFormValues() {
$("relationsList").value = parent$("reminderRelation").value;
$("referencesList").value = parent$("reminderReference").value;
}
var actionList = $("actionList");
if (actionList) {
actionList.observe("change", onActionListChange);
var action = parent$("reminderAction").value;
if (!action)
action = "display";
actionList.value = action;
if (action == "email") {
$("emailOrganizer").checked = (parent$("reminderEmailOrganizer").value
== "true");
$("emailAttendees").checked = (parent$("reminderEmailAttendees").value
== "true");
}
updateActionCheckboxes(actionList);
}
}
function onActionListChange() {
updateActionCheckboxes(this);
}
function updateActionCheckboxes(list) {
var disabled = (list.value != "email");
$("emailOrganizer").disabled = disabled;
$("emailAttendees").disabled = disabled;
}
function onEditorOkClick(event) {
@@ -24,6 +50,22 @@ function onEditorOkClick(event) {
parent$("reminderRelation").value = $("relationsList").value;
parent$("reminderReference").value = $("referencesList").value;
var actionList = $("actionList");
var action;
if (actionList) {
action = $("actionList").value;
parent$("reminderEmailOrganizer").value = ($("emailOrganizer").checked
? "true"
: "false");
parent$("reminderEmailAttendees").value = ($("emailAttendees").checked
? "true"
: "false");
}
else {
action = "display";
}
parent$("reminderAction").value = action;
window.close();
}
else