Monotone-Parent: 025330d36e1af8f073a0b0a02b64a65e36da2ffb
Monotone-Revision: 62c54dca797fd3a058e6792e05ab111266735658 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-11-05T16:37:17 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
dcd79d986a
commit
cc21c0c948
36
ChangeLog
36
ChangeLog
|
@ -1,3 +1,39 @@
|
||||||
|
2007-11-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* UI/MailerUI/WOContext+UIxMailer.m ([-mailSubjectFormatter]):
|
||||||
|
removed method.
|
||||||
|
|
||||||
|
* UI/MailerUI/UIxMailView.m ([UIxMailView -messageSubject]): new
|
||||||
|
method replacing -objectTitle, written like the ones below.
|
||||||
|
|
||||||
|
* UI/MailerUI/UIxMailListView.m ([UIxMailListView
|
||||||
|
-messageSubject]): rewrote method to act the one below.
|
||||||
|
|
||||||
|
* UI/MailPartViewers/UIxMailPartMessageViewer.m
|
||||||
|
([UIxMailPartMessageViewer -messageSubject]): new method that
|
||||||
|
returns the decoded mail subject or "Untitled" if the subject is
|
||||||
|
empty.
|
||||||
|
|
||||||
|
* SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject
|
||||||
|
-decodedSubject]): new method that invoke -decodedSubject from the
|
||||||
|
NSString and NSData class, depending on the identity of the
|
||||||
|
subject obtained from the envelope.
|
||||||
|
|
||||||
|
* SoObjects/Mailer/SOGoMailObject+Draft.m ([SOGoMailObject
|
||||||
|
-subjectForReply]): take the value of -[SOGoMail decodedSubject]
|
||||||
|
instead of the subject of the envelope.
|
||||||
|
([SOGoMailObject -filenameForForward]): same as above.
|
||||||
|
([SOGoMailObject -subjectForForward]): same as above.
|
||||||
|
|
||||||
|
* SoObjects/Mailer/NSString+Mail.m ([NSString -decodedSubject]):
|
||||||
|
same as below for NSString.
|
||||||
|
|
||||||
|
* SoObjects/Mailer/NSData+Mail.m ([NSData -decodedSubject]): new
|
||||||
|
method that decodes the subject of a mail taken as an NSData
|
||||||
|
instance. Handling the exceptions and the badly formatted headers.
|
||||||
|
|
||||||
|
* UI/MailerUI/UIxSubjectFormatter.[hm]: dropped class module.
|
||||||
|
|
||||||
2007-11-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2007-11-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* SoObjects/SOGo/SOGoFolder.m ([SOGoFolder
|
* SoObjects/SOGo/SOGoFolder.m ([SOGoFolder
|
||||||
|
|
|
@ -52,4 +52,50 @@
|
||||||
return decodedData;
|
return decodedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) decodedSubject
|
||||||
|
{
|
||||||
|
const char *cData, *endFlag;
|
||||||
|
unsigned int len;
|
||||||
|
NSString *converted, *decodedSubject;
|
||||||
|
|
||||||
|
cData = [self bytes];
|
||||||
|
len = [self length];
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
decodedSubject = nil;
|
||||||
|
if (len > 6)
|
||||||
|
{
|
||||||
|
endFlag = cData + len - 2;
|
||||||
|
if (*cData == '=' && *(cData + 1) == '?'
|
||||||
|
&& *endFlag == '?' && *(endFlag + 1) == '=')
|
||||||
|
{
|
||||||
|
converted
|
||||||
|
= [[NSString alloc] initWithData: self
|
||||||
|
encoding: NSASCIIStringEncoding];
|
||||||
|
if (converted)
|
||||||
|
{
|
||||||
|
[converted autorelease];
|
||||||
|
decodedSubject = [converted stringByDecodingQuotedPrintable];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!decodedSubject)
|
||||||
|
{
|
||||||
|
decodedSubject
|
||||||
|
= [[NSString alloc] initWithData: self
|
||||||
|
encoding: NSUTF8StringEncoding];
|
||||||
|
if (!decodedSubject)
|
||||||
|
decodedSubject
|
||||||
|
= [[NSString alloc] initWithData: self
|
||||||
|
encoding: NSISOLatin1StringEncoding];
|
||||||
|
[decodedSubject autorelease];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
decodedSubject = @"";
|
||||||
|
|
||||||
|
return decodedSubject;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
- (NSString *) htmlToText;
|
- (NSString *) htmlToText;
|
||||||
|
|
||||||
|
- (NSString *) decodedSubject;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif /* NSSTRING_MAIL_H */
|
#endif /* NSSTRING_MAIL_H */
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#import <SaxObjC/SaxLexicalHandler.h>
|
#import <SaxObjC/SaxLexicalHandler.h>
|
||||||
#import <SaxObjC/SaxXMLReader.h>
|
#import <SaxObjC/SaxXMLReader.h>
|
||||||
#import <SaxObjC/SaxXMLReaderFactory.h>
|
#import <SaxObjC/SaxXMLReaderFactory.h>
|
||||||
|
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
||||||
#import <NGExtensions/NSString+misc.h>
|
#import <NGExtensions/NSString+misc.h>
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
|
|
||||||
|
@ -348,4 +349,20 @@
|
||||||
return [handler result];
|
return [handler result];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) decodedSubject
|
||||||
|
{
|
||||||
|
NSString *decodedSubject;
|
||||||
|
|
||||||
|
if ([self hasPrefix: @"=?"] && [self hasSuffix: @"?="])
|
||||||
|
{
|
||||||
|
decodedSubject = [self stringByDecodingQuotedPrintable];
|
||||||
|
if (!decodedSubject)
|
||||||
|
decodedSubject = self;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
decodedSubject = self;
|
||||||
|
|
||||||
|
return decodedSubject;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
hasPrefix = NO;
|
hasPrefix = NO;
|
||||||
|
|
||||||
subject = [[self envelope] subject];
|
subject = [self decodedSubject];
|
||||||
i = 0;
|
i = 0;
|
||||||
while (!hasPrefix && replyPrefixes[i])
|
while (!hasPrefix && replyPrefixes[i])
|
||||||
if ([subject hasPrefix: replyPrefixes[i]])
|
if ([subject hasPrefix: replyPrefixes[i]])
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
};
|
};
|
||||||
unsigned int count, length;
|
unsigned int count, length;
|
||||||
|
|
||||||
subject = [[self envelope] subject];
|
subject = [self decodedSubject];
|
||||||
length = [subject length];
|
length = [subject length];
|
||||||
if (!length)
|
if (!length)
|
||||||
{
|
{
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
{
|
{
|
||||||
NSString *subject, *newSubject;
|
NSString *subject, *newSubject;
|
||||||
|
|
||||||
subject = [[self envelope] subject];
|
subject = [self decodedSubject];
|
||||||
if ([subject length] > 0)
|
if ([subject length] > 0)
|
||||||
newSubject = [NSString stringWithFormat: @"[Fwd: %@]", subject];
|
newSubject = [NSString stringWithFormat: @"[Fwd: %@]", subject];
|
||||||
else
|
else
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
|
|
||||||
- (NGImap4Envelope *)envelope;
|
- (NGImap4Envelope *)envelope;
|
||||||
- (NSString *)subject;
|
- (NSString *)subject;
|
||||||
|
- (NSString *)decodedSubject;
|
||||||
- (NSCalendarDate *)date;
|
- (NSCalendarDate *)date;
|
||||||
- (NSArray *)fromEnvelopeAddresses;
|
- (NSArray *)fromEnvelopeAddresses;
|
||||||
- (NSArray *)toEnvelopeAddresses;
|
- (NSArray *)toEnvelopeAddresses;
|
||||||
|
|
|
@ -261,6 +261,11 @@ static BOOL debugSoParts = NO;
|
||||||
return [[self envelope] subject];
|
return [[self envelope] subject];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) decodedSubject
|
||||||
|
{
|
||||||
|
return [[self subject] decodedSubject];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *) date
|
- (NSCalendarDate *) date
|
||||||
{
|
{
|
||||||
NSTimeZone *userTZ;
|
NSTimeZone *userTZ;
|
||||||
|
|
|
@ -11,7 +11,11 @@ add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||||
publish_info_text = "The sender informs you of the attached event.";
|
publish_info_text = "The sender informs you of the attached event.";
|
||||||
cancel_info_text = "Your invitation or the whole event was canceled.";
|
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.";
|
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.";
|
||||||
Organizer = "Organizer";
|
Appointment = "Appointment";
|
||||||
|
|
||||||
|
Organizer = "Organisateur";
|
||||||
|
Time = "Time";
|
||||||
|
Attendees = "Attendees";
|
||||||
request_info = "invites you to participate in a meeting.";
|
request_info = "invites you to participate in a meeting.";
|
||||||
do_add_to_cal = "add to calendar";
|
do_add_to_cal = "add to calendar";
|
||||||
do_del_from_cal = "delete from calendar";
|
do_del_from_cal = "delete from calendar";
|
||||||
|
@ -21,3 +25,7 @@ do_tentative = "tentative";
|
||||||
do_update_status = "update status in calendar";
|
do_update_status = "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_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.";
|
||||||
|
|
||||||
|
"Untitled" = "Untitled";
|
||||||
|
|
||||||
|
"Size" = "Size";
|
||||||
|
|
|
@ -26,4 +26,6 @@ do_update_status = "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_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é.";
|
||||||
|
|
||||||
|
"Untitled" = "Sans titre";
|
||||||
|
|
||||||
"Size" = "Taille";
|
"Size" = "Taille";
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
ACCEPTED = "Accepté";
|
ACCEPTED = "accepted";
|
||||||
COMPLETED = "Terminé";
|
COMPLETED = "completed";
|
||||||
DECLINED = "Refusé";
|
DECLINED = "declined";
|
||||||
DELEGATED = "Délégué";
|
DELEGATED = "delegated";
|
||||||
IN-PROCESS = "En cours de traitement";
|
IN-PROCESS = "in process";
|
||||||
NEEDS-ACTION = "Prise de décision nécessaire";
|
NEEDS-ACTION = "needs action";
|
||||||
TENTATIVE = "Proposition";
|
TENTATIVE = "tentative";
|
||||||
organized_by_you = "vous êtes l'organisateur";
|
organized_by_you = "organized by you";
|
||||||
you_are_an_attendee = "vous êtes invité";
|
you_are_an_attendee = "you are an attendee";
|
||||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
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é.";
|
publish_info_text = "The sender informs you of the attached event.";
|
||||||
cancel_info_text = "Votre invitation ou l'événement au complet a été annulé.";
|
cancel_info_text = "Your invitation or the whole event was canceled.";
|
||||||
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é.";
|
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 = "Événement";
|
Appointment = "Appointment";
|
||||||
|
|
||||||
Organizer = "Organisateur";
|
Organizer = "Organisateur";
|
||||||
Time = "Date";
|
Time = "Time";
|
||||||
Attendees = "Invités";
|
Attendees = "Attendees";
|
||||||
request_info = "vous invite à une réunion.";
|
request_info = "invites you to participate in a meeting.";
|
||||||
do_add_to_cal = "ajouter à l'agenda";
|
do_add_to_cal = "add to calendar";
|
||||||
do_del_from_cal = "effacer de l'agenda";
|
do_del_from_cal = "delete from calendar";
|
||||||
do_accept = "accepter";
|
do_accept = "accept";
|
||||||
do_decline = "decliner";
|
do_decline = "decline";
|
||||||
do_tentative = "tentative";
|
do_tentative = "tentative";
|
||||||
do_update_status = "mettre l'agenda à jour";
|
do_update_status = "update status in calendar";
|
||||||
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_no_attendee = "You received a reply to a scheduling event but the sender of the reply is not a participant.";
|
||||||
reply_info = "Ceci est une réponse à un événement que vous avez organisé.";
|
reply_info = "This is a reply to an event invitation done by you.";
|
||||||
|
|
||||||
"Size" = "Taille";
|
"Untitled" = "Untitled";
|
||||||
|
|
||||||
|
"Size" = "Size";
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#import <NGImap4/NGImap4Envelope.h>
|
#import <NGImap4/NGImap4Envelope.h>
|
||||||
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
||||||
|
|
||||||
|
#import <SoObjects/Mailer/NSData+Mail.h>
|
||||||
|
#import <SoObjects/Mailer/NSString+Mail.h>
|
||||||
|
|
||||||
#import <UI/MailerUI/WOContext+UIxMailer.h>
|
#import <UI/MailerUI/WOContext+UIxMailer.h>
|
||||||
#import "UIxMailRenderingContext.h"
|
#import "UIxMailRenderingContext.h"
|
||||||
|
|
||||||
|
@ -144,6 +147,19 @@
|
||||||
return [formattedComponents componentsJoinedByString: @", "];
|
return [formattedComponents componentsJoinedByString: @", "];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) messageSubject
|
||||||
|
{
|
||||||
|
id baseSubject;
|
||||||
|
NSString *subject;
|
||||||
|
|
||||||
|
baseSubject = [[self envelope] subject];
|
||||||
|
subject = [baseSubject decodedSubject];
|
||||||
|
if (![subject length])
|
||||||
|
subject = [self labelForKey: @"Untitled"];
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *) fromAddresses
|
- (NSString *) fromAddresses
|
||||||
{
|
{
|
||||||
NSArray *from;
|
NSArray *from;
|
||||||
|
|
|
@ -127,6 +127,8 @@
|
||||||
"Mark Unread" = "Mark Unread";
|
"Mark Unread" = "Mark Unread";
|
||||||
"Mark Read" = "Mark Read";
|
"Mark Read" = "Mark Read";
|
||||||
|
|
||||||
|
"Untitled" = "Untitled";
|
||||||
|
|
||||||
/* Tree */
|
/* Tree */
|
||||||
|
|
||||||
"SentFolderName" = "Sent";
|
"SentFolderName" = "Sent";
|
||||||
|
|
|
@ -122,11 +122,13 @@
|
||||||
"next" = "Suivant";
|
"next" = "Suivant";
|
||||||
"last" = "Dernier";
|
"last" = "Dernier";
|
||||||
|
|
||||||
|
"msgnumber_to" = "à";
|
||||||
|
"msgnumber_of" = "de";
|
||||||
|
|
||||||
"Mark Unread" = "Marquer comme non lu";
|
"Mark Unread" = "Marquer comme non lu";
|
||||||
"Mark Read" = "Marquer comme lu";
|
"Mark Read" = "Marquer comme lu";
|
||||||
|
|
||||||
"msgnumber_to" = "à";
|
"Untitled" = "Sans titre";
|
||||||
"msgnumber_of" = "de";
|
|
||||||
|
|
||||||
/* Tree */
|
/* Tree */
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ MailerUI_OBJC_FILES += \
|
||||||
MailerUIProduct.m \
|
MailerUIProduct.m \
|
||||||
\
|
\
|
||||||
UIxMailFormatter.m \
|
UIxMailFormatter.m \
|
||||||
UIxSubjectFormatter.m \
|
|
||||||
UIxEnvelopeAddressFormatter.m \
|
UIxEnvelopeAddressFormatter.m \
|
||||||
WOContext+UIxMailer.m \
|
WOContext+UIxMailer.m \
|
||||||
\
|
\
|
||||||
|
|
|
@ -105,11 +105,13 @@
|
||||||
"next" = "Nächste";
|
"next" = "Nächste";
|
||||||
"last" = "Letzter";
|
"last" = "Letzter";
|
||||||
|
|
||||||
|
"msgnumber_to" = "bis";
|
||||||
|
"msgnumber_of" = "von";
|
||||||
|
|
||||||
"Mark Unread" = "Als ungelesen markieren";
|
"Mark Unread" = "Als ungelesen markieren";
|
||||||
"Mark Read" = "Als gelesen markieren";
|
"Mark Read" = "Als gelesen markieren";
|
||||||
|
|
||||||
"msgnumber_to" = "bis";
|
"Untitled" = "Untitled";
|
||||||
"msgnumber_of" = "von";
|
|
||||||
|
|
||||||
/* Tree */
|
/* Tree */
|
||||||
|
|
||||||
|
|
|
@ -63,32 +63,6 @@
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: the subject formatter should deal with the various 're:' like prefixes
|
|
||||||
and translate them into the native languages?
|
|
||||||
(or something like Re(5): ?)
|
|
||||||
*/
|
|
||||||
|
|
||||||
@interface UIxSubjectFormatter : UIxMailFormatter
|
|
||||||
{
|
|
||||||
unsigned maxLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* configuration */
|
|
||||||
|
|
||||||
- (unsigned int)maxLength;
|
|
||||||
|
|
||||||
/* labels */
|
|
||||||
|
|
||||||
- (NSString *)missingSubjectLabel;
|
|
||||||
|
|
||||||
/* specific formatters */
|
|
||||||
|
|
||||||
- (NSString *)stringForStringValue:(NSString *)_subject;
|
|
||||||
- (NSString *)stringForDataValue:(NSData *)_subject;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface UIxEnvelopeAddressFormatter : UIxMailFormatter
|
@interface UIxEnvelopeAddressFormatter : UIxMailFormatter
|
||||||
{
|
{
|
||||||
NSString *separator;
|
NSString *separator;
|
||||||
|
|
|
@ -100,18 +100,13 @@
|
||||||
|
|
||||||
- (NSString *) messageSubject
|
- (NSString *) messageSubject
|
||||||
{
|
{
|
||||||
|
id baseSubject;
|
||||||
NSString *subject;
|
NSString *subject;
|
||||||
id envSubject;
|
|
||||||
|
|
||||||
envSubject = [[message valueForKey: @"envelope"] subject];
|
baseSubject = [[message valueForKey: @"envelope"] subject];
|
||||||
if ([envSubject isKindOfClass: [NSData class]])
|
subject = [baseSubject decodedSubject];
|
||||||
{
|
if (![subject length])
|
||||||
subject = [[NSString alloc] initWithData: envSubject
|
subject = [self labelForKey: @"Untitled"];
|
||||||
encoding: NSUTF8StringEncoding];
|
|
||||||
[subject autorelease];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
subject = envSubject;
|
|
||||||
|
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,16 +88,22 @@ static NSString *mailETag = nil;
|
||||||
return currentAddress;
|
return currentAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) objectTitle
|
- (NSString *) messageSubject
|
||||||
{
|
{
|
||||||
return [[self clientObject] subject];
|
NSString *subject;
|
||||||
|
|
||||||
|
subject = [[self clientObject] decodedSubject];
|
||||||
|
if (![subject length])
|
||||||
|
subject = [self labelForKey: @"Untitled"];
|
||||||
|
|
||||||
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) panelTitle
|
- (NSString *) panelTitle
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat: @"%@: %@",
|
return [NSString stringWithFormat: @"%@: %@",
|
||||||
[self labelForKey: @"View Mail"],
|
[self labelForKey: @"View Mail"],
|
||||||
[self objectTitle]];
|
[self messageSubject]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* links (DUP to UIxMailPartViewer!) */
|
/* links (DUP to UIxMailPartViewer!) */
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
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
|
|
||||||
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 <NGExtensions/NSNull+misc.h>
|
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
|
||||||
#import <NGMail/NGMimeMessageParser.h>
|
|
||||||
|
|
||||||
#import "UIxMailFormatter.h"
|
|
||||||
|
|
||||||
@implementation UIxSubjectFormatter
|
|
||||||
|
|
||||||
static Class StrClass = Nil;
|
|
||||||
static Class DataClass = Nil;
|
|
||||||
|
|
||||||
+ (void)initialize {
|
|
||||||
StrClass = [NSString class];
|
|
||||||
DataClass = [NSData class];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init {
|
|
||||||
if ((self = [super init])) {
|
|
||||||
self->maxLength = 64;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* configuration */
|
|
||||||
|
|
||||||
- (unsigned int)maxLength {
|
|
||||||
return self->maxLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)shouldDecodeQP {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* labels */
|
|
||||||
|
|
||||||
- (NSString *)missingSubjectLabel {
|
|
||||||
return [self labelForKey:@"no_subject"];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* specific formatters */
|
|
||||||
|
|
||||||
- (NSString *)stringForStringValue:(NSString *)_subject {
|
|
||||||
NSString *s;
|
|
||||||
|
|
||||||
/* quoted printable */
|
|
||||||
if ([self shouldDecodeQP] && [_subject hasPrefix:@"=?"]) {
|
|
||||||
/*
|
|
||||||
Now this is interesting. An NSString should not contain QP markers since
|
|
||||||
it is already 'charset decoded'. This is also why the NGMime parser
|
|
||||||
expects an NSData.
|
|
||||||
|
|
||||||
Sample:
|
|
||||||
=?iso-8859-1?q?Yannick=20DAmboise?=
|
|
||||||
|
|
||||||
Note: -stringByDecodingQuotedPrintable only expands =D0 like charcodes!
|
|
||||||
*/
|
|
||||||
NSData *data;
|
|
||||||
|
|
||||||
/* header field data should always be ASCII */
|
|
||||||
data = [_subject dataUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
return [self stringForDataValue:data];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([_subject length] == 0)
|
|
||||||
return [self missingSubjectLabel];
|
|
||||||
|
|
||||||
if ([_subject length] <= [self maxLength])
|
|
||||||
return _subject;
|
|
||||||
|
|
||||||
s = [_subject substringToIndex:([self maxLength] - 3)];
|
|
||||||
return [s stringByAppendingString:@"..."];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)stringForDataValue:(NSData *)_subject {
|
|
||||||
NSString *s, *r;
|
|
||||||
unsigned len;
|
|
||||||
|
|
||||||
if ((len = [_subject length]) == 0)
|
|
||||||
return [self missingSubjectLabel];
|
|
||||||
|
|
||||||
/* check for quoted printable */
|
|
||||||
|
|
||||||
if (len > 6 && [self shouldDecodeQP]) {
|
|
||||||
const unsigned char *b;
|
|
||||||
|
|
||||||
b = [_subject bytes];
|
|
||||||
if (b[0] == '=' && b[1] == '?') {
|
|
||||||
/* eg: '=?iso-8859-1?q?Yannick=20DAmboise?=' */
|
|
||||||
id t;
|
|
||||||
|
|
||||||
t = [_subject decodeQuotedPrintableValueOfMIMEHeaderField:@"subject"];
|
|
||||||
if ([t isNotNull])
|
|
||||||
return [self stringForObjectValue:t];
|
|
||||||
else
|
|
||||||
[self warnWithFormat:@"decoding QP failed: '%@'", t];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* continue NSData processing */
|
|
||||||
|
|
||||||
[self warnWithFormat:@"NSData subject, using UTF-8 to decode."];
|
|
||||||
|
|
||||||
// TODO: exception handler?
|
|
||||||
s = [[NSString alloc] initWithData:_subject encoding:NSUTF8StringEncoding];
|
|
||||||
if (s == nil) {
|
|
||||||
[self errorWithFormat:@"could do not decode NSData subject!"];
|
|
||||||
return [self labelForKey:@"Error_CouldNotDecodeSubject"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([s hasPrefix:@"=?"]) { // TODO: this should never happen?
|
|
||||||
[self warnWithFormat:@"subject still has QP signature: '%@'", s];
|
|
||||||
r = [s copy];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
r = [[self stringForStringValue:s] copy];
|
|
||||||
[s release];
|
|
||||||
return [r autorelease];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* formatter entry function */
|
|
||||||
|
|
||||||
- (NSString *)stringForObjectValue:(id)_subject {
|
|
||||||
if (![_subject isNotNull])
|
|
||||||
return [self missingSubjectLabel];
|
|
||||||
|
|
||||||
if ([_subject isKindOfClass:StrClass])
|
|
||||||
return [self stringForStringValue:_subject];
|
|
||||||
if ([_subject isKindOfClass:DataClass])
|
|
||||||
return [self stringForDataValue:_subject];
|
|
||||||
|
|
||||||
return [self stringForStringValue:[_subject stringValue]];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end /* UIxSubjectFormatter */
|
|
|
@ -32,12 +32,11 @@
|
||||||
|
|
||||||
@class NSFormatter;
|
@class NSFormatter;
|
||||||
|
|
||||||
@interface WOContext(UIxMailer)
|
@interface WOContext (UIxMailer)
|
||||||
|
|
||||||
- (NSFormatter *)mailSubjectFormatter;
|
- (NSFormatter *) mailDateFormatter;
|
||||||
- (NSFormatter *)mailDateFormatter;
|
- (NSFormatter *) mailEnvelopeAddressFormatter;
|
||||||
- (NSFormatter *)mailEnvelopeAddressFormatter;
|
- (NSFormatter *) mailEnvelopeFullAddressFormatter;
|
||||||
- (NSFormatter *)mailEnvelopeFullAddressFormatter;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,6 @@
|
||||||
// TODO: make configurable
|
// TODO: make configurable
|
||||||
// TODO: cache!
|
// TODO: cache!
|
||||||
|
|
||||||
- (NSFormatter *) mailSubjectFormatter
|
|
||||||
{
|
|
||||||
return [[[UIxSubjectFormatter alloc] init] autorelease];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSFormatter *) mailDateFormatter
|
- (NSFormatter *) mailDateFormatter
|
||||||
{
|
{
|
||||||
return [[self activeUser] dateFormatterInContext: self];
|
return [[self activeUser] dateFormatterInContext: self];
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
<!-- TODO: the table is a DUP to UIxMailView, own component? -->
|
<!-- TODO: the table is a DUP to UIxMailView, own component? -->
|
||||||
<div class="bodyFields">
|
<div class="bodyFields">
|
||||||
<span class="fieldName"><var:string label:value="Subject"/>:</span>
|
<span class="fieldName"><var:string label:value="Subject"/>:</span>
|
||||||
<var:string value="envelope.subject"
|
<var:string value="messageSubject"/><br/>
|
||||||
formatter="context.mailSubjectFormatter"/><br/>
|
|
||||||
<span class="fieldName"><var:string label:value="From"/>:</span>
|
<span class="fieldName"><var:string label:value="From"/>:</span>
|
||||||
<var:string value="fromAddresses"/><br/>
|
<var:string value="fromAddresses"/><br/>
|
||||||
<span class="fieldName"><var:string label:value="Date"/>:</span>
|
<span class="fieldName"><var:string label:value="Date"/>:</span>
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
<tr class="mailer_fieldrow">
|
<tr class="mailer_fieldrow">
|
||||||
<td class="mailer_fieldname" ><var:string label:value="Subject"/>:</td>
|
<td class="mailer_fieldname" ><var:string label:value="Subject"/>:</td>
|
||||||
<td class="mailer_subjectfieldvalue">
|
<td class="mailer_subjectfieldvalue">
|
||||||
<var:string value="clientObject.subject"
|
<var:string value="messageSubject"/>
|
||||||
formatter="context.mailSubjectFormatter"/>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="mailer_fieldrow">
|
<tr class="mailer_fieldrow">
|
||||||
|
|
Loading…
Reference in New Issue