This is TransferPanel.m in view mode; [Download] [Up]
/* -*-ObjC-*-
*******************************************************************************
*
* File: TransferPanel.m
* RCS: TransferPanel.m,v 1.23 1998/06/14 01:33:32 tom Exp
* Description:
* Author: Tom Hageman <tom@basil.icce.rug.nl>
* Created: October 1996
* Modified:
* Language: Objective-C
* Package: EnhanceMail
* Status: Experimental
*
* Copyright (C) 1996, 1997 Tom Hageman, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/
#import "EnhanceMail.h"
#import "TransferPanel.h"
#import "MailboxSummary.h"
#import "MailboxSummaryList.h"
#import "Preferences.h"
#if DEBUG || DEBUG_SUMMARY
# define DFPRINTF(arglist) fprintf arglist
#else
# define DFPRINTF(arglist)
#endif
enum { KIND_UNREAD, KIND_FLAGGED };
@interface NXBrowser (EnhanceTransferPanel)
- (const char *)getPath:(char *)path toCell:(Cell *)cell inColumn:(int)column;
@end
@interface EnhanceMailboxSummary (Mail_app)
- (BOOL)incorporatePendingAppnmailInReader:(MailReader *)reader;
@end
@implementation EnhanceTransferPanel
+ finishLoading:(struct mach_header *)header
{
[self poseAs:[self superclass]];
[[TransferPanel new] changeClassTo:[self class]];
return self;
}
- (void)_updateBrowser:(BOOL)force
{
Window *w = [browser window];
if (force && [w isVisible])
{
DFPRINTF((stderr, "-[%s %s]\n", [[self class] name], SELNAME(_cmd)));
[self loadMailSummaries:NO];
}
[w disableDisplay];
[browser validateVisibleColumns];
[w reenableDisplay];
[browser displayIfNeeded];
[w flushWindow];
}
- (void)updateBrowser
{
[self _updateBrowser:YES];
}
- (void)updateBrowserForMailBoxNamed:(const char *)mailBoxName
{
#if NOTYET
EnhanceMailboxSummary *summary = [EnhanceMailboxSummary summaryForName:mailBoxName];
char path[MAXPATHLEN+1];
// XXX outdated to boot...
int len = mailboxdir(path);
mailBoxName = [summary name];
if (strncmp(path, mailBoxName, len) == 0 && mailBoxName[len] == '/')
{
strcpy(path, &mailBoxName[len]);
len = strlen(path);
if (len > 5 && strcmp(&path[len-5], ".mbox")==0) path[len-5] = '\0';
// XXX how to get cell at path without visual artefacts?
long nUnread = [summary numNewMessages] + [summary numUnreadMessages];
}
#endif
[self _updateBrowser:NO];
}
- (BOOL)browser:sender columnIsValid:(int)column
// delegate method, invoked by [browser validateVisibleColumns].
{
if (![win isVisible]) return YES;
return NO; // make this smarter, but it's usually fast enough for now
}
- show
{
DFPRINTF((stderr, "-[%s %s]\n", [[self class] name], SELNAME(_cmd)));
[self loadMailSummaries:([[browser window] isVisible] ? NO : YES)];
return [super show];
}
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
DFPRINTF((stderr, "-[%s %s]: column=%d\n", [[self class] name], SELNAME(_cmd), column));
[[matrix setPrototype:[[EnhanceMailboxBrowserCell allocFromZone:[matrix zone]] init]] free];
return [super browser:sender fillMatrix:matrix inColumn:column];
}
- browser:sender loadCell:(EnhanceMailboxBrowserCell *)cell atRow:(int)row inColumn:(int)column
{
char path[MAXPATHLEN+1];
unsigned long numMessages = 0;
BOOL pending = NO;
BOOL newMail = NO;
int kind = KIND_UNREAD;
int status = EMS_LOADED;
int scan = 0;
if (EnhanceMaxTocCheckSize != 0)
{
// XXX Should make Summary and SummaryList polymorphic.
if ([cell isLeaf])
{
EnhanceMailboxSummary *summary;
[sender getPath:path toCell:cell inColumn:column];
// (path+1) to skip leading '/'.
summary = [EnhanceMailboxSummary summaryForName:(path+1)];
status = [summary loadStatus];
if (status == EMS_UNLOADED || [summary needsReload])
{
status = [summary load];
}
numMessages = [summary numNewOrUnreadMessages];
if (numMessages == 0 && EnhanceShowFlagged)
{
// Show #flagged messages instead if #unread is zero.
numMessages = [summary numFlaggedMessages];
kind = KIND_FLAGGED;
}
pending = [summary hasPendingAppnmail];
newMail = [summary hasNewMail];
}
else
{
EnhanceMailboxSummaryList *list;
[sender getPath:path toCell:cell inColumn:column];
list = [EnhanceMailboxSummaryList summaryListForName:(path+1)];
status = [list loadStatus];
numMessages = [list numMailboxesWithNewOrUnreadMessages];
pending = [list hasPendingAppnmail];
newMail = [list hasNewMail];
scan = ([list doScan] ? 1 : [list dontScan] ? -1 : 0);
}
}
[cell setNewMail:newMail];
[cell setPending:pending];
[cell setNumMessages:numMessages];
[cell setStatus:status];
[cell setKind:kind];
[cell setScan:scan];
return self;
}
// Mailboxes browser target method.
- loadForm:sender
{
NXBrowserCell *selected = [sender selectedCell];
/* Get selected cell. If it is a non-leaf cell, check modifiers, and
toggle load suppression status accordingly. */
if (selected && ![selected isLeaf])
{
BOOL control = EnhanceControlP();
BOOL alternate = EnhanceAlternateP();
BOOL command = EnhanceCommandP();
if (command || control || alternate)
{
char path[MAXPATHLEN+1];
EnhanceMailboxSummaryList *list;
[sender getPath:path toCell:selected inColumn:[sender selectedColumn]];
list = [EnhanceMailboxSummaryList summaryListForName:(path+1)];
if (command)
{
// Turn both off, thus restoring normal inheritance behiaviour.
[list setDoScan:NO];
[list setDontScan:NO];
}
else if (control)
{
[list setDontScan:YES];
}
else if (alternate)
{
[list setDoScan:YES];
}
/* delayed perform since we're lockfocused here... */
[list perform:@selector(iterateLoad:) with:self afterDelay:0 cancelPrevious:YES];
}
}
return [super loadForm:sender];
}
- (void)updateMessageCount:(unsigned)newMessageCount old:(unsigned)oldMessageCount
forMailBoxNamed:(const char *)mailBoxName isNew:(BOOL)isNew
{
EnhanceMailboxSummary *summary = [EnhanceMailboxSummary summaryForName:mailBoxName];
long summaryUnread, summaryNew;
if ([summary loadStatus] != EMS_LOADED) return;
summaryUnread = [summary numUnreadMessages];
summaryNew = [summary numNewMessages];
// MailReader's messageCounts are totals of summary's (new + unread) counts.
// Try to compensate for this.
if (oldMessageCount != summaryUnread + summaryNew)
{
oldMessageCount = summaryUnread + summaryNew;
}
if (newMessageCount > oldMessageCount)
{
if (isNew)
{
[summary setNewMessages:summaryNew + newMessageCount - oldMessageCount];
}
else
{
[summary setUnreadMessages:summaryUnread + newMessageCount - oldMessageCount];
}
}
else if (newMessageCount < oldMessageCount)
{
// We don't know really at this point if it's a marked-unread or a new message that has been read. So guess.
if (oldMessageCount - newMessageCount <= summaryNew)
{
[summary setNewMessages:summaryNew + newMessageCount - oldMessageCount];
}
else
{
[summary setNewMessages:0];
[summary setUnreadMessages:summaryUnread + newMessageCount - oldMessageCount + summaryNew];
}
}
[self updateBrowserForMailBoxNamed:mailBoxName];
}
- (void)updateFlaggedCountBy:(int)increment forMailBoxNamed:(const char *)mailBoxName
{
EnhanceMailboxSummary *summary = [EnhanceMailboxSummary summaryForName:mailBoxName];
if ([summary loadStatus] != EMS_LOADED) return;
[summary setFlaggedMessages:[summary numFlaggedMessages] + increment];
[self updateBrowserForMailBoxNamed:mailBoxName];
}
- (void)setNewMailFlagForMailBoxNamed:(const char *)mailBoxName
{
EnhanceMailboxSummary *summary = [EnhanceMailboxSummary summaryForName:mailBoxName];
[summary setHasNewMail:YES];
[self updateBrowserForMailBoxNamed:mailBoxName];
}
- (void)loadMailSummaries:(BOOL)reload
{
EnhanceMailboxSummaryList *list;
DFPRINTF((stderr, "-[%s %s]: reload=%d\n", [[self class] name], SELNAME(_cmd), reload));
list = [EnhanceMailboxSummaryList summaryListForName:""];
if (!list)
{
list = [EnhanceMailboxSummaryList cachedSummaryListForName:""];
if (!list)
{
list = [[EnhanceMailboxSummaryList alloc] initWithName:""];
}
[list setAutoUpdateCache:YES];
reload = YES;
}
if (reload) [list scandir];
[EnhanceMailboxSummary setDoPendingAppnmailCheck:EnhanceCheckPendingAppnmail];
[EnhanceMailboxSummaryList setIterateLoadInterval:EnhanceMailboxCheckInterval];
[list iterateLoad:self];
}
// -iterateLoad callback methods:
- (void)didFinishIterateLoad:(EnhanceMailboxSummaryList *)sender
{
DFPRINTF((stderr, "-[%s %s]\n", [[self class] name], SELNAME(_cmd)));
[self _updateBrowser:NO];
}
- (void)newMailForSummary:(EnhanceMailboxSummary *)sender
{
DFPRINTF((stderr, "-[%s %s] (%s)\n", [[self class] name], SELNAME(_cmd), [sender shortName]));
[self _updateBrowser:NO];
if (!EnhanceSilentNewMail) [(MailDriver *)NXApp newMailMsg];
}
- (void)flushSummaryCache
{
EnhanceMailboxSummaryList *list;
list = [EnhanceMailboxSummaryList summaryListForName:""];
[list storeToCache];
}
- (BOOL)checkNewMailForReader:(MailReader *)reader
{
const char *name = [[reader mailbox] dirname];
EnhanceMailboxSummary *summary;
summary = [EnhanceMailboxSummary summaryForName:name];
if ([summary incorporatePendingAppnmailInReader:reader])
{
[self updateBrowserForMailBoxNamed:name];
return YES;
}
return NO;
}
@end // EnhanceTransferPanel
@implementation EnhanceMailboxBrowserCell : NXBrowserCell
static NXImage *loadTiff(const char *fileName, const char *imageName)
{
char path[MAXPATHLEN+1];
NXImage *image=nil;
if ([EnhanceBundle getPath:path forResource:fileName ofType:"tiff"])
{
image=[[NXImage alloc] initFromFile:path];
if (imageName) [image setName:imageName];
}
return image;
}
#define EM(constName) "EM" constName
#define LOAD_TIFF(constName) loadTiff(constName, EM(constName))
+ finishLoading:(struct mach_header *)header
{
EnhanceBundleInit();
LOAD_TIFF("disabled");
LOAD_TIFF("disabledh");
LOAD_TIFF("dots");
LOAD_TIFF("dotsh");
LOAD_TIFF("kaputt");
LOAD_TIFF("kaputth");
LOAD_TIFF("disabledarrow");
LOAD_TIFF("unreadarrow");
LOAD_TIFF("mbox12");
LOAD_TIFF("mbox12h");
LOAD_TIFF("newmail12");
LOAD_TIFF("newmail12h");
LOAD_TIFF("doscan");
LOAD_TIFF("dontscan");
return self;
}
- (long)numMessages { return numMessages; }
- setNumMessages:(long)value { numMessages = value; return self; }
- (BOOL)pending { return pending; }
- setPending:(BOOL)value { pending = value; return self; }
- (BOOL)newMail { return newMail; }
- setNewMail:(BOOL)value { newMail = value; return self; }
- (int)scan { return scan; }
- setScan:(int)value { scan = value; return self; }
- (int)status { return status; }
- setStatus:(int)value { status = value; return self; }
- (int)kind { return kind; }
- setKind:(int)value { kind = value; return self; }
- (NXCoord)_drawImage:(NXImage *)image inside:(const NXRect *)cellFrame
rightAlignedAt:(NXCoord)right
{
NXSize imageSize;
NXPoint imageOrigin;
[image getSize:&imageSize];
imageOrigin.x = right - imageSize.width;
imageOrigin.y = (NX_Y(cellFrame) + NX_HEIGHT(cellFrame) -
(NX_HEIGHT(cellFrame) - imageSize.height) / 2);
[image composite:NX_SOVER toPoint:&imageOrigin];
return imageOrigin.x;
}
- drawInside:(const NXRect *)cellFrame inView:controlView
{
// fudge to line our dot icons up with branch arrow icon.
static const int DOT_XOFFSET = 2;
static const int DOT_WIDTH = 11;
BOOL hilite = (cFlags1.state || cFlags1.highlighted);
NXCoord rightx = NX_MAXX(cellFrame);
NXCoord maxx = rightx - DOT_XOFFSET;
NXImage *dot;
[super drawInside:cellFrame inView:controlView];
if (numMessages > 0)
{
// draw number of unread/flagged messages plus bullet to the right
static id sharedTextCell = nil;
char numstr[20];
NXRect rect;
dot = [NXImage findImageNamed:
![self isLeaf] ? (status == EMS_LOADED ? EM("unreadarrow") : EM("disabledarrow")) :
((kind == KIND_UNREAD) ? (hilite ? "unread" : "unreadh") : "check")];
maxx = [self _drawImage:dot inside:cellFrame rightAlignedAt:maxx];
sprintf(numstr, "%lu", numMessages);
// make cell
if (!sharedTextCell)
{
sharedTextCell = [[TextFieldCell alloc] init];
[sharedTextCell setWrap:NO];
[sharedTextCell setFont:[self font]];
[sharedTextCell setTextGray:NX_DKGRAY];
}
// draw #numMessages, right-aligned.
[sharedTextCell setStringValueNoCopy:numstr];
[sharedTextCell calcCellSize:&rect.size];
NX_HEIGHT(&rect) = NX_HEIGHT(cellFrame);
NX_X(&rect) = NX_X(cellFrame) + NX_WIDTH(cellFrame) - NX_WIDTH(&rect) - DOT_WIDTH;
NX_Y(&rect) = NX_Y(cellFrame);
[sharedTextCell setBackgroundGray:(hilite ? NX_WHITE : NX_LTGRAY)];
[sharedTextCell drawInside:&rect inView:controlView];
maxx = NX_X(&rect);
}
else if (![self isLeaf])
{
if (status != EMS_LOADED)
{
dot = [NXImage findImageNamed:EM("disabledarrow")];
[self _drawImage:dot inside:cellFrame rightAlignedAt:maxx];
}
maxx -= DOT_WIDTH;
}
if (newMail)
{
dot = [NXImage findImageNamed:(hilite ? EM("newmail12") : EM("newmail12h"))];
maxx = [self _drawImage:dot inside:cellFrame rightAlignedAt:maxx];
}
if (status != EMS_LOADED && [self isLeaf])
{
dot = [NXImage findImageNamed:
(status == EMS_LOADSUPPRESSED) ? (hilite ? EM("disabled") : EM("disabledh")) :
(status == EMS_LOADFAILED) ? (hilite ? EM("kaputt") : EM("kaputth")) :
(hilite ? EM("dots") : EM("dotsh"))];
maxx = [self _drawImage:dot inside:cellFrame rightAlignedAt:maxx];
}
if (pending)
{
dot = [NXImage findImageNamed:(hilite ? EM("mbox12") : EM("mbox12h"))];
maxx = [self _drawImage:dot inside:cellFrame rightAlignedAt:maxx];
}
if (scan)
{
dot = [NXImage findImageNamed:(scan > 0 ? EM("doscan") : EM("dontscan"))];
[self _drawImage:dot inside:cellFrame rightAlignedAt:rightx];
}
return self;
}
@end // EnhanceMailboxBrowserCell
@implementation NXBrowser (EnhanceTransferPanel)
- (const char *)getPath:(char *)path toCell:(Cell *)aCell inColumn:(int)column
{
int pathlen;
[self getPath:path toColumn:column];
pathlen = strlen(path);
sprintf(&path[pathlen], "/%s", [aCell stringValue]);
return path;
}
@end // NXBrowser (EnhanceTransferPanel)
@implementation EnhanceMailboxSummary (EnhanceOverride)
- (BOOL)suppressLoad
{
return ([self tableOfContentsSize] / 1024 >= (unsigned)EnhanceMaxTocCheckSize);
}
@end // EnhanceMailboxSummary (EnhanceOverride)
// XXX This knows too much about appnmail internals...
#import "mailtoc.h"
#define APPNMAIL_TOC "appnmail_"MBOX_TOC_FILE
#define APPNMAIL_MBOX "appnmail_"MBOX_CONTENTS_FILE
#define INCOMING_TOC "Incoming_Table_of_Contents"
#define INCOMING_MBOX "Incoming_Mail"
#define APPNMAIL_LOCK ".appnmail.lock"
@implementation EnhanceMailboxSummary (Mail_app)
- (BOOL)_incorporateInReader:(MailReader *)reader
{
/* Assumes proper locking is in place. */
char appnmailTocPath[MAXPATHLEN+1], incomingTocPath[MAXPATHLEN+1];
char appnmailMboxPath[MAXPATHLEN+1], incomingMboxPath[MAXPATHLEN+1];
int result = NO;
[self getPath:appnmailTocPath forFile:APPNMAIL_TOC];
[self getPath:incomingTocPath forFile:INCOMING_TOC];
[self getPath:appnmailMboxPath forFile:APPNMAIL_MBOX];
[self getPath:incomingMboxPath forFile:INCOMING_MBOX];
if (link(appnmailTocPath, incomingTocPath) == 0)
{
if (link(appnmailMboxPath, incomingMboxPath) == 0)
{
[reader incorporateMail:self];
// This should have removed Incoming_* files.
if (access(incomingTocPath, F_OK) != 0 &&
access(incomingMboxPath, F_OK) != 0)
{
unlink(appnmailTocPath);
unlink(appnmailMboxPath);
result = YES;
[self load];
}
unlink(incomingMboxPath);
}
unlink(incomingTocPath);
}
return result;
}
- (BOOL)_lockAppnmail
{
char path[MAXPATHLEN+1];
char line[BUFSIZ];
char localhost[MAXHOSTNAMELEN];
int fd;
[self getPath:path forFile:APPNMAIL_LOCK];
if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) return NO;
gethostname(localhost, sizeof(localhost));
sprintf(line, "%s,%s.app,%d", localhost, [NXApp appName], getpid());
write(fd, line, strlen(line));
close(fd);
return YES;
}
- (void)_unlockAppnmail
{
char path[MAXPATHLEN+1];
[self getPath:path forFile:APPNMAIL_LOCK];
unlink(path);
}
- (BOOL)incorporatePendingAppnmailInReader:(MailReader *)reader
{
BOOL result = NO;
if ([self _lockAppnmail])
{
result = [self _incorporateInReader:reader];
[self _unlockAppnmail];
}
return result;
}
@end // EnhanceMailboxSummary (Mail_app)
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.