This is MailboxInspector.m in view mode; [Download] [Up]
/*+++*
* title: MailboxInspector.m
* abstract: NEXTSTEP Workspace Manager Inspector for Mail.app ".mbox" files.
* author: T.R.Hageman, The Netherlands
* created: May 1996
* modified: (see RCS Log at end)
* copyleft:
*
* Copyright (C) 1996,1997 Tom R. Hageman.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* description:
*
*---*/
static const char *const RCSid = ((void)&RCSid, /* to avoid `unused' warning. */
"@(#)MailboxInspector.m,v 1.5 1997/05/10 15:22:21 tom Exp");
#define VERSION "1.1"
#ifndef DEBUG
# define DEBUG 0
#endif
#import "MailboxInspector.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mailtoc.h"
// Localized strings
#define OPENBUTTON NXLocalizedStringFromTableInBundle(NULL, bundle, "Open", NULL, okbutton label)
#define NO_NEW_MESSAGES NXLocalizedStringFromTableInBundle(NULL, bundle, "", NULL, newMailTextField: No new messages)
#define ONE_NEW_MESSAGE NXLocalizedStringFromTableInBundle(NULL, bundle, "1 new message", NULL, newMailTextField: 1 new message)
#define N_NEW_MESSAGES NXLocalizedStringFromTableInBundle(NULL, bundle, "%lu new messages", NULL, newMailTextField: %lu new messages format string)
#define CANNOT_READ_TOC NXLocalizedStringFromTableInBundle(NULL, bundle, "Unable to read Table of Contents", NULL, newMailTextField: Cannot read Table of Contents)
#define INDEX_SIZE NXLocalizedStringFromTableInBundle(NULL, bundle, "(index: %s)", NULL, indexSizeField: (index: %s))
#define TOC_SIZE NXLocalizedStringFromTableInBundle(NULL, bundle, "(table of contents: %s)", NULL, tocSizeField: (table of contents: %s))
#define KBYTES NXLocalizedStringFromTableInBundle(NULL, bundle, "KB", NULL, KiloBytes)
#define MBYTES NXLocalizedStringFromTableInBundle(NULL, bundle, "MB", NULL, MegaBytes)
#define LOCALIZE(s) NXLoadLocalized\
StringFromTableInBundle(NULL, bundle, s, NULL)
// (line continuation to keep "genstrings" from breaking.)
@implementation MailboxInspector
- initWithNibName:(const char *)nibname
{
char path[MAXPATHLEN+1];
bundle = [NXBundle bundleForClass:[self class]];
if ([bundle getPath:path forResource:nibname ofType:"nib"] &&
[NXApp loadNibFile:path owner:self])
{
// Set version field.
[inspectorVersionField setStringValue:VERSION];
}
else
{
fprintf(stderr, "Couldn't load %s.nib\n", nibname);
[self free];
self = nil;
}
return self;
}
+ new
{
static MailboxInspector *instance;
if (instance == nil)
{
instance = [[super new] initWithNibName:[self name]];
}
return instance;
}
- showInfo:sender
{
if (infoPanel == nil)
{
char path[MAXPATHLEN+1];
if ([bundle getPath:path forResource:"Info" ofType:"nib"] &&
[NXApp loadNibFile:path owner:self])
{
[infoVersionField setStringValue:[inspectorVersionField stringValue]];
}
}
[infoPanel makeKeyAndOrderFront:sender];
return self;
}
- revert:sender
{
[super revert:sender];
if ([self selectionCount] != 1)
{
return nil;
}
else
{
char path[MAXPATHLEN+1];
[mailbox free];
[self selectionPathsInto:path separator:'\0'];
if (!(mailbox = [[NXBundle allocFromZone:[self zone]] initForDirectory:path]))
{
return nil;
}
if ([self shouldLoad])
{
[self load];
}
}
[[[self okButton] setTitle:OPENBUTTON] setEnabled:YES];
return self;
}
- ok:sender
{
[self perform:@selector(open:) with:sender afterDelay:0 cancelPrevious:NO];
[super ok:sender];
return self;
}
- load
{
unsigned long counts[NUMTAGS] = {0};
unsigned long sizes[NUMTAGS] = {0};
unsigned long attachCounts[NUMTAGS] = {0};
unsigned long attachSizes[NUMTAGS] = {0};
BOOL indexed;
unsigned long indexSize;
unsigned long tocSize;
BOOL valid = FALSE;
char path[MAXPATHLEN+1];
char sizeBuf[20];
FILE *tocf;
int tag;
/* Quick hack; knows about *.mbox internals.
A more OO solution would be to introduce a MailBoxSummary object
that does the dirty work, and have us query it. */
if ((tocf = fopen([self getPath:path forFile:FILE_TOC], "rb")) != NULL)
{
struct table_of_contents_header *th;
if ((th = get_table_of_contents_header(tocf, NO)) != NULL)
{
int msgCount = th->num_msgs;
free(th);
valid = TRUE;
// Tally read, new and deleted messages.
while (--msgCount >= 0)
{
struct message_index *mi;
long size, attachSize;
if ((mi = get_message_index(tocf)) == NULL)
{
valid = FALSE;
break;
}
switch (mi->status)
{
case '*':
tag = TAG_NEW;
break;
case 'd': case 'D':
tag = TAG_DELETED;
break;
case 'u': case 'U':
tag = TAG_UNREAD;
break;
case '+':
tag = TAG_FLAGGED;
break;
default:
tag = TAG_READ;
break;
}
size = mi->mes_length;
if ((attachSize = message_attachsize(mi)) > 0)
{
attachCounts[tag]++;
attachSizes[tag] += attachSize;
attachCounts[TAG_TOTAL]++;
attachSizes[TAG_TOTAL] += attachSize;
size += attachSize;
}
counts[tag]++;
sizes[tag] += size;
counts[TAG_TOTAL]++;
sizes[TAG_TOTAL] += size;
free(mi);
}
}
fclose(tocf);
}
/* Quick&dirty hack to determine if index store file exists. */
indexed = (stats[STAT_INDEX].st_ino != 0);
indexSize = stats[STAT_INDEX].st_size;
#if DEBUG & 4
fprintf(stderr, "MailboxInspector: indexed = %d\n", indexed);
#endif
tocSize = stats[STAT_TOC].st_size;
/* Fill in the inspector fields. */
[[self window] disableFlushWindow];
[indexTagButton setState:indexed];
[newMailIconButton setState:(valid && counts[TAG_NEW] > 0)];
[newMailTextField setStringValue:
(valid ? (counts[TAG_NEW] == 0 ? NO_NEW_MESSAGES :
counts[TAG_NEW] == 1 ? ONE_NEW_MESSAGE :
(sprintf(path, N_NEW_MESSAGES, counts[TAG_NEW]), path)) :
CANNOT_READ_TOC)];
for (tag = 0; tag < NUMTAGS; tag++)
{
#define FORMATCOUNT(count) \
(valid ? ((count) ? (sprintf(sizeBuf, "%lu", (count)), sizeBuf) : \
"Ð") : "?")
#define FORMATSIZE(size) \
(valid ? [self formatSize:(size) inBuf:sizeBuf] : "")
[[messageCountMatrix findCellWithTag:tag]
setStringValue:FORMATCOUNT(counts[tag])];
[[messageSizeMatrix findCellWithTag:tag]
setStringValue:FORMATSIZE(sizes[tag])];
[[attachmentCountMatrix findCellWithTag:tag]
setStringValue:FORMATCOUNT(attachCounts[tag])];
[[attachmentSizeMatrix findCellWithTag:tag]
setStringValue:FORMATSIZE(attachSizes[tag])];
#undef FORMATCOUNT
#undef FORMATSIZE
}
[indexSizeField setStringValue:
(indexed ? (sprintf(path, INDEX_SIZE, [self formatSize:indexSize
inBuf:sizeBuf]), path) : "")];
[tocSizeField setStringValue:
(sprintf(path, TOC_SIZE, [self formatSize:tocSize inBuf:sizeBuf]), path)];
[[self window] reenableFlushWindow];
[[self window] flushWindowIfNeeded];
return self;
}
#define STAT_EQ(s1, s2) ((s1)->st_ino == (s2)->st_ino && \
(s1)->st_dev == (s2)->st_dev && \
(s1)->st_mtime == (s2)->st_mtime && \
(s1)->st_size == (s2)->st_size)
- (BOOL)shouldLoad
{
char path[MAXPATHLEN+1];
struct stat newstats[NUMSTATS];
static const char * const filesToStat[NUMSTATS] = { FILESTOSTAT };
BOOL result = NO;
int i;
for (i = 0; i < NUMSTATS; i++)
{
memset(&newstats[i], 0, sizeof(struct stat));
stat([self getPath:path forFile:filesToStat[i]], &newstats[i]);
if (!STAT_EQ(&newstats[i], &stats[i]))
{
result = YES;
///break; // NOT!!! must stat all for accurate cache.
}
stats[i] = newstats[i];
}
return result;
}
// Support methods
- (const char *)getPath:(char *)buf forFile:(const char *)file
{
sprintf(buf, "%s/%s", [mailbox directory], file);
#if DEBUG & 2
fprintf(stderr, "MailboxInspector: file=\"%s\" path=\"%s\"\n",
file, buf);
#endif
return buf;
}
- (const char *)formatSize:(unsigned long)size inBuf:(char *)buf
{
#define KB 1024
#define MB (KB * 1024)
if (size == 0)
{
strcpy(buf, "");
}
else if (size < 1000*KB - KB/2)
{
sprintf(buf, "%.*f%s",
//(size < 10*KB - KB/2 ? 2 : size < 100*KB - KB/2 ? 1 : 0),
(size < 10*KB - KB/2 ? 1 : 0),
(double) size / KB, KBYTES);
}
else
{
sprintf(buf, "%.*f%s",
//(size < 10*MB - MB/2 ? 2 : size < 100*MB - MB/2 ? 1 : 0),
(size < 10*MB - MB/2 ? 1 : 0),
(double) size / MB, MBYTES);
}
return buf;
#undef KB
#undef MB
}
static void openInWorkspace(const char *filename)
{
// Indirect approach to circumvent Workspace deadlock/timeout.
char command[14+3*MAXPATHLEN+1];
const char *s;
char *d = command;
for (s = "exec open '"; *s; ) *d++ = *s++;
// Escape single quote characters.
for (s = filename; *s; )
{
if ((*d++ = *s++) == '\'')
{
*d++ = '\\', *d++ = '\'', *d++ = '\'';
}
}
for (s = "'&"; *d++ = *s++; ) ;
system(command);
}
- open:sender
{
openInWorkspace([mailbox directory]);
return self;
}
@end // MailboxInspector
//======================================================================
// MailboxInspector.m,v
// Revision 1.5 1997/05/10 15:22:21 tom
// MailboxInspector:
// (tocSizeField): new outlet.
// (VERSION): bumped to 1.1.
// (TOC_SIZE): new localizable string.
// (LOCALIZE): hack to keep "genstrings" from breaking.
// (-load): show toc size.
//
// Makefile.preamble:
// (GENSTRINGS,LANGUAGE_DIRECTORIES): new variables.
//
// Makefile.postamble:
// (clean::,resources::,genstrings:): new targets.
//
// README.rtf:
// - updated for 1.1.
//
// Revision 1.4 1997/04/19 18:14:56 tom
// (VERSION): upped to 1.0.
// (-load): adapt to mailtoc API changes.
//
// Revision 1.3 1996/06/27 22:55:52 tom
// Add sccs `what' marker in ident.
//
// Revision 1.2 1996/06/27 20:04:40 tom
// (VERSION): bumped to 0.9.
// (INDEX_SIZE): new localizable.
// (-load): show size of index store.
//
// Revision 1.1 1996/06/26 14:40:42 tom
// Initial revision
//
//======================================================================
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.