]> err.no Git - scalable-opengroupware.org/blobdiff - UI/MailPartViewers/UIxMailPartICalViewer.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1305 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / MailPartViewers / UIxMailPartICalViewer.m
index 8b31e5325e3e2f686b4726c30ead13a7b0d06e41..737e17d27b5a0e8f9ed7872f784ba1b8c7298eb0 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.
 */
 
+#import <NGObjWeb/WOResponse.h>
+
 #import <NGExtensions/NSCalendarDate+misc.h>
-#import <NGExtensions/NSNull+misc.h>
 #import <NGExtensions/NSObject+Logs.h>
 
 #import <NGImap4/NGImap4EnvelopeAddress.h>
 
 #import <SoObjects/SOGo/SOGoDateFormatter.h>
 #import <SoObjects/SOGo/SOGoUser.h>
+#import <SoObjects/Appointments/iCalEntityObject+SOGo.h>
 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
 #import <SoObjects/Appointments/SOGoAppointmentObject.h>
 #import <SoObjects/Mailer/SOGoMailObject.h>
+#import <SoObjects/Mailer/SOGoMailBodyPart.h>
 
 #import "UIxMailPartICalViewer.h"
 
 @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;
-}
-
-/* raw content handling */
-
-- (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).
-  */
-  return NSISOLatin1StringEncoding;
+  [attendee release]; attendee = nil;
+  [item release]; item = nil;
 }
 
 /* accessors */
   if (!inCalendar)
     {
       inCalendar
-        = [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
+       = [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
       [inCalendar retain];
     }
 
   return inCalendar;
 }
 
-- (BOOL)couldParseCalendar {
-  return [[self inCalendar] isNotNull];
+- (BOOL) couldParseCalendar
+{
+  return ([self inCalendar] != nil);
 }
 
-- (iCalEvent *)inEvent {
+- (iCalEvent *) inEvent
+{
   NSArray *events;
-  
-  if (self->inEvent != nil)
-    return [self->inEvent isNotNull] ? self->inEvent : nil;
-  
-  events = [[self inCalendar] events];
-  if ([events count] > 0) {
-    self->inEvent = [[events objectAtIndex:0] retain];
-    return self->inEvent;
-  }
-  else {
-    self->inEvent = [[NSNull null] retain];
-    return nil;
-  }
+  if (!inEvent)
+    {
+      events = [[self inCalendar] events];
+      if ([events count] > 0)
+       inEvent = [[events objectAtIndex:0] retain];
+    }
+
+  return inEvent;
 }
 
 /* formatters */
 
-- (SOGoDateFormatter *)dateFormatter {
-  if (self->dateFormatter == nil) {
-    dateFormatter = [[context activeUser] dateFormatterInContext: context];
-    [dateFormatter retain];
-  }
+- (SOGoDateFormatter *) dateFormatter
+{
+  if (!dateFormatter)
+    {
+      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]];
 }
 
 /* calendar folder support */
 
-- (id) calendarFolder
+- (SOGoAppointmentFolder *) calendarFolder
 {
   /* return scheduling calendar of currently logged-in user */
   SOGoUser *user;
   return [folder lookupName: @"personal" inContext: context acquire: NO];
 }
 
-- (id)storedEventObject {
+- (SOGoAppointmentObject *) storedEventObject
+{
   /* lookup object in the users Calendar */
-  id calendar;
-  
-  if (self->storedEventObject != nil)
-    return [self->storedEventObject isNotNull] ? self->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) {
-      // 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.
-      id tmp;
-      
-      tmp = [calendar lookupName:filename inContext:[self context] acquire:NO];
-      if ([tmp isNotNull] && ![tmp isKindOfClass:[NSException class]])
-       self->storedEventObject = [tmp retain];
+  SOGoAppointmentFolder *calendar;
+  NSString *filename;
+  if (!storedEventObject)
+    {
+      calendar = [self calendarFolder];
+      if ([calendar isKindOfClass: [NSException class]])
+       [self errorWithFormat:@"Did not find Calendar folder: %@", calendar];
+      else
+       {
+         filename = [calendar resourceNameForEventUID:[[self inEvent] uid]];
+         if (filename)
+           {
+             storedEventObject = [calendar lookupName: filename
+                                           inContext: [self context]
+                                           acquire: NO];
+             if ([storedEventObject isKindOfClass: [NSException class]])
+               storedEventObject = nil;
+             else
+               [storedEventObject retain];
+           }
+       }
     }
-  }
-  
-  if (self->storedEventObject == nil)
-    self->storedEventObject = [[NSNull null] retain];
-  
-  return self->storedEventObject;
+  return storedEventObject;
 }
 
-- (BOOL)isEventStoredInCalendar {
-  return [[self storedEventObject] isNotNull];
+- (BOOL) isEventStoredInCalendar
+{
+  return ([self storedEventObject] != nil);
 }
 
-- (iCalEvent *)storedEvent {
-  return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component: NO];
+- (iCalEvent *) storedEvent
+{
+  if (!storedEvent)
+    {
+      storedEvent = [[self storedEventObject] component: NO secure: NO];
+      [storedEvent retain];
+    }
+
+  return storedEvent;
 }
 
 /* organizer tracking */
   return [identity objectForKey: @"email"];
 }
 
-- (iCalEvent *)authorativeEvent {
-  /* DB is considered master, when in DB, ignore mail organizer */
-  return [self isEventStoredInCalendar]
-    ? [self storedEvent]
-    : [self inEvent];
-}
+- (iCalEvent *) authorativeEvent
+{
+  iCalEvent *authorativeEvent;
 
-- (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];
+  [self storedEvent];
+  if (!storedEvent
+      || ([storedEvent compare: [self inEvent]] == NSOrderedAscending))
+    authorativeEvent = inEvent;
+  else
+    authorativeEvent = [self storedEvent];
+
+  return authorativeEvent;
 }
 
-- (BOOL)isLoggedInUserAnAttendee {
-  NSString *loginEMail;
-  
-  if ((loginEMail = [self loggedInUserEMail]) == nil) {
-    [self warnWithFormat:@"Could not determine email of logged in user?"];
-    return NO;
-  }
+- (BOOL) isLoggedInUserTheOrganizer
+{
+  return [[self authorativeEvent] userIsOrganizer: [context activeUser]];
+}
 
-  return [[self authorativeEvent] isParticipant:loginEMail];
+- (BOOL) isLoggedInUserAnAttendee
+{
+  return [[self authorativeEvent] userIsParticipant: [context activeUser]];
 }
 
 /* derived fields */
 
 /* 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 {
-  return [[self storedReplyAttendee] isNotNull];
+
+- (BOOL) isReplySenderAnAttendee
+{
+  return ([self storedReplyAttendee] != nil);
 }
 
-/* action URLs */
+- (iCalPerson *) _emailParticipantWithEvent: (iCalEvent *) event
+{
+  NSString *emailFrom;
+  SOGoMailObject *mailObject;
+  NGImap4EnvelopeAddress *address;
 
-- (id)acceptLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/accept"];
-}
-- (id)declineLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/decline"];
+  mailObject = [[self clientObject] mailObject];
+  address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0];
+  emailFrom = [address baseEMail];
+
+  return [event findParticipantWithEmail: emailFrom];
 }
-- (id)tentativeLink {
-  return [[self pathToAttachmentObject] stringByAppendingString:@"/tentative"];
+
+- (BOOL) hasSenderStatusChanged
+{
+  iCalPerson *emailParticipant, *calendarParticipant;
+
+  [self inEvent];
+  [self storedEvent];
+  emailParticipant = [self _emailParticipantWithEvent: inEvent];
+  calendarParticipant = [self _emailParticipantWithEvent: storedEvent];
+
+  return ([[emailParticipant partStat]
+           caseInsensitiveCompare: [calendarParticipant partStat]]
+         != NSOrderedSame);
 }
 
 @end /* UIxMailPartICalViewer */