"Fossies" - the Fresh Open Source Software Archive 
Member "opengroupware-5.5rc3/WebUI/Mailer/OGoMailViewers/LSWMimePartViewer.m" (5 Dec 2015, 21089 Bytes) of package /linux/privat/opengroupware-5.5rc3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Matlab source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "LSWMimePartViewer.m" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.5rc2_vs_5.5rc3.
1 /*
2 Copyright (C) 2000-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 #include "LSWMimePartViewer.h"
23 #include "LSWPartBodyViewer.h"
24 #include "common.h"
25 #include <NGObjWeb/WEClientCapabilities.h>
26 #include <NGMime/NGMimeBodyPart.h>
27 #include <NGMime/NGConcreteMimeType.h>
28 #include <NGMime/NGMimeFileData.h>
29 #include <NGMail/NGMimeMessage.h>
30 #include <NGMail/NGMimeMessageGenerator.h>
31 #include "SkyDecodeWrapperData.h"
32
33 @interface NSObject(Private)
34 - (NGImap4Context *)imapContext;
35 - (void)setData:(NSData *)_data;
36 + (NGImap4Context *)sessionImapContext:(id)_ses;
37 @end /* Private */
38
39 @interface LSWMimePartViewer(Private)
40 - (NSString *)url;
41 - (NSString *)mimeTypeString;
42 - (NSString *)encodingString;
43 - (NSString *)partUrl;
44 - (NSNumber *)showBodyDepSizeVar;
45 @end /* LSWMimePartViewer(Private) */
46
47 @implementation WOComponent(Download)
48
49 - (BOOL)isDownloadable {
50 return NO;
51 }
52
53 @end /* WOComponent(Download) */
54
55 @implementation LSWMimePartViewer
56
57 static int CreateMailDownloadFileNamesDisable = -1;
58 static int ShowBodyDependingSizeDisable = -1;
59 static int ShowBodySize = -1;
60
61 + (void)initialize {
62 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
63
64 CreateMailDownloadFileNamesDisable =
65 [ud boolForKey:@"CreateMailDownloadFileNamesDisable"] ? 1 : 0;
66 ShowBodyDependingSizeDisable =
67 [ud boolForKey:@"ShowBodySizeDisable"] ? 1 : 0;
68
69 ShowBodySize = [ud integerForKey:@"ShowBodySize"];
70 if (ShowBodySize < 1000) ShowBodySize = 100000;
71 }
72
73 - (id)init {
74 if ((self = [super init])) {
75 self->showBody = YES;
76 self->printMode = NO;
77 }
78 return self;
79 }
80
81 - (void)dealloc {
82 [self->bodyViewer release];
83 [self->part release];
84 [self->source release];
85 [super dealloc];
86 }
87
88 /* notifications */
89
90 - (void)sleep {
91 [super sleep];
92 ASSIGN(self->bodyViewer, nil);
93 ASSIGN(self->part, nil);
94 ASSIGN(self->source, nil);
95 }
96
97 /* accessors */
98
99 - (BOOL)isDownloadable {
100 return NO;
101 }
102
103 /* response generation */
104
105 - (void)appendToResponse:(WOResponse *)_resp
106 inContext:(WOContext *)_ctx
107 {
108 NSMutableArray *array;
109
110 [super appendToResponse:_resp inContext:_ctx];
111
112 if (![(LSWPartBodyViewer *)[self bodyViewerComponent] isDownloadable])
113 return;
114
115 array = [[self session] valueForKey:@"displayedAttachmentDownloadUrls"];
116 [array addObject:
117 [(LSWPartBodyViewer *)[self bodyViewerComponent] bodyDescription]];
118 }
119
120
121 - (void)setNestingDepth:(int)_depth {
122 self->nestingDepth = _depth;
123 }
124 - (int)nestingDepth {
125 return self->nestingDepth;
126 }
127 - (int)nextNestingDepth {
128 return (self->nestingDepth + 1);
129 }
130
131 - (void)setPart:(id)_part {
132 ASSIGN(self->part, _part);
133 }
134 - (id)part {
135 return self->part;
136 }
137
138 - (void)setShowHeaders:(BOOL)_flag {
139 self->showHeaders = _flag;
140 }
141 - (BOOL)showHeaders {
142 return self->showHeaders;
143 }
144
145 /* body */
146
147 - (id)body {
148 return [self->part body];
149 }
150
151 - (NSData *)contentForURL:(NSURL *)_url {
152 NGImap4Context *imapCtx;
153 NGImap4Folder *folder;
154 NSString *path, *encoding;
155 NSData *data;
156
157 encoding = [[self encodingString] lowercaseString];
158 imapCtx = [NSClassFromString(@"SkyImapContextHandler")
159 sessionImapContext:[self session]];
160 path = [_url path];
161
162 folder = [imapCtx folderWithName:
163 [path stringByDeletingLastPathComponent]];
164 if (folder == nil) {
165 [self logWithFormat:
166 @"%s: could not find folder at path %@", __PRETTY_FUNCTION__,
167 [path stringByDeletingLastPathComponent]];
168 return [[[NSData alloc] init] autorelease];
169 }
170
171 data = [folder blobForUid:[[path lastPathComponent] intValue]
172 part:[[[_url query] componentsSeparatedByString:@"="]
173 lastObject]];
174 if (data == nil) {
175 [self logWithFormat:
176 @"%s: could not fetch blob for folder %@ path %@ uid %d part %@",
177 __PRETTY_FUNCTION__, folder, path,
178 [[path lastPathComponent] intValue],
179 [[[_url query] componentsSeparatedByString:@"="] lastObject]];
180 return [[[NSData alloc] init] autorelease];
181 }
182
183 if ([encoding isEqualToString:@"base64"])
184 return [data dataByDecodingBase64];
185
186 if ([encoding isEqualToString:@"quoted-printable"])
187 return [data dataByDecodingQuotedPrintable];
188
189 return data;
190 }
191
192 /* header fields */
193
194 // Correct content-type if possible. We're using
195 // the "content-type" field for getting the filename.
196 // A second filename may be exists in "content-disposition".
197
198 - (NGMimeType *)correctedContentType {
199 NSString *ext, *fn;
200 NSArray *e, *a;
201 NSDictionary *mimeTypes = nil;
202 NSString *mt;
203 id ct;
204
205 ct = [self->part contentType];
206 if (!([[[(NGMimeType *)ct type]
207 lowercaseString] isEqualToString:@"application"] &&
208 [[[(NGMimeType *)ct subType] lowercaseString]
209 isEqualToString:@"octet-stream"]))
210 return ct;
211
212 fn = [[ct parametersAsDictionary] objectForKey:@"name"];
213
214 if (![fn isNotNull])
215 return ct;
216
217 ext = @"";
218 e = [fn componentsSeparatedByString:@"."];
219 if ([e count] > 0)
220 ext = [e lastObject];
221
222 mimeTypes = [[[self session] userDefaults] dictionaryForKey:@"LSMimeTypes"];
223 if (!([ext length] > 0 && [mimeTypes isNotNull]))
224 return ct;
225
226 if ((mt = [mimeTypes valueForKey:ext]) == nil)
227 return ct;
228
229
230 a = [mt componentsSeparatedByString:@"/"];
231 if ([a count] == 2) {
232 NGMimeType *mimeType = nil;
233
234 mimeType = [NGMimeType mimeType:[a objectAtIndex:0]
235 subType:[a objectAtIndex:1]
236 parameters:[ct parametersAsDictionary]];
237 return mimeType;
238 }
239 return ct;
240 }
241
242 - (NGMimeType *)contentType {
243 //return [self->part contentType];
244 return [self correctedContentType];
245 }
246 - (NSString *)contentId {
247 return [self->part contentId];
248 }
249 - (NSArray *)contentLanguage {
250 return [self->part contentLanguage];
251 }
252 - (NSString *)contentMd5 {
253 return [self->part contentMd5];
254 }
255 - (NSString *)encoding {
256 return [self->part encoding];
257 }
258 - (NSString *)contentDescription {
259 return [self->part contentDescription];
260 }
261
262 - (NSString *)contentLength {
263 id len;
264 len = [self->part valuesOfHeaderFieldWithName:@"content-length"];
265 len = [len nextObject];
266 return [len stringValue];
267 }
268 - (NSString *)contentDisposition {
269 id v;
270 v = [self->part valuesOfHeaderFieldWithName:@"content-disposition"];
271 v = [v nextObject];
272 return [v stringValue];
273 }
274 - (NSString *)contentTransferEncoding {
275 id v;
276 v = [self->part valuesOfHeaderFieldWithName:@"content-transfer-encoding"];
277 v = [v nextObject];
278 return [v stringValue];
279 }
280
281 - (NSString *)downloadIconName {
282 id cfg = nil;
283 NGMimeType *contentType;
284
285 contentType = [self contentType];
286 #if DEBUG
287 NSAssert1(contentType == nil ||
288 [contentType isKindOfClass:[NGMimeType class]],
289 @"invalid content-type class '%@'", contentType);
290 #endif
291
292 cfg = [[self config] valueForKey:@"typeIcons"];
293
294 if (contentType == nil) {
295 return [cfg valueForKey:@"unknown"];
296 }
297 else {
298 cfg = [cfg valueForKey:[contentType type]];
299 cfg = [cfg valueForKey:[contentType subType]];
300 return cfg
301 ? cfg
302 : [[[self config] valueForKey:@"typeIcons"] valueForKey:@"unknown"];
303 }
304 }
305
306 - (NSString *)downloadType {
307 return [NSString stringWithFormat:@"%@/%@", [[self contentType] type],
308 [[self contentType] subType]];
309 }
310
311 - (NSString *)downloadTarget {
312 #if 0
313 NSString *t = [[self contentType] subType];
314
315 return ([t isEqualToString:@"plain"]
316 || [t isEqualToString:@"html"]
317 || [t isEqualToString:@"gif"]
318 || [t isEqualToString:@"jpeg"])
319 ? [[self context] contextID]
320 : @"";
321 #else
322 return [[self context] contextID];
323 #endif
324 }
325
326 /* actions */
327
328 - (NSString *)_checkFor8Bit:(NSString *)_str {
329 unsigned char *c;
330 int len;
331 int i;
332 BOOL changed;
333
334 changed = NO;
335 len = [_str length];
336 c = calloc(len + 6 /* be defensive */, sizeof(id));
337
338 [_str getCString:(char *)c];
339 for (i = 0; i < len; i++) {
340 if (c[i] > 127) {
341 c[i] = '_';
342 changed = YES;
343 }
344 }
345 if (changed) {
346 #if LIB_FOUNDATION_LIBRARY
347 _str = [NSString stringWithCStringNoCopy:(char *)c length:len
348 freeWhenDone:YES];
349 #else
350 _str = [NSString stringWithCString:(char *)c length:len];
351 if (c != NULL) free(c); c = NULL;
352 #endif
353 }
354 else
355 if (c) free(c); c = NULL;
356
357 return _str;
358 }
359
360 - (id)downloadPart {
361 // TODO: split up method
362 WOResponse *response;
363 id content;
364 NSString *disposition, *transferEncoding, *fileName, *type;
365
366 disposition = [self contentDisposition];
367 transferEncoding = [self contentTransferEncoding];
368 fileName = [[[self contentType] parametersAsDictionary]
369 objectForKey:@"name"];
370 if (![fileName length])
371 fileName = nil;
372
373 response = [WOResponse responseWithRequest:[[self context] request]];
374 [response setStatus:200];
375
376 [response setHeader:[self _checkFor8Bit:[[self contentType] stringValue]]
377 forKey:@"content-type"];
378
379 content = [self body];
380
381 if ([content isKindOfClass:[NSData class]]) {
382 }
383 else if ([content isKindOfClass:[NSString class]]) {
384 BOOL useUTF8;
385 NSString *ct;
386 WORequest *req;
387
388 req = [[self context] request];
389 useUTF8 = [[req clientCapabilities] doesSupportUTF8Encoding];
390
391 if (!useUTF8) {
392 NSRange r;
393
394 r = [[req headerForKey:@"accept-charset"] rangeOfString:@"utf-8"];
395 useUTF8 = (r.length > 0) ? YES : NO;
396 }
397 if (useUTF8) {
398 content = [content dataUsingEncoding:NSUTF8StringEncoding
399 allowLossyConversion:YES];
400 ct = @"text/plain; charset=utf-8";
401 }
402 else {
403 content = [content dataUsingEncoding:NSISOLatin1StringEncoding
404 allowLossyConversion:YES];
405 ct = @"text/plain; charset=iso-8859-1";
406 }
407 [response setHeader:ct forKey:@"content-type"];
408 }
409 else if ([content isKindOfClass:[NSURL class]]) {
410 content = [self contentForURL:content];
411 }
412 else {
413 [(id)[[self context] page]
414 setErrorString:
415 @"couldn't provide downloadable representation of body"];
416 [self logWithFormat:
417 @"couldn't provide downloadable representation of body"];
418 return nil;
419 }
420 type = [[self contentType] type];
421 if ([type isEqualToString:@"text"] || [type isEqualToString:@"image"]) {
422 if (disposition) {
423 [response setHeader:[self _checkFor8Bit:[disposition stringValue]]
424 forKey:@"content-disposition"];
425 }
426 }
427 else {
428 static Class DispClass = Nil;
429 id tmp;
430
431 if (DispClass == Nil)
432 DispClass = [NGMimeContentDispositionHeaderField class];
433
434 if (![disposition isKindOfClass:DispClass]) {
435 disposition =
436 [[[DispClass alloc] initWithString:[disposition stringValue]]
437 autorelease];
438 }
439 tmp = [(NGMimeContentDispositionHeaderField *)disposition filename];
440
441 if (![tmp length])
442 tmp = fileName;
443
444 if (tmp != nil) {
445 tmp = [[tmp componentsSeparatedByString:@"\\"] lastObject];
446 tmp = [NSString stringWithFormat:@"attachment; filename=\"%@\"", tmp];
447 }
448 else
449 tmp = @"attachment";
450
451 [response setHeader:[self _checkFor8Bit:tmp]
452 forKey:@"content-disposition"];
453 }
454 [response setHeader:[NSString stringWithFormat:@"%"PRIuPTR, [content length]]
455 forKey:@"content-length"];
456
457 if (transferEncoding) {
458 if ([transferEncoding isEqualToString:@"base64"])
459 content = [content dataByDecodingBase64];
460 else if ([transferEncoding isEqualToString:@"quoted-printable"])
461 content = [content dataByDecodingQuotedPrintable];
462 else {
463 [self logWithFormat:@"Unknown content-transfer-encoding: %@",
464 transferEncoding];
465 }
466 }
467 [response setHeader:@"identity" forKey:@"content-encoding"];
468
469 [response setContent:content];
470 return response;
471 }
472
473 - (id)buildDocumentBodyForPath {
474 id body;
475
476 body = [self body];
477 if ([body isKindOfClass:[NSString class]])
478 body = [body dataUsingEncoding:[NSString defaultCStringEncoding]];
479 else if ([body isKindOfClass:[NSURL class]])
480 body = [self contentForURL:body];
481 return body;
482 }
483
484 - (NSString *)buildDocumentPathForPart {
485 NSString *path;
486
487 path = [self contentDisposition];
488 if ([path length] > 0) {
489 NGMimeContentDispositionHeaderField *cd;
490
491 cd = [[NGMimeContentDispositionHeaderField alloc]
492 initWithString:[self contentDisposition]];
493 path = [[[cd filename] copy] autorelease];
494 [cd release]; cd = nil;
495 }
496 else
497 path = nil;
498
499 if (path == nil) {
500 NGMimeType *ct;
501 NSString *subject;
502
503 ct = [self contentType];
504 path = [[ct parametersAsDictionary] objectForKey:@"name"];
505
506 if (path == nil) {
507 if ([[ct type] isEqualToString:@"text"]) {
508 path = ([[ct subType] isEqualToString:@"html"])
509 ? @".html" : @".txt";
510 }
511 else
512 path = [@"." stringByAppendingString:[ct subType]];;
513
514 if ((subject = [[self source] valueForKey:@"subject"]) == nil)
515 subject = @"<unknown>";
516
517 path = [subject stringByAppendingString:path];
518 }
519 }
520 #if LIB_FOUNDATION_LIBRARY
521 if ([path isKindOfClass:[NSInlineUTF16String class]]) {
522 path = [NSString stringWithFormat:@"%@", path];
523 /* hack to avoid utf16 string confusings */
524 }
525 #endif
526 return path;
527 }
528
529 - (NSString *)buildDocumentTitleForPart {
530 id tmp;
531 NSString *subject;
532
533 tmp = [[self source] valueForKey:@"sendDate"];
534 if ([tmp respondsToSelector:@selector(descriptionWithCalendarFormat:)])
535 tmp = [tmp descriptionWithCalendarFormat:@"%Y-%m-%d %H:%M"];
536 else
537 tmp = @"<unknown>";
538
539 if ([tmp length] == 0)
540 tmp = @"<unknown>";
541
542 subject = [[self source] valueForKey:@"subject"];
543 if (![subject isNotNull])
544 subject = @"<unknown>";
545
546 return [NSString stringWithFormat:@"%@ [%@]", subject, tmp];
547 }
548
549 - (id)toDoc {
550 OGoContentPage *page;
551
552 #if 1
553 page = [self pageWithName:@"OGoDocumentImport"];
554 #else
555 // TODO: shouldn't we use a separate page for imports?
556 page = [self pageWithName:@"SkyProject4DocumentEditor"];
557 [page takeValue:[NSNumber numberWithBool:YES] forKey:@"isImport"];
558 #endif
559 [page takeValue:[self buildDocumentBodyForPath] forKey:@"blob"];
560 [page takeValue:[self buildDocumentPathForPart] forKey:@"fileName"];
561 [page takeValue:[self buildDocumentTitleForPart] forKey:@"subject"];
562
563 // TODO: is this required?
564 [[[[self context] valueForKey:@"page"] navigation] enterPage:page];
565 return page;
566 }
567
568 /* viewer */
569
570 - (WOComponent *)bodyViewerComponent {
571 /* TODO: split up this method */
572 if (self->bodyViewer)
573 return self->bodyViewer;
574
575 self->bodyViewer =
576 [[[self session] instantiateComponentForCommand:@"mailview"
577 type:[self contentType]] retain];
578 if (self->bodyViewer == nil) {
579 NGMimeType *appOctet;
580
581 appOctet = [NGMimeType mimeType:@"application/octet-stream"];
582
583 self->bodyViewer = [[[self session]
584 instantiateComponentForCommand:@"mailview"
585 type:appOctet] retain];
586 }
587 {
588 NSData *data;
589
590 data = [self body];
591
592 if ([data isKindOfClass:[NGMimeFileData class]]) {
593
594 data = [(SkyDecodeWrapperData *)[SkyDecodeWrapperData alloc]
595 initWithData:data
596 encoding:[[self part]
597 valueForKey:@"encoding"]];
598 [data autorelease];
599 }
600 [(id)self->bodyViewer setBody:data];
601 [(id)self->bodyViewer setPartOfBody:[self part]];
602 [(id)self->bodyViewer setSource:[self source]];
603 }
604
605 if ([[[self contentType] type] isEqualToString:@"eo-pkey"]) {
606 if ([(id)self->bodyViewer object] == nil) {
607 ASSIGN(self->bodyViewer, nil);
608 self->bodyViewer =
609 [[[self session] instantiateComponentForCommand:@"mailview"
610 type:[NGMimeType mimeType:@"eo" subType:@"deleted"]]
611 retain];
612 }
613 }
614 return self->bodyViewer;
615 }
616
617 - (BOOL)showBody {
618 return self->showBody;
619 }
620 - (void)setShowBody:(BOOL)_body {
621 self->showBody = _body;
622 }
623
624 - (BOOL)printMode {
625 return self->printMode;
626 }
627 - (void)setPrintMode:(BOOL)_print {
628 self->printMode = _print;
629 }
630
631 - (void)setSource:(id)_source {
632 ASSIGN(self->source, _source);
633 }
634 - (id)source {
635 return self->source;
636 }
637
638 - (BOOL)hasUrl {
639 return [[self body] isKindOfClass:[NSURL class]];
640 }
641
642 - (NSString *)downloadPartActionName {
643 /*
644 This appends a filename to the download action, this helps with browser
645 detection of filenames and filetypes in case the browser does not
646 properly work on the content disposition field.
647 */
648 // TBD: DUP in LSWPartBodyViewer?
649 NSString *name;
650
651 /* first check whether we are supposed to generate custom names */
652
653 if (CreateMailDownloadFileNamesDisable)
654 return @"get";
655
656 /* check whether an attachment has a name assigned */
657
658 name = [[[self->part contentType] parametersAsDictionary]
659 objectForKey:@"name"];
660 if ([name isNotEmpty]) {
661 /* be sure to escape the URL */
662 name = [[name stringValue] stringByEscapingURL];
663 return [@"get/" stringByAppendingString:name];
664 }
665
666
667 /* no escaping, a MIME subtype should always be urlsafe */
668
669 name = [[self->part contentType] subType];
670 return [@"get/download." stringByAppendingString:name];
671 }
672
673 - (NSString *)url {
674 if ([[self body] isKindOfClass:[NSURL class]])
675 return [[self body] absoluteString];
676 return nil;
677 }
678 - (NSString *)mimeTypeString {
679 return [[self->part contentType] stringValue];
680 }
681
682 - (NSString *)encodingString {
683 return [[self->part encoding] stringValue];
684 }
685
686 - (NSString *)partUrl {
687 return [[self body] query];
688 }
689
690 - (BOOL)showBodyDepSize {
691 if (ShowBodyDependingSizeDisable)
692 return YES;
693
694 if ([self showBodyDepSizeVar])
695 return [[self showBodyDepSizeVar] boolValue];
696
697 if ([[[self->part contentType] type] isEqualToString:@"application"])
698 return NO;
699
700 if (([[self contentLength] intValue] > ShowBodySize))
701 return NO;
702
703 return YES;
704 }
705
706 - (BOOL)isImageViewerComponent:(WOComponent *)_component {
707 return [_component isKindOfClass:[LSWImageBodyViewer class]];
708 }
709
710 - (BOOL)showBodyDepSizeEnabled {
711 BOOL viewImageInline;
712
713 viewImageInline =
714 [[[self session] userDefaults] boolForKey:@"mail_viewImagesInline"];
715
716 if ([self isImageViewerComponent:[self bodyViewerComponent]]
717 && !viewImageInline) {
718 return NO;
719 }
720 return ShowBodyDependingSizeDisable ? NO : YES;
721 }
722
723 - (NSString *)partKey {
724 NSString *key;
725
726 if ((key = [self url]) == nil) {
727 char buf[32];
728
729 // TODO: better use some part hier-id?
730 sprintf(buf, "%p", [self body]);
731 key = [NSString stringWithCString:buf];
732 }
733 return key;
734 }
735
736 - (NSNumber *)showBodyDepSizeVar {
737 NSMutableDictionary *cache;
738
739 cache = [[self session] valueForKey:@"ShowBodyPartsCache"];
740 if (cache == nil) {
741 cache = [NSMutableDictionary dictionaryWithCapacity:64];
742 [[self session] takeValue:cache forKey:@"ShowBodyPartsCache"];
743 }
744 return [cache objectForKey:[self partKey]];
745 }
746
747 - (void)setShowBodyDepSizeVar:(NSNumber *)_n {
748 NSMutableDictionary *cache;
749
750 cache = [[self session] valueForKey:@"ShowBodyPartsCache"];
751
752 if (!cache) {
753 cache = [NSMutableDictionary dictionaryWithCapacity:64];
754 [[self session] takeValue:cache forKey:@"ShowBodyPartsCache"];
755 }
756 [cache takeValue:_n forKey:[self partKey]];
757 }
758
759 - (id)alternateShowBody {
760 NSNumber *n;
761
762 n = ((n = [self showBodyDepSizeVar]) != nil)
763 ? [NSNumber numberWithBool:[n boolValue] ? NO : YES]
764 : [NSNumber numberWithBool:[self showBodyDepSize] ? NO : YES];
765
766 [self setShowBodyDepSizeVar:n];
767 return nil;
768 }
769
770 @end /* LSWMimePartViewer */
771
772 /* categories */
773
774 @implementation NSObject(ViewerSelection)
775
776 - (NSString *)lswPartViewer {
777 return @"LSWMimePartViewer";
778 }
779
780 @end /* NSObject(ViewerSelection) */
781
782 @implementation NGMimeBodyPart(ViewerSelection)
783
784 - (NSString *)lswPartViewer {
785 return @"LSWMimeBodyPartViewer";
786 }
787
788 @end /* NGMimeBodyPart(ViewerSelection) */
789
790 @implementation NGMimeMessage(ViewerSelection)
791
792 - (NSString *)lswPartViewer {
793 //return @"LSWMimeMessageViewer";
794 //return @"LSWMimeBodyPartViewer";
795 return @"SkyMessageRfc822Viewer";
796 }
797
798 @end /* NGMimeMessage(ViewerSelection) */
799
800 @implementation WOSession(ViewerSelection)
801
802 - (NSString *)viewerComponentForPart:(id)_part {
803 return [_part lswPartViewer];
804 }
805
806 @end /* WOSession(ViewerSelection) */