]> err.no Git - sope/blob - sope-mime/NGMime/NGMimePartGenerator.m
minor fixes
[sope] / sope-mime / NGMime / NGMimePartGenerator.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
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 // $Id$
22
23 #import "NGMimePartGenerator.h"
24 #import "NGMimeHeaderFieldGenerator.h"
25 #import "NGMimeBodyGenerator.h"
26 #import "NGMimeJoinedData.h"
27 #import <NGMime/NGMimeType.h>
28 #import "common.h"
29
30 @implementation NGMimePartGenerator
31
32 + (int)version {
33   return 2;
34 }
35
36 + (id)mimePartGenerator {
37   return [[[self alloc] init] autorelease];
38 }
39
40 - (id)init {
41   if ((self = [super init])) {
42     self->part        = nil;
43     self->delegate    = nil;
44     self->appendBytes = NULL;
45   }
46   return self;
47 }
48
49 - (void)dealloc {
50   [self->result release];
51   [self->part   release];
52   self->appendBytes = NULL;
53   [super dealloc];
54 }
55
56 /* setting the delegate */
57
58 - (void)setDelegate:(id)_delegate {
59   self->delegate = _delegate;
60
61   self->delegateRespondsTo.generatorGenerateDataForHeaderField =
62     [self->delegate respondsToSelector:
63          @selector(mimePartGenerator:generateDataForHeaderField:value:)];
64   
65   self->delegateRespondsTo.generatorGeneratorForBodyOfPart =
66     [self->delegate respondsToSelector:
67          @selector(mimePartGenerator:generatorForBodyOfPart:)];
68   
69   self->delegateRespondsTo.generatorGenerateDataForBodyOfPart =
70     [self->delegate respondsToSelector:
71          @selector(mimePartGenerator:generateDataForBodyOfPart:additionalHeaders:)];
72 }
73
74 - (id)delegate {
75   return self->delegate;
76 }
77
78 - (BOOL)prepareForGenerationOfPart:(id<NGMimePart>)_part {
79   {
80     id tmp = self->part;
81
82     self->part = _part;
83     
84     [self->part retain];
85     [tmp release]; tmp = nil;
86   }
87   if (self->result) {
88     [self->result release];
89     self->result = nil;
90   }
91   self->result = (self->useMimeData)
92     ? [[NGMimeJoinedData alloc] init]
93     : [[NSMutableData alloc] initWithCapacity:4096];
94     
95   
96   if ([self->result respondsToSelector:@selector(methodForSelector:)])
97     self->appendBytes = (void(*)(id,SEL,const void *, unsigned))
98                         [self->result methodForSelector:
99                                           @selector(appendBytes:length:)];
100   else
101     self->appendBytes = NULL;
102   return YES;
103 }
104
105 - (BOOL)generatePrefix {
106   return YES;
107 }
108
109 - (void)generateSuffix {
110 }
111
112 - (id<NGMimeHeaderFieldGenerator>)generatorForHeaderField:(NSString *)_name {
113   return [NGMimeHeaderFieldGeneratorSet defaultRfc822HeaderFieldGeneratorSet];
114 }
115
116 - (NSData *)generateDataForHeaderField:(NSString *)_headerField
117   value:(id)_value
118 {
119   NSData *data = nil;
120
121   if (self->delegateRespondsTo.generatorGenerateDataForHeaderField)
122     data = [self->delegate mimePartGenerator:self
123                            generateDataForHeaderField:_headerField
124                            value:_value];
125   else {
126     data = [[self generatorForHeaderField:_headerField]
127                   generateDataForHeaderFieldNamed:_headerField
128                   value:_value];
129   }
130   return data;
131 }
132
133 - (NSData *)generateDataWithHeaderField:(NSString *)_headerField
134   values:(NSEnumerator *)_values
135 {
136   NSMutableData *res   = nil;
137   NSData        *data  = nil;
138   id            value  = nil;
139   const char    *bytes = NULL;
140   unsigned      len    = 0;
141
142   res = [NSMutableData dataWithCapacity:64];
143   bytes = [_headerField cString];
144   len   = [_headerField length];
145   while (len > 0) {
146     if (*bytes != ' ')
147       break;
148     bytes++;
149     len--;
150   }
151   while ((value = [_values nextObject])) {
152     data = [self generateDataForHeaderField:(NSString *)_headerField
153                  value:value];
154     [res appendBytes:bytes length:len];
155     [res appendBytes:": " length:2];
156     [res appendData:data];
157     [res appendBytes:"\n" length:1];
158   }
159   return res;
160 }
161   
162
163 - (NSData *)generateHeaderData:(NGHashMap *)_additionalHeaders {
164   NSEnumerator     *headerFieldNames = nil;
165   NSString         *headerFieldName  = nil;
166   NGMutableHashMap *addHeaders       = nil;
167   NSMutableData    *data             = nil;
168
169   data = (self->useMimeData)
170     ? [[[NGMimeJoinedData alloc] init] autorelease]
171     : [NSMutableData dataWithCapacity:2048];
172   
173   headerFieldNames = [self->part headerFieldNames];
174   addHeaders       = [_additionalHeaders mutableCopy];
175
176   while ((headerFieldName = [headerFieldNames nextObject])) {
177     NSData       *headerFieldData = nil;
178     NSEnumerator *enumerator      = nil;
179     BOOL         reset;
180       
181     if ([[_additionalHeaders objectsForKey:headerFieldName] count] > 0) {
182       enumerator = [addHeaders objectEnumeratorForKey:headerFieldName];
183       reset = YES;
184     }
185     else {
186       reset = NO;
187       enumerator = [self->part valuesOfHeaderFieldWithName:headerFieldName];
188     }
189     headerFieldData = [self generateDataWithHeaderField:headerFieldName
190                             values:enumerator];
191     if (reset)
192       [addHeaders removeAllObjectsForKey:headerFieldName];
193     
194     if (headerFieldData)
195       [data appendData:headerFieldData];
196   }
197   headerFieldNames = [addHeaders keyEnumerator];
198   while ((headerFieldName = [headerFieldNames nextObject])) {
199     NSData *headerFieldData = nil;
200     headerFieldData = [self generateDataWithHeaderField:headerFieldName
201                             values:[addHeaders objectEnumeratorForKey:
202                                               headerFieldName]];
203     if (headerFieldData)
204       [data appendData:headerFieldData];
205   }
206   [addHeaders release]; addHeaders = nil;
207   return data;
208 }
209
210 - (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part {
211   return [NGMimeType mimeType:@"application/octet"];
212 }
213
214 - (id<NGMimeBodyGenerator>)defaultBodyGenerator {
215   id<NGMimeBodyGenerator> gen;
216
217   gen = [[[NGMimeBodyGenerator alloc] init] autorelease];
218   [(id)gen setUseMimeData:self->useMimeData];
219   return gen;
220 }
221
222 - (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part {
223   id<NGMimeBodyGenerator> bodyGen      = nil;
224   NGMimeType              *contentType = nil;
225   NSString                *type        = nil;
226   
227   if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart)
228     bodyGen = [self->delegate mimePartGenerator:self
229                    generatorForBodyOfPart:self->part];
230
231   if (!bodyGen) {
232     contentType = [_part contentType];
233     if (contentType == nil) {
234       contentType = [self defaultContentTypeForPart:_part];
235     }
236     if (contentType == nil) {
237       NSLog(@"WARNING(%s): no content-type", __PRETTY_FUNCTION__);
238       return nil;
239     }
240     type = [contentType type];
241   
242     if ([type isEqualToString:NGMimeTypeMultipart]) {
243       bodyGen = [[[NGMimeMultipartBodyGenerator alloc] init] autorelease];
244     }
245     else if ([type isEqualToString:NGMimeTypeText]) {
246       bodyGen = [[[NGMimeTextBodyGenerator alloc] init] autorelease];
247     }
248     else if (([type isEqualToString:NGMimeTypeMessage]) &&
249              [[contentType subType] isEqualToString:@"rfc822"]) {
250       bodyGen = [[[NGMimeRfc822BodyGenerator alloc] init] autorelease];
251     }
252   }
253   [(id)bodyGen setUseMimeData:self->useMimeData];
254   return bodyGen;
255 }
256
257 - (NSData *)generateBodyData:(NGMutableHashMap *)_additionalHeaders {
258   NSData                  *data   = nil;
259   id<NGMimeBodyGenerator> bodyGen = nil;
260
261   if (self->delegateRespondsTo.generatorGenerateDataForBodyOfPart) {
262     data = [self->delegate mimePartGenerator:self
263                            generateDataForBodyOfPart:self->part
264                            additionalHeaders:_additionalHeaders];
265   }
266   else {
267     bodyGen = [self generatorForBodyOfPart:self->part];
268
269     if (bodyGen == nil) // no generator for body
270       bodyGen = [self defaultBodyGenerator];
271
272     [(id)bodyGen setUseMimeData:self->useMimeData];
273     
274     if (bodyGen == nil) {
275       id body = [self->part body];        
276       NSLog(@"WARNING(%s): no defaultBodyGenerator", __PRETTY_FUNCTION__);
277       if ([body isKindOfClass:[NSData class]]) {
278         data = body;
279       }
280       else if ([body isKindOfClass:[NSString class]]) {
281         data = [body dataUsingEncoding:[NSString defaultCStringEncoding]];
282       }
283     }
284     else {
285       data = [bodyGen generateBodyOfPart:self->part
286                       additionalHeaders:_additionalHeaders
287                       delegate:self->delegate];
288     }
289   }
290   return data;
291 }
292
293 - (void)generateData {
294   NGMutableHashMap *additionalHeaders = nil;
295   NSData           *bodyData          = nil;
296   NSData           *headerData        = nil;
297   
298   additionalHeaders = [[NGMutableHashMap alloc] initWithCapacity:16];
299   
300   bodyData   = [self generateBodyData:additionalHeaders];
301   headerData = [self generateHeaderData:additionalHeaders];
302
303   if (headerData != nil) {
304     [self->result appendData:headerData];
305     [self->result appendBytes:"\n" length:1];
306     if (bodyData != nil)
307       [self->result appendData:bodyData];
308   }
309   [additionalHeaders release];
310 }
311
312 - (NSData *)generateMimeFromPart:(id<NGMimePart>)_part {
313   [self prepareForGenerationOfPart:_part];
314   if ([self generatePrefix]) {
315     NSData *data;
316     
317     [self generateData];
318     [self generateSuffix];
319     data = self->result;
320     self->result = nil;
321     return [data autorelease];
322   }
323   return nil;
324 }
325
326 - (NSString *)generateMimeFromPartToFile:(id<NGMimePart>)_part {
327   NSString *filename = nil;
328
329   static NSString      *TmpPath = nil;
330   static NSProcessInfo *Pi      = nil;
331   
332   if (TmpPath == nil) {
333     NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
334     
335     TmpPath = [ud stringForKey:@"NGMimeBuildMimeTempDirectory"];
336     if (TmpPath == nil)
337       TmpPath = @"/tmp/";
338     TmpPath = [[TmpPath stringByAppendingPathComponent:@"OGo"] copy];
339   }
340   if (Pi == nil)
341     Pi = [[NSProcessInfo processInfo] retain];
342
343   filename = [Pi temporaryFileName:TmpPath];
344
345   [self setUseMimeData:YES];
346
347   if (![[self generateMimeFromPart:_part]
348               writeToFile:filename atomically:YES]) {
349     NSLog(@"ERROR[%s] couldn`t write data to temorary file %@",
350           __PRETTY_FUNCTION__, filename);
351     return nil;
352   }
353   return filename;
354 }
355
356 - (id<NGMimePart>)part {
357   return self->part;
358 }
359
360 - (BOOL)useMimeData {
361   return self->useMimeData;
362 }
363
364 - (void)setUseMimeData:(BOOL)_b {
365   self->useMimeData = _b;
366 }
367
368 @end /* NGMimePartGenerator */
369