Monotone-Parent: a164259525f718f804b625a9f09b4c3b3c9e83f8
Monotone-Revision: 11f4bdac420d36e45b12ca5d1d393ec34f43c609 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-11-10T00:02:30 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
aebac17d01
commit
1eda040e84
16
ChangeLog
16
ChangeLog
|
@ -1,5 +1,21 @@
|
|||
2007-11-09 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartICalViewer.m
|
||||
([UIxMailPartICalViewer -acceptLink])
|
||||
([UIxMailPartICalViewer -declineLink])
|
||||
([UIxMailPartICalViewer -tentativeLink]): removed useless methods.
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartICalAction.m ([UIxMailPartICalAction -addToCalendarAction])
|
||||
([UIxMailPartICalAction -deleteFromCalendarAction]): new stub
|
||||
methods.
|
||||
|
||||
* SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject
|
||||
-lookupImap4BodyPartKey:]): make use of the new method below.
|
||||
|
||||
* SoObjects/Mailer/SOGoMailBodyPart.m ([SOGoMailBodyPart
|
||||
+bodyPartClassForMimeType:mimeTypeinContext:_ctx]): new method
|
||||
that returns an appropriate Class depending on a given mime type.
|
||||
|
||||
* UI/SOGoUI/UIxComponent.m ([UIxComponent -canCreateOrModify]):
|
||||
new boolean accessor that determines whether someone can create
|
||||
(i.e. modify a new entry) or modify an existing entry.
|
||||
|
|
|
@ -62,6 +62,8 @@
|
|||
|
||||
+ (Class) bodyPartClassForKey: (NSString *) _key
|
||||
inContext: (id) _ctx;
|
||||
+ (Class) bodyPartClassForMimeType: (NSString *) mimeType
|
||||
inContext: (id) _ctx;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGImap4/NGImap4Connection.h>
|
||||
|
||||
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
|
||||
|
||||
#import "SOGoMailObject.h"
|
||||
#import "SOGoMailManager.h"
|
||||
|
||||
|
@ -305,7 +307,9 @@ static BOOL debugOn = NO;
|
|||
|
||||
/* factory */
|
||||
|
||||
+ (Class)bodyPartClassForKey:(NSString *)_key inContext:(id)_ctx {
|
||||
+ (Class) bodyPartClassForKey: (NSString *) _key
|
||||
inContext: (id) _ctx
|
||||
{
|
||||
NSString *pe;
|
||||
|
||||
pe = [_key pathExtension];
|
||||
|
@ -335,6 +339,36 @@ static BOOL debugOn = NO;
|
|||
return self;
|
||||
}
|
||||
|
||||
+ (Class) bodyPartClassForMimeType: (NSString *) mimeType
|
||||
inContext: (id) _ctx
|
||||
{
|
||||
NSString *classString;
|
||||
Class klazz;
|
||||
|
||||
if ([mimeType isEqualToString: @"image/gif"]
|
||||
|| [mimeType isEqualToString: @"image/png"]
|
||||
|| [mimeType isEqualToString: @"image/jpg"])
|
||||
classString = @"SOGoImageMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"text/calendar"])
|
||||
classString = @"SOGoCalendarMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"text/x-vcard"])
|
||||
classString = @"SOGoVCardMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"message/rfc822"])
|
||||
classString = @"SOGoMessageMailBodyPart";
|
||||
else
|
||||
{
|
||||
NSLog (@"unhandled mime type: '%@'", mimeType);
|
||||
classString = nil;
|
||||
}
|
||||
|
||||
if (classString)
|
||||
klazz = NSClassFromString (classString);
|
||||
else
|
||||
klazz = Nil;
|
||||
|
||||
return klazz;
|
||||
}
|
||||
|
||||
/* etag support */
|
||||
|
||||
- (id)davEntityTag {
|
||||
|
|
|
@ -735,8 +735,22 @@ static BOOL debugSoParts = NO;
|
|||
{
|
||||
// TODO: we might want to check for existence prior controller creation
|
||||
Class clazz;
|
||||
|
||||
clazz = [SOGoMailBodyPart bodyPartClassForKey:_key inContext:_ctx];
|
||||
NSArray *parts;
|
||||
int part;
|
||||
NSDictionary *partDesc;
|
||||
NSString *mimeType;
|
||||
|
||||
parts = [[self bodyStructure] objectForKey: @"parts"];
|
||||
part = [_key intValue] - 1;
|
||||
if (part > -1 && part < [parts count])
|
||||
{
|
||||
partDesc = [parts objectAtIndex: part];
|
||||
mimeType = [[partDesc keysWithFormat: @"%{type}/%{subtype}"] lowercaseString];
|
||||
clazz = [SOGoMailBodyPart bodyPartClassForMimeType: mimeType
|
||||
inContext: _ctx];
|
||||
}
|
||||
else
|
||||
clazz = Nil;
|
||||
|
||||
return [clazz objectWithName:_key inContainer: self];
|
||||
}
|
||||
|
@ -755,7 +769,7 @@ static BOOL debugSoParts = NO;
|
|||
|
||||
if ([self isBodyPartKey:_key inContext:_ctx]) {
|
||||
if ((obj = [self lookupImap4BodyPartKey:_key inContext:_ctx]) != nil) {
|
||||
if (debugSoParts)
|
||||
if (debugSoParts)
|
||||
[self logWithFormat: @"mail looked up part %@: %@", _key, obj];
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
ACCEPTED = "accepted";
|
||||
COMPLETED = "completed";
|
||||
DECLINED = "declined";
|
||||
DELEGATED = "delegated";
|
||||
IN-PROCESS = "in process";
|
||||
NEEDS-ACTION = "needs action";
|
||||
TENTATIVE = "tentative";
|
||||
organized_by_you = "organized by you";
|
||||
ACCEPTED = "accepted";
|
||||
COMPLETED = "completed";
|
||||
DECLINED = "declined";
|
||||
DELEGATED = "delegated";
|
||||
IN-PROCESS = "in process";
|
||||
NEEDS-ACTION = "needs action";
|
||||
TENTATIVE = "tentative";
|
||||
organized_by_you = "organized by you";
|
||||
you_are_an_attendee = "you are an attendee";
|
||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||
publish_info_text = "The sender informs you of the attached event.";
|
||||
cancel_info_text = "Your invitation or the whole event was canceled.";
|
||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||
publish_info_text = "The sender informs you of the attached event.";
|
||||
cancel_info_text = "Your invitation or the whole event was canceled.";
|
||||
request_info_no_attendee = "is proposing a meeting to the attendees. You receive this mail as a notification, you are not scheduled as a participant.";
|
||||
Appointment = "Appointment";
|
||||
Appointment = "Appointment";
|
||||
|
||||
Organizer = "Organisateur";
|
||||
Time = "Time";
|
||||
Attendees = "Attendees";
|
||||
request_info = "invites you to participate in a meeting.";
|
||||
do_add_to_cal = "add to calendar";
|
||||
do_del_from_cal = "delete from calendar";
|
||||
do_accept = "accept";
|
||||
do_decline = "decline";
|
||||
do_tentative = "tentative";
|
||||
do_update_status = "update status in calendar";
|
||||
Organizer = "Organisateur";
|
||||
Time = "Time";
|
||||
Attendees = "Attendees";
|
||||
request_info = "invites you to participate in a meeting.";
|
||||
"Add to calendar" = "Add to calendar";
|
||||
"Delete from calendar" = "Delete from calendar";
|
||||
Accept = "Accept";
|
||||
Decline = "Decline";
|
||||
Tentative = "Tentative";
|
||||
"Update status in calendar" = "Update status in calendar";
|
||||
reply_info_no_attendee = "You received a reply to a scheduling event but the sender of the reply is not a participant.";
|
||||
reply_info = "This is a reply to an event invitation done by you.";
|
||||
reply_info = "This is a reply to an event invitation done by you.";
|
||||
|
||||
"to" = "to";
|
||||
|
||||
"Untitled" = "Untitled";
|
||||
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
ACCEPTED = "Accepté";
|
||||
COMPLETED = "Terminé";
|
||||
DECLINED = "Refusé";
|
||||
DELEGATED = "Délégué";
|
||||
IN-PROCESS = "En cours de traitement";
|
||||
ACCEPTED = "Accepté";
|
||||
COMPLETED = "Terminé";
|
||||
DECLINED = "Refusé";
|
||||
DELEGATED = "Délégué";
|
||||
IN-PROCESS = "En cours de traitement";
|
||||
NEEDS-ACTION = "Prise de décision nécessaire";
|
||||
TENTATIVE = "Proposition";
|
||||
organized_by_you = "vous êtes l'organisateur";
|
||||
TENTATIVE = "Proposition";
|
||||
organized_by_you = "vous êtes l'organisateur";
|
||||
you_are_an_attendee = "vous êtes invité";
|
||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||
publish_info_text = "L'expéditeur vous informe de l'événement attaché.";
|
||||
cancel_info_text = "Votre invitation ou l'événement au complet a été annulé.";
|
||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||
publish_info_text = "L'expéditeur vous informe de l'événement attaché.";
|
||||
cancel_info_text = "Votre invitation ou l'événement au complet a été annulé.";
|
||||
request_info_no_attendee = "propose une réunion entre les invités. Ce message tint seulement lieu d'avis, vous n'êtes pas indiqué comme invité.";
|
||||
Appointment = "Événement";
|
||||
Appointment = "Événement";
|
||||
|
||||
Organizer = "Organisateur";
|
||||
Time = "Date";
|
||||
Attendees = "Invités";
|
||||
request_info = "vous invite à une réunion.";
|
||||
do_add_to_cal = "ajouter à l'agenda";
|
||||
do_del_from_cal = "effacer de l'agenda";
|
||||
do_accept = "accepter";
|
||||
do_decline = "decliner";
|
||||
do_tentative = "tentative";
|
||||
do_update_status = "mettre l'agenda à jour";
|
||||
Organizer = "Organisateur";
|
||||
Time = "Date";
|
||||
Attendees = "Invités";
|
||||
request_info = "vous invite à une réunion.";
|
||||
"Add to calendar" = "Ajouter à l'agenda";
|
||||
"Delete from calendar" = "Effacer de l'agenda";
|
||||
Accept = "Accepter";
|
||||
Decline = "Decliner";
|
||||
Tentative = "Tentative";
|
||||
"Update status in calendar" = "Mettre l'agenda à jour";
|
||||
reply_info_no_attendee = "Vous avez reçu une réponse à un événement mais l'expéditeur n'est pas un invité.";
|
||||
reply_info = "Ceci est une réponse à un événement que vous avez organisé.";
|
||||
reply_info = "Ceci est une réponse à un événement que vous avez organisé.";
|
||||
|
||||
"to" = "à";
|
||||
|
||||
"Untitled" = "Sans titre";
|
||||
|
||||
|
|
|
@ -17,15 +17,17 @@ Organizer = "Organisateur";
|
|||
Time = "Time";
|
||||
Attendees = "Attendees";
|
||||
request_info = "invites you to participate in a meeting.";
|
||||
do_add_to_cal = "add to calendar";
|
||||
do_del_from_cal = "delete from calendar";
|
||||
do_accept = "accept";
|
||||
do_decline = "decline";
|
||||
do_tentative = "tentative";
|
||||
do_update_status = "update status in calendar";
|
||||
"Add to calendar" = "Add to calendar";
|
||||
"Delete from calendar" = "Delete from calendar";
|
||||
Accept = "Accept";
|
||||
Decline = "Decline";
|
||||
Tentative = "Tentative";
|
||||
"Update status in calendar" = "Update status in calendar";
|
||||
reply_info_no_attendee = "You received a reply to a scheduling event but the sender of the reply is not a participant.";
|
||||
reply_info = "This is a reply to an event invitation done by you.";
|
||||
|
||||
"to" = "to";
|
||||
|
||||
"Untitled" = "Untitled";
|
||||
|
||||
"Size" = "Size";
|
||||
|
|
|
@ -1,76 +1,63 @@
|
|||
/*
|
||||
Copyright (C) 2005 SKYRIX Software AG
|
||||
/* UIxMailPartICalAction.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 Inverse groupe conseil
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <NGObjWeb/SoObject.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <NGObjWeb/WODirectAction.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <UI/Common/WODirectAction+SOGo.h>
|
||||
|
||||
@interface UIxMailPartICalAction : WODirectAction
|
||||
@end
|
||||
|
||||
@implementation UIxMailPartICalAction
|
||||
|
||||
- (id)redirectToViewerWithError:(NSString *)_error {
|
||||
WOResponse *r;
|
||||
NSString *viewURL;
|
||||
id mail;
|
||||
|
||||
mail = [[self clientObject] valueForKey:@"mailObject"];
|
||||
[self logWithFormat:@"MAIL: %@", mail];
|
||||
|
||||
viewURL = [mail baseURLInContext:[self context]];
|
||||
[self logWithFormat:@" url: %@", viewURL];
|
||||
|
||||
viewURL = [viewURL stringByAppendingString:
|
||||
[viewURL hasSuffix:@"/"] ? @"view" : @"/view"];
|
||||
|
||||
if ([_error isNotNull] && [_error length] > 0) {
|
||||
viewURL = [viewURL stringByAppendingString:@"?error="];
|
||||
viewURL = [viewURL stringByAppendingString:
|
||||
[_error stringByEscapingURL]];
|
||||
}
|
||||
|
||||
r = [[self context] response];
|
||||
[r setStatus:302 /* moved */];
|
||||
[r setHeader:viewURL forKey:@"location"];
|
||||
return r;
|
||||
- (WOResponse *) _changePartStatusAction: (NSString *) _newStatus
|
||||
{
|
||||
return [self responseWithStatus: 404];
|
||||
}
|
||||
|
||||
- (id)changePartStatusAction:(NSString *)_newStatus {
|
||||
[self logWithFormat:@"TODO: should %@: %@", _newStatus, [self clientObject]];
|
||||
return [self redirectToViewerWithError:
|
||||
[_newStatus stringByAppendingString:@" not implemented!"]];
|
||||
- (WOResponse *) markAcceptedAction
|
||||
{
|
||||
return [self _changePartStatusAction: @"ACCEPTED"];
|
||||
}
|
||||
|
||||
- (id)markAcceptedAction {
|
||||
return [self changePartStatusAction:@"ACCEPTED"];
|
||||
- (WOResponse *) markDeclinedAction
|
||||
{
|
||||
return [self _changePartStatusAction: @"DECLINED"];
|
||||
}
|
||||
- (id)markDeclinedAction {
|
||||
return [self changePartStatusAction:@"DECLINED"];
|
||||
|
||||
- (WOResponse *) markTentativeAction
|
||||
{
|
||||
return [self _changePartStatusAction: @"TENTATIVE"];
|
||||
}
|
||||
- (id)markTentativeAction {
|
||||
return [self changePartStatusAction:@"TENTATIVE"];
|
||||
|
||||
- (WOResponse *) addToCalendarAction
|
||||
{
|
||||
return [self responseWithStatus: 404];
|
||||
}
|
||||
|
||||
- (WOResponse *) deleteFromCalendarAction
|
||||
{
|
||||
return [self responseWithStatus: 404];
|
||||
}
|
||||
|
||||
@end /* UIxMailPartICalAction */
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
OGo 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 Lesser General Public
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
@ -30,13 +30,13 @@
|
|||
|
||||
@interface UIxMailPartICalViewer : UIxMailPartViewer
|
||||
{
|
||||
iCalCalendar *inCalendar;
|
||||
iCalEvent *inEvent;
|
||||
id attendee;
|
||||
iCalCalendar *inCalendar;
|
||||
iCalEvent *inEvent;
|
||||
id attendee;
|
||||
SOGoDateFormatter *dateFormatter;
|
||||
id item;
|
||||
id storedEventObject;
|
||||
iCalEvent *storedEvent;
|
||||
id item;
|
||||
id storedEventObject;
|
||||
iCalEvent *storedEvent;
|
||||
}
|
||||
|
||||
- (iCalEvent *) authorativeEvent;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
|
@ -10,18 +10,18 @@
|
|||
|
||||
OGo 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 Lesser General Public
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
UIxMailPartICalViewer
|
||||
|
||||
|
||||
Show plain/calendar mail parts.
|
||||
*/
|
||||
|
||||
|
@ -46,44 +46,47 @@
|
|||
|
||||
@implementation UIxMailPartICalViewer
|
||||
|
||||
- (void)dealloc {
|
||||
[self->storedEventObject release];
|
||||
[self->storedEvent release];
|
||||
[self->attendee release];
|
||||
[self->item release];
|
||||
[self->inCalendar release];
|
||||
[self->inEvent release];
|
||||
[self->dateFormatter release];
|
||||
- (void) dealloc
|
||||
{
|
||||
[storedEventObject release];
|
||||
[storedEvent release];
|
||||
[attendee release];
|
||||
[item release];
|
||||
[inCalendar release];
|
||||
[inEvent release];
|
||||
[dateFormatter release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* maintain caches */
|
||||
|
||||
- (void)resetPathCaches {
|
||||
- (void) resetPathCaches
|
||||
{
|
||||
[super resetPathCaches];
|
||||
[self->inEvent release]; self->inEvent = nil;
|
||||
[self->inCalendar release]; self->inCalendar = nil;
|
||||
[self->storedEventObject release]; self->storedEventObject = nil;
|
||||
[self->storedEvent release]; self->storedEvent = nil;
|
||||
|
||||
[inEvent release]; inEvent = nil;
|
||||
[inCalendar release]; inCalendar = nil;
|
||||
[storedEventObject release]; storedEventObject = nil;
|
||||
[storedEvent release]; storedEvent = nil;
|
||||
|
||||
/* not strictly path-related, but useless without it anyway: */
|
||||
[self->attendee release]; self->attendee = nil;
|
||||
[self->item release]; self->item = nil;
|
||||
[attendee release]; attendee = nil;
|
||||
[item release]; item = nil;
|
||||
}
|
||||
|
||||
/* raw content handling */
|
||||
|
||||
- (NSStringEncoding)fallbackStringEncoding {
|
||||
- (NSStringEncoding) fallbackStringEncoding
|
||||
{
|
||||
/*
|
||||
iCalendar invitations sent by Outlook 2002 have the annoying bug that the
|
||||
mail states an UTF-8 content encoding but the actual iCalendar content is
|
||||
encoding in Latin-1 (or Windows Western?).
|
||||
|
||||
|
||||
As a result the content decoding will fail (TODO: always?). In this case we
|
||||
try to decode with Latin-1.
|
||||
|
||||
|
||||
Note: we could check for the Outlook x-mailer, but it was considered better
|
||||
to try Latin-1 as a fallback in any case (be tolerant).
|
||||
to try Latin-1 as a fallback in any case (be tolerant).
|
||||
*/
|
||||
return NSISOLatin1StringEncoding;
|
||||
}
|
||||
|
@ -95,59 +98,73 @@
|
|||
if (!inCalendar)
|
||||
{
|
||||
inCalendar
|
||||
= [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
|
||||
= [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
|
||||
[inCalendar retain];
|
||||
}
|
||||
|
||||
return inCalendar;
|
||||
}
|
||||
|
||||
- (BOOL)couldParseCalendar {
|
||||
- (BOOL) couldParseCalendar
|
||||
{
|
||||
return [[self inCalendar] isNotNull];
|
||||
}
|
||||
|
||||
- (iCalEvent *)inEvent {
|
||||
- (iCalEvent *) inEvent
|
||||
{
|
||||
NSArray *events;
|
||||
|
||||
if (self->inEvent != nil)
|
||||
return [self->inEvent isNotNull] ? self->inEvent : nil;
|
||||
|
||||
|
||||
if (inEvent)
|
||||
return [inEvent isNotNull] ? inEvent : nil;
|
||||
|
||||
events = [[self inCalendar] events];
|
||||
if ([events count] > 0) {
|
||||
self->inEvent = [[events objectAtIndex:0] retain];
|
||||
return self->inEvent;
|
||||
inEvent = [[events objectAtIndex:0] retain];
|
||||
return inEvent;
|
||||
}
|
||||
else {
|
||||
self->inEvent = [[NSNull null] retain];
|
||||
inEvent = [[NSNull null] retain];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/* formatters */
|
||||
|
||||
- (SOGoDateFormatter *)dateFormatter {
|
||||
if (self->dateFormatter == nil) {
|
||||
- (SOGoDateFormatter *) dateFormatter
|
||||
{
|
||||
if (dateFormatter == nil) {
|
||||
dateFormatter = [[context activeUser] dateFormatterInContext: context];
|
||||
[dateFormatter retain];
|
||||
}
|
||||
|
||||
return self->dateFormatter;
|
||||
return dateFormatter;
|
||||
}
|
||||
|
||||
/* below is copied from UIxAppointmentView, can we avoid that? */
|
||||
|
||||
- (void)setAttendee:(id)_attendee {
|
||||
ASSIGN(self->attendee, _attendee);
|
||||
- (void) setAttendee: (id) _attendee
|
||||
{
|
||||
ASSIGN(attendee, _attendee);
|
||||
}
|
||||
- (id)attendee {
|
||||
return self->attendee;
|
||||
|
||||
- (id) attendee
|
||||
{
|
||||
return attendee;
|
||||
}
|
||||
|
||||
- (NSString *) _personForDisplay: (iCalPerson *) person
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@ <%@>",
|
||||
[person cnWithoutQuotes],
|
||||
[person rfc822Email]];
|
||||
NSString *fn, *email, *result;
|
||||
|
||||
fn = [person cnWithoutQuotes];
|
||||
email = [person rfc822Email];
|
||||
if ([fn length])
|
||||
result = [NSString stringWithFormat: @"%@ <%@>",
|
||||
fn, email];
|
||||
else
|
||||
result = email;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *) attendeeForDisplay
|
||||
|
@ -155,18 +172,21 @@
|
|||
return [self _personForDisplay: attendee];
|
||||
}
|
||||
|
||||
- (void)setItem:(id)_item {
|
||||
ASSIGN(self->item, _item);
|
||||
- (void) setItem: (id) _item
|
||||
{
|
||||
ASSIGN(item, _item);
|
||||
}
|
||||
- (id)item {
|
||||
return self->item;
|
||||
|
||||
- (id) item
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) startTime
|
||||
{
|
||||
NSCalendarDate *date;
|
||||
NSTimeZone *timeZone;
|
||||
|
||||
|
||||
date = [[self authorativeEvent] startDate];
|
||||
timeZone = [[context activeUser] timeZone];
|
||||
[date setTimeZone: timeZone];
|
||||
|
@ -178,7 +198,7 @@
|
|||
{
|
||||
NSCalendarDate *date;
|
||||
NSTimeZone *timeZone;
|
||||
|
||||
|
||||
date = [[self authorativeEvent] endDate];
|
||||
timeZone = [[context activeUser] timeZone];
|
||||
[date setTimeZone: timeZone];
|
||||
|
@ -186,10 +206,13 @@
|
|||
return date;
|
||||
}
|
||||
|
||||
- (BOOL)isEndDateOnSameDay {
|
||||
- (BOOL) isEndDateOnSameDay
|
||||
{
|
||||
return [[self startTime] isDateOnSameDay:[self endTime]];
|
||||
}
|
||||
- (NSTimeInterval)duration {
|
||||
|
||||
- (NSTimeInterval) duration
|
||||
{
|
||||
return [[self endTime] timeIntervalSinceDate:[self startTime]];
|
||||
}
|
||||
|
||||
|
@ -209,45 +232,48 @@
|
|||
return [folder lookupName: @"personal" inContext: context acquire: NO];
|
||||
}
|
||||
|
||||
- (id)storedEventObject {
|
||||
- (id) storedEventObject
|
||||
{
|
||||
/* lookup object in the users Calendar */
|
||||
id calendar;
|
||||
|
||||
if (self->storedEventObject != nil)
|
||||
return [self->storedEventObject isNotNull] ? self->storedEventObject : nil;
|
||||
|
||||
|
||||
if (storedEventObject)
|
||||
return [storedEventObject isNotNull] ? storedEventObject : nil;
|
||||
|
||||
calendar = [self calendarFolder];
|
||||
if ([calendar isKindOfClass:[NSException class]]) {
|
||||
[self errorWithFormat:@"Did not find Calendar folder: %@", calendar];
|
||||
}
|
||||
else {
|
||||
NSString *filename;
|
||||
|
||||
|
||||
filename = [calendar resourceNameForEventUID:[[self inEvent] uid]];
|
||||
if (filename != nil) {
|
||||
if (filename) {
|
||||
// TODO: When we get an exception, this might be an auth issue meaning
|
||||
// that the UID indeed exists but that the user has no access to
|
||||
// the object.
|
||||
// Of course this is quite unusual for the private calendar though.
|
||||
// that the UID indeed exists but that the user has no access to
|
||||
// the object.
|
||||
// Of course this is quite unusual for the private calendar though.
|
||||
id tmp;
|
||||
|
||||
|
||||
tmp = [calendar lookupName:filename inContext:[self context] acquire:NO];
|
||||
if ([tmp isNotNull] && ![tmp isKindOfClass:[NSException class]])
|
||||
self->storedEventObject = [tmp retain];
|
||||
storedEventObject = [tmp retain];
|
||||
}
|
||||
}
|
||||
|
||||
if (self->storedEventObject == nil)
|
||||
self->storedEventObject = [[NSNull null] retain];
|
||||
|
||||
return self->storedEventObject;
|
||||
|
||||
if (storedEventObject == nil)
|
||||
storedEventObject = [[NSNull null] retain];
|
||||
|
||||
return storedEventObject;
|
||||
}
|
||||
|
||||
- (BOOL)isEventStoredInCalendar {
|
||||
- (BOOL) isEventStoredInCalendar
|
||||
{
|
||||
return [[self storedEventObject] isNotNull];
|
||||
}
|
||||
|
||||
- (iCalEvent *)storedEvent {
|
||||
- (iCalEvent *) storedEvent
|
||||
{
|
||||
return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component: NO];
|
||||
}
|
||||
|
||||
|
@ -262,27 +288,30 @@
|
|||
return [identity objectForKey: @"email"];
|
||||
}
|
||||
|
||||
- (iCalEvent *)authorativeEvent {
|
||||
- (iCalEvent *) authorativeEvent
|
||||
{
|
||||
/* DB is considered master, when in DB, ignore mail organizer */
|
||||
return [self isEventStoredInCalendar]
|
||||
? [self storedEvent]
|
||||
: [self inEvent];
|
||||
}
|
||||
|
||||
- (BOOL)isLoggedInUserTheOrganizer {
|
||||
- (BOOL) isLoggedInUserTheOrganizer
|
||||
{
|
||||
NSString *loginEMail;
|
||||
|
||||
|
||||
if ((loginEMail = [self loggedInUserEMail]) == nil) {
|
||||
[self warnWithFormat:@"Could not determine email of logged in user?"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
return [[self authorativeEvent] isOrganizer:loginEMail];
|
||||
}
|
||||
|
||||
- (BOOL)isLoggedInUserAnAttendee {
|
||||
- (BOOL) isLoggedInUserAnAttendee
|
||||
{
|
||||
NSString *loginEMail;
|
||||
|
||||
|
||||
if ((loginEMail = [self loggedInUserEMail]) == nil) {
|
||||
[self warnWithFormat:@"Could not determine email of logged in user?"];
|
||||
return NO;
|
||||
|
@ -309,69 +338,70 @@
|
|||
|
||||
/* replies */
|
||||
|
||||
- (NGImap4EnvelopeAddress *)replySenderAddress {
|
||||
- (NGImap4EnvelopeAddress *) replySenderAddress
|
||||
{
|
||||
/*
|
||||
The iMIP reply is the sender of the mail, the 'attendees' are NOT set to
|
||||
the actual attendees. BUT the attendee field contains the reply-status!
|
||||
*/
|
||||
id tmp;
|
||||
|
||||
|
||||
tmp = [[self clientObject] fromEnvelopeAddresses];
|
||||
if ([tmp count] == 0) return nil;
|
||||
return [tmp objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (NSString *)replySenderEMail {
|
||||
- (NSString *) replySenderEMail
|
||||
{
|
||||
return [[self replySenderAddress] email];
|
||||
}
|
||||
- (NSString *)replySenderBaseEMail {
|
||||
|
||||
- (NSString *) replySenderBaseEMail
|
||||
{
|
||||
return [[self replySenderAddress] baseEMail];
|
||||
}
|
||||
|
||||
- (iCalPerson *)inReplyAttendee {
|
||||
- (iCalPerson *) inReplyAttendee
|
||||
{
|
||||
NSArray *attendees;
|
||||
|
||||
|
||||
attendees = [[self inEvent] attendees];
|
||||
if ([attendees count] == 0)
|
||||
return nil;
|
||||
if ([attendees count] > 1)
|
||||
[self warnWithFormat:@"More than one attendee in REPLY: %@", attendees];
|
||||
|
||||
|
||||
return [attendees objectAtIndex:0];
|
||||
}
|
||||
- (iCalPerson *)storedReplyAttendee {
|
||||
|
||||
- (iCalPerson *) storedReplyAttendee
|
||||
{
|
||||
/*
|
||||
TODO: since an attendee can have multiple email addresses, maybe we
|
||||
should translate the email to an internal uid and then retrieve
|
||||
all emails addresses for matching the participant.
|
||||
|
||||
should translate the email to an internal uid and then retrieve
|
||||
all emails addresses for matching the participant.
|
||||
|
||||
Note: -findParticipantWithEmail: does not parse the email!
|
||||
*/
|
||||
iCalEvent *e;
|
||||
iCalEvent *e;
|
||||
iCalPerson *p;
|
||||
|
||||
if ((e = [self storedEvent]) == nil)
|
||||
return nil;
|
||||
if ((p = [e findParticipantWithEmail:[self replySenderBaseEMail]]))
|
||||
return p;
|
||||
if ((p = [e findParticipantWithEmail:[self replySenderEMail]]))
|
||||
return p;
|
||||
return nil;
|
||||
|
||||
p = nil;
|
||||
|
||||
e = [self storedEvent];
|
||||
if (e)
|
||||
{
|
||||
p = [e findParticipantWithEmail: [self replySenderBaseEMail]];
|
||||
if (!p)
|
||||
p = [e findParticipantWithEmail:[self replySenderEMail]];
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
- (BOOL)isReplySenderAnAttendee {
|
||||
|
||||
- (BOOL) isReplySenderAnAttendee
|
||||
{
|
||||
return [[self storedReplyAttendee] isNotNull];
|
||||
}
|
||||
|
||||
/* action URLs */
|
||||
|
||||
- (id)acceptLink {
|
||||
return [[self pathToAttachmentObject] stringByAppendingString:@"/accept"];
|
||||
}
|
||||
- (id)declineLink {
|
||||
return [[self pathToAttachmentObject] stringByAppendingString:@"/decline"];
|
||||
}
|
||||
- (id)tentativeLink {
|
||||
return [[self pathToAttachmentObject] stringByAppendingString:@"/tentative"];
|
||||
}
|
||||
|
||||
@end /* UIxMailPartICalViewer */
|
||||
|
|
|
@ -25,6 +25,16 @@
|
|||
actionClass = "UIxMailPartICalAction";
|
||||
actionName = "markTentative";
|
||||
};
|
||||
addToCalendar = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailPartICalAction";
|
||||
actionName = "addToCalendar";
|
||||
};
|
||||
deleteFromCalendar = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailPartICalAction";
|
||||
actionName = "deleteFromCalendar";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,203 +1,208 @@
|
|||
<?xml version="1.0" standalone="yes"?>
|
||||
<!DOCTYPE div>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:label="OGo:label"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:rsrc="OGo:url"
|
||||
class="linked_attachment_frame"
|
||||
>
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:label="OGo:label"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:rsrc="OGo:url"
|
||||
class="linked_attachment_frame"
|
||||
>
|
||||
<!-- TODO: add iMIP actions -->
|
||||
|
||||
<var:if condition="couldParseCalendar" const:negate="1">
|
||||
<fieldset>
|
||||
<legend>Parsing Error</legend>
|
||||
|
||||
The SOGo/SOPE iCalendar parser could not parse the body of this MIME part.
|
||||
<var:if condition="couldParseCalendar" const:negate="1">
|
||||
<fieldset>
|
||||
<legend>Parsing Error</legend>
|
||||
|
||||
The SOGo/SOPE iCalendar parser could not parse the body of this MIME part.
|
||||
|
||||
<pre><var:string value="flatContentAsString" /></pre>
|
||||
</fieldset>
|
||||
</var:if>
|
||||
<pre><var:string value="flatContentAsString" /></pre>
|
||||
</fieldset>
|
||||
</var:if>
|
||||
|
||||
<var:if condition="couldParseCalendar">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<var:string label:value="Appointment"/>:
|
||||
<var:string value="inEvent.summary" /> <!-- TODO: shorted title -->
|
||||
<var:if condition="couldParseCalendar">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<var:string label:value="Appointment"/>:
|
||||
<var:string value="inEvent.summary" /> <!-- TODO: shorted title -->
|
||||
|
||||
<var:if condition="isLoggedInUserTheOrganizer">
|
||||
(<var:string label:value="organized_by_you"/>)
|
||||
</var:if>
|
||||
<var:if condition="isLoggedInUserAnAttendee">
|
||||
(<var:string label:value="you_are_an_attendee"/>)
|
||||
</var:if>
|
||||
</legend>
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="REQUEST">
|
||||
<!-- sent to attendees to propose or update a meeting -->
|
||||
<var:if condition="isLoggedInUserAnAttendee">
|
||||
<p class="uix_ical_toolbar" id="iCalendarToolbar">
|
||||
<input id="iCalendarAttachment" type="hidden"
|
||||
var:value="pathToAttachmentObject"/>
|
||||
<input id="iCalendarAccept" class="button"
|
||||
type="button" label:value="Accept"/>
|
||||
<input id="iCalendarDecline" class="button"
|
||||
type="button" label:value="Decline"/>
|
||||
<input id="iCalendarTentative" class="button"
|
||||
type="button" label:value="Tentative"/>
|
||||
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
||||
| <input id="iCalendarAddToCalendar" class="button"
|
||||
type="button" label:value="Add to calendar"/>
|
||||
</var:if>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
<var:string label:value="request_info" />
|
||||
</p>
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isLoggedInUserAnAttendee" const:negate="YES">
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
<var:string label:value="request_info_no_attendee" />
|
||||
</p>
|
||||
</var:if>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="REPLY">
|
||||
<!-- sent to organizer to update the status of the participant -->
|
||||
<var:if condition="isReplySenderAnAttendee" const:negate="1">
|
||||
<p><var:string label:value="reply_info_no_attendee" /></p>
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isReplySenderAnAttendee">
|
||||
<p class="uix_ical_toolbar">
|
||||
<a var:href="addStatusReplyLink"
|
||||
var:_newstat="$inReplyAttendee.partStatWithDefault"
|
||||
var:_sender="replySenderBaseEMail"
|
||||
label:string="do_update_status"/>
|
||||
</p>
|
||||
|
||||
<!-- TODO: replies to events not in the calendar? -->
|
||||
|
||||
<p>
|
||||
Status Update:
|
||||
<var:string label:value="$inReplyAttendee.partStatWithDefault" />,
|
||||
was:
|
||||
<var:string
|
||||
label:value="$storedReplyAttendee.partStatWithDefault" />.
|
||||
</p>
|
||||
</var:if>
|
||||
</var:if>
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="CANCEL">
|
||||
<!-- sent to attendees to notify of the attendee being removed or the
|
||||
event being deleted -->
|
||||
<var:if condition="isEventStoredInCalendar">
|
||||
<p class="uix_ical_toolbar">
|
||||
<input id="iCalendarDeleteFromCalendar" class="button"
|
||||
type="button" label:value="Delete from calendar"/>
|
||||
</p>
|
||||
</var:if>
|
||||
|
||||
<p>
|
||||
<!-- todo: if there are no attendees, the whole meeting was stopped -->
|
||||
<var:string label:value="cancel_info_text" />
|
||||
</p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="ADD">
|
||||
<!-- TODO -->
|
||||
<p><var:string label:value="add_info_text" /></p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="PUBLISH">
|
||||
<!-- none-scheduling event sent to someone for adding to the calendar -->
|
||||
<p><var:string label:value="publish_info_text" /></p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="isLoggedInUserTheOrganizer">
|
||||
(<var:string label:value="organized_by_you"/>)
|
||||
<!--
|
||||
Possible Status:
|
||||
REPLY => check whether it matches, if not suggest change, show
|
||||
comment
|
||||
REFRESH => add button to resent iCal
|
||||
COUNTER => show panel to decide on counter
|
||||
-->
|
||||
</var:if>
|
||||
<var:if condition="isLoggedInUserAnAttendee">
|
||||
(<var:string label:value="you_are_an_attendee"/>)
|
||||
<var:if condition="isLoggedInUserTheOrganizer" const:negate="1">
|
||||
<!--
|
||||
Possible Status:
|
||||
REQUEST => ACCEPT, TENTATIVELY, DECLINE buttons with comment field
|
||||
- only show buttons for attendees
|
||||
PUBLISH => just the 'add to calendar' button, rewrite organizer?
|
||||
ADD / CANCEL
|
||||
DECLINE-COUNTER
|
||||
-->
|
||||
</var:if>
|
||||
</legend>
|
||||
|
||||
|
||||
<!-- var:if condition="inCalendar.method" const:value="REQUEST" -->
|
||||
<!-- sent to attendees to propose or update a meeting -->
|
||||
<var:if condition="isLoggedInUserAnAttendee">
|
||||
<p class="uix_ical_toolbar">
|
||||
<a var:href="acceptLink" label:string="do_accept"/> |
|
||||
<a var:href="declineLink" label:string="do_decline"/> |
|
||||
<a var:href="tentativeLink" label:string="do_tentative"/>
|
||||
<var:if condition="isEventStoredInCalendar" const:negate="1">
|
||||
| <a var:href="addToCalendarLink" label:string="do_add_to_cal" />
|
||||
</var:if>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
<var:string label:value="request_info" />
|
||||
</p>
|
||||
|
||||
|
||||
<!-- the user comment is used in replies -->
|
||||
<var:if condition="inEvent.userComment.isNotEmpty">
|
||||
<div class="linked_attachment_meta" style="background-color: white;">
|
||||
<var:string value="inEvent.userComment" const:insertBR="1" />
|
||||
</div>
|
||||
<br />
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isLoggedInUserAnAttendee" const:negate="1">
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
<var:string label:value="request_info_no_attendee" />
|
||||
</p>
|
||||
</var:if>
|
||||
<!-- var:if -->
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="REPLY">
|
||||
<!-- sent to organizer to update the status of the participant -->
|
||||
<var:if condition="isReplySenderAnAttendee" const:negate="1">
|
||||
<p><var:string label:value="reply_info_no_attendee" /></p>
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isReplySenderAnAttendee">
|
||||
<p class="uix_ical_toolbar">
|
||||
<a var:href="addStatusReplyLink"
|
||||
var:_newstat="$inReplyAttendee.partStatWithDefault"
|
||||
var:_sender="replySenderBaseEMail"
|
||||
label:string="do_update_status"/>
|
||||
</p>
|
||||
|
||||
<!-- TODO: replies to events not in the calendar? -->
|
||||
|
||||
<p>
|
||||
Status Update:
|
||||
<var:string label:value="$inReplyAttendee.partStatWithDefault" />,
|
||||
was:
|
||||
<var:string
|
||||
label:value="$storedReplyAttendee.partStatWithDefault" />.
|
||||
</p>
|
||||
</var:if>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="CANCEL">
|
||||
<!-- sent to attendees to notify of the attendee being removed or the
|
||||
event being deleted -->
|
||||
<var:if condition="isEventStoredInCalendar">
|
||||
<p class="uix_ical_toolbar">
|
||||
<a var:href="delFromCalendarLink" label:string="do_del_from_cal"/>
|
||||
</p>
|
||||
</var:if>
|
||||
|
||||
<p>
|
||||
<!-- todo: if there are no attendees, the whole meeting was stopped -->
|
||||
<var:string label:value="cancel_info_text" />
|
||||
</p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="ADD">
|
||||
<!-- TODO -->
|
||||
<p><var:string label:value="add_info_text" /></p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="inCalendar.method" const:value="PUBLISH">
|
||||
<!-- none-scheduling event sent to someone for adding to the calendar -->
|
||||
<p><var:string label:value="publish_info_text" /></p>
|
||||
</var:if>
|
||||
|
||||
|
||||
<var:if condition="isLoggedInUserTheOrganizer">
|
||||
<!--
|
||||
Possible Status:
|
||||
REPLY => check whether it matches, if not suggest change, show
|
||||
comment
|
||||
REFRESH => add button to resent iCal
|
||||
COUNTER => show panel to decide on counter
|
||||
-->
|
||||
</var:if>
|
||||
<var:if condition="isLoggedInUserTheOrganizer" const:negate="1">
|
||||
<!--
|
||||
Possible Status:
|
||||
REQUEST => ACCEPT, TENTATIVELY, DECLINE buttons with comment field
|
||||
- only show buttons for attendees
|
||||
PUBLISH => just the 'add to calendar' button, rewrite organizer?
|
||||
ADD / CANCEL
|
||||
DECLINE-COUNTER
|
||||
-->
|
||||
</var:if>
|
||||
|
||||
|
||||
<!-- the user comment is used in replies -->
|
||||
<var:if condition="inEvent.userComment.isNotEmpty">
|
||||
<div class="linked_attachment_meta" style="background-color: white;">
|
||||
<var:string value="inEvent.userComment" const:insertBR="1" />
|
||||
<table border="0" class="linked_attachment_meta">
|
||||
<tr>
|
||||
<td><var:string label:value="Time"/>:</td>
|
||||
<td>
|
||||
<!-- TODO: we need a better viewer for that -->
|
||||
<var:string value="startTime" formatter="dateFormatter" />
|
||||
<var:string label:value="to" />
|
||||
<var:string value="endTime" formatter="dateFormatter" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><var:string label:value="Organizer"/>:</td>
|
||||
<td>
|
||||
<a var:href="authorativeEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top"><var:string label:value="Attendees"/>:</td>
|
||||
<td>
|
||||
<var:foreach list="authorativeEvent.participants" item="attendee">
|
||||
<a var:href="attendee.email"><var:string value="attendeeForDisplay"/></a>
|
||||
(<var:string label:value="$attendee.partStatWithDefault" />)
|
||||
<br />
|
||||
</var:foreach>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<var:if condition="inEvent.comment.isNotEmpty">
|
||||
<tr> <!-- description in iCal -->
|
||||
<td valign="top"><var:string label:value="Comment"/>:</td>
|
||||
<td>
|
||||
<var:string value="authorativeEvent.comment" const:insertBR="1" />
|
||||
</td>
|
||||
</tr>
|
||||
</var:if>
|
||||
</table>
|
||||
</div>
|
||||
<br />
|
||||
</var:if>
|
||||
</fieldset>
|
||||
</var:if><!-- could parse -->
|
||||
|
||||
|
||||
<div class="linked_attachment_meta" style="background-color: white;">
|
||||
<table border="0" class="linked_attachment_meta">
|
||||
<tr>
|
||||
<td><var:string label:value="Time"/>:</td>
|
||||
<td>
|
||||
<!-- TODO: we need a better viewer for that -->
|
||||
<var:string value="startTime" formatter="dateFormatter" />
|
||||
<var:string label:value="to" />
|
||||
<var:string value="endTime" formatter="dateFormatter" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><var:string label:value="Organizer"/>:</td>
|
||||
<td>
|
||||
<a var:href="authorativeEvent.organizer.email"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top"><var:string label:value="Attendees"/>:</td>
|
||||
<td>
|
||||
<var:foreach list="authorativeEvent.participants" item="attendee">
|
||||
<a var:href="attendee.email"><var:string value="attendeeForDisplay"/></a>
|
||||
(<var:string label:value="$attendee.partStatWithDefault" />)
|
||||
<br />
|
||||
</var:foreach>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<var:if condition="inEvent.comment.isNotEmpty">
|
||||
<tr> <!-- description in iCal -->
|
||||
<td valign="top"><var:string label:value="Comment"/>:</td>
|
||||
<td>
|
||||
<var:string value="authorativeEvent.comment" const:insertBR="1" />
|
||||
</td>
|
||||
</tr>
|
||||
</var:if>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
</var:if><!-- could parse -->
|
||||
|
||||
<!--
|
||||
<!--
|
||||
<var:string value="appointment" />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
-->
|
||||
-->
|
||||
<pre style="display: none;"><var:string value="flatContentAsString" /></pre>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ if (typeof textMailAccounts != 'undefined') {
|
|||
mailAccounts = new Array();
|
||||
}
|
||||
|
||||
var currentMessages = new Array();
|
||||
var currentMessages = {};
|
||||
var maxCachedMessages = 20;
|
||||
var cachedMessages = new Array();
|
||||
var currentMailbox = null;
|
||||
|
@ -743,13 +743,56 @@ function configureLinksInMessage() {
|
|||
if (editDraftButton)
|
||||
Event.observe(editDraftButton, "click",
|
||||
onMessageEditDraft.bindAsEventListener(editDraftButton));
|
||||
|
||||
configureiCalLinksInMessage();
|
||||
}
|
||||
|
||||
function configureiCalLinksInMessage() {
|
||||
var buttons = { "iCalendarAccept": "accept",
|
||||
"iCalendarDecline": "decline",
|
||||
"iCalendarTentative": "tentative",
|
||||
"iCalendarAddToCalendar": "addToCalendar",
|
||||
"iCalendarDeleteFromCalendar": "deleteFromCalendar" };
|
||||
|
||||
for (var key in buttons) {
|
||||
var button = $(key);
|
||||
if (button) {
|
||||
button.action = buttons[key];
|
||||
Event.observe(button, "click",
|
||||
onICalendarButtonClick.bindAsEventListener(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onICalendarButtonClick(event) {
|
||||
var link = $("iCalendarAttachment").value;
|
||||
if (link) {
|
||||
var urlstr = link + "/" + this.action;
|
||||
triggerAjaxRequest(urlstr, ICalendarButtonCallback,
|
||||
currentMailbox + "/"
|
||||
+ currentMessages[currentMailbox]);
|
||||
window.alert(urlstr);
|
||||
}
|
||||
}
|
||||
|
||||
function ICalendarButtonCallback(http) {
|
||||
if (http.readyState == 4)
|
||||
if (isHttpStatus204(http.status)) {
|
||||
var oldMsg = http.callbackData;
|
||||
var msg = currentMailbox + "/" + currentMessages[currentMailbox];
|
||||
if (oldMsg == msg) {
|
||||
deleteCachedMessage(oldMsg);
|
||||
loadMessage(currentMessages[currentMailbox]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resizeMailContent() {
|
||||
var headerTable = document.getElementsByClassName('mailer_fieldtable')[0];
|
||||
var contentDiv = document.getElementsByClassName('mailer_mailcontent')[0];
|
||||
|
||||
contentDiv.setStyle({ 'top': (Element.getHeight(headerTable) + headerTable.offsetTop) + 'px' });
|
||||
contentDiv.setStyle({ 'top':
|
||||
(Element.getHeight(headerTable) + headerTable.offsetTop) + 'px' });
|
||||
}
|
||||
|
||||
function onMessageContentMenu(event) {
|
||||
|
|
Loading…
Reference in New Issue