2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 Show plain/calendar mail parts.
28 #import <SOGoUI/SOGoDateFormatter.h>
29 #import <SOGo/SOGoUser.h>
30 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
31 #import <SoObjects/Appointments/SOGoAppointmentObject.h>
32 #import <SoObjects/Mailer/SOGoMailObject.h>
33 #import <NGCards/NGCards.h>
34 #import <NGImap4/NGImap4EnvelopeAddress.h>
37 #import "UIxMailPartICalViewer.h"
39 @implementation UIxMailPartICalViewer
42 [self->storedEventObject release];
43 [self->storedEvent release];
44 [self->attendee release];
46 [self->inCalendar release];
47 [self->inEvent release];
48 [self->dateFormatter release];
54 - (void)resetPathCaches {
55 [super resetPathCaches];
56 [self->inEvent release]; self->inEvent = nil;
57 [self->inCalendar release]; self->inCalendar = nil;
58 [self->storedEventObject release]; self->storedEventObject = nil;
59 [self->storedEvent release]; self->storedEvent = nil;
61 /* not strictly path-related, but useless without it anyway: */
62 [self->attendee release]; self->attendee = nil;
63 [self->item release]; self->item = nil;
66 /* raw content handling */
68 - (NSStringEncoding)fallbackStringEncoding {
70 iCalendar invitations sent by Outlook 2002 have the annoying bug that the
71 mail states an UTF-8 content encoding but the actual iCalendar content is
72 encoding in Latin-1 (or Windows Western?).
74 As a result the content decoding will fail (TODO: always?). In this case we
75 try to decode with Latin-1.
77 Note: we could check for the Outlook x-mailer, but it was considered better
78 to try Latin-1 as a fallback in any case (be tolerant).
80 return NSISOLatin1StringEncoding;
85 - (iCalCalendar *) inCalendar
90 = [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
97 - (BOOL)couldParseCalendar {
98 return [[self inCalendar] isNotNull];
101 - (iCalEvent *)inEvent {
104 if (self->inEvent != nil)
105 return [self->inEvent isNotNull] ? self->inEvent : nil;
107 events = [[self inCalendar] events];
108 if ([events count] > 0) {
109 self->inEvent = [[events objectAtIndex:0] retain];
110 return self->inEvent;
113 self->inEvent = [[NSNull null] retain];
120 - (SOGoDateFormatter *)dateFormatter {
121 if (self->dateFormatter == nil) {
122 self->dateFormatter =
123 [[SOGoDateFormatter alloc] initWithLocale:[self locale]];
124 [self->dateFormatter setFullWeekdayNameAndDetails];
126 return self->dateFormatter;
129 /* below is copied from UIxAppointmentView, can we avoid that? */
131 - (void)setAttendee:(id)_attendee {
132 ASSIGN(self->attendee, _attendee);
135 return self->attendee;
138 - (void)setItem:(id)_item {
139 ASSIGN(self->item, _item);
145 - (NSCalendarDate *)startTime {
146 NSCalendarDate *date;
148 date = [[self authorativeEvent] startDate];
149 [date setTimeZone:[[self clientObject] userTimeZone]];
153 - (NSCalendarDate *)endTime {
154 NSCalendarDate *date;
156 date = [[self authorativeEvent] endDate];
157 [date setTimeZone:[[self clientObject] userTimeZone]];
161 - (BOOL)isEndDateOnSameDay {
162 return [[self startTime] isDateOnSameDay:[self endTime]];
164 - (NSTimeInterval)duration {
165 return [[self endTime] timeIntervalSinceDate:[self startTime]];
168 /* calendar folder support */
170 - (id)calendarFolder {
171 /* return scheduling calendar of currently logged-in user */
172 return [[[self context] activeUser] schedulingCalendarInContext:
176 - (id)storedEventObject {
177 /* lookup object in the users Calendar */
180 if (self->storedEventObject != nil)
181 return [self->storedEventObject isNotNull] ? self->storedEventObject : nil;
183 calendar = [self calendarFolder];
184 if ([calendar isKindOfClass:[NSException class]]) {
185 [self errorWithFormat:@"Did not find Calendar folder: %@", calendar];
190 filename = [calendar resourceNameForEventUID:[[self inEvent] uid]];
191 if (filename != nil) {
192 // TODO: When we get an exception, this might be an auth issue meaning
193 // that the UID indeed exists but that the user has no access to
195 // Of course this is quite unusual for the private calendar though.
198 tmp = [calendar lookupName:filename inContext:[self context] acquire:NO];
199 if ([tmp isNotNull] && ![tmp isKindOfClass:[NSException class]])
200 self->storedEventObject = [tmp retain];
204 if (self->storedEventObject == nil)
205 self->storedEventObject = [[NSNull null] retain];
207 return self->storedEventObject;
210 - (BOOL)isEventStoredInCalendar {
211 return [[self storedEventObject] isNotNull];
214 - (iCalEvent *)storedEvent {
215 return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component];
218 /* organizer tracking */
220 - (NSString *)loggedInUserEMail {
221 return [[[self context] activeUser] email];
224 - (iCalEvent *)authorativeEvent {
225 /* DB is considered master, when in DB, ignore mail organizer */
226 return [self isEventStoredInCalendar]
231 - (BOOL)isLoggedInUserTheOrganizer {
232 NSString *loginEMail;
234 if ((loginEMail = [self loggedInUserEMail]) == nil) {
235 [self warnWithFormat:@"Could not determine email of logged in user?"];
239 return [[self authorativeEvent] isOrganizer:loginEMail];
242 - (BOOL)isLoggedInUserAnAttendee {
243 NSString *loginEMail;
245 if ((loginEMail = [self loggedInUserEMail]) == nil) {
246 [self warnWithFormat:@"Could not determine email of logged in user?"];
250 return [[self authorativeEvent] isParticipant:loginEMail];
255 - (NSString *)organizerDisplayName {
256 iCalPerson *organizer;
259 if ((organizer = [[self authorativeEvent] organizer]) != nil) {
260 cn = [organizer valueForKey:@"cnWithoutQuotes"];
261 if ([cn isNotNull] && [cn length] > 0)
264 cn = [organizer valueForKey:@"rfc822Email"];
265 if ([cn isNotNull] && [cn length] > 0)
268 return @"[error: unable to derive organizer name]";
271 return @"[todo: no organizer set, use 'from']";
276 - (NGImap4EnvelopeAddress *)replySenderAddress {
278 The iMIP reply is the sender of the mail, the 'attendees' are NOT set to
279 the actual attendees. BUT the attendee field contains the reply-status!
283 tmp = [[self clientObject] fromEnvelopeAddresses];
284 if ([tmp count] == 0) return nil;
285 return [tmp objectAtIndex:0];
288 - (NSString *)replySenderEMail {
289 return [[self replySenderAddress] email];
291 - (NSString *)replySenderBaseEMail {
292 return [[self replySenderAddress] baseEMail];
295 - (iCalPerson *)inReplyAttendee {
298 attendees = [[self inEvent] attendees];
299 if ([attendees count] == 0)
301 if ([attendees count] > 1)
302 [self warnWithFormat:@"More than one attendee in REPLY: %@", attendees];
304 return [attendees objectAtIndex:0];
306 - (iCalPerson *)storedReplyAttendee {
308 TODO: since an attendee can have multiple email addresses, maybe we
309 should translate the email to an internal uid and then retrieve
310 all emails addresses for matching the participant.
312 Note: -findParticipantWithEmail: does not parse the email!
317 if ((e = [self storedEvent]) == nil)
319 if ((p = [e findParticipantWithEmail:[self replySenderBaseEMail]]))
321 if ((p = [e findParticipantWithEmail:[self replySenderEMail]]))
325 - (BOOL)isReplySenderAnAttendee {
326 return [[self storedReplyAttendee] isNotNull];
332 return [[self pathToAttachmentObject] stringByAppendingString:@"/accept"];
335 return [[self pathToAttachmentObject] stringByAppendingString:@"/decline"];
337 - (id)tentativeLink {
338 return [[self pathToAttachmentObject] stringByAppendingString:@"/tentative"];
341 @end /* UIxMailPartICalViewer */