Adding loads of neato registration stuff!
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Tue, 30 Sep 2003 01:48:31 +0000 (01:48 +0000)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Tue, 30 Sep 2003 01:48:31 +0000 (01:48 +0000)
14 files changed:
English.lproj/Localizable.strings
MTBlingController.h [new file with mode: 0755]
MTBlingController.m [new file with mode: 0755]
MTShizzleWindow.h [new file with mode: 0755]
MTShizzleWindow.m [new file with mode: 0755]
MTeSerialNumber.h [new file with mode: 0755]
MTeSerialNumber.m [new file with mode: 0755]
MainController.h
MainController.m
MenuController.h
MenuController.m
esellerate.gif [new file with mode: 0755]
libValidate.a [new file with mode: 0755]
validate.h [new file with mode: 0755]

index fc317b5..b501a3f 100755 (executable)
@@ -27,4 +27,9 @@ autolaunch_msg = "Would you like MenuTunes to automatically launch at login?";
 duplicateCombo = "Duplicate Key Combo";
 duplicateCombo_msg = "The specified key combo is already in use...";
 replace = "Replace";
-cancel = "Cancel";
\ No newline at end of file
+cancel = "Cancel";
+register = "Register MenuTunes...";
+validated_title = "Registration Successful";
+validated_msg = "Your license key has been validated and stored.  Thank you for your support.";
+failed_title = "Registration Failed";
+failed_msg = "Your license key could not be validated.  Be sure that the name you entered matches the license key.";
\ No newline at end of file
diff --git a/MTBlingController.h b/MTBlingController.h
new file mode 100755 (executable)
index 0000000..642bdc9
--- /dev/null
@@ -0,0 +1,33 @@
+//
+//  MTBlingController.h
+//  MenuTunes
+//
+//  Created by Matthew L. Judy on Tue Aug 19 2003.
+//  Copyright (c) 2003 NibFile.com. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "MTShizzleWindow.h"
+
+@interface MTBlingController : NSObject {
+
+    MTShizzleWindow *window;
+
+    int        checkDone;
+
+}
+
+
+- (void)showPanel;
+- (void)showPanelIfNeeded;
+
+- (void)goToTheStore:(id)sender;
+- (void)registerLater:(id)sender;
+- (void)verifyKey:(id)sender;
+
+- (int)checkKeyFile;
+- (int)checkDone;
+
+- (void)test:(id)sender;
+
+@end
diff --git a/MTBlingController.m b/MTBlingController.m
new file mode 100755 (executable)
index 0000000..bc20477
--- /dev/null
@@ -0,0 +1,146 @@
+//
+//  MTBlingController.m
+//  MenuTunes
+//
+//  Created by Matthew L. Judy on Tue Aug 19 2003.
+//  Copyright (c) 2003 iThink Software. All rights reserved.
+//
+
+#import "MTBlingController.h"
+#import "MTeSerialNumber.h"
+
+#define APP_SUPPORT_PATH_STRING [@"~/Library/Application Support/MenuTunes/" stringByExpandingTildeInPath]
+#define LICENSE_PATH_STRING [APP_SUPPORT_PATH_STRING stringByAppendingString:@"/.license"]
+
+
+@interface MTBlingController (Private)
+- (void)showPanel;
+@end
+
+
+@implementation MTBlingController
+
+
+- (void)_HEY {}
+- (void)_SUCKA {}
+- (void)_QUIT {}
+- (void)_HACKING {}
+- (void)_AND {}
+- (void)_GO {}
+- (void)_BUY {}
+- (void)_IT {}
+- (void)_YOU {}
+- (void)_TIGHTWAD {}
+
+- (id)init
+{
+    if ( ( self = [super init] ) ) {
+        checkDone = 0;
+    }
+    return self;
+}
+
+
+- (void)showPanel
+{
+    if ( ! window ) {
+        window = [MTShizzleWindow sharedWindowForSender:self];
+    }
+
+    [window center];
+    [window makeKeyAndOrderFront:nil];
+    [window setLevel:NSStatusWindowLevel];
+}
+
+- (void)showPanelIfNeeded
+{
+    if ( ! (checkDone == 2475) ) {
+        if ( ! ([self checkKeyFile] == 7465) ) {
+            [self showPanel];
+        } else {
+            checkDone = 2475;
+        }
+    }
+}
+
+- (void)goToTheStore:(id)sender
+{
+    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://store.eSellerate.net/s.asp?s=STR090894476"]];
+}
+
+- (void)registerLater:(id)sender
+{
+    [window orderOut:self];
+}
+
+- (void)verifyKey:(id)sender
+{
+    NSString *o = [window owner];
+    NSString *k = [window key];
+
+    MTeSerialNumber *s = [[[MTeSerialNumber alloc] initWithSerialNumber:k
+                                                                   name:o
+                                                                  extra:nil
+                                                              publisher:@"04611"] autorelease];
+    if ( [s isValid] == ITeSerialNumberIsValid && ( [[s infoDictionary] objectForKey:@"appIdentifier"] == @"MT" ) ) {
+    
+        NSFileManager *fm = [NSFileManager defaultManager];
+        
+        if ( ! [fm fileExistsAtPath:APP_SUPPORT_PATH_STRING] ) {
+            [fm createDirectoryAtPath:APP_SUPPORT_PATH_STRING attributes:nil];
+        }
+        
+        [[NSDictionary dictionaryWithObjectsAndKeys:
+            o, @"Owner",
+            k, @"Key",
+            nil] writeToFile:LICENSE_PATH_STRING atomically:YES];
+
+        checkDone = 2475;
+
+        NSBeginInformationalAlertSheet(NSLocalizedString(@"validated_title", @"Validated Title"),
+                                       @"Thank You!", nil, nil,
+                                       window,
+                                       self,
+                                       @selector(finishValidSheet:returnCode:contextInfo:),
+                                       nil,
+                                       nil,
+                                       NSLocalizedString(@"validated_msg", @"Validated Message"));
+
+    } else {
+    
+        NSBeginAlertSheet(NSLocalizedString(@"failed_title", @"Failed Title"),
+                          @"Try Again", nil, nil,
+                          window,
+                          self,
+                          nil, nil, nil,
+                          NSLocalizedString(@"failed_msg", @"Failed Message"));
+    }
+    
+}
+
+- (int)checkKeyFile
+{
+    NSString        *p = LICENSE_PATH_STRING;
+    MTeSerialNumber *k = [[[MTeSerialNumber alloc] initWithContentsOfFile:p
+                                                                    extra:@""
+                                                                publisher:@"04611"] autorelease];
+    if ( k && [k isValid] == ITeSerialNumberIsValid && ( [[k infoDictionary] objectForKey:@"appIdentifier"] == @"MT" )) {
+        return 7465;
+    } else {
+        [[NSFileManager defaultManager] removeFileAtPath:p handler:nil];
+        return 0;
+    }
+
+}
+
+- (int)checkDone
+{
+    return checkDone;
+}
+
+- (void)finishValidSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+    [window orderOut:self];
+}
+
+@end
diff --git a/MTShizzleWindow.h b/MTShizzleWindow.h
new file mode 100755 (executable)
index 0000000..ea1fac4
--- /dev/null
@@ -0,0 +1,18 @@
+#import <Cocoa/Cocoa.h>
+
+@interface MTShizzleWindow : NSWindow
+{
+    NSTextField *regMessage, *regBenefits, *enterInfo, *owner, *key;
+    NSTextField *ownerEntry, *keyEntry;
+    NSView *contentView;
+    NSBox *box;
+    NSButton *registerButton, *regLater, *verifyKey;
+    
+    id _sender;
+}
+
++ (id)sharedWindowForSender:(id)sender;
+- (NSString *)owner;
+- (NSString *)key;
+
+@end
\ No newline at end of file
diff --git a/MTShizzleWindow.m b/MTShizzleWindow.m
new file mode 100755 (executable)
index 0000000..b5241c8
--- /dev/null
@@ -0,0 +1,180 @@
+#import "MTShizzleWindow.h"
+
+@interface MTShizzleWindow (Private)
+- (void)setBling:(id)bling;
+- (void)buildWindow;
+- (void)setTargets;
+@end
+
+@implementation MTShizzleWindow
+
+static MTShizzleWindow *_privateSharedWindow = nil;
+
++ (id)sharedWindowForSender:(id)sender
+{
+    if( _privateSharedWindow ) {
+        [_privateSharedWindow setBling:sender];
+        return _privateSharedWindow;
+    } else {
+        _privateSharedWindow = [[MTShizzleWindow alloc]
+                        initWithContentRect:NSMakeRect(0, 0, 385, 353)
+                        styleMask:NSTitledWindowMask
+                        backing:NSBackingStoreBuffered
+                        defer:YES];
+        [_privateSharedWindow setBling:sender];
+        return _privateSharedWindow;
+    }
+}
+
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
+{
+    if ( (self = [super initWithContentRect:contentRect
+                        styleMask:styleMask
+                        backing:backingType
+                        defer:flag]) ) {
+        [self buildWindow];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [regMessage release];
+    [regBenefits release];
+    [enterInfo release];
+    [owner release];
+    [key release];
+    [ownerEntry release];
+    [keyEntry release];
+    [registerButton release];
+    [regLater release];
+    [verifyKey release];
+    [contentView release];
+    [box release];
+    [super dealloc];
+}
+
+- (void)setBling:(id)bling
+{
+    _sender = bling;
+    [self setTargets];
+}
+
+- (void)buildWindow
+{
+    unichar returnChar = '\r';
+    
+    [self setReleasedWhenClosed:NO];
+    [self setTitle:[NSString stringWithFormat:@"Register %@", @"MenuTunes"]];
+    contentView = [self contentView];
+    
+    regMessage = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 282, 345, 51)];
+    [regMessage setStringValue:[NSString stringWithFormat:@"%@ is shareware.  If you find it to be a valuable tool, please click the button below to buy your copy.  Your support is greatly appreciated.", @"MenuTunes"]];
+    [regMessage setBordered:NO];
+    [regMessage setBezeled:NO];
+    [regMessage setEditable:NO];
+    [regMessage setSelectable:NO];
+    [regMessage setDrawsBackground:NO];
+    [contentView addSubview:regMessage];
+    
+    //Make me gray!
+    box = [[NSBox alloc] initWithFrame:NSMakeRect(20, 181, 345, 81)];
+    [box setTitlePosition:NSNoTitle];
+    [box setBorderType:NSBezelBorder];
+    [contentView addSubview:box];
+    
+    //This isn't tall enough
+    registerButton = [[NSButton alloc] initWithFrame:NSMakeRect(24, 13, 115, 49)];
+    [registerButton setImage:[NSImage imageNamed:@"esellerate"]];
+    [registerButton setButtonType:NSMomentaryPushButton];
+    [registerButton setBezelStyle:NSRegularSquareBezelStyle];
+    [registerButton setTarget:_sender];
+    [registerButton setAction:@selector(goToTheStore:)];
+    [[box contentView] addSubview:registerButton];
+    
+    regBenefits = [[NSTextField alloc] initWithFrame:NSMakeRect(152, 16, 175, 42)];
+    [regBenefits setStringValue:[NSString stringWithUTF8String:"• Register instantly and easily.\n• Fast, secure transaction.\n• Major credit cards accepted."]];
+    [regBenefits setBordered:NO];
+    [regBenefits setBezeled:NO];
+    [regBenefits setEditable:NO];
+    [regBenefits setSelectable:NO];
+    [regBenefits setDrawsBackground:NO];
+    [regBenefits setFont:[NSFont fontWithName:@"Lucida Grande" size:11]];
+    [[box contentView] addSubview:regBenefits];
+    
+    enterInfo = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 148, 345, 17)];
+    [enterInfo setStringValue:@"Please enter your registration information below."];
+    [enterInfo setBordered:NO];
+    [enterInfo setBezeled:NO];
+    [enterInfo setEditable:NO];
+    [enterInfo setSelectable:NO];
+    [enterInfo setDrawsBackground:NO];
+    [enterInfo setFont:[NSFont fontWithName:@"Lucida Grande" size:13]];
+    [contentView addSubview:enterInfo];
+    
+    owner = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 126, 345, 14)];
+    [owner setStringValue:@"License Owner:"];
+    [owner setBordered:NO];
+    [owner setBezeled:NO];
+    [owner setEditable:NO];
+    [owner setSelectable:NO];
+    [owner setDrawsBackground:NO];
+    [owner setFont:[NSFont fontWithName:@"Lucida Grande" size:11]];
+    [contentView addSubview:owner];
+    
+    key = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 82, 345, 14)];
+    [key setStringValue:@"License Key:"];
+    [key setBordered:NO];
+    [key setBezeled:NO];
+    [key setEditable:NO];
+    [key setSelectable:NO];
+    [key setDrawsBackground:NO];
+    [key setFont:[NSFont fontWithName:@"Lucida Grande" size:11]];
+    [contentView addSubview:key];
+    
+    ownerEntry = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 104, 345, 22)];
+    [ownerEntry setTarget:_sender];
+    [ownerEntry setAction:@selector(verifyKey:)];
+    [contentView addSubview:ownerEntry];
+    
+    keyEntry = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 60, 345, 22)];
+    [keyEntry setTarget:_sender];
+    [keyEntry setAction:@selector(verifyKey:)];
+    [contentView addSubview:keyEntry];
+    
+    regLater = [[NSButton alloc] initWithFrame:NSMakeRect(138, 16, 116, 25)];
+    [regLater setTitle:@"Register Later"];
+    [regLater setTarget:_sender];
+    [regLater setAction:@selector(registerLater:)];
+    [regLater setBezelStyle:NSRoundedBezelStyle];
+    [contentView addSubview:regLater];
+    
+    verifyKey = [[NSButton alloc] initWithFrame:NSMakeRect(255, 16, 116, 25)];
+    [verifyKey setTitle:@"Verify Key"];
+    [verifyKey setTarget:_sender];
+    [verifyKey setAction:@selector(verifyKey:)];
+    [verifyKey setBezelStyle:NSRoundedBezelStyle];
+    [verifyKey setKeyEquivalent:[NSString stringWithCharacters:&returnChar length:1]];
+    [contentView addSubview:verifyKey];
+}
+
+- (void)setTargets
+{
+    [registerButton setTarget:_sender];
+    [ownerEntry setTarget:_sender];
+    [keyEntry setTarget:_sender];
+    [regLater setTarget:_sender];
+    [verifyKey setTarget:_sender];
+}
+
+- (NSString *)owner
+{
+    return [ownerEntry stringValue];
+}
+
+- (NSString *)key
+{
+    return [keyEntry stringValue];
+}
+
+@end
diff --git a/MTeSerialNumber.h b/MTeSerialNumber.h
new file mode 100755 (executable)
index 0000000..3529dea
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *     MenuTunes
+ *  MTeSerialNumber
+ *    Object which represents, and operates on,
+ *    an eSellerate serial number.
+ *
+ *  Original Author : Matt Judy <mjudy@ithinksw.com>
+ *   Responsibility : Matt Judy <mjudy@ithinksw.com>
+ *
+ *  Copyright (c) 2003 iThink Software.
+ *  All Rights Reserved
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+
+typedef enum {
+    ITeSerialNumberIsDead    = -1 ,
+    ITeSerialNumberIsInvalid =  0 ,
+    ITeSerialNumberIsValid   =  1
+} MTeSerialNumberValidationResult;
+
+typedef enum {
+    ITeSerialNumberWillNotExpire = -1 ,
+    ITeSerialNumberHasExpired    =  0 ,
+    ITeSerialNumberWillExpire    =  1
+} MTeSerialNumberExpirationResult;
+
+
+@interface MTeSerialNumber : NSObject {
+    NSString *_serialNumber;
+    NSString *_nameBasedKey;
+    NSString *_extraDataKey;
+    NSString *_publisherKey;
+
+    NSArray *_deadSerials;
+}
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark INITIALIZATION METHODS
+/*************************************************************************/
+
+/*!
+    @method initWithSerialNumber:name:extra:publisher:
+    @abstract Creates an ITeSerialNumber with the information provided.
+    @discussion This is the designated initializer for this class.
+    @param serial The eSellerate serial number
+    @param name The name-based key for the serial number
+    @param extra This is present for future use.  eSellerate does not use this data yet.  Pass nil.
+    @param publisher The publisher key, provided by the Serial Number management part of eSellerate.
+    @result The newly initialized object.
+*/
+- (id)initWithSerialNumber:(NSString *)serial
+                      name:(NSString *)name
+                     extra:(NSString *)extra  // Extra data not used.  Pass nil.
+                 publisher:(NSString *)publisher;
+
+/*!
+    @method initWithDictionary:
+    @abstract Creates an ITeSerialNumber with the information provided in dictionary form
+    @discussion Utilizes initWithSerialNumber:name:extra:publisher:
+    @param dict Consists of 4 keys, and 4 NSStrings.  The keys must be named 
+                "Key", "Owner", "Extra", and "Publisher".
+    @result The newly initialized object.
+*/
+- (id)initWithDictionary:(NSDictionary *)dict;
+
+/*!
+    @method initWithContentsOfFile:extra:publisher:
+    @abstract Creates an ITeSerialNumber from the combination of a plist, and arguments.
+    @discussion Only the serial (Key) and name (Owner) should ever be stored in the plist,
+                for security.  This method will ignore any other data present in the file.
+    @param path Path to the file on disk.  This file must be a plist containing one dictionary.
+    @param extra eSellerate extra data.  Currently unused by eSellerate.  Pass nil.
+    @param publisher The publisher key, provided by the Serial Number management part of eSellerate.
+    @result The newly initialized object.
+*/
+- (id)initWithContentsOfFile:(NSString *)path
+                       extra:(NSString *)extra
+                   publisher:(NSString *)publisher;
+
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark ACCESSOR METHODS
+/*************************************************************************/
+
+- (NSString *)serialNumber;
+- (void)setSerialNumber:(NSString *)newSerial;
+
+- (NSString *)nameBasedKey;
+- (void)setNameBasedKey:(NSString *)newName;
+
+- (NSString *)extraDataKey;
+- (void)setExtraDataKey:(NSString *)newData;
+
+- (NSString *)publisherKey;
+- (void)setPublisherKey:(NSString *)newPublisher;
+
+- (NSArray *)deadSerials;
+- (void)setDeadSerials:(NSArray *)newList;
+
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark INSTANCE METHODS
+/*************************************************************************/
+
+/*!
+    @method isValid
+    @abstract Checks the current serial for validity.
+    @result ITeSerialNumberValidationResult, based on the current serial's validity.
+*/
+- (MTeSerialNumberValidationResult)isValid;
+
+/*!
+    @method isExpired
+    @abstract Tests for validity, and returns whether or not the
+              serial is expired, or will expire.
+    @result YES if the serial will expire, NO if it will not.
+*/
+- (MTeSerialNumberExpirationResult)isExpired;
+
+- (NSDate *)storedDate;
+
+- (NSTimeInterval)secondsRemaining;
+
+- (NSDictionary *)infoDictionary;
+
+@end
diff --git a/MTeSerialNumber.m b/MTeSerialNumber.m
new file mode 100755 (executable)
index 0000000..9d8da42
--- /dev/null
@@ -0,0 +1,239 @@
+#import "MTeSerialNumber.h"
+#import "validate.h"
+
+
+@interface MTeSerialNumber (Private)
+- (short)validate;
+- (eSellerate_String)eSellerateStringForString:(NSString *)string;
+@end
+
+@implementation MTeSerialNumber
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark INITIALIZATION METHODS
+/*************************************************************************/
+
+- (id)initWithSerialNumber:(NSString *)serial
+                      name:(NSString *)name
+                     extra:(NSString *)extra
+                 publisher:(NSString *)publisher
+{
+    if ( self = [super init] ) {
+        _serialNumber = serial;
+        _nameBasedKey = name;
+        _extraDataKey = nil;       //extra data is currently unused.
+        _publisherKey = publisher;
+        _deadSerials  = nil;
+    }
+    return self;
+}
+
+- (id)initWithDictionary:(NSDictionary *)dict
+{
+    return [self initWithSerialNumber:[dict objectForKey:@"Key"]
+                                 name:[dict objectForKey:@"Owner"]
+                                extra:[dict objectForKey:@"Extra"]
+                            publisher:[dict objectForKey:@"Publisher"]];
+}
+
+- (id)initWithContentsOfFile:(NSString *)path
+                       extra:(NSString *)extra
+                   publisher:(NSString *)publisher
+{
+    NSDictionary *fileDict = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease];
+    
+    if ( fileDict ) {
+        NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
+
+        [dict setObject:[fileDict objectForKey:@"Key"] forKey:@"Key"];
+        [dict setObject:[fileDict objectForKey:@"Owner"] forKey:@"Owner"];
+        [dict setObject:extra forKey:@"Extra"];
+        [dict setObject:publisher forKey:@"Publisher"];
+
+        return [self initWithDictionary:dict];
+    } else {
+        return nil;
+    }
+}
+
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark ACCESSOR METHODS
+/*************************************************************************/
+
+- (NSString *)serialNumber
+{
+    return _serialNumber;
+}
+
+- (void)setSerialNumber:(NSString *)newSerial
+{
+    [_serialNumber autorelease];
+    _serialNumber = [newSerial copy];
+}
+
+- (NSString *)nameBasedKey
+{
+    return _nameBasedKey;
+}
+
+- (void)setNameBasedKey:(NSString *)newName
+{
+    [_nameBasedKey autorelease];
+    _nameBasedKey = [newName copy];
+}
+
+- (NSString *)extraDataKey
+{
+    return _extraDataKey;
+}
+
+- (void)setExtraDataKey:(NSString *)newData
+{
+    [_extraDataKey autorelease];
+    _extraDataKey = [newData copy];
+}
+
+- (NSString *)publisherKey
+{
+    return _publisherKey;
+}
+
+- (void)setPublisherKey:(NSString *)newPublisher
+{
+    [_publisherKey autorelease];
+    _publisherKey = [newPublisher copy];
+}
+
+- (NSArray *)deadSerials
+{
+    return _deadSerials;
+}
+
+- (void)setDeadSerials:(NSArray *)newList
+{
+    [_deadSerials autorelease];
+    _deadSerials = [newList copy];
+}
+
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark INSTANCE METHODS
+/*************************************************************************/
+
+- (MTeSerialNumberValidationResult)isValid
+{
+    if ( _serialNumber ) {
+
+        BOOL dead = NO;
+        
+        if ( [_deadSerials count] )  {
+            NSEnumerator *deadEnum = [_deadSerials objectEnumerator];
+            id            aDeadSerial;
+            
+            while ( aDeadSerial = [deadEnum nextObject] ) {
+                if ( [aDeadSerial isEqualToString:_serialNumber] ) {
+                    dead = YES;
+               }
+            }
+        }
+
+        if ( dead ) {
+            return ITeSerialNumberIsDead;
+        } else {
+            return ( ( [self validate] > 0 ) ? ITeSerialNumberIsValid : ITeSerialNumberIsInvalid );
+        }
+    } else {
+        return nil;
+    }
+}
+
+- (MTeSerialNumberExpirationResult)isExpired;
+{
+    return ( ! [self secondsRemaining] > 0 );
+}
+
+- (NSDate *)storedDate
+{
+    NSCalendarDate *refDate = [NSCalendarDate dateWithYear:2000 month:1 day:1
+                                                      hour:0 minute:0 second:0
+                                                  timeZone:[NSTimeZone systemTimeZone]];
+
+    NSTimeInterval secondsFromRefToExp = ([self validate] * 86400);
+
+    return [[[NSDate alloc] initWithTimeInterval:secondsFromRefToExp
+                                       sinceDate:refDate] autorelease];
+}
+
+- (NSTimeInterval)secondsRemaining
+{
+    return [[self storedDate] timeIntervalSinceDate:[NSDate date]];
+}
+
+- (NSDictionary *)infoDictionary
+{
+    NSString *prefix        = [[_serialNumber componentsSeparatedByString:@"-"] objectAtIndex:0];
+    NSString *appIdentifier = nil;
+    NSString *version       = nil;
+    NSString *typeCode      = nil;
+    NSString *quantity      = nil;
+    
+    if ( ( [prefix length] == 10 ) || ( [prefix length] == 7 ) ) {
+        appIdentifier = [_serialNumber substringWithRange:NSMakeRange(0,2)];
+        version       = [_serialNumber substringWithRange:NSMakeRange(2,3)];
+        typeCode      = [_serialNumber substringWithRange:NSMakeRange(5,2)];
+    } else {
+        return nil;
+    }
+
+    if ( [prefix length] == 10 ) {
+        quantity = [_serialNumber substringWithRange:NSMakeRange(7,3)];
+    }
+
+    return [NSDictionary dictionaryWithObjectsAndKeys:
+        appIdentifier, @"appIdentifier",
+        version,       @"version",
+        typeCode,      @"typeCode",
+        quantity,      @"quantity",   nil];
+}
+
+
+/*************************************************************************/
+#pragma mark -
+#pragma mark PRIVATE IMPLEMENTATIONS
+/*************************************************************************/
+
+- (short)validate
+{
+    eSellerate_String pSerial    = [self eSellerateStringForString:_serialNumber];
+    eSellerate_String pName      = [self eSellerateStringForString:_nameBasedKey];
+    eSellerate_String pExtraData = [self eSellerateStringForString:_extraDataKey];
+    eSellerate_String pPublisher = [self eSellerateStringForString:_publisherKey];
+    
+    return eSellerate_ValidateSerialNumber(pSerial,
+                                           pName,
+                                           pExtraData,
+                                           pPublisher);
+}
+
+- (eSellerate_String)eSellerateStringForString:(NSString *)string
+{
+    if ( string ) {
+        NSMutableData *buffer = [[[NSMutableData alloc] initWithCapacity:256] autorelease];
+        
+        CFStringGetPascalString( (CFStringRef)string,
+                                 [buffer mutableBytes],
+                                 256,
+                                 CFStringGetSystemEncoding());
+                                 
+        return (eSellerate_String)[buffer bytes];
+    } else {
+        return nil;
+    }
+}
+
+
+@end
index 6383a8d..c6fd5f3 100755 (executable)
@@ -17,6 +17,7 @@
 #import <ITKit/ITKit.h>
 #import <ITFoundation/ITFoundation.h>
 #import <ITMTRemote/ITMTRemote.h>
+#import "MTBlingController.h"
 
 @class StatusWindowController, MenuController;
 
     StatusWindowController *statusWindowController; //Shows status windows
     MenuController *menuController;
     NSUserDefaults *df;
+    
+    NSDate *blingDate;
+    MTBlingController *bling;
 }
 + (MainController *)sharedController;
 
 - (void)menuClicked;
 
 //Methods called from MenuController by menu items
+- (void)blingTime;
+- (void)blingNow;
+- (BOOL)blingBling;
+
 - (void)playPause;
 - (void)nextSong;
 - (void)prevSong;
index a480e3b..06ae1d9 100755 (executable)
@@ -50,6 +50,9 @@ static MainController *sharedController;
         SetITDebugMode(YES);
     }
     
+    bling = [[MTBlingController alloc] init];
+    blingDate = nil;
+    
     currentRemote = [self loadRemote];
     [currentRemote begin];
     
@@ -142,6 +145,32 @@ static MainController *sharedController;
     [pool release];
 }*/
 
+- (void)blingTime
+{
+    NSDate *now = [NSDate date];
+    if ( (! blingDate) || ([now timeIntervalSinceDate:blingDate] >= 86400) ) {
+        [bling showPanelIfNeeded];
+        [blingDate autorelease];
+        blingDate = [now retain];
+    }
+}
+
+- (void)blingNow
+{
+    [bling showPanel];
+    [blingDate autorelease];
+    blingDate = [[NSDate date] retain];
+}
+
+- (BOOL)blingBling
+{
+    if ( ! ([bling checkDone] == 2475) ) {
+        return NO;
+    } else {
+        return YES;
+    }
+}
+
 - (BOOL)songIsPlaying
 {
     return ( ! ([[currentRemote playerStateUniqueIdentifier] isEqualToString:@"0-0"]) );
@@ -688,6 +717,7 @@ static MainController *sharedController;
 - (void)dealloc
 {
     [self applicationTerminated:nil];
+    [bling release];
     [statusItem release];
     [statusWindowController release];
     [menuController release];
index a3da9e5..55ae240 100755 (executable)
@@ -35,7 +35,8 @@ typedef enum {
     MTMenuNextTrackItem,
     MTMenuShowPlayerItem,
     MTMenuPreferencesItem,
-    MTMenuQuitItem
+    MTMenuQuitItem,
+    MTMenuRegisterItem
 } MTMenuItemTag;
 
 @interface MenuController : NSObject
index 332e7f8..f57f331 100755 (executable)
                     keyEquivalent:@""];
             [tempItem setTag:MTMenuQuitItem];
             [tempItem setTarget:self];
+            if ([[MainController sharedController] blingBling] == NO) {
+                ITDebugLog(@"Add \"Register MenuTunes...\" menu item.");
+                tempItem = [menu addItemWithTitle:NSLocalizedString(@"register", @"Register MenuTunes...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
+                [tempItem setTag:MTMenuRegisterItem];
+                [tempItem setTarget:self];
+            }
         } else if ([nextObject isEqualToString:@"trackInfo"]) {
             ITDebugLog(@"Check to see if a Track is playing...");
             //Handle playing radio too
     tempItem = [menu addItemWithTitle:NSLocalizedString(@"preferences", @"Preferences...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
     [tempItem setTag:MTMenuPreferencesItem];
     [tempItem setTarget:self];
+    if ([[MainController sharedController] blingBling] == NO) {
+        ITDebugLog(@"Add \"Register MenuTunes...\" menu item.");
+        tempItem = [menu addItemWithTitle:NSLocalizedString(@"register", @"Register MenuTunes...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
+        [tempItem setTag:MTMenuRegisterItem];
+        [tempItem setTarget:self];
+    }
     ITDebugLog(@"Add \"Quit\" menu item.");
     tempItem = [menu addItemWithTitle:NSLocalizedString(@"quit", @"Quit") action:@selector(performMainMenuAction:) keyEquivalent:@""];
     [tempItem setTag:MTMenuQuitItem];
             ITDebugLog(@"Performing Menu Action: Quit");
             [[MainController sharedController] quitMenuTunes];
             break;
+        case MTMenuRegisterItem:
+            ITDebugLog(@"Performing Menu Action: Register");
+            [[MainController sharedController] blingNow];
+            break;
         default:
             ITDebugLog(@"Performing Menu Action: Unimplemented Menu Item OR Child-bearing Menu Item");
             break;
diff --git a/esellerate.gif b/esellerate.gif
new file mode 100755 (executable)
index 0000000..5b5c5d9
Binary files /dev/null and b/esellerate.gif differ
diff --git a/libValidate.a b/libValidate.a
new file mode 100755 (executable)
index 0000000..344ebc5
Binary files /dev/null and b/libValidate.a differ
diff --git a/validate.h b/validate.h
new file mode 100755 (executable)
index 0000000..4e5f639
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+ *validate.h\r
+ *   Copyright 2000-2002, eSellerate Inc.\r
+ *   All rights reserved worldwide.\r
+ */\r
+\r
+#ifndef _VALIDATE_API_H_\r
+#define _VALIDATE_API_H_\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+typedef unsigned char* eSellerate_String;\r
+\r
+typedef short eSellerate_DaysSince2000;\r
+\r
+eSellerate_DaysSince2000 eSellerate_ValidateSerialNumber (\r
+  eSellerate_String serialNumber, /* ASCII Pascal string                   */\r
+  eSellerate_String nameBasedKey, /* ASCII Pascal string (nil if unneeded) */\r
+  eSellerate_String extraDataKey, /* ASCII Pascal string (nil if unneeded) */\r
+  eSellerate_String publisherKey  /* ASCII Pascal string (nil if unneeded) */\r
+);\r
+/*\r
+ * return codes:\r
+ *   if valid: date (days since January 1 2000) of expiration or (non-expiring) purchase\r
+ *   if invalid: 0\r
+ */\r
+\r
+eSellerate_DaysSince2000 eSellerate_Today ( ); /* days from 1/1/2000 to today */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif
\ No newline at end of file