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.