home *** CD-ROM | disk | FTP | other *** search
- //
- // MailWatchView.m
- // A BackSpace Module
- // Version 1.1 11/09/94
- // by Robert Lutwak robert@amo.mit.edu
- //
- // Revision History
- //
- // Version 1.1
- //
- // Replaced calls to opendir() and readdir() with stat() on file name.
- // This way we can catch zero-size mail files left behind
- // by some mail clients
- //
- // Added dwrite for no-mail gray level: dwrite MailWatch DarkGray (0.0-1.0)
- //
- // Replaced dumb time-counting loop with call to currentTimeInMS
- // Added dwrite for when to check (in seconds): dwrite MailWatch TimeToCheck
- //
- // Obliterated random color change
- // Switched to Hue-Saturation-Brightness color method
- // Now Hue is scaled 0.0-1.0 proportional amount of mail on 0-100KB
- //
- // Version 1.2
- //
- // Added "magic" names to list for: "time" "day" "date"
- // Version 1.3
- // Added cool new pref. panel for defaults
- // Added "hostname" option
- // Added Energy adjustment
- // Ya' know, this is just getting to different for minor indices...
- //
- //
- // Version 2.0
- //
- // Restructuring of pretty much everything.
- //
- // 2/3/96 Fixed bug in initUsers: which caused an an unitialized user to be
- // created if the NameList was empty
- // Added check for MAXU in addName: to avoid writing beyond bounds
- // of users[]. Now addName: returns -1 if full.
- //
- // 2/4/96 Fixed assignment of BOOL users[TAG].active in initFrame: so that
- // BOOL is assigned 0 or 1 rather than strcmp("YES", "NO")
-
-
- #import "MailWatchView.h"
- #import <appkit/appkit.h>
- #import <strings.h>
- #import <appkit/Font.h>
- #import <sys/types.h>
- #import <sys/stat.h>
- #import <defaults/defaults.h>
- #import <math.h>
- #import <time.h>
- #import <dpsclient/wraps.h>
- #import <appkit/FontManager.h>
- #include <pwd.h>
- #import "Thinker.h"
-
- @implementation MailWatchView
-
- - checkMail:(int)tag
- {
- struct stat fileinfo;
- char path[100];
- int size;
- time_t tTime;
- struct tm *currentTime;
-
-
- if (tag >= NAMETAGSTART) {
- // Construct full path
- strcpy(path, MailDirectory);
- strcat(path, "/");
- strcat(path, users[tag].name);
- // Get file info check size
- if ( (stat(path, &fileinfo) < 0)
- || ((size=fileinfo.st_size) == 0) ) {
- users[tag].HasMail = NO;
- }
-
- else {
- users[tag].HasMail = YES;
-
- if (BW) {
- users[tag].hue = 1.0;
- }
- else {
- // Change color to indicate amount of Mail
- users[tag].hue = (double) size / (double)(MaxMail * 1000);
- if (users[tag].hue > 1.0) users[tag].hue = 1.0;
- }
- }
- }
- /* Time */
- else if (tag == TIMETAG) {
- time(&tTime);
- currentTime= localtime(&tTime);
- strftime(users[tag].name, 30, "%H:%M", currentTime);
-
- if (BW) users[tag].hue = 1.0;
- else users[tag].hue = (float) (currentTime->tm_min) / 60.0;
- }
- /* Day */
- else if (tag == DAYTAG) {
- time(&tTime);
- currentTime= localtime(&tTime);
-
- strftime(users[tag].name, 10, "%A", currentTime);
- if (BW) users[tag].hue = 1.0;
- else users[tag].hue = (float) (currentTime->tm_wday) / 7.0;
-
- }
-
- /* Date */
- else if (tag == DATETAG) {
- time(&tTime);
- currentTime= localtime(&tTime);
-
- strftime(users[tag].name, 10, "%m/%d", currentTime);
- if (BW) users[tag].hue = 1.0;
- else users[tag].hue = (float) (currentTime->tm_mday) / 31.0;
- }
- /* Host */
- else if (tag == HOSTTAG) {
- users[tag].hue += (double)Energy/1.e6;
- if (users[tag].hue > 1.0) users[tag].hue -= 1.0;
- }
-
- users[tag].rect.size.width
- = [NameFont[(int)users[tag].HasMail] getWidthOf:users[tag].name];
-
- users[tag].rect.size.height
- = [NameFont[(int)users[tag].HasMail] pointSize];
-
- users[tag].mass
- = (float) (users[tag].rect.size.height * users[tag].rect.size.width);
-
- return self;
- }
-
-
- // Elastic collision between two point particles.
- // Recoil velocities are calculated by simultaneously solving:
- // m1v1 + m2v2 = m1v1' + m2v2' (momentum conservation)
- // and
- // m1 v1^2 + m2 v2^2 = m1 (v1')^2 + m2 (v2')^2 (energy conservation)
- //
- - collide:(int)i1:(int)i2
- {
- float newv1, newv2;
- float m1, m2, v2, v1;
-
-
- m1 = users[i1].mass;
- m2 = users[i2].mass;
-
- v1 = users[i1].v.x;
- v2 = users[i2].v.x;
-
- newv1 = v2 * 2.0 * m2 / (m2 + m1) - v1 * (m2 - m1) / (m2 + m1);
- newv2 = v2 * (m2 - m1) / (m2 + m1) + v1 * 2.0 * m1 / (m2 + m1);
-
- users[i1].v.x = newv1;
- users[i2].v.x = newv2;
-
- v1 = users[i1].v.y;
- v2 = users[i2].v.y;
-
- newv1 = v2 * 2.0 * m2 / (m2 + m1) - v1 * (m2 - m1) / (m2 + m1);
- newv2 = v2 * (m2 - m1) / (m2 + m1) + v1 * 2.0 * m1 / (m2 + m1);
-
- users[i1].v.y = newv1;
- users[i2].v.y = newv2;
-
- return self;
- }
-
-
- - move:(int)u
- {
- int i;
-
- // Take a step
- NXOffsetRect(&users[u].rect, users[u].v.x, users[u].v.y);
-
- // Check for Elastic Collisions
- for (i=0; i < numusers; ++i) {
- if (i == u) continue;
- if (!users[i].active) continue;
- if (NXIntersectsRect(&users[i].rect,&users[u].rect)) {
- NXOffsetRect(&users[u].rect, -1.0*users[u].v.x, -1.0*users[u].v.y);
- [self collide:i:u];
- NXOffsetRect(&users[u].rect, users[u].v.x, users[u].v.y);
- }
- }
-
-
- // Specular reflection from walls
- if ( (users[u].rect.origin.x <= bounds.origin.x)
- || ((users[u].rect.origin.x+users[u].rect.size.width) >= bounds.size.width) ) {
- NXOffsetRect(&users[u].rect, -2.0*users[u].v.x, 0.0);
- users[u].v.x *= -1.0;
- }
-
- if ( ((users[u].rect.origin.y-users[u].rect.size.height) <= bounds.origin.y)
- || (users[u].rect.origin.y >= bounds.size.height) ) {
- NXOffsetRect(&users[u].rect, 0.0, -2.0 * users[u].v.y);
- users[u].v.y *= -1.0;
- }
-
-
- return self;
- }
-
- - oneStep
- {
- int i;
- BStimeval CurrentTime;
- int checkIt=0;
-
- // Check for Mail if it's time
- CurrentTime = currentTimeInMs();
- if ((CurrentTime - LastTime) > TimeToCheck) {
- checkIt = 1;
- LastTime = CurrentTime;
- }
-
- for (i=0; i < numusers ; ++i) {
- if (!users[i].active) continue;
-
- // Erase last iteration
- [self eraseName:i];
-
- if (checkIt) [self checkMail:i];
-
- // Move as necessary
- [self move:i];
-
- [self drawName:i];
- }
-
- return self;
- }
-
- - eraseName: (int)u
- {
- PSsetgray(0.0);
- PSmoveto(users[u].rect.origin.x,users[u].rect.origin.y);
-
- [NameFont[(int)users[u].HasMail] set];
- PSshow(users[u].name);
-
- return self;
- }
-
- - drawName: (int) tag
- {
- // Set Color
- if (users[tag].HasMail) {
- if (BW) PSsetgray(users[tag].hue);
- else PSsethsbcolor(users[tag].hue, 1.0, 1.0);
- }
-
- else {
- PSsetgray(Gray);
- }
- [NameFont[(int)users[tag].HasMail] set];
-
- // Draw this iteration
- PSmoveto(users[tag].rect.origin.x,users[tag].rect.origin.y);
- PSshow(users[tag].name);
-
- return self;
- }
-
-
- - (const char *)windowTitle
- {
- return "MailWatch";
- }
-
- - drawSelf:(const NXRect *)rects :(int)rectCount
- {
- if (!rects || !rectCount) return self;
- PSsetgray(0);
- NXRectFill(rects);
- return self;
- }
-
- - sizeTo:(NXCoord)width :(NXCoord)height
- {
- [super sizeTo:width :height];
- [self initUsers];
- return self;
- }
-
- - initFrame:(const NXRect *)frameRect
- {
- int fontsize;
- static NXDefaultsVector MailWatchDefaults = {
- {"NameList", ""},
- {"MailDirectory", "/usr/spool/mail"},
- {"Gray", "0.3"},
- {"MaxMail", "100"},
- {"TimeToCheck", "30"},
- {"NoMailFont", "Times-Roman"},
- {"MailFont", "Times-Italic"},
- {"NoMailFontSize", "24"},
- {"MailFontSize", "24"},
- {"Time", "YES"},
- {"Date", "YES"},
- {"Day", "YES"},
- {"Host", "YES"},
- {"Energy", "10000"},
- {NULL} };
-
-
- [super initFrame:frameRect];
- [self allocateGState]; // For faster lock/unlockFocus
-
- // Load Defaults:
-
- NXRegisterDefaults("MailWatch", MailWatchDefaults);
-
- strncpy(NameList, NXGetDefaultValue("MailWatch", "NameList"), 1000);
-
- users[TIMETAG].active
- = (strcmp(NXGetDefaultValue("MailWatch","Time"),"YES") == 0);
- users[DAYTAG].active
- = (strcmp(NXGetDefaultValue("MailWatch","Day"),"YES") == 0);
- users[DATETAG].active
- = (strcmp(NXGetDefaultValue("MailWatch","Date"),"YES") == 0);
- users[HOSTTAG].active
- = (strcmp(NXGetDefaultValue("MailWatch","Host"),"YES") == 0);
-
-
- strncpy(MailDirectory, NXGetDefaultValue("MailWatch", "MailDirectory"), 100);
-
- Gray = atof(NXGetDefaultValue("MailWatch","Gray"));
- MaxMail = atoi(NXGetDefaultValue("MailWatch","MaxMail"));
-
- fontsize = atoi(NXGetDefaultValue("MailWatch", "MailFontSize"));
- NameFont[YESMAIL]
- = [Font newFont:NXGetDefaultValue("MailWatch", "MailFont")
- size:fontsize];
-
- fontsize = atoi(NXGetDefaultValue("MailWatch", "NoMailFontSize"));
- NameFont[NOMAIL]
- = [Font newFont:NXGetDefaultValue("MailWatch", "NoMailFont")
- size:fontsize];
-
- Energy = atoi(NXGetDefaultValue("MailWatch", "Energy"));
-
- TimeToCheck = 1000 * atoi(NXGetDefaultValue("MailWatch","TimeToCheck"));
- LastTime = 0;
-
- //
- [self setFlipped:YES];
-
- [inspectorPanel display];
-
- // Determine whether to use color or BW
- if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) BW = 1;
-
-
- return self;
- }
-
-
- - initUsers
- {
- char *pn, *un, name[30];
- BOOL done;
- int tag;
-
- numusers = 0;
- for (tag=0; tag < NAMETAGSTART; ++tag) {
- sprintf(name, "tag%d", tag);
- tag = [self addName:name];
- }
-
- pn = NameList;
- done = NO;
- while (!done) {
- while (*pn == ' ') ++pn;
- un = name;
- while(*pn != ' ') {
- if (*pn == 0) {
- done = YES;
- break;
- }
- *un++ = *pn++;
- }
- *un = 0;
- if (*name != 0) {
- tag = [self addName:name];
- if (tag < 0) return self;
- users[tag].active = YES;
- }
- }
-
- return self;
- }
-
-
- //- (BOOL) useBufferedWindow{ return YES;}
-
- - inspector:sender
- {
- char buf[500];
- int tag;
-
-
-
- if (!inspectorPanel) {
- // Load NIB
- [NXBundle
- getPath:buf
- forResource:"MailWatchView"
- ofType:"nib"
- inDirectory:[(BSThinker()) moduleDirectory:"MailWatch"]
- withVersion:0
- ];
-
- [NXApp
- loadNibFile:buf
- owner:self
- withNames:NO
- ];
-
- // Load Help
- if (helpPanel == nil) helpPanel = [NXHelpPanel new];
- sprintf(buf, "%s/English.lproj",
- [(BSThinker()) moduleDirectory:"MailWatch"]);
- [helpPanel addSupplement:"Help" inPath:buf];
-
-
- // Initialization
- // Settings Panel
- // Energy
- [EnergySlider setIntValue:(int)sqrt((double)Energy)];
- // Checking for Mail
- [MailDirectoryText setStringValue:MailDirectory];
- [TimeToCheckSlider setIntValue:(TimeToCheck/1000)];
- [TimeToCheckText setIntValue:(TimeToCheck/1000)];
- // Colors
- [GraySlider setFloatValue:Gray];
- sprintf(buf, "%3.1f", Gray);
- [GrayText setStringValue:buf];
- [MaxMailSlider setIntValue:MaxMail];
- [MaxMailText setIntValue:MaxMail];
-
- // NameList
- // NameBrowser
- [NameBrowser setDelegate:self];
- [NameBrowser setDoubleAction:@selector(browserChanged:)];
- [NameBrowser setTarget:self];
- // NameButtons
- for (tag=0; tag < NAMETAGSTART; ++tag) {
- [[NameButtons findCellWithTag:tag] setState:users[tag].active];
- }
-
- }
-
- return inspectorPanel;
- }
-
-
- - setEnergy:sender
- {
- char buf[10];
- int i;
- double Eold;
- double factor;
-
- Eold = Energy;
- Energy = [sender intValue] * [sender intValue];
-
- sprintf(buf, "%d", Energy);
- NXWriteDefault("MailWatch", "Energy", buf);
-
- factor = sqrt(Energy/Eold);
-
- for (i=0; i < numusers; ++i) {
- users[i].v.x *= factor;
- users[i].v.y *= factor;
- }
- return self;
- }
-
- - setTimeToCheck:sender
- {
- char buf[10];
- int Secs;
-
- Secs = [sender intValue];
- sprintf(buf, "%d", Secs);
- NXWriteDefault("MailWatch", "TimeToCheck", buf);
- [TimeToCheckSlider setIntValue:Secs];
- [TimeToCheckText setIntValue:Secs];
-
- TimeToCheck = Secs * 1000; /* in milliseconds */
-
- return self;
- }
-
- - clearNames
- {
- int i;
- id myView;
-
- [self lockFocus];
- myView = [(BSThinker()) backView];
- for (i=0; i < numusers; ++i) [myView eraseName:i];
- [self unlockFocus];
-
- return self;
- }
-
-
- - NameButtonsChanged:sender
- {
- id selectedButton;
- int tag;
- BOOL State;
-
- selectedButton = [sender selectedCell];
- State = [selectedButton state];
- tag = [selectedButton tag];
-
- users[tag].active = State;
-
- NXWriteDefault("MailWatch", [selectedButton title], State ? "YES" : "NO");
-
- [self clearNames];
-
- return self;
- }
-
- - browserChanged:sender
- {
- id cell;
- char title[20];
- int tag;
-
- cell = [sender selectedCell];
- strcpy(title, [cell stringValue]);
-
- tag = [self addName:title];
-
- if (tag < 0) return self;
-
- if (users[tag].active) {
- users[tag].active = NO;
- [cell setImage:[[NXImage findImageNamed:"CheckOff"] copy]];
- }
- else {
- users[tag].active = YES;
- [cell setImage:[[NXImage findImageNamed:"CheckOn"] copy]];
- }
-
- [sender displayAllColumns];
-
- *NameList = 0;
- for (tag=NAMETAGSTART; tag < numusers; ++tag)
- if (users[tag].active)
- sprintf(NameList, "%s %s", NameList, users[tag].name);
- NXWriteDefault("MailWatch", "NameList", NameList);
-
- // Don't leave shadows
- [self clearNames];
-
- return self;
- }
-
-
- - setMailDirectory:sender
- {
- strncpy(MailDirectory, [sender stringValue], 100);
- NXWriteDefault("MailWatch", "MailDirectory", MailDirectory);
- return self;
- }
-
- -(int)browser:sender fillMatrix:(id)matrix inColumn:(int)col
- {
- struct passwd *pwentry;
- int row;
- id newCell;
- int tag;
-
- if (!CheckOn || !CheckOff) [self initImages];
-
- setpwent();
- for (row=0; (pwentry = getpwent()) != NULL;) {
- if (!strcmp(pwentry->pw_name, "uucp")) continue;
- if (!strcmp(pwentry->pw_name, "nobody")) continue;
- if (!strcmp(pwentry->pw_name, "agent")) continue;
- if (!strcmp(pwentry->pw_name, "daemon")) continue;
- if (!strcmp(pwentry->pw_name, "sybase")) continue;
-
- [matrix addRow];
-
- newCell = [matrix cellAt:row:col];
-
- [newCell initTextCell:pwentry->pw_name];
- [newCell setLoaded:YES];
- [newCell setLeaf:YES];
-
- for (tag=NAMETAGSTART; tag < numusers; ++tag) {
- if (!strcmp(users[tag].name, pwentry->pw_name)) break;
- }
- if (tag != numusers)
- [newCell setImage:[[NXImage findImageNamed:"CheckOn"] copy]];
- else
- [newCell setImage:[[NXImage findImageNamed:"CheckOff"] copy]];
- ++row;
- }
- endpwent();
-
-
- return(row);
- }
-
- - initImages
- {
- CheckOn = [NXImage findImageNamed:"CheckOn"];
- CheckOff = [NXImage findImageNamed:"CheckOff"];
- return self;
-
- return self;
- }
-
- // Returns tag of name
- // Creating new entry if necessary
- - (int)addName:(char *)newName
- {
- BOOL bad;
- int j;
- double v, vx, vy;
- int tag;
-
- // Check to see if it already exists
- for (tag=0; tag < numusers; ++tag) {
- if (!strcmp(users[tag].name, newName)) return tag;
- }
-
- // Check to make sure we've got room
- if (numusers >= MAXU) return(-1);
-
- // Gotta create it
- // fprintf(stderr, "Creating Name %s\n", newName);
- strcpy(users[tag].name, newName);
-
- if (tag < NAMETAGSTART) {
- users[tag].HasMail = YES;
- if (tag == HOSTTAG) gethostname(users[HOSTTAG].name, NAMELEN);
- }
- else {
- users[tag].active = NO;
- }
-
- [self checkMail:tag];
-
- // Find an unoccupied place to put it:
- bad = YES;
- while (bad) {
- users[tag].rect.origin.x =
- randBetween(bounds.origin.x,
- bounds.size.width-users[tag].rect.size.width);
- users[tag].rect.origin.y =
- randBetween(bounds.origin.y+users[tag].rect.size.height,
- bounds.size.height-users[tag].rect.size.height);
-
- for (bad=NO,j=tag-1; j >= 0; --j) {
- if (NXIntersectsRect(&users[j].rect, &users[tag].rect))
- bad = YES;
- }
- }
-
- v = sqrt(2 * Energy / users[tag].mass);
-
- vx = randBetween(0, v);
- vy = sqrt (v*v - vx * vx);
-
- users[tag].v.x = vx;
- users[tag].v.y = vy;
-
- ++numusers;
-
- return tag;
-
- }
-
- - inspectorWillBeRemoved
- {
- if (SettingsPanel) [SettingsPanel orderOut:self];
- if (NameListInspector) [NameListInspector orderOut:self];
- if (InfoPanel) [InfoPanel orderOut:self];
- if (fontPanel) [fontPanel orderOut:self];
- if (helpPanel) [helpPanel orderOut:self];
-
- return self;
- }
-
- - helpPushed:sender
- {
- char HelpPath[MAXPATHLEN];
-
- [helpPanel makeKeyAndOrderFront:self];
-
- sprintf(HelpPath, "%s/English.lproj/Help/Overview.rtfd",
- [(BSThinker()) moduleDirectory:"MailWatch"]);
- [helpPanel showFile:HelpPath atMarker:NULL];
-
- return self;
- }
-
- - fontPushed:sender
- {
- if (fontManager == nil) fontManager = [FontManager new];
-
- [fontManager setSelFont:NameFont[(int)settingMailFont] isMultiple:NO];
-
- if (fontPanel == nil) {
- fontPanel = [fontManager getFontPanel:YES];
- [fontPanel setAccessoryView:fontPopUpView];
- }
-
- [fontPanel setDelegate:self];
- [fontPanel makeKeyAndOrderFront:self];
- return self;
- }
-
- - changeFont:sender
- {
- char buf1[20], buf2[20];
-
-
- [self clearNames];
- NameFont[(int)settingMailFont]
- = [fontManager convertFont:NameFont[(int)settingMailFont]];
-
- /* Either "MailFont" or "NoMailFont" */
- strcpy(buf1, [[fontPopUp findCellWithTag:(int)settingMailFont] title]);
- NXWriteDefault("MailWatch", buf1, [NameFont[(int)settingMailFont] name]);
-
- /* Make that "MailFontSize" or "NoMailFontSize" */
- strcat(buf1, "Size");
- sprintf(buf2, "%g", [NameFont[(int)settingMailFont] pointSize]);
- NXWriteDefault("MailWatch", buf1, buf2);
-
-
- return self;
- }
-
- - fontPopUpChanged:sender
- {
- settingMailFont = [[sender selectedCell] tag];
- [fontManager setSelFont:NameFont[(int)settingMailFont] isMultiple:NO];
-
- return self;
- }
-
- - setGray:sender
- {
- char buf[10];
-
- Gray = [sender floatValue];
-
- sprintf(buf, "%3.1f", Gray);
-
- [GrayText setStringValue:buf];
-
- NXWriteDefault("MailWatch", "Gray", buf);
-
- return self;
-
- }
-
- - setMaxMail:sender
- {
- char buf[30];
-
- MaxMail = [sender intValue];
-
- [MaxMailText setIntValue:MaxMail];
- sprintf(buf, "%d", MaxMail);
- NXWriteDefault("MailWatch", "MaxMail", buf);
-
- return self;
- }
-
- @end
-