]> err.no Git - scalable-opengroupware.org/blob - UI/MailerUI/UIxSubjectFormatter.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1127 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / MailerUI / UIxSubjectFormatter.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #import <NGExtensions/NSNull+misc.h>
23 #import <NGExtensions/NSObject+Logs.h>
24 #import <NGMail/NGMimeMessageParser.h>
25
26 #import "UIxMailFormatter.h"
27
28 @implementation UIxSubjectFormatter
29
30 static Class StrClass  = Nil;
31 static Class DataClass = Nil;
32
33 + (void)initialize {
34   StrClass  = [NSString class];
35   DataClass = [NSData   class];
36 }
37
38 - (id)init {
39   if ((self = [super init])) {
40     self->maxLength = 64;
41   }
42   return self;
43 }
44
45 /* configuration */
46
47 - (unsigned int)maxLength {
48   return self->maxLength;
49 }
50
51 - (BOOL)shouldDecodeQP {
52   return YES;
53 }
54
55 /* labels */
56
57 - (NSString *)missingSubjectLabel {
58   return [self labelForKey:@"no_subject"];
59 }
60
61 /* specific formatters */
62
63 - (NSString *)stringForStringValue:(NSString *)_subject {
64   NSString *s;
65   
66   /* quoted printable */
67   if ([self shouldDecodeQP] && [_subject hasPrefix:@"=?"]) {
68     /* 
69        Now this is interesting. An NSString should not contain QP markers since
70        it is already 'charset decoded'. This is also why the NGMime parser
71        expects an NSData.
72        
73        Sample:
74          =?iso-8859-1?q?Yannick=20DAmboise?=
75
76        Note: -stringByDecodingQuotedPrintable only expands =D0 like charcodes!
77     */
78     NSData *data;
79     
80     /* header field data should always be ASCII */
81     data = [_subject dataUsingEncoding:NSUTF8StringEncoding];
82     return [self stringForDataValue:data];
83   }
84   
85   if ([_subject length] == 0)
86     return [self missingSubjectLabel];
87   
88   if ([_subject length] <= [self maxLength])
89     return _subject;
90   
91   s = [_subject substringToIndex:([self maxLength] - 3)];
92   return [s stringByAppendingString:@"..."];
93 }
94
95 - (NSString *)stringForDataValue:(NSData *)_subject {
96   NSString *s, *r;
97   unsigned len;
98   
99   if ((len = [_subject length]) == 0)
100     return [self missingSubjectLabel];
101   
102   /* check for quoted printable */
103   
104   if (len > 6 && [self shouldDecodeQP]) {
105     const unsigned char *b;
106     
107     b = [_subject bytes];
108     if (b[0] == '=' && b[1] == '?') {
109       /* eg: '=?iso-8859-1?q?Yannick=20DAmboise?=' */
110       id t;
111       
112       t = [_subject decodeQuotedPrintableValueOfMIMEHeaderField:@"subject"];
113       if ([t isNotNull])
114         return [self stringForObjectValue:t];
115       else
116         [self warnWithFormat:@"decoding QP failed: '%@'", t];
117     }
118   }
119   
120   /* continue NSData processing */
121   
122   [self warnWithFormat:@"NSData subject, using UTF-8 to decode."];
123   
124   // TODO: exception handler?
125   s = [[NSString alloc] initWithData:_subject encoding:NSUTF8StringEncoding];
126   if (s == nil) {
127     [self errorWithFormat:@"could do not decode NSData subject!"];
128     return [self labelForKey:@"Error_CouldNotDecodeSubject"];
129   }
130   
131   if ([s hasPrefix:@"=?"]) { // TODO: this should never happen?
132     [self warnWithFormat:@"subject still has QP signature: '%@'", s];
133     r = [s copy];
134   }
135   else
136     r = [[self stringForStringValue:s] copy];
137   [s release];
138   return [r autorelease];
139 }
140
141 /* formatter entry function */
142
143 - (NSString *)stringForObjectValue:(id)_subject {
144   if (![_subject isNotNull])
145     return [self missingSubjectLabel];
146   
147   if ([_subject isKindOfClass:StrClass])
148     return [self stringForStringValue:_subject];
149   if ([_subject isKindOfClass:DataClass])
150     return [self stringForDataValue:_subject];
151   
152   return [self stringForStringValue:[_subject stringValue]];
153 }
154
155 @end /* UIxSubjectFormatter */