This is ArticleViewControl.m in view mode; [Download] [Up]
// Most of this implementation is an ugly hack to integrate the new
// message framework into the old Alexandra codebase.
#import "Alexandra.h"
#import "AlexandraApp.h"
#import "ArticleViewControl.h"
#import <misckit/MiscAppDefaults.h>
#import "response_codes.h"
#import "FaceView.h"
#import <misckit/MiscClockView.h>
#import "parse-header.h"
#import "rfc822realname.h"
#include <ctype.h>
#import <foundation/foundation.h>
#import "LFCompatibility.h"
#import "Message.h"
#import "UrlGraphicCell.h"
#import "ImageCell.h"
#import "AttachmentCell.h"
#import "NSString+MessageUtils.h"
#define URLIFIER_DIRECTIVE "URLAdornment"
#define IMAGE_DIRECTIVE "Image"
#define ATTACHMENT_DIRECTIVE "Attachment"
#define QUOTESTRING "> "
//#define ISEMPTY(string) ((string==NULL)||(*(string)=='\0'))
#define FORCEBREAK "\n\t -·1234567890>#}:"
static void writeNSStringToRTFStream(NXStream *stream, void *item, void *data)
{
NSString *string = item;
unsigned char c;
const char *cp;
int i, l;
if(string == nil)
{
NXPrintf(stream, "*nil*");
}
else
{
for(cp = [string cString]; *cp != '\0'; cp++)
{
c = *cp;
if(NXIsPrint(c) || NXIsSpace(c))
{
if((c == '\n') || (c == '\\') || (c == '{') || (c == '}'))
NXPutc(stream, '\\');
NXPutc(stream, c);
}
}
}
}
static void writeNSStringToASCIIStream(NXStream *stream, void *item, void *data)
{
NSString *string = item;
NSData *cstring;
if(string == nil)
{
NXPrintf(stream, "*nil*");
}
else
{
cstring = [string dataUsingEncoding:NSNEXTSTEPStringEncoding
allowLossyConversion:NO];
NXWrite(stream, [cstring bytes], [cstring length]);
}
}
@implementation ArticleViewControl
+ initialize
{
NXRegisterPrintfProc('w', &writeNSStringToRTFStream, [(Object *)self zone]);
NXRegisterPrintfProc('v', &writeNSStringToASCIIStream, [(Object *)self zone]);
return self;
}
- init
{
[super init];
noArticle=TRUE;
rot13=FALSE;
[ERROR_MANAGER addObserver:self
selector:@selector(updateText)
forError:ENOTEPrefsChanged];
[Text registerDirective: URLIFIER_DIRECTIVE forClass:[UrlGraphicCell class]];
[Text registerDirective:IMAGE_DIRECTIVE forClass:[ImageCell class]];
[Text registerDirective:ATTACHMENT_DIRECTIVE forClass:[AttachmentCell class]];
[self updateText];
return self;
}
- awakeFromNib
{
[theText setFontPanelEnabled:FALSE];
[clockView setMilitaryTime:[NXApp defaultBoolValue:"24HourClock"]];
[clockView setHide:YES];
return self;
}
- free
{
[article release];
[ERROR_MANAGER removeObserver:self forError:ENOTEPrefsChanged];
return [super free];
}
- updateText
{
[self displayArticleScrollUp:NO];
return self;
}
- (int)loadArticle:(Article *)theArticle fromGroup:(const char *)theGroup
{
int statusCode;
NSData *articleData;
NSString *hfList[FIELD_COUNT - XOVER_COUNT] =
{@"Reply-To", @"Followup-To", @"Newsgroups", @"Organization"};
NSString *hfValue;
int i;
time_t t;
[article release];
article = nil;
statusCode = [nntpServer loadArticleWithNumber:[theArticle number]
intoData:&articleData];
if(statusCode != OK_ARTICLE)
return statusCode;
article = [[MessagePart messagePartWithData:articleData] retain];
for(i = 0; i < FIELD_COUNT - XOVER_COUNT; i++)
if((hfValue = [article stringValueOfHeaderFieldNamed:hfList[i]]) != nil)
[theArticle header]->fieldBody[XOVER_COUNT + i] =
NXCopyStringBuffer([hfValue cString]);
noArticle=FALSE;
rot13 = FALSE;
urlZaps = TRUE;
[self displayArticleScrollUp:YES];
if(![imageView showFaceForName:[theArticle header]->fieldBody[FROM]])
{
const char *r = [theArticle header]->fieldBody[REPLY_TO];
if((r != NULL) && (*r != '\0'))
[imageView showFaceForName:r];
}
t = [theArticle time];
[[[clockView setHide:FALSE] setTime:localtime(&t)] display];
return OK_ARTICLE;
}
- displayArticleScrollUp:(BOOL)scroll
{
Font *textFont, *sigFont, *nptitleFont;
NXSize visibleSize;
NXRect theUpperRect;
NXStream *stream;
if(noArticle)
return self;
textFont = [NXApp defaultFont:DEFAULT_ARTICLE_FONT];
sigFont = [Font userFixedPitchFontOfSize:0 matrix:NX_FLIPPEDMATRIX];
nptitleFont = [Font systemFontOfSize:24 matrix:NX_FLIPPEDMATRIX];
signatureDetection = [NXApp defaultBoolValue:DEFAULT_SIG_DETECTION];
rewrapping = [NXApp defaultBoolValue:DEFAULT_REWRAP_ARTICLE_TEXT];
headerMode = [NXApp defaultIntValue:DEFAULT_HEADER_MODE];
rtfCellCounter = 0;
stream = NXOpenMemory(NULL, 0, NX_READWRITE);
NXPrintf(stream, "{\\rtf0\\ansi{\\fonttbl\\f0\\fnil %s;\\f1\\fnil %s;\\f2\\fnil %s;}\n\\paperw11040\\paperh9800\\margl120\\margr120\\pard\\tx520\\tx1060\\f0\\b0\\i0\\ulnone\\fc0\\cf0\\fs%d ", [textFont name], [nptitleFont name], [sigFont name], (int)([textFont pointSize] * 2));
if(headerMode==NEWSPAPER_HEADER)
[self writeNewspaperHeaderOntoStream:stream];
else if(headerMode==FULL_HEADER)
[self writeCompleteHeaderOntoStream:stream];
else if(headerMode==SMALL_HEADER)
[self writeFilteredHeaderOntoStream:stream];
NXPrintf(stream, "\\\n\\f0\\fs%d ", (int)([textFont pointSize] * 2));
[self writeMessagePart:article ontoStream:stream type:StreamTypeRTF];
NXPrintf(stream, "}\n");
[[theText window] disableDisplay];
[theText setAutodisplay:NO];
#if DEBUG
NXSeek(stream, 0, NX_FROMSTART);
NXSaveToFile(stream, "/tmp/article.rtf");
#endif
NXSeek(stream, 0, NX_FROMSTART);
chdir([NXApp scratchDirectoryName]);
[theText readRichText:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
if(scroll)
{
[[[theText superview] superview] getContentSize:&visibleSize];
NXSetRect(&theUpperRect,0.0,0.0,visibleSize.width,visibleSize.height);
[theText scrollRectToVisible:&theUpperRect];
}
[theText setAutodisplay:YES];
[[theText window] reenableDisplay];
[[theText window] display];
return self;
}
//---------------------------------------------------------------------------------------
// Writing the header
//---------------------------------------------------------------------------------------
- (void)writeCompleteHeaderOntoStream:(NXStream *)stream;
{
NSEnumerator *fieldEnum;
NSString *fieldName;
fieldEnum = [[article headerFieldNames] objectEnumerator];
while((fieldName = [fieldEnum nextObject]) != nil)
{
NXPrintf(stream, "{\\b %w:} ", fieldName);
[self writeString:[article stringValueOfHeaderFieldNamed:fieldName]
ontoStream:stream type:StreamTypeRTF];
NXPrintf(stream, "\\\n");
}
}
- (void)writeFilteredHeaderOntoStream:(NXStream *)stream;
{
const char *ddbValue;
NSArray *requestedFields;
NSEnumerator *fieldEnum;
NSString *fieldName, *fieldValue;
ddbValue = [NXApp defaultValue:DEFAULT_HEADER_FILTER];
if(*ddbValue == '\0')
return;
requestedFields = [[NSString stringWithCString:ddbValue]
componentsSeparatedByString:@":"];
fieldEnum = [requestedFields objectEnumerator];
while((fieldName = [fieldEnum nextObject]) != nil)
{
if([fieldName isEqualToString:@""])
continue;
if((fieldValue = [article stringValueOfHeaderFieldNamed:fieldName]) == nil)
continue;
NXPrintf(stream, "{\\b %w:} ", fieldName);
[self writeString:fieldValue ontoStream:stream type:StreamTypeRTF];
NXPrintf(stream, "\\\n");
}
}
- (void)writeNewspaperHeaderOntoStream:(NXStream *)stream;
{
NSString *subject, *from, *organization;
subject = [article stringValueOfHeaderFieldNamed:@"Subject"];
if([subject isEqualToString:@""] == NO)
{
Font *titleFont;
int titleSize = 24;
NXRect visibleRect;
titleFont = [Font systemFontOfSize:titleSize matrix:NX_FLIPPEDMATRIX];
titleFont = [[FontManager new] convert:titleFont toHaveTrait:NX_BOLD];
[theText getVisibleRect:&visibleRect];
while(([titleFont getWidthOf:[subject cString]] > NX_WIDTH(&visibleRect) - 10) &&
(titleSize > 12))
{
titleSize -= 2;
titleFont = [[FontManager new] convert:titleFont toSize:titleSize];
}
NXPrintf(stream, "\\f1\\b\\fs%d %w\\b0\\\n", titleSize * 2, subject);
}
from = [article stringValueOfHeaderFieldNamed:@"From"];
if((from != nil) && ([from isEqualToString:@""] == NO))
{
NSString *realname;
realname = [from realnameFromEMailAddress];
NXPrintf(stream, "\\f1\\b\\i0\\ulnone\\fs28 by %w", realname);
organization = [article stringValueOfHeaderFieldNamed:@"Organization"];
if((organization != nil) && ([organization isEqualToString:@""] == NO))
NXPrintf(stream, ", %w", organization);
NXPrintf(stream, "\\b0\\\n");
}
}
//---------------------------------------------------------------------------------------
// writing the body
//---------------------------------------------------------------------------------------
- writeBody:(NXStream *)aStream
{
[self writeMessagePart:article ontoStream:aStream type:StreamTypeASCII];
return self;
}
- writeQuotedText:(NXStream *)aStream
{
NXStream *tmpStream;
NSString *quotePrefixString, *string;
const char *quotePrefixCString;
char *buffer;
int length, maxlength, width;
quotePrefixCString=[NXApp defaultValue:DEFAULT_QUOTING_PREFIX];
if(!quotePrefixCString){
[NXApp setDefault:DEFAULT_QUOTING_PREFIX to:QUOTESTRING];
quotePrefixCString=[NXApp defaultValue:DEFAULT_QUOTING_PREFIX];
}
quotePrefixString = [NSString stringWithCString:quotePrefixCString];
// this is awkward...
tmpStream = NXOpenMemory(NULL, 0, NX_READWRITE);
[self writeMessagePart:article ontoStream:tmpStream type:StreamTypeASCII];
NXGetMemoryBuffer(tmpStream, &buffer, &length, &maxlength);
string = [[[NSString alloc] initWithCStringNoCopy:buffer length:length
freeWhenDone:NO] autorelease];
width = 72 - [quotePrefixString length];
string = [[string stringByWrappingToLineLength:width]
stringByPrefixingLinesWithString:quotePrefixString];
NXWrite(aStream, [string cString], [string cStringLength]);
NXCloseMemory(tmpStream, NX_FREEBUFFER);
return self;
}
//---------------------------------------------------------------------------------------
// writing a message part
//---------------------------------------------------------------------------------------
- (void)writeMessagePart:(MessagePart *)part ontoStream:(NXStream *)stream type:(int)streamType;
{
NSString *contentType = [part contentType];
NSString *contentSubtype = [part contentSubtype];
if(contentType == MIMEMultipartContentType)
{
NSEnumerator *subpartEnum;
MessagePart *subpart, *richestAcceptableVersion;
if([contentSubtype isEqualToString:MIMEAlternativeMPSubtype])
{ // this is not perfect yet. no nested parts allowed! also assumes that
// subparts are textual. who would post two versions of, say, an image
// anyway?!
richestAcceptableVersion = nil;
subpartEnum = [(NSArray *)[part contents] reverseObjectEnumerator];
while((subpart = [subpartEnum nextObject]) != nil)
{
if([subpart contentType] == MIMETextContentType)
{
NSString *subtype = [subpart contentSubtype];
if([subtype isEqualToString:@"plain"] || [subtype
isEqualToString:@"enriched"])
break;
else if([subtype isEqualToString:@"html"])
richestAcceptableVersion = subpart;
}
}
if(subpart == nil)
if(richestAcceptableVersion != nil)
subpart = richestAcceptableVersion;
else
subpart = [(NSArray *)[part contents] lastObject];
[self writeMessagePart:subpart ontoStream:stream type:streamType];
}
else
{
subpartEnum = [(NSArray *)[part contents] objectEnumerator];
while((subpart = [subpartEnum nextObject]) != nil)
[self writeMessagePart:subpart ontoStream:stream type:streamType];
}
}
else if(contentType == MIMETextContentType)
{
if([contentSubtype isEqualToString:@"plain"])
[self writePlainText:[part contents] ontoStream:stream type:streamType];
else if([contentSubtype isEqualToString:@"enriched"])
[self writeEnrichedText:[part contents] ontoStream:stream type:streamType];
else if([contentSubtype isEqualToString:@"html"])
[self writeAttachment:
[(NSString *)[part contents] dataUsingEncoding:NSISOLatin1StringEncoding]
withName:[part filename] ontoStream:stream type:streamType];
else
[self writeAttachment:
[(NSString *)[part contents] dataUsingEncoding:[NSString
defaultCStringEncoding]] withName:[part filename] ontoStream:stream
type:streamType];
}
else if(contentType == MIMEMessageContentType)
{
if([contentSubtype isEqualToString:@"rfc822"])
[self writeAttachment:[part contents] withName:[part filename]
ontoStream:stream type:streamType];
else if([contentSubtype isEqualToString:@"external-body"])
[self writeAttachment:[part transferRepresentation]
withName:[part filename] ontoStream:stream type:streamType];
else
NXRunAlertPanel(NULL, "Cannot handle MIME type message/%@ yet.", "Cancel",
NULL, NULL, contentSubtype);
}
else if((contentType == MIMEImageContentType) ||
((contentType == MIMEApplicationContentType) && [contentSubtype
isEqualToString:@"postscript"]))
{
NSString *dispositionType;
if((contentType != MIMEImageContentType) && ([NXApp
defaultBoolValue:DEFAULT_ALLOW_PS_INLINE] == NO))
dispositionType = MIMEAttachmentContentDisposition;
else
if((dispositionType = [part contentDisposition]) == nil)
dispositionType = MIMEInlineContentDisposition;
if(dispositionType == MIMEInlineContentDisposition)
[self writeImage:[part contents] withName:[part filename] ontoStream:stream
type:streamType];
else
[self writeAttachment:[part contents] withName:[part filename]
ontoStream:stream type:streamType];
}
else // cannot display anything inline
{
[self writeAttachment:[part contents] withName:[part filename] ontoStream:stream
type:streamType];
}
}
//---------------------------------------------------------------------------------------
// writing textual contents
//---------------------------------------------------------------------------------------
- (void)writePlainText:(NSString *)string ontoStream:(NXStream *)stream type:(int)streamType;
{
if(rewrapping)
string = [string stringByUnwrappingParagraphs];
[self writeString:string ontoStream:stream type:streamType];
}
- (void)writeEnrichedText:(NSString *)text ontoStream:(NXStream *)stream type:(int)streamType;
{
static NSCharacterSet *etSpecialSet = nil, *newlineSet;
NSScanner *scanner;
NSMutableString *buffer, *output;
NSString *string, *command;
int nofillct, paramct;
char *attribChange;
BOOL scanNormal = YES;
if(etSpecialSet == nil)
{
etSpecialSet = [[NSCharacterSet characterSetWithCharactersInString:@"\n<"]
retain];
newlineSet = [[NSCharacterSet characterSetWithCharactersInString:@"\n"] retain];
}
buffer = [NSMutableString string];
nofillct = paramct = 0;
scanner = [NSScanner scannerWithString:text];
[scanner setCharactersToBeSkipped:nil];
while([scanner isAtEnd] == NO)
{
output = (paramct > 0) ? nil : buffer;
if(scanNormal)
{
if([scanner scanUpToCharactersFromSet:etSpecialSet intoString:&string])
[output appendString:string];
scanNormal = NO;
}
else if([scanner scanString:@"<" intoString:NULL])
{
if([scanner scanString:@"<" intoString:NULL])
{
[output appendString:@"<"];
}
else
{
if([scanner scanUpToString:@">" intoString:&string] == NO)
[NSException raise:MIMEFormatException format:@"text/enriched"];
[scanner scanString:@">" intoString:NULL];
command = string = [string lowercaseString];
if([command hasPrefix:@"/"])
command = [command substringFromIndex:1];
attribChange = NULL;
if([string isEqualToString:@"param"])
paramct += 1;
else if([string isEqualToString:@"/param"])
paramct -= 1;
else if([string isEqualToString:@"nofill"])
nofillct += 1;
else if([string isEqualToString:@"/nofill"])
nofillct -= 1;
else if([command isEqualToString:@"bold"])
attribChange = "b";
else if([command isEqualToString:@"italic"])
attribChange = "i";
if((attribChange != NULL) && (streamType == StreamTypeRTF))
{
[self writeString:buffer ontoStream:stream type:streamType];
buffer = [NSMutableString string];
if([string hasPrefix:@"/"] == NO)
NXPrintf(stream, "\\%s ", attribChange);
else
NXPrintf(stream, "\\%s0 ", attribChange);
}
}
}
else if([scanner scanCharactersFromSet:newlineSet intoString:&string])
{
if(nofillct > 0)
[output appendString:string];
else
if([string length] == 1)
[output appendString:@" "];
else
[output appendString:[string substringFromIndex:1]];
}
else
{
scanNormal = YES;
}
}
[self writeString:buffer ontoStream:stream type:streamType];
}
//---------------------------------------------------------------------------------------
// primitives
//---------------------------------------------------------------------------------------
- (void)writeString:(NSString *)string ontoStream:(NXStream *)stream type:(int)streamType;
{
static NSCharacterSet *colon = nil, *alpha, *urlstop;
static NSArray *services;
static unsigned int maxServLength;
NSRange r, remainingRange, possServRange, servRange, urlRange;
NSEnumerator *serviceEnumerator;
NSString *service;
unsigned int outputLocation, nextLocation;
if(rot13)
string = [string stringByApplyingROT13];
if(streamType == StreamTypeASCII)
{
NXPrintf(stream, "%v", string);
return;
}
else if(urlZaps == NO)
{
NXPrintf(stream, "%w", string);
return;
}
if(colon == nil)
{
colon = [[NSCharacterSet characterSetWithCharactersInString:@":"] retain];
alpha = [[NSCharacterSet alphanumericCharacterSet] retain];
urlstop = [[NSCharacterSet characterSetWithCharactersInString:
@"\"<>()[]',; \t\n\r"] retain];
services = [[NSArray arrayWithObjects:@"http", @"ftp", @"mailto", @"gopher",
@"news", nil] retain];
maxServLength = 6;
}
nextLocation = outputLocation = 0;
while(1)
{
remainingRange = NSMakeRange(nextLocation, [string length] - nextLocation);
r = [string rangeOfCharacterFromSet:colon options:0 range:remainingRange];
if(r.length == 0)
break;
nextLocation = r.location + r.length;
if(r.location < maxServLength)
possServRange = NSMakeRange(0, r.location);
else
possServRange = NSMakeRange(r.location - 6, 6);
// no need to clean up composed chars becasue they are not allowed in URLs anyway
serviceEnumerator = [services objectEnumerator]; // b/c
while((service = [serviceEnumerator nextObject]) != nil)
{
servRange = [string rangeOfString:service options: (NSBackwardsSearch |
NSAnchoredSearch | NSLiteralSearch) range:possServRange];
if(servRange.length != 0)
{
r.length = [string length] - r.location;
r = [string rangeOfCharacterFromSet:urlstop options:0 range:r];
urlRange.location = servRange.location;
if(r.length == 0) // not found, assume URL extends to end of string
r.location = [string length];
urlRange = NSMakeRange(servRange.location,
r.location - servRange.location);
nextLocation = urlRange.location + urlRange.length;
r = NSMakeRange(outputLocation, urlRange.location - outputLocation);
NXPrintf(stream, "%w", [string substringWithRange:r]);
[self writeURL:[string substringWithRange:urlRange] ontoStream:stream
type:streamType];
outputLocation = nextLocation;
break;
}
}
}
if(outputLocation < [string length])
{
r = NSMakeRange(outputLocation, [string length] - outputLocation);
NXPrintf(stream, "%w", [string substringWithRange:r]);
}
}
- (void)writeImage:(NSData *)data withName:(NSString *)name ontoStream:(NXStream *)stream type:(int)streamType;
{
if(streamType == StreamTypeRTF)
{
NSString *pathName;
pathName = [NSString stringWithFormat:@"%s/%@",
[NXApp scratchDirectoryName], name];
[data writeToFile:pathName atomically:NO];
NXPrintf(stream, "{{\\%s%d %w}\n\254}",
IMAGE_DIRECTIVE, rtfCellCounter++, pathName);
}
else
{
NXPrintf(stream, "[An image was included here]");
}
}
- (void)writeAttachment:(NSData *)data withName:(NSString *)name ontoStream:(NXStream *)stream type:(int)streamType;
{
if(streamType == StreamTypeRTF)
{
// file + file.tiff ablegen
NSString *pathName;
pathName = [NSString stringWithFormat:@"%s/%@",
[NXApp scratchDirectoryName], name];
[data writeToFile:pathName atomically:NO];
NXPrintf(stream, "{{\\%s%d %w}\n\254}",
ATTACHMENT_DIRECTIVE, rtfCellCounter++, pathName);
}
else
{
NXPrintf(stream, "[An attachment was included here]");
}
}
- (void)writeURL:(NSString *)url ontoStream:(NXStream *)stream type:(int)streamType;
{
if(streamType == StreamTypeRTF)
{
NXPrintf(stream, "{{\\%s%d %w}%c}%w", URLIFIER_DIRECTIVE, rtfCellCounter++,
url, 254, url);
}
else
{
NXPrintf(stream, "%v", url);
}
}
//---------------------------------------------------------------------------------------
// target methods
//---------------------------------------------------------------------------------------
- clear
{
[theText setAutodisplay:NO];
[theText setText:""];
[[theText setAutodisplay:YES] display];
noArticle=TRUE;
[imageView showFaceForName:NULL];
[[clockView setHide:TRUE] display];
if(article != nil)
[article release];
article = nil;
return self;
}
- saveAs:sender
{
SavePanel *panel;
int fd;
NXStream *theStream;
static char *dir=NULL;
const char *articleHeader;
if(dir==NULL)
dir=NXCopyStringBuffer([NXApp defaultValue:DEFAULT_SAVE_PATH]);
if([theText textLength]==0 || noArticle)
return self;
panel=[SavePanel new];
if([panel runModalForDirectory:dir file:""]!=NX_CANCELTAG){
free(dir);
dir=NXCopyStringBuffer([panel filename]);
}
else
return nil;
//Save
fd=open([panel filename],O_WRONLY|O_CREAT|O_TRUNC,0666);
if(fd<0){
NXRunAlertPanel("ALEXANDRA","Can't save file: %s",NULL,NULL,NULL,strerror(errno));
return self;
}
articleHeader = [self articleHeader];
theStream=NXOpenFile(fd,NX_WRITEONLY);
NXWrite(theStream,articleHeader,strlen(articleHeader));
NXWrite(theStream,"\n",1);
[self writeBody:theStream];
NXClose(theStream);
close(fd);
return self;
}
- printText:sender
{
if([theText textLength]!=0){
[[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
[theText printPSCode:self];
}
return self;
}
- (const char *)articleHeader
{
NSEnumerator *headerEnum;
NSString *headerFieldName;
NSMutableString *allHeaderFields;
if(noArticle)
return NULL;
allHeaderFields = [[[NSMutableString alloc] init] autorelease];
headerEnum = [[article headerFieldNames] objectEnumerator];
while((headerFieldName = [headerEnum nextObject]) != nil)
{
[allHeaderFields appendString:headerFieldName];
[allHeaderFields appendString:@": "];
[allHeaderFields appendString:
[article stringValueOfHeaderFieldNamed:headerFieldName]];
[allHeaderFields appendString:@"\n"];
}
return [allHeaderFields cString]; // is autoreleased...
}
-(id)theText
{
return theText;
}
- setModeTo:(int)mode
{
[NXApp setDefault:DEFAULT_HEADER_MODE toInt:mode];
if(!noArticle)
[self displayArticleScrollUp:NO];
return self;
}
- showHeader:sender
{
[self setModeTo:FULL_HEADER];
return self;
}
- hideHeader:sender
{
[self setModeTo:NO_HEADER];
return self;
}
- smallHeader:sender
{
[self setModeTo:SMALL_HEADER];
return self;
}
- newspaperHeader:sender
{
[self setModeTo:NEWSPAPER_HEADER];
return self;
}
- (BOOL)headermodeCellEnabled:menuCell
{
if((headerMode!=FULL_HEADER)&&([menuCell action]==@selector(showHeader:)))
return TRUE;
else if((headerMode!=NO_HEADER)&&([menuCell action]==@selector(hideHeader:)))
return TRUE;
else if((headerMode!=SMALL_HEADER)&&([menuCell action]==@selector(smallHeader:)))
return TRUE;
else if((headerMode!=NEWSPAPER_HEADER)&&([menuCell action]==@selector(newspaperHeader:)))
return TRUE;
return FALSE;
}
- rot13:sender
{
rot13=!rot13;
[self displayArticleScrollUp:NO];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.