This is FoneTones.m in view mode; [Download] [Up]
#import "FoneTones.h"
#import "FoneTonesConstants.h"
#import <appkit/appkit.h>
#import <strings.h>
#import <soundkit/soundkit.h>
#import <drivers/event_status_driver.h>
const char *knownFoneTones[] = {
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "splat", "pound", NULL
};
static char *handlerList[] = {
"dialnumber",
// "remembernumber",
// "forgetnumber",
// "NUMBERSSTARTINGWITH",
// "ALLPHONENUMBERS",
// "PHONEBOOK",
// "PHONEBOOKS",
// "switchtobook",
// "speeddialing",
"preloadtones",
// "phonebookeditor",
"CURRENTVOLUME",
"setcurrentvolume",
"ft_version",
NULL
};
static struct mach_header *loadHeader = NULL;
static NXEventHandle ourEventStatusHandle;
@implementation FoneTones : XModule
- init
{
[super init];
// Do your stuff here...
foneTonesAreLoaded = NO;
ourEventStatusHandle = NXOpenEventStatus();
return ( self );
}
- free
{
// Do your stuff here...
return ( [super free] );
}
+ (const char *)moduleName
{
return ( "FoneTones" );
}
+ (const char **)xCmdsAndFcns
{
return ( handlerList );
}
- prepareToExecuteHandlers
{
// [self loadInterfaceData];
return ( self );
}
- executeHandler:(NXAtom)handlerName
{
if (!strcmp(handlerName, "dialnumber")) {
return ( [self dial] );
} else if (!strcmp(handlerName, "remembernumber")) {
//return ( [self rememberNumber] );
return ( [[self getEmptyContainer]
setString:"rememberNumber command, not implemented yet."] );
} else if (!strcmp(handlerName, "forgetnumber")) {
// return ( [self forgetNumber] );
return ( [[self getEmptyContainer]
setString:"forgetNumber command, not implemented yet."] );
} else if (!strcmp(handlerName, "NUMBERSSTARTINGWITH")) {
// return ( [self numbersStartingWith] );
return ( [[self getEmptyContainer]
setString:"forgetNumber command, not implemented yet."] );
} else if (!strcmp(handlerName, "ALLPHONENUMBERS")) {
// return ( [self allPhoneNumbers] );
return ( [[self getEmptyContainer]
setString:"forgetNumber command, not implemented yet."] );
} else if (!strcmp(handlerName, "PHONEBOOK")) {
// return ( [self phoneBook] );
return ( [[self getEmptyContainer]
setString:"phoneBook command, not implemented yet."] );
} else if (!strcmp(handlerName, "PHONEBOOKS")) {
// return ( [self phoneBooks] );
return ( [[self getEmptyContainer]
setString:"phoneBooks command, not implemented yet."] );
} else if (!strcmp(handlerName, "switchtobook")) {
// return ( [self switchToBook] );
return ( [[self getEmptyContainer]
setString:"switchToBook command, not implemented yet."] );
} else if (!strcmp(handlerName, "speeddialing")) {
// return ( [self speedDialing] );
return ( [[self getEmptyContainer]
setString:"speedDialing command, not implemented yet."] );
} else if (!strcmp(handlerName, "preloadtones")) {
return ( [self preloadTones] );
} else if (!strcmp(handlerName, "phonebookeditor")) {
// return ( [self phoneBookEditor] );
return ( [[self getEmptyContainer]
setString:"phoneBookEditor command, not implemented yet."] );
} else if (!strcmp(handlerName, "ft_version")) {
return ( [self ft_version] );
} else if (!strcmp(handlerName, "setcurrentvolume")) {
return ( [self setCurrentVolume] );
} else if (!strcmp(handlerName, "CURRENTVOLUME")) {
return ( [self currentVolume] );
} else return ( nil ); // handlerName not recognized!
}
+ finishLoading:(struct mach_header *)header
{
loadHeader = header; // Save this for later use
return ( self );
}
- loadInterfaceData
{
//[NXApp loadNibSection:"MyXModule.nib" owner:self
// withNames:NO fromHeader:loadHeader] )
return ( self );
}
///
// FoneTones XModule Specific Methods
///
- dial
{
int pCount = [self paramCount];
char phoneNumber[256] = ""; // Hopefully enough space.
char *pnIndex;
Sound *sndObj = nil;
float approxTimeToPlay;
if ( pCount != 1 ) {
return ( [[self getEmptyContainer]
setString:"Usage: dial <phoneNumber>"] );
}
if ( !foneTonesAreLoaded ) [self preloadTones:self];
pnIndex = strncpy(phoneNumber, [[self getParam:1] stringVal], 255);
if ( !pnIndex || !*pnIndex ) return ( self );
// If we don't have a sound to pile tones into, then create one.
if ( ![Sound findSoundFor:"numberToPlay"] ) {
[Sound addName:"numberToPlay" sound:[[Sound alloc] init]];
}
// Go and remove all the junk!, anything but numbers, letters, and '*' or '#'
while ( *pnIndex ) {
if ( index("#", *pnIndex) ) sndObj = [Sound findSoundFor:"pound_tone"];
else if ( index("*", *pnIndex) ) sndObj = [Sound findSoundFor:"splat_tone"];
else if ( index("1", *pnIndex) ) sndObj = [Sound findSoundFor:"one_tone"];
else if ( index("2abcABC", *pnIndex) ) sndObj = [Sound findSoundFor:"two_tone"];
else if ( index("3defDEF", *pnIndex) ) sndObj = [Sound findSoundFor:"three_tone"];
else if ( index("4ghiGHI", *pnIndex) ) sndObj = [Sound findSoundFor:"four_tone"];
else if ( index("5jklJKL", *pnIndex) ) sndObj = [Sound findSoundFor:"five_tone"];
else if ( index("6mnoMNO", *pnIndex) ) sndObj = [Sound findSoundFor:"six_tone"];
else if ( index("7prsPRS", *pnIndex) ) sndObj = [Sound findSoundFor:"seven_tone"];
else if ( index("8tuvTUV", *pnIndex) ) sndObj = [Sound findSoundFor:"eight_tone"];
else if ( index("9wxyWXY", *pnIndex) ) sndObj = [Sound findSoundFor:"nine_tone"];
else if ( index("0qzQZ", *pnIndex) ) sndObj = [Sound findSoundFor:"zero_tone"];
else sndObj = nil;
if (( sndObj != nil ) && [[Sound findSoundFor:"numberToPlay"] compatibleWith:sndObj]) {
[[Sound findSoundFor:"numberToPlay"] compactSamples];
[[Sound findSoundFor:"numberToPlay"] insertSamples:sndObj
at:[[Sound findSoundFor:"numberToPlay"] dataSize]];
}
pnIndex++;
}
[[Sound findSoundFor:"numberToPlay"] compactSamples]; // Ensure no fragmentation.
approxTimeToPlay = [[Sound findSoundFor:"numberToPlay"] duration];
[[Sound findSoundFor:"numberToPlay"] play]; // Jam the sound out to the speaker.
[[Sound findSoundFor:"numberToPlay"] deleteSamples]; // Get ready for next use?
[[Sound findSoundFor:"numberToPlay"] compactSamples]; // Why not, just to clean up.
return ( [[self getEmptyContainer] setFloat:approxTimeToPlay] );
}
// Add a number to the current fonebook.
- rememberNumber
{
return ( self );
}
// Given a key, this method will remove the key-value association
// from the current fone book. If the key doesn't exist, then
// nothing happens.
- forgetNumber
{
return ( self );
}
// This puppy returns all the numbers starting with the letters
// in the parameter string passed to this function.
- numbersStartingWith
{
return ( self );
}
// Returns a line delimited list of all the keys and associated
// phone numbers to go along with them.
- allPhoneNumbers
{
return ( self );
}
// Return the name of the current fone book.
- phoneBook
{
return ( self );
}
// Return the names of all the fone books located in...
//
// ~/Library/FoneBooks
// /Library/FoneBooks
// /NextLibrary/FoneBooks
//
// directories.
- phoneBooks
{
return ( self );
}
// Switch from one fone book to another.
- switchToBook
{
return ( self );
}
// Don't know if I am going to bother with this one. After Doug
// and I talked about it, it would seem that most phones will allow
// take speed dialing. So for now, this function isn't worth working
// on.
- speedDialing
{
return ( self );
}
// Used to avoid any delay loading of tones may cause.
- preloadTones:sender
{
char **kftIndex = knownFoneTones;
char sndName[256];
if ( foneTonesAreLoaded ) {
if ( sender == nil ) { // Caller was HS
return ( [[self getEmptyContainer] setString:"Tones already loaded."] );
} else return ( self );
}
while ( *kftIndex ) { // Loop until we don't have anymore to load.
sprintf(sndName, "%s%s", *kftIndex, "_tone");
if ( ![Sound findSoundFor:sndName] ) {
NXLogError("%s Error -- preloadTones: Could not load the"
" sound file %s.\n", [[self class] name], sndName);
}
kftIndex++; // Point to next string.
}
foneTonesAreLoaded = TRUE;
if ( sender == nil ) {
return ( [[self getEmptyContainer]
setString:"Tones successfully loaded."] );
}
return ( self );
}
// Front to calling the real preloadTones: function.
- preloadTones
{
return ( [self preloadTones:nil] );
}
// At some time in the future, it would be nice to have a graphical
// front end to the current fone book. I figure a nice association
// of keys and values in a DBTableView would work. But hey, this
// is something for the future.
- phoneBookEditor
{
return ( self );
}
///
// FoneTones XModule Support Methods
///
#define MAXKEYSIZE (30)
#define MAXVALUESIZE (50)
// This puppy will create a new book if specified book doesn't exist.
// It will be created in the ~/Library/FoneBooks directory. Only place
// we for sure can create directories/files.
- (HashTable *)loadPhoneBook:(const char *)newBookName
{
// id newFoneBook;
BOOL successfullyLoadedNewBook;
// char bookPathBuff[MAXPATHLEN + 1];
const char *defaultPath = NULL;
NXStream *fonebookStream;
NXStringTable *newStringTable;
char currKey[MAXKEYSIZE],
currValue[MAXVALUESIZE];
// Determine if we are to load the default fone book, or one specified.
if ( !newBookName && !*newBookName ) { // Go and try to load the defaults...
newBookName = NXReadDefault("FoneTonesXModule", "StartupFoneBook");
if ( !defaultPath && !*defaultPath ) {
NXLogError("%s Error -- loadPhoneBook:: default fone book was not specified"
" in the user's defaults data.\n", [[self class] name]);
return ( (HashTable *)nil );
}
}
// Attempt to get a stream open to the fone book.
fonebookStream = NXMapFile(newBookName, NX_READONLY);
if ( fonebookStream == NULL ) {
NXLogError("%s Error -- loadPhoneBook:: could not get a stream open to the"
" defaults file specified (%s)\n", [[self class] name], newBookName);
return ( nil );
}
// Well, now we have to create a table, and go and parse the file...
// File format (for convenience of user so they can use a text
// processor [non-rtf] to define a phone book.
newStringTable = [[NXStringTable alloc] init];
NXScanf(fonebookStream, "%MAXKEYSIZEs\t%MAXVALUESIZEs\n", currKey, currValue);
if ( successfullyLoadedNewBook ) {
}
return ( newStringTable );
}
- ft_version
{
id version;
version = [[ self getEmptyContainer ] setString:"r" ];
[ version appendString:FT_RELEASE ];
[ version appendString:" v" ];
[ version appendString:FT_VERSION ];
[ version appendString:" " ];
[ version appendString:FT_RELTIME ];
[ version appendString:"\n" ];
[ version appendString:FT_COPYRIGHT ];
return ( version );
}
/////////////////////
// Volume Functions
/////////////////////
- setCurrentVolume
{
int pCount = [ self paramCount ];
float newVolume;
if (( pCount != 1 ) || ( !([[ self getParam:1 ] validAsNumber ]) )) {
return ( [[ self getEmptyContainer ]
setString:"Usage: setCurrentVolume <0.0 - 1.0>" ] );
}
newVolume = [[ self getParam:1 ] floatVal ];
if (( newVolume < 0.0 ) || ( newVolume > 1.0 )) {
return ( [[ self getEmptyContainer ]
setString:"Usage: setCurrentVolume <0.0 - 1.0>" ] );
}
NXSetCurrentVolume(ourEventStatusHandle, newVolume);
return ( self );
}
- currentVolume
{
return ( [[ self getEmptyContainer ]
setFloat:NXCurrentVolume(ourEventStatusHandle) ] );
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.