]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1259 d1b88da0-ebda-0310...
authorwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Sat, 10 Nov 2007 00:02:58 +0000 (00:02 +0000)
committerwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Sat, 10 Nov 2007 00:02:58 +0000 (00:02 +0000)
19 files changed:
ChangeLog
SoObjects/Contacts/SOGoContactGCSFolder.m
SoObjects/Contacts/SOGoContactLDAPFolder.m
SoObjects/Mailer/SOGoMailBodyPart.h
SoObjects/Mailer/SOGoMailBodyPart.m
SoObjects/Mailer/SOGoMailObject.m
SoObjects/SOGo/SOGoFolder.h
SoObjects/SOGo/SOGoFolder.m
SoObjects/SOGo/SOGoGCSFolder.h
SoObjects/SOGo/SOGoGCSFolder.m
UI/MailPartViewers/English.lproj/Localizable.strings
UI/MailPartViewers/French.lproj/Localizable.strings
UI/MailPartViewers/German.lproj/Localizable.strings
UI/MailPartViewers/UIxMailPartICalAction.m
UI/MailPartViewers/UIxMailPartICalViewer.h
UI/MailPartViewers/UIxMailPartICalViewer.m
UI/MailPartViewers/product.plist
UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox
UI/WebServerResources/MailerUI.js

index 6ed0724241c0896e09bd667003addb3d5e19846e..e7cd85b127b590c816fd1f729d666ea65848008d 100644 (file)
--- a/ChangeLog
+++ b/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.
index f8a7b4a2405a28246ad3c214fe0afe50ea807d85..7fd56ba8dc09e4f4803647e582ec4bd935bb10bd 100644 (file)
   return @"vcard-collection";
 }
 
-// /* GET */
-
-// - (id) GETAction: (id)_ctx
-// {
-//   // TODO: I guess this should really be done by SOPE (redirect to
-//   //       default method)
-//   WOResponse *r;
-//   NSString *uri;
-
-//   uri = [[_ctx request] uri];
-//   if (![uri hasSuffix:@"/"]) uri = [uri stringByAppendingString:@"/"];
-//   uri = [uri stringByAppendingString:@"view"];
-  
-//   r = [_ctx response];
-//   [r setStatus:302 /* moved */];
-//   [r setHeader:uri forKey:@"location"];
-//   return r;
-// }
-
 /* sorting */
 - (NSComparisonResult) compare: (id) otherFolder
 {
index 7345c9c5a34ba18fe2b2547a5a5ce8b1412596a5..b35f0d0d78502386b614253dc8c8ed9b715ac47e 100644 (file)
@@ -98,7 +98,6 @@
 {
   if ((self = [super init]))
     {
-      displayName = nil;
       entries = nil;
       ldapSource = nil;
     }
 
 - (void) dealloc
 {
-  [displayName release];
   [entries release];
   [ldapSource release];
   [super dealloc];
   ASSIGN (ldapSource, newLDAPSource);
 }
 
-- (NSString *) displayName
+- (NSArray *) davNamespaces
 {
-  return displayName;
+  return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
 }
 
-- (NSArray *) davNamespaces
+- (NSString *) groupDavResourceType
 {
-  return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
+  return @"vcard-collection";
 }
 
 - (id) lookupName: (NSString *) objectName
   return result;
 }
 
-- (NSArray *) davResourceType
-{
-  NSArray *rType, *groupDavCollection;
-
-  groupDavCollection = [NSArray arrayWithObjects: @"vcard-collection",
-                               XMLNS_GROUPDAV, nil];
-  rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
-
-  return rType;
-}
-
-- (NSString *) davContentType
+- (NSString *) davDisplayName
 {
-  return @"httpd/unix-directory";
+  return displayName;
 }
 
-- (BOOL) davIsCollection
+- (BOOL) isFolderish
 {
   return YES;
 }
 
-- (NSString *) davDisplayName
+/* folder type */
+
+- (NSString *) folderType
 {
-  return displayName;
+  return @"Contact";
 }
 
-- (BOOL) isFolderish
+- (NSString *) outlookFolderClass
 {
-  return YES;
+  return @"IPF.Contact";
 }
 
 /* sorting */
index bfb30aa2fa93897fdd38d59f402dd68d4316122f..c3d6509dd1bb04512dd50a57a4bc70439426a308 100644 (file)
@@ -62,6 +62,8 @@
 
 + (Class) bodyPartClassForKey: (NSString *) _key
                    inContext: (id) _ctx;
++ (Class) bodyPartClassForMimeType: (NSString *) mimeType
+                        inContext: (id) _ctx;
 
 @end
 
index 550fc04a547ac1b0f442fefaeb33e32961283c79..5c32a2ef22c77e0309c2eaf220379d49c1f07b49 100644 (file)
@@ -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 {
index 9397b725ea989e9186842bf1bbaad8e11af8934e..0cda214ec520d4af68db69a6d0854328d0b4309f 100644 (file)
@@ -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;
     }
index 1292b96e39e9df7e3f3bf087253bad2b022d0414..afb55cfc5e32043a966d49760e83d98d70c73ff9 100644 (file)
 
 @end
 
+@interface SOGoFolder (GroupDAVExtensions)
+
+- (NSString *) groupDavResourceType;
+
+@end
+
 #endif /* SOGOFOLDER_H */
index 3f49d254fb38c42a57bdc7434ac7f30cb3c79c00..aae0a632b6accfc91c8b35446ef6b09215919b54 100644 (file)
@@ -26,6 +26,8 @@
 
 #import <NGObjWeb/SoSelectorInvocation.h>
 
+#import <SaxObjC/XMLNamespaces.h>
+
 #import "NSString+Utilities.h"
 
 #import "SOGoFolder.h"
   return @"httpd/unix-directory";
 }
 
+- (NSArray *) davResourceType
+{
+  NSArray *rType, *groupDavCollection;
+
+  if ([self respondsToSelector: @selector (groupDavResourceType)])
+    {
+      groupDavCollection
+       = [NSArray arrayWithObjects: [self groupDavResourceType],
+                  XMLNS_GROUPDAV, nil];
+      rType = [NSArray arrayWithObjects: @"collection", groupDavCollection,
+                      nil];
+    }
+  else
+    rType = [NSArray arrayWithObject: @"collection"];
+
+  return rType;
+}
+
 /* folder type */
 
 - (NSString *) outlookFolderClass
index 21fb8934ab5878686355fbbbaaf3f07c1283d541..6a89dd4b2dac0d72bf3c08308e547be1e05b2a09 100644 (file)
 
 @end
 
-@interface SOGoGCSFolder (GroupDAVExtensions)
-
-- (NSString *) groupDavResourceType;
-
-@end
-
 #endif /* __SOGo_SOGoGCSFolder_H__ */
index a5118ea82b5bc1078e144ad8f3f8d32f678636ed..5b938f0916a7381aff2d8903b0b6e5cedcb6841f 100644 (file)
@@ -381,24 +381,6 @@ static NSString *defaultUserID = @"<default>";
   return nil;
 }
 
-- (NSArray *) davResourceType
-{
-  NSArray *rType, *groupDavCollection;
-
-  if ([self respondsToSelector: @selector (groupDavResourceType)])
-    {
-      groupDavCollection
-       = [NSArray arrayWithObjects: [self groupDavResourceType],
-                  XMLNS_GROUPDAV, nil];
-      rType = [NSArray arrayWithObjects: @"collection", groupDavCollection,
-                      nil];
-    }
-  else
-    rType = [NSArray arrayWithObject: @"collection"];
-
-  return rType;
-}
-
 - (NSArray *) toOneRelationshipKeys
 {
   /* toOneRelationshipKeys are the 'files' contained in a folder */
index c120183f84c7827ea8a2dca251c212b06263a67e..5fadd32d1e5f21ca7347cf32b82bf7e140d92937 100644 (file)
@@ -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";
 
index ad6492f83793b82eaeaa1731a4654b92661a9f91..b5db9cecc31a6b038f0460836eda3031f160870c 100644 (file)
@@ -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";
 
index c120183f84c7827ea8a2dca251c212b06263a67e..b96425ebc689f849cf35f5b608d04ee2392a776d 100644 (file)
@@ -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";
index 7f1cf9e8f3dd694792b685fdfcaafc43b3009157..f83a338198df9c06aa5eb39da2c790b4b5b6bde1 100644 (file)
@@ -1,76 +1,63 @@
-/*
-  Copyright (C) 2005 SKYRIX Software AG
-
-  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>
+/* 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.
+ */
+
+#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"];
+- (WOResponse *) _changePartStatusAction: (NSString *) _newStatus
+{
+  return [self responseWithStatus: 404];
+}
 
-  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 *) markAcceptedAction
+{
+  return [self _changePartStatusAction: @"ACCEPTED"];
 }
 
-- (id)changePartStatusAction:(NSString *)_newStatus {
-  [self logWithFormat:@"TODO: should %@: %@", _newStatus, [self clientObject]];
-  return [self redirectToViewerWithError:
-                [_newStatus stringByAppendingString:@" not implemented!"]];
+- (WOResponse *) markDeclinedAction
+{
+  return [self _changePartStatusAction: @"DECLINED"];
 }
 
-- (id)markAcceptedAction {
-  return [self changePartStatusAction:@"ACCEPTED"];
+- (WOResponse *) markTentativeAction
+{
+  return [self _changePartStatusAction: @"TENTATIVE"];
 }
-- (id)markDeclinedAction {
-  return [self changePartStatusAction:@"DECLINED"];
+
+- (WOResponse *) addToCalendarAction
+{
+  return [self responseWithStatus: 404];
 }
-- (id)markTentativeAction {
-  return [self changePartStatusAction:@"TENTATIVE"];
+
+- (WOResponse *) deleteFromCalendarAction
+{
+  return [self responseWithStatus: 404];
 }
 
 @end /* UIxMailPartICalAction */
index 08ed095dd08debf504a2c3817ee8a39fc9b80a1b..98d75abe40648e9680ce0e5eeb91d43ddbf91e23 100644 (file)
 
   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.
 */
 
 @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;
index 8b31e5325e3e2f686b4726c30ead13a7b0d06e41..ec8c18af87cf1f085a1f4791a31584ee6d86077b 100644 (file)
@@ -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
 
   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.
 */
 
 
 @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;
 }
   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
   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];
 {
   NSCalendarDate *date;
   NSTimeZone *timeZone;
-  
   date = [[self authorativeEvent] endDate];
   timeZone = [[context activeUser] timeZone];
   [date setTimeZone: timeZone];
   return date;
 }
 
-- (BOOL)isEndDateOnSameDay {
+- (BOOL) isEndDateOnSameDay
+{
   return [[self startTime] isDateOnSameDay:[self endTime]];
 }
-- (NSTimeInterval)duration {
+
+- (NSTimeInterval) duration
+{
   return [[self endTime] timeIntervalSinceDate:[self startTime]];
 }
 
   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];
 }
 
   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;
 
 /* 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;
-}
-- (BOOL)isReplySenderAnAttendee {
-  return [[self storedReplyAttendee] isNotNull];
-}
 
-/* action URLs */
+  p = nil;
+  e = [self storedEvent];
+  if (e)
+    {
+      p = [e findParticipantWithEmail: [self replySenderBaseEMail]];
+      if (!p)
+       p = [e findParticipantWithEmail:[self replySenderEMail]];
+    }
 
-- (id)acceptLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/accept"];
-}
-- (id)declineLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/decline"];
+  return p;
 }
-- (id)tentativeLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/tentative"];
+
+- (BOOL) isReplySenderAnAttendee
+{
+  return [[self storedReplyAttendee] isNotNull];
 }
 
 @end /* UIxMailPartICalViewer */
index a042a538bf66804f2ba22949237543eca1438482..145b47245752c3ab70d71fed96994ec7a2f40b22 100644 (file)
           actionClass = "UIxMailPartICalAction"; 
           actionName  = "markTentative";
         };
+        addToCalendar = {
+          protectedBy = "View";
+          actionClass = "UIxMailPartICalAction"; 
+          actionName  = "addToCalendar";
+        };
+        deleteFromCalendar = {
+          protectedBy = "View";
+          actionClass = "UIxMailPartICalAction"; 
+          actionName  = "deleteFromCalendar";
+        };
       };
     };
   };
index 72a2fc92d02a144589f4f753434ce186f3cdcd9b..87b072dab81d4ae1cb4080bf4fb027bdd8ee1913 100644 (file)
 <?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>
+
+  <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>
 
-    <pre><var:string value="flatContentAsString" /></pre>
-  </fieldset>
- </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="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 condition="inCalendar.method" const:value="ADD">
+       <!-- TODO -->
+       <p><var:string label:value="add_info_text" /></p>
       </var:if>
-      <var:if condition="isLoggedInUserAnAttendee">
-        (<var:string label:value="you_are_an_attendee"/>)
+
+
+      <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>
-    </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>
-      </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 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 -->
-
-    
-    <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 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>
 
-      <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>
+
+      <!-- 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>
       
-      <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>
-
-    
-    <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 -->
-
-<!--
+    </fieldset>
+  </var:if><!-- could parse -->
+
+  <!--
   <var:string value="appointment" />
   <br />
   <br />
   <br />
--->
+  -->
   <pre style="display: none;"><var:string value="flatContentAsString" /></pre>
 </div>
index 450b5f2a4e4ff7380e076b693467f3a7b2c0b580..9f8ce6a2882d81d6de6fea65e16c103ab9babb56 100644 (file)
@@ -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) {