VoiceMac Start
This commit is contained in:
commit
f52814a819
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
build
|
||||||
|
*.zip
|
||||||
|
*.xcodeproj/*.pbxuser
|
||||||
|
*.xcodeproj/*.mode*
|
||||||
|
*.xcodeproj/*.perspective*
|
||||||
|
*.xcodeproj/xcuserdata
|
||||||
|
*.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
|
*.xcworkspace/xcuserdata
|
||||||
|
SIP/opt*
|
||||||
|
SIP/pjproject*
|
||||||
|
VoiceMac/*
|
||||||
|
Screenshots/*
|
22
About.rtf
Normal file
22
About.rtf
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320
|
||||||
|
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||||
|
{\colortbl;\red255\green255\blue255;}
|
||||||
|
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
|
||||||
|
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
|
||||||
|
|
||||||
|
\f0\fs32 \cf0 Special Thanks To\
|
||||||
|
|
||||||
|
\fs24 MegaEduX ({\field{\*\fldinst{HYPERLINK "http://megaedux.com"}}{\fldrslt megaedux.com}})\
|
||||||
|
RockStar ({\field{\*\fldinst{HYPERLINK "http://rocknthesweater.com"}}{\fldrslt rocknthesweater.com}})\
|
||||||
|
PowerOfCheese ({\field{\*\fldinst{HYPERLINK "http://xtrememachinez.com"}}{\fldrslt xtrememachinez.com}})\
|
||||||
|
\
|
||||||
|
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
|
||||||
|
\cf0 VoiceMac Uses {\field{\*\fldinst{HYPERLINK "http://mrgeckosmedia.com"}}{\fldrslt MGMSIP}} as a wrapper for {\field{\*\fldinst{HYPERLINK "http://www.pjsip.org/"}}{\fldrslt PJSIP}} which is a VOIP library, {\field{\*\fldinst{HYPERLINK "http://sparkle.andymatuschak.org"}}{\fldrslt Sparkle}} for software update, and Growl for notifications.\
|
||||||
|
\
|
||||||
|
VoiceMac is the first Google Voice client for the Mac. Send multiple SMS Messages, send SMS Messages, receive SMS Messages, place calls, look at your call history, receive voicemail, reverse lookup a phone number, and search your contact list in one easy interface. When you receive a SMS Message or Voicemail, you get notifications view Growl and hear sounds that is customizable.\
|
||||||
|
\
|
||||||
|
With SIP support you can place calls from your computer using your favorite SIP service and if you link your Google Voice Number with the SIP service, you can place calls with your Google Voice Number from your computer. With the reverse lookup data, you can see who is calling you, even if their number isn't in your contacts list.\
|
||||||
|
\
|
||||||
|
With themes, you can customize your SMS Messages look anyway you like with simple HTML or by downloading a theme.\
|
||||||
|
\
|
||||||
|
VoiceMac's contacts system is one of the best contacts system around, with support for Address Book and Google Contacts. You can search your contacts just like a Search Engine with speed.}
|
45
Classes/Theme Tester/MGMThemeTesterController.h
Normal file
45
Classes/Theme Tester/MGMThemeTesterController.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// MGMThemeTesterController.h
|
||||||
|
// Voice Mac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/24/10.
|
||||||
|
// Copyright 2010 Mr. Gecko's Media. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class WebView, MGMThemeManager;
|
||||||
|
|
||||||
|
@interface MGMThemeTesterController : NSObject {
|
||||||
|
NSPipe *errorPipe;
|
||||||
|
IBOutlet NSTextView *errorConsole;
|
||||||
|
IBOutlet NSWindow *errorConsoleWindow;
|
||||||
|
|
||||||
|
MGMThemeManager *themeManager;
|
||||||
|
IBOutlet NSWindow *mainWindow;
|
||||||
|
IBOutlet WebView *SMSView;
|
||||||
|
|
||||||
|
NSMutableArray *messages;
|
||||||
|
|
||||||
|
IBOutlet NSTextField *yPhotoField;
|
||||||
|
IBOutlet NSTextField *yNumberField;
|
||||||
|
IBOutlet NSTextField *tPhotoField;
|
||||||
|
IBOutlet NSTextField *tNameField;
|
||||||
|
IBOutlet NSTextField *tNumberField;
|
||||||
|
IBOutlet NSDatePicker *lastDatePicker;
|
||||||
|
IBOutlet NSTextField *IDField;
|
||||||
|
IBOutlet NSTextField *messageField;
|
||||||
|
IBOutlet NSPopUpButton *variantsButton;
|
||||||
|
}
|
||||||
|
- (IBAction)open:(id)sender;
|
||||||
|
- (IBAction)save:(id)sender;
|
||||||
|
|
||||||
|
- (void)buildHTML;
|
||||||
|
|
||||||
|
- (IBAction)chooseYPhoto:(id)sender;
|
||||||
|
- (IBAction)chooseTPhoto:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)rebuild:(id)sender;
|
||||||
|
- (IBAction)incoming:(id)sender;
|
||||||
|
- (IBAction)outgoing:(id)sender;
|
||||||
|
@end
|
221
Classes/Theme Tester/MGMThemeTesterController.m
Normal file
221
Classes/Theme Tester/MGMThemeTesterController.m
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
//
|
||||||
|
// MGMThemeTesterController.m
|
||||||
|
// Voice Mac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/24/10.
|
||||||
|
// Copyright 2010 Mr. Gecko's Media. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMThemeTesterController.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
@implementation MGMThemeTesterController
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
errorPipe = [NSPipe new];
|
||||||
|
dup2([[errorPipe fileHandleForWriting] fileDescriptor], fileno(stderr));
|
||||||
|
|
||||||
|
NSFileHandle *pipeHandle = [errorPipe fileHandleForReading];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(errorHandle:) name:NSFileHandleReadCompletionNotification object:pipeHandle];
|
||||||
|
[pipeHandle readInBackgroundAndNotify];
|
||||||
|
|
||||||
|
[SMSView setResourceLoadDelegate:self];
|
||||||
|
messages = [NSMutableArray new];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Hey, you got the message?", MGMIText, @"5:56 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No, can you resend it?", MGMIText, @"5:57 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No, all local copies were destroyed, because we don't want this to get out.", MGMIText, @"5:58 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Oh, yea, right, that thing.", MGMIText, @"5:59 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"I can't send you on SMS because your cell phone company spy's on you.", MGMIText, @"6:00 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"True. We can meet in the secret spot.", MGMIText, @"6:00 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No thanks, I think we should meet at my house.", MGMIText, @"6:01 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Would you like to come for dinner?", MGMIText, @"6:01 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"I'd love, but my girl needs me more.", MGMIText, @"6:02 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Well why not make it a double date? I bring my wife and you bring yours.", MGMIText, @"6:03 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Sure I pick Mucha Pizza. What time should we meet?", MGMIText, @"6:05 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"7PM?", MGMIText, @"6:05 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"That sounds good.", MGMIText, @"6:06 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Great, meet you then.", MGMIText, @"6:07 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[[SMSView mainFrame] loadHTMLString:@"<div style=\"text-align: center; font-size: 14pt; font-weight: bold;\">Please open a theme to preview it.</div>" baseURL:nil];
|
||||||
|
[mainWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (IBAction)open:(id)sender {
|
||||||
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setResolvesAliases:YES];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
[panel setAllowedFileTypes:[NSArray arrayWithObject:@"vmt"]];
|
||||||
|
[panel setTreatsFilePackagesAsDirectories:NO];
|
||||||
|
int returnCode = [panel runModal];
|
||||||
|
if (returnCode==NSOKButton) {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setObject:[[[panel URL] path] stringByDeletingLastPathComponent] forKey:MGMTCurrentThemePath];
|
||||||
|
[defaults setObject:[[[panel URL] path] lastPathComponent] forKey:MGMTCurrentThemeName];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMTCurrentThemeVariant];
|
||||||
|
if (themeManager!=nil) [themeManager release];
|
||||||
|
NSLog(@"Loading Theme Manager");
|
||||||
|
themeManager = [MGMThemeManager new];
|
||||||
|
if (themeManager!=nil) {
|
||||||
|
NSArray *variants = [[themeManager theme] objectForKey:MGMTVariants];
|
||||||
|
[variantsButton removeAllItems];
|
||||||
|
for (int i=0; i<[variants count]; i++) {
|
||||||
|
[variantsButton addItemWithTitle:[[variants objectAtIndex:i] objectForKey:MGMTName]];
|
||||||
|
}
|
||||||
|
[self buildHTML];
|
||||||
|
} else {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Error loading theme"];
|
||||||
|
[alert setInformativeText:@"For some reason, the Theme Manager was unable to load the theme. For more information, view the console."];
|
||||||
|
[alert runModal];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)save:(id)sender {
|
||||||
|
NSSavePanel *panel = [NSSavePanel savePanel];
|
||||||
|
int returnCode = [panel runModal];
|
||||||
|
if (returnCode==NSOKButton) {
|
||||||
|
[[[[SMSView mainFrame] dataSource] data] writeToURL:[panel URL] atomically:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)buildHTML {
|
||||||
|
NSLog(@"Building HTML");
|
||||||
|
NSMutableDictionary *messageInfo = [NSMutableDictionary dictionary];
|
||||||
|
[messageInfo setObject:[lastDatePicker dateValue] forKey:MGMITime];
|
||||||
|
[messageInfo setObject:[tNameField stringValue] forKey:MGMTInName];
|
||||||
|
[messageInfo setObject:[tNumberField stringValue] forKey:MGMIPhoneNumber];
|
||||||
|
[messageInfo setObject:[yNumberField stringValue] forKey:MGMTUserNumber];
|
||||||
|
[messageInfo setObject:[IDField stringValue] forKey:MGMIID];
|
||||||
|
NSString *yPhotoPath = nil;
|
||||||
|
if ([[yPhotoField stringValue] isEqual:@""])
|
||||||
|
yPhotoPath = [[themeManager outgoingIconPath] filePath];
|
||||||
|
else
|
||||||
|
yPhotoPath = [[yPhotoField stringValue] filePath];
|
||||||
|
NSString *tPhotoPath = nil;
|
||||||
|
if ([[tPhotoField stringValue] isEqual:@""])
|
||||||
|
tPhotoPath = [[themeManager incomingIconPath] filePath];
|
||||||
|
else
|
||||||
|
tPhotoPath = [[tPhotoField stringValue] filePath];
|
||||||
|
NSMutableArray *messageArray = [NSMutableArray array];
|
||||||
|
for (unsigned int i=0; i<[messages count]; i++) {
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionaryWithDictionary:[messages objectAtIndex:i]];
|
||||||
|
[message setObject:[[NSNumber numberWithInt:i] stringValue] forKey:MGMIID];
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
[message setObject:yPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:NSFullUserName() forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTUserNumber] forKey:MGMIPhoneNumber];
|
||||||
|
} else {
|
||||||
|
[message setObject:tPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTInName] forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMIPhoneNumber] forKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
[messageArray addObject:message];
|
||||||
|
}
|
||||||
|
NSString *html = [themeManager buildHTMLWithMessages:messageArray messageInfo:messageInfo];
|
||||||
|
[[SMSView mainFrame] loadHTMLString:html baseURL:[NSURL fileURLWithPath:[themeManager currentThemeVariantPath]]];
|
||||||
|
}
|
||||||
|
- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource {
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:@"scrollToBottom();"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)chooseYPhoto:(id)sender {
|
||||||
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setResolvesAliases:YES];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"png", @"jpg", @"tif", @"jpeg", @"tiff", nil]];
|
||||||
|
[panel setTreatsFilePackagesAsDirectories:NO];
|
||||||
|
int returnCode = [panel runModal];
|
||||||
|
if (returnCode==NSOKButton) {
|
||||||
|
[yPhotoField setStringValue:[[panel URL] path]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)chooseTPhoto:(id)sender {
|
||||||
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setResolvesAliases:YES];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"png", @"jpg", @"tif", @"jpeg", @"tiff", nil]];
|
||||||
|
[panel setTreatsFilePackagesAsDirectories:NO];
|
||||||
|
int returnCode = [panel runModal];
|
||||||
|
if (returnCode==NSOKButton) {
|
||||||
|
[tPhotoField setStringValue:[[panel URL] path]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)rebuild:(id)sender {
|
||||||
|
if (themeManager!=nil) {
|
||||||
|
[themeManager setVariant:[variantsButton titleOfSelectedItem]];
|
||||||
|
[self buildHTML];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)addMessage:(NSDictionary *)theMessage {
|
||||||
|
NSMutableDictionary *messageInfo = [NSMutableDictionary dictionary];
|
||||||
|
[messageInfo setObject:[lastDatePicker dateValue] forKey:MGMITime];
|
||||||
|
[messageInfo setObject:[tNameField stringValue] forKey:MGMTInName];
|
||||||
|
[messageInfo setObject:[tNumberField stringValue] forKey:MGMIPhoneNumber];
|
||||||
|
[messageInfo setObject:[yNumberField stringValue] forKey:MGMTUserNumber];
|
||||||
|
NSString *yPhotoPath = nil;
|
||||||
|
if ([[yPhotoField stringValue] isEqual:@""])
|
||||||
|
yPhotoPath = [[themeManager outgoingIconPath] filePath];
|
||||||
|
else
|
||||||
|
yPhotoPath = [[yPhotoField stringValue] filePath];
|
||||||
|
NSString *tPhotoPath = nil;
|
||||||
|
if ([[tPhotoField stringValue] isEqual:@""])
|
||||||
|
tPhotoPath = [[themeManager incomingIconPath] filePath];
|
||||||
|
else
|
||||||
|
tPhotoPath = [[tPhotoField stringValue] filePath];
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionaryWithDictionary:theMessage];
|
||||||
|
[message setObject:[[NSNumber numberWithInt:[messages count]-1] stringValue] forKey:MGMIID];
|
||||||
|
int type = 1;
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
type = ([[[messages objectAtIndex:[[message objectForKey:MGMIID] intValue]-1] objectForKey:MGMIYou] boolValue] ? 2 : 1);
|
||||||
|
NSLog(@"Adding Outgoing %@", (type==1 ? @"Content" : @"Next Content"));
|
||||||
|
[message setObject:yPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:NSFullUserName() forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTUserNumber] forKey:MGMIPhoneNumber];
|
||||||
|
} else {
|
||||||
|
type = ([[[messages objectAtIndex:[[message objectForKey:MGMIID] intValue]-1] objectForKey:MGMIYou] boolValue] ? 3 : 4);
|
||||||
|
NSLog(@"Adding Incoming %@", (type==3 ? @"Content" : @"Next Content"));
|
||||||
|
[message setObject:tPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTInName] forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMIPhoneNumber] forKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:[[themeManager variant] objectForKey:MGMTDate]];
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"newMessage('%@', '%@', '%@', %@, '%@', '%@', '%@', %d);", [[message objectForKey:MGMIText] escapeSMS], [[message objectForKey:MGMTPhoto] escapeSMS], [[message objectForKey:MGMITime] escapeSMS], [message objectForKey:MGMIID], [[message objectForKey:MGMTName] escapeSMS], [[[message objectForKey:MGMIPhoneNumber] readableNumber] escapeSMS], [formatter stringFromDate:[messageInfo objectForKey:MGMITime]], type]];
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:@"scrollToBottom();"];
|
||||||
|
}
|
||||||
|
- (IBAction)incoming:(id)sender {
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:@"h:mm a"];
|
||||||
|
NSDictionary *message = [NSDictionary dictionaryWithObjectsAndKeys:[messageField stringValue], MGMIText, [formatter stringFromDate:[lastDatePicker dateValue]], MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil];
|
||||||
|
[messages addObject:message];
|
||||||
|
if ([[[themeManager variant] objectForKey:MGMTRebuild] boolValue]) {
|
||||||
|
[self buildHTML];
|
||||||
|
} else {
|
||||||
|
[self addMessage:message];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)outgoing:(id)sender {
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:@"h:mm a"];
|
||||||
|
NSDictionary *message = [NSDictionary dictionaryWithObjectsAndKeys:[messageField stringValue], MGMIText, [formatter stringFromDate:[lastDatePicker dateValue]], MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil];
|
||||||
|
[messages addObject:message];
|
||||||
|
if ([[[themeManager variant] objectForKey:MGMTRebuild] boolValue]) {
|
||||||
|
[self buildHTML];
|
||||||
|
} else {
|
||||||
|
[self addMessage:message];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)errorHandle:(NSNotification *)theNotification {
|
||||||
|
[[theNotification object] readInBackgroundAndNotify];
|
||||||
|
NSString *string = [[NSString alloc] initWithData:[[theNotification userInfo] objectForKey:NSFileHandleNotificationDataItem] encoding:NSUTF8StringEncoding];
|
||||||
|
[errorConsole insertText:string];
|
||||||
|
[string release];
|
||||||
|
}
|
||||||
|
@end
|
7
Classes/Theme Tester/Theme Tester_Prefix.pch
Normal file
7
Classes/Theme Tester/Theme Tester_Prefix.pch
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//
|
||||||
|
// Prefix header for all source files of the 'Voice Mac' target in the 'Voice Mac' project
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
16
Classes/Theme Tester/main.m
Normal file
16
Classes/Theme Tester/main.m
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// Voice Mac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 7/24/09.
|
||||||
|
// Copyright Mr. Gecko's Media 2009. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDeveloperExtras"];
|
||||||
|
[pool drain];
|
||||||
|
return NSApplicationMain(argc, (const char **)argv);
|
||||||
|
}
|
41
Classes/VoiceBase/AddressBook/MGMAddressBook.h
Normal file
41
Classes/VoiceBase/AddressBook/MGMAddressBook.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// MGMAddressBook.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <AddressBook/ABAddressBook.h>
|
||||||
|
#else
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@protocol MGMContactsDelegate, MGMContactsOwnerDelegate;
|
||||||
|
|
||||||
|
@class ABAddressBook;
|
||||||
|
|
||||||
|
@interface MGMAddressBook : NSObject {
|
||||||
|
id<MGMContactsOwnerDelegate> delegate;
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
ABAddressBookRef addressBook;
|
||||||
|
#else
|
||||||
|
ABAddressBook *addressBook;
|
||||||
|
#endif
|
||||||
|
BOOL shouldStop;
|
||||||
|
BOOL gettingContacts;
|
||||||
|
BOOL gettingGroups;
|
||||||
|
id<MGMContactsDelegate> contactsSender;
|
||||||
|
id<MGMContactsDelegate> groupsSender;
|
||||||
|
}
|
||||||
|
- (id)initWithDelegate:(id)theDelegate;
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
+ (NSData *)userPhotoData;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- (void)getContacts:(id)sender;
|
||||||
|
- (void)getGroups:(id)sender;
|
||||||
|
@end
|
253
Classes/VoiceBase/AddressBook/MGMAddressBook.m
Normal file
253
Classes/VoiceBase/AddressBook/MGMAddressBook.m
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
//
|
||||||
|
// MGMAddressBook.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMAddressBook.h"
|
||||||
|
#import "MGMContactsProtocol.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <AddressBook/ABAddressBook.h>
|
||||||
|
#import <AddressBook/ABPerson.h>
|
||||||
|
#import <AddressBook/ABGroup.h>
|
||||||
|
#import <AddressBook/ABMultiValue.h>
|
||||||
|
#else
|
||||||
|
#import <AddressBook/AddressBook.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@implementation MGMAddressBook
|
||||||
|
- (id)initWithDelegate:(id)theDelegate {
|
||||||
|
if (self = [super init]) {
|
||||||
|
delegate = theDelegate;
|
||||||
|
shouldStop = NO;
|
||||||
|
gettingContacts = NO;
|
||||||
|
gettingGroups = NO;
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
addressBook = ABAddressBookCreate();
|
||||||
|
#else
|
||||||
|
addressBook = [[ABAddressBook sharedAddressBook] retain];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
if (addressBook!=NULL)
|
||||||
|
CFRelease(addressBook);
|
||||||
|
#else
|
||||||
|
if (addressBook!=nil)
|
||||||
|
[addressBook release];
|
||||||
|
#endif
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
+ (NSData *)userPhotoData {
|
||||||
|
return [[[ABAddressBook sharedAddressBook] me] imageData];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- (void)stop {
|
||||||
|
shouldStop = YES;
|
||||||
|
while (gettingContacts)
|
||||||
|
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
||||||
|
while (gettingGroups)
|
||||||
|
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
||||||
|
shouldStop = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getContacts:(id)sender {
|
||||||
|
if (gettingContacts) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithObject:contactsSender forKey:MGMCRecallSender];
|
||||||
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
||||||
|
if ([sender respondsToSelector:@selector(contactsError:)]) [sender contactsError:error];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gettingContacts = YES;
|
||||||
|
contactsSender = sender;
|
||||||
|
[NSThread detachNewThreadSelector:@selector(contactsBackground) toTarget:self withObject:nil];
|
||||||
|
}
|
||||||
|
- (void)contactsBackground {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
NSArray *people = [(NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook) autorelease];
|
||||||
|
for (unsigned int i=0; i<[people count]; i++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABRecordRef person = [people objectAtIndex:i];
|
||||||
|
NSString *name = @"";
|
||||||
|
NSString *firstName = [(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) autorelease];
|
||||||
|
if (firstName!=nil)
|
||||||
|
name = firstName;
|
||||||
|
NSString *lastName = [(NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty) autorelease];
|
||||||
|
if ([name isEqualToString:@""] && lastName!=nil)
|
||||||
|
name = lastName;
|
||||||
|
else if (lastName!=nil)
|
||||||
|
name = [name stringByAppendingFormat:@" %@", lastName];
|
||||||
|
NSString *company = [(NSString *)ABRecordCopyValue(person, kABPersonOrganizationProperty) autorelease];
|
||||||
|
if (company==nil)
|
||||||
|
company = @"";
|
||||||
|
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
|
||||||
|
int phonesCount = ABMultiValueGetCount(phones);
|
||||||
|
NSData *image = [(NSData *)ABPersonCopyImageData(person) autorelease];
|
||||||
|
if (phonesCount>0) {
|
||||||
|
//if (image!=nil)
|
||||||
|
// image = [image resizeTo:NSMakeSize(MGMABPhotoSize, MGMABPhotoSize)];
|
||||||
|
}
|
||||||
|
for (int p=0; p<phonesCount; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
|
||||||
|
[contact setObject:name forKey:MGMABName];
|
||||||
|
[contact setObject:company forKey:MGMABCompany];
|
||||||
|
if (delegate!=nil)
|
||||||
|
[contact setObject:[[(NSString *)ABMultiValueCopyValueAtIndex(phones, p) autorelease] phoneFormatWithAreaCode:[delegate areaCode]] forKey:MGMABNumber];
|
||||||
|
else
|
||||||
|
[contact setObject:[[(NSString *)ABMultiValueCopyValueAtIndex(phones, p) autorelease] phoneFormat] forKey:MGMABNumber];
|
||||||
|
NSString *label = [(NSString *)ABMultiValueCopyLabelAtIndex(phones, p) autorelease];
|
||||||
|
NSRange range = [label rangeOfString:@"<"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [label substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0007");
|
||||||
|
} else {
|
||||||
|
label = [string substringWithRange:NSMakeRange(0, range.location)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contact setObject:[label capitalizedString] forKey:MGMABLabel];
|
||||||
|
if (image!=nil)
|
||||||
|
[contact setObject:image forKey:MGMABPhoto];
|
||||||
|
if ([contactsSender respondsToSelector:@selector(gotContact:)]) [contactsSender gotContact:contact];
|
||||||
|
}
|
||||||
|
CFRelease(phones);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NSArray *people = [addressBook people];
|
||||||
|
for (unsigned int i=0; i<[people count]; i++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABPerson *person = [people objectAtIndex:i];
|
||||||
|
if ([person valueForProperty:kABPhoneProperty]!=nil) {
|
||||||
|
NSString *name = @"";
|
||||||
|
if ([person valueForProperty:kABFirstNameProperty])
|
||||||
|
name = [person valueForProperty:kABFirstNameProperty];
|
||||||
|
if ([name isEqualToString:@""] && [person valueForProperty:kABLastNameProperty]!=nil)
|
||||||
|
name = [person valueForProperty:kABLastNameProperty];
|
||||||
|
else if ([person valueForProperty:kABLastNameProperty]!=nil)
|
||||||
|
name = [name stringByAppendingFormat:@" %@", [person valueForProperty:kABLastNameProperty]];
|
||||||
|
NSString *company = @"";
|
||||||
|
if ([person valueForProperty:kABOrganizationProperty]!=nil)
|
||||||
|
company = [person valueForProperty:kABOrganizationProperty];
|
||||||
|
ABMultiValue *phones = [person valueForProperty:kABPhoneProperty];
|
||||||
|
NSData *image = [person imageData];
|
||||||
|
if ([phones count]>0) {
|
||||||
|
if (image!=nil)
|
||||||
|
image = [image resizeTo:NSMakeSize(MGMABPhotoSize, MGMABPhotoSize)];
|
||||||
|
}
|
||||||
|
for (int p=0; p<[phones count]; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
|
||||||
|
[contact setObject:name forKey:MGMCName];
|
||||||
|
[contact setObject:company forKey:MGMCCompany];
|
||||||
|
if (delegate!=nil)
|
||||||
|
[contact setObject:[[phones valueAtIndex:p] phoneFormatWithAreaCode:[delegate areaCode]] forKey:MGMCNumber];
|
||||||
|
else
|
||||||
|
[contact setObject:[[phones valueAtIndex:p] phoneFormat] forKey:MGMCNumber];
|
||||||
|
NSString *label = [phones labelAtIndex:p];
|
||||||
|
NSRange range = [label rangeOfString:@"<"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [label substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0007");
|
||||||
|
} else {
|
||||||
|
label = [string substringWithRange:NSMakeRange(0, range.location)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contact setObject:[label capitalizedString] forKey:MGMCLabel];
|
||||||
|
if (image!=nil)
|
||||||
|
[contact setObject:image forKey:MGMCPhoto];
|
||||||
|
if ([contactsSender respondsToSelector:@selector(gotContact:)]) [contactsSender gotContact:contact];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!shouldStop)
|
||||||
|
if ([contactsSender respondsToSelector:@selector(doneGettingContacts)]) [contactsSender doneGettingContacts];
|
||||||
|
gettingContacts = NO;
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getGroups:(id)sender {
|
||||||
|
if (gettingGroups) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithObject:groupsSender forKey:MGMCRecallSender];
|
||||||
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
||||||
|
if ([sender respondsToSelector:@selector(groupsError:)]) [sender groupsError:error];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gettingGroups = YES;
|
||||||
|
groupsSender = sender;
|
||||||
|
[NSThread detachNewThreadSelector:@selector(groupsBackground:) toTarget:self withObject:sender];
|
||||||
|
}
|
||||||
|
- (void)groupsBackground:(id<MGMContactsDelegate>)sender {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
NSArray *abGroups = [(NSArray *)ABAddressBookCopyArrayOfAllGroups(addressBook) autorelease];
|
||||||
|
for (unsigned int i=0; i<[abGroups count]; i++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABRecordRef abGroup = [abGroups objectAtIndex:i];
|
||||||
|
NSString *name = [(NSString *)ABRecordCopyValue(abGroup, kABGroupNameProperty) autorelease];
|
||||||
|
NSArray *people = [(NSArray *)ABGroupCopyArrayOfAllMembers(abGroup) autorelease];
|
||||||
|
NSMutableArray *groupMembers = [NSMutableArray array];
|
||||||
|
for (unsigned int p=0; p<[people count]; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABRecordRef person = [people objectAtIndex:i];
|
||||||
|
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
|
||||||
|
if (phones!=NULL) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
int phonesCount = ABMultiValueGetCount(phones);
|
||||||
|
for (int p=0; p<phonesCount; p++) {
|
||||||
|
if (delegate!=nil)
|
||||||
|
[groupMembers addObject:[[(NSString *)ABMultiValueCopyValueAtIndex(phones, p) autorelease] phoneFormatWithAreaCode:[delegate areaCode]]];
|
||||||
|
else
|
||||||
|
[groupMembers addObject:[[(NSString *)ABMultiValueCopyValueAtIndex(phones, p) autorelease] phoneFormat]];
|
||||||
|
}
|
||||||
|
CFRelease(phones);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!shouldStop)
|
||||||
|
if ([groupsSender respondsToSelector:@selector(gotGroup:withMembers:)]) [groupsSender gotGroup:name withMembers:groupMembers];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NSArray *abGroups = [addressBook groups];
|
||||||
|
for (unsigned int i=0; i<[abGroups count]; i++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABGroup *abGroup = [abGroups objectAtIndex:i];
|
||||||
|
NSString *name = [abGroup valueForProperty:kABGroupNameProperty];
|
||||||
|
NSArray *people = [abGroup members];
|
||||||
|
NSMutableArray *groupMembers = [NSMutableArray array];
|
||||||
|
for (unsigned int p=0; p<[people count]; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
ABPerson *person = [people objectAtIndex:p];
|
||||||
|
if ([person valueForProperty:kABPhoneProperty]!=nil) {
|
||||||
|
ABMultiValue *phones = [person valueForProperty:kABPhoneProperty];
|
||||||
|
for (int p=0; p<[phones count]; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
if (delegate!=nil)
|
||||||
|
[groupMembers addObject:[[phones valueAtIndex:p] phoneFormatWithAreaCode:[delegate areaCode]]];
|
||||||
|
else
|
||||||
|
[groupMembers addObject:[[phones valueAtIndex:p] phoneFormat]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!shouldStop)
|
||||||
|
if ([groupsSender respondsToSelector:@selector(gotGroup:withMembers:)]) [groupsSender gotGroup:name withMembers:groupMembers];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!shouldStop)
|
||||||
|
if ([groupsSender respondsToSelector:@selector(doneGettingGroups)]) [groupsSender doneGettingGroups];
|
||||||
|
gettingGroups = NO;
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
@end
|
59
Classes/VoiceBase/AddressBook/MGMContacts.h
Normal file
59
Classes/VoiceBase/AddressBook/MGMContacts.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// MGMContacts.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/18/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@protocol MGMContactsProtocol, MGMContactsOwnerDelegate;
|
||||||
|
@class MGMUser, MGMLiteConnection;
|
||||||
|
|
||||||
|
#define MGMContactsDebug 0
|
||||||
|
|
||||||
|
@interface MGMContacts : NSObject {
|
||||||
|
id<MGMContactsOwnerDelegate> delegate;
|
||||||
|
MGMUser *user;
|
||||||
|
MGMLiteConnection *contactsConnection;
|
||||||
|
MGMLiteConnection *updateConnection;
|
||||||
|
Class contactsClass;
|
||||||
|
id<MGMContactsProtocol> contacts;
|
||||||
|
BOOL isUpdating;
|
||||||
|
BOOL stopingUpdate;
|
||||||
|
NSLock *updateLock;
|
||||||
|
NSLock *contactsLock;
|
||||||
|
int maxResults;
|
||||||
|
}
|
||||||
|
+ (id)contactsWithClass:(Class)theClass delegate:(id)theDelegate;
|
||||||
|
- (id)initWithClass:(Class)theClass delegate:(id)theDelegate;
|
||||||
|
|
||||||
|
- (void)stop;
|
||||||
|
|
||||||
|
- (void)setMaxResults:(int)theMaxResults;
|
||||||
|
- (int)maxResults;
|
||||||
|
|
||||||
|
- (MGMLiteConnection *)contactsConnection;
|
||||||
|
- (void)setContactsConnection:(MGMLiteConnection *)theConnection;
|
||||||
|
|
||||||
|
- (void)updateContacts;
|
||||||
|
- (void)contactsError:(NSError *)theError;
|
||||||
|
- (void)groupsError:(NSError *)theError;
|
||||||
|
|
||||||
|
- (NSNumber *)countContactsMatching:(NSString *)theString;
|
||||||
|
- (NSArray *)contactsMatching:(NSString *)theString page:(int)thePage;
|
||||||
|
- (NSArray *)contactCompletionsMatching:(NSString *)theString;
|
||||||
|
- (NSDictionary *)contactWithID:(NSNumber *)theID;
|
||||||
|
- (NSData *)photoDataForNumber:(NSString *)theNumber;
|
||||||
|
- (NSString *)cachedPhotoForNumber:(NSString *)theNumber;
|
||||||
|
- (NSString *)nameForNumber:(NSString *)theNumber;
|
||||||
|
|
||||||
|
- (NSArray *)groups;
|
||||||
|
- (NSDictionary *)groupWithID:(NSNumber *)theID;
|
||||||
|
- (NSNumber *)membersCountOfGroup:(NSDictionary *)theGroup;
|
||||||
|
- (NSNumber *)membersCountOfGroupID:(NSNumber *)theGroup;
|
||||||
|
- (NSArray *)membersOfGroup:(NSDictionary *)theGroup;
|
||||||
|
- (NSArray *)membersOfGroupID:(NSNumber *)theGroup;
|
||||||
|
- (NSArray *)groupsOfContact:(NSDictionary *)theContact;
|
||||||
|
@end
|
552
Classes/VoiceBase/AddressBook/MGMContacts.m
Normal file
552
Classes/VoiceBase/AddressBook/MGMContacts.m
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
//
|
||||||
|
// MGMContacts.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/18/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMContacts.h"
|
||||||
|
#import "MGMContactsProtocol.h"
|
||||||
|
#import "MGMAddressBook.h"
|
||||||
|
#import "MGMGoogleContacts.h"
|
||||||
|
#import "MGMInstance.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMCContactsDB = @"contacts.db";
|
||||||
|
NSString * const MGMCUpdateDB = @"update.db";
|
||||||
|
|
||||||
|
NSString * const MGMCWordSA = @"%@*";
|
||||||
|
NSString * const MGMCWordSSA = @" %@*";
|
||||||
|
NSString * const MGMCWordS = @" %@";
|
||||||
|
NSString * const MGMCQoute = @"\"";
|
||||||
|
NSString * const MGMCNum = @"%%%@%%";
|
||||||
|
NSString * const MGMCNEAR = @"NEAR";
|
||||||
|
NSString * const MGMCAND = @"AND";
|
||||||
|
NSString * const MGMCOR = @"OR";
|
||||||
|
NSString * const MGMCNOT = @"NOT";
|
||||||
|
|
||||||
|
NSString * const MGMCCNumber = @"%@ (%@)";
|
||||||
|
|
||||||
|
NSString * const MGMTiffExt = @"tif";
|
||||||
|
|
||||||
|
const int MGMCMaxResults = 10;
|
||||||
|
|
||||||
|
@interface MGMContacts (MGMPrivate)
|
||||||
|
- (void)updated;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMContacts
|
||||||
|
+ (id)contactsWithClass:(Class)theClass delegate:(id)theDelegate {
|
||||||
|
return [[[self alloc] initWithClass:theClass delegate:theDelegate] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithClass:(Class)theClass delegate:(id)theDelegate {
|
||||||
|
if (self = [super init]) {
|
||||||
|
maxResults = MGMCMaxResults;
|
||||||
|
delegate = theDelegate;
|
||||||
|
user = [delegate user];
|
||||||
|
contactsLock = [NSLock new];
|
||||||
|
isUpdating = NO;
|
||||||
|
stopingUpdate = NO;
|
||||||
|
updateLock = [NSLock new];
|
||||||
|
if (theClass==NULL) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
contacts = [[theClass alloc] initWithDelegate:delegate];
|
||||||
|
if (contacts==nil) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
if ([[NSFileManager defaultManager] fileExistsAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB]]) {
|
||||||
|
[self setContactsConnection:[MGMLiteConnection connectionWithPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB]]];
|
||||||
|
}
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userUpdated:) name:MGMUserUpdatedNotification object:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (updateLock!=nil) {
|
||||||
|
[updateLock lock];
|
||||||
|
[updateLock unlock];
|
||||||
|
[updateLock release];
|
||||||
|
}
|
||||||
|
if (contactsLock!=nil) {
|
||||||
|
[contactsLock lock];
|
||||||
|
[contactsLock unlock];
|
||||||
|
[contactsLock release];
|
||||||
|
}
|
||||||
|
if (contactsConnection!=nil)
|
||||||
|
[contactsConnection release];
|
||||||
|
if (updateConnection!=nil)
|
||||||
|
[updateConnection release];
|
||||||
|
if (contacts!=nil)
|
||||||
|
[contacts release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stop {
|
||||||
|
if (isUpdating) {
|
||||||
|
stopingUpdate = YES;
|
||||||
|
[contacts stop];
|
||||||
|
[updateLock lock];
|
||||||
|
[updateLock unlock];
|
||||||
|
if (updateConnection!=nil) {
|
||||||
|
[updateConnection release];
|
||||||
|
updateConnection = nil;
|
||||||
|
}
|
||||||
|
isUpdating = NO;
|
||||||
|
stopingUpdate = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userUpdated:(NSNotification *)theNotification {
|
||||||
|
MGMUser *theUser = [theNotification object];
|
||||||
|
if ([theUser isEqual:user] && (![[theUser settingForKey:MGMSContactsSourceKey] isEqual:NSStringFromClass([contacts class])] || ([contacts isKindOfClass:[MGMGoogleContacts class]] && ![[[(MGMGoogleContacts *)contacts user] settingForKey:MGMUserID] isEqual:[theUser settingForKey:MGMCGoogleContactsUser]]))) {
|
||||||
|
if (stopingUpdate) return;
|
||||||
|
[self stop];
|
||||||
|
if (contacts!=nil) [contacts release];
|
||||||
|
contacts = [[NSClassFromString([theUser settingForKey:MGMSContactsSourceKey]) alloc] initWithDelegate:delegate];
|
||||||
|
[self updateContacts];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMaxResults:(int)theMaxResults {
|
||||||
|
maxResults = theMaxResults;
|
||||||
|
}
|
||||||
|
- (int)maxResults {
|
||||||
|
return maxResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMLiteConnection *)contactsConnection {
|
||||||
|
return contactsConnection;
|
||||||
|
}
|
||||||
|
- (void)setContactsConnection:(MGMLiteConnection *)theConnection {
|
||||||
|
[contactsLock lock];
|
||||||
|
if (contactsConnection!=nil) [contactsConnection release];
|
||||||
|
contactsConnection = [theConnection retain];
|
||||||
|
[contactsLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateContacts {
|
||||||
|
if (isUpdating)
|
||||||
|
return;
|
||||||
|
isUpdating = YES;
|
||||||
|
[updateLock lock];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if ([manager fileExistsAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB]]) {
|
||||||
|
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
|
||||||
|
[manager removeFileAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB] handler:nil];
|
||||||
|
else
|
||||||
|
[manager removeItemAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB] error:nil];
|
||||||
|
}
|
||||||
|
updateConnection = [[MGMLiteConnection connectionWithPath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB]] retain];
|
||||||
|
if (updateConnection==nil) {
|
||||||
|
[self contactsError:nil];
|
||||||
|
}
|
||||||
|
#if MGMContactsDebug
|
||||||
|
NSLog(@"Getting Contacts");
|
||||||
|
[updateConnection setLogQuery:YES];
|
||||||
|
#endif
|
||||||
|
[updateConnection query:@"CREATE VIRTUAL TABLE contacts USING fts3(name, company, number, label, photo)"];
|
||||||
|
[updateConnection query:@"CREATE TABLE groups (docid INTEGER PRIMARY KEY AUTOINCREMENT, name)"];
|
||||||
|
[updateConnection query:@"CREATE TABLE groupMembers (docid INTEGER PRIMARY KEY AUTOINCREMENT, groupid INTEGER, contactid INTEGER)"];
|
||||||
|
[updateLock unlock];
|
||||||
|
[contacts getContacts:self];
|
||||||
|
}
|
||||||
|
- (void)gotContact:(NSDictionary *)theContact {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[updateLock lock];
|
||||||
|
if (updateConnection!=nil) {
|
||||||
|
[updateConnection query:@"INSERT INTO contacts (name, company, number, label, photo) VALUES (%@, %@, %@, %@, %@)", [theContact objectForKey:MGMCName], [theContact objectForKey:MGMCCompany], [theContact objectForKey:MGMCNumber], [theContact objectForKey:MGMCLabel], [theContact objectForKey:MGMCPhoto]];
|
||||||
|
#if MGMContactsDebug
|
||||||
|
if ([updateConnection errorID]!=0)
|
||||||
|
NSLog(@"%@ %@", [updateConnection errorMessage], theContact);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
[updateLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)doneGettingContacts {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[contacts getGroups:self];
|
||||||
|
#if MGMContactsDebug
|
||||||
|
NSLog(@"Finished Adding Contacts");
|
||||||
|
#endif
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)contactsError:(NSError *)theError {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSLog(@"MGMContacts Error: %@", theError);
|
||||||
|
isUpdating = NO;
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)gotGroup:(NSString *)theName withMembers:(NSArray *)theMembers {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[updateLock lock];
|
||||||
|
if (updateConnection!=nil) {
|
||||||
|
[updateConnection query:@"INSERT INTO groups (name) VALUES (%@)", theName];
|
||||||
|
long long int groupID = [updateConnection insertId];
|
||||||
|
for (unsigned int i=0; i<[theMembers count]; i++) {
|
||||||
|
NSDictionary *result = [[updateConnection query:@"SELECT docid, * FROM contacts WHERE number = %@", [theMembers objectAtIndex:i]] nextRow];
|
||||||
|
if (result!=nil) {
|
||||||
|
[updateConnection query:@"INSERT INTO groupMembers (groupid, contactid) VALUES (%qi, %@)", groupID, [result objectForKey:MGMCDocID]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[updateLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)doneGettingGroups {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[self updated];
|
||||||
|
#if MGMContactsDebug
|
||||||
|
NSLog(@"Finished Adding Groups");
|
||||||
|
#endif
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)groupsError:(NSError *)theError {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSLog(@"MGMContacts Group Error: %@", theError);
|
||||||
|
[self updated];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)updated {
|
||||||
|
[updateLock lock];
|
||||||
|
[self setContactsConnection:nil];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if ([manager fileExistsAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB]]) {
|
||||||
|
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
|
||||||
|
[manager removeFileAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB] handler:nil];
|
||||||
|
else
|
||||||
|
[manager removeItemAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB] error:nil];
|
||||||
|
}
|
||||||
|
if ([manager respondsToSelector:@selector(movePath:toPath:handler:)] )
|
||||||
|
[manager movePath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB] toPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB] handler:nil];
|
||||||
|
else
|
||||||
|
[manager moveItemAtPath:[[user supportPath] stringByAppendingPathComponent:MGMCUpdateDB] toPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB] error:nil];
|
||||||
|
[self setContactsConnection:[MGMLiteConnection connectionWithPath:[[user supportPath] stringByAppendingPathComponent:MGMCContactsDB]]];
|
||||||
|
[updateLock unlock];
|
||||||
|
isUpdating = NO;
|
||||||
|
if ([delegate respondsToSelector:@selector(updatedContacts)]) [delegate updatedContacts];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSNumber *)countContactsMatching:(NSString *)theString {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return [NSNumber numberWithInt:0];
|
||||||
|
[contactsLock lock];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *string = [theString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
MGMLiteResult *result;
|
||||||
|
if (theString==nil || [string isEqual:@""]) {
|
||||||
|
result = [contactsConnection query:@"SELECT COUNT(docid) AS count FROM contacts"];
|
||||||
|
} else {
|
||||||
|
if ([string isPhone]) {
|
||||||
|
NSString *search = [NSString stringWithFormat:MGMCNum, [[string removePhoneWhiteSpace] littersToNumbers]];
|
||||||
|
result = [contactsConnection query:@"SELECT COUNT(docid) AS count FROM contacts WHERE number LIKE %@", search];
|
||||||
|
} else {
|
||||||
|
NSArray *words = [string componentsSeparatedByString:@" "];
|
||||||
|
NSMutableString *search = [NSMutableString string];
|
||||||
|
BOOL quote = NO;
|
||||||
|
for (int i=0; i<[words count]; i++) {
|
||||||
|
NSString *word = [words objectAtIndex:i];
|
||||||
|
if (quote) {
|
||||||
|
quote = ![word hasSuffix:MGMCQoute];
|
||||||
|
if (i==0)
|
||||||
|
[search appendString:word];
|
||||||
|
else
|
||||||
|
[search appendFormat:MGMCWordS, word];
|
||||||
|
} else {
|
||||||
|
quote = [word hasPrefix:MGMCQoute];
|
||||||
|
if (quote) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i==0)
|
||||||
|
[search appendFormat:MGMCWordSA, word];
|
||||||
|
else {
|
||||||
|
if ([word hasPrefix:MGMCNEAR] || [word isEqual:MGMCAND] || [word isEqual:MGMCOR] || [word isEqual:MGMCNOT]) {
|
||||||
|
[search appendFormat:MGMCWordS, word];
|
||||||
|
} else {
|
||||||
|
[search appendFormat:MGMCWordSSA, word];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = [contactsConnection query:@"SELECT COUNT(docid) AS count FROM contacts WHERE contacts MATCH %@", search];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSNumber *count = [[[result nextRow] objectForKey:@"count"] copy];
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return [count autorelease];
|
||||||
|
}
|
||||||
|
- (NSArray *)contactsMatching:(NSString *)theString page:(int)thePage {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSMutableArray *contactsArray = [NSMutableArray array];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *string = [theString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
MGMLiteResult *result;
|
||||||
|
if (thePage==0) thePage = 1;
|
||||||
|
long long int page = (thePage*maxResults)-maxResults;
|
||||||
|
if (theString==nil || [string isEqual:@""]) {
|
||||||
|
result = [contactsConnection query:@"SELECT docid, * FROM contacts ORDER BY company, name LIMIT %qi, %i", page, maxResults];
|
||||||
|
} else {
|
||||||
|
if ([string isPhone]) {
|
||||||
|
NSString *search = [NSString stringWithFormat:MGMCNum, [[string removePhoneWhiteSpace] littersToNumbers]];
|
||||||
|
result = [contactsConnection query:@"SELECT docid, * FROM contacts WHERE number LIKE %@ ORDER BY company, name LIMIT %qi, %i", search, page, maxResults];
|
||||||
|
} else {
|
||||||
|
NSArray *words = [string componentsSeparatedByString:@" "];
|
||||||
|
NSMutableString *search = [NSMutableString string];
|
||||||
|
BOOL quote = NO;
|
||||||
|
for (int i=0; i<[words count]; i++) {
|
||||||
|
NSString *word = [words objectAtIndex:i];
|
||||||
|
if (quote) {
|
||||||
|
quote = ![word hasSuffix:MGMCQoute];
|
||||||
|
if (i==0)
|
||||||
|
[search appendString:word];
|
||||||
|
else
|
||||||
|
[search appendFormat:MGMCWordS, word];
|
||||||
|
} else {
|
||||||
|
quote = [word hasPrefix:MGMCQoute];
|
||||||
|
if (quote) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i==0)
|
||||||
|
[search appendFormat:MGMCWordSA, word];
|
||||||
|
else {
|
||||||
|
if ([word hasPrefix:MGMCNEAR] || [word isEqual:MGMCAND] || [word isEqual:MGMCOR] || [word isEqual:MGMCNOT]) {
|
||||||
|
[search appendFormat:MGMCWordS, word];
|
||||||
|
} else {
|
||||||
|
[search appendFormat:MGMCWordSSA, word];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = [contactsConnection query:@"SELECT docid, *, offsets(contacts) AS offset FROM contacts WHERE contacts MATCH %@ ORDER BY offset LIMIT %qi, %i", search, page, maxResults];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSDictionary *contact = nil;
|
||||||
|
while ((contact=[result nextRow])!=nil) {
|
||||||
|
[contactsArray addObject:contact];
|
||||||
|
}
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return contactsArray;
|
||||||
|
}
|
||||||
|
- (NSArray *)contactCompletionsMatching:(NSString *)theString {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSMutableArray *completions = [NSMutableArray array];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *string = [theString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
if (theString==nil || [string isEqual:@""]) {
|
||||||
|
[pool drain];
|
||||||
|
return completions;
|
||||||
|
} else {
|
||||||
|
if ([string isPhone]) {
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
|
NSString *search = [NSString stringWithFormat:@"%@%%", (i==0 ? [string phoneFormat] : [string phoneFormatAreaCode:[delegate areaCode]])];
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT docid, * FROM contacts WHERE number LIKE %@ ORDER BY company, name LIMIT %i", search, maxResults];
|
||||||
|
|
||||||
|
NSDictionary *contact = nil;
|
||||||
|
while ((contact=[result nextRow])!=nil) {
|
||||||
|
NSString *completion = nil;
|
||||||
|
NSString *number = [contact objectForKey:MGMCNumber];
|
||||||
|
if (i==0) {
|
||||||
|
if (![string hasPrefix:@"+1"] && ![string hasPrefix:@"011"]) {
|
||||||
|
if ([number hasPrefix:@"+1"])
|
||||||
|
number = [number substringFromIndex:2];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
number = [number substringFromIndex:5];
|
||||||
|
}
|
||||||
|
if ([contact objectForKey:MGMCName]!=nil && ![[contact objectForKey:MGMCName] isEqual:@""]) {
|
||||||
|
completion = [NSString stringWithFormat:MGMCCNumber, number, [contact objectForKey:MGMCName]];
|
||||||
|
} else if ([contact objectForKey:MGMCCompany]!=nil && ![[contact objectForKey:MGMCCompany] isEqual:@""]) {
|
||||||
|
completion = [NSString stringWithFormat:MGMCCNumber, number, [contact objectForKey:MGMCCompany]];
|
||||||
|
} else {
|
||||||
|
completion = number;
|
||||||
|
}
|
||||||
|
[completions addObject:completion];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSArray *words = [string componentsSeparatedByString:@" "];
|
||||||
|
NSMutableString *search = [NSMutableString string];
|
||||||
|
for (int i=0; i<[words count]; i++) {
|
||||||
|
NSString *word = [words objectAtIndex:i];
|
||||||
|
if (i==0)
|
||||||
|
[search appendFormat:MGMCWordSA, word];
|
||||||
|
else {
|
||||||
|
[search appendFormat:MGMCWordSSA, word];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT docid, *, offsets(contacts) AS offset FROM contacts WHERE contacts MATCH %@ ORDER BY offset LIMIT %i", search, maxResults];
|
||||||
|
|
||||||
|
NSDictionary *contact = nil;
|
||||||
|
while ((contact=[result nextRow])!=nil) {
|
||||||
|
NSString *completion = nil;
|
||||||
|
if (([contact objectForKey:MGMCName]!=nil && ![[contact objectForKey:MGMCName] isEqual:@""]) || ([contact objectForKey:MGMCCompany]!=nil && ![[contact objectForKey:MGMCCompany] isEqual:@""])) {
|
||||||
|
NSArray *words = [string componentsSeparatedByString:@" "];
|
||||||
|
NSString *name = nil;
|
||||||
|
if ([contact objectForKey:MGMCName]!=nil && ![[contact objectForKey:MGMCName] isEqual:@""])
|
||||||
|
name = [contact objectForKey:MGMCName];
|
||||||
|
else
|
||||||
|
name = [contact objectForKey:MGMCCompany];
|
||||||
|
if (![name hasPrefix:[words objectAtIndex:0]]) {
|
||||||
|
NSMutableArray *nameArray = [NSMutableArray arrayWithArray:[name componentsSeparatedByString:@" "]];
|
||||||
|
for (int i=0; i<[nameArray count]; i++) {
|
||||||
|
if ([[nameArray objectAtIndex:i] hasPrefix:[words objectAtIndex:0]]) {
|
||||||
|
name = [nameArray objectAtIndex:i];
|
||||||
|
[nameArray removeObjectAtIndex:i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<[nameArray count]; i++) {
|
||||||
|
name = [name stringByAppendingFormat:MGMCWordS, [nameArray objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completion = [NSString stringWithFormat:@"%@ <%@>", name, [[contact objectForKey:MGMCNumber] readableNumber]];
|
||||||
|
} else {
|
||||||
|
completion = [[contact objectForKey:MGMCNumber] readableNumber];
|
||||||
|
}
|
||||||
|
[completions addObject:completion];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)contactWithID:(NSNumber *)theID {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
return [[contactsConnection query:@"SELECT docid, * FROM contacts WHERE docid = %@", theID] nextRow];
|
||||||
|
}
|
||||||
|
- (NSData *)photoDataForNumber:(NSString *)theNumber {
|
||||||
|
NSDictionary *contact = [[contactsConnection query:@"SELECT photo FROM contacts WHERE number = %@ AND photo NOT NULL", theNumber] nextRow];
|
||||||
|
if (contact!=nil)
|
||||||
|
return [contact objectForKey:MGMCPhoto];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (NSString *)cachedPhotoForNumber:(NSString *)theNumber {
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
if ([delegate respondsToSelector:@selector(userNumber)] && [[delegate userNumber] isEqual:theNumber]) {
|
||||||
|
if (![manager fileExistsAtPath:[[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]]]) {
|
||||||
|
NSData *photo = [MGMAddressBook userPhotoData];
|
||||||
|
if (photo!=nil) {
|
||||||
|
[photo writeToFile:[[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]] atomically:YES];
|
||||||
|
return [[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return [[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (![manager fileExistsAtPath:[[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]]]) {
|
||||||
|
NSData *photo = [self photoDataForNumber:theNumber];
|
||||||
|
if (photo!=nil) {
|
||||||
|
[photo writeToFile:[[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]] atomically:YES];
|
||||||
|
return [[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return [[MGMUser cachePath] stringByAppendingPathComponent:[theNumber stringByAppendingPathExtension:MGMTiffExt]];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (NSString *)nameForNumber:(NSString *)theNumber {
|
||||||
|
NSDictionary *contact = [[contactsConnection query:@"SELECT name, company FROM contacts WHERE number = %@ AND (name != '' OR company != '')", theNumber] nextRow];
|
||||||
|
if (contact!=nil) {
|
||||||
|
if (![[contact objectForKey:MGMCName] isEqual:@""])
|
||||||
|
return [contact objectForKey:MGMCName];
|
||||||
|
else if (![[contact objectForKey:MGMCCompany] isEqual:@""])
|
||||||
|
return [contact objectForKey:MGMCCompany];
|
||||||
|
}
|
||||||
|
return [theNumber readableNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)groups {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSMutableArray *groupsArray = [NSMutableArray array];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT * FROM groups ORDER BY name"];
|
||||||
|
NSDictionary *group = nil;
|
||||||
|
while ((group=[result nextRow])!=nil) {
|
||||||
|
[groupsArray addObject:group];
|
||||||
|
}
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return groupsArray;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)groupWithID:(NSNumber *)theID {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
return [[contactsConnection query:@"SELECT * FROM groups WHERE docid = %@", theID] nextRow];
|
||||||
|
}
|
||||||
|
- (NSNumber *)membersCountOfGroup:(NSDictionary *)theGroup {
|
||||||
|
return [self membersCountOfGroupID:[theGroup objectForKey:MGMCDocID]];
|
||||||
|
}
|
||||||
|
- (NSNumber *)membersCountOfGroupID:(NSNumber *)theGroup {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT COUNT(docid) AS count FROM groupMembers WHERE groupid = %@", theGroup];
|
||||||
|
NSNumber *count = [[[result nextRow] objectForKey:@"count"] copy];
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return [count autorelease];
|
||||||
|
}
|
||||||
|
- (NSArray *)membersOfGroup:(NSDictionary *)theGroup {
|
||||||
|
return [self membersOfGroupID:[theGroup objectForKey:MGMCDocID]];
|
||||||
|
}
|
||||||
|
- (NSArray *)membersOfGroupID:(NSNumber *)theGroup {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSMutableArray *memebersArray = [NSMutableArray array];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT * FROM groupMembers WHERE groupid = %@", theGroup];
|
||||||
|
NSDictionary *member = nil;
|
||||||
|
while ((member=[result nextRow])!=nil) {
|
||||||
|
NSDictionary *contact = [self contactWithID:[member objectForKey:MGMCContactID]];
|
||||||
|
if (contact!=nil) {
|
||||||
|
[memebersArray addObject:contact];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return memebersArray;
|
||||||
|
}
|
||||||
|
- (NSArray *)groupsOfContact:(NSDictionary *)theContact {
|
||||||
|
if (contactsConnection==nil)
|
||||||
|
return nil;
|
||||||
|
[contactsLock lock];
|
||||||
|
NSMutableArray *groupsArray = [NSMutableArray array];
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMLiteResult *result = [contactsConnection query:@"SELECT * FROM groupMembers WHERE contactid = %@", [theContact objectForKey:MGMCDocID]];
|
||||||
|
NSDictionary *groupMember = nil;
|
||||||
|
while ((groupMember=[result nextRow])!=nil) {
|
||||||
|
NSDictionary *group = [self groupWithID:[groupMember objectForKey:MGMCGroupID]];
|
||||||
|
if (group!=nil)
|
||||||
|
[groupsArray addObject:group];
|
||||||
|
}
|
||||||
|
[contactsLock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return groupsArray;
|
||||||
|
}
|
||||||
|
@end
|
54
Classes/VoiceBase/AddressBook/MGMContactsProtocol.h
Normal file
54
Classes/VoiceBase/AddressBook/MGMContactsProtocol.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// MGMAddressBookProtocol.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#else
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern NSString * const MGMCRecallError;
|
||||||
|
extern NSString * const MGMCRecallSender;
|
||||||
|
|
||||||
|
extern NSString * const MGMCName;
|
||||||
|
extern NSString * const MGMCCompany;
|
||||||
|
extern NSString * const MGMCNumber;
|
||||||
|
extern NSString * const MGMCLabel;
|
||||||
|
extern NSString * const MGMCPhoto;
|
||||||
|
extern NSString * const MGMCDocID;
|
||||||
|
extern NSString * const MGMCGroupID;
|
||||||
|
extern NSString * const MGMCContactID;
|
||||||
|
|
||||||
|
extern NSString * const MGMCGoogleContactsUser;
|
||||||
|
|
||||||
|
extern const int MGMABPhotoSize;
|
||||||
|
|
||||||
|
@class MGMUser;
|
||||||
|
|
||||||
|
@protocol MGMContactsProtocol <NSObject>
|
||||||
|
- (id)initWithUser:(MGMUser *)theUser;
|
||||||
|
- (void)stop;
|
||||||
|
- (void)getContacts:(id)sender;
|
||||||
|
- (void)getGroups:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MGMContactsDelegate <NSObject>
|
||||||
|
- (void)gotContact:(NSDictionary *)theContact;
|
||||||
|
- (void)doneGettingContacts;
|
||||||
|
- (void)contactsError:(NSError *)theError;
|
||||||
|
- (void)gotGroup:(NSString *)theName withMembers:(NSArray *)theMembers;
|
||||||
|
- (void)doneGettingGroups;
|
||||||
|
- (void)groupsError:(NSError *)theError;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MGMContactsOwnerDelegate <NSObject>
|
||||||
|
- (MGMUser *)user;
|
||||||
|
- (NSString *)areaCode;
|
||||||
|
- (NSString *)userNumber;
|
||||||
|
- (void)updatedContacts;
|
||||||
|
@end
|
25
Classes/VoiceBase/AddressBook/MGMContactsProtocol.m
Normal file
25
Classes/VoiceBase/AddressBook/MGMContactsProtocol.m
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// MGMAddressBookProtocol.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMContactsProtocol.h"
|
||||||
|
|
||||||
|
NSString * const MGMCRecallError = @"com.MrGeckosMedia.MGMContacts.AlreadyCalled";
|
||||||
|
NSString * const MGMCRecallSender = @"sender";
|
||||||
|
|
||||||
|
NSString * const MGMCName = @"name";
|
||||||
|
NSString * const MGMCCompany = @"company";
|
||||||
|
NSString * const MGMCNumber = @"number";
|
||||||
|
NSString * const MGMCLabel = @"label";
|
||||||
|
NSString * const MGMCPhoto = @"photo";
|
||||||
|
NSString * const MGMCDocID = @"docid";
|
||||||
|
NSString * const MGMCGroupID = @"groupid";
|
||||||
|
NSString * const MGMCContactID = @"contactid";
|
||||||
|
|
||||||
|
NSString * const MGMCGoogleContactsUser = @"MGMCGoogleContactsUser";
|
||||||
|
|
||||||
|
const int MGMABPhotoSize = 64;
|
43
Classes/VoiceBase/AddressBook/MGMGoogleContacts.h
Normal file
43
Classes/VoiceBase/AddressBook/MGMGoogleContacts.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// MGMGoogleContacts.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMUser, MGMURLConnectionManager;
|
||||||
|
@protocol MGMContactsDelegate, MGMContactsOwnerDelegate;
|
||||||
|
|
||||||
|
extern NSString * const MGMGCAuthenticationURL;
|
||||||
|
extern NSString * const MGMGCAuthenticationBody;
|
||||||
|
extern NSString * const MGMGCUseragent;
|
||||||
|
|
||||||
|
@interface MGMGoogleContacts : NSObject {
|
||||||
|
id<MGMContactsOwnerDelegate> delegate;
|
||||||
|
MGMUser *user;
|
||||||
|
MGMURLConnectionManager *connectionManager;
|
||||||
|
BOOL isAuthenticating;
|
||||||
|
NSString *authenticationString;
|
||||||
|
NSMutableArray *afterAuthentication;
|
||||||
|
NSMutableArray *contacts;
|
||||||
|
NSArray *contactEntries;
|
||||||
|
unsigned int contactsIndex;
|
||||||
|
NSData *contactPhoto;
|
||||||
|
BOOL shouldStop;
|
||||||
|
BOOL gettingContacts;
|
||||||
|
BOOL gettingGroups;
|
||||||
|
id<MGMContactsDelegate> contactsSender;
|
||||||
|
id<MGMContactsDelegate> groupsSender;
|
||||||
|
NSTimer *releaseTimer;
|
||||||
|
}
|
||||||
|
- (id)initWithDelegate:(id)theDelegate;
|
||||||
|
+ (NSDictionary *)dictionaryWithData:(NSData *)theData;
|
||||||
|
- (MGMUser *)user;
|
||||||
|
- (void)getContacts:(id)sender;
|
||||||
|
- (void)parseContact;
|
||||||
|
- (void)continueContacts;
|
||||||
|
- (void)getGroups:(id)sender;
|
||||||
|
@end
|
303
Classes/VoiceBase/AddressBook/MGMGoogleContacts.m
Normal file
303
Classes/VoiceBase/AddressBook/MGMGoogleContacts.m
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
//
|
||||||
|
// MGMGoogleContacts.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/17/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMGoogleContacts.h"
|
||||||
|
#import "MGMContactsProtocol.h"
|
||||||
|
#import "MGMInstance.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMGCAuthenticationURL = @"https://www.google.com/accounts/ClientLogin";
|
||||||
|
NSString * const MGMGCAuthenticationBody = @"Email=%@&Passwd=%@&source=MrGeckosMedia-VoiceBase-0.1&service=cp&accountType=HOSTED_OR_GOOGLE";
|
||||||
|
NSString * const MGMGCUseragent = @"VoiceBase/0.1";
|
||||||
|
|
||||||
|
NSString * const MGMGCContactsURL = @"https://www.google.com/m8/feeds/contacts/default/full?max-results=10000";
|
||||||
|
NSString * const MGMGCGroupsURL = @"https://www.google.com/m8/feeds/groups/default/full?max-results=10000";
|
||||||
|
NSString * const MGMGCAuthorization = @"Authorization";
|
||||||
|
|
||||||
|
const BOOL MGMGoogleContactsInvisible = YES;
|
||||||
|
|
||||||
|
@implementation MGMGoogleContacts
|
||||||
|
- (id)initWithDelegate:(id)theDelegate {
|
||||||
|
if (self = [super init]) {
|
||||||
|
gettingContacts = NO;
|
||||||
|
delegate = theDelegate;
|
||||||
|
user = [[MGMUser userWithID:[[delegate user] settingForKey:MGMCGoogleContactsUser]] retain];
|
||||||
|
if (user==nil)
|
||||||
|
user = [[delegate user] retain];
|
||||||
|
NSString *username = [user settingForKey:MGMUserName];
|
||||||
|
if (![username containsString:@"@"])
|
||||||
|
username = [username stringByAppendingString:@"@gmail.com"];
|
||||||
|
NSURLCredential *credentials = [NSURLCredential credentialWithUser:username password:[user password] persistence:NSURLCredentialPersistenceForSession];
|
||||||
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[user cookieStorage]] retain];
|
||||||
|
[connectionManager setCredentials:credentials];
|
||||||
|
[connectionManager setCustomUseragent:MGMGCUseragent];
|
||||||
|
isAuthenticating = YES;
|
||||||
|
afterAuthentication = [NSMutableArray new];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCAuthenticationURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:MGMGCAuthenticationBody, [username addPercentEscapes], [[user password] addPercentEscapes]] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(authentication:didFailWithError:) didFinish:@selector(authenticationDidFinish:) invisible:MGMGoogleContactsInvisible object:nil];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (user!=nil)
|
||||||
|
[user release];
|
||||||
|
if (connectionManager!=nil) {
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
[connectionManager release];
|
||||||
|
}
|
||||||
|
if (authenticationString!=nil)
|
||||||
|
[authenticationString release];
|
||||||
|
if (afterAuthentication!=nil)
|
||||||
|
[afterAuthentication release];
|
||||||
|
if (releaseTimer!=nil)
|
||||||
|
[releaseTimer fire];
|
||||||
|
if (contactEntries!=nil)
|
||||||
|
[contactEntries release];
|
||||||
|
if (contactPhoto!=nil)
|
||||||
|
[contactPhoto release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
- (void)authentication:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
||||||
|
}
|
||||||
|
+ (NSDictionary *)dictionaryWithData:(NSData *)theData {
|
||||||
|
NSString *string = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
|
||||||
|
NSArray *values = [string componentsSeparatedByString:@"\n"];
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
for (int i=0; i<[values count]; i++) {
|
||||||
|
if (![[values objectAtIndex:i] isEqual:@""]) {
|
||||||
|
NSMutableArray *info = [NSMutableArray arrayWithArray:[[values objectAtIndex:i] componentsSeparatedByString:@"="]];
|
||||||
|
NSString *key = [info objectAtIndex:0];
|
||||||
|
[info removeObjectAtIndex:0];
|
||||||
|
NSString *value = [info componentsJoinedByString:@"="];
|
||||||
|
[dictionary setObject:value forKey:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[string release];
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
- (void)authenticationDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSDictionary *info = [MGMGoogleContacts dictionaryWithData:[theInfo objectForKey:MGMConnectionData]];
|
||||||
|
if (authenticationString!=nil) [authenticationString release];
|
||||||
|
authenticationString = [[NSString stringWithFormat:@"GoogleLogin auth=%@", [info objectForKey:@"Auth"]] retain];
|
||||||
|
isAuthenticating = NO;
|
||||||
|
while ([afterAuthentication count]!=0) {
|
||||||
|
[[afterAuthentication objectAtIndex:0] invoke];
|
||||||
|
[afterAuthentication removeObjectAtIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (MGMUser *)user {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)stop {
|
||||||
|
shouldStop = YES;
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
if (gettingContacts || gettingGroups)
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
shouldStop = NO;
|
||||||
|
}
|
||||||
|
- (void)getContacts:(id)sender {
|
||||||
|
if (isAuthenticating) {
|
||||||
|
SEL selector = @selector(getContacts:);
|
||||||
|
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setTarget:self];
|
||||||
|
[invocation setArgument:&sender atIndex:2];
|
||||||
|
[afterAuthentication addObject:invocation];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gettingContacts) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithObject:contactsSender forKey:MGMCRecallSender];
|
||||||
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
||||||
|
if ([sender respondsToSelector:@selector(contactsError:)]) [sender contactsError:error];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gettingContacts = YES;
|
||||||
|
contactsSender = sender;
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCContactsURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
|
||||||
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(contacts:didFailWithError:) didFinish:@selector(contactsDidFinish:) invisible:MGMGoogleContactsInvisible object:nil];
|
||||||
|
}
|
||||||
|
- (void)contacts:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
gettingContacts = NO;
|
||||||
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
||||||
|
if ([contactsSender respondsToSelector:@selector(contactsError:)]) [contactsSender contactsError:theError];
|
||||||
|
}
|
||||||
|
- (void)contactsDidFinish:(NSDictionary *)theInfo {
|
||||||
|
if (releaseTimer!=nil) {
|
||||||
|
[releaseTimer invalidate];
|
||||||
|
[releaseTimer release];
|
||||||
|
releaseTimer = nil;
|
||||||
|
}
|
||||||
|
if (contacts!=nil) [contacts release];
|
||||||
|
contacts = [NSMutableArray new];
|
||||||
|
NSXMLElement *XML = [[[[NSXMLDocument alloc] initWithData:[theInfo objectForKey:MGMConnectionData] options:NSXMLDocumentTidyXML error:nil] autorelease] rootElement];
|
||||||
|
contactEntries = [[XML elementsForName:@"entry"] retain];
|
||||||
|
contactsIndex=0;
|
||||||
|
[self continueContacts];
|
||||||
|
}
|
||||||
|
- (void)photo:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSLog(@"MGMGoogleContacts Photo Error: %@", theError);
|
||||||
|
[self parseContact];
|
||||||
|
contactsIndex++;
|
||||||
|
[self continueContacts];
|
||||||
|
}
|
||||||
|
- (void)photoDidFinish:(NSDictionary *)theInfo {
|
||||||
|
contactPhoto = [[theInfo objectForKey:MGMConnectionData] retain];
|
||||||
|
[self parseContact];
|
||||||
|
contactsIndex++;
|
||||||
|
[self continueContacts];
|
||||||
|
}
|
||||||
|
- (void)parseContact {
|
||||||
|
if (shouldStop) return;
|
||||||
|
NSXMLElement *entry = [contactEntries objectAtIndex:contactsIndex];
|
||||||
|
NSArray *titles = [entry elementsForName:@"title"];
|
||||||
|
NSString *name = @"";
|
||||||
|
if ([titles count]!=0)
|
||||||
|
name = [[titles objectAtIndex:0] stringValue];
|
||||||
|
NSArray *organizations = [entry elementsForName:@"gd:organization"];
|
||||||
|
NSString *company = @"";
|
||||||
|
if ([organizations count]!=0) {
|
||||||
|
NSArray *organizationName = [[organizations objectAtIndex:0] elementsForName:@"gd:orgName"];
|
||||||
|
if ([organizationName count]!=0)
|
||||||
|
company = [[organizationName objectAtIndex:0] stringValue];
|
||||||
|
}
|
||||||
|
NSArray *phones = [entry elementsForName:@"gd:phoneNumber"];
|
||||||
|
NSData *image = nil;
|
||||||
|
if ([phones count]>0) {
|
||||||
|
if (contactPhoto!=nil) {
|
||||||
|
image = [contactPhoto resizeTo:NSMakeSize(MGMABPhotoSize, MGMABPhotoSize)];
|
||||||
|
[contactPhoto release];
|
||||||
|
contactPhoto = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int p=0; p<[phones count]; p++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
NSXMLElement *phone = [phones objectAtIndex:p];
|
||||||
|
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
|
||||||
|
[contact setObject:name forKey:MGMCName];
|
||||||
|
[contact setObject:company forKey:MGMCCompany];
|
||||||
|
if (delegate!=nil)
|
||||||
|
[contact setObject:[[phone stringValue] phoneFormatWithAreaCode:[delegate areaCode]] forKey:MGMCNumber];
|
||||||
|
else
|
||||||
|
[contact setObject:[[phone stringValue] phoneFormat] forKey:MGMCNumber];
|
||||||
|
NSString *label = @"";
|
||||||
|
NSXMLNode *labelXML = [phone attributeForName:@"label"];
|
||||||
|
if (labelXML==nil) {
|
||||||
|
NSXMLNode *rel = [phone attributeForName:@"rel"];
|
||||||
|
if (rel!=nil) {
|
||||||
|
NSString *string = [rel stringValue];
|
||||||
|
NSRange range = [string rangeOfString:@"#"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
label = [string substringFromIndex:range.location+range.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = [labelXML stringValue];
|
||||||
|
}
|
||||||
|
[contact setObject:[label capitalizedString] forKey:MGMCLabel];
|
||||||
|
[contacts addObject:[[contact copy] autorelease]];
|
||||||
|
if (image!=nil)
|
||||||
|
[contact setObject:image forKey:MGMCPhoto];
|
||||||
|
if ([contactsSender respondsToSelector:@selector(gotContact:)]) [contactsSender gotContact:contact];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)continueContacts {
|
||||||
|
for (; contactsIndex<[contactEntries count]; contactsIndex++) {
|
||||||
|
if (shouldStop) break;
|
||||||
|
NSXMLElement *entry = [contactEntries objectAtIndex:contactsIndex];
|
||||||
|
NSArray *phones = [entry elementsForName:@"gd:phoneNumber"];
|
||||||
|
if ([phones count]!=0) {
|
||||||
|
NSArray *links = [entry elementsForName:@"link"];
|
||||||
|
BOOL loadingPhoto = NO;
|
||||||
|
for (int i=0; i<[links count]; i++) {
|
||||||
|
NSXMLNode *rel = [[links objectAtIndex:i] attributeForName:@"rel"];
|
||||||
|
if (rel!=nil) {
|
||||||
|
if ([[rel stringValue] containsString:@"#photo"]) {
|
||||||
|
NSString *url = [[[links objectAtIndex:i] attributeForName:@"href"] stringValue];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
|
||||||
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(photo:didFailWithError:) didFinish:@selector(photoDidFinish:) invisible:YES object:nil];
|
||||||
|
loadingPhoto = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loadingPhoto)
|
||||||
|
[self parseContact];
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contactsIndex>=[contactEntries count]) {
|
||||||
|
releaseTimer = [[NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(releaseContacts) userInfo:nil repeats:NO] retain];
|
||||||
|
if ([contactsSender respondsToSelector:@selector(doneGettingContacts)]) [contactsSender doneGettingContacts];
|
||||||
|
[contactEntries release];
|
||||||
|
contactEntries = nil;
|
||||||
|
contactsSender = nil;
|
||||||
|
gettingContacts = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)releaseContacts {
|
||||||
|
if (releaseTimer!=nil) {
|
||||||
|
[releaseTimer invalidate];
|
||||||
|
[releaseTimer release];
|
||||||
|
releaseTimer = nil;
|
||||||
|
}
|
||||||
|
if (contacts!=nil) {
|
||||||
|
[contacts release];
|
||||||
|
contacts = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getGroups:(id)sender {
|
||||||
|
if (isAuthenticating) {
|
||||||
|
SEL selector = @selector(getGroups:);
|
||||||
|
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setTarget:self];
|
||||||
|
[invocation setArgument:&sender atIndex:2];
|
||||||
|
[afterAuthentication addObject:invocation];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gettingGroups) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithObject:groupsSender forKey:MGMCRecallSender];
|
||||||
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
||||||
|
if ([sender respondsToSelector:@selector(groupsError:)]) [sender groupsError:error];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([sender respondsToSelector:@selector(groupsError:)]) [sender groupsError:nil];
|
||||||
|
return;
|
||||||
|
gettingGroups = YES;
|
||||||
|
groupsSender = sender;
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCGroupsURL]];
|
||||||
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(groups:didFailWithError:) didFinish:@selector(groupsDidFinish:) invisible:MGMGoogleContactsInvisible object:nil];
|
||||||
|
}
|
||||||
|
- (void)groups:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
gettingGroups = NO;
|
||||||
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
||||||
|
}
|
||||||
|
- (void)groupsDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSXMLElement *XML = [[[[NSXMLDocument alloc] initWithData:[theInfo objectForKey:MGMConnectionData] options:NSXMLDocumentTidyXML error:nil] autorelease] rootElement];
|
||||||
|
NSLog(@"%@", XML);
|
||||||
|
gettingGroups = NO;
|
||||||
|
}
|
||||||
|
@end
|
77
Classes/VoiceBase/MGMAddons.h
Normal file
77
Classes/VoiceBase/MGMAddons.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// NSAddons.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 3/4/09.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#else
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <pjsua-lib/pjsua.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@interface NSString (MGMAddons)
|
||||||
|
+ (NSString *)stringWithSeconds:(int)theSeconds;
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
- (NSString *)flattenHTML;
|
||||||
|
#endif
|
||||||
|
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString;
|
||||||
|
- (BOOL)containsString:(NSString *)string;
|
||||||
|
|
||||||
|
- (NSString *)escapeSMS;
|
||||||
|
- (NSString *)filePath;
|
||||||
|
|
||||||
|
- (NSString *)littersToNumbers;
|
||||||
|
- (NSString *)removePhoneWhiteSpace;
|
||||||
|
- (BOOL)isPhone;
|
||||||
|
- (BOOL)isPhoneComplete;
|
||||||
|
- (NSString *)phoneFormatWithAreaCode:(NSString *)theAreaCode;
|
||||||
|
- (NSString *)phoneFormatAreaCode:(NSString *)theAreaCode;
|
||||||
|
- (NSString *)phoneFormat;
|
||||||
|
- (NSString *)readableNumber;
|
||||||
|
- (NSString *)areaCode;
|
||||||
|
- (NSString *)areaCodeLocation;
|
||||||
|
|
||||||
|
- (NSString *)addPercentEscapes;
|
||||||
|
|
||||||
|
- (NSString *)truncateForWidth:(double)theWidth attributes:(NSDictionary *)theAttributes;
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
NSComparisonResult dateSort(NSDictionary *info1, NSDictionary *info2, void *context);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- (BOOL)isIPAddress;
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
+ (NSString *)stringWithPJString:(pj_str_t)pjString;
|
||||||
|
- (pj_str_t)PJString;
|
||||||
|
#endif
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSData (MGMAddons)
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
|
||||||
|
#else
|
||||||
|
- (NSData *)resizeTo:(NSSize)theSize;
|
||||||
|
#endif
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol NSFileManagerProtocol <NSObject>
|
||||||
|
- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error;
|
||||||
|
- (BOOL)createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes;
|
||||||
|
|
||||||
|
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;
|
||||||
|
- (BOOL)removeFileAtPath:(NSString *)path handler:(id)handler;
|
||||||
|
|
||||||
|
- (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
|
||||||
|
- (BOOL)copyPath:(NSString *)source toPath:(NSString *)destination handler:(id)handler;
|
||||||
|
|
||||||
|
- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
|
||||||
|
- (BOOL)movePath:(NSString *)source toPath:(NSString *)destination handler:(id)handler;
|
||||||
|
@end
|
1385
Classes/VoiceBase/MGMAddons.m
Normal file
1385
Classes/VoiceBase/MGMAddons.m
Normal file
File diff suppressed because it is too large
Load Diff
111
Classes/VoiceBase/MGMInbox.h
Normal file
111
Classes/VoiceBase/MGMInbox.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// MGMInbox.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#else
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@class MGMInstance, MGMURLConnectionManager;
|
||||||
|
|
||||||
|
#define MGMInboxDebug 0
|
||||||
|
|
||||||
|
extern NSString * const MGMIDelegate;
|
||||||
|
extern NSString * const MGMIDidReceiveInfo;
|
||||||
|
extern NSString * const MGMIDidFinish;
|
||||||
|
extern NSString * const MGMIDidFailWithError;
|
||||||
|
extern NSString * const MGMIEntries;
|
||||||
|
extern NSString * const MGMIPhoneNumbers;
|
||||||
|
extern NSString * const MGMIMessage;
|
||||||
|
|
||||||
|
extern NSString * const MGMIVoiceMailDownloadURL;
|
||||||
|
|
||||||
|
extern NSString * const MGMIPhoneNumber;
|
||||||
|
extern NSString * const MGMIID;
|
||||||
|
extern NSString * const MGMIUniqueId;
|
||||||
|
extern NSString * const MGMIText;
|
||||||
|
extern NSString * const MGMIYou;
|
||||||
|
extern NSString * const MGMITime;
|
||||||
|
extern NSString * const MGMIStartTime;
|
||||||
|
extern NSString * const MGMIInfo;
|
||||||
|
extern NSString * const MGMIMessages;
|
||||||
|
extern NSString * const MGMIUseful;
|
||||||
|
extern NSString * const MGMIRead;
|
||||||
|
extern NSString * const MGMIType;
|
||||||
|
extern NSString * const MGMIStarred;
|
||||||
|
extern NSString * const MGMISpam;
|
||||||
|
extern NSString * const MGMITrash;
|
||||||
|
|
||||||
|
extern const int MGMIMissedType;
|
||||||
|
extern const int MGMIReceivedType;
|
||||||
|
extern const int MGMIVoicemailType;
|
||||||
|
extern const int MGMIRecordedType;
|
||||||
|
extern const int MGMIPlaced;
|
||||||
|
extern const int MGMISMSIn;
|
||||||
|
extern const int MGMISMSOut;
|
||||||
|
|
||||||
|
@interface MGMInbox : NSObject {
|
||||||
|
MGMInstance *instance;
|
||||||
|
MGMURLConnectionManager *connectionManager;
|
||||||
|
}
|
||||||
|
+ (id)inboxWithInstance:(MGMInstance *)theInstance;
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance;
|
||||||
|
|
||||||
|
- (void)stop;
|
||||||
|
|
||||||
|
- (void)getInboxForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getInboxForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getStarredForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getStarredForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getSpamForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getSpamForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getTrashForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getTrashForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getVoicemailForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getVoicemailForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getSMSForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getSMSForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getRecordedCallsForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getRecordedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getPlacedCallsForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getPlacedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getReceivedCallsForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getReceivedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)getMissedCallsForPage:(int)thePage delegate:(id)theDelegate;
|
||||||
|
- (void)getMissedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo;
|
||||||
|
|
||||||
|
- (void)retrieveURL:(NSString *)theURL page:(int)thePage info:(NSDictionary *)theInfo;
|
||||||
|
- (NSDictionary *)parseMessageWithHTML:(NSString *)theHTML info:(NSDictionary *)theInfo;
|
||||||
|
|
||||||
|
- (void)deleteEntriesForever:(NSArray *)theEntries delegate:(id)theDelegate;
|
||||||
|
- (void)deleteEntriesForever:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
- (void)deleteEntries:(NSArray *)theEntries delegate:(id)theDelegate;
|
||||||
|
- (void)deleteEntries:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
|
||||||
|
- (void)markEntries:(NSArray *)theEntries read:(BOOL)isRead delegate:(id)theDelegate;
|
||||||
|
- (void)markEntries:(NSArray *)theEntries read:(BOOL)isRead delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
|
||||||
|
- (void)reportEntries:(NSArray *)theEntries delegate:(id)theDelegate;
|
||||||
|
- (void)reportEntries:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
|
||||||
|
- (void)starEntries:(NSArray *)theEntries starred:(BOOL)isStarred delegate:(id)theDelegate;
|
||||||
|
- (void)starEntries:(NSArray *)theEntries starred:(BOOL)isStarred delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
|
||||||
|
- (void)sendMessage:(NSString *)theMessage phoneNumbers:(NSArray *)thePhoneNumbers smsID:(NSString *)theID delegate:(id)theDelegate;
|
||||||
|
- (void)sendMessage:(NSString *)theMessage phoneNumbers:(NSArray *)thePhoneNumbers smsID:(NSString *)theID delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
@end
|
574
Classes/VoiceBase/MGMInbox.m
Normal file
574
Classes/VoiceBase/MGMInbox.m
Normal file
@ -0,0 +1,574 @@
|
|||||||
|
//
|
||||||
|
// MGMInbox.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMInbox.h"
|
||||||
|
#import "MGMInstance.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMIDelegate = @"delegate";
|
||||||
|
NSString * const MGMIDidReceiveInfo = @"didReceiveInfo";
|
||||||
|
NSString * const MGMIDidFinish = @"didFinish";
|
||||||
|
NSString * const MGMIDidFailWithError = @"didFailWithError";
|
||||||
|
NSString * const MGMIEntries = @"entries";
|
||||||
|
NSString * const MGMIPhoneNumbers = @"phoneNumbers";
|
||||||
|
NSString * const MGMIMessage = @"message";
|
||||||
|
|
||||||
|
NSString * const MGMIInboxURL = @"https://www.google.com/voice/inbox/recent/";
|
||||||
|
NSString * const MGMIStarredURL = @"https://www.google.com/voice/inbox/recent/starred/";
|
||||||
|
NSString * const MGMIStarURL = @"https://www.google.com/voice/inbox/star/";
|
||||||
|
NSString * const MGMISpamURL = @"https://www.google.com/voice/inbox/recent/spam/";
|
||||||
|
NSString * const MGMITrashURL = @"https://www.google.com/voice/inbox/recent/trash/";
|
||||||
|
|
||||||
|
NSString * const MGMIVoiceMailURL = @"https://www.google.com/voice/inbox/recent/voicemail/";
|
||||||
|
NSString * const MGMIVoiceMailDownloadURL = @"https://www.google.com/voice/media/send_voicemail/%@";
|
||||||
|
NSString * const MGMISMSURL = @"https://www.google.com/voice/inbox/recent/sms/";
|
||||||
|
NSString * const MGMISMSSendURL = @"https://www.google.com/voice/sms/send/";
|
||||||
|
NSString * const MGMIRecordedURL = @"https://www.google.com/voice/inbox/recent/recorded/";
|
||||||
|
NSString * const MGMIPlacedURL = @"https://www.google.com/voice/inbox/recent/placed/";
|
||||||
|
NSString * const MGMIReceivedURL = @"https://www.google.com/voice/inbox/recent/received/";
|
||||||
|
NSString * const MGMIMissedURL = @"https://www.google.com/voice/inbox/recent/missed/";
|
||||||
|
|
||||||
|
NSString * const MGMIMarkURL = @"https://www.google.com/voice/inbox/mark/";
|
||||||
|
NSString * const MGMIDeleteURL = @"https://www.google.com/voice/inbox/deleteMessages/";
|
||||||
|
NSString * const MGMIDeleteForeverURL = @"https://www.google.com/voice/inbox/deleteForeverMessages/";
|
||||||
|
NSString * const MGMIReportURL = @"https://www.google.com/voice/inbox/spam/";
|
||||||
|
|
||||||
|
NSString * const MGMIPhoneNumber = @"phoneNumber";
|
||||||
|
NSString * const MGMIID = @"id";
|
||||||
|
NSString * const MGMIUniqueId = @"uniqueId";
|
||||||
|
NSString * const MGMIText = @"text";
|
||||||
|
NSString * const MGMIYou = @"you";
|
||||||
|
NSString * const MGMITime = @"time";
|
||||||
|
NSString * const MGMIStartTime = @"startTime";
|
||||||
|
NSString * const MGMIInfo = @"info";
|
||||||
|
NSString * const MGMIMessages = @"messages";
|
||||||
|
NSString * const MGMIUseful = @"useful";
|
||||||
|
NSString * const MGMIRead = @"isRead";
|
||||||
|
NSString * const MGMIType = @"type";
|
||||||
|
NSString * const MGMIStarred = @"star";
|
||||||
|
NSString * const MGMISpam = @"isSpam";
|
||||||
|
NSString * const MGMITrash = @"isTrash";
|
||||||
|
|
||||||
|
const int MGMIMissedType = 0;
|
||||||
|
const int MGMIReceivedType = 1;
|
||||||
|
const int MGMIVoicemailType = 2;
|
||||||
|
const int MGMIRecordedType = 4;
|
||||||
|
const int MGMIPlaced = 8;
|
||||||
|
const int MGMISMSIn = 10;
|
||||||
|
const int MGMISMSOut = 11;
|
||||||
|
|
||||||
|
NSString * const MGMIPage = @"%@?page=p%d";
|
||||||
|
|
||||||
|
const BOOL MGMInboxInvisible = YES;
|
||||||
|
|
||||||
|
@implementation MGMInbox
|
||||||
|
+ (id)inboxWithInstance:(MGMInstance *)theInstance {
|
||||||
|
return [[[self alloc] initWithInstance:theInstance] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance {
|
||||||
|
if (self = [super init]) {
|
||||||
|
instance = theInstance;
|
||||||
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[theInstance cookieStorage]] retain];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (connectionManager!=nil) {
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
[connectionManager release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stop {
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getInboxForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getInboxForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getInboxForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIInboxURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getStarredForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getStarredForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getStarredForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIStarredURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getSpamForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getSpamForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getSpamForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMISpamURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getTrashForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getTrashForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getTrashForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMITrashURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getVoicemailForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getVoicemailForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getVoicemailForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIVoiceMailURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getSMSForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getSMSForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getSMSForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMISMSURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getRecordedCallsForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getRecordedCallsForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getRecordedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIRecordedURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getPlacedCallsForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getPlacedCallsForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getPlacedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIPlacedURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getReceivedCallsForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getPlacedCallsForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getReceivedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIReceivedURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getMissedCallsForPage:(int)thePage delegate:(id)theDelegate {
|
||||||
|
[self getPlacedCallsForPage:thePage delegate:theDelegate didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)getMissedCallsForPage:(int)thePage delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didReceiveInfo:(SEL)didReceiveInfo {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didReceiveInfo!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didReceiveInfo) forKey:MGMIDidReceiveInfo];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[self retrieveURL:MGMIMissedURL page:thePage info:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)retrieveURL:(NSString *)theURL page:(int)thePage info:(NSDictionary *)theInfo {
|
||||||
|
NSString *url = nil;
|
||||||
|
if (thePage<=1)
|
||||||
|
url = theURL;
|
||||||
|
else
|
||||||
|
url = [NSString stringWithFormat:MGMIPage, theURL, thePage];
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will load %@", url);
|
||||||
|
#endif
|
||||||
|
[connectionManager connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] delegate:self didFailWithError:@selector(request:didFailWithError:) didFinish:@selector(requestDidFinish:) invisible:MGMInboxInvisible object:theInfo];
|
||||||
|
}
|
||||||
|
- (void)request:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSDictionary *info = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([info objectForKey:MGMIDidFailWithError]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([info objectForKey:MGMIDidFailWithError]);
|
||||||
|
id delegate = [info objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&theInfo atIndex:2];
|
||||||
|
[invocation setArgument:&theError atIndex:3];
|
||||||
|
[invocation setArgument:&instance atIndex:4];
|
||||||
|
[invocation invokeWithTarget:delegate];
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Error: %@", theError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Error: %@", theError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)requestDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSXMLElement *XML = [[[[NSXMLDocument alloc] initWithData:[theInfo objectForKey:MGMConnectionData] options:NSXMLDocumentTidyXML error:nil] autorelease] rootElement];
|
||||||
|
NSDictionary *infoDic = [[[[XML elementsForName:@"json"] objectAtIndex:0] stringValue] parseJSON];
|
||||||
|
NSDictionary *messagesInfo = [infoDic objectForKey:@"messages"];
|
||||||
|
NSArray *messagesInfoKeys = [messagesInfo allKeys];
|
||||||
|
NSXMLElement *html = [[[[NSXMLDocument alloc] initWithXMLString:[[[XML elementsForName:@"html"] objectAtIndex:0] stringValue] options:NSXMLDocumentTidyHTML error:nil] autorelease] rootElement];
|
||||||
|
NSArray *messages = [(NSXMLElement *)[html childAtIndex:1] elementsForName:@"div"];
|
||||||
|
NSMutableArray *info = [NSMutableArray array];
|
||||||
|
for (unsigned int i=0; i<[messages count]; i++) {
|
||||||
|
NSXMLElement *message = [messages objectAtIndex:i];
|
||||||
|
NSString *messageID = [[message attributeForName:MGMIID] stringValue];
|
||||||
|
if (messageID) {
|
||||||
|
for (unsigned int m=0; m<[messagesInfoKeys count]; m++) {
|
||||||
|
NSDictionary *messageInfo = [messagesInfo objectForKey:[messagesInfoKeys objectAtIndex:m]];
|
||||||
|
if ([[messageInfo objectForKey:MGMIID] isEqualToString:messageID]) {
|
||||||
|
NSMutableDictionary *thisInfo = [NSMutableDictionary dictionary];
|
||||||
|
[thisInfo setObject:[[messageInfo objectForKey:MGMIPhoneNumber] phoneFormatWithAreaCode:[instance userAreaCode]] forKey:MGMIPhoneNumber];
|
||||||
|
[thisInfo setObject:messageID forKey:MGMIID];
|
||||||
|
[thisInfo setObject:[NSDate dateWithTimeIntervalSince1970:[[NSDecimalNumber decimalNumberWithString:[messageInfo objectForKey:MGMIStartTime]] longLongValue]/1000] forKey:MGMITime];
|
||||||
|
[thisInfo setObject:[messageInfo objectForKey:MGMIRead] forKey:MGMIRead];
|
||||||
|
[thisInfo setObject:[messageInfo objectForKey:MGMIStarred] forKey:MGMIStarred];
|
||||||
|
[thisInfo setObject:[messageInfo objectForKey:MGMISpam] forKey:MGMISpam];
|
||||||
|
[thisInfo setObject:[messageInfo objectForKey:MGMITrash] forKey:MGMITrash];
|
||||||
|
|
||||||
|
[thisInfo setObject:[messageInfo objectForKey:MGMIType] forKey:MGMIType];
|
||||||
|
int type = [[thisInfo objectForKey:MGMIType] intValue];
|
||||||
|
if (type==MGMIVoicemailType) {
|
||||||
|
[thisInfo setObject:[NSNumber numberWithBool:[[message XMLString] containsString:@"gc-message-transcript-rate-up-active"]] forKey:MGMIUseful];
|
||||||
|
NSString *transcript = [[[[[message childAtIndex:0] nodesForXPath:[NSString stringWithFormat:@"/html[1]/body[1]/div[%d]/div[1]/div[2]/table[1]/tr[1]/td[3]/div[1]/table[1]/tr[2]/td[2]/table[1]/tr[2]/td[1]/div[1]/div[1]/table[1]/tr[1]/td[2]/div[1]/div[1]/table[1]/tr[1]/td[1]/div[1]", i+1] error:nil] objectAtIndex:0] stringValue] flattenHTML];
|
||||||
|
[thisInfo setObject:transcript forKey:MGMIText];
|
||||||
|
} else if (type==MGMISMSIn || type==MGMISMSOut) {
|
||||||
|
NSArray *messagesXML = [[message childAtIndex:0] nodesForXPath:[NSString stringWithFormat:@"/html[1]/body[1]/div[%d]/div[1]/div[2]/table[1]/tr[1]/td[3]/div[1]/table[1]/tr[2]/td[2]/table[1]/tr[2]/td[1]/div[1]/div[1]/table[1]/tr[1]/td[2]/div[1]/div[1]/div[1]/div", i+1] error:nil];
|
||||||
|
NSMutableArray *messagesArray = [NSMutableArray array];
|
||||||
|
for (unsigned int m=0; m<[messagesXML count]; m++) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *messageString = [[messagesXML objectAtIndex:m] XMLString];
|
||||||
|
if (![messageString hasPrefix:@"<div class=\"gc-message-sms-more\">"]) {
|
||||||
|
[messagesArray addObject:[self parseMessageWithHTML:messageString info:thisInfo]];
|
||||||
|
} else {
|
||||||
|
m++;
|
||||||
|
NSArray *moreMessages = [(NSXMLElement *)[messagesXML objectAtIndex:m] elementsForName:@"div"];
|
||||||
|
for (unsigned int ms=0; ms<[moreMessages count]; ms++) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *messageString = [[moreMessages objectAtIndex:ms] XMLString];
|
||||||
|
[messagesArray addObject:[self parseMessageWithHTML:messageString info:thisInfo]];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
[thisInfo setObject:messagesArray forKey:MGMIMessages];
|
||||||
|
}
|
||||||
|
|
||||||
|
[info addObject:thisInfo];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[info sortUsingFunction:dateSort context:nil];
|
||||||
|
|
||||||
|
NSDictionary *thisInfo = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([thisInfo objectForKey:MGMIDidReceiveInfo]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([thisInfo objectForKey:MGMIDidReceiveInfo]);
|
||||||
|
id delegate = [thisInfo objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&info atIndex:2];
|
||||||
|
[invocation setArgument:&instance atIndex:3];
|
||||||
|
[invocation invokeWithTarget:delegate];
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Info: %@", info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Info: %@", info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (NSDictionary *)parseMessageWithHTML:(NSString *)theHTML info:(NSDictionary *)theInfo {
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionary];
|
||||||
|
NSRange range;
|
||||||
|
range = [theHTML rangeOfString:@"<span class=\"gc-message-sms-from\">"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [theHTML substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"</span>"];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 0010");
|
||||||
|
[message setObject:[NSNumber numberWithBool:[[string substringWithRange:NSMakeRange(0, range.location)] containsString:@"Me:"]] forKey:MGMIYou];
|
||||||
|
}
|
||||||
|
range = [theHTML rangeOfString:@"<span class=\"gc-message-sms-text\">"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [theHTML substringFromIndex:range.location + range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"</span>"];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 0011");
|
||||||
|
[message setObject:[[string substringWithRange:NSMakeRange(0, range.location)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:MGMIText];
|
||||||
|
}
|
||||||
|
range = [theHTML rangeOfString:@"<span class=\"gc-message-sms-time\">"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [theHTML substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"</span>"];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 0012");
|
||||||
|
[message setObject:[[string substringWithRange:NSMakeRange(0, range.location)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:MGMITime];
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)deleteEntriesForever:(NSArray *)theEntries delegate:(id)theDelegate {
|
||||||
|
[self deleteEntriesForever:theEntries delegate:theDelegate didFailWithError:@selector(delete:didFailWithError:instance:) didFinish:@selector(deleteDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)deleteEntriesForever:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will delete %@", theEntries);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[info setObject:theEntries forKey:MGMIEntries];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMIDeleteForeverURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString string];
|
||||||
|
for (int i=0; i<[theEntries count]; i++) {
|
||||||
|
[body appendFormat:@"messages=%@&", [theEntries objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"_rnr_se=%@", [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
- (void)deleteEntries:(NSArray *)theEntries delegate:(id)theDelegate {
|
||||||
|
[self deleteEntries:theEntries delegate:theDelegate didFailWithError:@selector(delete:didFailWithError:instance:) didFinish:@selector(deleteDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)deleteEntries:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will delete %@", theEntries);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[info setObject:theEntries forKey:MGMIEntries];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMIDeleteURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString string];
|
||||||
|
for (int i=0; i<[theEntries count]; i++) {
|
||||||
|
[body appendFormat:@"messages=%@&", [theEntries objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"trash=1&_rnr_se=%@", [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)markEntries:(NSArray *)theEntries read:(BOOL)isRead delegate:(id)theDelegate {
|
||||||
|
[self markEntries:theEntries read:isRead delegate:theDelegate didFailWithError:@selector(mark:didFailWithError:instance:) didFinish:@selector(markDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)markEntries:(NSArray *)theEntries read:(BOOL)isRead delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will delete %@", theEntries);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[info setObject:theEntries forKey:MGMIEntries];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMIMarkURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString string];
|
||||||
|
for (int i=0; i<[theEntries count]; i++) {
|
||||||
|
[body appendFormat:@"messages=%@&", [theEntries objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"read=%d&_rnr_se=%@", (isRead ? 1 : 0), [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reportEntries:(NSArray *)theEntries delegate:(id)theDelegate {
|
||||||
|
[self reportEntries:theEntries delegate:theDelegate didFailWithError:@selector(report:didFailWithError:instance:) didFinish:@selector(reportDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)reportEntries:(NSArray *)theEntries delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will delete %@", theEntries);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[info setObject:theEntries forKey:MGMIEntries];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMIReportURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString string];
|
||||||
|
for (int i=0; i<[theEntries count]; i++) {
|
||||||
|
[body appendFormat:@"messages=%@&", [theEntries objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"spam=1&_rnr_se=%@", [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)starEntries:(NSArray *)theEntries starred:(BOOL)isStarred delegate:(id)theDelegate {
|
||||||
|
[self starEntries:theEntries starred:isStarred delegate:theDelegate didFailWithError:@selector(star:didFailWithError:instance:) didFinish:@selector(starDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)starEntries:(NSArray *)theEntries starred:(BOOL)isStarred delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Will delete %@", theEntries);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
[info setObject:theEntries forKey:MGMIEntries];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMIStarURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString string];
|
||||||
|
for (int i=0; i<[theEntries count]; i++) {
|
||||||
|
[body appendFormat:@"messages=%@&", [theEntries objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"star=%d&_rnr_se=%@", (isStarred ? 1 : 0), [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendMessage:(NSString *)theMessage phoneNumbers:(NSArray *)thePhoneNumbers smsID:(NSString *)theID delegate:(id)theDelegate {
|
||||||
|
[self sendMessage:theMessage phoneNumbers:thePhoneNumbers smsID:theID delegate:theDelegate didFailWithError:@selector(message:didFailWithError:instance:) didFinish:@selector(messageDidFinish:instance:)];
|
||||||
|
}
|
||||||
|
- (void)sendMessage:(NSString *)theMessage phoneNumbers:(NSArray *)thePhoneNumbers smsID:(NSString *)theID delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
if (theMessage!=nil)
|
||||||
|
[info setObject:theMessage forKey:MGMIMessage];
|
||||||
|
if (thePhoneNumbers!=nil)
|
||||||
|
[info setObject:thePhoneNumbers forKey:MGMIPhoneNumbers];
|
||||||
|
if (theID==nil) theID = @"";
|
||||||
|
[info setObject:theID forKey:MGMIID];
|
||||||
|
if (thePhoneNumbers==nil || [thePhoneNumbers count]==0 || theMessage==nil || [theMessage isEqual:@""]) {
|
||||||
|
NSMethodSignature *signature = [theDelegate methodSignatureForSelector:didFailWithError];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:didFailWithError];
|
||||||
|
[invocation setArgument:&info atIndex:2];
|
||||||
|
NSError *error = [NSError errorWithDomain:@"com.MrGeckosMedia.MGMInbox.SendMessage" code:1 userInfo:nil];
|
||||||
|
[invocation setArgument:&error atIndex:3];
|
||||||
|
[invocation invokeWithTarget:theDelegate];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMISMSSendURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
NSMutableString *body = [NSMutableString stringWithFormat:@"id=%@&phoneNumber=", theID];
|
||||||
|
for (int i=0; i<[thePhoneNumbers count]; i++) {
|
||||||
|
if ([thePhoneNumbers count]!=1)
|
||||||
|
[body appendFormat:@"%@%%2C%%20", [[thePhoneNumbers objectAtIndex:i] addPercentEscapes]];
|
||||||
|
else
|
||||||
|
[body appendString:[[thePhoneNumbers objectAtIndex:i] addPercentEscapes]];
|
||||||
|
}
|
||||||
|
[body appendFormat:@"&text=%@&sendErrorSms=0&_rnr_se=%@", [theMessage addPercentEscapes], [instance rnr_se]];
|
||||||
|
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(sendRequest:didFailWithError:) didFinish:@selector(sendRequestDidFinish:) invisible:MGMInboxInvisible object:info];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendRequest:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSDictionary *info = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([info objectForKey:MGMIDidFailWithError]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([info objectForKey:MGMIDidFailWithError]);
|
||||||
|
id delegate = [info objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&theInfo atIndex:2];
|
||||||
|
[invocation setArgument:&theError atIndex:3];
|
||||||
|
[invocation setArgument:&instance atIndex:4];
|
||||||
|
[invocation invokeWithTarget:delegate];
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Send Request Error: %@", theError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInbox Send Request Error: %@", theError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)sendRequestDidFinish:(NSDictionary *)theInfo {
|
||||||
|
#if MGMInboxDebug
|
||||||
|
NSLog(@"MGMInbox Did Send Request %@", [[[NSString alloc] initWithData:[theInfo objectForKey:MGMConnectionData] encoding:NSUTF8StringEncoding] autorelease]);
|
||||||
|
#endif
|
||||||
|
NSMutableDictionary *thisInfo = [NSMutableDictionary dictionaryWithDictionary:[theInfo objectForKey:MGMConnectionObject]];
|
||||||
|
[thisInfo setObject:[theInfo objectForKey:MGMConnectionData] forKey:MGMConnectionData];
|
||||||
|
if ([thisInfo objectForKey:MGMIDidFinish]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([thisInfo objectForKey:MGMIDidFinish]);
|
||||||
|
id delegate = [thisInfo objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&thisInfo atIndex:2];
|
||||||
|
[invocation setArgument:&instance atIndex:3];
|
||||||
|
[invocation invokeWithTarget:delegate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
125
Classes/VoiceBase/MGMInstance.h
Normal file
125
Classes/VoiceBase/MGMInstance.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//
|
||||||
|
// MGMInstance.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#else
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@class MGMInstance, MGMUser, MGMHTTPCookieStorage, MGMURLConnectionManager, MGMWhitePages, MGMInbox, MGMContacts;
|
||||||
|
|
||||||
|
#define MGMInstanceDebug 0
|
||||||
|
|
||||||
|
extern NSString * const MGMVoiceIndexURL;
|
||||||
|
extern NSString * const MGMLoginURL;
|
||||||
|
extern NSString * const MGMLoginBody;
|
||||||
|
extern NSString * const MGMXPCPath;
|
||||||
|
extern NSString * const MGMCheckPath;
|
||||||
|
extern NSString * const MGMCreditURL;
|
||||||
|
extern NSString * const MGMCallURL;
|
||||||
|
extern NSString * const MGMCallCancelURL;
|
||||||
|
|
||||||
|
extern NSString * const MGMPostMethod;
|
||||||
|
extern NSString * const MGMURLForm;
|
||||||
|
extern NSString * const MGMContentType;
|
||||||
|
|
||||||
|
extern NSString * const MGMPhoneNumber;
|
||||||
|
extern NSString * const MGMPhone;
|
||||||
|
extern NSString * const MGMName;
|
||||||
|
extern NSString * const MGMType;
|
||||||
|
|
||||||
|
extern NSString * const MGMSContactsSourceKey;
|
||||||
|
extern NSString * const MGMSContactsActionKey;
|
||||||
|
|
||||||
|
extern NSString * const MGMUCAll;
|
||||||
|
extern NSString * const MGMUCInbox;
|
||||||
|
extern NSString * const MGMUCMissed;
|
||||||
|
extern NSString * const MGMUCPlaced;
|
||||||
|
extern NSString * const MGMUCReceived;
|
||||||
|
extern NSString * const MGMUCRecorded;
|
||||||
|
extern NSString * const MGMUCSMS;
|
||||||
|
extern NSString * const MGMUCSpam;
|
||||||
|
extern NSString * const MGMUCStarred;
|
||||||
|
extern NSString * const MGMUCTrash;
|
||||||
|
extern NSString * const MGMUCUnread;
|
||||||
|
extern NSString * const MGMUCVoicemail;
|
||||||
|
|
||||||
|
@protocol MGMInstanceDelegate <NSObject>
|
||||||
|
- (void)loginError:(NSError *)theError;
|
||||||
|
- (void)loginSuccessful;
|
||||||
|
- (void)updatedContacts;
|
||||||
|
- (void)updateUnreadCount:(int)theCount;
|
||||||
|
- (void)updateVoicemail;
|
||||||
|
- (void)updateSMS;
|
||||||
|
- (void)updateCredit:(NSString *)credit;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMInstance : NSObject {
|
||||||
|
id<MGMInstanceDelegate> delegate;
|
||||||
|
MGMUser *user;
|
||||||
|
MGMHTTPCookieStorage *cookeStorage;
|
||||||
|
MGMURLConnectionManager *connectionManager;
|
||||||
|
MGMInbox *inbox;
|
||||||
|
MGMContacts *contacts;
|
||||||
|
|
||||||
|
int webLoginTries;
|
||||||
|
BOOL loggedIn;
|
||||||
|
NSString *GALX;
|
||||||
|
|
||||||
|
NSString *XPCURL;
|
||||||
|
NSString *XPCCD;
|
||||||
|
NSString *rnr_se;
|
||||||
|
|
||||||
|
NSString *userName;
|
||||||
|
NSString *userNumber;
|
||||||
|
NSString *userAreacode;
|
||||||
|
NSMutableArray *userPhoneNumbers;
|
||||||
|
|
||||||
|
NSTimer *checkTimer;
|
||||||
|
NSDictionary *unreadCounts;
|
||||||
|
NSTimer *creditTimer;
|
||||||
|
|
||||||
|
BOOL checkingAccount;
|
||||||
|
}
|
||||||
|
+ (id)instanceWithUser:(MGMUser *)theUser delegate:(id)theDelegate;
|
||||||
|
+ (id)instanceWithUser:(MGMUser *)theUser delegate:(id)theDelegate isCheck:(BOOL)isCheck;
|
||||||
|
- (id)initWithUser:(MGMUser *)theUser delegate:(id)theDelegate isCheck:(BOOL)isCheck;
|
||||||
|
|
||||||
|
- (void)registerSettings;
|
||||||
|
|
||||||
|
- (void)stop;
|
||||||
|
|
||||||
|
- (void)setDelegate:(id)theDelegate;
|
||||||
|
- (id<MGMInstanceDelegate>)delegate;
|
||||||
|
- (MGMUser *)user;
|
||||||
|
- (MGMHTTPCookieStorage *)cookieStorage;
|
||||||
|
- (MGMURLConnectionManager *)connectionManager;
|
||||||
|
- (MGMInbox *)inbox;
|
||||||
|
- (MGMContacts *)contacts;
|
||||||
|
|
||||||
|
- (NSString *)XPCURL;
|
||||||
|
- (NSString *)XPCCD;
|
||||||
|
- (NSString *)rnr_se;
|
||||||
|
|
||||||
|
- (NSString *)userName;
|
||||||
|
- (NSString *)userNumber;
|
||||||
|
- (NSString *)userAreaCode;
|
||||||
|
- (NSArray *)userPhoneNumbers;
|
||||||
|
- (NSDictionary *)unreadCounts;
|
||||||
|
|
||||||
|
- (void)login;
|
||||||
|
- (BOOL)isLoggedIn;
|
||||||
|
- (void)checkTimer;
|
||||||
|
- (void)creditTimer;
|
||||||
|
|
||||||
|
- (void)placeCall:(NSString *)thePhoneNumber usingPhone:(int)thePhone delegate:(id)theDelegate;
|
||||||
|
- (void)placeCall:(NSString *)thePhoneNumber usingPhone:(int)thePhone delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
- (void)cancelCallWithDelegate:(id)theDelegate;
|
||||||
|
- (void)cancelCallWithDelegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish;
|
||||||
|
@end
|
598
Classes/VoiceBase/MGMInstance.m
Normal file
598
Classes/VoiceBase/MGMInstance.m
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
//
|
||||||
|
// MGMInstance.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMInstance.h"
|
||||||
|
#import "MGMInbox.h"
|
||||||
|
#import "MGMContacts.h"
|
||||||
|
#import "MGMAddressBook.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMVoiceBaseCopyright = @"Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/";
|
||||||
|
|
||||||
|
NSString * const MGMVoiceIndexURL = @"https://www.google.com/voice/#inbox";
|
||||||
|
NSString * const MGMLoginURL = @"https://www.google.com/accounts/ServiceLoginAuth?service=grandcentral";
|
||||||
|
NSString * const MGMLoginBody = @"ltmpl=bluebar&continue=https://www.google.com/voice/account/signin&GALX=%@&Email=%@&Passwd=%@&PersistentCookie=yes&rmShown=1";
|
||||||
|
NSString * const MGMXPCPath = @"/voice/xpc/?xpc=%7B%22cn%22%3A%22i70avDIMsA%22%2C%22tp%22%3Anull%2C%22pru%22%3A%22https%3A%2F%2Fwww.google.com%2Fvoice%2Fxpc%2Frelay%22%2C%22ppu%22%3A%22https%3A%2F%2Fwww.google.com%2Fvoice%2Fxpc%2Fblank%2F%22%2C%22lpu%22%3A%22https%3A%2F%2Fclients4.google.com%2Fvoice%2Fxpc%2Fblank%2F%22%7D";
|
||||||
|
NSString * const MGMCheckPath = @"/voice/xpc/checkMessages?r=%@";
|
||||||
|
NSString * const MGMCreditURL = @"https://www.google.com/voice/settings/billingcredit/";
|
||||||
|
NSString * const MGMCallURL = @"https://www.google.com/voice/call/connect/";
|
||||||
|
NSString * const MGMCallCancelURL = @"https://www.google.com/voice/call/cancel/";
|
||||||
|
|
||||||
|
NSString * const MGMPostMethod = @"POST";
|
||||||
|
NSString * const MGMURLForm = @"application/x-www-form-urlencoded";
|
||||||
|
NSString * const MGMContentType = @"content-type";
|
||||||
|
|
||||||
|
NSString * const MGMPhoneNumber = @"phoneNumber";
|
||||||
|
NSString * const MGMPhone = @"phone";
|
||||||
|
NSString * const MGMName = @"name";
|
||||||
|
NSString * const MGMType = @"type";
|
||||||
|
|
||||||
|
NSString * const MGMSContactsSourceKey = @"MGMContactsSource";
|
||||||
|
NSString * const MGMSContactsActionKey = @"MGMContactsAction";
|
||||||
|
|
||||||
|
NSString * const MGMUCAll = @"all";
|
||||||
|
NSString * const MGMUCInbox = @"inbox";
|
||||||
|
NSString * const MGMUCMissed = @"missed";
|
||||||
|
NSString * const MGMUCPlaced = @"placed";
|
||||||
|
NSString * const MGMUCReceived = @"received";
|
||||||
|
NSString * const MGMUCRecorded = @"recorded";
|
||||||
|
NSString * const MGMUCSMS = @"sms";
|
||||||
|
NSString * const MGMUCSpam = @"spam";
|
||||||
|
NSString * const MGMUCStarred = @"starred";
|
||||||
|
NSString * const MGMUCTrash = @"trash";
|
||||||
|
NSString * const MGMUCUnread = @"unread";
|
||||||
|
NSString * const MGMUCVoicemail = @"voicemail";
|
||||||
|
|
||||||
|
const BOOL MGMInstanceInvisible = YES;
|
||||||
|
|
||||||
|
@implementation MGMInstance
|
||||||
|
+ (id)instanceWithUser:(MGMUser *)theUser delegate:(id)theDelegate {
|
||||||
|
return [[[self alloc] initWithUser:theUser delegate:theDelegate isCheck:NO] autorelease];
|
||||||
|
}
|
||||||
|
+ (id)instanceWithUser:(MGMUser *)theUser delegate:(id)theDelegate isCheck:(BOOL)isCheck {
|
||||||
|
return [[[self alloc] initWithUser:theUser delegate:theDelegate isCheck:isCheck] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithUser:(MGMUser *)theUser delegate:(id)theDelegate isCheck:(BOOL)isCheck {
|
||||||
|
if (self = [super init]) {
|
||||||
|
checkingAccount = isCheck;
|
||||||
|
loggedIn = NO;
|
||||||
|
webLoginTries = 0;
|
||||||
|
delegate = theDelegate;
|
||||||
|
user = [theUser retain];
|
||||||
|
cookeStorage = [[theUser cookieStorage] retain];
|
||||||
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:cookeStorage] retain];
|
||||||
|
[self registerSettings];
|
||||||
|
inbox = [[MGMInbox inboxWithInstance:self] retain];
|
||||||
|
if (!checkingAccount)
|
||||||
|
contacts = [[MGMContacts contactsWithClass:NSClassFromString([user settingForKey:MGMSContactsSourceKey]) delegate:self] retain];
|
||||||
|
[connectionManager connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:MGMVoiceIndexURL]] delegate:self didFailWithError:@selector(index:didFailWithError:) didFinish:@selector(indexDidFinish:) invisible:MGMInstanceInvisible object:nil];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (connectionManager!=nil) {
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
[connectionManager release];
|
||||||
|
}
|
||||||
|
if (user!=nil)
|
||||||
|
[user release];
|
||||||
|
if (cookeStorage!=nil)
|
||||||
|
[cookeStorage release];
|
||||||
|
if (inbox!=nil)
|
||||||
|
[inbox release];
|
||||||
|
if (contacts!=nil)
|
||||||
|
[contacts release];
|
||||||
|
if (GALX!=nil)
|
||||||
|
[GALX release];
|
||||||
|
if (XPCURL!=nil)
|
||||||
|
[XPCURL release];
|
||||||
|
if (XPCCD!=nil)
|
||||||
|
[XPCCD release];
|
||||||
|
if (rnr_se!=nil)
|
||||||
|
[rnr_se release];
|
||||||
|
if (userName!=nil)
|
||||||
|
[userName release];
|
||||||
|
if (userNumber!=nil)
|
||||||
|
[userNumber release];
|
||||||
|
if (userAreacode!=nil)
|
||||||
|
[userAreacode release];
|
||||||
|
if (userPhoneNumbers!=nil)
|
||||||
|
[userPhoneNumbers release];
|
||||||
|
if (checkTimer!=nil) {
|
||||||
|
[checkTimer invalidate];
|
||||||
|
[checkTimer release];
|
||||||
|
checkTimer = nil;
|
||||||
|
}
|
||||||
|
if (unreadCounts!=nil)
|
||||||
|
[unreadCounts release];
|
||||||
|
if (creditTimer!=nil) {
|
||||||
|
[creditTimer invalidate];
|
||||||
|
[creditTimer release];
|
||||||
|
creditTimer = nil;
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)description {
|
||||||
|
return [NSString stringWithFormat:@"%@ Number: %@ Account: %@", [super description], userNumber, userName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stop {
|
||||||
|
if (!checkingAccount)
|
||||||
|
[contacts stop];
|
||||||
|
[inbox stop];
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
if (checkTimer!=nil) {
|
||||||
|
[checkTimer invalidate];
|
||||||
|
[checkTimer release];
|
||||||
|
checkTimer = nil;
|
||||||
|
}
|
||||||
|
if (creditTimer!=nil) {
|
||||||
|
[creditTimer invalidate];
|
||||||
|
[creditTimer release];
|
||||||
|
creditTimer = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerSettings {
|
||||||
|
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
|
||||||
|
[settings setObject:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[settings setObject:[NSNumber numberWithInt:0] forKey:MGMSContactsActionKey];
|
||||||
|
[user registerSettings:settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDelegate:(id)theDelegate {
|
||||||
|
delegate = theDelegate;
|
||||||
|
}
|
||||||
|
- (id<MGMInstanceDelegate>)delegate {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
- (MGMUser *)user {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
- (MGMHTTPCookieStorage *)cookieStorage {
|
||||||
|
return cookeStorage;
|
||||||
|
}
|
||||||
|
- (MGMURLConnectionManager *)connectionManager {
|
||||||
|
return connectionManager;
|
||||||
|
}
|
||||||
|
- (MGMInbox *)inbox {
|
||||||
|
return inbox;
|
||||||
|
}
|
||||||
|
- (MGMContacts *)contacts {
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
- (void)updatedContacts {
|
||||||
|
if ([delegate respondsToSelector:@selector(updatedContacts)]) [delegate updatedContacts];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)XPCURL {
|
||||||
|
return XPCURL;
|
||||||
|
}
|
||||||
|
- (NSString *)XPCCD {
|
||||||
|
return XPCCD;
|
||||||
|
}
|
||||||
|
- (NSString *)rnr_se {
|
||||||
|
return rnr_se;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)userName {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
- (NSString *)userNumber {
|
||||||
|
return userNumber;
|
||||||
|
}
|
||||||
|
- (NSString *)userAreaCode {
|
||||||
|
return userAreacode;
|
||||||
|
}
|
||||||
|
- (NSString *)areaCode {
|
||||||
|
return userAreacode;
|
||||||
|
}
|
||||||
|
- (NSArray *)userPhoneNumbers {
|
||||||
|
return userPhoneNumbers;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)unreadCounts {
|
||||||
|
return unreadCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)index:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
if ([delegate respondsToSelector:@selector(loginError:)]) {
|
||||||
|
[delegate loginError:theError];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Login Error: %@", theError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)indexDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSString *returnedString = [[[NSString alloc] initWithData:[theInfo objectForKey:MGMConnectionData] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
if ([returnedString containsString:@"<div id=\"gaia_loginbox\">"]) {
|
||||||
|
if (webLoginTries>2) {
|
||||||
|
NSError *error = [NSError errorWithDomain:@"com.MrGeckosMedia.MGMInstance.Login" code:1 userInfo:[NSDictionary dictionaryWithObject:@"Unable to login. Please check your Credentials." forKey:NSLocalizedDescriptionKey]];
|
||||||
|
if ([delegate respondsToSelector:@selector(loginError:)]) {
|
||||||
|
[delegate loginError:error];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Login Error: %@", error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSRange range = [returnedString rangeOfString:@"name=\"GALX\""];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"value=\""];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 243");
|
||||||
|
string = [string substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@"\" />"];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 532");
|
||||||
|
if (GALX!=nil) [GALX release];
|
||||||
|
GALX = [[string substringWithRange:NSMakeRange(0, range.location)] copy];
|
||||||
|
}
|
||||||
|
[self login];
|
||||||
|
} else {
|
||||||
|
NSString *string, *guser = @"", *phonesInfo = @"";
|
||||||
|
NSRange range;
|
||||||
|
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"Parsing rnr_se");
|
||||||
|
#endif
|
||||||
|
range = [returnedString rangeOfString:@"'_rnr_se': '"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"',"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0001");
|
||||||
|
} else {
|
||||||
|
if (rnr_se!=nil) [rnr_se release];
|
||||||
|
rnr_se = [[[string substringWithRange:NSMakeRange(0, range.location)] addPercentEscapes] copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"rnr_se = %@", rnr_se);
|
||||||
|
NSLog(@"Parsing Right Header");
|
||||||
|
#endif
|
||||||
|
range = [returnedString rangeOfString:@"<div id=guser"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0002");
|
||||||
|
} else {
|
||||||
|
string = [string substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@"</div>"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0002.1");
|
||||||
|
} else {
|
||||||
|
guser = [string substringWithRange:NSMakeRange(0, range.location)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"Parsing User Name");
|
||||||
|
#endif
|
||||||
|
range = [guser rangeOfString:@"<b"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [guser substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0003");
|
||||||
|
} else {
|
||||||
|
string = [string substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@"</b>"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0003.1");
|
||||||
|
} else {
|
||||||
|
if (userName!=nil) [userName release];
|
||||||
|
userName = [[string substringWithRange:NSMakeRange(0, range.location)] copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"User Name = %@", userName);
|
||||||
|
NSLog(@"Parsing Google Number Header");
|
||||||
|
#endif
|
||||||
|
range = [returnedString rangeOfString:@"gc-header-info"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0002");
|
||||||
|
} else {
|
||||||
|
string = [string substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@"</div>"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0002.1");
|
||||||
|
} else {
|
||||||
|
guser = [string substringWithRange:NSMakeRange(0, range.location)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"Parsing Google Number");
|
||||||
|
#endif
|
||||||
|
range = [guser rangeOfString:@"href=\"#phones\""];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [guser substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0004");
|
||||||
|
} else {
|
||||||
|
string = [string substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@"</a>"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0004.1");
|
||||||
|
} else {
|
||||||
|
if (userNumber!=nil) [userNumber release];
|
||||||
|
userNumber = [[[string substringWithRange:NSMakeRange(0, range.location)] phoneFormat] copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (![returnedString containsString:@"gc-header-did-display"] && ![userNumber isPhoneComplete]) {
|
||||||
|
NSError *error = [NSError errorWithDomain:@"com.MrGeckosMedia.MGMInstance.Login" code:2 userInfo:[NSDictionary dictionaryWithObject:@"Your Google Account does not appear to have a Google Number, please visit voice.google.com and setup one before continuing." forKey:NSLocalizedDescriptionKey]];
|
||||||
|
if ([delegate respondsToSelector:@selector(loginError:)]) {
|
||||||
|
[delegate loginError:error];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Login Error: %@", error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (userAreacode!=nil) [userAreacode release];
|
||||||
|
userAreacode = [[userNumber areaCode] copy];
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"Google Number = %@", userNumber);
|
||||||
|
NSLog(@"Areacode = %@", userAreacode);
|
||||||
|
NSLog(@"Parsing User Phones");
|
||||||
|
#endif
|
||||||
|
range = [returnedString rangeOfString:@"'phones': "];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@",\n"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0005");
|
||||||
|
} else {
|
||||||
|
phonesInfo = [string substringWithRange:NSMakeRange(0, range.location)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSDictionary *phones = [phonesInfo parseJSON];
|
||||||
|
//NSLog(@"%@", phones);
|
||||||
|
NSArray *phoneKeys = [phones allKeys];
|
||||||
|
if (userPhoneNumbers!=nil) [userPhoneNumbers release];
|
||||||
|
userPhoneNumbers = [NSMutableArray new];
|
||||||
|
for (int i=0; i<[phoneKeys count]; i++) {
|
||||||
|
NSDictionary *phoneInfo = [phones objectForKey:[phoneKeys objectAtIndex:i]];
|
||||||
|
if ([[phoneInfo objectForKey:@"telephonyVerified"] intValue]==1) {
|
||||||
|
NSMutableDictionary *phone = [NSMutableDictionary dictionary];
|
||||||
|
[phone setObject:[[phoneInfo objectForKey:MGMPhoneNumber] phoneFormat] forKey:MGMPhoneNumber];
|
||||||
|
[phone setObject:[[phoneInfo objectForKey:MGMName] flattenHTML] forKey:MGMName];
|
||||||
|
[phone setObject:[phoneInfo objectForKey:MGMType] forKey:MGMType];
|
||||||
|
[userPhoneNumbers addObject:phone];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"User Phones = %@", userPhoneNumbers);
|
||||||
|
NSLog(@"Parsing XPCURL");
|
||||||
|
#endif
|
||||||
|
range = [returnedString rangeOfString:@"'xpcUrl': '"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"'"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0008");
|
||||||
|
} else {
|
||||||
|
if (XPCURL!=nil) [XPCURL release];
|
||||||
|
XPCURL = [[string substringWithRange:NSMakeRange(0, range.location)] copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"XPCURL = %@", XPCURL);
|
||||||
|
#endif
|
||||||
|
loggedIn = YES;
|
||||||
|
if ([delegate respondsToSelector:@selector(loginSuccessful)]) [delegate loginSuccessful];
|
||||||
|
if (!checkingAccount) {
|
||||||
|
[contacts updateContacts];
|
||||||
|
if (checkTimer!=nil) {
|
||||||
|
[checkTimer invalidate];
|
||||||
|
[checkTimer release];
|
||||||
|
}
|
||||||
|
checkTimer = [[NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(checkTimer) userInfo:nil repeats:YES] retain];
|
||||||
|
[checkTimer fire];
|
||||||
|
if (creditTimer!=nil) {
|
||||||
|
[creditTimer invalidate];
|
||||||
|
[creditTimer release];
|
||||||
|
}
|
||||||
|
creditTimer = [[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(creditTimer) userInfo:nil repeats:YES] retain];
|
||||||
|
[creditTimer fire];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)login {
|
||||||
|
webLoginTries++;
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMLoginURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:MGMLoginBody, GALX, [(webLoginTries==2 ? [[user settingForKey:MGMUserName] stringByAppendingString:@"@gmail.com"] : [user settingForKey:MGMUserName]) addPercentEscapes], [[user password] addPercentEscapes]] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(index:didFailWithError:) didFinish:@selector(indexDidFinish:) invisible:MGMInstanceInvisible object:nil];
|
||||||
|
}
|
||||||
|
- (BOOL)isLoggedIn {
|
||||||
|
return loggedIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)xpcFinished:(NSDictionary *)theInfo {
|
||||||
|
NSString *returnedString = [[[NSString alloc] initWithData:[theInfo objectForKey:MGMConnectionData] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
NSRange range = [returnedString rangeOfString:@"new _cd('"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [returnedString substringFromIndex:range.location+range.length];
|
||||||
|
|
||||||
|
range = [string rangeOfString:@"'"];
|
||||||
|
if (range.location==NSNotFound) NSLog(@"failed 0009");
|
||||||
|
if (XPCCD!=nil) [XPCCD release];
|
||||||
|
XPCCD = [[[string substringWithRange:NSMakeRange(0, range.location)] addPercentEscapes] copy];
|
||||||
|
}
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"XPCCD = %@", XPCCD);
|
||||||
|
#endif
|
||||||
|
[checkTimer fire];
|
||||||
|
}
|
||||||
|
- (void)checkTimer {
|
||||||
|
if (XPCCD)
|
||||||
|
[connectionManager connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:[XPCURL stringByAppendingString:MGMCheckPath], XPCCD]]] delegate:self didFailWithError:NULL didFinish:@selector(checkFinished:) invisible:MGMInstanceInvisible object:nil];
|
||||||
|
else
|
||||||
|
[connectionManager connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[XPCURL stringByAppendingString:MGMXPCPath]]] delegate:self didFailWithError:NULL didFinish:@selector(xpcFinished:) invisible:MGMInstanceInvisible object:nil];
|
||||||
|
}
|
||||||
|
- (void)checkFinished:(NSDictionary *)theInfo {
|
||||||
|
NSDictionary *returnDic = [[theInfo objectForKey:MGMConnectionData] parseJSON];
|
||||||
|
if (returnDic!=nil) {
|
||||||
|
if ([[returnDic objectForKey:@"ok"] intValue]!=0) {
|
||||||
|
NSDictionary *currentUnreadCounts = [[returnDic objectForKey:@"data"] objectForKey:@"unreadCounts"];
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"unreadCounts = %@", currentUnreadCounts);
|
||||||
|
#endif
|
||||||
|
int inboxCount = [[currentUnreadCounts objectForKey:MGMUCInbox] intValue];
|
||||||
|
//int recordedCount = [[currentUnreadCounts objectForKey:MGMUCRecorded] intValue];
|
||||||
|
int voicemailCount = [[currentUnreadCounts objectForKey:MGMUCVoicemail] intValue];
|
||||||
|
int smsCount = [[currentUnreadCounts objectForKey:MGMUCSMS] intValue];
|
||||||
|
if ([[unreadCounts objectForKey:MGMUCInbox] intValue]!=inboxCount) {
|
||||||
|
if ([delegate respondsToSelector:@selector(updateUnreadCount:)]) [delegate updateUnreadCount:inboxCount];
|
||||||
|
}
|
||||||
|
if (voicemailCount>0)
|
||||||
|
if ([delegate respondsToSelector:@selector(updateVoicemail)]) [delegate updateVoicemail];
|
||||||
|
if (smsCount>0)
|
||||||
|
if ([delegate respondsToSelector:@selector(updateSMS)]) [delegate updateSMS];
|
||||||
|
if (unreadCounts!=nil) [unreadCounts release];
|
||||||
|
unreadCounts = [currentUnreadCounts copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)creditTimer {
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMCreditURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:@"_rnr_se=%@", rnr_se] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:NULL didFinish:@selector(creditFinished:) invisible:MGMInstanceInvisible object:nil];
|
||||||
|
}
|
||||||
|
- (void)creditFinished:(NSDictionary *)theInfo {
|
||||||
|
NSString *credit = [[[theInfo objectForKey:MGMConnectionData] parseJSON] objectForKey:@"formattedCredit"];
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"Credit = %@", credit);
|
||||||
|
#endif
|
||||||
|
if ([delegate respondsToSelector:@selector(updateCredit:)]) [delegate updateCredit:credit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)placeCall:(NSString *)thePhoneNumber usingPhone:(int)thePhone delegate:(id)theDelegate {
|
||||||
|
[self placeCall:thePhoneNumber usingPhone:thePhone delegate:theDelegate didFailWithError:@selector(call:didFailWithError:) didFinish:@selector(callDidFinish:)];
|
||||||
|
}
|
||||||
|
- (void)placeCall:(NSString *)thePhoneNumber usingPhone:(int)thePhone delegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
if (thePhoneNumber!=nil)
|
||||||
|
[info setObject:thePhoneNumber forKey:MGMPhoneNumber];
|
||||||
|
[info setObject:[userPhoneNumbers objectAtIndex:thePhone] forKey:MGMPhone];
|
||||||
|
if (thePhoneNumber==nil || [thePhoneNumber isEqual:@""]) {
|
||||||
|
NSMethodSignature *signature = [theDelegate methodSignatureForSelector:didFailWithError];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:didFailWithError];
|
||||||
|
[invocation setArgument:&info atIndex:2];
|
||||||
|
NSError *error = [NSError errorWithDomain:@"com.MrGeckosMedia.MGMInstance.Call" code:1 userInfo:nil];
|
||||||
|
[invocation setArgument:&error atIndex:3];
|
||||||
|
[invocation invokeWithTarget:theDelegate];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMCallURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:@"outgoingNumber=%@&forwardingNumber=%@&subscriberNumber=undefined&phoneType=%@&remember=1&_rnr_se=%@", thePhoneNumber, [[userPhoneNumbers objectAtIndex:thePhone] objectForKey:MGMPhoneNumber], [[userPhoneNumbers objectAtIndex:thePhone] objectForKey:MGMType], rnr_se] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(call:didFailWithError:) didFinish:@selector(callDidFinish:) invisible:MGMInstanceInvisible object:info];
|
||||||
|
}
|
||||||
|
- (void)cancelCallWithDelegate:(id)theDelegate {
|
||||||
|
[self cancelCallWithDelegate:theDelegate didFailWithError:@selector(callCancel:didFailWithError:) didFinish:@selector(callCancelDidFinish:)];
|
||||||
|
}
|
||||||
|
- (void)cancelCallWithDelegate:(id)theDelegate didFailWithError:(SEL)didFailWithError didFinish:(SEL)didFinish {
|
||||||
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
||||||
|
[info setObject:theDelegate forKey:MGMIDelegate];
|
||||||
|
if (didFinish!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFinish) forKey:MGMIDidFinish];
|
||||||
|
if (didFailWithError!=NULL)
|
||||||
|
[info setObject:NSStringFromSelector(didFailWithError) forKey:MGMIDidFailWithError];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMCallCancelURL]];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:@"outgoingNumber=undefined&forwardingNumber=undefined&cancelType=C2C&_rnr_se=%@", rnr_se] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[connectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(call:didFailWithError:) didFinish:@selector(callDidFinish:) invisible:MGMInstanceInvisible object:info];
|
||||||
|
}
|
||||||
|
- (void)call:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSDictionary *info = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([info objectForKey:MGMIDidFailWithError]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([info objectForKey:MGMIDidFailWithError]);
|
||||||
|
id theDelegate = [info objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [theDelegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&theInfo atIndex:2];
|
||||||
|
[invocation setArgument:&theError atIndex:3];
|
||||||
|
[invocation invokeWithTarget:theDelegate];
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInstance Call Error: %@", theError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInstance Call Error: %@", theError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)callDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSDictionary *infoDic = [[theInfo objectForKey:MGMConnectionData] parseJSON];
|
||||||
|
if ([[infoDic objectForKey:@"ok"] boolValue]) {
|
||||||
|
#if MGMInstanceDebug
|
||||||
|
NSLog(@"MGMInstance Did Call %@", infoDic);
|
||||||
|
#endif
|
||||||
|
NSDictionary *thisInfo = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([thisInfo objectForKey:MGMIDidFinish]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([thisInfo objectForKey:MGMIDidFinish]);
|
||||||
|
id theDelegate = [thisInfo objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [theDelegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&theInfo atIndex:2];
|
||||||
|
[invocation invokeWithTarget:theDelegate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithObject:[infoDic objectForKey:@"error"] forKey:NSLocalizedDescriptionKey];
|
||||||
|
NSError *error = [NSError errorWithDomain:@"com.MrGeckosMedia.VoiceBase.Call" code:1 userInfo:info];
|
||||||
|
NSDictionary *thisInfo = [theInfo objectForKey:MGMConnectionObject];
|
||||||
|
if ([thisInfo objectForKey:MGMIDidFailWithError]!=nil) {
|
||||||
|
SEL selector = NSSelectorFromString([thisInfo objectForKey:MGMIDidFailWithError]);
|
||||||
|
id theDelegate = [thisInfo objectForKey:MGMIDelegate];
|
||||||
|
NSMethodSignature *signature = [theDelegate methodSignatureForSelector:selector];
|
||||||
|
if (signature!=nil) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
[invocation setArgument:&theInfo atIndex:2];
|
||||||
|
[invocation setArgument:&error atIndex:3];
|
||||||
|
[invocation invokeWithTarget:theDelegate];
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInstance Call Error: %@", error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"MGMInstance Call Error: %@", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
104
Classes/VoiceBase/MGMThemeManager.h
Normal file
104
Classes/VoiceBase/MGMThemeManager.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// MGMThemeManager.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/23/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#define MGMThemeManagerDebug 0
|
||||||
|
|
||||||
|
extern NSString * const MGMTThemeChangedNotification;
|
||||||
|
extern NSString * const MGMTUpdatedSMSThemeNotification;
|
||||||
|
|
||||||
|
extern NSString * const MGMTCurrentThemeName;
|
||||||
|
extern NSString * const MGMTCurrentThemePath;
|
||||||
|
extern NSString * const MGMTCurrentThemeVariant;
|
||||||
|
extern NSString * const MGMTShowHeader;
|
||||||
|
extern NSString * const MGMTShowFooter;
|
||||||
|
extern NSString * const MGMTInfoPlist;
|
||||||
|
|
||||||
|
extern NSString * const MGMTThemePath;
|
||||||
|
extern NSString * const MGMTVariantFolder;
|
||||||
|
extern NSString * const MGMTVariants;
|
||||||
|
extern NSString * const MGMTSounds;
|
||||||
|
extern NSString * const MGMTName;
|
||||||
|
extern NSString * const MGMTFolder;
|
||||||
|
extern NSString * const MGMTFile;
|
||||||
|
extern NSString * const MGMTRebuild;
|
||||||
|
extern NSString * const MGMTIncomingIcon;
|
||||||
|
extern NSString * const MGMTOutgoingIcon;
|
||||||
|
extern NSString * const MGMTDate;
|
||||||
|
extern NSString * const MGMTAuthor;
|
||||||
|
extern NSString * const MGMTSite;
|
||||||
|
|
||||||
|
extern NSString * const MGMTUserNumber;
|
||||||
|
extern NSString * const MGMTInName;
|
||||||
|
extern NSString * const MGMTInNumber;
|
||||||
|
extern NSString * const MGMTPhoto;
|
||||||
|
|
||||||
|
extern NSString * const MGMTSoundChangedNotification;
|
||||||
|
|
||||||
|
extern NSString * const MGMTCallSoundsFolder;
|
||||||
|
extern NSString * const MGMTSoundsFolder;
|
||||||
|
extern NSString * const MGMTSDefaultPath;
|
||||||
|
extern NSString * const MGMTSDefaultSMSMessageName;
|
||||||
|
extern NSString * const MGMTSDefaultVoicemailName;
|
||||||
|
extern NSString * const MGMTNoSound;
|
||||||
|
extern NSString * const MGMTSFolderName;
|
||||||
|
extern NSString * const MGMTSPath;
|
||||||
|
extern NSString * const MGMTSName;
|
||||||
|
extern NSString * const MGMTSSMSMessage;
|
||||||
|
extern NSString * const MGMTSVoicemail;
|
||||||
|
extern NSString * const MGMTSSIPRingtone;
|
||||||
|
extern NSString * const MGMTSSIPHoldMusic;
|
||||||
|
extern NSString * const MGMTSSIPConnected;
|
||||||
|
extern NSString * const MGMTSSIPDisconnected;
|
||||||
|
extern NSString * const MGMTSSIPSound1;
|
||||||
|
extern NSString * const MGMTSSIPSound2;
|
||||||
|
extern NSString * const MGMTSSIPSound3;
|
||||||
|
extern NSString * const MGMTSSIPSound4;
|
||||||
|
extern NSString * const MGMTSSIPSound5;
|
||||||
|
|
||||||
|
extern NSString * const MGMTThemeExt;
|
||||||
|
extern NSString * const MGMTSoundExt;
|
||||||
|
extern NSString * const MGMAiffExt;
|
||||||
|
extern NSString * const MGMAifExt;
|
||||||
|
extern NSString * const MGMMP3Ext;
|
||||||
|
extern NSString * const MGMWavExt;
|
||||||
|
extern NSString * const MGMAuExt;
|
||||||
|
extern NSString * const MGMM4AExt;
|
||||||
|
|
||||||
|
@interface MGMThemeManager : NSObject {
|
||||||
|
NSMutableDictionary *currentTheme;
|
||||||
|
BOOL shouldPostNotification;
|
||||||
|
}
|
||||||
|
- (void)registerDefaults;
|
||||||
|
- (NSString *)soundsFolderPath;
|
||||||
|
- (NSDictionary *)sounds;
|
||||||
|
- (NSString *)currentSoundPath:(NSString *)theSoundName;
|
||||||
|
- (NSString *)nameOfSound:(NSString *)theSoundName;
|
||||||
|
- (BOOL)setSound:(NSString *)theSoundName withPath:(NSString *)thePath;
|
||||||
|
- (NSSound *)playSound:(NSString *)theSoundName;
|
||||||
|
|
||||||
|
- (NSString *)themesFolderPath;
|
||||||
|
- (BOOL)setupCurrentTheme;
|
||||||
|
- (NSString *)currentThemePath;
|
||||||
|
- (NSString *)currentThemeVariantPath;
|
||||||
|
|
||||||
|
- (NSArray *)themes;
|
||||||
|
- (NSDictionary *)theme;
|
||||||
|
- (BOOL)setTheme:(NSDictionary *)theTheme;
|
||||||
|
- (NSDictionary *)variant;
|
||||||
|
- (void)setVariant:(NSString *)theVariant;
|
||||||
|
|
||||||
|
- (BOOL)hasCustomIncomingIcon;
|
||||||
|
- (NSString *)incomingIconPath;
|
||||||
|
- (NSString *)outgoingIconPath;
|
||||||
|
|
||||||
|
- (NSString *)replace:(NSString *)theHTML messageInfo:(NSDictionary *)theMessageInfo;
|
||||||
|
- (NSString *)replace:(NSString *)theHTML message:(NSDictionary *)theMessage;
|
||||||
|
- (NSString *)buildHTMLWithMessages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo;
|
||||||
|
@end
|
728
Classes/VoiceBase/MGMThemeManager.m
Normal file
728
Classes/VoiceBase/MGMThemeManager.m
Normal file
@ -0,0 +1,728 @@
|
|||||||
|
//
|
||||||
|
// MGMThemeManager.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/23/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMThemeManager.h"
|
||||||
|
#import "MGMInbox.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMTThemeChangedNotification = @"MGMTThemeChangedNotification";
|
||||||
|
NSString * const MGMTUpdatedSMSThemeNotification = @"MGMTUpdatedSMSThemeNotification";
|
||||||
|
|
||||||
|
NSString * const MGMTThemeFolder = @"SMS Themes";
|
||||||
|
NSString * const MGMTDefaultTheme = @"default.vmt";
|
||||||
|
NSString * const MGMTCurrentThemeName = @"MGMTCurrentThemeName";
|
||||||
|
NSString * const MGMTCurrentThemePath = @"MGMTCurrentThemePath";
|
||||||
|
NSString * const MGMTCurrentThemeVariant = @"MGMTCurrentThemeVariant";
|
||||||
|
NSString * const MGMTShowHeader = @"MGMTShowHeader";
|
||||||
|
NSString * const MGMTShowFooter = @"MGMTShowFooter";
|
||||||
|
NSString * const MGMTInfoPlist = @"info.plist";
|
||||||
|
|
||||||
|
NSString * const MGMTPResource = @"%RESOURCE%";
|
||||||
|
NSString * const MGMTPThemes = @"%THEMES%";
|
||||||
|
NSString * const MGMTPSounds = @"%SOUNDS%";
|
||||||
|
|
||||||
|
NSString * const MGMTThemePath = @"themePath";
|
||||||
|
NSString * const MGMTVariantFolder = @"variantFolder";
|
||||||
|
NSString * const MGMTVariants = @"variants";
|
||||||
|
NSString * const MGMTSounds = @"sounds";
|
||||||
|
NSString * const MGMTName = @"name";
|
||||||
|
NSString * const MGMTFolder = @"folder";
|
||||||
|
NSString * const MGMTFile = @"file";
|
||||||
|
NSString * const MGMTRebuild = @"rebuild";
|
||||||
|
NSString * const MGMTIncomingIcon = @"incomingIcon";
|
||||||
|
NSString * const MGMTOutgoingIcon = @"outgoingIcon";
|
||||||
|
NSString * const MGMTDate = @"date";
|
||||||
|
NSString * const MGMTAuthor = @"author";
|
||||||
|
NSString * const MGMTSite = @"site";
|
||||||
|
|
||||||
|
NSString * const MGMTThemeHeaderName = @"themeHeader.html";
|
||||||
|
NSString * const MGMTThemeFooterName = @"themeFooter.html";
|
||||||
|
NSString * const MGMTHeaderName = @"header.html";
|
||||||
|
NSString * const MGMTFooterName = @"footer.html";
|
||||||
|
NSString * const MGMTIncomingFolder = @"incoming";
|
||||||
|
NSString * const MGMTOutgoingFolder = @"outgoing";
|
||||||
|
|
||||||
|
NSString * const MGMTContentName = @"content.html";
|
||||||
|
NSString * const MGMTContextName = @"context.html";
|
||||||
|
NSString * const MGMTNextContentName = @"nextContent.html";
|
||||||
|
NSString * const MGMTNextContextName = @"nextContext.html";
|
||||||
|
|
||||||
|
NSString * const MGMTUserNumber = @"userNumber";
|
||||||
|
NSString * const MGMTInName = @"inName";
|
||||||
|
NSString * const MGMTPhoto = @"photo";
|
||||||
|
|
||||||
|
NSString * const MGMTRHeader = @"%HEADER%";
|
||||||
|
NSString * const MGMTRFooter = @"%FOOTER%";
|
||||||
|
NSString * const MGMTRResource = @"%RESOURCE%";
|
||||||
|
NSString * const MGMTRTheme = @"%THEME%";
|
||||||
|
NSString * const MGMTRThemes = @"%THEMES%";
|
||||||
|
NSString * const MGMTRUserName = @"%USERNAME%";
|
||||||
|
NSString * const MGMTRUserNumber = @"%USERNUMBER%";
|
||||||
|
NSString * const MGMTRInName = @"%INNAME%";
|
||||||
|
NSString * const MGMTRInNumber = @"%INNUMBER%";
|
||||||
|
NSString * const MGMTRLastDate = @"%LASTDATE%";
|
||||||
|
NSString * const MGMTRText = @"%TEXT%";
|
||||||
|
NSString * const MGMTRPhoto = @"%PHOTO%";
|
||||||
|
NSString * const MGMTRTime = @"%TIME%";
|
||||||
|
NSString * const MGMTRID = @"%ID%";
|
||||||
|
NSString * const MGMTRMessageID = @"%MESSAGEID%";
|
||||||
|
NSString * const MGMTRName = @"%NAME%";
|
||||||
|
NSString * const MGMTRNumber = @"%NUMBER%";
|
||||||
|
|
||||||
|
NSString * const MGMTSoundChangedNotification = @"MGMTSoundChangedNotification";
|
||||||
|
|
||||||
|
NSString * const MGMTCallSoundsFolder = @"CallSounds";
|
||||||
|
NSString * const MGMTSoundsFolder = @"Sounds";
|
||||||
|
NSString * const MGMTSDefaultPath = @"/default.vms";
|
||||||
|
NSString * const MGMTSDefaultSMSMessageName = @"bass.mp3";
|
||||||
|
NSString * const MGMTSDefaultVoicemailName = @"bells.mp3";
|
||||||
|
NSString * const MGMTSDefaultSIPRingtoneName = @"ringtone.mp3";
|
||||||
|
NSString * const MGMTNoSound = @"NoSound";
|
||||||
|
NSString * const MGMTSFolderName = @"soundFolderName";
|
||||||
|
NSString * const MGMTSPath = @"soundPath";
|
||||||
|
NSString * const MGMTSName = @"soundName";
|
||||||
|
NSString * const MGMTSSMSMessage = @"SMSMessage";
|
||||||
|
NSString * const MGMTSVoicemail = @"Voicemail";
|
||||||
|
NSString * const MGMTSSIPRingtone = @"SIPRingtone";
|
||||||
|
NSString * const MGMTSSIPHoldMusic = @"SIPHoldMusic";
|
||||||
|
NSString * const MGMTSSIPConnected = @"SIPConnected";
|
||||||
|
NSString * const MGMTSSIPDisconnected = @"SIPDisconnected";
|
||||||
|
NSString * const MGMTSSIPSound1 = @"SIPSound1";
|
||||||
|
NSString * const MGMTSSIPSound2 = @"SIPSound2";
|
||||||
|
NSString * const MGMTSSIPSound3 = @"SIPSound3";
|
||||||
|
NSString * const MGMTSSIPSound4 = @"SIPSound4";
|
||||||
|
NSString * const MGMTSSIPSound5 = @"SIPSound5";
|
||||||
|
|
||||||
|
NSString * const MGMTThemeExt = @"vmt";
|
||||||
|
NSString * const MGMTSoundExt = @"vms";
|
||||||
|
NSString * const MGMAiffExt = @"aiff";
|
||||||
|
NSString * const MGMAifExt = @"aif";
|
||||||
|
NSString * const MGMMP3Ext = @"mp3";
|
||||||
|
NSString * const MGMWavExt = @"wav";
|
||||||
|
NSString * const MGMAuExt = @"au";
|
||||||
|
NSString * const MGMM4AExt = @"m4a";
|
||||||
|
|
||||||
|
@implementation MGMThemeManager
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
shouldPostNotification = NO;
|
||||||
|
[self registerDefaults];
|
||||||
|
if (![self setupCurrentTheme]) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
shouldPostNotification = YES;
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(themeChanged:) name:MGMTThemeChangedNotification object:nil];
|
||||||
|
}
|
||||||
|
[self setSound:MGMTSSMSMessage withPath:nil];
|
||||||
|
[self setSound:MGMTSVoicemail withPath:nil];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (currentTheme!=nil)
|
||||||
|
[currentTheme release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerDefaults {
|
||||||
|
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
|
||||||
|
[defaults setObject:MGMTDefaultTheme forKey:MGMTCurrentThemeName];
|
||||||
|
[defaults setObject:MGMTPResource forKey:MGMTCurrentThemePath];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMTCurrentThemeVariant];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMTShowHeader];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMTShowFooter];
|
||||||
|
[defaults setObject:[MGMTPResource stringByAppendingString:MGMTSDefaultPath] forKey:[MGMTSPath stringByAppendingString:MGMTSSMSMessage]];
|
||||||
|
[defaults setObject:MGMTSDefaultSMSMessageName forKey:[MGMTSName stringByAppendingString:MGMTSSMSMessage]];
|
||||||
|
[defaults setObject:[MGMTPResource stringByAppendingString:MGMTSDefaultPath] forKey:[MGMTSPath stringByAppendingString:MGMTSVoicemail]];
|
||||||
|
[defaults setObject:MGMTSDefaultVoicemailName forKey:[MGMTSName stringByAppendingString:MGMTSVoicemail]];
|
||||||
|
[defaults setObject:[MGMTPResource stringByAppendingString:MGMTSDefaultPath] forKey:[MGMTSPath stringByAppendingString:MGMTSSIPRingtone]];
|
||||||
|
[defaults setObject:MGMTSDefaultSIPRingtoneName forKey:[MGMTSName stringByAppendingString:MGMTSSIPRingtone]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPHoldMusic]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPConnected]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPDisconnected]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPSound1]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPSound2]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPSound3]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPSound4]];
|
||||||
|
[defaults setObject:MGMTNoSound forKey:[MGMTSPath stringByAppendingString:MGMTSSIPSound5]];
|
||||||
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||||
|
}
|
||||||
|
- (NSString *)soundsFolderPath {
|
||||||
|
NSString *supportPath = [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTSoundsFolder];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if (![manager fileExistsAtPath:supportPath]) {
|
||||||
|
if ([manager respondsToSelector:@selector(createDirectoryAtPath:attributes:)])
|
||||||
|
[manager createDirectoryAtPath:supportPath attributes:nil];
|
||||||
|
else
|
||||||
|
[manager createDirectoryAtPath:supportPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
}
|
||||||
|
return supportPath;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)sounds {
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSMutableDictionary *sounds = [NSMutableDictionary dictionary];
|
||||||
|
NSMutableArray *systemSounds = [NSMutableArray array];
|
||||||
|
NSMutableArray *userSounds = [NSMutableArray array];
|
||||||
|
NSMutableArray *unknownSounds = [NSMutableArray array];
|
||||||
|
NSString *systemSoundsPath = @"/System/Library/Sounds/";
|
||||||
|
NSString *userSoundsPath = [@"~/Library/Sounds/" stringByExpandingTildeInPath];
|
||||||
|
NSArray *allowedExtensions = [NSArray arrayWithObjects:MGMAiffExt, MGMAifExt, MGMMP3Ext, MGMWavExt, MGMAuExt, MGMM4AExt, nil];
|
||||||
|
NSArray *checkPaths = [NSArray arrayWithObjects:[self soundsFolderPath], [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTSoundsFolder], systemSoundsPath, userSoundsPath, nil];
|
||||||
|
for (int i=0; i<[checkPaths count]; i++) {
|
||||||
|
NSDirectoryEnumerator *soundFolders = [manager enumeratorAtPath:[checkPaths objectAtIndex:i]];
|
||||||
|
NSString *soundName = nil;
|
||||||
|
while (soundName = [soundFolders nextObject]) {
|
||||||
|
NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:soundName] stringByResolvingSymlinksInPath];
|
||||||
|
if ([[[soundName pathExtension] lowercaseString] isEqual:MGMTSoundExt]) {
|
||||||
|
if (![manager fileExistsAtPath:[path stringByAppendingPathComponent:MGMTInfoPlist]])
|
||||||
|
continue;
|
||||||
|
NSMutableDictionary *soundsInfo = [NSMutableDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
NSMutableArray *thisSounds = [NSMutableArray array];
|
||||||
|
for (int s=0; s<[[soundsInfo objectForKey:MGMTSounds] count]; s++) {
|
||||||
|
NSDictionary *soundInfo = [[soundsInfo objectForKey:MGMTSounds] objectAtIndex:s];
|
||||||
|
NSString *soundPath = [path stringByAppendingPathComponent:[soundInfo objectForKey:MGMTFile]];
|
||||||
|
if (![allowedExtensions containsObject:[[soundPath pathExtension] lowercaseString]] || ![manager fileExistsAtPath:soundPath] || ![manager isReadableFileAtPath:soundPath])
|
||||||
|
continue;
|
||||||
|
NSMutableDictionary *sound = [NSMutableDictionary dictionary];
|
||||||
|
if ([soundInfo objectForKey:MGMTName]!=nil)
|
||||||
|
[sound setObject:[soundInfo objectForKey:MGMTName] forKey:MGMTSName];
|
||||||
|
else
|
||||||
|
[sound setObject:[[soundPath lastPathComponent] stringByDeletingPathExtension] forKey:MGMTSName];
|
||||||
|
[sound setObject:soundPath forKey:MGMTSPath];
|
||||||
|
[thisSounds addObject:sound];
|
||||||
|
}
|
||||||
|
if ([thisSounds count]>0) {
|
||||||
|
if ([soundsInfo objectForKey:MGMTName]!=nil)
|
||||||
|
[sounds setObject:thisSounds forKey:[soundsInfo objectForKey:MGMTName]];
|
||||||
|
else
|
||||||
|
[sounds setObject:thisSounds forKey:[soundName stringByDeletingPathExtension]];
|
||||||
|
}
|
||||||
|
} else if ([allowedExtensions containsObject:[[soundName pathExtension] lowercaseString]] && ![[[[soundName stringByDeletingLastPathComponent] pathExtension] lowercaseString] isEqual:MGMTSoundExt]) {
|
||||||
|
NSMutableDictionary *sound = [NSMutableDictionary dictionary];
|
||||||
|
[sound setObject:[soundName stringByDeletingPathExtension] forKey:MGMTSName];
|
||||||
|
[sound setObject:path forKey:MGMTSPath];
|
||||||
|
if ([[checkPaths objectAtIndex:i] isEqual:systemSoundsPath])
|
||||||
|
[systemSounds addObject:sound];
|
||||||
|
else if ([[checkPaths objectAtIndex:i] isEqual:userSoundsPath])
|
||||||
|
[userSounds addObject:sound];
|
||||||
|
else
|
||||||
|
[unknownSounds addObject:sound];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ([systemSounds count]>0)
|
||||||
|
[sounds setObject:systemSounds forKey:@"System Sounds"];
|
||||||
|
if ([userSounds count]>0)
|
||||||
|
[sounds setObject:userSounds forKey:@"User Sounds"];
|
||||||
|
if ([unknownSounds count]>1)
|
||||||
|
[sounds setObject:unknownSounds forKey:@"Unknown"];
|
||||||
|
return sounds;
|
||||||
|
}
|
||||||
|
- (NSString *)nameOfSound:(NSString *)theSoundName {
|
||||||
|
NSString *path = [self currentSoundPath:theSoundName];
|
||||||
|
if ([path isEqual:MGMTNoSound])
|
||||||
|
return @"No Sound";
|
||||||
|
NSString *file = [path lastPathComponent];
|
||||||
|
NSString *name = [file stringByDeletingPathExtension];
|
||||||
|
if ([[NSFileManager defaultManager] fileExistsAtPath:[[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]]) {
|
||||||
|
NSDictionary *soundsInfo = [NSDictionary dictionaryWithContentsOfFile:[[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
for (int s=0; s<[[soundsInfo objectForKey:MGMTSounds] count]; s++) {
|
||||||
|
NSDictionary *soundInfo = [[soundsInfo objectForKey:MGMTSounds] objectAtIndex:s];
|
||||||
|
if ([[soundInfo objectForKey:MGMTFile] isEqual:file]) {
|
||||||
|
if ([soundInfo objectForKey:MGMTName]!=nil)
|
||||||
|
name = [soundInfo objectForKey:MGMTName];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
- (NSString *)currentSoundPath:(NSString *)theSoundName {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSString *path = [defaults objectForKey:[MGMTSPath stringByAppendingString:theSoundName]];
|
||||||
|
if ([path isEqual:MGMTNoSound])
|
||||||
|
return path;
|
||||||
|
path = [path replace:MGMTPResource with:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTSoundsFolder]];
|
||||||
|
path = [path replace:MGMTPSounds with:[self soundsFolderPath]];
|
||||||
|
return [path stringByAppendingPathComponent:[defaults objectForKey:[MGMTSName stringByAppendingString:theSoundName]]];
|
||||||
|
}
|
||||||
|
- (BOOL)setSound:(NSString *)theSoundName withPath:(NSString *)thePath {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
if (thePath==nil) {
|
||||||
|
if ([[self currentSoundPath:theSoundName] isEqual:MGMTNoSound])
|
||||||
|
return YES;
|
||||||
|
if (![manager fileExistsAtPath:[self currentSoundPath:theSoundName]]) {
|
||||||
|
NSString *path = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTSoundsFolder] stringByAppendingPathComponent:MGMTSDefaultPath];
|
||||||
|
if ([theSoundName isEqual:MGMTSSMSMessage])
|
||||||
|
path = [path stringByAppendingPathComponent:MGMTSDefaultSMSMessageName];
|
||||||
|
else if ([theSoundName isEqual:MGMTSVoicemail])
|
||||||
|
path = [path stringByAppendingPathComponent:MGMTSDefaultVoicemailName];
|
||||||
|
else if ([theSoundName isEqual:MGMTSSIPRingtone])
|
||||||
|
path = [path stringByAppendingPathComponent:MGMTSDefaultSIPRingtoneName];
|
||||||
|
else
|
||||||
|
path = MGMTNoSound;
|
||||||
|
return [self setSound:theSoundName withPath:path];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ([thePath isEqual:MGMTNoSound]) {
|
||||||
|
[defaults setObject:thePath forKey:[MGMTSPath stringByAppendingString:theSoundName]];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
NSArray *allowedExtensions = [NSArray arrayWithObjects:MGMAiffExt, MGMAifExt, MGMMP3Ext, MGMWavExt, MGMAuExt, MGMM4AExt, nil];
|
||||||
|
if (![allowedExtensions containsObject:[[thePath pathExtension] lowercaseString]])
|
||||||
|
return NO;
|
||||||
|
if (![manager fileExistsAtPath:thePath] || ![manager isReadableFileAtPath:thePath])
|
||||||
|
return NO;
|
||||||
|
[defaults setObject:[thePath lastPathComponent] forKey:[MGMTSName stringByAppendingString:theSoundName]];
|
||||||
|
thePath = [thePath stringByDeletingLastPathComponent];
|
||||||
|
if ([thePath containsString:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTSoundsFolder]])
|
||||||
|
thePath = [thePath replace:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTSoundsFolder] with:MGMTPResource];
|
||||||
|
else if ([thePath containsString:[self soundsFolderPath]])
|
||||||
|
thePath = [thePath replace:[self soundsFolderPath] with:MGMTPSounds];
|
||||||
|
[defaults setObject:thePath forKey:[MGMTSPath stringByAppendingString:theSoundName]];
|
||||||
|
}
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMTSoundChangedNotification object:theSoundName];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (NSSound *)playSound:(NSString *)theSoundName {
|
||||||
|
NSSound *sound = nil;
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *path = [self currentSoundPath:theSoundName];
|
||||||
|
if ([manager fileExistsAtPath:path]) {
|
||||||
|
sound = [[NSSound alloc] initWithContentsOfFile:path byReference:YES];
|
||||||
|
[sound setDelegate:self];
|
||||||
|
[sound play];
|
||||||
|
}
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
|
||||||
|
if (finishedPlaying)
|
||||||
|
[sound release];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)themesFolderPath {
|
||||||
|
NSString *supportPath = [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTThemeFolder];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if (![manager fileExistsAtPath:supportPath]) {
|
||||||
|
if ([manager respondsToSelector:@selector(createDirectoryAtPath:attributes:)])
|
||||||
|
[manager createDirectoryAtPath:supportPath attributes:nil];
|
||||||
|
else
|
||||||
|
[manager createDirectoryAtPath:supportPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
}
|
||||||
|
return supportPath;
|
||||||
|
}
|
||||||
|
- (NSString *)currentThemePath {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSString *path = [defaults objectForKey:MGMTCurrentThemePath];
|
||||||
|
path = [path replace:MGMTPResource with:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTThemeFolder]];
|
||||||
|
path = [path replace:MGMTPThemes with:[self themesFolderPath]];
|
||||||
|
return [path stringByAppendingPathComponent:[defaults objectForKey:MGMTCurrentThemeName]];
|
||||||
|
}
|
||||||
|
- (NSString *)currentThemeVariantPath {
|
||||||
|
return [[currentTheme objectForKey:MGMTThemePath] stringByAppendingPathComponent:[currentTheme objectForKey:MGMTVariantFolder]];
|
||||||
|
}
|
||||||
|
- (BOOL)setupCurrentTheme {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"%@ Path: %@", self, [defaults objectForKey:MGMTCurrentThemePath]);
|
||||||
|
NSLog(@"%@ Name: %@", self, [defaults objectForKey:MGMTCurrentThemeName]);
|
||||||
|
#endif
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if (![manager fileExistsAtPath:[[self currentThemePath] stringByAppendingPathComponent:MGMTInfoPlist]]) {
|
||||||
|
if ([[defaults objectForKey:MGMTCurrentThemePath] isEqual:MGMTPResource]) {
|
||||||
|
NSLog(@"Error: Theme not found in resource!");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
[defaults setObject:MGMTDefaultTheme forKey:MGMTCurrentThemeName];
|
||||||
|
[defaults setObject:MGMTPResource forKey:MGMTCurrentThemePath];
|
||||||
|
[defaults setInteger:0 forKey:MGMTCurrentThemeVariant];
|
||||||
|
return [self setupCurrentTheme];
|
||||||
|
}
|
||||||
|
NSMutableDictionary *theme = [NSMutableDictionary dictionaryWithContentsOfFile:[[self currentThemePath] stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
[theme setObject:[self currentThemePath] forKey:MGMTThemePath];
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"%@ Theme Path %@", self, [theme objectForKey:MGMTThemePath]);
|
||||||
|
#endif
|
||||||
|
[defaults synchronize];
|
||||||
|
return [self setTheme:theme];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)themeChanged:(NSNotification *)theNotification {
|
||||||
|
if ([theNotification object]==self) return;
|
||||||
|
shouldPostNotification = NO;
|
||||||
|
[self setupCurrentTheme];
|
||||||
|
shouldPostNotification = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)themes {
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSMutableArray *themes = [NSMutableArray array];
|
||||||
|
NSArray *checkPaths = [NSArray arrayWithObjects:[self themesFolderPath], [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTThemeFolder], nil];
|
||||||
|
for (int i=0; i<[checkPaths count]; i++) {
|
||||||
|
NSDirectoryEnumerator *themeFolders = [manager enumeratorAtPath:[checkPaths objectAtIndex:i]];
|
||||||
|
NSString *themeFolder = nil;
|
||||||
|
while (themeFolder = [themeFolders nextObject]) {
|
||||||
|
if ([[[themeFolder pathExtension] lowercaseString] isEqual:MGMTThemeExt]) {
|
||||||
|
NSString *folder = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:themeFolder] stringByResolvingSymlinksInPath];
|
||||||
|
if (![manager fileExistsAtPath:[folder stringByAppendingPathComponent:MGMTInfoPlist]])
|
||||||
|
continue;
|
||||||
|
NSMutableDictionary *theme = [NSMutableDictionary dictionaryWithContentsOfFile:[folder stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
if ([[theme objectForKey:MGMTVariants] count]>=1) {
|
||||||
|
[theme setObject:folder forKey:MGMTThemePath];
|
||||||
|
[themes addObject:theme];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)theme {
|
||||||
|
return currentTheme;
|
||||||
|
}
|
||||||
|
- (BOOL)setTheme:(NSDictionary *)theTheme {
|
||||||
|
BOOL isNew = ![[theTheme objectForKey:MGMTThemePath] isEqual:[self currentThemePath]];
|
||||||
|
if (currentTheme!=nil) [currentTheme release];
|
||||||
|
currentTheme = [theTheme mutableCopy];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
if (isNew) {
|
||||||
|
if ([[currentTheme objectForKey:MGMTThemePath] containsString:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTThemeFolder]])
|
||||||
|
[defaults setObject:MGMTPResource forKey:MGMTCurrentThemePath];
|
||||||
|
else if ([[currentTheme objectForKey:MGMTThemePath] containsString:[self themesFolderPath]])
|
||||||
|
[defaults setObject:MGMTPThemes forKey:MGMTCurrentThemePath];
|
||||||
|
else
|
||||||
|
[defaults setObject:[[currentTheme objectForKey:MGMTThemePath] stringByDeletingLastPathComponent] forKey:MGMTCurrentThemePath];
|
||||||
|
[defaults setObject:[[currentTheme objectForKey:MGMTThemePath] lastPathComponent] forKey:MGMTCurrentThemeName];
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"%@ Path: %@", self, [defaults objectForKey:MGMTCurrentThemePath]);
|
||||||
|
NSLog(@"%@ Name: %@", self, [defaults objectForKey:MGMTCurrentThemeName]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if ([[currentTheme objectForKey:MGMTVariants] count]<=0) {
|
||||||
|
if ([[defaults objectForKey:MGMTCurrentThemePath] isEqual:MGMTPResource]) {
|
||||||
|
NSLog(@"Error: No varients in the resource!");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
NSLog(@"Error: No variants! Trying to go to default.");
|
||||||
|
[defaults setObject:MGMTDefaultTheme forKey:MGMTCurrentThemeName];
|
||||||
|
[defaults setObject:MGMTPResource forKey:MGMTCurrentThemePath];
|
||||||
|
[defaults setInteger:0 forKey:MGMTCurrentThemeVariant];
|
||||||
|
return [self setupCurrentTheme];
|
||||||
|
} else if ([defaults integerForKey:MGMTCurrentThemeVariant]<[[currentTheme objectForKey:MGMTVariants] count]) {
|
||||||
|
NSString *varriant = [[[currentTheme objectForKey:MGMTVariants] objectAtIndex:[defaults integerForKey:MGMTCurrentThemeVariant]] objectForKey:MGMTFolder];
|
||||||
|
if (![manager fileExistsAtPath:[[currentTheme objectForKey:MGMTThemePath] stringByAppendingPathComponent:varriant]]) {
|
||||||
|
NSLog(@"Error: Varient Folder Is Missing!");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
[currentTheme setObject:varriant forKey:MGMTVariantFolder];
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"%@ Variant Folder is %@", self, [currentTheme objectForKey:MGMTVariantFolder]);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error: What? We are over the varient count? Reverting to varient 0");
|
||||||
|
[defaults setInteger:0 forKey:MGMTCurrentThemeVariant];
|
||||||
|
return [self setupCurrentTheme];
|
||||||
|
}
|
||||||
|
[defaults synchronize];
|
||||||
|
if (shouldPostNotification)
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMTThemeChangedNotification object:self];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMTUpdatedSMSThemeNotification object:self];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)variant {
|
||||||
|
return [[currentTheme objectForKey:MGMTVariants] objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:MGMTCurrentThemeVariant]];
|
||||||
|
}
|
||||||
|
- (void)setVariant:(NSString *)theVariant {
|
||||||
|
NSArray *variants = [currentTheme objectForKey:MGMTVariants];
|
||||||
|
for (int i=0; i<[variants count]; i++) {
|
||||||
|
if ([[[variants objectAtIndex:i] objectForKey:MGMTName] isEqual:theVariant]) {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *varriant = [[variants objectAtIndex:i] objectForKey:MGMTFolder];
|
||||||
|
if (![manager fileExistsAtPath:[[currentTheme objectForKey:MGMTThemePath] stringByAppendingPathComponent:varriant]]) {
|
||||||
|
NSLog(@"Error: Varient Folder Is Missing!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[currentTheme setObject:varriant forKey:MGMTVariantFolder];
|
||||||
|
[defaults setInteger:i forKey:MGMTCurrentThemeVariant];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMTThemeChangedNotification object:self];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMTUpdatedSMSThemeNotification object:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCustomIncomingIcon {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSDictionary *variant = [[currentTheme objectForKey:MGMTVariants] objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:MGMTCurrentThemeVariant]];
|
||||||
|
NSString *photoPath = nil;
|
||||||
|
if (variant!=nil) {
|
||||||
|
if ([variant objectForKey:MGMTIncomingIcon]!=nil && ![[variant objectForKey:MGMTIncomingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]];
|
||||||
|
} else if ([variant objectForKey:MGMTOutgoingIcon]!=nil && ![[variant objectForKey:MGMTOutgoingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (photoPath!=nil);
|
||||||
|
}
|
||||||
|
- (NSString *)incomingIconPath {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSDictionary *variant = [[currentTheme objectForKey:MGMTVariants] objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:MGMTCurrentThemeVariant]];
|
||||||
|
NSString *photoPath = nil;
|
||||||
|
if (variant!=nil) {
|
||||||
|
if ([variant objectForKey:MGMTIncomingIcon]!=nil && ![[variant objectForKey:MGMTIncomingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]];
|
||||||
|
} else if ([variant objectForKey:MGMTOutgoingIcon]!=nil && ![[variant objectForKey:MGMTOutgoingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (photoPath==nil)
|
||||||
|
photoPath = [[NSBundle mainBundle] pathForResource:@"blankicon" ofType:@"png"];
|
||||||
|
return photoPath;
|
||||||
|
}
|
||||||
|
- (NSString *)outgoingIconPath {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSDictionary *variant = [[currentTheme objectForKey:MGMTVariants] objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:MGMTCurrentThemeVariant]];
|
||||||
|
NSString *photoPath = nil;
|
||||||
|
if (variant!=nil) {
|
||||||
|
if ([variant objectForKey:MGMTOutgoingIcon]!=nil && ![[variant objectForKey:MGMTOutgoingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTOutgoingIcon]];
|
||||||
|
} else if ([variant objectForKey:MGMTIncomingIcon]!=nil && ![[variant objectForKey:MGMTIncomingIcon] isEqual:@""] && [manager fileExistsAtPath:[[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]]]) {
|
||||||
|
photoPath = [[self currentThemeVariantPath] stringByAppendingPathComponent:[variant objectForKey:MGMTIncomingIcon]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (photoPath==nil)
|
||||||
|
photoPath = [[NSBundle mainBundle] pathForResource:@"blankicon" ofType:@"png"];
|
||||||
|
return photoPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)replace:(NSString *)theHTML messageInfo:(NSDictionary *)theMessageInfo {
|
||||||
|
NSString *HTML = [theHTML replace:MGMTRResource with:[[[NSBundle mainBundle] resourcePath] filePath]];
|
||||||
|
HTML = [HTML replace:MGMTRTheme with:[[self currentThemeVariantPath] filePath]];
|
||||||
|
HTML = [HTML replace:MGMTRThemes with:[[currentTheme objectForKey:MGMTThemePath] filePath]];
|
||||||
|
HTML = [HTML replace:MGMTRUserName with:NSFullUserName()];
|
||||||
|
HTML = [HTML replace:MGMTRUserNumber with:[[theMessageInfo objectForKey:MGMTUserNumber] readableNumber]];
|
||||||
|
HTML = [HTML replace:MGMTRInName with:[theMessageInfo objectForKey:MGMTInName]];
|
||||||
|
HTML = [HTML replace:MGMTRInNumber with:[[theMessageInfo objectForKey:MGMIPhoneNumber] readableNumber]];
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:[[self variant] objectForKey:MGMTDate]];
|
||||||
|
HTML = [HTML replace:MGMTRLastDate with:[formatter stringFromDate:[theMessageInfo objectForKey:MGMITime]]];
|
||||||
|
HTML = [HTML replace:MGMTRID with:[theMessageInfo objectForKey:MGMIID]];
|
||||||
|
return HTML;
|
||||||
|
}
|
||||||
|
- (NSString *)replace:(NSString *)theHTML message:(NSDictionary *)theMessage {
|
||||||
|
NSString *HTML = [theHTML replace:MGMTRText with:[theMessage objectForKey:MGMIText]];
|
||||||
|
HTML = [HTML replace:MGMTRPhoto with:[theMessage objectForKey:MGMTPhoto]];
|
||||||
|
HTML = [HTML replace:MGMTRTime with:[theMessage objectForKey:MGMITime]];
|
||||||
|
HTML = [HTML replace:MGMTRMessageID with:[theMessage objectForKey:MGMIID]];
|
||||||
|
HTML = [HTML replace:MGMTRName with:[theMessage objectForKey:MGMTName]];
|
||||||
|
HTML = [HTML replace:MGMTRNumber with:[[theMessage objectForKey:MGMIPhoneNumber] readableNumber]];
|
||||||
|
return HTML;
|
||||||
|
}
|
||||||
|
- (NSString *)buildHTMLWithMessages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSString *variantPath = [self currentThemeVariantPath];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSMutableString *html = [NSMutableString string];
|
||||||
|
if ([manager fileExistsAtPath:[variantPath stringByAppendingPathComponent:MGMTThemeHeaderName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Loading Theme Header");
|
||||||
|
#endif
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *themeHeader = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[variantPath stringByAppendingPathComponent:MGMTThemeHeaderName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
NSMutableString *header = [NSMutableString new];
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContextName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Incoming Context");
|
||||||
|
#endif
|
||||||
|
[header appendString:[[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContextName]] encoding:NSUTF8StringEncoding] autorelease]];
|
||||||
|
}
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContextName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Incoming Next Context");
|
||||||
|
#endif
|
||||||
|
[header appendString:[[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContextName]] encoding:NSUTF8StringEncoding] autorelease]];
|
||||||
|
}
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContextName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Outgoing Context");
|
||||||
|
#endif
|
||||||
|
[header appendString:[[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContextName]] encoding:NSUTF8StringEncoding] autorelease]];
|
||||||
|
}
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContextName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Outgoing Next Context");
|
||||||
|
#endif
|
||||||
|
[header appendString:[[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContextName]] encoding:NSUTF8StringEncoding] autorelease]];
|
||||||
|
}
|
||||||
|
if ([defaults boolForKey:MGMTShowHeader]) {
|
||||||
|
if ([manager fileExistsAtPath:[variantPath stringByAppendingPathComponent:MGMTHeaderName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Header");
|
||||||
|
#endif
|
||||||
|
NSString *headerHTML = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[variantPath stringByAppendingPathComponent:MGMTHeaderName]] encoding:NSUTF8StringEncoding];
|
||||||
|
[header appendString:[self replace:headerHTML messageInfo:theMessageInfo]];
|
||||||
|
[headerHTML release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
themeHeader = [themeHeader replace:MGMTRHeader with:header];
|
||||||
|
themeHeader = [self replace:themeHeader messageInfo:theMessageInfo];
|
||||||
|
[header release];
|
||||||
|
[html appendString:themeHeader];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
NSDictionary *lastMessage = nil;
|
||||||
|
for (unsigned int i=0; i<[theMessages count]; i++) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSDictionary *message = [theMessages objectAtIndex:i];
|
||||||
|
NSString *messageHTML = nil;
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
if (lastMessage==nil || ![[lastMessage objectForKey:MGMIYou] boolValue]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Message for Outgoing Content");
|
||||||
|
#endif
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Incoming Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Outgoing Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Incoming Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error: No HTML FOUND!");
|
||||||
|
[pool drain];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Message for Outgoing Next Content");
|
||||||
|
#endif
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Incoming Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Outgoing Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Outgoing Next Content doesn't exist, using Incoming Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error: No HTML FOUND!");
|
||||||
|
[pool drain];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lastMessage==nil || [[lastMessage objectForKey:MGMIYou] boolValue]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Message for Incoming Content");
|
||||||
|
#endif
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Content doesn't exist, using Outgoing Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Content doesn't exist, using Incoming Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Content doesn't exist, using Outgoing Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error: No HTML FOUND!");
|
||||||
|
[pool drain];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Message for Incoming Next Content");
|
||||||
|
#endif
|
||||||
|
if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Next Content doesn't exist, using Outgoing Next Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTNextContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Next Content doesn't exist, using Incoming Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTIncomingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else if ([manager fileExistsAtPath:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Incoming Next Content doesn't exist, using Outgoing Content.");
|
||||||
|
#endif
|
||||||
|
messageHTML = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[[variantPath stringByAppendingPathComponent:MGMTOutgoingFolder] stringByAppendingPathComponent:MGMTContentName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error: No HTML FOUND!");
|
||||||
|
[pool drain];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageHTML = [self replace:messageHTML messageInfo:theMessageInfo];
|
||||||
|
messageHTML = [self replace:messageHTML message:message];
|
||||||
|
[html appendString:messageHTML];
|
||||||
|
lastMessage = message;
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
if ([manager fileExistsAtPath:[variantPath stringByAppendingPathComponent:MGMTThemeFooterName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Loading Theme Footer");
|
||||||
|
#endif
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSString *themeFooter = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[variantPath stringByAppendingPathComponent:MGMTThemeFooterName]] encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
NSMutableString *footer = [NSMutableString new];
|
||||||
|
if ([defaults boolForKey:MGMTShowFooter]) {
|
||||||
|
if ([manager fileExistsAtPath:[variantPath stringByAppendingPathComponent:MGMTFooterName]]) {
|
||||||
|
#if MGMThemeManagerDebug
|
||||||
|
NSLog(@"Adding Footer");
|
||||||
|
#endif
|
||||||
|
NSString *footerHTML = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:[variantPath stringByAppendingPathComponent:MGMTFooterName]] encoding:NSUTF8StringEncoding];
|
||||||
|
[footer appendString:[self replace:footerHTML messageInfo:theMessageInfo]];
|
||||||
|
[footerHTML release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
themeFooter = [themeFooter replace:MGMTRFooter with:footer];
|
||||||
|
themeFooter = [self replace:themeFooter messageInfo:theMessageInfo];
|
||||||
|
[footer release];
|
||||||
|
[html appendString:themeFooter];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
@end
|
156
Classes/VoiceBase/SIP/MGMSIP.h
Normal file
156
Classes/VoiceBase/SIP/MGMSIP.h
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
//
|
||||||
|
// MGMSIP.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <pjsua-lib/pjsua.h>
|
||||||
|
#import <SystemConfiguration/SystemConfiguration.h>
|
||||||
|
|
||||||
|
@class MGMSIPAccount, MGMSIPCall;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPOutboundProxy;
|
||||||
|
extern NSString * const MGMSIPOutboundProxyPort;
|
||||||
|
extern NSString * const MGMSIPSTUN;
|
||||||
|
extern NSString * const MGMSIPSTUNPort;
|
||||||
|
extern NSString * const MGMSIPLogFile;
|
||||||
|
extern NSString * const MGMSIPLogLevel;
|
||||||
|
extern NSString * const MGMSIPConsoleLogLevel;
|
||||||
|
extern NSString * const MGMSIPVoiceActivityDetection;
|
||||||
|
extern NSString * const MGMSIPInteractiveConnectivityEstablishment;
|
||||||
|
extern NSString * const MGMSIPNameServersEnabled;
|
||||||
|
extern NSString * const MGMSIPEchoCacnellationEnabled;
|
||||||
|
extern NSString * const MGMSIPPort;
|
||||||
|
extern NSString * const MGMSIPPublicAddress;
|
||||||
|
|
||||||
|
extern NSString * const MGMNetworkConnectedNotification;
|
||||||
|
extern NSString * const MGMNetworkDisconnectedNotification;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPVolume;
|
||||||
|
extern NSString * const MGMSIPMicVolume;
|
||||||
|
extern NSString * const MGMSIPVolumeChangedNotification;
|
||||||
|
extern NSString * const MGMSIPMicVolumeChangedNotification;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPADeviceIdentifier;
|
||||||
|
extern NSString * const MGMSIPADeviceIndex;
|
||||||
|
extern NSString * const MGMSIPADeviceUID;
|
||||||
|
extern NSString * const MGMSIPADeviceName;
|
||||||
|
extern NSString * const MGMSIPADeviceInputCount;
|
||||||
|
extern NSString * const MGMSIPADeviceOutputCount;
|
||||||
|
extern NSString * const MGMSIPADeviceIsDefaultInput;
|
||||||
|
extern NSString * const MGMSIPADeviceIsDefaultOutput;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPACurrentInputDevice;
|
||||||
|
extern NSString * const MGMSIPACurrentOutputDevice;
|
||||||
|
extern NSString * const MGMSIPASystemDefault;
|
||||||
|
extern NSString * const MGMSIPAudioChangedNotification;
|
||||||
|
|
||||||
|
@protocol MGMSIPDelegate <NSObject>
|
||||||
|
- (void)SIPStarted;
|
||||||
|
- (void)SIPStopped;
|
||||||
|
- (void)accountLoggedIn:(MGMSIPAccount *)theAccount;
|
||||||
|
- (void)accountLoggedOut:(MGMSIPAccount *)theAccount;
|
||||||
|
- (void)receivedNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)startingNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)gotNewCall:(MGMSIPCall *)theCall;
|
||||||
|
@end
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MGMSIPNULLState = -1,
|
||||||
|
MGMSIPStoppedState = 0,
|
||||||
|
MGMSIPStartingState = 1,
|
||||||
|
MGMSIPStartedState = 2,
|
||||||
|
MGMSIPStoppingState = 3
|
||||||
|
} MGMSIPState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MGMSIPNATUnknownType = PJ_STUN_NAT_TYPE_UNKNOWN,
|
||||||
|
MGMSIPNATErrorUnknownType = PJ_STUN_NAT_TYPE_ERR_UNKNOWN,
|
||||||
|
MGMSIPNATOpen = PJ_STUN_NAT_TYPE_OPEN,
|
||||||
|
MGMSIPNATBlocked = PJ_STUN_NAT_TYPE_BLOCKED,
|
||||||
|
MGMSIPNATSymmetricUDP = PJ_STUN_NAT_TYPE_SYMMETRIC_UDP,
|
||||||
|
MGMSIPNATFullCone = PJ_STUN_NAT_TYPE_FULL_CONE,
|
||||||
|
MGMSIPNATSymmetric = PJ_STUN_NAT_TYPE_SYMMETRIC,
|
||||||
|
MGMSIPNATRestricted = PJ_STUN_NAT_TYPE_RESTRICTED,
|
||||||
|
MGMSIPNATPortRestricted = PJ_STUN_NAT_TYPE_PORT_RESTRICTED
|
||||||
|
} MGMSIPNATType;
|
||||||
|
|
||||||
|
@interface MGMSIP : NSObject {
|
||||||
|
id<MGMSIPDelegate> delegate;
|
||||||
|
NSLock *lock;
|
||||||
|
MGMSIPState state;
|
||||||
|
|
||||||
|
pj_pool_t *PJPool;
|
||||||
|
int port;
|
||||||
|
pjmedia_port *ringbackPort;
|
||||||
|
pjsua_conf_port_id ringbackSlot;
|
||||||
|
pjsua_transport_id UDPTransport;
|
||||||
|
pjsua_transport_id TCPTransport;
|
||||||
|
MGMSIPNATType NATType;
|
||||||
|
|
||||||
|
BOOL shouldRestart;
|
||||||
|
NSTimer *restartTimer;
|
||||||
|
|
||||||
|
NSMutableArray *accounts;
|
||||||
|
NSMutableArray *restartAccounts;
|
||||||
|
NSArray *audioDevices;
|
||||||
|
|
||||||
|
int ringbackCount;
|
||||||
|
|
||||||
|
SCDynamicStoreRef store;
|
||||||
|
CFRunLoopSourceRef storeRunLoop;
|
||||||
|
}
|
||||||
|
+ (MGMSIP *)sharedSIP;
|
||||||
|
|
||||||
|
- (void)registerDefaults;
|
||||||
|
|
||||||
|
- (id<MGMSIPDelegate>)delegate;
|
||||||
|
- (void)setDelegate:(id)theDelegate;
|
||||||
|
|
||||||
|
- (MGMSIPState)state;
|
||||||
|
- (BOOL)isStarted;
|
||||||
|
- (pj_pool_t *)PJPool;
|
||||||
|
- (int)port;
|
||||||
|
- (void)setPort:(int)thePort;
|
||||||
|
- (pjmedia_port *)ringbackPort;
|
||||||
|
- (pjsua_conf_port_id)ringbackSlot;
|
||||||
|
- (MGMSIPNATType)NATType;
|
||||||
|
- (void)setNATType:(MGMSIPNATType)theNATType;
|
||||||
|
|
||||||
|
- (void)start;
|
||||||
|
- (void)stop;
|
||||||
|
- (void)restart;
|
||||||
|
|
||||||
|
- (void)registerThread;
|
||||||
|
|
||||||
|
- (void)loginToAccount:(MGMSIPAccount *)theAccount;
|
||||||
|
- (void)logoutOfAccount:(MGMSIPAccount *)theAccount;
|
||||||
|
|
||||||
|
- (NSArray *)accounts;
|
||||||
|
- (MGMSIPAccount *)accountWithIdentifier:(int)theIdentifier;
|
||||||
|
|
||||||
|
- (int)ringbackCount;
|
||||||
|
- (void)setRingbackCount:(int)theRingbackCount;
|
||||||
|
|
||||||
|
- (void)hangUpAllCalls;
|
||||||
|
|
||||||
|
- (float)volume;
|
||||||
|
- (void)setVolume:(float)theVolume;
|
||||||
|
- (float)micVolume;
|
||||||
|
- (void)setMicVolume:(float)theVolume;
|
||||||
|
|
||||||
|
- (BOOL)setInputSoundDevice:(int)theInputDevice outputSoundDevice:(int)theOutputDevice;
|
||||||
|
- (BOOL)stopSound;
|
||||||
|
- (void)updateAudioDevices;
|
||||||
|
- (NSArray *)audioDevices;
|
||||||
|
|
||||||
|
- (void)receivedNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)startingNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (NSArray *)calls;
|
||||||
|
- (MGMSIPCall *)callWithIdentifier:(int)theIdentifier;
|
||||||
|
@end
|
||||||
|
#endif
|
958
Classes/VoiceBase/SIP/MGMSIP.m
Normal file
958
Classes/VoiceBase/SIP/MGMSIP.m
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
//
|
||||||
|
// MGMSIP.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIP.h"
|
||||||
|
#import "MGMSIPAccount.h"
|
||||||
|
#import "MGMSIPCall.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
#import <SystemConfiguration/SystemConfiguration.h>
|
||||||
|
#import <CoreAudio/CoreAudio.h>
|
||||||
|
|
||||||
|
NSString * const MGMSIPCopyright = @"Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/";
|
||||||
|
|
||||||
|
const int MGMSIPMaxCalls = 8;
|
||||||
|
const int MGMSIPDefaultOutboundProxyPort = 5060;
|
||||||
|
const int MGMSIPDefaultSTUNPort = 3478;
|
||||||
|
|
||||||
|
NSString * const MGMSIPOutboundProxy = @"MGMSIPOutboundProxy";
|
||||||
|
NSString * const MGMSIPOutboundProxyPort = @"MGMSIPOutboundProxyPort";
|
||||||
|
NSString * const MGMSIPSTUN = @"MGMSIPSTUN";
|
||||||
|
NSString * const MGMSIPSTUNPort = @"MGMSIPSTUNPort";
|
||||||
|
NSString * const MGMSIPLogFile = @"MGMSIPLogFile";
|
||||||
|
NSString * const MGMSIPLogLevel = @"MGMSIPLogLevel";
|
||||||
|
NSString * const MGMSIPConsoleLogLevel = @"MGMSIPConsoleLogLevel";
|
||||||
|
NSString * const MGMSIPVoiceActivityDetection = @"MGMSIPVoiceActivityDetection";
|
||||||
|
NSString * const MGMSIPInteractiveConnectivityEstablishment = @"MGMSIPInteractiveConnectivityEstablishment";
|
||||||
|
NSString * const MGMSIPNameServersEnabled = @"MGMSIPNameServersEnabled";
|
||||||
|
NSString * const MGMSIPEchoCacnellationEnabled = @"MGMSIPEchoCacnellationEnabled";
|
||||||
|
NSString * const MGMSIPPort = @"MGMSIPPort";
|
||||||
|
NSString * const MGMSIPPublicAddress = @"MGMSIPPublicAddress";
|
||||||
|
|
||||||
|
NSString * const MGMNetworkConnectedNotification = @"MGMNetworkConnectedNotification";
|
||||||
|
NSString * const MGMNetworkDisconnectedNotification = @"MGMNetworkDisconnectedNotification";
|
||||||
|
|
||||||
|
NSString * const MGMSIPVolume = @"MGMSIPVolume";
|
||||||
|
NSString * const MGMSIPMicVolume = @"MGMSIPMicVolume";
|
||||||
|
NSString * const MGMSIPVolumeChangedNotification = @"MGMSIPVolumeChangedNotification";
|
||||||
|
NSString * const MGMSIPMicVolumeChangedNotification = @"MGMSIPMicVolumeChangedNotification";
|
||||||
|
|
||||||
|
NSString * const MGMSIPADeviceIdentifier = @"MGMSIPADeviceIdentifier";
|
||||||
|
NSString * const MGMSIPADeviceIndex = @"MGMSIPADeviceIndex";
|
||||||
|
NSString * const MGMSIPADeviceUID = @"MGMSIPADeviceUID";
|
||||||
|
NSString * const MGMSIPADeviceName = @"MGMSIPADeviceName";
|
||||||
|
NSString * const MGMSIPADeviceInputCount = @"MGMSIPADeviceInputCount";
|
||||||
|
NSString * const MGMSIPADeviceOutputCount = @"MGMSIPADeviceOutputCount";
|
||||||
|
NSString * const MGMSIPADeviceIsDefaultInput = @"MGMSIPADeviceIsDefaultInput";
|
||||||
|
NSString * const MGMSIPADeviceIsDefaultOutput = @"MGMSIPADeviceIsDefaultOutput";
|
||||||
|
|
||||||
|
NSString * const MGMSIPACurrentInputDevice = @"MGMSIPACurrentInputDevice";
|
||||||
|
NSString * const MGMSIPACurrentOutputDevice = @"MGMSIPACurrentOutputDevice";
|
||||||
|
NSString * const MGMSIPASystemDefault = @"System Default";
|
||||||
|
NSString * const MGMSIPAudioChangedNotification = @"MGMSIPAudioChangedNotification";
|
||||||
|
|
||||||
|
static MGMSIP *MGMSIPSingleton = nil;
|
||||||
|
|
||||||
|
#define THIS_FILE "MGMSIP.m"
|
||||||
|
|
||||||
|
static void MGMSIPIncomingCallReceived(pjsua_acc_id accountIdentifier, pjsua_call_id callIdentifier, pjsip_rx_data *messageData) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Incoming call for account %d!", accountIdentifier));
|
||||||
|
MGMSIPAccount *account = [[MGMSIP sharedSIP] accountWithIdentifier:accountIdentifier];
|
||||||
|
MGMSIPCall *call = [account addCallWithIdentifier:callIdentifier];
|
||||||
|
[[MGMSIP sharedSIP] receivedNewCall:call];
|
||||||
|
id<MGMSIPDelegate> delegate = [[MGMSIP sharedSIP] delegate];
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(gotNewCall:)]) [delegate gotNewCall:call];
|
||||||
|
if ([account delegate]!=nil && [[account delegate] respondsToSelector:@selector(receivedNewCall:)]) [[account delegate] receivedNewCall:call];
|
||||||
|
if ([account delegate]!=nil && [[account delegate] respondsToSelector:@selector(gotNewCall:)]) [[account delegate] gotNewCall:call];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMSIPCallStateChanged(pjsua_call_id callIdentifier, pjsip_event *sipEvent) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMSIPCall *call = [[MGMSIP sharedSIP] callWithIdentifier:callIdentifier];
|
||||||
|
pjsua_call_info callInfo;
|
||||||
|
pjsua_call_get_info(callIdentifier, &callInfo);
|
||||||
|
|
||||||
|
if (call==nil && callInfo.state==MGMSIPCallCallingState) {
|
||||||
|
MGMSIPAccount *account = [[MGMSIP sharedSIP] accountWithIdentifier:callInfo.acc_id];
|
||||||
|
MGMSIPCall *call = [account addCallWithIdentifier:callIdentifier];
|
||||||
|
[[MGMSIP sharedSIP] startingNewCall:call];
|
||||||
|
id<MGMSIPDelegate> delegate = [[MGMSIP sharedSIP] delegate];
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(gotNewCall:)]) [delegate gotNewCall:call];
|
||||||
|
if ([account delegate]!=nil && [[account delegate] respondsToSelector:@selector(startingNewCall:)]) [[account delegate] startingNewCall:call];
|
||||||
|
if ([account delegate]!=nil && [[account delegate] respondsToSelector:@selector(gotNewCall:)]) [[account delegate] gotNewCall:call];
|
||||||
|
} else {
|
||||||
|
[call setState:callInfo.state];
|
||||||
|
[call setStateText:[NSString stringWithPJString:callInfo.state_text]];
|
||||||
|
[call setLastStatus:callInfo.last_status];
|
||||||
|
[call setLastStatusText:[NSString stringWithPJString:callInfo.last_status_text]];
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(stateChanged:)]) [[call delegate] stateChanged:call];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callInfo.state==MGMSIPCallDisconnectedState) {
|
||||||
|
[call stopRingback];
|
||||||
|
NSLog(@"%@ Disconnected", call);
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(disconnected:)]) [[call delegate] disconnected:call];
|
||||||
|
[call setIdentifier:PJSUA_INVALID_ID];
|
||||||
|
[[call account] removeCall:call];
|
||||||
|
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Call %d disconnected reason %d (%s)", callIdentifier, callInfo.last_status, callInfo.last_status_text.ptr));
|
||||||
|
} else if (callInfo.state==MGMSIPCallEarlyState) {
|
||||||
|
if (sipEvent->type!=PJSIP_EVENT_TSX_STATE) {
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pjsip_msg *msg;
|
||||||
|
if (sipEvent->body.tsx_state.type==PJSIP_EVENT_RX_MSG)
|
||||||
|
msg = sipEvent->body.tsx_state.src.rdata->msg_info.msg;
|
||||||
|
else
|
||||||
|
msg = sipEvent->body.tsx_state.src.tdata->msg;
|
||||||
|
|
||||||
|
pj_str_t reason = msg->line.status.reason;
|
||||||
|
int code = msg->line.status.code;
|
||||||
|
|
||||||
|
if (callInfo.role==PJSIP_ROLE_UAC && code==180 && msg->body==NULL && callInfo.media_status==PJSUA_CALL_MEDIA_NONE)
|
||||||
|
[call startRingback];
|
||||||
|
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Call %d state changed to %s %d (%.*s)", callIdentifier, callInfo.state_text.ptr, code, (int)reason.slen, reason.ptr));
|
||||||
|
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(early:code:reason:)]) [[call delegate] early:call code:code reason:[NSString stringWithPJString:reason]];
|
||||||
|
} else {
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Call %d state changed to %s", callIdentifier, callInfo.state_text.ptr));
|
||||||
|
|
||||||
|
switch (callInfo.state) {
|
||||||
|
case MGMSIPCallCallingState:
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(calling:)]) [[call delegate] calling:call];
|
||||||
|
break;
|
||||||
|
case MGMSIPCallConnectingState:
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(connecting:)]) [[call delegate] connecting:call];
|
||||||
|
break;
|
||||||
|
case MGMSIPCallConfirmedState:
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(confirmed:)]) [[call delegate] confirmed:call];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMSIPCallMediaStateChanged(pjsua_call_id callIdentifier) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMSIPCall *call = [[MGMSIP sharedSIP] callWithIdentifier:callIdentifier];
|
||||||
|
[call stopRingback];
|
||||||
|
|
||||||
|
pjsua_call_info callInfo;
|
||||||
|
pjsua_call_get_info(callIdentifier, &callInfo);
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(mediaStateChanged:)]) [[call delegate] mediaStateChanged:call];
|
||||||
|
|
||||||
|
if (callInfo.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
|
||||||
|
pjsua_conf_connect(callInfo.conf_slot, 0);
|
||||||
|
pjsua_conf_connect(0, callInfo.conf_slot);
|
||||||
|
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Media for call %d is active", callIdentifier));
|
||||||
|
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(becameActive:)]) [[call delegate] becameActive:call];
|
||||||
|
} else if (callInfo.media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) {
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Media for call %d is placed on hold by local", callIdentifier));
|
||||||
|
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(localPlacedHold:)]) [[call delegate] becameActive:call];
|
||||||
|
} else if (callInfo.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) {
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Media for call %d is placed on hold by remote", callIdentifier));
|
||||||
|
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(remotePlacedHold:)]) [[call delegate] becameActive:call];
|
||||||
|
} else if (callInfo.media_status == PJSUA_CALL_MEDIA_ERROR) {
|
||||||
|
PJ_LOG(1, (THIS_FILE, "Media has reported error, disconnecting call"));
|
||||||
|
|
||||||
|
pj_str_t reason = pj_str("ICE negotiation failed");
|
||||||
|
pjsua_call_hangup(callIdentifier, 500, &reason, NULL);
|
||||||
|
} else {
|
||||||
|
PJ_LOG(3, (THIS_FILE, "Media for call %d is inactive", [call identifier]));
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMSIPCallTransferStatusChanged(pjsua_call_id callIdentifier, int statusCode, const pj_str_t *statusText, pj_bool_t isFinal, pj_bool_t *pCont) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMSIPCall *call = [[MGMSIP sharedSIP] callWithIdentifier:callIdentifier];
|
||||||
|
[call setTransferStatus:statusCode];
|
||||||
|
[call setTransferStatusText:[NSString stringWithPJString:*statusText]];
|
||||||
|
if ([call delegate]!=nil && [[call delegate] respondsToSelector:@selector(transferStatusCahgned:)]) [[call delegate] transferStatusCahgned:call];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMSIPAccountRegistrationStateChanged(pjsua_acc_id accountIdentifier) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
MGMSIPAccount *account = [[MGMSIP sharedSIP] accountWithIdentifier:accountIdentifier];
|
||||||
|
if ([account delegate]!=nil && [[account delegate] respondsToSelector:@selector(registrationChanged)]) [[account delegate] registrationChanged];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMSIPDetectedNAT(const pj_stun_nat_detect_result *result) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
if (result->status!=PJ_SUCCESS) {
|
||||||
|
pjsua_perror(THIS_FILE, "NAT detection failed", result->status);
|
||||||
|
} else {
|
||||||
|
PJ_LOG(3, (THIS_FILE, "NAT detected as %s", result->nat_type_name));
|
||||||
|
[[MGMSIP sharedSIP] setNATType:result->nat_type];
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MGMNetworkNotification(SCDynamicStoreRef store, NSArray *changedKeys, void *info) {
|
||||||
|
for (int i=0; i<[changedKeys count]; ++i) {
|
||||||
|
NSString *key = [changedKeys objectAtIndex:i];
|
||||||
|
if ([key isEqual:@"State:/Network/Global/IPv4"]) {
|
||||||
|
NSDictionary *value = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)key);
|
||||||
|
if (value!=nil)
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMNetworkConnectedNotification object:[value autorelease]];
|
||||||
|
else
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMNetworkDisconnectedNotification object:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus MGMAudioDevicesChanged(AudioHardwarePropertyID propertyID, void *clientData) {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
if (propertyID==kAudioHardwarePropertyDevices || propertyID==kAudioHardwarePropertyDefaultInputDevice || propertyID==kAudioHardwarePropertyDefaultOutputDevice) {
|
||||||
|
[NSObject cancelPreviousPerformRequestsWithTarget:(MGMSIP *)clientData selector:@selector(updateAudioDevices) object:nil];
|
||||||
|
[(MGMSIP *)clientData performSelector:@selector(updateAudioDevices) withObject:nil afterDelay:0.2];
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface MGMSIP (MGMPrivate)
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMSIP
|
||||||
|
+ (MGMSIP *)sharedSIP {
|
||||||
|
if (MGMSIPSingleton==nil)
|
||||||
|
MGMSIPSingleton = [MGMSIP new];
|
||||||
|
return MGMSIPSingleton;
|
||||||
|
}
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
[self registerDefaults];
|
||||||
|
port = [[NSUserDefaults standardUserDefaults] integerForKey:MGMSIPPort];
|
||||||
|
lock = [NSLock new];
|
||||||
|
state = MGMSIPStoppedState;
|
||||||
|
NATType = MGMSIPNATUnknownType;
|
||||||
|
accounts = [NSMutableArray new];
|
||||||
|
shouldRestart = NO;
|
||||||
|
|
||||||
|
store = SCDynamicStoreCreate(kCFAllocatorDefault, CFBundleGetIdentifier(CFBundleGetMainBundle()), (SCDynamicStoreCallBack)MGMNetworkNotification, NULL);
|
||||||
|
if (!store) {
|
||||||
|
NSLog(@"Unable to create store for system configuration %s", SCErrorString(SCError()));
|
||||||
|
} else {
|
||||||
|
NSArray *keys = [NSArray arrayWithObjects:@"State:/Network/Global/IPv4", nil];
|
||||||
|
if (!SCDynamicStoreSetNotificationKeys(store, (CFArrayRef)keys, NULL)) {
|
||||||
|
NSLog(@"Faild to set the store for notifications %s", SCErrorString(SCError()));
|
||||||
|
CFRelease(store);
|
||||||
|
store = NULL;
|
||||||
|
} else {
|
||||||
|
storeRunLoop = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0);
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRunLoop, kCFRunLoopDefaultMode);
|
||||||
|
CFRelease(storeRunLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[self stop];
|
||||||
|
if (storeRunLoop!=NULL)
|
||||||
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRunLoop, kCFRunLoopDefaultMode);
|
||||||
|
if (store!=NULL)
|
||||||
|
CFRelease(store);
|
||||||
|
if (lock!=nil)
|
||||||
|
[lock release];
|
||||||
|
if (accounts!=nil)
|
||||||
|
[accounts release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerDefaults {
|
||||||
|
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMSIPLogLevel];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMSIPConsoleLogLevel];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMSIPVoiceActivityDetection];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:NO] forKey:MGMSIPInteractiveConnectivityEstablishment];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:NO] forKey:MGMSIPNameServersEnabled];
|
||||||
|
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMSIPEchoCacnellationEnabled];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMSIPPort];
|
||||||
|
[defaults setObject:[NSNumber numberWithFloat:1.0] forKey:MGMSIPVolume];
|
||||||
|
[defaults setObject:[NSNumber numberWithFloat:1.0] forKey:MGMSIPMicVolume];
|
||||||
|
[defaults setObject:MGMSIPASystemDefault forKey:MGMSIPACurrentInputDevice];
|
||||||
|
[defaults setObject:MGMSIPASystemDefault forKey:MGMSIPACurrentOutputDevice];
|
||||||
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MGMSIPDelegate>)delegate {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
- (void)setDelegate:(id)theDelegate {
|
||||||
|
delegate = theDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMSIPState)state {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
- (BOOL)isStarted {
|
||||||
|
return (state==MGMSIPStartedState);
|
||||||
|
}
|
||||||
|
- (pj_pool_t *)PJPool {
|
||||||
|
return PJPool;
|
||||||
|
}
|
||||||
|
- (int)port {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
- (void)setPort:(int)thePort {
|
||||||
|
port = thePort;
|
||||||
|
}
|
||||||
|
- (pjmedia_port *)ringbackPort {
|
||||||
|
return ringbackPort;
|
||||||
|
}
|
||||||
|
- (pjsua_conf_port_id)ringbackSlot {
|
||||||
|
return ringbackSlot;
|
||||||
|
}
|
||||||
|
- (MGMSIPNATType)NATType {
|
||||||
|
return NATType;
|
||||||
|
}
|
||||||
|
- (void)setNATType:(MGMSIPNATType)theNATType {
|
||||||
|
NATType = theNATType;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)start {
|
||||||
|
if (state>MGMSIPStoppedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (restartTimer!=nil) {
|
||||||
|
[restartTimer invalidate];
|
||||||
|
[restartTimer release];
|
||||||
|
restartTimer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NSThread detachNewThreadSelector:@selector(startBackground) toTarget:self withObject:nil];
|
||||||
|
}
|
||||||
|
- (void)startBackground {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[lock lock];
|
||||||
|
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
|
||||||
|
pj_status_t status;
|
||||||
|
|
||||||
|
state = MGMSIPStartingState;
|
||||||
|
status = pjsua_create();
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Unable to create PJSUA.");
|
||||||
|
state = MGMSIPNULLState;
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
PJPool = pjsua_pool_create("MGMSIP-pjsua", 1000, 1000);
|
||||||
|
|
||||||
|
pjsua_logging_config loggingConfig;
|
||||||
|
pjsua_logging_config_default(&loggingConfig);
|
||||||
|
if ([defaults objectForKey:MGMSIPLogFile]!=nil && ![[defaults objectForKey:MGMSIPLogFile] isEqual:@""])
|
||||||
|
loggingConfig.log_filename = [[[defaults objectForKey:MGMSIPLogFile] stringByExpandingTildeInPath] PJString];
|
||||||
|
loggingConfig.level = [defaults integerForKey:MGMSIPLogLevel];
|
||||||
|
loggingConfig.console_level = [defaults integerForKey:MGMSIPConsoleLogLevel];
|
||||||
|
|
||||||
|
pjsua_media_config mediaConfig;
|
||||||
|
pjsua_media_config_default(&mediaConfig);
|
||||||
|
mediaConfig.no_vad = ![defaults boolForKey:MGMSIPVoiceActivityDetection];
|
||||||
|
mediaConfig.enable_ice = [defaults boolForKey:MGMSIPInteractiveConnectivityEstablishment];
|
||||||
|
mediaConfig.snd_auto_close_time = 1;
|
||||||
|
if (![defaults boolForKey:MGMSIPEchoCacnellationEnabled])
|
||||||
|
mediaConfig.ec_tail_len = 0;
|
||||||
|
|
||||||
|
pjsua_config sipConfig;
|
||||||
|
pjsua_config_default(&sipConfig);
|
||||||
|
|
||||||
|
sipConfig.user_agent = [[NSString stringWithFormat:@"%@ %@", [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey], [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]] PJString];
|
||||||
|
|
||||||
|
sipConfig.cb.on_incoming_call = &MGMSIPIncomingCallReceived;
|
||||||
|
sipConfig.cb.on_call_media_state = &MGMSIPCallMediaStateChanged;
|
||||||
|
sipConfig.cb.on_call_state = &MGMSIPCallStateChanged;
|
||||||
|
sipConfig.cb.on_call_transfer_status = &MGMSIPCallTransferStatusChanged;
|
||||||
|
sipConfig.cb.on_reg_state = &MGMSIPAccountRegistrationStateChanged;
|
||||||
|
sipConfig.cb.on_nat_detect = &MGMSIPDetectedNAT;
|
||||||
|
|
||||||
|
sipConfig.max_calls = MGMSIPMaxCalls;
|
||||||
|
|
||||||
|
if ([defaults boolForKey:MGMSIPNameServersEnabled]) {
|
||||||
|
SCDynamicStoreRef dynamicStore = SCDynamicStoreCreate(NULL, CFBundleGetIdentifier(CFBundleGetMainBundle()), NULL, NULL);
|
||||||
|
CFPropertyListRef DNSSettings = SCDynamicStoreCopyValue(dynamicStore, CFSTR("State:/Network/Global/DNS"));
|
||||||
|
NSArray *nameServers = nil;
|
||||||
|
if (DNSSettings!=NULL) {
|
||||||
|
nameServers = [[[(NSDictionary *)DNSSettings objectForKey:@"ServerAddresses"] retain] autorelease];
|
||||||
|
CFRelease(DNSSettings);
|
||||||
|
}
|
||||||
|
CFRelease(dynamicStore);
|
||||||
|
|
||||||
|
if ([nameServers count]>=0) {
|
||||||
|
sipConfig.nameserver_count = ([nameServers count]>4 ? 4 : [nameServers count]);
|
||||||
|
for (int i=0; i<[nameServers count] && i<4; i++)
|
||||||
|
sipConfig.nameserver[i] = [[nameServers objectAtIndex:i] PJString];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([defaults objectForKey:MGMSIPOutboundProxy]!=nil && ![[defaults objectForKey:MGMSIPOutboundProxy] isEqual:@""]) {
|
||||||
|
sipConfig.outbound_proxy_cnt = 1;
|
||||||
|
if ([defaults integerForKey:MGMSIPOutboundProxyPort]==0 || [defaults integerForKey:MGMSIPOutboundProxyPort]==MGMSIPDefaultOutboundProxyPort)
|
||||||
|
sipConfig.outbound_proxy[0] = [[NSString stringWithFormat:@"sip:%@", [defaults objectForKey:MGMSIPOutboundProxy]] PJString];
|
||||||
|
else
|
||||||
|
sipConfig.outbound_proxy[0] = [[NSString stringWithFormat:@"sip:%@:%d", [defaults objectForKey:MGMSIPOutboundProxy], [defaults integerForKey:MGMSIPOutboundProxyPort]] PJString];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ([defaults objectForKey:MGMSIPSTUN]!=nil && ![[defaults objectForKey:MGMSIPSTUN] isEqual:@""]) {
|
||||||
|
int STUNPort = [defaults integerForKey:MGMSIPSTUNPort];
|
||||||
|
if (STUNPort==0) STUNPort = MGMSIPDefaultSTUNPort;
|
||||||
|
sipConfig.stun_host = [[NSString stringWithFormat:@"%@:%d", [defaults objectForKey:MGMSIPSTUN], STUNPort] PJString];
|
||||||
|
}
|
||||||
|
|
||||||
|
status = pjsua_init(&sipConfig, &loggingConfig, &mediaConfig);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Error initializing PJSUA");
|
||||||
|
[self stop];
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int samplesPerFrame = mediaConfig.audio_frame_ptime * mediaConfig.clock_rate * mediaConfig.channel_count / 1000;
|
||||||
|
pj_str_t name = pj_str("ringback");
|
||||||
|
status = pjmedia_tonegen_create2(PJPool, &name, mediaConfig.clock_rate, mediaConfig.channel_count, samplesPerFrame, 16, PJMEDIA_TONEGEN_LOOP, &ringbackPort);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Error creating ringback tones");
|
||||||
|
[self stop];
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pjmedia_tone_desc tone[1];
|
||||||
|
pj_bzero(&tone, sizeof(tone));
|
||||||
|
tone[0].freq1 = 440;
|
||||||
|
tone[0].freq2 = 480;
|
||||||
|
tone[0].on_msec = 2000;
|
||||||
|
tone[0].off_msec = 4000;
|
||||||
|
tone[0].off_msec = 4000;
|
||||||
|
|
||||||
|
pjmedia_tonegen_play(ringbackPort, 1, tone, PJMEDIA_TONEGEN_LOOP);
|
||||||
|
status = pjsua_conf_add_port(PJPool, ringbackPort, &ringbackSlot);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Error adding ringback tone");
|
||||||
|
[self stop];
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pjsua_transport_config transportConfig;
|
||||||
|
pjsua_transport_config_default(&transportConfig);
|
||||||
|
transportConfig.port = port;
|
||||||
|
if ([defaults objectForKey:MGMSIPPublicAddress]!=nil && ![[defaults objectForKey:MGMSIPPublicAddress] isEqual:@""])
|
||||||
|
transportConfig.public_addr = [[defaults objectForKey:MGMSIPPublicAddress] PJString];
|
||||||
|
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &transportConfig, &UDPTransport);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Error creating transport");
|
||||||
|
[self stop];
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (port == 0) {
|
||||||
|
pjsua_transport_info transportInfo;
|
||||||
|
status = pjsua_transport_get_info(UDPTransport, &transportInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Unable to get transport info");
|
||||||
|
|
||||||
|
port = transportInfo.local_name.port;
|
||||||
|
transportConfig.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &transportConfig, &TCPTransport);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error creating TCP transport");
|
||||||
|
|
||||||
|
status = pjsua_start();
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Error starting PJSUA");
|
||||||
|
[self stop];
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = MGMSIPStartedState;
|
||||||
|
|
||||||
|
pjsua_conf_adjust_tx_level(0, [defaults floatForKey:MGMSIPVolume]);
|
||||||
|
pjsua_conf_adjust_rx_level(0, [defaults floatForKey:MGMSIPMicVolume]);
|
||||||
|
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, &MGMAudioDevicesChanged, self);
|
||||||
|
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, &MGMAudioDevicesChanged, self);
|
||||||
|
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, &MGMAudioDevicesChanged, self);
|
||||||
|
[self updateAudioDevices];
|
||||||
|
|
||||||
|
[accounts makeObjectsPerformSelector:@selector(login)];
|
||||||
|
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(SIPStarted)]) [delegate SIPStarted];
|
||||||
|
|
||||||
|
NSLog(@"MGMSIP Started");
|
||||||
|
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)stop {
|
||||||
|
if (state==MGMSIPStoppingState || state==MGMSIPStoppedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[NSThread detachNewThreadSelector:@selector(stopBackground) toTarget:self withObject:nil];
|
||||||
|
}
|
||||||
|
- (void)stopBackground {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[lock lock];
|
||||||
|
|
||||||
|
pj_status_t status;
|
||||||
|
|
||||||
|
state = MGMSIPStoppingState;
|
||||||
|
|
||||||
|
[accounts makeObjectsPerformSelector:@selector(logout)];
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
if (ringbackPort!=NULL && ringbackSlot!=PJSUA_INVALID_ID) {
|
||||||
|
pjsua_conf_remove_port(ringbackSlot);
|
||||||
|
ringbackSlot = PJSUA_INVALID_ID;
|
||||||
|
pjmedia_port_destroy(ringbackPort);
|
||||||
|
ringbackPort = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PJPool!=NULL) {
|
||||||
|
pj_pool_release(PJPool);
|
||||||
|
PJPool = NULL;
|
||||||
|
}
|
||||||
|
pjsua_transport_close(UDPTransport, PJ_FALSE);
|
||||||
|
pjsua_transport_close(TCPTransport, PJ_FALSE);
|
||||||
|
|
||||||
|
status = pjsua_destroy();
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error stopping SIP");
|
||||||
|
|
||||||
|
state = MGMSIPStoppedState;
|
||||||
|
|
||||||
|
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, &MGMAudioDevicesChanged);
|
||||||
|
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultInputDevice, &MGMAudioDevicesChanged);
|
||||||
|
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultOutputDevice, &MGMAudioDevicesChanged);
|
||||||
|
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(SIPStopped)]) [delegate SIPStopped];
|
||||||
|
|
||||||
|
NSLog(@"MGMSIP Stopped");
|
||||||
|
|
||||||
|
if (shouldRestart) {
|
||||||
|
if (restartAccounts!=nil) {
|
||||||
|
for (int i=0; i<[restartAccounts count]; i++) {
|
||||||
|
if (![accounts containsObject:[restartAccounts objectAtIndex:i]])
|
||||||
|
[accounts addObject:[restartAccounts objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
[restartAccounts release];
|
||||||
|
restartAccounts = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldRestart = NO;
|
||||||
|
[self start];
|
||||||
|
//[self performSelectorOnMainThread:@selector(startRestartTimer) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
[lock unlock];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)startRestartTimer {
|
||||||
|
if (restartTimer!=nil) {
|
||||||
|
[restartTimer invalidate];
|
||||||
|
[restartTimer release];
|
||||||
|
restartTimer = nil;
|
||||||
|
}
|
||||||
|
restartTimer = [[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(start) userInfo:nil repeats:NO] retain];
|
||||||
|
}
|
||||||
|
- (void)restart {
|
||||||
|
if (shouldRestart)
|
||||||
|
return;
|
||||||
|
restartAccounts = [accounts copy];
|
||||||
|
shouldRestart = YES;
|
||||||
|
[self stop];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerThread {
|
||||||
|
pj_thread_desc PJThreadDesc;
|
||||||
|
if (!pj_thread_is_registered()) {
|
||||||
|
pj_thread_t *PJThread;
|
||||||
|
pj_status_t status = pj_thread_register(NULL, PJThreadDesc, &PJThread);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error registering thread for PJSUA with status %d", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loginToAccount:(MGMSIPAccount *)theAccount {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
if (![theAccount informationComplete]) {
|
||||||
|
[theAccount setLastError:@"The Account Information is not complete."];
|
||||||
|
[theAccount loginErrored];
|
||||||
|
NSLog(@"Error With Account %@: %@", theAccount, [theAccount lastError]);
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (![accounts containsObject:theAccount]) [accounts addObject:theAccount];
|
||||||
|
if (state!=MGMSIPStartedState) {
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([theAccount identifier]!=PJSUA_INVALID_ID) {
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_config accountConfig;
|
||||||
|
pjsua_acc_config_default(&accountConfig);
|
||||||
|
|
||||||
|
accountConfig.cred_count = 1;
|
||||||
|
if ([theAccount domain]!=nil && ![[theAccount domain] isEqual:@""])
|
||||||
|
accountConfig.cred_info[0].realm = [[theAccount domain] PJString];
|
||||||
|
else
|
||||||
|
accountConfig.cred_info[0].realm = pj_str("*");
|
||||||
|
accountConfig.cred_info[0].scheme = pj_str("digest");
|
||||||
|
accountConfig.cred_info[0].username = [[theAccount userName] PJString];
|
||||||
|
accountConfig.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
|
||||||
|
accountConfig.cred_info[0].data = [[theAccount password] PJString];
|
||||||
|
|
||||||
|
if ([theAccount fullName]!=nil)
|
||||||
|
accountConfig.id = [[NSString stringWithFormat:@"%@ <sip:%@>", [theAccount fullName], [theAccount SIPAddress]] PJString];
|
||||||
|
else
|
||||||
|
accountConfig.id = [[NSString stringWithFormat:@"<sip:%@>", [theAccount SIPAddress]] PJString];
|
||||||
|
accountConfig.reg_uri = [[NSString stringWithFormat:@"sip:%@", [theAccount registrar]] PJString];
|
||||||
|
|
||||||
|
if ([theAccount proxy]!=nil && ![[theAccount proxy] isEqual:@""]) {
|
||||||
|
accountConfig.proxy_cnt = 1;
|
||||||
|
accountConfig.proxy[0] = [[NSString stringWithFormat:@"sip:%@:%d", [theAccount proxy], [theAccount proxyPort]] PJString];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
if ([defaults boolForKey:MGMSIPInteractiveConnectivityEstablishment] && [defaults objectForKey:MGMSIPSTUN]!=nil && ![[defaults objectForKey:MGMSIPSTUN] isEqual:@""])
|
||||||
|
accountConfig.allow_contact_rewrite = PJ_TRUE;
|
||||||
|
else
|
||||||
|
accountConfig.allow_contact_rewrite = PJ_FALSE;
|
||||||
|
|
||||||
|
accountConfig.reg_timeout = [theAccount reregisterTimeout];
|
||||||
|
|
||||||
|
pjsua_acc_id identifier;
|
||||||
|
pj_status_t status = pjsua_acc_add(&accountConfig, PJ_FALSE, &identifier);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
[theAccount setLastError:[NSString stringWithFormat:@"Unable to login with status %d.", status]];
|
||||||
|
[theAccount loginErrored];
|
||||||
|
NSLog(@"Error With Account %@: %@", theAccount, [theAccount lastError]);
|
||||||
|
[accounts removeObject:theAccount];
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[theAccount setIdentifier:identifier];
|
||||||
|
[theAccount setOnline:YES];
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(accountLoggedIn:)]) [delegate accountLoggedIn:theAccount];
|
||||||
|
if ([theAccount delegate]!=nil && [[theAccount delegate] respondsToSelector:@selector(loggedIn)]) [[theAccount delegate] loggedIn];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)logoutOfAccount:(MGMSIPAccount *)theAccount {
|
||||||
|
if (state<MGMSIPStartedState) return;
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
if ([theAccount identifier]==PJSUA_INVALID_ID) {
|
||||||
|
[theAccount setLastError:@"Unable to logout due to missing information."];
|
||||||
|
[theAccount logoutErrored];
|
||||||
|
NSLog(@"Error With Account %@: %@", theAccount, [theAccount lastError]);
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_acc_del([theAccount identifier]);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
[theAccount setLastError:[NSString stringWithFormat:@"Unable to logout with status %d.", status]];
|
||||||
|
[theAccount logoutErrored];
|
||||||
|
NSLog(@"Error With Account %@: %@", theAccount, [theAccount lastError]);
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[theAccount setIdentifier:PJSUA_INVALID_ID];
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(accountLoggedOut:)]) [delegate accountLoggedOut:theAccount];
|
||||||
|
if ([theAccount delegate]!=nil && [[theAccount delegate] respondsToSelector:@selector(loggedOut)]) [[theAccount delegate] loggedOut];
|
||||||
|
[accounts removeObject:theAccount];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)accounts {
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
- (MGMSIPAccount *)accountWithIdentifier:(int)theIdentifier {
|
||||||
|
for (int i=0; i<[accounts count]; i++) {
|
||||||
|
if ([(MGMSIPAccount *)[accounts objectAtIndex:i] identifier]==theIdentifier)
|
||||||
|
return [accounts objectAtIndex:i];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)ringbackCount {
|
||||||
|
return ringbackCount;
|
||||||
|
}
|
||||||
|
- (void)setRingbackCount:(int)theRingbackCount {
|
||||||
|
ringbackCount = theRingbackCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)hangUpAllCalls {
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pjsua_call_hangup_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)volume {
|
||||||
|
return [[NSUserDefaults standardUserDefaults] floatForKey:MGMSIPVolume];
|
||||||
|
}
|
||||||
|
- (void)setVolume:(float)theVolume {
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
[[NSUserDefaults standardUserDefaults] setFloat:theVolume forKey:MGMSIPVolume];
|
||||||
|
pjsua_conf_adjust_tx_level(0, theVolume);
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMSIPVolumeChangedNotification object:[NSNumber numberWithFloat:theVolume]];
|
||||||
|
}
|
||||||
|
- (float)micVolume {
|
||||||
|
return [[NSUserDefaults standardUserDefaults] floatForKey:MGMSIPMicVolume];
|
||||||
|
}
|
||||||
|
- (void)setMicVolume:(float)theVolume {
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
[[NSUserDefaults standardUserDefaults] setFloat:theVolume forKey:MGMSIPMicVolume];
|
||||||
|
pjsua_conf_adjust_rx_level(0, theVolume);
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMSIPMicVolumeChangedNotification object:[NSNumber numberWithFloat:theVolume]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setInputSoundDevice:(int)theInputDevice outputSoundDevice:(int)theOutputDevice {
|
||||||
|
if (state!=MGMSIPStartedState)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
NSString *inputDeviceUID = nil;
|
||||||
|
if (theInputDevice==-1) {
|
||||||
|
inputDeviceUID = MGMSIPASystemDefault;
|
||||||
|
for (int i=0; i<[audioDevices count]; i++) {
|
||||||
|
if ([[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIsDefaultInput] boolValue]) {
|
||||||
|
theInputDevice = [[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIndex] intValue];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i=0; i<[audioDevices count]; i++) {
|
||||||
|
if ([[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIndex] intValue]==theInputDevice) {
|
||||||
|
inputDeviceUID = [[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceUID];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSString *outputDeviceUID = nil;
|
||||||
|
if (theOutputDevice==-1) {
|
||||||
|
outputDeviceUID = MGMSIPASystemDefault;
|
||||||
|
for (int i=0; i<[audioDevices count]; i++) {
|
||||||
|
if ([[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIsDefaultOutput] boolValue]) {
|
||||||
|
theOutputDevice = [[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIndex] intValue];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i=0; i<[audioDevices count]; i++) {
|
||||||
|
if ([[[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceIndex] intValue]==theOutputDevice) {
|
||||||
|
outputDeviceUID = [[audioDevices objectAtIndex:i] objectForKey:MGMSIPADeviceUID];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setObject:inputDeviceUID forKey:MGMSIPACurrentInputDevice];
|
||||||
|
[defaults setObject:outputDeviceUID forKey:MGMSIPACurrentOutputDevice];
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_set_snd_dev(theInputDevice, theOutputDevice);
|
||||||
|
return (status==PJ_SUCCESS);
|
||||||
|
}
|
||||||
|
- (BOOL)stopSound {
|
||||||
|
if (state!=MGMSIPStartedState)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_set_null_snd_dev();
|
||||||
|
return (status==PJ_SUCCESS);
|
||||||
|
}
|
||||||
|
- (void)updateAudioDevices {
|
||||||
|
if (state!=MGMSIPStartedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
|
||||||
|
OSStatus error = noErr;
|
||||||
|
UInt32 size = 0;
|
||||||
|
AudioBufferList *bufferList = NULL;
|
||||||
|
|
||||||
|
NSMutableArray *devicesArray = [NSMutableArray array];
|
||||||
|
AudioDeviceID *devices = NULL;
|
||||||
|
int deviceCount = 0;
|
||||||
|
Boolean writable;
|
||||||
|
|
||||||
|
error = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &writable);
|
||||||
|
if (error!=noErr) {
|
||||||
|
[pool drain];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceCount = size / sizeof(AudioDeviceID);
|
||||||
|
if (deviceCount>=1) {
|
||||||
|
devices = malloc(size);
|
||||||
|
memset(devices, 0, size);
|
||||||
|
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, (void *)devices);
|
||||||
|
}
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
size = sizeof(AudioDeviceID);
|
||||||
|
AudioDeviceID defaultInput = 0;
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, &defaultInput);
|
||||||
|
size = sizeof(AudioDeviceID);
|
||||||
|
AudioDeviceID defaultOutput = 0;
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &defaultOutput);
|
||||||
|
|
||||||
|
NSMutableDictionary *defaultDevice = [NSMutableDictionary dictionary];
|
||||||
|
[defaultDevice setObject:[NSNumber numberWithUnsignedInt:0] forKey:MGMSIPADeviceIdentifier];
|
||||||
|
[defaultDevice setObject:[NSNumber numberWithUnsignedInt:-1] forKey:MGMSIPADeviceIndex];
|
||||||
|
[defaultDevice setObject:MGMSIPASystemDefault forKey:MGMSIPADeviceName];
|
||||||
|
[defaultDevice setObject:MGMSIPASystemDefault forKey:MGMSIPADeviceUID];
|
||||||
|
[devicesArray addObject:defaultDevice];
|
||||||
|
|
||||||
|
int currentInput = -1;
|
||||||
|
int currentOutput = -1;
|
||||||
|
|
||||||
|
for (int d=0; d<deviceCount; d++) {
|
||||||
|
NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionary];
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithUnsignedLong:devices[d]] forKey:MGMSIPADeviceIdentifier];
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithInt:d] forKey:MGMSIPADeviceIndex];
|
||||||
|
|
||||||
|
if (devices[d]==defaultInput)
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMSIPADeviceIsDefaultInput];
|
||||||
|
if (devices[d]==defaultOutput)
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMSIPADeviceIsDefaultOutput];
|
||||||
|
|
||||||
|
CFStringRef UIDString = NULL;
|
||||||
|
size = sizeof(CFStringRef);
|
||||||
|
error = AudioDeviceGetProperty(devices[d], 0, 0, kAudioDevicePropertyDeviceUID, &size, &UIDString);
|
||||||
|
if (error==noErr && UIDString!=NULL)
|
||||||
|
[deviceInfo setObject:[(NSString *)UIDString autorelease] forKey:MGMSIPADeviceUID];
|
||||||
|
|
||||||
|
CFStringRef nameString = NULL;
|
||||||
|
size = sizeof(CFStringRef);
|
||||||
|
error = AudioDeviceGetProperty(devices[d], 0, 0, kAudioDevicePropertyDeviceNameCFString, &size, &nameString);
|
||||||
|
if (error==noErr && nameString!=NULL)
|
||||||
|
[deviceInfo setObject:[(NSString *)nameString autorelease] forKey:MGMSIPADeviceName];
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
unsigned int inputChannelCount = 0;
|
||||||
|
error = AudioDeviceGetPropertyInfo(devices[d], 0, 1, kAudioDevicePropertyStreamConfiguration, &size, NULL);
|
||||||
|
if (error==noErr && size!=0) {
|
||||||
|
bufferList = malloc(size);
|
||||||
|
if (bufferList!=NULL) {
|
||||||
|
error = AudioDeviceGetProperty(devices[d], 0, 1, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
|
||||||
|
if (error==noErr) {
|
||||||
|
for (unsigned int i=0; i<bufferList->mNumberBuffers; i++)
|
||||||
|
inputChannelCount += bufferList->mBuffers[i].mNumberChannels;
|
||||||
|
}
|
||||||
|
free(bufferList);
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithUnsignedInt:inputChannelCount] forKey:MGMSIPADeviceInputCount];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
unsigned int outputChannelCount = 0;
|
||||||
|
error = AudioDeviceGetPropertyInfo(devices[d], 0, 0, kAudioDevicePropertyStreamConfiguration, &size, NULL);
|
||||||
|
if(error==noErr && size!=0) {
|
||||||
|
bufferList = malloc(size);
|
||||||
|
if (bufferList!=NULL) {
|
||||||
|
error = AudioDeviceGetProperty(devices[d], 0, 0, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
|
||||||
|
if (error==noErr) {
|
||||||
|
for (unsigned int i = 0; i < bufferList->mNumberBuffers; ++i)
|
||||||
|
outputChannelCount += bufferList->mBuffers[i].mNumberChannels;
|
||||||
|
}
|
||||||
|
free(bufferList);
|
||||||
|
[deviceInfo setObject:[NSNumber numberWithUnsignedInt:outputChannelCount] forKey:MGMSIPADeviceOutputCount];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([[deviceInfo objectForKey:MGMSIPADeviceInputCount] unsignedIntValue]!=0 && [[deviceInfo objectForKey:MGMSIPADeviceUID] isEqual:[defaults objectForKey:MGMSIPACurrentInputDevice]])
|
||||||
|
currentInput = d;
|
||||||
|
if ([[deviceInfo objectForKey:MGMSIPADeviceOutputCount] unsignedIntValue]!=0 && [[deviceInfo objectForKey:MGMSIPADeviceUID] isEqual:[defaults objectForKey:MGMSIPACurrentOutputDevice]])
|
||||||
|
currentOutput = d;
|
||||||
|
|
||||||
|
if ([[deviceInfo objectForKey:MGMSIPADeviceInputCount] unsignedIntValue]!=0 || [[deviceInfo objectForKey:MGMSIPADeviceOutputCount] unsignedIntValue]!=0)
|
||||||
|
[devicesArray addObject:deviceInfo];
|
||||||
|
}
|
||||||
|
free(devices);
|
||||||
|
|
||||||
|
if (audioDevices!=nil) [audioDevices release];
|
||||||
|
audioDevices = [devicesArray copy];
|
||||||
|
|
||||||
|
[self registerThread];
|
||||||
|
|
||||||
|
pjsua_set_null_snd_dev();
|
||||||
|
pjmedia_snd_deinit();
|
||||||
|
pjmedia_snd_init(pjsua_get_pool_factory());
|
||||||
|
|
||||||
|
[self setInputSoundDevice:currentInput outputSoundDevice:currentOutput];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMSIPAudioChangedNotification object:audioDevices];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (NSArray *)audioDevices {
|
||||||
|
return audioDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)receivedNewCall:(MGMSIPCall *)theCall {
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(receivedNewCall:)]) [delegate receivedNewCall:theCall];
|
||||||
|
}
|
||||||
|
- (void)startingNewCall:(MGMSIPCall *)theCall {
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(startingNewCall:)]) [delegate startingNewCall:theCall];
|
||||||
|
}
|
||||||
|
- (NSArray *)calls {
|
||||||
|
NSMutableArray *calls = [NSMutableArray array];
|
||||||
|
for (int i=0; i<[accounts count]; i++)
|
||||||
|
[calls addObjectsFromArray:[[accounts objectAtIndex:i] calls]];
|
||||||
|
return calls;
|
||||||
|
}
|
||||||
|
- (MGMSIPCall *)callWithIdentifier:(int)theIdentifier {
|
||||||
|
for (int i=0; i<[accounts count]; i++) {
|
||||||
|
MGMSIPCall *call = [[accounts objectAtIndex:i] callWithIdentifier:theIdentifier];
|
||||||
|
if (call!=nil)
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
109
Classes/VoiceBase/SIP/MGMSIPAccount.h
Normal file
109
Classes/VoiceBase/SIP/MGMSIPAccount.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPAccount.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPAccountFullName;
|
||||||
|
extern NSString * const MGMSIPAccountUserName;
|
||||||
|
extern NSString * const MGMSIPAccountDomain;
|
||||||
|
extern NSString * const MGMSIPAccountRegistrar;
|
||||||
|
extern NSString * const MGMSIPAccountSIPAddress;
|
||||||
|
extern NSString * const MGMSIPAccountProxy;
|
||||||
|
extern NSString * const MGMSIPAccountProxyPort;
|
||||||
|
extern NSString * const MGMSIPAccountRegisterTimeout;
|
||||||
|
extern const int MGMSIPAccountDefaultProxyPort;
|
||||||
|
|
||||||
|
@class MGMSIPCall, MGMSIPURL;
|
||||||
|
|
||||||
|
@protocol MGMSIPAccountDelegate <NSObject>
|
||||||
|
- (NSString *)password;
|
||||||
|
- (void)loggedIn;
|
||||||
|
- (void)loginErrored;
|
||||||
|
- (void)loggedOut;
|
||||||
|
- (void)logoutErrored;
|
||||||
|
- (void)registrationChanged;
|
||||||
|
- (void)receivedNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)startingNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)gotNewCall:(MGMSIPCall *)theCall;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMSIPAccount : NSObject {
|
||||||
|
id<MGMSIPAccountDelegate> delegate;
|
||||||
|
NSString *fullName;
|
||||||
|
NSString *userName;
|
||||||
|
NSString *domain;
|
||||||
|
NSString *registrar;
|
||||||
|
NSString *SIPAddress;
|
||||||
|
NSString *proxy;
|
||||||
|
int proxyPort;
|
||||||
|
int reregisterTimeout;
|
||||||
|
NSTimer *reregisterTimer;
|
||||||
|
|
||||||
|
int identifier;
|
||||||
|
|
||||||
|
NSMutableArray *calls;
|
||||||
|
|
||||||
|
NSString *lastError;
|
||||||
|
}
|
||||||
|
- (id)initWithSettings:(NSDictionary *)theSettings;
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain;
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain SIPAddress:(NSString *)theSIPAddress;
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain SIPAddress:(NSString *)theSIPAddress registrar:(NSString *)theRegistrar;
|
||||||
|
- (BOOL)informationComplete;
|
||||||
|
- (id<MGMSIPAccountDelegate>)delegate;
|
||||||
|
- (void)setDelegate:(id)theDelegate;
|
||||||
|
- (NSString *)fullName;
|
||||||
|
- (void)setFullName:(NSString *)theFullName;
|
||||||
|
- (NSString *)userName;
|
||||||
|
- (void)setUserName:(NSString *)theUserName;
|
||||||
|
- (NSString *)domain;
|
||||||
|
- (void)setDomain:(NSString *)theDomain;
|
||||||
|
- (NSString *)registrar;
|
||||||
|
- (void)setRegistrar:(NSString *)theRegistrar;
|
||||||
|
- (NSString *)SIPAddress;
|
||||||
|
- (void)setSIPAddress:(NSString *)theSIPAddress;
|
||||||
|
- (NSString *)proxy;
|
||||||
|
- (void)setProxy:(NSString *)theProxy;
|
||||||
|
- (int)proxyPort;
|
||||||
|
- (void)setProxyPort:(int)theProxyPort;
|
||||||
|
- (int)reregisterTimeout;
|
||||||
|
- (void)setReregisterTimeout:(int)theReregisterTimeout;
|
||||||
|
- (int)identifier;
|
||||||
|
- (void)setIdentifier:(int)theIdentifier;
|
||||||
|
- (NSString *)password;
|
||||||
|
- (NSDictionary *)settings;
|
||||||
|
|
||||||
|
- (void)setLastError:(NSString *)theError;
|
||||||
|
- (NSString *)lastError;
|
||||||
|
|
||||||
|
- (BOOL)isLoggedIn;
|
||||||
|
- (void)login;
|
||||||
|
- (void)loginErrored;
|
||||||
|
- (void)logout;
|
||||||
|
- (void)logoutErrored;
|
||||||
|
|
||||||
|
- (BOOL)isRegistered;
|
||||||
|
- (void)reregister;
|
||||||
|
- (void)setRegistered:(BOOL)isRegistered;
|
||||||
|
- (int)registrationStatus;
|
||||||
|
- (NSString *)registrationStatusText;
|
||||||
|
- (int)registrationExpireTime;
|
||||||
|
|
||||||
|
- (BOOL)isOnline;
|
||||||
|
- (void)setOnline:(BOOL)isOnline;
|
||||||
|
- (NSString *)onlineStatusText;
|
||||||
|
|
||||||
|
- (MGMSIPCall *)addCallWithIdentifier:(int)theIndentifier;
|
||||||
|
- (MGMSIPCall *)makeCallToNumber:(NSString *)theNumber;
|
||||||
|
- (MGMSIPCall *)makeCallToSIPURL:(MGMSIPURL *)theURL;
|
||||||
|
- (NSArray *)calls;
|
||||||
|
- (MGMSIPCall *)callWithIdentifier:(int)theIdentifier;
|
||||||
|
- (void)removeCall:(MGMSIPCall *)theCall;
|
||||||
|
@end
|
||||||
|
#endif
|
375
Classes/VoiceBase/SIP/MGMSIPAccount.m
Normal file
375
Classes/VoiceBase/SIP/MGMSIPAccount.m
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPAccount.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPAccount.h"
|
||||||
|
#import "MGMSIP.h"
|
||||||
|
#import "MGMSIPCall.h"
|
||||||
|
#import "MGMSIPURL.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
|
||||||
|
NSString * const MGMSIPAccountFullName = @"MGMSIPAccountFullName";
|
||||||
|
NSString * const MGMSIPAccountUserName = @"MGMSIPAccountUserName";
|
||||||
|
NSString * const MGMSIPAccountDomain = @"MGMSIPAccountDomain";
|
||||||
|
NSString * const MGMSIPAccountRegistrar = @"MGMSIPAccountRegistrar";
|
||||||
|
NSString * const MGMSIPAccountSIPAddress = @"MGMSIPAccountSIPAddress";
|
||||||
|
NSString * const MGMSIPAccountProxy = @"MGMSIPAccountProxy";
|
||||||
|
NSString * const MGMSIPAccountProxyPort = @"MGMSIPAccountProxyPort";
|
||||||
|
NSString * const MGMSIPAccountRegisterTimeout = @"MGMSIPAccountRegisterTimeout";
|
||||||
|
const int MGMSIPAccountDefaultProxyPort = 5060;
|
||||||
|
|
||||||
|
const int MGMSIPAccountReregisterTimeoutMin = 60;
|
||||||
|
const int MGMSIPAccountReregisterTimeoutMax = 3600;
|
||||||
|
const int MGMSIPAccountReregisterTimeoutDefault = 300;
|
||||||
|
|
||||||
|
@implementation MGMSIPAccount
|
||||||
|
- (id)initWithSettings:(NSDictionary *)theSettings {
|
||||||
|
if (self = [self init]) {
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountUserName]==nil || [[theSettings objectForKey:MGMSIPAccountUserName] isEqual:@""] || [theSettings objectForKey:MGMSIPAccountDomain]==nil || [[theSettings objectForKey:MGMSIPAccountDomain] isEqual:@""]) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountFullName]!=nil && ![[theSettings objectForKey:MGMSIPAccountFullName] isEqual:@""])
|
||||||
|
fullName = [[theSettings objectForKey:MGMSIPAccountFullName] copy];
|
||||||
|
userName = [[theSettings objectForKey:MGMSIPAccountUserName] copy];
|
||||||
|
domain = [[theSettings objectForKey:MGMSIPAccountDomain] copy];
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountRegistrar]!=nil && ![[theSettings objectForKey:MGMSIPAccountRegistrar] isEqual:@""])
|
||||||
|
registrar = [[theSettings objectForKey:MGMSIPAccountRegistrar] copy];
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountSIPAddress]!=nil && ![[theSettings objectForKey:MGMSIPAccountSIPAddress] isEqual:@""])
|
||||||
|
SIPAddress = [[theSettings objectForKey:MGMSIPAccountSIPAddress] copy];
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountProxy]!=nil && ![[theSettings objectForKey:MGMSIPAccountProxy] isEqual:@""])
|
||||||
|
proxy = [[theSettings objectForKey:MGMSIPAccountProxy] copy];
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountProxyPort]!=nil && [[theSettings objectForKey:MGMSIPAccountProxyPort] intValue]!=0)
|
||||||
|
proxyPort = [[theSettings objectForKey:MGMSIPAccountProxyPort] intValue];
|
||||||
|
else
|
||||||
|
proxyPort = 0;
|
||||||
|
if ([theSettings objectForKey:MGMSIPAccountRegisterTimeout]!=nil && [[theSettings objectForKey:MGMSIPAccountRegisterTimeout] intValue]!=0)
|
||||||
|
reregisterTimeout = [[theSettings objectForKey:MGMSIPAccountRegisterTimeout] intValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain {
|
||||||
|
return [self initWithFullName:theFullName userName:theUserName domain:theDomain SIPAddress:nil];
|
||||||
|
}
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain SIPAddress:(NSString *)theSIPAddress {
|
||||||
|
return [self initWithFullName:theFullName userName:theUserName domain:theDomain SIPAddress:theSIPAddress registrar:nil];
|
||||||
|
}
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName domain:(NSString *)theDomain SIPAddress:(NSString *)theSIPAddress registrar:(NSString *)theRegistrar {
|
||||||
|
if (theUserName==nil || theDomain==nil) return nil;
|
||||||
|
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
|
||||||
|
if (theFullName!=nil)
|
||||||
|
[settings setObject:theFullName forKey:MGMSIPAccountFullName];
|
||||||
|
[settings setObject:theUserName forKey:MGMSIPAccountUserName];
|
||||||
|
[settings setObject:theDomain forKey:MGMSIPAccountDomain];
|
||||||
|
if (theSIPAddress!=nil)
|
||||||
|
[settings setObject:theSIPAddress forKey:MGMSIPAccountSIPAddress];
|
||||||
|
if (theRegistrar!=nil)
|
||||||
|
[settings setObject:theRegistrar forKey:MGMSIPAccountRegistrar];
|
||||||
|
return [self initWithSettings:settings];
|
||||||
|
}
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
reregisterTimeout = MGMSIPAccountReregisterTimeoutDefault;
|
||||||
|
identifier = PJSUA_INVALID_ID;
|
||||||
|
calls = [NSMutableArray new];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkConnected:) name:MGMNetworkConnectedNotification object:nil];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[self logout];
|
||||||
|
if (calls!=nil)
|
||||||
|
[calls release];
|
||||||
|
if (fullName!=nil)
|
||||||
|
[fullName release];
|
||||||
|
if (userName!=nil)
|
||||||
|
[userName release];
|
||||||
|
if (domain!=nil)
|
||||||
|
[domain release];
|
||||||
|
if (registrar!=nil)
|
||||||
|
[registrar release];
|
||||||
|
if (SIPAddress!=nil)
|
||||||
|
[SIPAddress release];
|
||||||
|
if (proxy!=nil)
|
||||||
|
[proxy release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)informationComplete {
|
||||||
|
return ((delegate!=nil && [delegate respondsToSelector:@selector(password)]) && userName!=nil && (domain!=nil || [self SIPAddress]!=nil));
|
||||||
|
}
|
||||||
|
- (NSString *)description {
|
||||||
|
return [NSString stringWithFormat:@"%@ %@", [super description], [self SIPAddress]];
|
||||||
|
}
|
||||||
|
- (id<MGMSIPAccountDelegate>)delegate {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
- (void)setDelegate:(id)theDelegate {
|
||||||
|
delegate = theDelegate;
|
||||||
|
}
|
||||||
|
- (NSString *)fullName {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
- (void)setFullName:(NSString *)theFullName {
|
||||||
|
if (fullName!=nil) [fullName release];
|
||||||
|
fullName = [theFullName copy];
|
||||||
|
}
|
||||||
|
- (NSString *)userName {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
- (void)setUserName:(NSString *)theUserName {
|
||||||
|
if (theUserName==nil || [theUserName isEqual:@""]) return;
|
||||||
|
if (userName!=nil) [userName release];
|
||||||
|
userName = [theUserName copy];
|
||||||
|
}
|
||||||
|
- (NSString *)domain {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
- (void)setDomain:(NSString *)theDomain {
|
||||||
|
if (domain!=nil) [domain release];
|
||||||
|
domain = [theDomain copy];
|
||||||
|
}
|
||||||
|
- (NSString *)registrar {
|
||||||
|
if (registrar==nil && domain!=nil) return domain;
|
||||||
|
return registrar;
|
||||||
|
}
|
||||||
|
- (void)setRegistrar:(NSString *)theRegistrar {
|
||||||
|
if (registrar!=nil) [registrar release];
|
||||||
|
registrar = [theRegistrar copy];
|
||||||
|
}
|
||||||
|
- (NSString *)SIPAddress {
|
||||||
|
if (SIPAddress==nil && domain!=nil && userName!=nil)
|
||||||
|
return [NSString stringWithFormat:@"%@@%@", userName, domain];
|
||||||
|
return SIPAddress;
|
||||||
|
}
|
||||||
|
- (void)setSIPAddress:(NSString *)theSIPAddress {
|
||||||
|
if (SIPAddress!=nil) [SIPAddress release];
|
||||||
|
SIPAddress = [theSIPAddress copy];
|
||||||
|
}
|
||||||
|
- (NSString *)proxy {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
- (void)setProxy:(NSString *)theProxy {
|
||||||
|
if (proxy!=nil) [proxy release];
|
||||||
|
proxy = [theProxy copy];
|
||||||
|
}
|
||||||
|
- (int)proxyPort {
|
||||||
|
if (proxyPort==0) return MGMSIPAccountDefaultProxyPort;
|
||||||
|
return proxyPort;
|
||||||
|
}
|
||||||
|
- (void)setProxyPort:(int)theProxyPort {
|
||||||
|
proxyPort = theProxyPort;
|
||||||
|
}
|
||||||
|
- (int)reregisterTimeout {
|
||||||
|
return reregisterTimeout;
|
||||||
|
}
|
||||||
|
- (void)setReregisterTimeout:(int)theReregisterTimeout {
|
||||||
|
if (theReregisterTimeout==0)
|
||||||
|
reregisterTimeout = MGMSIPAccountReregisterTimeoutDefault;
|
||||||
|
else if (theReregisterTimeout < MGMSIPAccountReregisterTimeoutMin)
|
||||||
|
reregisterTimeout = MGMSIPAccountReregisterTimeoutMin;
|
||||||
|
else if (theReregisterTimeout > MGMSIPAccountReregisterTimeoutMax)
|
||||||
|
reregisterTimeout = MGMSIPAccountReregisterTimeoutMax;
|
||||||
|
else
|
||||||
|
reregisterTimeout = theReregisterTimeout;
|
||||||
|
}
|
||||||
|
- (int)identifier {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
- (void)setIdentifier:(int)theIdentifier {
|
||||||
|
identifier = theIdentifier;
|
||||||
|
}
|
||||||
|
- (NSString *)password {
|
||||||
|
NSString *password = nil;
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(password)])
|
||||||
|
password = [delegate password];
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)settings {
|
||||||
|
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
|
||||||
|
if (fullName!=nil)
|
||||||
|
[settings setObject:fullName forKey:MGMSIPAccountFullName];
|
||||||
|
if (userName!=nil)
|
||||||
|
[settings setObject:userName forKey:MGMSIPAccountUserName];
|
||||||
|
if (domain!=nil)
|
||||||
|
[settings setObject:domain forKey:MGMSIPAccountDomain];
|
||||||
|
if (registrar!=nil)
|
||||||
|
[settings setObject:registrar forKey:MGMSIPAccountRegistrar];
|
||||||
|
if (SIPAddress!=nil)
|
||||||
|
[settings setObject:SIPAddress forKey:MGMSIPAccountSIPAddress];
|
||||||
|
if (proxy!=nil)
|
||||||
|
[settings setObject:proxy forKey:MGMSIPAccountProxy];
|
||||||
|
if (proxyPort!=0)
|
||||||
|
[settings setObject:[NSNumber numberWithInt:proxyPort] forKey:MGMSIPAccountProxyPort];
|
||||||
|
if (reregisterTimeout!=0)
|
||||||
|
[settings setObject:[NSNumber numberWithInt:reregisterTimeout] forKey:MGMSIPAccountRegisterTimeout];
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLastError:(NSString *)theError {
|
||||||
|
if (lastError!=nil) [lastError release];
|
||||||
|
lastError = [theError copy];
|
||||||
|
}
|
||||||
|
- (NSString *)lastError {
|
||||||
|
return (lastError!=nil ? lastError : @"");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isLoggedIn {
|
||||||
|
return (identifier!=PJSUA_INVALID_ID);
|
||||||
|
}
|
||||||
|
- (void)login {
|
||||||
|
[[MGMSIP sharedSIP] loginToAccount:self];
|
||||||
|
}
|
||||||
|
- (void)loginErrored {
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(loginErrored)]) [delegate loginErrored];
|
||||||
|
}
|
||||||
|
- (void)logout {
|
||||||
|
[[MGMSIP sharedSIP] logoutOfAccount:self];
|
||||||
|
}
|
||||||
|
- (void)logoutErrored {
|
||||||
|
if (delegate!=nil && [delegate respondsToSelector:@selector(logoutErrored)]) [delegate logoutErrored];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isRegistered {
|
||||||
|
return (([self registrationStatus]/100)==2 && [self registrationExpireTime]>0);
|
||||||
|
}
|
||||||
|
- (void)reregister {
|
||||||
|
[self setRegistered:YES];
|
||||||
|
}
|
||||||
|
- (void)setRegistered:(BOOL)isRegistered {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_set_registration(identifier, (isRegistered ? PJ_TRUE : PJ_FALSE));
|
||||||
|
[self setOnline:isRegistered];
|
||||||
|
}
|
||||||
|
- (void)networkConnected:(NSNotification *)theNotification {
|
||||||
|
if ([self isLoggedIn])
|
||||||
|
[self performSelector:@selector(reregister) withObject:nil afterDelay:1.0];
|
||||||
|
}
|
||||||
|
- (int)registrationStatus {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_info accountInfo;
|
||||||
|
pj_status_t status = pjsua_acc_get_info(identifier, &accountInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
return 0;
|
||||||
|
return accountInfo.status;
|
||||||
|
}
|
||||||
|
- (NSString *)registrationStatusText {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_info accountInfo;
|
||||||
|
pj_status_t status = pjsua_acc_get_info(identifier, &accountInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
return nil;
|
||||||
|
return [NSString stringWithPJString:accountInfo.status_text];
|
||||||
|
}
|
||||||
|
- (int)registrationExpireTime {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_info accountInfo;
|
||||||
|
pj_status_t status = pjsua_acc_get_info(identifier, &accountInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
return accountInfo.expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOnline {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_info accountInfo;
|
||||||
|
pj_status_t status = pjsua_acc_get_info(identifier, &accountInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
return NO;
|
||||||
|
return (accountInfo.online_status==PJ_TRUE);
|
||||||
|
}
|
||||||
|
- (void)setOnline:(BOOL)isOnline {
|
||||||
|
if ([self identifier]==PJSUA_INVALID_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_acc_set_online_status(identifier, (isOnline ? PJ_TRUE : PJ_FALSE));
|
||||||
|
if (status==PJ_SUCCESS) {
|
||||||
|
if (reregisterTimer!=nil) {
|
||||||
|
[reregisterTimer invalidate];
|
||||||
|
[reregisterTimer release];
|
||||||
|
reregisterTimer = nil;
|
||||||
|
}
|
||||||
|
if (isOnline)
|
||||||
|
reregisterTimer = [[NSTimer scheduledTimerWithTimeInterval:(float)reregisterTimeout target:self selector:@selector(reregister) userInfo:nil repeats:YES] retain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (NSString *)onlineStatusText {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_acc_info accountInfo;
|
||||||
|
pj_status_t status = pjsua_acc_get_info(identifier, &accountInfo);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
return nil;
|
||||||
|
return [NSString stringWithPJString:accountInfo.online_status_text];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMSIPCall *)addCallWithIdentifier:(int)theIndentifier {
|
||||||
|
MGMSIPCall *call = [[[MGMSIPCall alloc] initWithIdentifier:theIndentifier account:self] autorelease];
|
||||||
|
[calls addObject:call];
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
- (MGMSIPCall *)makeCallToNumber:(NSString *)theNumber {
|
||||||
|
MGMSIPURL *SIPURL = [MGMSIPURL URLWithFullName:nil userName:theNumber host:domain];
|
||||||
|
return [self makeCallToSIPURL:SIPURL];
|
||||||
|
}
|
||||||
|
- (MGMSIPCall *)makeCallToSIPURL:(MGMSIPURL *)theURL {
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_call_id callIdentifier;
|
||||||
|
pj_str_t url = [[theURL SIPID] PJString];
|
||||||
|
pj_status_t status = pjsua_call_make_call(identifier, &url, 0, NULL, NULL, &callIdentifier);
|
||||||
|
MGMSIPCall *call = nil;
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Unable to make call to %@ with account %@", theURL, self);
|
||||||
|
} else {
|
||||||
|
call = [self callWithIdentifier:callIdentifier];
|
||||||
|
}
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
- (NSArray *)calls {
|
||||||
|
return calls;
|
||||||
|
}
|
||||||
|
- (MGMSIPCall *)callWithIdentifier:(int)theIdentifier {
|
||||||
|
for (int i=0; i<[calls count]; i++) {
|
||||||
|
if ([(MGMSIPCall *)[calls objectAtIndex:i] identifier]==theIdentifier)
|
||||||
|
return [calls objectAtIndex:i];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (void)removeCall:(MGMSIPCall *)theCall {
|
||||||
|
[calls removeObject:theCall];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
121
Classes/VoiceBase/SIP/MGMSIPCall.h
Normal file
121
Classes/VoiceBase/SIP/MGMSIPCall.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPCall.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <pjsua-lib/pjsua.h>
|
||||||
|
|
||||||
|
@class MGMSIPCall, MGMSIPAccount, MGMSIPURL;
|
||||||
|
|
||||||
|
@protocol MGMSIPCallDelegate <NSObject>
|
||||||
|
- (void)stateChanged:(MGMSIPCall *)theCall;
|
||||||
|
- (void)disconnected:(MGMSIPCall *)theCall;
|
||||||
|
- (void)early:(MGMSIPCall *)theCall code:(int)theCode reason:(NSString *)theReason;
|
||||||
|
- (void)calling:(MGMSIPCall *)theCall;
|
||||||
|
- (void)connecting:(MGMSIPCall *)theCall;
|
||||||
|
- (void)confirmed:(MGMSIPCall *)theCall;
|
||||||
|
- (void)mediaStateChanged:(MGMSIPCall *)theCall;
|
||||||
|
- (void)becameActive:(MGMSIPCall *)theCall;
|
||||||
|
- (void)localPlacedHold:(MGMSIPCall *)theCall;
|
||||||
|
- (void)remotePlacedHold:(MGMSIPCall *)theCall;
|
||||||
|
- (void)transferStatusCahgned:(MGMSIPCall *)theCall;
|
||||||
|
@end
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MGMSIPCallNULLState = PJSIP_INV_STATE_NULL,
|
||||||
|
MGMSIPCallCallingState = PJSIP_INV_STATE_CALLING,
|
||||||
|
MGMSIPCallIncomingState = PJSIP_INV_STATE_INCOMING,
|
||||||
|
MGMSIPCallEarlyState = PJSIP_INV_STATE_EARLY,
|
||||||
|
MGMSIPCallConnectingState = PJSIP_INV_STATE_CONNECTING,
|
||||||
|
MGMSIPCallConfirmedState = PJSIP_INV_STATE_CONFIRMED,
|
||||||
|
MGMSIPCallDisconnectedState = PJSIP_INV_STATE_DISCONNECTED
|
||||||
|
} MGMSIPCallState;
|
||||||
|
|
||||||
|
@interface MGMSIPCall : NSObject {
|
||||||
|
id<MGMSIPCallDelegate> delegate;
|
||||||
|
MGMSIPAccount *account;
|
||||||
|
int identifier;
|
||||||
|
|
||||||
|
MGMSIPURL *remoteURL;
|
||||||
|
MGMSIPURL *localURL;
|
||||||
|
MGMSIPCallState state;
|
||||||
|
NSString *stateText;
|
||||||
|
int lastStatus;
|
||||||
|
NSString *lastStatusText;
|
||||||
|
int transferStatus;
|
||||||
|
NSString *transferStatusText;
|
||||||
|
BOOL incoming;
|
||||||
|
BOOL muted;
|
||||||
|
BOOL micMuted;
|
||||||
|
NSString *holdMusicPath;
|
||||||
|
BOOL onHold;
|
||||||
|
pjsua_player_id holdMusicPlayer;
|
||||||
|
pjsua_recorder_id recorderID;
|
||||||
|
|
||||||
|
BOOL isRingbackOn;
|
||||||
|
}
|
||||||
|
- (id)initWithIdentifier:(int)theIdentifier account:(MGMSIPAccount *)theAccount;
|
||||||
|
|
||||||
|
- (id<MGMSIPCallDelegate>)delegate;
|
||||||
|
- (void)setDelegate:(id)theDelegate;
|
||||||
|
- (MGMSIPAccount *)account;
|
||||||
|
- (int)identifier;
|
||||||
|
- (void)setIdentifier:(int)theIdentifier;
|
||||||
|
|
||||||
|
- (MGMSIPURL *)remoteURL;
|
||||||
|
- (MGMSIPURL *)localURL;
|
||||||
|
|
||||||
|
- (MGMSIPCallState)state;
|
||||||
|
- (void)setState:(MGMSIPCallState)theState;
|
||||||
|
- (NSString *)stateText;
|
||||||
|
- (void)setStateText:(NSString *)theStateText;
|
||||||
|
- (int)lastStatus;
|
||||||
|
- (void)setLastStatus:(int)theLastStatus;
|
||||||
|
- (NSString *)lastStatusText;
|
||||||
|
- (void)setLastStatusText:(NSString *)theLastStatusText;
|
||||||
|
- (int)transferStatus;
|
||||||
|
- (void)setTransferStatus:(int)theTransferStatus;
|
||||||
|
- (NSString *)transferStatusText;
|
||||||
|
- (void)setTransferStatusText:(NSString *)theTransferStatusText;;
|
||||||
|
- (BOOL)isIncoming;
|
||||||
|
|
||||||
|
- (BOOL)isActive;
|
||||||
|
- (BOOL)hasMedia;
|
||||||
|
- (BOOL)hasActiveMedia;
|
||||||
|
|
||||||
|
- (BOOL)isLocalOnHold;
|
||||||
|
- (BOOL)isRemoteOnHold;
|
||||||
|
- (void)setHoldMusicPath:(NSString *)thePath;
|
||||||
|
- (void)hold;
|
||||||
|
|
||||||
|
- (void)answer;
|
||||||
|
- (void)hangUp;
|
||||||
|
|
||||||
|
- (void)sendRingingNotification;
|
||||||
|
|
||||||
|
- (void)replyWithTemporarilyUnavailable;
|
||||||
|
|
||||||
|
- (void)startRingback;
|
||||||
|
- (void)stopRingback;
|
||||||
|
|
||||||
|
- (void)sendDTMFDigits:(NSString *)theDigits;
|
||||||
|
|
||||||
|
- (void)playSound:(NSString *)theFile;
|
||||||
|
- (pjsua_player_id)playSoundMain:(NSString *)theFile loop:(BOOL)shouldLoop;
|
||||||
|
- (void)stopPlayingSound:(pjsua_player_id *)thePlayerID;
|
||||||
|
|
||||||
|
- (BOOL)isRecording;
|
||||||
|
- (void)startRecording:(NSString *)toFile;
|
||||||
|
- (void)stopRecording;
|
||||||
|
|
||||||
|
- (BOOL)isMuted;
|
||||||
|
- (void)mute;
|
||||||
|
- (BOOL)isMicMuted;
|
||||||
|
- (void)muteMic;
|
||||||
|
@end
|
||||||
|
#endif
|
428
Classes/VoiceBase/SIP/MGMSIPCall.m
Normal file
428
Classes/VoiceBase/SIP/MGMSIPCall.m
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPCall.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/10/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPCall.h"
|
||||||
|
#import "MGMSIPAccount.h"
|
||||||
|
#import "MGMSIPURL.h"
|
||||||
|
#import "MGMSIP.h"
|
||||||
|
#import "MGMAddons.h"
|
||||||
|
|
||||||
|
@implementation MGMSIPCall
|
||||||
|
- (id)initWithIdentifier:(int)theIdentifier account:(MGMSIPAccount *)theAccount {
|
||||||
|
if (self = [super init]) {
|
||||||
|
account = theAccount;
|
||||||
|
identifier = theIdentifier;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_call_info callInfo;
|
||||||
|
pj_status_t status = pjsua_call_get_info(identifier, &callInfo);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
remoteURL = [[MGMSIPURL URLWithSIPID:[NSString stringWithPJString:callInfo.remote_info]] retain];
|
||||||
|
localURL = [[MGMSIPURL URLWithSIPID:[NSString stringWithPJString:callInfo.local_info]] retain];
|
||||||
|
state = callInfo.state;
|
||||||
|
stateText = [[NSString stringWithPJString:callInfo.state_text] copy];
|
||||||
|
lastStatus = callInfo.last_status;
|
||||||
|
lastStatusText = [[NSString stringWithPJString:callInfo.last_status_text] copy];
|
||||||
|
onHold = NO;
|
||||||
|
holdMusicPlayer = PJSUA_INVALID_ID;
|
||||||
|
recorderID = PJSUA_INVALID_ID;
|
||||||
|
|
||||||
|
incoming = (state==MGMSIPCallIncomingState);
|
||||||
|
muted = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (isRingbackOn)
|
||||||
|
[self stopRingback];
|
||||||
|
[self hangUp];
|
||||||
|
if (remoteURL!=nil)
|
||||||
|
[remoteURL release];
|
||||||
|
if (localURL!=nil)
|
||||||
|
[localURL release];
|
||||||
|
if (stateText!=nil)
|
||||||
|
[stateText release];
|
||||||
|
if (lastStatusText!=nil)
|
||||||
|
[lastStatusText release];
|
||||||
|
if (transferStatusText!=nil)
|
||||||
|
[transferStatusText release];
|
||||||
|
if (holdMusicPath!=nil)
|
||||||
|
[holdMusicPath release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)description {
|
||||||
|
return [NSString stringWithFormat:@"Remote: %@ Local: %@", remoteURL, localURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MGMSIPCallDelegate>)delegate {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
- (void)setDelegate:(id)theDelegate {
|
||||||
|
delegate = theDelegate;
|
||||||
|
}
|
||||||
|
- (MGMSIPAccount *)account {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
- (int)identifier {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
- (void)setIdentifier:(int)theIdentifier {
|
||||||
|
identifier = theIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMSIPURL *)remoteURL {
|
||||||
|
return remoteURL;
|
||||||
|
}
|
||||||
|
- (MGMSIPURL *)localURL {
|
||||||
|
return localURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMSIPCallState)state {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
- (void)setState:(MGMSIPCallState)theState {
|
||||||
|
if (theState==MGMSIPCallDisconnectedState) {
|
||||||
|
if (holdMusicPlayer!=PJSUA_INVALID_ID)
|
||||||
|
[self performSelectorOnMainThread:@selector(stopHoldMusic) withObject:nil waitUntilDone:NO];
|
||||||
|
if (recorderID!=PJSUA_INVALID_ID)
|
||||||
|
[self performSelectorOnMainThread:@selector(stopRecordingMain) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
state = theState;
|
||||||
|
}
|
||||||
|
- (NSString *)stateText {
|
||||||
|
return stateText;
|
||||||
|
}
|
||||||
|
- (void)setStateText:(NSString *)theStateText {
|
||||||
|
if (stateText!=nil) [stateText release];
|
||||||
|
stateText = [theStateText copy];
|
||||||
|
}
|
||||||
|
- (int)lastStatus {
|
||||||
|
return lastStatus;
|
||||||
|
}
|
||||||
|
- (void)setLastStatus:(int)theLastStatus {
|
||||||
|
lastStatus = theLastStatus;
|
||||||
|
}
|
||||||
|
- (NSString *)lastStatusText {
|
||||||
|
return lastStatusText;
|
||||||
|
}
|
||||||
|
- (void)setLastStatusText:(NSString *)theLastStatusText {
|
||||||
|
if (lastStatusText!=nil) [lastStatusText release];
|
||||||
|
lastStatusText = [theLastStatusText copy];
|
||||||
|
}
|
||||||
|
- (int)transferStatus {
|
||||||
|
return transferStatus;
|
||||||
|
}
|
||||||
|
- (void)setTransferStatus:(int)theTransferStatus {
|
||||||
|
transferStatus = theTransferStatus;
|
||||||
|
}
|
||||||
|
- (NSString *)transferStatusText {
|
||||||
|
return transferStatusText;
|
||||||
|
}
|
||||||
|
- (void)setTransferStatusText:(NSString *)theTransferStatusText {
|
||||||
|
if (transferStatusText!=nil) [transferStatusText release];
|
||||||
|
transferStatusText = [theTransferStatusText copy];
|
||||||
|
}
|
||||||
|
- (BOOL)isIncoming {
|
||||||
|
return incoming;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isActive {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
return pjsua_call_is_active(identifier);
|
||||||
|
}
|
||||||
|
- (BOOL)hasMedia {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
return pjsua_call_has_media(identifier);
|
||||||
|
}
|
||||||
|
- (BOOL)hasActiveMedia {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_call_info callInfo;
|
||||||
|
pjsua_call_get_info(identifier, &callInfo);
|
||||||
|
return (callInfo.media_status==PJSUA_CALL_MEDIA_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isLocalOnHold {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return onHold;
|
||||||
|
}
|
||||||
|
- (BOOL)isRemoteOnHold {
|
||||||
|
if (identifier==PJSUA_INVALID_ID)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_call_info callInfo;
|
||||||
|
pjsua_call_get_info(identifier, &callInfo);
|
||||||
|
return (callInfo.media_status==PJSUA_CALL_MEDIA_REMOTE_HOLD);
|
||||||
|
}
|
||||||
|
- (void)setHoldMusicPath:(NSString *)thePath {
|
||||||
|
if (holdMusicPath!=nil) [holdMusicPath release];
|
||||||
|
holdMusicPath = [thePath copy];
|
||||||
|
}
|
||||||
|
- (void)hold {
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
if (state==MGMSIPCallConfirmedState) {
|
||||||
|
pjsua_conf_port_id conf_port = pjsua_call_get_conf_port(identifier);
|
||||||
|
if (!onHold) {
|
||||||
|
onHold = YES;
|
||||||
|
pjsua_conf_disconnect(0, conf_port);
|
||||||
|
pjsua_conf_adjust_rx_level(conf_port, 0);
|
||||||
|
[self performSelectorOnMainThread:@selector(startHoldMusic) withObject:nil waitUntilDone:NO];
|
||||||
|
} else {
|
||||||
|
onHold = NO;
|
||||||
|
pjsua_conf_connect(0, conf_port);
|
||||||
|
pjsua_conf_adjust_rx_level(conf_port, [[MGMSIP sharedSIP] micVolume]);
|
||||||
|
[self performSelectorOnMainThread:@selector(stopHoldMusic) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)startHoldMusic {
|
||||||
|
if (holdMusicPlayer!=PJSUA_INVALID_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
holdMusicPlayer = [self playSoundMain:holdMusicPath loop:YES];
|
||||||
|
}
|
||||||
|
- (void)stopHoldMusic {
|
||||||
|
[self stopPlayingSound:&holdMusicPlayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)answer {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_call_answer(identifier, PJSIP_SC_OK, NULL, NULL);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error answering call %@", self);
|
||||||
|
}
|
||||||
|
- (void)hangUp {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_call_hangup(identifier, 0, NULL, NULL);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error hanging up call %@", self);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendRingingNotification {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_call_answer(identifier, PJSIP_SC_RINGING, NULL, NULL);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error sending ringing notification to call %@", self);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replyWithTemporarilyUnavailable {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status = pjsua_call_answer(identifier, PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL, NULL);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error replying 480 Temporarily Unavailable");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startRingback {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isRingbackOn)
|
||||||
|
return;
|
||||||
|
isRingbackOn = YES;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] setRingbackCount:[[MGMSIP sharedSIP] ringbackCount]+1];
|
||||||
|
if ([[MGMSIP sharedSIP] ringbackCount]==1 && [[MGMSIP sharedSIP] ringbackSlot]!=PJSUA_INVALID_ID)
|
||||||
|
pjsua_conf_connect([[MGMSIP sharedSIP] ringbackSlot], 0);
|
||||||
|
}
|
||||||
|
- (void)stopRingback {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state==MGMSIPCallDisconnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isRingbackOn)
|
||||||
|
return;
|
||||||
|
isRingbackOn = NO;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
int ringbackCount = [[MGMSIP sharedSIP] ringbackCount];
|
||||||
|
if (ringbackCount<0) return;
|
||||||
|
[[MGMSIP sharedSIP] setRingbackCount:ringbackCount-1];
|
||||||
|
if ([[MGMSIP sharedSIP] ringbackSlot]!=PJSUA_INVALID_ID) {
|
||||||
|
pjsua_conf_disconnect([[MGMSIP sharedSIP] ringbackSlot], 0);
|
||||||
|
pjmedia_tonegen_rewind([[MGMSIP sharedSIP] ringbackPort]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendDTMFDigits:(NSString *)theDigits {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state!=MGMSIPCallConfirmedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_str_t digits = [theDigits PJString];
|
||||||
|
pj_status_t status = pjsua_call_dial_dtmf(identifier, &digits);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
const pj_str_t INFO = pj_str("INFO");
|
||||||
|
for (unsigned int i=0; i<[theDigits length]; i++) {
|
||||||
|
pjsua_msg_data messageData;
|
||||||
|
pjsua_msg_data_init(&messageData);
|
||||||
|
messageData.content_type = pj_str("application/dtmf-relay");
|
||||||
|
messageData.msg_body = [[NSString stringWithFormat:@"Signal=%C\r\nDuration=300", [theDigits characterAtIndex:i]] PJString];
|
||||||
|
|
||||||
|
status = pjsua_call_send_request(identifier, &INFO, &messageData);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Unable to send DTMF with status %d.", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)playSound:(NSString *)theFile {
|
||||||
|
NSMethodSignature *signature = [self methodSignatureForSelector:@selector(playSoundMain:loop:)];
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||||
|
[invocation setSelector:@selector(playSoundMain:loop:)];
|
||||||
|
[invocation setArgument:&theFile atIndex:2];
|
||||||
|
BOOL shouldLoop = NO;
|
||||||
|
[invocation setArgument:&shouldLoop atIndex:3];
|
||||||
|
[invocation performSelectorOnMainThread:@selector(invokeWithTarget:) withObject:self waitUntilDone:YES];
|
||||||
|
}
|
||||||
|
- (pjsua_player_id)playSoundMain:(NSString *)theFile loop:(BOOL)shouldLoop {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || state!=MGMSIPCallConfirmedState)
|
||||||
|
return PJSUA_INVALID_ID;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_player_id player_id = PJSUA_INVALID_ID;
|
||||||
|
if (theFile==nil || ![[NSFileManager defaultManager] fileExistsAtPath:theFile])
|
||||||
|
return player_id;
|
||||||
|
pj_str_t file = [theFile PJString];
|
||||||
|
pj_status_t status = pjsua_player_create(&file, (shouldLoop ? 0 : PJMEDIA_FILE_NO_LOOP), &player_id);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Couldn't create player");
|
||||||
|
return PJSUA_INVALID_ID;
|
||||||
|
} else {
|
||||||
|
status = pjsua_conf_connect(pjsua_player_get_conf_port(player_id), pjsua_call_get_conf_port(identifier));
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Unable to play sound");
|
||||||
|
}
|
||||||
|
return player_id;
|
||||||
|
}
|
||||||
|
- (void)stopPlayingSound:(pjsua_player_id *)thePlayerID {
|
||||||
|
if (*thePlayerID==PJSUA_INVALID_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_player_destroy(*thePlayerID);
|
||||||
|
*thePlayerID = PJSUA_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isRecording {
|
||||||
|
return (recorderID!=PJSUA_INVALID_ID);
|
||||||
|
}
|
||||||
|
- (void)startRecording:(NSString *)toFile {
|
||||||
|
[self performSelectorOnMainThread:@selector(startRecordingMain:) withObject:toFile waitUntilDone:YES];
|
||||||
|
}
|
||||||
|
- (void)startRecordingMain:(NSString *)toFile {
|
||||||
|
if (recorderID!=PJSUA_INVALID_ID || identifier==PJSUA_INVALID_ID || state!=MGMSIPCallConfirmedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_str_t file = [toFile PJString];
|
||||||
|
pj_status_t status = pjsua_recorder_create(&file, 0, NULL, 0, 0, &recorderID);
|
||||||
|
if (status!=PJ_SUCCESS) {
|
||||||
|
NSLog(@"Couldn't create recorder");
|
||||||
|
} else {
|
||||||
|
pjsua_conf_connect(pjsua_call_get_conf_port(identifier), pjsua_recorder_get_conf_port(recorderID));
|
||||||
|
pjsua_conf_connect(0, pjsua_recorder_get_conf_port(recorderID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)stopRecording {
|
||||||
|
[self performSelectorOnMainThread:@selector(stopRecordingMain) withObject:nil waitUntilDone:YES];
|
||||||
|
}
|
||||||
|
- (void)stopRecordingMain {
|
||||||
|
if (recorderID==PJSUA_INVALID_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pjsua_recorder_destroy(recorderID);
|
||||||
|
recorderID = PJSUA_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isMuted {
|
||||||
|
return muted;
|
||||||
|
}
|
||||||
|
- (void)mute {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || holdMusicPlayer!=PJSUA_INVALID_ID || state!=MGMSIPCallConfirmedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status;
|
||||||
|
if (muted)
|
||||||
|
status = pjsua_conf_adjust_rx_level(pjsua_call_get_conf_port(identifier), [[MGMSIP sharedSIP] micVolume]);
|
||||||
|
else
|
||||||
|
status = pjsua_conf_adjust_rx_level(pjsua_call_get_conf_port(identifier), 0);
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error %@ speakers for call %@", (muted ? @"unmuting" : @"mutting"), self);
|
||||||
|
else
|
||||||
|
muted = !muted;
|
||||||
|
}
|
||||||
|
- (BOOL)isMicMuted {
|
||||||
|
return micMuted;
|
||||||
|
}
|
||||||
|
- (void)muteMic {
|
||||||
|
if (identifier==PJSUA_INVALID_ID || holdMusicPlayer!=PJSUA_INVALID_ID || state!=MGMSIPCallConfirmedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] registerThread];
|
||||||
|
|
||||||
|
pj_status_t status;
|
||||||
|
if (micMuted)
|
||||||
|
status = pjsua_conf_connect(0, pjsua_call_get_conf_port(identifier));
|
||||||
|
else
|
||||||
|
status = pjsua_conf_disconnect(0, pjsua_call_get_conf_port(identifier));
|
||||||
|
if (status!=PJ_SUCCESS)
|
||||||
|
NSLog(@"Error %@ microphone for call %@", (micMuted ? @"unmuting" : @"mutting"), self);
|
||||||
|
else
|
||||||
|
micMuted = !micMuted;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
37
Classes/VoiceBase/SIP/MGMSIPURL.h
Normal file
37
Classes/VoiceBase/SIP/MGMSIPURL.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPURL.h
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/11/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMSIPURL : NSObject {
|
||||||
|
NSString *fullName;
|
||||||
|
NSString *userName;
|
||||||
|
NSString *host;
|
||||||
|
int port;
|
||||||
|
}
|
||||||
|
+ (id)URLWithFullName:(NSString *)theFullName userName:(NSString *)theUserName host:(NSString *)theHost;
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName host:(NSString *)theHost;
|
||||||
|
+ (id)URLWithSIPAddress:(NSString *)theSIPAddress;
|
||||||
|
- (id)initWithSIPAddress:(NSString *)theSIPAddress;
|
||||||
|
+ (id)URLWithSIPID:(NSString *)theSIPID;
|
||||||
|
- (id)initWithSIPID:(NSString *)theSIPID;
|
||||||
|
|
||||||
|
- (NSString *)fullName;
|
||||||
|
- (void)setFullName:(NSString *)theFullName;
|
||||||
|
- (NSString *)userName;
|
||||||
|
- (void)setUserName:(NSString *)theUserName;
|
||||||
|
- (NSString *)host;
|
||||||
|
- (void)setHost:(NSString *)theHost;
|
||||||
|
- (int)port;
|
||||||
|
- (void)setPort:(int)thePort;
|
||||||
|
|
||||||
|
- (NSString *)SIPAddress;
|
||||||
|
- (NSString *)SIPID;
|
||||||
|
@end
|
||||||
|
#endif
|
143
Classes/VoiceBase/SIP/MGMSIPURL.m
Normal file
143
Classes/VoiceBase/SIP/MGMSIPURL.m
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPURL.m
|
||||||
|
// VoiceBase
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/11/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPURL.h"
|
||||||
|
|
||||||
|
@implementation MGMSIPURL
|
||||||
|
+ (id)URLWithFullName:(NSString *)theFullName userName:(NSString *)theUserName host:(NSString *)theHost {
|
||||||
|
return [[[self alloc] initWithFullName:theFullName userName:theUserName host:theHost] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithFullName:(NSString *)theFullName userName:(NSString *)theUserName host:(NSString *)theHost {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (theHost==nil || [theHost isEqual:@""]) {
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
fullName = [theFullName copy];
|
||||||
|
userName = [theUserName copy];
|
||||||
|
host = [theHost copy];
|
||||||
|
port = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
+ (id)URLWithSIPAddress:(NSString *)theSIPAddress {
|
||||||
|
return [[[self alloc] initWithSIPAddress:theSIPAddress] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithSIPAddress:(NSString *)theSIPAddress {
|
||||||
|
return [self initWithSIPID:[NSString stringWithFormat:@"<sip:%@>", theSIPAddress]];
|
||||||
|
}
|
||||||
|
+ (id)URLWithSIPID:(NSString *)theSIPID {
|
||||||
|
return [[[self alloc] initWithSIPID:theSIPID] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithSIPID:(NSString *)theSIPID {
|
||||||
|
if (self = [super init]) {
|
||||||
|
NSString *fullNameString, *addressString;
|
||||||
|
NSRange range = [theSIPID rangeOfString:@"<sip:"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"Not a valid SIP ID.");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
NSMutableCharacterSet *characterSet = [NSMutableCharacterSet whitespaceCharacterSet];
|
||||||
|
[characterSet addCharactersInString:@"'\"<>"];
|
||||||
|
fullNameString = [[theSIPID substringToIndex:range.location] stringByTrimmingCharactersInSet:characterSet];
|
||||||
|
addressString = [[theSIPID substringFromIndex:range.location+range.length] stringByTrimmingCharactersInSet:characterSet];
|
||||||
|
if (![fullNameString isEqual:@""])
|
||||||
|
fullName = [fullNameString copy];
|
||||||
|
if (![addressString isEqual:@""]) {
|
||||||
|
range = [addressString rangeOfString:@"@"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
userName = [[addressString substringToIndex:range.location] copy];
|
||||||
|
addressString = [addressString substringFromIndex:range.location+range.length];
|
||||||
|
range = [addressString rangeOfString:@":"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
host = [[addressString substringToIndex:range.location] copy];
|
||||||
|
port = [[addressString substringFromIndex:range.location+range.length] intValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (host==nil) {
|
||||||
|
host = [addressString copy];
|
||||||
|
port = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (fullName!=nil)
|
||||||
|
[fullName release];
|
||||||
|
if (userName!=nil)
|
||||||
|
[userName release];
|
||||||
|
if (host!=nil)
|
||||||
|
[host release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)description {
|
||||||
|
return [self SIPID];
|
||||||
|
}
|
||||||
|
- (NSString *)fullName {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
- (void)setFullName:(NSString *)theFullName {
|
||||||
|
if (fullName!=nil) [fullName release];
|
||||||
|
fullName = [theFullName copy];
|
||||||
|
}
|
||||||
|
- (NSString *)userName {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
- (void)setUserName:(NSString *)theUserName {
|
||||||
|
if (userName!=nil) [userName release];
|
||||||
|
if (theUserName==nil) {
|
||||||
|
userName = [@"" copy];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
userName = [theUserName copy];
|
||||||
|
}
|
||||||
|
- (NSString *)host {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
- (void)setHost:(NSString *)theHost {
|
||||||
|
if (theHost==nil || [theHost isEqual:@""]) return;
|
||||||
|
if (host!=nil) [host release];
|
||||||
|
host = [theHost copy];
|
||||||
|
}
|
||||||
|
- (int)port {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
- (void)setPort:(int)thePort {
|
||||||
|
port = thePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)SIPAddress {
|
||||||
|
NSMutableString *string = [NSMutableString string];
|
||||||
|
if (userName!=nil && ![userName isEqual:@""])
|
||||||
|
[string appendFormat:@"%@@", userName];
|
||||||
|
[string appendString:host];
|
||||||
|
if (port!=0)
|
||||||
|
[string appendFormat:@":%d", port];
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
- (NSString *)SIPID {
|
||||||
|
NSMutableString *string = [NSMutableString string];
|
||||||
|
if (fullName!=nil && ![fullName isEqual:@""])
|
||||||
|
[string appendFormat:@"%@ ", fullName];
|
||||||
|
[string appendString:@"<sip:"];
|
||||||
|
if (userName!=nil && ![userName isEqual:@""])
|
||||||
|
[string appendFormat:@"%@@", userName];
|
||||||
|
[string appendString:host];
|
||||||
|
if (port!=0)
|
||||||
|
[string appendFormat:@":%d", port];
|
||||||
|
[string appendString:@">"];
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
23
Classes/VoiceBase/VoiceBase.h
Normal file
23
Classes/VoiceBase/VoiceBase.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* VoiceBase.h
|
||||||
|
* VoiceBase
|
||||||
|
*
|
||||||
|
* Created by Mr. Gecko on 8/15/10.
|
||||||
|
* Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <VoiceBase/MGMAddons.h>
|
||||||
|
#import <VoiceBase/MGMInstance.h>
|
||||||
|
#import <VoiceBase/MGMInbox.h>
|
||||||
|
#import <VoiceBase/MGMContactsProtocol.h>
|
||||||
|
#import <VoiceBase/MGMContacts.h>
|
||||||
|
#import <VoiceBase/MGMAddressBook.h>
|
||||||
|
#import <VoiceBase/MGMGoogleContacts.h>
|
||||||
|
#import <VoiceBase/MGMThemeManager.h>
|
||||||
|
|
||||||
|
//MGMSIP Stuff
|
||||||
|
#import <VoiceBase/MGMSIP.h>
|
||||||
|
#import <VoiceBase/MGMSIPAccount.h>
|
||||||
|
#import <VoiceBase/MGMSIPCall.h>
|
||||||
|
#import <VoiceBase/MGMSIPURL.h>
|
7
Classes/VoiceBase/VoiceBase_Prefix.pch
Normal file
7
Classes/VoiceBase/VoiceBase_Prefix.pch
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//
|
||||||
|
// Prefix header for all source files of the 'VoiceBase' target in the 'VoiceBase' project.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
23
Classes/VoiceMac/Inbox/MGMInboxPlayWindow.h
Normal file
23
Classes/VoiceMac/Inbox/MGMInboxPlayWindow.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// MGMInboxPlayWindow.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/4/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMInstance, MGMURLConnectionManager, QTMovieView;
|
||||||
|
|
||||||
|
@interface MGMInboxPlayWindow : NSWindow {
|
||||||
|
MGMInstance *instance;
|
||||||
|
MGMURLConnectionManager *connectionManager;
|
||||||
|
IBOutlet NSView *view;
|
||||||
|
IBOutlet QTMovieView *audioPlayer;
|
||||||
|
IBOutlet NSTextField *transcriptionField;
|
||||||
|
BOOL forceDisplay;
|
||||||
|
}
|
||||||
|
- (id)initWithNibNamed:(NSString *)theNib data:(NSDictionary *)theData instance:(MGMInstance *)theInstance;
|
||||||
|
- (NSColor *)whiteBackground;
|
||||||
|
@end
|
133
Classes/VoiceMac/Inbox/MGMInboxPlayWindow.m
Normal file
133
Classes/VoiceMac/Inbox/MGMInboxPlayWindow.m
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
//
|
||||||
|
// MGMInboxPlayWindow.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/4/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMInboxPlayWindow.h"
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <QTKit/QTKit.h>
|
||||||
|
|
||||||
|
@implementation MGMInboxPlayWindow
|
||||||
|
- (id)initWithNibNamed:(NSString *)theNib data:(NSDictionary *)theData instance:(MGMInstance *)theInstance {
|
||||||
|
if (self = [super initWithContentRect:NSMakeRect(34, 34, 0, 0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]) {
|
||||||
|
if (![NSBundle loadNibNamed:theNib owner:self]) {
|
||||||
|
NSLog(@"Unable to load nib for the Play Window");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
instance = theInstance;
|
||||||
|
if (transcriptionField!=nil) {
|
||||||
|
[transcriptionField setStringValue:[theData objectForKey:MGMIText]];
|
||||||
|
NSSize transcriptionSize = [transcriptionField frame].size;
|
||||||
|
NSRect viewRect = [view frame];
|
||||||
|
float widthDiff = viewRect.size.width-transcriptionSize.width;
|
||||||
|
float heightDiff = viewRect.size.height-transcriptionSize.height;
|
||||||
|
NSAttributedString *string = [transcriptionField attributedStringValue];
|
||||||
|
float width = [string widthForHeight:transcriptionSize.height];
|
||||||
|
if (transcriptionSize.width<width) {
|
||||||
|
if (width>455)
|
||||||
|
transcriptionSize.width = 455;
|
||||||
|
else
|
||||||
|
transcriptionSize.width = width;
|
||||||
|
}
|
||||||
|
transcriptionSize.height = [string heightForWidth:transcriptionSize.width];
|
||||||
|
viewRect.size.width = transcriptionSize.width + widthDiff;
|
||||||
|
viewRect.size.height = transcriptionSize.height + heightDiff;
|
||||||
|
[view setFrame:viewRect];
|
||||||
|
}
|
||||||
|
if (audioPlayer!=nil) {
|
||||||
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[instance cookieStorage]] retain];
|
||||||
|
[connectionManager connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:MGMIVoiceMailDownloadURL, [[theData objectForKey:MGMIID] addPercentEscapes]]]] delegate:self];
|
||||||
|
}
|
||||||
|
forceDisplay = NO;
|
||||||
|
[self setLevel:NSStatusWindowLevel];
|
||||||
|
[self setBackgroundColor:[NSColor clearColor]];
|
||||||
|
[self setOpaque:NO];
|
||||||
|
[self setHasShadow:YES];
|
||||||
|
[self setAlphaValue:1.0];
|
||||||
|
[self setMovableByWindowBackground:NO];
|
||||||
|
[self setContentSize:[view frame].size];
|
||||||
|
[self setContentView:view];
|
||||||
|
[self setBackgroundColor:[self whiteBackground]];
|
||||||
|
[self setReleasedWhenClosed:YES];
|
||||||
|
[self setDelegate:self];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (connectionManager!=nil)
|
||||||
|
[connectionManager release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)request:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSLog(@"Starting Voicemail Error: %@", theError);
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error loading voicemail"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
}
|
||||||
|
- (void)requestDidFinish:(NSDictionary *)theInfo {
|
||||||
|
QTDataReference *audioReference = [QTDataReference dataReferenceWithReferenceToData:[theInfo objectForKey:MGMConnectionData] name:@"voicemail.mp3" MIMEType:nil];
|
||||||
|
QTMovie *theAudio = [QTMovie movieWithDataReference:audioReference error:NULL];
|
||||||
|
[theAudio autoplay];
|
||||||
|
[audioPlayer setMovie:theAudio];
|
||||||
|
[audioPlayer setBackButtonVisible:NO];
|
||||||
|
[audioPlayer setVolumeButtonVisible:NO];
|
||||||
|
[audioPlayer setStepButtonsVisible:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification *)aNotification {
|
||||||
|
[self setBackgroundColor:[self whiteBackground]];
|
||||||
|
if (forceDisplay)
|
||||||
|
[self display];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(NSRect)frameRect display:(BOOL)displayFlag animate:(BOOL)animationFlag {
|
||||||
|
forceDisplay = YES;
|
||||||
|
[super setFrame:frameRect display:displayFlag animate:animationFlag];
|
||||||
|
forceDisplay = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSColor *)whiteBackground {
|
||||||
|
float alpha = 0.9;
|
||||||
|
NSImage *bg = [[NSImage alloc] initWithSize:[self frame].size];
|
||||||
|
[bg lockFocus];
|
||||||
|
|
||||||
|
float radius = 6.0;
|
||||||
|
float stroke = 3.0;
|
||||||
|
NSRect bgRect = NSMakeRect(stroke/2, stroke/2, [bg size].width-stroke, [bg size].height-stroke);
|
||||||
|
NSBezierPath *bgPath = [NSBezierPath pathWithRect:bgRect radiusX:radius radiusY:radius];
|
||||||
|
[bgPath setLineWidth:stroke];
|
||||||
|
|
||||||
|
[[NSColor colorWithCalibratedWhite:1.0 alpha:alpha] set];
|
||||||
|
[bgPath fill];
|
||||||
|
[[NSColor colorWithCalibratedWhite:0.6 alpha:alpha] set];
|
||||||
|
[bgPath stroke];
|
||||||
|
|
||||||
|
[bg unlockFocus];
|
||||||
|
|
||||||
|
return [NSColor colorWithPatternImage:[bg autorelease]];
|
||||||
|
}
|
||||||
|
- (void)windowDidResignKey:(NSNotification *)notification {
|
||||||
|
if (connectionManager!=nil)
|
||||||
|
[connectionManager cancelAll];
|
||||||
|
if (audioPlayer!=nil)
|
||||||
|
[audioPlayer setMovie:nil];
|
||||||
|
[self setContentView:nil];
|
||||||
|
[view release];
|
||||||
|
[self close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyWindow {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
@end
|
65
Classes/VoiceMac/Inbox/MGMInboxWindow.h
Normal file
65
Classes/VoiceMac/Inbox/MGMInboxWindow.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// MGMInboxWindow.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/3/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMInstance, MGMSplitView;
|
||||||
|
|
||||||
|
@interface MGMInboxWindow : NSObject {
|
||||||
|
MGMInstance *instance;
|
||||||
|
IBOutlet NSWindow *inboxWindow;
|
||||||
|
IBOutlet MGMSplitView *splitView;
|
||||||
|
IBOutlet NSOutlineView *sidebarView;
|
||||||
|
IBOutlet NSTableView *inboxTable;
|
||||||
|
IBOutlet NSButton *nextButton;
|
||||||
|
IBOutlet NSButton *previousButton;
|
||||||
|
IBOutlet NSTextField *pageField;
|
||||||
|
IBOutlet NSProgressIndicator *progress;
|
||||||
|
int progressStartCount;
|
||||||
|
|
||||||
|
int currentInbox;
|
||||||
|
int maxResults;
|
||||||
|
unsigned int start;
|
||||||
|
int resultsCount;
|
||||||
|
|
||||||
|
float rightMax;
|
||||||
|
float leftMax;
|
||||||
|
NSMutableArray *currentData;
|
||||||
|
NSDate *lastDate;
|
||||||
|
}
|
||||||
|
+ (id)windowWithInstance:(MGMInstance *)theInstance;
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance;
|
||||||
|
- (NSWindow *)inboxWindow;
|
||||||
|
- (IBAction)showWindow:(id)sender;
|
||||||
|
- (void)closeWindow;
|
||||||
|
|
||||||
|
- (void)startProgress;
|
||||||
|
- (void)stopProgress;
|
||||||
|
|
||||||
|
- (void)checkVoicemail;
|
||||||
|
|
||||||
|
- (IBAction)next:(id)sender;
|
||||||
|
- (IBAction)previous:(id)sender;
|
||||||
|
|
||||||
|
- (void)loadInbox;
|
||||||
|
- (int)currentInbox;
|
||||||
|
- (void)setCurrentData:(NSArray *)theData;
|
||||||
|
- (NSDictionary *)selectedItem;
|
||||||
|
- (NSString *)currentPhoneNumber;
|
||||||
|
- (NSURL *)audioURL;
|
||||||
|
- (IBAction)spam:(id)sender;
|
||||||
|
- (IBAction)markRead:(id)sender;
|
||||||
|
- (IBAction)delete:(id)sender;
|
||||||
|
- (IBAction)undelete:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMInboxTableView : NSTableView {
|
||||||
|
IBOutlet MGMInboxWindow *inboxWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
505
Classes/VoiceMac/Inbox/MGMInboxWindow.m
Normal file
505
Classes/VoiceMac/Inbox/MGMInboxWindow.m
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
//
|
||||||
|
// MGMInboxWindow.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/3/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMInboxWindow.h"
|
||||||
|
#import "MGMInboxPlayWindow.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMSMSManager.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <Growl/GrowlApplicationBridge.h>
|
||||||
|
|
||||||
|
static NSMutableArray *sideItems;
|
||||||
|
|
||||||
|
NSString * const MGMSName = @"name";
|
||||||
|
NSString * const MGMSObjects = @"objects";
|
||||||
|
NSString * const MGMSSelectable = @"selectable";
|
||||||
|
NSString * const MGMSID = @"id";
|
||||||
|
|
||||||
|
@implementation MGMInboxWindow
|
||||||
|
+ (id)windowWithInstance:(MGMInstance *)theInstance {
|
||||||
|
return [[[self alloc] initWithInstance:theInstance] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (sideItems==nil) {
|
||||||
|
sideItems = [NSMutableArray new];
|
||||||
|
[sideItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Inbox", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:0], MGMSID, nil]];
|
||||||
|
[sideItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Starred", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:1], MGMSID, nil]];
|
||||||
|
[sideItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Spam", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:2], MGMSID, nil]];
|
||||||
|
[sideItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Trash", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:3], MGMSID, nil]];
|
||||||
|
NSMutableArray *history = [NSMutableArray array];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Voicemail", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:4], MGMSID, nil]];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"SMS Messages", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:5], MGMSID, nil]];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Recorded", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:6], MGMSID, nil]];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Placed", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:7], MGMSID, nil]];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Received", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:8], MGMSID, nil]];
|
||||||
|
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Missed", MGMSName, [NSNumber numberWithBool:YES], MGMSSelectable, [NSNumber numberWithInt:9], MGMSID, nil]];
|
||||||
|
[sideItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"History", MGMSName, [NSNumber numberWithBool:NO], MGMSSelectable, history, MGMSObjects, nil]];
|
||||||
|
}
|
||||||
|
instance = theInstance;
|
||||||
|
maxResults = 10;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[inboxTable setTarget:self];
|
||||||
|
[inboxTable setDoubleAction:@selector(inboxAction:)];
|
||||||
|
[nextButton setEnabled:NO];
|
||||||
|
[previousButton setEnabled:NO];
|
||||||
|
progressStartCount = 0;
|
||||||
|
[inboxWindow setFrameAutosaveName:[@"inboxWindow" stringByAppendingString:[[instance user] settingForKey:MGMUserID]]];
|
||||||
|
[inboxWindow setTitle:[NSString stringWithFormat:@"%@ (%@)", [inboxWindow title], [[instance userNumber] readableNumber]]];
|
||||||
|
if ([splitView respondsToSelector:@selector(setAutosaveName:)])
|
||||||
|
[splitView setAutosaveName:[@"inboxSplitView" stringByAppendingString:[[instance user] settingForKey:MGMUserID]]];
|
||||||
|
[sidebarView setAutosaveName:[@"inboxSidebarView" stringByAppendingString:[[instance user] settingForKey:MGMUserID]]];
|
||||||
|
[sidebarView setAutosaveExpandedItems:YES];
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (currentData!=nil)
|
||||||
|
[currentData release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSWindow *)inboxWindow {
|
||||||
|
return inboxWindow;
|
||||||
|
}
|
||||||
|
- (IBAction)showWindow:(id)sender {
|
||||||
|
if (inboxWindow==nil) {
|
||||||
|
if (![NSBundle loadNibNamed:@"InboxWindow" owner:self]) {
|
||||||
|
NSLog(@"Error: Unable to load Inbox Window!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ([sender isKindOfClass:[NSMenuItem class]]) {
|
||||||
|
switch ([sender tag]) {
|
||||||
|
case 1:
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:6] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[[[sideItems objectAtIndex:4] objectForKey:MGMSObjects] objectAtIndex:1]];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:5] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[[[sideItems objectAtIndex:4] objectForKey:MGMSObjects] objectAtIndex:0]];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:8] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[[[sideItems objectAtIndex:4] objectForKey:MGMSObjects] objectAtIndex:3]];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:9] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[[[sideItems objectAtIndex:4] objectForKey:MGMSObjects] objectAtIndex:4]];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:10] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[[[sideItems objectAtIndex:4] objectForKey:MGMSObjects] objectAtIndex:5]];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[sideItems objectAtIndex:0]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (sender!=self) {
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||||
|
[self outlineView:sidebarView shouldSelectItem:[sideItems objectAtIndex:0]];
|
||||||
|
} else {
|
||||||
|
start = 0;
|
||||||
|
[sidebarView expandItem:[sideItems objectAtIndex:4]];
|
||||||
|
[sidebarView selectRowIndexes:[NSIndexSet indexSetWithIndex:5] byExtendingSelection:NO];
|
||||||
|
currentInbox = 4;
|
||||||
|
[pageField setStringValue:@"Page 1"];
|
||||||
|
}
|
||||||
|
[sidebarView setAllowsEmptySelection:NO];
|
||||||
|
[inboxWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (void)closeWindow {
|
||||||
|
if (inboxWindow!=nil)
|
||||||
|
[inboxWindow close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startProgress {
|
||||||
|
if (progressStartCount==0)
|
||||||
|
[progress startAnimation:self];
|
||||||
|
progressStartCount++;
|
||||||
|
}
|
||||||
|
- (void)stopProgress {
|
||||||
|
if (progressStartCount==1)
|
||||||
|
[progress stopAnimation:self];
|
||||||
|
progressStartCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)checkVoicemail {
|
||||||
|
[[instance inbox] getVoicemailForPage:1 delegate:self didFailWithError:@selector(voicemail:didFailWithError:instance:) didReceiveInfo:@selector(voicemailGotInfo:instance:)];
|
||||||
|
}
|
||||||
|
- (void)voicemail:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
NSLog(@"Voicemail Error: %@ for instance: %@", theError, theInstance);
|
||||||
|
}
|
||||||
|
- (void)voicemailGotInfo:(NSArray *)theMessages instance:(MGMInstance *)theInstance {
|
||||||
|
NSDate *newestDate = [NSDate distantPast];
|
||||||
|
BOOL newMessage = NO;
|
||||||
|
for (unsigned int i=0; i<[theMessages count]; i++) {
|
||||||
|
if (![[[theMessages objectAtIndex:i] objectForKey:MGMIRead] boolValue] && (lastDate==nil || (![lastDate isEqual:[[theMessages objectAtIndex:i] objectForKey:MGMITime]] && [lastDate earlierDate:[[theMessages objectAtIndex:i] objectForKey:MGMITime]]==lastDate))) {
|
||||||
|
[GrowlApplicationBridge notifyWithTitle:[NSString stringWithFormat:@"Voicemail from %@", [[instance contacts] nameForNumber:[[theMessages objectAtIndex:i] objectForKey:MGMIPhoneNumber]]] description:[[[theMessages objectAtIndex:i] objectForKey:MGMIText] flattenHTML] notificationName:@"Voicemail" iconData:[[instance contacts] photoDataForNumber:[[theMessages objectAtIndex:i] objectForKey:MGMIPhoneNumber]] priority:0 isSticky:NO clickContext:nil];
|
||||||
|
newMessage = YES;
|
||||||
|
if ([newestDate earlierDate:[[theMessages objectAtIndex:i] objectForKey:MGMITime]]==newestDate)
|
||||||
|
newestDate = [[theMessages objectAtIndex:i] objectForKey:MGMITime];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newMessage) {
|
||||||
|
if (lastDate!=nil) [lastDate release];
|
||||||
|
lastDate = [newestDate copy];
|
||||||
|
[self setCurrentData:theMessages];
|
||||||
|
[self showWindow:self];
|
||||||
|
[[[(MGMVoiceUser *)[instance delegate] controller] themeManager] playSound:MGMTSVoicemail];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
||||||
|
return (item==nil ? [sideItems count] : ([item objectForKey:MGMSObjects]!=nil ? [[item objectForKey:MGMSObjects] count] : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
||||||
|
return (item!=nil ? ([item objectForKey:MGMSObjects]!=nil && [[item objectForKey:MGMSObjects] count]>0) : NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
||||||
|
return (item==nil ? [sideItems objectAtIndex:index] : [[item objectForKey:MGMSObjects] objectAtIndex:index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
||||||
|
return [item objectForKey:MGMSName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item {
|
||||||
|
if ([item objectForKey:MGMSSelectable]!=nil && ![[item objectForKey:MGMSSelectable] boolValue])
|
||||||
|
return NO;
|
||||||
|
[self setCurrentData:nil];
|
||||||
|
if ([item objectForKey:MGMSID]!=nil) {
|
||||||
|
currentInbox = [[item objectForKey:MGMSID] intValue];
|
||||||
|
start = 0;
|
||||||
|
[self loadInbox];
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)next:(id)sender {
|
||||||
|
start += maxResults;
|
||||||
|
[self loadInbox];
|
||||||
|
}
|
||||||
|
- (IBAction)previous:(id)sender {
|
||||||
|
start -= maxResults;
|
||||||
|
[self loadInbox];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadInbox {
|
||||||
|
int page = (start/maxResults)+1;
|
||||||
|
[nextButton setEnabled:NO];
|
||||||
|
[previousButton setEnabled:NO];
|
||||||
|
[pageField setStringValue:[NSString stringWithFormat:@"Page %d", page]];
|
||||||
|
[self startProgress];
|
||||||
|
switch (currentInbox) {
|
||||||
|
case 0:
|
||||||
|
[[instance inbox] getInboxForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
[[instance inbox] getStarredForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[[instance inbox] getSpamForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
[[instance inbox] getTrashForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
[[instance inbox] getVoicemailForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
[[instance inbox] getSMSForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
[[instance inbox] getRecordedCallsForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
[[instance inbox] getPlacedCallsForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
[[instance inbox] getReceivedCallsForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
[[instance inbox] getMissedCallsForPage:page delegate:self didFailWithError:@selector(inbox:didFailWithError:instance:) didReceiveInfo:@selector(inboxGotInfo:instance:)];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)inbox:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
NSLog(@"Inbox Error: %@ for instance: %@", theError, theInstance);
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error loading inbox"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
- (void)inboxGotInfo:(NSArray *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
if (theInfo!=nil) {
|
||||||
|
[self setCurrentData:theInfo];
|
||||||
|
} else {
|
||||||
|
NSLog(@"Error 234554: Hold on, this should never happen.");
|
||||||
|
}
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
- (int)currentInbox {
|
||||||
|
return currentInbox;
|
||||||
|
}
|
||||||
|
- (void)setCurrentData:(NSArray *)theData {
|
||||||
|
if (currentData!=nil) [currentData release];
|
||||||
|
currentData = [theData mutableCopy];
|
||||||
|
|
||||||
|
resultsCount = [currentData count];
|
||||||
|
if (resultsCount==maxResults)
|
||||||
|
[nextButton setEnabled:YES];
|
||||||
|
else
|
||||||
|
[nextButton setEnabled:NO];
|
||||||
|
if (start!=0)
|
||||||
|
[previousButton setEnabled:YES];
|
||||||
|
else
|
||||||
|
[previousButton setEnabled:NO];
|
||||||
|
[inboxTable reloadData];
|
||||||
|
}
|
||||||
|
- (NSDictionary *)selectedItem {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return nil;
|
||||||
|
return [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
}
|
||||||
|
- (NSString *)currentPhoneNumber {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return nil;
|
||||||
|
return [[currentData objectAtIndex:[inboxTable selectedRow]] objectForKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
- (NSURL *)audioURL {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return nil;
|
||||||
|
NSDictionary *data = [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
if ([[data objectForKey:MGMIType] intValue]==MGMIVoicemailType || [[data objectForKey:MGMIType] intValue]==MGMIRecordedType)
|
||||||
|
return [NSURL URLWithString:[NSString stringWithFormat:MGMIVoiceMailDownloadURL, [[data objectForKey:MGMIID] addPercentEscapes]]];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (IBAction)spam:(id)sender {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return;
|
||||||
|
NSMutableDictionary *data = [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
[self startProgress];
|
||||||
|
[[instance inbox] reportEntries:[NSArray arrayWithObject:[data objectForKey:MGMIID]] delegate:self];
|
||||||
|
[currentData removeObject:data];
|
||||||
|
[inboxTable reloadData];
|
||||||
|
}
|
||||||
|
- (IBAction)report:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
NSLog(@"Report Error: %@ for instance: %@", theError, theInstance);
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error reporting"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
- (void)reportDidFinish:(NSDictionary *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
[self loadInbox];
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
- (IBAction)markRead:(id)sender {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return;
|
||||||
|
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithDictionary:[currentData objectAtIndex:[inboxTable selectedRow]]];
|
||||||
|
[[instance inbox] markEntries:[NSArray arrayWithObject:[data objectForKey:MGMIID]] read:![[data objectForKey:MGMIRead] boolValue] delegate:self];
|
||||||
|
[data setObject:[NSNumber numberWithBool:![[data objectForKey:MGMIRead] boolValue]] forKey:MGMIRead];
|
||||||
|
[currentData replaceObjectAtIndex:[inboxTable selectedRow] withObject:data];
|
||||||
|
[inboxTable reloadData];
|
||||||
|
}
|
||||||
|
- (IBAction)delete:(id)sender {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return;
|
||||||
|
NSDictionary *data = [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
[self startProgress];
|
||||||
|
if (currentInbox==3)
|
||||||
|
[[instance inbox] deleteEntriesForever:[NSArray arrayWithObject:[data objectForKey:MGMIID]] delegate:self];
|
||||||
|
else
|
||||||
|
[[instance inbox] deleteEntries:[NSArray arrayWithObject:[data objectForKey:MGMIID]] delegate:self];
|
||||||
|
[currentData removeObject:data];
|
||||||
|
[inboxTable reloadData];
|
||||||
|
}
|
||||||
|
- (IBAction)undelete:(id)sender {
|
||||||
|
if (inboxTable==nil || [inboxTable selectedRow]==-1)
|
||||||
|
return;
|
||||||
|
NSDictionary *data = [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
[self startProgress];
|
||||||
|
[[instance inbox] deleteEntries:[NSArray arrayWithObject:[data objectForKey:MGMIID]] delegate:self];
|
||||||
|
[currentData removeObject:data];
|
||||||
|
[inboxTable reloadData];
|
||||||
|
}
|
||||||
|
- (void)delete:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
NSLog(@"Delete Error: %@ for instance: %@", theError, theInstance);
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error deleting"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
- (void)deleteDidFinish:(NSDictionary *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
[self loadInbox];
|
||||||
|
[self stopProgress];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
|
||||||
|
return [currentData count];
|
||||||
|
}
|
||||||
|
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
|
||||||
|
NSDictionary *data = [currentData objectAtIndex:rowIndex];
|
||||||
|
NSString *identifier = [aTableColumn identifier];
|
||||||
|
if ([identifier isEqual:@"read"]) {
|
||||||
|
return ([[data objectForKey:MGMIRead] boolValue] ? @"" : @"•");
|
||||||
|
} else if ([identifier isEqual:@"name"]) {
|
||||||
|
return [[instance contacts] nameForNumber:[data objectForKey:MGMIPhoneNumber]];
|
||||||
|
} else if ([identifier isEqual:@"text"]) {
|
||||||
|
int type = [[data objectForKey:MGMIType] intValue];
|
||||||
|
if (type==MGMIVoicemailType) {
|
||||||
|
return [data objectForKey:MGMIText];
|
||||||
|
} else if (type==MGMISMSIn || type==MGMISMSOut) {
|
||||||
|
return [[[[data objectForKey:MGMIMessages] lastObject] objectForKey:MGMIText] flattenHTML];
|
||||||
|
} else {
|
||||||
|
return [[[data objectForKey:MGMIPhoneNumber] areaCode] areaCodeLocation];
|
||||||
|
}
|
||||||
|
} else if ([identifier isEqual:@"date"]) {
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:@"M/d/yy h:mm:ss a"];
|
||||||
|
return [formatter stringFromDate:[data objectForKey:MGMITime]];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (IBAction)inboxAction:(id)sender {
|
||||||
|
NSDictionary *data = [currentData objectAtIndex:[inboxTable selectedRow]];
|
||||||
|
int type = [[data objectForKey:MGMIType] intValue];
|
||||||
|
if (type==MGMIVoicemailType) {
|
||||||
|
NSArray *cookies = [[instance cookieStorage] cookies];
|
||||||
|
for (int i=0; i<[cookies count]; i++) {
|
||||||
|
NSHTTPCookie *cookie = [cookies objectAtIndex:i];
|
||||||
|
if ([[cookie path] isEqual:@"/voice"] && [[cookie name] isEqual:@"gv"])
|
||||||
|
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
|
||||||
|
}
|
||||||
|
MGMInboxPlayWindow *playWindow = [[MGMInboxPlayWindow alloc] initWithNibNamed:@"VoicemailView" data:data instance:instance];
|
||||||
|
NSRect rowRect = [inboxTable rectOfRow:[inboxTable selectedRow]];
|
||||||
|
rowRect.origin = [[inboxWindow contentView] convertPoint:rowRect.origin fromView:inboxTable];
|
||||||
|
rowRect.origin = [inboxWindow convertBaseToScreen:rowRect.origin];
|
||||||
|
rowRect.origin.y -= ([playWindow frame].size.height+20);
|
||||||
|
rowRect.origin.x += ((rowRect.size.width-[playWindow frame].size.width)/2);
|
||||||
|
[playWindow setFrameOrigin:rowRect.origin];
|
||||||
|
[playWindow makeKeyAndOrderFront:self];
|
||||||
|
} else if (type==MGMIRecordedType) {
|
||||||
|
NSArray *cookies = [[instance cookieStorage] cookies];
|
||||||
|
for (int i=0; i<[cookies count]; i++) {
|
||||||
|
NSHTTPCookie *cookie = [cookies objectAtIndex:i];
|
||||||
|
if ([[cookie path] isEqual:@"/voice"] && [[cookie name] isEqual:@"gv"])
|
||||||
|
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
|
||||||
|
}
|
||||||
|
MGMInboxPlayWindow *playWindow = [[MGMInboxPlayWindow alloc] initWithNibNamed:@"RecordedView" data:data instance:instance];
|
||||||
|
NSRect rowRect = [inboxTable rectOfRow:[inboxTable selectedRow]];
|
||||||
|
rowRect.origin = [[inboxWindow contentView] convertPoint:rowRect.origin fromView:inboxTable];
|
||||||
|
rowRect.origin = [inboxWindow convertBaseToScreen:rowRect.origin];
|
||||||
|
rowRect.origin.y -= ([playWindow frame].size.height+20);
|
||||||
|
rowRect.origin.x += ((rowRect.size.width-[playWindow frame].size.width)/2);
|
||||||
|
[playWindow setFrameOrigin:rowRect.origin];
|
||||||
|
[playWindow makeKeyAndOrderFront:self];
|
||||||
|
} else if (type==MGMISMSIn || type==MGMISMSOut) {
|
||||||
|
[[[(MGMVoiceUser *)[instance delegate] controller] SMSManager] messageWithData:data instance:instance];
|
||||||
|
} else {
|
||||||
|
[(MGMVoiceUser *)[instance delegate] runAction:sender];
|
||||||
|
}
|
||||||
|
if (![[data objectForKey:MGMIRead] boolValue]) {
|
||||||
|
[self markRead:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)offset {
|
||||||
|
leftMax = [[[sender subviews] objectAtIndex:0] frame].size.width;
|
||||||
|
rightMax = [[[sender subviews] objectAtIndex:1] frame].size.width;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)offset{
|
||||||
|
leftMax = [[[sender subviews] objectAtIndex:0] frame].size.width;
|
||||||
|
rightMax = [[[sender subviews] objectAtIndex:1] frame].size.width;
|
||||||
|
return proposedMax - 250.0;
|
||||||
|
}
|
||||||
|
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
|
||||||
|
NSRect newFrame = [sender frame];
|
||||||
|
if (newFrame.size.width == oldSize.width) {
|
||||||
|
[sender adjustSubviews];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSView *left = [[sender subviews] objectAtIndex:0];
|
||||||
|
NSRect leftFrame = [left frame];
|
||||||
|
NSView *right = [[sender subviews] objectAtIndex:1];
|
||||||
|
NSRect rightFrame = [right frame];
|
||||||
|
|
||||||
|
if (rightFrame.size.width<250.0) {
|
||||||
|
rightMax = newFrame.size.width-(250.0+[sender dividerThickness]);
|
||||||
|
rightFrame.size.width = rightMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightMax<250.0)
|
||||||
|
rightMax = 250.0;
|
||||||
|
|
||||||
|
if (leftFrame.size.width < leftMax || leftFrame.size.width > leftMax)
|
||||||
|
leftFrame.size.width = leftMax;
|
||||||
|
[left setFrame:leftFrame];
|
||||||
|
[right setFrame:rightFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||||
|
[sidebarView display];
|
||||||
|
[(MGMVoiceUser *)[instance delegate] windowDidBecomeKey:notification];
|
||||||
|
}
|
||||||
|
- (void)windowDidResignKey:(NSNotification *)notification {
|
||||||
|
[sidebarView display];
|
||||||
|
}
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
[self setCurrentData:nil];
|
||||||
|
inboxWindow = nil;
|
||||||
|
splitView = nil;
|
||||||
|
sidebarView = nil;
|
||||||
|
inboxTable = nil;
|
||||||
|
nextButton = nil;
|
||||||
|
previousButton = nil;
|
||||||
|
pageField = nil;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMInboxTableView
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent {
|
||||||
|
int keyCode = [theEvent keyCode];
|
||||||
|
if (keyCode==51 || keyCode==117) {
|
||||||
|
if ([inboxWindow currentInbox]==3 && [theEvent modifierFlags] & NSAlternateKeyMask)
|
||||||
|
[inboxWindow undelete:self];
|
||||||
|
else
|
||||||
|
[inboxWindow delete:self];
|
||||||
|
} else {
|
||||||
|
[super keyDown:theEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)copy:(id)sender {
|
||||||
|
NSString *phoneNumber = [inboxWindow currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
|
||||||
|
[pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
|
||||||
|
[pasteBoard setString:[phoneNumber readableNumber] forType:NSStringPboardType];
|
||||||
|
}
|
||||||
|
@end
|
102
Classes/VoiceMac/MGMAccountSetup.h
Normal file
102
Classes/VoiceMac/MGMAccountSetup.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
//
|
||||||
|
// MGMAccountSetup.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class WebView, MGMUser, MGMInstance, MGMURLConnectionManager, MGMSIPAccount;
|
||||||
|
|
||||||
|
extern NSString * const MGMSGoogleVoice;
|
||||||
|
extern NSString * const MGMSGoogleContacts;
|
||||||
|
extern NSString * const MGMSSIP;
|
||||||
|
extern NSString * const MGMSAccountType;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPDefaultDomain;
|
||||||
|
|
||||||
|
@interface MGMAccountSetup : NSObject {
|
||||||
|
IBOutlet NSWindow *setupWindow;
|
||||||
|
IBOutlet NSTextField *titleField;
|
||||||
|
IBOutlet NSTabView *stepView;
|
||||||
|
IBOutlet NSButton *backButton;
|
||||||
|
IBOutlet NSButton *continueButton;
|
||||||
|
|
||||||
|
BOOL isAttached;
|
||||||
|
int step;
|
||||||
|
int accountType;
|
||||||
|
NSMutableArray *accountsCreated;
|
||||||
|
|
||||||
|
//Step 1 - Welcome To VoiceMac
|
||||||
|
|
||||||
|
//Step 2 - Account Type
|
||||||
|
IBOutlet NSMatrix *S2AccountTypeMatrix;
|
||||||
|
|
||||||
|
//Step 3 - Google Voice Privacy Policy
|
||||||
|
IBOutlet WebView *S3Browser;
|
||||||
|
|
||||||
|
//Step 4 - Google Voice Setup
|
||||||
|
IBOutlet NSTextField *S4EmailField;
|
||||||
|
IBOutlet NSTextField *S4PasswordField;
|
||||||
|
|
||||||
|
//Step 5 - Google Contacts Setup
|
||||||
|
IBOutlet NSTextField *S5EmailField;
|
||||||
|
IBOutlet NSTextField *S5PasswordField;
|
||||||
|
|
||||||
|
//Step 6 - SIP Setup
|
||||||
|
IBOutlet NSTextField *S6FullNameField;
|
||||||
|
IBOutlet NSTextField *S6DomainField;
|
||||||
|
IBOutlet NSTextField *S6RegistrarField;
|
||||||
|
IBOutlet NSTextField *S6UserNameField;
|
||||||
|
IBOutlet NSTextField *S6PasswordField;
|
||||||
|
|
||||||
|
//Step 7 - Checking Login Credentials
|
||||||
|
IBOutlet NSProgressIndicator *S7Progress;
|
||||||
|
IBOutlet NSTextField *S7StatusField;
|
||||||
|
MGMUser *S7CheckUser;
|
||||||
|
MGMInstance *S7CheckInstance;
|
||||||
|
MGMURLConnectionManager *S7ConnectionManager;
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
MGMSIPAccount *S7CheckSIPAccount;
|
||||||
|
BOOL S7AccountRegistered;
|
||||||
|
NSTimer *S7SIPRegistrationTimeout;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Step 8 - Setup Error
|
||||||
|
IBOutlet NSTextField *S8MessageField;
|
||||||
|
NSString *S8Message;
|
||||||
|
|
||||||
|
//Step 9 - Setup Successful
|
||||||
|
IBOutlet NSTextField *S9MessageField;
|
||||||
|
}
|
||||||
|
- (IBAction)showSetupWindow:(id)sender;
|
||||||
|
- (void)attachToWindow:(NSWindow *)theWindow;
|
||||||
|
- (void)displayStep;
|
||||||
|
|
||||||
|
- (IBAction)back:(id)sender;
|
||||||
|
- (IBAction)continue:(id)sender;
|
||||||
|
|
||||||
|
//Step 4
|
||||||
|
- (void)S4Reset;
|
||||||
|
|
||||||
|
//Step 5
|
||||||
|
- (void)S5Reset;
|
||||||
|
|
||||||
|
//Step 6
|
||||||
|
- (IBAction)S6UserNameChanged:(id)sender;
|
||||||
|
- (IBAction)S6DomainChanged:(id)sender;
|
||||||
|
- (void)S6Reset;
|
||||||
|
|
||||||
|
//Step 7
|
||||||
|
- (void)S7CheckGoogleVoice;
|
||||||
|
- (void)S7CheckGoogleContacts;
|
||||||
|
- (void)S7CheckSIP;
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
- (void)loginErrored;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Step 9
|
||||||
|
- (IBAction)S9AddAnotherAccount:(id)sender;
|
||||||
|
@end
|
515
Classes/VoiceMac/MGMAccountSetup.m
Normal file
515
Classes/VoiceMac/MGMAccountSetup.m
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
//
|
||||||
|
// MGMAccountSetup.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMAccountSetup.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
NSString * const MGMSGoBack = @"Go Back";
|
||||||
|
NSString * const MGMSCancel = @"Cancel";
|
||||||
|
NSString * const MGMSDisagree = @"Disagree";
|
||||||
|
NSString * const MGMSContinue = @"Continue";
|
||||||
|
NSString * const MGMSDone = @"Done";
|
||||||
|
NSString * const MGMSAgree = @"Agree";
|
||||||
|
|
||||||
|
NSString * const MGMSGoogleVoice = @"Google Voice";
|
||||||
|
NSString * const MGMSGoogleContacts = @"Google Contacts";
|
||||||
|
NSString * const MGMSSIP = @"Session Initiation Protocol";
|
||||||
|
NSString * const MGMSAccountType = @"MGMSAccountType";
|
||||||
|
|
||||||
|
NSString * const MGMS7Crediential = @"Checking Login Credentials.";
|
||||||
|
NSString * const MGMS7SIPWaiting = @"Waiting for Registration Status.";
|
||||||
|
|
||||||
|
NSString * const MGMSIPDefaultDomain = @"proxy01.sipphone.com";
|
||||||
|
|
||||||
|
@implementation MGMAccountSetup
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"AccountSetup" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Account Set Up!");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
isAttached = NO;
|
||||||
|
step = 1;
|
||||||
|
accountType = -1;
|
||||||
|
accountsCreated = [NSMutableArray new];
|
||||||
|
S7ConnectionManager = [[MGMURLConnectionManager managerWithCookieStorage:nil] retain];
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (setupWindow!=nil)
|
||||||
|
[setupWindow release];
|
||||||
|
if (accountsCreated!=nil)
|
||||||
|
[accountsCreated release];
|
||||||
|
if (S7CheckUser!=nil)
|
||||||
|
[S7CheckUser release];
|
||||||
|
if (S7CheckInstance!=nil)
|
||||||
|
[S7CheckInstance release];
|
||||||
|
if (S7ConnectionManager!=nil)
|
||||||
|
[S7ConnectionManager release];
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
if (S7CheckSIPAccount!=nil)
|
||||||
|
[S7CheckSIPAccount release];
|
||||||
|
#endif
|
||||||
|
if (S8Message!=nil)
|
||||||
|
[S8Message release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)showSetupWindow:(id)sender {
|
||||||
|
[setupWindow makeKeyAndOrderFront:sender];
|
||||||
|
}
|
||||||
|
- (void)attachToWindow:(NSWindow *)theWindow {
|
||||||
|
isAttached = YES;
|
||||||
|
step = 2;
|
||||||
|
[self displayStep];
|
||||||
|
[[NSApplication sharedApplication] beginSheet:setupWindow modalForWindow:theWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||||
|
}
|
||||||
|
- (void)displayStep {
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
[titleField setStringValue:@"Welcome to VoiceMac"];
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:NO];
|
||||||
|
[continueButton setTitle:MGMSContinue];
|
||||||
|
[continueButton setEnabled:YES];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[titleField setStringValue:@"Account Set Up"];
|
||||||
|
if (isAttached)
|
||||||
|
[backButton setTitle:MGMSCancel];
|
||||||
|
else
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:YES];
|
||||||
|
[continueButton setTitle:MGMSContinue];
|
||||||
|
[continueButton setEnabled:YES];
|
||||||
|
if (accountType==-1)
|
||||||
|
[S2AccountTypeMatrix selectCellAtRow:0 column:0];
|
||||||
|
else
|
||||||
|
[S2AccountTypeMatrix selectCellAtRow:accountType column:0];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
[titleField setStringValue:@"Google Voice Privacy Policy"];
|
||||||
|
[backButton setTitle:MGMSDisagree];
|
||||||
|
[backButton setEnabled:YES];
|
||||||
|
[continueButton setTitle:MGMSAgree];
|
||||||
|
[continueButton setEnabled:YES];
|
||||||
|
[[S3Browser mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com/googlevoice/legal-notices.html"]]];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6: {
|
||||||
|
NSString *type = nil;
|
||||||
|
if (accountType==0)
|
||||||
|
type = MGMSGoogleVoice;
|
||||||
|
else if (accountType==1)
|
||||||
|
type = MGMSGoogleContacts;
|
||||||
|
else if (accountType==2)
|
||||||
|
type = MGMSSIP;
|
||||||
|
[titleField setStringValue:[NSString stringWithFormat:@"Set Up %@", type]];
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:YES];
|
||||||
|
[continueButton setTitle:MGMSContinue];
|
||||||
|
[continueButton setEnabled:YES];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 7:
|
||||||
|
[titleField setStringValue:@"Checking Credentials"];
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:NO];
|
||||||
|
[continueButton setTitle:MGMSContinue];
|
||||||
|
[continueButton setEnabled:NO];
|
||||||
|
[S7StatusField setStringValue:MGMS7Crediential];
|
||||||
|
if (accountType==0)
|
||||||
|
[self S7CheckGoogleVoice];
|
||||||
|
else if (accountType==1)
|
||||||
|
[self S7CheckGoogleContacts];
|
||||||
|
else if (accountType==2)
|
||||||
|
[self S7CheckSIP];
|
||||||
|
[S7Progress startAnimation:self];
|
||||||
|
break;
|
||||||
|
case 8: {
|
||||||
|
[S7Progress stopAnimation:self];
|
||||||
|
NSString *type = nil;
|
||||||
|
if (accountType==0)
|
||||||
|
type = MGMSGoogleVoice;
|
||||||
|
else if (accountType==1)
|
||||||
|
type = MGMSGoogleContacts;
|
||||||
|
else if (accountType==2)
|
||||||
|
type = MGMSSIP;
|
||||||
|
[titleField setStringValue:@"Credentials Error"];
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:YES];
|
||||||
|
[continueButton setTitle:MGMSContinue];
|
||||||
|
[continueButton setEnabled:NO];
|
||||||
|
[S8MessageField setStringValue:[NSString stringWithFormat:@"Unable to set up your %@ account, the error we receviced was \"%@\" Please go back and correct the problem.", type, S8Message]];
|
||||||
|
if (S8Message!=nil) {
|
||||||
|
[S8Message release];
|
||||||
|
S8Message = nil;
|
||||||
|
}
|
||||||
|
NSBeep();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 9: {
|
||||||
|
[titleField setStringValue:@"Set Up Successful"];
|
||||||
|
NSString *type = nil;
|
||||||
|
if (accountType==0)
|
||||||
|
type = MGMSGoogleVoice;
|
||||||
|
else if (accountType==1)
|
||||||
|
type = MGMSGoogleContacts;
|
||||||
|
else if (accountType==2)
|
||||||
|
type = MGMSSIP;
|
||||||
|
[S7Progress stopAnimation:self];
|
||||||
|
[backButton setTitle:MGMSGoBack];
|
||||||
|
[backButton setEnabled:NO];
|
||||||
|
[continueButton setTitle:MGMSDone];
|
||||||
|
[continueButton setEnabled:YES];
|
||||||
|
[S9MessageField setStringValue:[NSString stringWithFormat:@"You have sucessfully set up your %@ account. You may continue to the Application or you add another account by pressing \"Add Another Account\". If you are confused about VoiceMac, please read the documentation which explains how you use it and all you can do with it.", type]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[stepView selectTabViewItemAtIndex:step-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)back:(id)sender {
|
||||||
|
switch (step) {
|
||||||
|
case 2:
|
||||||
|
if (isAttached) {
|
||||||
|
[[NSApplication sharedApplication] endSheet:setupWindow];
|
||||||
|
[setupWindow orderOut:self];
|
||||||
|
[accountsCreated makeObjectsPerformSelector:@selector(start)];
|
||||||
|
[self release];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
step--;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
step = 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
if (accountType==0)
|
||||||
|
[self S4Reset];
|
||||||
|
else if (accountType==1)
|
||||||
|
[self S5Reset];
|
||||||
|
else if (accountType==2)
|
||||||
|
[self S6Reset];
|
||||||
|
step = 2;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
if (accountType==0)
|
||||||
|
step = 4;
|
||||||
|
else if (accountType==1)
|
||||||
|
step = 5;
|
||||||
|
else if (accountType==2)
|
||||||
|
step = 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
step--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
- (IBAction)continue:(id)sender {
|
||||||
|
switch (step) {
|
||||||
|
case 2:
|
||||||
|
accountType = [S2AccountTypeMatrix selectedRow];
|
||||||
|
switch (accountType) {
|
||||||
|
case 1:
|
||||||
|
step = 5;
|
||||||
|
break;
|
||||||
|
case 2: {
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
step = 6;
|
||||||
|
#else
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Unable to Add Account"];
|
||||||
|
[theAlert setInformativeText:@"MGMSIP is not compiled with VoiceMac, you can not add a SIP account without first compiling with MGMSIP."];
|
||||||
|
[theAlert runModal];
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6: {
|
||||||
|
BOOL emptyFields = NO;
|
||||||
|
if (accountType==0) {
|
||||||
|
if ([[S4EmailField stringValue] isEqual:@""] || [[S4PasswordField stringValue] isEqual:@""])
|
||||||
|
emptyFields = YES;
|
||||||
|
} else if (accountType==1) {
|
||||||
|
if ([[S5EmailField stringValue] isEqual:@""] || [[S5PasswordField stringValue] isEqual:@""])
|
||||||
|
emptyFields = YES;
|
||||||
|
} else if (accountType==2) {
|
||||||
|
if ([[S6UserNameField stringValue] isEqual:@""] || [[S6PasswordField stringValue] isEqual:@""])
|
||||||
|
emptyFields = YES;
|
||||||
|
}
|
||||||
|
if (emptyFields) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Missing Information"];
|
||||||
|
[theAlert setInformativeText:@"It appears as if you did not fill the required fields, please fill out the required fields and then continue."];
|
||||||
|
[theAlert runModal];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
step = 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 9:
|
||||||
|
if (isAttached) {
|
||||||
|
[[NSApplication sharedApplication] endSheet:setupWindow];
|
||||||
|
}
|
||||||
|
[setupWindow orderOut:self];
|
||||||
|
[accountsCreated makeObjectsPerformSelector:@selector(start)];
|
||||||
|
[self release];
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Step 4
|
||||||
|
- (void)S4Reset {
|
||||||
|
[S4EmailField setStringValue:@""];
|
||||||
|
[S4PasswordField setStringValue:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Step 5
|
||||||
|
- (void)S5Reset {
|
||||||
|
[S5EmailField setStringValue:@""];
|
||||||
|
[S5PasswordField setStringValue:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Step 6
|
||||||
|
- (IBAction)S6UserNameChanged:(id)sender {
|
||||||
|
[[S6FullNameField cell] setPlaceholderString:[S6UserNameField stringValue]];
|
||||||
|
}
|
||||||
|
- (IBAction)S6DomainChanged:(id)sender {
|
||||||
|
if ([[S6DomainField stringValue] isEqual:@""])
|
||||||
|
[[S6RegistrarField cell] setPlaceholderString:MGMSIPDefaultDomain];
|
||||||
|
else
|
||||||
|
[[S6RegistrarField cell] setPlaceholderString:[S6DomainField stringValue]];
|
||||||
|
}
|
||||||
|
- (void)S6Reset {
|
||||||
|
[S6FullNameField setStringValue:@""];
|
||||||
|
[[S6FullNameField cell] setPlaceholderString:@"UserName"];
|
||||||
|
[S6DomainField setStringValue:@""];
|
||||||
|
[S6RegistrarField setStringValue:@""];
|
||||||
|
[S6UserNameField setStringValue:@""];
|
||||||
|
[S6PasswordField setStringValue:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Step 7
|
||||||
|
- (void)S7CheckGoogleVoice {
|
||||||
|
S7CheckUser = [[MGMUser createUserWithName:[S4EmailField stringValue] password:[S4PasswordField stringValue]] retain];
|
||||||
|
[S7CheckUser setSetting:MGMSGoogleVoice forKey:MGMSAccountType];
|
||||||
|
S7CheckInstance = [[MGMInstance instanceWithUser:S7CheckUser delegate:self isCheck:YES] retain];
|
||||||
|
}
|
||||||
|
- (void)loginError:(NSError *)theError {
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
[S7CheckUser remove];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
if (S7CheckInstance!=nil) {
|
||||||
|
[S7CheckInstance release];
|
||||||
|
S7CheckInstance = nil;
|
||||||
|
}
|
||||||
|
NSLog(@"Login Failed %@", theError);
|
||||||
|
S8Message = [[theError localizedDescription] copy];
|
||||||
|
step = 8;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
- (void)loginSuccessful {
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
[accountsCreated addObject:S7CheckUser];
|
||||||
|
MGMUser *contactsUser = [MGMUser createUserWithName:[S4EmailField stringValue] password:[S4PasswordField stringValue]];
|
||||||
|
[contactsUser setSetting:MGMSGoogleContacts forKey:MGMSAccountType];
|
||||||
|
[S7CheckUser setSetting:[contactsUser settingForKey:MGMUserID] forKey:MGMCGoogleContactsUser];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
if (S7CheckInstance!=nil) {
|
||||||
|
[S7CheckInstance release];
|
||||||
|
S7CheckInstance = nil;
|
||||||
|
}
|
||||||
|
[self S4Reset];
|
||||||
|
step = 9;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)S7CheckGoogleContacts {
|
||||||
|
S7CheckUser = [[MGMUser createUserWithName:[S5EmailField stringValue] password:[S5PasswordField stringValue]] retain];
|
||||||
|
[S7CheckUser setSetting:MGMSGoogleContacts forKey:MGMSAccountType];
|
||||||
|
NSString *username = [S7CheckUser settingForKey:MGMUserName];
|
||||||
|
if (![username containsString:@"@"])
|
||||||
|
username = [username stringByAppendingString:@"@gmail.com"];
|
||||||
|
NSURLCredential *credentials = [NSURLCredential credentialWithUser:username password:[S7CheckUser password] persistence:NSURLCredentialPersistenceForSession];
|
||||||
|
[S7ConnectionManager setCookieStorage:[S7CheckUser cookieStorage]];
|
||||||
|
[S7ConnectionManager setCredentials:credentials];
|
||||||
|
[S7ConnectionManager setCustomUseragent:MGMGCUseragent];
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCAuthenticationURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
|
||||||
|
[request setHTTPMethod:MGMPostMethod];
|
||||||
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
||||||
|
[request setHTTPBody:[[NSString stringWithFormat:MGMGCAuthenticationBody, [username addPercentEscapes], [[S7CheckUser password] addPercentEscapes]] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
[S7ConnectionManager connectionWithRequest:request delegate:self didFailWithError:@selector(authentication:didFailWithError:) didFinish:@selector(authenticationDidFinish:) invisible:NO object:nil];
|
||||||
|
}
|
||||||
|
- (void)authentication:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
[S7CheckUser remove];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
if (S7ConnectionManager!=nil)
|
||||||
|
[S7ConnectionManager setCookieStorage:nil];
|
||||||
|
NSLog(@"Login Failed %@", theError);
|
||||||
|
S8Message = [[theError localizedDescription] copy];
|
||||||
|
step = 8;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
- (void)authenticationDidFinish:(NSDictionary *)theInfo {
|
||||||
|
NSDictionary *info = [MGMGoogleContacts dictionaryWithData:[theInfo objectForKey:MGMConnectionData]];
|
||||||
|
if (S7ConnectionManager!=nil)
|
||||||
|
[S7ConnectionManager setCookieStorage:nil];
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
if ([info objectForKey:@"Error"]!=nil) {
|
||||||
|
[S7CheckUser remove];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
S8Message = [@"Unable to login. Please check your Credentials." retain];
|
||||||
|
step = 8;
|
||||||
|
[self displayStep];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[S7CheckUser done];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self S5Reset];
|
||||||
|
step = 9;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)S7CheckSIP {
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
if (![[MGMSIP sharedSIP] isStarted]) [[MGMSIP sharedSIP] start];
|
||||||
|
S7CheckUser = [[MGMUser createUserWithName:[S6UserNameField stringValue] password:[S6PasswordField stringValue]] retain];
|
||||||
|
[S7CheckUser setSetting:MGMSSIP forKey:MGMSAccountType];
|
||||||
|
NSString *fullName = [S6FullNameField stringValue];
|
||||||
|
if ([fullName isEqual:@""])
|
||||||
|
fullName = [S6UserNameField stringValue];
|
||||||
|
[S7CheckUser setSetting:fullName forKey:MGMSIPAccountFullName];
|
||||||
|
[S7CheckUser setSetting:[S6UserNameField stringValue] forKey:MGMSIPAccountUserName];
|
||||||
|
if ([[S6UserNameField stringValue] isPhone])
|
||||||
|
[S7CheckUser setSetting:[[S6UserNameField stringValue] areaCode] forKey:MGMSIPUserAreaCode];
|
||||||
|
if ([[S6DomainField stringValue] isEqual:@""])
|
||||||
|
[S7CheckUser setSetting:MGMSIPDefaultDomain forKey:MGMSIPAccountDomain];
|
||||||
|
else
|
||||||
|
[S7CheckUser setSetting:[S6DomainField stringValue] forKey:MGMSIPAccountDomain];
|
||||||
|
if (![[S6RegistrarField stringValue] isEqual:@""])
|
||||||
|
[S7CheckUser setSetting:[S6RegistrarField stringValue] forKey:MGMSIPAccountRegistrar];
|
||||||
|
S7CheckSIPAccount = [[MGMSIPAccount alloc] initWithSettings:[S7CheckUser settings]];
|
||||||
|
[S7CheckSIPAccount setDelegate:self];
|
||||||
|
S7AccountRegistered = NO;
|
||||||
|
[NSThread detachNewThreadSelector:@selector(login) toTarget:S7CheckSIPAccount withObject:nil];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
- (NSString *)password {
|
||||||
|
return [S7CheckUser password];
|
||||||
|
}
|
||||||
|
- (void)registrationChanged {
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
if (S7SIPRegistrationTimeout!=nil) {
|
||||||
|
[S7SIPRegistrationTimeout invalidate];
|
||||||
|
[S7SIPRegistrationTimeout release];
|
||||||
|
S7SIPRegistrationTimeout = nil;
|
||||||
|
}
|
||||||
|
if (S7CheckSIPAccount!=nil) {
|
||||||
|
if (![S7CheckSIPAccount isRegistered]) {
|
||||||
|
[S7CheckSIPAccount setLastError:@"Unable to Register with Server. Please check your credentials."];
|
||||||
|
[self loginErrored];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[S7CheckSIPAccount setDelegate:nil];
|
||||||
|
[S7CheckSIPAccount logout];
|
||||||
|
[S7CheckSIPAccount release];
|
||||||
|
S7CheckSIPAccount = nil;
|
||||||
|
}
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
[accountsCreated addObject:S7CheckUser];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
[self S6Reset];
|
||||||
|
S7AccountRegistered = YES;
|
||||||
|
step = 9;
|
||||||
|
[self displayStep];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
- (void)S7SIPTimeout {
|
||||||
|
if (S7SIPRegistrationTimeout!=nil) {
|
||||||
|
[S7SIPRegistrationTimeout invalidate];
|
||||||
|
[S7SIPRegistrationTimeout release];
|
||||||
|
S7SIPRegistrationTimeout = nil;
|
||||||
|
}
|
||||||
|
[S7CheckSIPAccount setLastError:@"Registration Timeout."];
|
||||||
|
[self loginErrored];
|
||||||
|
}
|
||||||
|
- (void)loggedIn {
|
||||||
|
[S7StatusField setStringValue:MGMS7SIPWaiting];
|
||||||
|
[self performSelectorOnMainThread:@selector(S7StartRegistrationTimeoutTimer) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
- (void)S7StartRegistrationTimeoutTimer {
|
||||||
|
if (!S7AccountRegistered)
|
||||||
|
S7SIPRegistrationTimeout = [[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(S7SIPTimeout) userInfo:nil repeats:NO] retain];
|
||||||
|
}
|
||||||
|
- (void)loginErrored {
|
||||||
|
if (S7CheckUser!=nil) {
|
||||||
|
[S7CheckUser remove];
|
||||||
|
[S7CheckUser release];
|
||||||
|
S7CheckUser = nil;
|
||||||
|
}
|
||||||
|
if (S7CheckSIPAccount!=nil) {
|
||||||
|
NSLog(@"Login Failed %@", [S7CheckSIPAccount lastError]);
|
||||||
|
S8Message = [[S7CheckSIPAccount lastError] copy];
|
||||||
|
[S7CheckSIPAccount setDelegate:nil];
|
||||||
|
[S7CheckSIPAccount logout];
|
||||||
|
[S7CheckSIPAccount release];
|
||||||
|
S7CheckSIPAccount = nil;
|
||||||
|
}
|
||||||
|
step = 8;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Step 9
|
||||||
|
- (IBAction)S9AddAnotherAccount:(id)sender {
|
||||||
|
step = 2;
|
||||||
|
[self displayStep];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
step = 9;
|
||||||
|
[self continue:self];
|
||||||
|
}
|
||||||
|
@end
|
23
Classes/VoiceMac/MGMBadge.h
Normal file
23
Classes/VoiceMac/MGMBadge.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// MGMBadge.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/8/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMBadge : NSObject {
|
||||||
|
NSString *label;
|
||||||
|
BOOL visable;
|
||||||
|
NSImage *applicationIcon;
|
||||||
|
}
|
||||||
|
- (void)drawIcon;
|
||||||
|
|
||||||
|
- (void)setLabel:(NSString *)badgeLabel;
|
||||||
|
- (NSString *)label;
|
||||||
|
|
||||||
|
- (void)setVisable:(BOOL)isVisable;
|
||||||
|
- (BOOL)visable;
|
||||||
|
@end
|
76
Classes/VoiceMac/MGMBadge.m
Normal file
76
Classes/VoiceMac/MGMBadge.m
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// MGMBadge.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/8/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMBadge.h"
|
||||||
|
|
||||||
|
@implementation MGMBadge
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
applicationIcon = [[[NSApplication sharedApplication] applicationIconImage] copy];
|
||||||
|
visable = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (label!=nil)
|
||||||
|
[label release];
|
||||||
|
if (applicationIcon!=nil)
|
||||||
|
[applicationIcon release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawIcon {
|
||||||
|
NSImage *left = [NSImage imageNamed:@"badgel"];
|
||||||
|
NSImage *middle = [NSImage imageNamed:@"badgem"];
|
||||||
|
NSImage *right = [NSImage imageNamed:@"badger"];
|
||||||
|
NSSize leftSize = [left size];
|
||||||
|
NSSize middleSize = [middle size];
|
||||||
|
NSSize rightSize = [right size];
|
||||||
|
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"Helvetica" size:30], NSFontAttributeName, [NSColor whiteColor], NSForegroundColorAttributeName, nil];
|
||||||
|
NSSize textSize = [label sizeWithAttributes:attributes];
|
||||||
|
NSImage *icon = [[applicationIcon copy] autorelease];
|
||||||
|
NSSize iconSize = [icon size];
|
||||||
|
if (visable) {
|
||||||
|
NSSize imageSize = NSMakeSize(((textSize.width+leftSize.width+rightSize.width)>=iconSize.width ? iconSize.width : textSize.width+leftSize.width+rightSize.width), middleSize.height);
|
||||||
|
NSImage *badge = [[[NSImage alloc] initWithSize:imageSize] autorelease];
|
||||||
|
[badge lockFocus];
|
||||||
|
[left drawInRect:NSMakeRect(0, 0, leftSize.width, leftSize.height) fromRect:NSMakeRect(0, 0, leftSize.width, leftSize.height) operation:NSCompositeSourceOver fraction:1.0];
|
||||||
|
for (int y=leftSize.width; y<(imageSize.width-rightSize.width); y++) {
|
||||||
|
[middle drawInRect:NSMakeRect(y, 0, middleSize.width, middleSize.height) fromRect:NSMakeRect(0, 0, middleSize.width, middleSize.height) operation:NSCompositeSourceOver fraction:1.0];
|
||||||
|
}
|
||||||
|
[right drawInRect:NSMakeRect(imageSize.width-rightSize.width, 0, rightSize.width, rightSize.height) fromRect:NSMakeRect(0, 0, rightSize.width, rightSize.height) operation:NSCompositeSourceOver fraction:1.0];
|
||||||
|
|
||||||
|
[label drawInRect:NSMakeRect(leftSize.width, ((imageSize.height+2)-textSize.height)/2, textSize.width, textSize.height) withAttributes:attributes];
|
||||||
|
[badge unlockFocus];
|
||||||
|
[icon lockFocus];
|
||||||
|
[badge drawInRect:NSMakeRect(iconSize.width-imageSize.width, iconSize.height-imageSize.height, imageSize.width, imageSize.height) fromRect:NSMakeRect(0, 0, imageSize.width, imageSize.height) operation:NSCompositeSourceOver fraction:1.0];
|
||||||
|
[icon unlockFocus];
|
||||||
|
}
|
||||||
|
[[NSApplication sharedApplication] setApplicationIconImage:icon];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLabel:(NSString *)badgeLabel {
|
||||||
|
if (label!=nil) [label release];
|
||||||
|
label = [badgeLabel copy];
|
||||||
|
if (label==nil || [label isEqual:@""])
|
||||||
|
[self setVisable:NO];
|
||||||
|
else
|
||||||
|
[self setVisable:YES];
|
||||||
|
}
|
||||||
|
- (NSString *)label {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVisable:(BOOL)isVisable {
|
||||||
|
visable = isVisable;
|
||||||
|
[self drawIcon];
|
||||||
|
}
|
||||||
|
- (BOOL)visable {
|
||||||
|
return visable;
|
||||||
|
}
|
||||||
|
@end
|
73
Classes/VoiceMac/MGMContactsController.h
Normal file
73
Classes/VoiceMac/MGMContactsController.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// MGMContactsController.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/12/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMController, MGMPhoneField, MGMPhoneFieldView, MGMContactsTableView, MGMContacts;
|
||||||
|
|
||||||
|
extern NSString *MGMContactsWindowOpen;
|
||||||
|
|
||||||
|
@interface MGMContactsController : NSObject {
|
||||||
|
MGMController *controller;
|
||||||
|
IBOutlet NSWindow *contactsWindow;
|
||||||
|
BOOL closingWindow;
|
||||||
|
IBOutlet MGMContactsTableView *contactsTable;
|
||||||
|
IBOutlet MGMPhoneField *phoneField;
|
||||||
|
MGMPhoneFieldView *phoneFieldView;
|
||||||
|
|
||||||
|
NSLock *filterLock;
|
||||||
|
NSString *contactsMatchString;
|
||||||
|
int filterWaiting;
|
||||||
|
NSMutableArray *contactViews;
|
||||||
|
int contactsCount;
|
||||||
|
NSRange contactsLoading;
|
||||||
|
NSRange contactsVisible;
|
||||||
|
|
||||||
|
BOOL hasCustomIncomingIcon;
|
||||||
|
}
|
||||||
|
- (id)initWithController:(MGMController *)theController;
|
||||||
|
|
||||||
|
- (MGMController *)controller;
|
||||||
|
- (NSString *)menuTitle;
|
||||||
|
- (NSArray *)contactViews;
|
||||||
|
- (NSWindow *)contactsWindow;
|
||||||
|
- (NSTableView *)contactsTable;
|
||||||
|
- (MGMPhoneField *)phoneField;
|
||||||
|
- (void)showContactsWindow;
|
||||||
|
- (MGMContacts *)contacts;
|
||||||
|
- (NSString *)filterString;
|
||||||
|
|
||||||
|
- (void)reloadData;
|
||||||
|
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
|
||||||
|
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
|
||||||
|
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row;
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
|
||||||
|
- (void)checkContactRow:(int)row;
|
||||||
|
|
||||||
|
- (void)updatedTheme:(NSNotification *)theNotification;
|
||||||
|
|
||||||
|
- (void)filterContacts;
|
||||||
|
- (void)backgroundFilter;
|
||||||
|
- (void)loadContacts:(BOOL)updatingCount;
|
||||||
|
- (void)selectFirstContact;
|
||||||
|
|
||||||
|
- (void)updatedContacts;
|
||||||
|
|
||||||
|
- (NSString *)areaCode;
|
||||||
|
- (NSString *)currentPhoneNumber;
|
||||||
|
- (IBAction)runAction:(id)sender;
|
||||||
|
- (IBAction)call:(id)sender;
|
||||||
|
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMContactsTableView : NSTableView {
|
||||||
|
IBOutlet MGMContactsController *contactsController;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
293
Classes/VoiceMac/MGMContactsController.m
Normal file
293
Classes/VoiceMac/MGMContactsController.m
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
//
|
||||||
|
// MGMContactsController.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/12/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMContactsController.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMViewCell.h"
|
||||||
|
#import "MGMContactView.h"
|
||||||
|
#import "MGMPhoneFeild.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
NSString *MGMContactsWindowOpen = @"MGMContactsWindowOpen";
|
||||||
|
|
||||||
|
@implementation MGMContactsController
|
||||||
|
- (id)initWithController:(MGMController *)theController {
|
||||||
|
if (self = [super init]) {
|
||||||
|
controller = theController;
|
||||||
|
filterLock = [NSLock new];
|
||||||
|
filterWaiting = 0;
|
||||||
|
contactViews = [NSMutableArray new];
|
||||||
|
contactsCount = 0;
|
||||||
|
|
||||||
|
hasCustomIncomingIcon = [[controller themeManager] hasCustomIncomingIcon];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatedTheme:) name:MGMTUpdatedSMSThemeNotification object:[controller themeManager]];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[[[contactsTable tableColumns] objectAtIndex:0] setDataCell:[[MGMViewCell new] autorelease]];
|
||||||
|
[contactsTable setTarget:self];
|
||||||
|
[contactsTable setDoubleAction:@selector(runAction:)];
|
||||||
|
[contactsWindow setExcludedFromWindowsMenu:YES];
|
||||||
|
|
||||||
|
phoneFieldView = [[MGMPhoneFieldView alloc] initWithFrame:NSZeroRect];
|
||||||
|
[phoneFieldView setFieldEditor:YES];
|
||||||
|
[phoneFieldView setPhoneDelegate:self];
|
||||||
|
[phoneField setDelegate:self];
|
||||||
|
[self filterContacts];
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (contactsWindow!=nil)
|
||||||
|
[contactsWindow close];
|
||||||
|
if (filterLock!=nil) {
|
||||||
|
[filterLock lock];
|
||||||
|
[filterLock unlock];
|
||||||
|
[filterLock release];
|
||||||
|
}
|
||||||
|
if (contactViews!=nil)
|
||||||
|
[contactViews release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMController *)controller {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
- (NSString *)menuTitle {
|
||||||
|
return @"Contacts";
|
||||||
|
}
|
||||||
|
- (NSArray *)contactViews {
|
||||||
|
return contactViews;
|
||||||
|
}
|
||||||
|
- (NSWindow *)contactsWindow {
|
||||||
|
return contactsWindow;
|
||||||
|
}
|
||||||
|
- (NSTableView *)contactsTable {
|
||||||
|
return contactsTable;
|
||||||
|
}
|
||||||
|
- (MGMPhoneField *)phoneField {
|
||||||
|
return phoneField;
|
||||||
|
}
|
||||||
|
- (void)showContactsWindow {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (MGMContacts *)contacts {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (NSString *)filterString {
|
||||||
|
return [phoneField stringValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {
|
||||||
|
if (commandSelector==@selector(insertNewline:)) {
|
||||||
|
[self runAction:self];
|
||||||
|
return YES;
|
||||||
|
} else if (commandSelector==@selector(moveDown:)) {
|
||||||
|
[self selectFirstContact];
|
||||||
|
return YES;
|
||||||
|
} else if (commandSelector==@selector(deleteToBeginningOfLine:)) {
|
||||||
|
[self performSelector:@selector(filterContacts) withObject:nil afterDelay:0.2];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadData {
|
||||||
|
while ([[contactsTable subviews] count]>0)
|
||||||
|
[[[contactsTable subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay];
|
||||||
|
[contactsTable reloadData];
|
||||||
|
[contactsTable display];
|
||||||
|
}
|
||||||
|
- (int)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||||
|
return contactsCount;
|
||||||
|
}
|
||||||
|
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row {
|
||||||
|
if (row>=contactsCount) return;
|
||||||
|
[self checkContactRow:row];
|
||||||
|
[filterLock lock];
|
||||||
|
@try {
|
||||||
|
[(MGMViewCell *)cell addSubview:[contactViews objectAtIndex:row-contactsVisible.location]];
|
||||||
|
}
|
||||||
|
@catch (NSException *e) {
|
||||||
|
NSLog(@"Contact error, ignoreing. %@", e);
|
||||||
|
}
|
||||||
|
[filterLock unlock];
|
||||||
|
}
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row {
|
||||||
|
if (row>=contactsCount) return NO;
|
||||||
|
[self checkContactRow:row];
|
||||||
|
[phoneField setStringValue:[[[[contactViews objectAtIndex:row-contactsVisible.location] contact] objectForKey:MGMCNumber] readableNumber]];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)checkContactRow:(int)row {
|
||||||
|
if (!NSLocationInRange(row, contactsVisible)) {
|
||||||
|
int maxResults = [[self contacts] maxResults];
|
||||||
|
int page = (row/maxResults)+1;
|
||||||
|
contactsLoading.location = ((page==1 ? 1 : page-1)*maxResults)-maxResults;
|
||||||
|
contactsLoading.length = (row<(maxResults-3) ? maxResults : maxResults*2);
|
||||||
|
[self loadContacts:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatedTheme:(NSNotification *)theNotification {
|
||||||
|
BOOL customIncoming = [[controller themeManager] hasCustomIncomingIcon];
|
||||||
|
if (hasCustomIncomingIcon!=customIncoming || customIncoming) {
|
||||||
|
hasCustomIncomingIcon = customIncoming;
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)filterContacts {
|
||||||
|
[NSThread detachNewThreadSelector:@selector(backgroundFilter) toTarget:self withObject:nil];
|
||||||
|
}
|
||||||
|
- (void)backgroundFilter {
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
if (filterWaiting>=1)
|
||||||
|
return;
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
filterWaiting++;
|
||||||
|
[filterLock lock];
|
||||||
|
filterWaiting--;
|
||||||
|
contactsCount = 0;
|
||||||
|
[contactViews removeAllObjects];
|
||||||
|
if (contactsMatchString!=nil) [contactsMatchString release];
|
||||||
|
contactsMatchString = [[self filterString] copy];
|
||||||
|
int count = [[[self contacts] countContactsMatching:contactsMatchString] intValue];
|
||||||
|
[contactsTable scrollRowToVisible:0];
|
||||||
|
|
||||||
|
contactsLoading.location = 0;
|
||||||
|
contactsLoading.length = 0;
|
||||||
|
contactsVisible.location = 0;
|
||||||
|
contactsVisible.length = [[self contacts] maxResults];
|
||||||
|
|
||||||
|
NSArray *newContacts = [[self contacts] contactsMatching:contactsMatchString page:1];
|
||||||
|
for (int i=0; i<[newContacts count]; i++) {
|
||||||
|
MGMContactView *contact = [MGMContactView viewWithFrame:NSMakeRect(0, 0, 200, 64) themeManager:[controller themeManager]];
|
||||||
|
[contact setContact:[newContacts objectAtIndex:i]];
|
||||||
|
[contactViews addObject:contact];
|
||||||
|
}
|
||||||
|
contactsCount = count;
|
||||||
|
[filterLock unlock];
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
[self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)loadContacts:(BOOL)updatingCount {
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
[filterLock lock];
|
||||||
|
int count = 0;
|
||||||
|
if (updatingCount) {
|
||||||
|
count = [[[self contacts] countContactsMatching:contactsMatchString] intValue];
|
||||||
|
contactsCount = 0;
|
||||||
|
}
|
||||||
|
int maxResults = [[self contacts] maxResults];
|
||||||
|
[contactViews removeAllObjects];
|
||||||
|
int page = contactsLoading.location/maxResults;
|
||||||
|
int times = contactsLoading.length/maxResults;
|
||||||
|
for (int t=0; t<times; t++) {
|
||||||
|
page++;
|
||||||
|
NSArray *newContacts = [[self contacts] contactsMatching:contactsMatchString page:page];
|
||||||
|
for (int i=0; i<[newContacts count]; i++) {
|
||||||
|
MGMContactView *contact = [MGMContactView viewWithFrame:NSMakeRect(0, 0, 200, 64) themeManager:[controller themeManager]];
|
||||||
|
[contact setContact:[newContacts objectAtIndex:i]];
|
||||||
|
[contactViews addObject:contact];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contactsVisible = contactsLoading;
|
||||||
|
if (updatingCount)
|
||||||
|
contactsCount = count;
|
||||||
|
[filterLock unlock];
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
[self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
- (void)selectFirstContact {
|
||||||
|
[contactsWindow makeFirstResponder:contactsTable];
|
||||||
|
[contactsTable selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||||
|
[self tableView:contactsTable shouldSelectRow:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatedContacts {
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
contactsLoading = contactsVisible;
|
||||||
|
[self loadContacts:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)areaCode {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (NSString *)currentPhoneNumber {
|
||||||
|
NSString *phoneNumber = nil;
|
||||||
|
if (phoneNumber==nil && ![[phoneField stringValue] isPhoneComplete]) {
|
||||||
|
if ([contactViews count]>0) {
|
||||||
|
[self selectFirstContact];
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (phoneNumber==nil)
|
||||||
|
phoneNumber = [[phoneField stringValue] phoneFormatWithAreaCode:[self areaCode]];
|
||||||
|
return phoneNumber;
|
||||||
|
}
|
||||||
|
- (IBAction)runAction:(id)sender {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (IBAction)call:(id)sender {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject {
|
||||||
|
if ([anObject isKindOfClass:[MGMPhoneField class]]) {
|
||||||
|
return phoneFieldView;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||||
|
[controller contactsControllerBecameCurrent:self];
|
||||||
|
}
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
[contactViews removeAllObjects];
|
||||||
|
contactsCount = 0;
|
||||||
|
[self reloadData];
|
||||||
|
[contactsWindow setDelegate:nil];
|
||||||
|
contactsWindow = nil;
|
||||||
|
contactsTable = nil;
|
||||||
|
if (phoneFieldView!=nil) {
|
||||||
|
[phoneFieldView release];
|
||||||
|
phoneFieldView = nil;
|
||||||
|
}
|
||||||
|
phoneField = nil;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMContactsTableView
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent {
|
||||||
|
int keyCode = [theEvent keyCode];
|
||||||
|
if (keyCode==36 || keyCode==76) {
|
||||||
|
[contactsController runAction:self];
|
||||||
|
} else if (keyCode==48) {
|
||||||
|
[[self window] makeFirstResponder:[contactsController phoneField]];
|
||||||
|
} else {
|
||||||
|
[super keyDown:theEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)copy:(id)sender {
|
||||||
|
if ([self selectedRow]==-1) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSString *phoneNumber = [[[[contactsController contactViews] objectAtIndex:[self selectedRow]] contact] objectForKey:MGMCNumber];
|
||||||
|
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
|
||||||
|
[pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
|
||||||
|
[pasteBoard setString:[phoneNumber readableNumber] forType:NSStringPboardType];
|
||||||
|
}
|
||||||
|
@end
|
82
Classes/VoiceMac/MGMController.h
Normal file
82
Classes/VoiceMac/MGMController.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// MGMController.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMContactsController, MGMPreferences, MGMTaskManager, MGMWhitePages, MGMThemeManager, MGMSMSManager, MGMBadge, MGMMultiSMS, MGMInstance, WebView;
|
||||||
|
|
||||||
|
extern NSString * const MGMContactsControllersChangedNotification;
|
||||||
|
|
||||||
|
@interface MGMController : NSObject {
|
||||||
|
NSMutableArray *contactsControllers;
|
||||||
|
int currentContactsController;
|
||||||
|
NSMutableArray *multipleSMS;
|
||||||
|
MGMPreferences *preferences;
|
||||||
|
MGMTaskManager *taskManager;
|
||||||
|
MGMWhitePages *whitePages;
|
||||||
|
BOOL quitting;
|
||||||
|
|
||||||
|
MGMThemeManager *themeManager;
|
||||||
|
MGMSMSManager *SMSManager;
|
||||||
|
MGMBadge *badge;
|
||||||
|
NSMutableDictionary *badgeValues;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *aboutWindow;
|
||||||
|
IBOutlet NSTextField *aboutNameField;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *RLWindow;
|
||||||
|
IBOutlet NSTextField *RLName;
|
||||||
|
IBOutlet NSTextField *RLAddress;
|
||||||
|
IBOutlet NSTextField *RLCityState;
|
||||||
|
IBOutlet NSTextField *RLZipCode;
|
||||||
|
IBOutlet NSTextField *RLPhoneNumber;
|
||||||
|
IBOutlet WebView *RLMap;
|
||||||
|
IBOutlet NSMenu *windowMenu;
|
||||||
|
}
|
||||||
|
- (void)registerDefaults;
|
||||||
|
|
||||||
|
- (BOOL)isQuitting;
|
||||||
|
- (NSArray *)contactsControllers;
|
||||||
|
- (MGMPreferences *)preferences;
|
||||||
|
- (MGMThemeManager *)themeManager;
|
||||||
|
- (MGMSMSManager *)SMSManager;
|
||||||
|
- (MGMBadge *)badge;
|
||||||
|
- (void)setBadge:(int)theBadge forInstance:(MGMInstance *)theInstance;
|
||||||
|
|
||||||
|
- (void)updateWindowMenu;
|
||||||
|
|
||||||
|
- (IBAction)about:(id)sender;
|
||||||
|
- (IBAction)showTaskManager:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)showInbox:(id)sender;
|
||||||
|
- (IBAction)refreshInbox:(id)sender;
|
||||||
|
- (IBAction)inboxSpam:(id)sender;
|
||||||
|
- (IBAction)inboxMarkRead:(id)sender;
|
||||||
|
- (IBAction)inboxDelete:(id)sender;
|
||||||
|
- (IBAction)inboxUndelete:(id)sender;
|
||||||
|
|
||||||
|
- (void)contactsControllerBecameCurrent:(MGMContactsController *)theContactsController;
|
||||||
|
- (NSString *)currentPhoneNumber;
|
||||||
|
|
||||||
|
- (IBAction)preferences:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)sendMultipleSMS:(id)sender;
|
||||||
|
- (void)removeMultiSMS:(MGMMultiSMS *)theMultiSMS;
|
||||||
|
|
||||||
|
- (IBAction)saveAudio:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)call:(id)sender;
|
||||||
|
- (IBAction)sms:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)reverseLookup:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)donate:(id)sender;
|
||||||
|
- (IBAction)viewTOS:(id)sender;
|
||||||
|
- (IBAction)rates:(id)sender;
|
||||||
|
- (IBAction)billing:(id)sender;
|
||||||
|
@end
|
633
Classes/VoiceMac/MGMController.m
Normal file
633
Classes/VoiceMac/MGMController.m
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
//
|
||||||
|
// MGMController.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMAccountSetup.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import "MGMSMSManager.h"
|
||||||
|
#import "MGMSMSMessageView.h"
|
||||||
|
#import "MGMBadge.h"
|
||||||
|
#import "MGMMultiSMS.h"
|
||||||
|
#import "MGMInboxWindow.h"
|
||||||
|
#import "MGMPhoneFeild.h"
|
||||||
|
#import "MGMNumberOptions.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <GeckoReporter/GeckoReporter.h>
|
||||||
|
#import <Growl/GrowlApplicationBridge.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
NSString * const MGMCopyright = @"Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/";
|
||||||
|
NSString * const MGMVersion = @"MGMVersion";
|
||||||
|
NSString * const MGMLaunchCount = @"MGMLaunchCount";
|
||||||
|
|
||||||
|
NSString * const MGMMakeDefault = @"MGMMakeDefault";
|
||||||
|
|
||||||
|
NSString * const MGMContactsControllersChangedNotification = @"MGMContactsControllersChangedNotification";
|
||||||
|
|
||||||
|
NSString * const MGMLoading = @"Loading...";
|
||||||
|
|
||||||
|
@implementation MGMController
|
||||||
|
// MegaEduX was here.
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:MGMGRDoneNotification object:nil];
|
||||||
|
[MGMReporter sharedReporter];
|
||||||
|
}
|
||||||
|
- (void)setup {
|
||||||
|
[GrowlApplicationBridge setGrowlDelegate:nil];
|
||||||
|
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
if ([defaults boolForKey:MGMMakeDefault]) {
|
||||||
|
NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("tel"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("callto"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("telephone"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("phone"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("phonenumber"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("call"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("sms"), (CFStringRef)bundleID);
|
||||||
|
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("vmsound"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("vmtheme"), (CFStringRef)bundleID);
|
||||||
|
[defaults removeObjectForKey:MGMMakeDefault];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([defaults objectForKey:MGMVersion]==nil) {
|
||||||
|
[defaults setObject:[[MGMSystemInfo info] applicationVersion] forKey:MGMVersion];
|
||||||
|
[defaults removeObjectForKey:@"actionCall"];
|
||||||
|
[defaults removeObjectForKey:@"googleContact"];
|
||||||
|
[defaults removeObjectForKey:@"lastPhone"];
|
||||||
|
[defaults removeObjectForKey:@"MailSoundPath"];
|
||||||
|
[defaults removeObjectForKey:@"MailSoundVariant"];
|
||||||
|
[defaults removeObjectForKey:@"NSSplitView Subview Frames SMSSplitView"];
|
||||||
|
[defaults removeObjectForKey:@"NSWindow Frame SMSWindow"];
|
||||||
|
[defaults removeObjectForKey:@"NSWindow Frame contactsWindow"];
|
||||||
|
[defaults removeObjectForKey:@"NSWindow Frame InformationWindow"];
|
||||||
|
[defaults removeObjectForKey:@"SMSSoundPath"];
|
||||||
|
[defaults removeObjectForKey:@"SMSSoundVariant"];
|
||||||
|
[defaults removeObjectForKey:@"SMSThemePath"];
|
||||||
|
[defaults removeObjectForKey:@"SMSThemeVariant"];
|
||||||
|
}
|
||||||
|
[self registerDefaults];
|
||||||
|
if ([defaults integerForKey:MGMLaunchCount]!=5) {
|
||||||
|
[defaults setInteger:[defaults integerForKey:MGMLaunchCount]+1 forKey:MGMLaunchCount];
|
||||||
|
if ([defaults integerForKey:MGMLaunchCount]==5) {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Donations"];
|
||||||
|
[alert setInformativeText:@"Thank you for using VoiceMac. VoiceMac is donation supported software. If you like using it, please consider giving a donation to help with development."];
|
||||||
|
[alert addButtonWithTitle:@"Yes"];
|
||||||
|
[alert addButtonWithTitle:@"No"];
|
||||||
|
int result = [alert runModal];
|
||||||
|
if (result==1000)
|
||||||
|
[self donate:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if ([manager fileExistsAtPath:[MGMUser cachePath]]) {
|
||||||
|
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
|
||||||
|
[manager removeFileAtPath:[MGMUser cachePath] handler:nil];
|
||||||
|
else
|
||||||
|
[manager removeItemAtPath:[MGMUser cachePath] error:nil];
|
||||||
|
}
|
||||||
|
quitting = NO;
|
||||||
|
currentContactsController = -1;
|
||||||
|
preferences = [MGMPreferences new];
|
||||||
|
[preferences addPreferencesPaneClassName:@"MGMAccountsPane"];
|
||||||
|
[preferences addPreferencesPaneClassName:@"MGMSoundsPane"];
|
||||||
|
[preferences addPreferencesPaneClassName:@"MGMSMSThemesPane"];
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
[preferences addPreferencesPaneClassName:@"MGMSIPPane"];
|
||||||
|
|
||||||
|
[[MGMSIP sharedSIP] setDelegate:self];
|
||||||
|
#endif
|
||||||
|
taskManager = [[MGMTaskManager managerWithDelegate:self] retain];
|
||||||
|
whitePages = [MGMWhitePages new];
|
||||||
|
|
||||||
|
themeManager = [MGMThemeManager new];
|
||||||
|
SMSManager = [[MGMSMSManager managerWithController:self] retain];
|
||||||
|
badge = [MGMBadge new];
|
||||||
|
badgeValues = [NSMutableDictionary new];
|
||||||
|
|
||||||
|
contactsControllers = [NSMutableArray new];
|
||||||
|
NSArray *lastUsers = [MGMUser lastUsers];
|
||||||
|
for (int i=0; i<[lastUsers count]; i++) {
|
||||||
|
MGMUser *user = [MGMUser userWithID:[lastUsers objectAtIndex:i]];
|
||||||
|
if ([[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleVoice]) {
|
||||||
|
[contactsControllers addObject:[MGMVoiceUser voiceUser:user controller:self]];
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
else if ([[user settingForKey:MGMSAccountType] isEqual:MGMSSIP]) {
|
||||||
|
if (![[MGMSIP sharedSIP] isStarted]) [[MGMSIP sharedSIP] start];
|
||||||
|
[contactsControllers addObject:[MGMSIPUser SIPUser:user controller:self]];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
multipleSMS = [NSMutableArray new];
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(userStarted:) name:MGMUserStartNotification object:nil];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(userDone:) name:MGMUserDoneNotification object:nil];
|
||||||
|
if ([contactsControllers count]==0) {
|
||||||
|
if ([[MGMUser userNames] count]==0)
|
||||||
|
[[MGMAccountSetup new] showSetupWindow:self]; // This is not a leak, it'll auto release it self when done.
|
||||||
|
else
|
||||||
|
[self preferences:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[RLMap mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"map" ofType:@"html"]]]];
|
||||||
|
|
||||||
|
NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
|
||||||
|
[em setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
|
||||||
|
|
||||||
|
[notificationCenter addObserver:self selector:@selector(updateWindowMenu) name:MGMContactsControllersChangedNotification object:nil];
|
||||||
|
[notificationCenter postNotificationName:MGMContactsControllersChangedNotification object:self];
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (contactsControllers!=nil)
|
||||||
|
[contactsControllers release];
|
||||||
|
if (multipleSMS!=nil)
|
||||||
|
[multipleSMS release];
|
||||||
|
if (preferences!=nil)
|
||||||
|
[preferences release];
|
||||||
|
if (taskManager!=nil)
|
||||||
|
[taskManager release];
|
||||||
|
if (whitePages!=nil)
|
||||||
|
[whitePages release];
|
||||||
|
if (themeManager!=nil)
|
||||||
|
[themeManager release];
|
||||||
|
if (SMSManager!=nil)
|
||||||
|
[SMSManager release];
|
||||||
|
if (badge!=nil)
|
||||||
|
[badge release];
|
||||||
|
if (badgeValues!=nil)
|
||||||
|
[badgeValues release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerDefaults {
|
||||||
|
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
|
||||||
|
[defaults setObject:[NSNumber numberWithInt:1] forKey:MGMLaunchCount];
|
||||||
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isQuitting {
|
||||||
|
return quitting;
|
||||||
|
}
|
||||||
|
- (NSArray *)contactsControllers {
|
||||||
|
return contactsControllers;
|
||||||
|
}
|
||||||
|
- (MGMPreferences *)preferences {
|
||||||
|
return preferences;
|
||||||
|
}
|
||||||
|
- (MGMThemeManager *)themeManager {
|
||||||
|
return themeManager;
|
||||||
|
}
|
||||||
|
- (MGMSMSManager *)SMSManager {
|
||||||
|
return SMSManager;
|
||||||
|
}
|
||||||
|
- (MGMBadge *)badge {
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
- (void)setBadge:(int)theBadge forInstance:(MGMInstance *)theInstance {
|
||||||
|
if (![theInstance isLoggedIn]) return;
|
||||||
|
if (theBadge==0)
|
||||||
|
[badgeValues removeObjectForKey:[theInstance userNumber]];
|
||||||
|
else
|
||||||
|
[badgeValues setObject:[NSNumber numberWithInt:theBadge] forKey:[theInstance userNumber]];
|
||||||
|
NSArray *valueKeys = [badgeValues allKeys];
|
||||||
|
int value = 0;
|
||||||
|
for (int i=0; i<[valueKeys count]; i++)
|
||||||
|
value += [[badgeValues objectForKey:[valueKeys objectAtIndex:i]] intValue];
|
||||||
|
if (value==0)
|
||||||
|
[badge setLabel:nil];
|
||||||
|
else
|
||||||
|
[badge setLabel:[[NSNumber numberWithInt:value] stringValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
|
||||||
|
SEL menuSelector = [menuItem action];
|
||||||
|
if (menuSelector==@selector(showInbox:) || menuSelector==@selector(call:)) {
|
||||||
|
return (currentContactsController!=-1);
|
||||||
|
} else if (menuSelector==@selector(sms:)) {
|
||||||
|
return (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(sms:)]);
|
||||||
|
} else if (menuSelector==@selector(inboxSpam:)) {
|
||||||
|
if (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem]!=nil) {
|
||||||
|
if ([[[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem] objectForKey:MGMISpam] boolValue])
|
||||||
|
[menuItem setTitle:@"Unreport for Spam"];
|
||||||
|
else
|
||||||
|
[menuItem setTitle:@"Report for Spam"];
|
||||||
|
return YES;
|
||||||
|
} else
|
||||||
|
return NO;
|
||||||
|
} else if (menuSelector==@selector(inboxMarkRead:)) {
|
||||||
|
if (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem]!=nil) {
|
||||||
|
if ([[[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem] objectForKey:MGMIRead] boolValue])
|
||||||
|
[menuItem setTitle:@"Mark Unread"];
|
||||||
|
else
|
||||||
|
[menuItem setTitle:@"Mark Read"];
|
||||||
|
return YES;
|
||||||
|
} else
|
||||||
|
return NO;
|
||||||
|
} else if (menuSelector==@selector(refreshInbox:)) {
|
||||||
|
return (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] inboxWindow]!=nil && [[NSApplication sharedApplication] keyWindow]==[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] inboxWindow]);
|
||||||
|
} else if (menuSelector==@selector(inboxDelete:)) {
|
||||||
|
return (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem]!=nil);
|
||||||
|
} else if (menuSelector==@selector(inboxUndelete:)) {
|
||||||
|
return (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] selectedItem]!=nil && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] currentInbox]==3);
|
||||||
|
} else if (menuSelector==@selector(saveAudio:)) {
|
||||||
|
return (currentContactsController!=-1 && [[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] && [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] audioURL]!=nil);
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)updateWindowMenu {
|
||||||
|
if (quitting)
|
||||||
|
return;
|
||||||
|
int splitterIndex = 0;
|
||||||
|
for (int i=0; i<[windowMenu numberOfItems]; i++) {
|
||||||
|
if (splitterIndex!=0) {
|
||||||
|
if ([[windowMenu itemAtIndex:i] isSeparatorItem])
|
||||||
|
break;
|
||||||
|
[windowMenu removeItemAtIndex:i];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if ([[[windowMenu itemAtIndex:i] title] isEqual:@"users"])
|
||||||
|
splitterIndex = i;
|
||||||
|
}
|
||||||
|
for (int i=[contactsControllers count]-1; i>=0; i--) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[[contactsControllers objectAtIndex:i] menuTitle]];
|
||||||
|
if (currentContactsController==i)
|
||||||
|
[item setState:NSOnState];
|
||||||
|
if (i<10)
|
||||||
|
[item setKeyEquivalent:[[NSNumber numberWithInt:i+1] stringValue]];
|
||||||
|
[item setTag:i];
|
||||||
|
[item setTarget:self];
|
||||||
|
[item setAction:@selector(showUserWindow:)];
|
||||||
|
[windowMenu insertItem:item atIndex:splitterIndex+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)showUserWindow:(id)sender {
|
||||||
|
MGMContactsController *contactsController = [contactsControllers objectAtIndex:[sender tag]];
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
|
||||||
|
NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
|
||||||
|
NSString *scheme = [[url scheme] lowercaseString];
|
||||||
|
NSString *data = [url resourceSpecifier];
|
||||||
|
/*NSString *queryData = [url query];
|
||||||
|
NSDictionary *query;
|
||||||
|
if (queryData) {
|
||||||
|
NSMutableArray *dataArr = [NSMutableArray arrayWithArray:[data componentsSeparatedByString:@"?"]];
|
||||||
|
[dataArr removeLastObject];
|
||||||
|
data = [dataArr componentsJoinedByString:@"?"];
|
||||||
|
NSMutableDictionary *dataDic = [NSMutableDictionary dictionary];
|
||||||
|
NSArray *parameters = [queryData componentsSeparatedByString:@"&"];
|
||||||
|
for (int i=0; i<[parameters count]; i++) {
|
||||||
|
NSArray *info = [[parameters objectAtIndex:i] componentsSeparatedByString:@"="];
|
||||||
|
[dataDic setObject:[[[info subarrayWithRange:NSMakeRange(1, [info count]-1)] componentsJoinedByString:@"="] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[info objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
}
|
||||||
|
query = [NSDictionary dictionaryWithDictionary:dataDic];
|
||||||
|
}*/
|
||||||
|
if ([data hasPrefix:@"//"]) {
|
||||||
|
data = [data substringFromIndex:2];
|
||||||
|
}
|
||||||
|
if ([scheme isEqualToString:@"tel"] || [scheme isEqualToString:@"callto"] || [scheme isEqualToString:@"telephone"] || [scheme isEqualToString:@"phone"] || [scheme isEqualToString:@"phonenumber"]) {
|
||||||
|
if (currentContactsController==-1)
|
||||||
|
return;
|
||||||
|
MGMContactsController *contactsController = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
NSString *phoneNumber = [data phoneFormatWithAreaCode:[contactsController areaCode]];
|
||||||
|
[[MGMNumberOptions alloc] initWithContactsController:contactsController controller:self number:phoneNumber]; // This is not a leak as I release it within it self. I just don't want to keep track of it in here.
|
||||||
|
} else if ([scheme isEqualToString:@"call"]) {
|
||||||
|
if (currentContactsController==-1)
|
||||||
|
return;
|
||||||
|
MGMContactsController *contactsController = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
NSString *phoneNumber = [data phoneFormatWithAreaCode:[contactsController areaCode]];
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
[[contactsController phoneField] setStringValue:[phoneNumber readableNumber]];
|
||||||
|
[self call:self];
|
||||||
|
} else if ([scheme isEqualToString:@"sms"]) {
|
||||||
|
if (currentContactsController==-1)
|
||||||
|
return;
|
||||||
|
MGMContactsController *contactsController = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
if (![contactsController respondsToSelector:@selector(sms:)]) return;
|
||||||
|
NSString *phoneNumber = [data phoneFormatWithAreaCode:[contactsController areaCode]];
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
[[contactsController phoneField] setStringValue:[phoneNumber readableNumber]];
|
||||||
|
[self sms:self];
|
||||||
|
} else if ([scheme isEqualToString:@"vmtheme"]) {
|
||||||
|
[taskManager addTask:nil withURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@", data]]];
|
||||||
|
} else if ([scheme isEqualToString:@"vmsound"]) {
|
||||||
|
[taskManager addTask:nil withURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@", data]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
|
||||||
|
[taskManager application:sender openFiles:filenames];
|
||||||
|
for (int i=0; i<[filenames count]; i++) {
|
||||||
|
if ([[[[filenames objectAtIndex:i] pathExtension] lowercaseString] isEqualToString:MGMVMTExt]) {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if ([manager respondsToSelector:@selector(movePath:toPath:handler:)])
|
||||||
|
[manager movePath:[filenames objectAtIndex:i] toPath:[[themeManager themesFolderPath] stringByAppendingPathComponent:[[filenames objectAtIndex:i] lastPathComponent]] handler:nil];
|
||||||
|
else
|
||||||
|
[manager moveItemAtPath:[filenames objectAtIndex:i] toPath:[[themeManager themesFolderPath] stringByAppendingPathComponent:[[filenames objectAtIndex:i] lastPathComponent]] error:nil];
|
||||||
|
} else if ([[[[filenames objectAtIndex:i] pathExtension] lowercaseString] isEqualToString:MGMVMSExt]) {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
if ([manager respondsToSelector:@selector(movePath:toPath:handler:)])
|
||||||
|
[manager movePath:[filenames objectAtIndex:i] toPath:[[themeManager soundsFolderPath] stringByAppendingPathComponent:[[filenames objectAtIndex:i] lastPathComponent]] handler:nil];
|
||||||
|
else
|
||||||
|
[manager moveItemAtPath:[filenames objectAtIndex:i] toPath:[[themeManager soundsFolderPath] stringByAppendingPathComponent:[[filenames objectAtIndex:i] lastPathComponent]] error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
|
||||||
|
if (!flag && currentContactsController!=-1)
|
||||||
|
[[contactsControllers objectAtIndex:currentContactsController] showContactsWindow];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)about:(id)sender {
|
||||||
|
MGMSystemInfo *sysInfo = [MGMSystemInfo info];
|
||||||
|
[aboutNameField setStringValue:[NSString stringWithFormat:@"%@ %@", [sysInfo applicationName], [sysInfo applicationVersion]]];
|
||||||
|
[aboutWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (IBAction)showTaskManager:(id)sender {
|
||||||
|
[taskManager showTaskManager:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)showInbox:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] showWindow:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)refreshInbox:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] loadInbox];
|
||||||
|
}
|
||||||
|
- (IBAction)inboxSpam:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] spam:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)inboxMarkRead:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] markRead:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)inboxDelete:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] delete:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)inboxUndelete:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] undelete:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userStarted:(NSNotification *)theNotification {
|
||||||
|
MGMUser *user = [theNotification object];
|
||||||
|
if ([[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleVoice]) {
|
||||||
|
[contactsControllers addObject:[MGMVoiceUser voiceUser:user controller:self]];
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
else if ([[user settingForKey:MGMSAccountType] isEqual:MGMSSIP]) {
|
||||||
|
if (![[MGMSIP sharedSIP] isStarted]) [[MGMSIP sharedSIP] start];
|
||||||
|
[contactsControllers addObject:[MGMSIPUser SIPUser:user controller:self]];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMContactsControllersChangedNotification object:self];
|
||||||
|
}
|
||||||
|
- (void)contactsControllerBecameCurrent:(MGMContactsController *)theContactsController {
|
||||||
|
if ([contactsControllers containsObject:theContactsController])
|
||||||
|
currentContactsController = [contactsControllers indexOfObject:theContactsController];
|
||||||
|
else
|
||||||
|
currentContactsController = [contactsControllers count];
|
||||||
|
[self updateWindowMenu];
|
||||||
|
}
|
||||||
|
- (void)userDone:(NSNotification *)theNotification {
|
||||||
|
for (int i=0; i<[contactsControllers count]; i++) {
|
||||||
|
if ([[contactsControllers objectAtIndex:i] isKindOfClass:[MGMVoiceUser class]]) {
|
||||||
|
MGMVoiceUser *voiceUser = [contactsControllers objectAtIndex:i];
|
||||||
|
if ([[voiceUser user] isEqual:[theNotification object]]) {
|
||||||
|
for (unsigned int i=0; i<[multipleSMS count]; i++) {
|
||||||
|
if ([[multipleSMS objectAtIndex:i] instance]==[voiceUser instance]) {
|
||||||
|
[[[multipleSMS objectAtIndex:i] SMSWindow] close];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned int i=0; i<[[SMSManager SMSMessages] count]; i++) {
|
||||||
|
if ([[[SMSManager SMSMessages] objectAtIndex:i] instance]==[voiceUser instance]) {
|
||||||
|
[SMSManager closeSMSMessage:[[SMSManager SMSMessages] objectAtIndex:i]];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self setBadge:0 forInstance:[voiceUser instance]];
|
||||||
|
|
||||||
|
currentContactsController = -1;
|
||||||
|
[contactsControllers removeObject:voiceUser];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMContactsControllersChangedNotification object:self];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
else if ([[contactsControllers objectAtIndex:i] isKindOfClass:[MGMSIPUser class]]) {
|
||||||
|
MGMSIPUser *SIPUser = [contactsControllers objectAtIndex:i];
|
||||||
|
if ([[SIPUser user] isEqual:[theNotification object]]) {
|
||||||
|
currentContactsController = -1;
|
||||||
|
[contactsControllers removeObject:SIPUser];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MGMContactsControllersChangedNotification object:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (NSString *)currentPhoneNumber {
|
||||||
|
NSString *phoneNumber = nil;
|
||||||
|
if ([[NSApplication sharedApplication] mainWindow]==[SMSManager SMSWindow])
|
||||||
|
phoneNumber = [SMSManager currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil && currentContactsController!=-1)
|
||||||
|
phoneNumber = [[contactsControllers objectAtIndex:currentContactsController] currentPhoneNumber];
|
||||||
|
return phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)preferences:(id)sender {
|
||||||
|
[preferences showPreferences];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)sendMultipleSMS:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(instance)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[multipleSMS addObject:[MGMMultiSMS SMSWithInstance:[[contactsControllers objectAtIndex:currentContactsController] instance] controller:self]];
|
||||||
|
}
|
||||||
|
- (void)removeMultiSMS:(MGMMultiSMS *)theMultiSMS {
|
||||||
|
[multipleSMS removeObject:theMultiSMS];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)saveAudio:(id)sender {
|
||||||
|
if (currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(inboxWindow)] || [[[contactsControllers objectAtIndex:currentContactsController] inboxWindow] audioURL]==nil) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MGMVoiceUser *voiceUser = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
NSURL *audioURL = [[voiceUser inboxWindow] audioURL];
|
||||||
|
NSDictionary *data = [[voiceUser inboxWindow] selectedItem];
|
||||||
|
[taskManager saveURL:audioURL withName:[NSString stringWithFormat:@"%@ (%@)", [[voiceUser contacts] nameForNumber:[data objectForKey:MGMIPhoneNumber]], [[data objectForKey:MGMIPhoneNumber] readableNumber]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)call:(id)sender {
|
||||||
|
NSString *phoneNumber = [self currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil || currentContactsController==-1) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MGMContactsController *contactsController = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
[[contactsController phoneField] setStringValue:[phoneNumber readableNumber]];
|
||||||
|
[contactsController call:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)sms:(id)sender {
|
||||||
|
NSString *phoneNumber = [self currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil || currentContactsController==-1 || ![[contactsControllers objectAtIndex:currentContactsController] respondsToSelector:@selector(sms:)]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MGMVoiceUser *voiceUser = [contactsControllers objectAtIndex:currentContactsController];
|
||||||
|
[voiceUser showContactsWindow];
|
||||||
|
[[voiceUser phoneField] setStringValue:[phoneNumber readableNumber]];
|
||||||
|
[voiceUser sms:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)reverseLookup:(id)sender {
|
||||||
|
NSString *phoneNumber = [self currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[whitePages reverseLookup:phoneNumber delegate:self];
|
||||||
|
[RLName setStringValue:MGMLoading];
|
||||||
|
[RLAddress setStringValue:MGMLoading];
|
||||||
|
[RLCityState setStringValue:MGMLoading];
|
||||||
|
[RLZipCode setStringValue:MGMLoading];
|
||||||
|
[RLPhoneNumber setStringValue:MGMLoading];
|
||||||
|
[RLWindow orderFront:self];
|
||||||
|
}
|
||||||
|
- (void)reverseLookup:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Reverse Lookup Failed"];
|
||||||
|
[alert setInformativeText:[theError localizedDescription]];
|
||||||
|
[alert runModal];
|
||||||
|
}
|
||||||
|
- (void)reverseLookupDidFindInfo:(NSDictionary *)theInfo forRequest:(NSDictionary *)theRequest {
|
||||||
|
if ([theInfo objectForKey:MGMWPName]) {
|
||||||
|
[RLName setStringValue:[theInfo objectForKey:MGMWPName]];
|
||||||
|
} else {
|
||||||
|
[RLName setStringValue:@""];
|
||||||
|
}
|
||||||
|
if ([theInfo objectForKey:MGMWPAddress]) {
|
||||||
|
[RLAddress setStringValue:[theInfo objectForKey:MGMWPAddress]];
|
||||||
|
} else {
|
||||||
|
[RLAddress setStringValue:@""];
|
||||||
|
}
|
||||||
|
if ([theInfo objectForKey:MGMWPLocation]) {
|
||||||
|
[RLCityState setStringValue:[theInfo objectForKey:MGMWPLocation]];
|
||||||
|
} else {
|
||||||
|
[RLCityState setStringValue:@""];
|
||||||
|
}
|
||||||
|
if ([theInfo objectForKey:MGMWPZip]) {
|
||||||
|
[RLZipCode setStringValue:[theInfo objectForKey:MGMWPZip]];
|
||||||
|
} else {
|
||||||
|
[RLZipCode setStringValue:@""];
|
||||||
|
}
|
||||||
|
if ([theInfo objectForKey:MGMWPPhoneNumber]) {
|
||||||
|
[RLPhoneNumber setStringValue:[[theInfo objectForKey:MGMWPPhoneNumber] readableNumber]];
|
||||||
|
} else {
|
||||||
|
[RLPhoneNumber setStringValue:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([theInfo objectForKey:MGMWPAddress]) {
|
||||||
|
[[RLMap windowScriptObject] callWebScriptMethod:@"showAddress" withArguments:[NSArray arrayWithObjects:[NSString stringWithFormat:@"%@, %@", [theInfo objectForKey:MGMWPAddress], [theInfo objectForKey:MGMWPZip]], [NSNumber numberWithInt:15], nil]];
|
||||||
|
} else if ([theInfo objectForKey:MGMWPZip]) {
|
||||||
|
[[RLMap windowScriptObject] callWebScriptMethod:@"showAddress" withArguments:[NSArray arrayWithObjects:[theInfo objectForKey:MGMWPZip], [NSNumber numberWithInt:13], nil]];
|
||||||
|
} else if ([theInfo objectForKey:MGMWPLocation]) {
|
||||||
|
[[RLMap windowScriptObject] callWebScriptMethod:@"showAddress" withArguments:[NSArray arrayWithObjects:[theInfo objectForKey:MGMWPLocation], [NSNumber numberWithInt:13], nil]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)donate:(id)sender {
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7693931"]];
|
||||||
|
}
|
||||||
|
- (IBAction)viewTOS:(id)sender {
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.google.com/googlevoice/legal-notices.html"]];
|
||||||
|
}
|
||||||
|
- (IBAction)rates:(id)sender {
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.google.com/support/voice/bin/answer.py?answer=141925"]];
|
||||||
|
}
|
||||||
|
- (IBAction)billing:(id)sender {
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.google.com/voice/#billing"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)SIPStopped {
|
||||||
|
if (quitting)
|
||||||
|
[[NSApplication sharedApplication] replyToApplicationShouldTerminate:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||||
|
NSApplicationTerminateReply response = [taskManager applicationShouldTerminate:sender];
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
if (response==NSTerminateNow) {
|
||||||
|
for (int i=0; i<[contactsControllers count]; i++) {
|
||||||
|
if ([[contactsControllers objectAtIndex:i] isKindOfClass:[MGMSIPUser class]]) {
|
||||||
|
MGMSIPUser *SIPUser = [contactsControllers objectAtIndex:i];
|
||||||
|
if ([[SIPUser calls] count]!=0) {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Calls in Progress"];
|
||||||
|
[alert setInformativeText:@"You appear to have calls in progress, are you sure you want to quit?"];
|
||||||
|
[alert addButtonWithTitle:@"Yes"];
|
||||||
|
[alert addButtonWithTitle:@"No"];
|
||||||
|
int result = [alert runModal];
|
||||||
|
if (result==1001)
|
||||||
|
response = NSTerminateCancel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (response==NSTerminateNow) {
|
||||||
|
quitting = YES;
|
||||||
|
[contactsControllers removeAllObjects];
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
if (response==NSTerminateNow) {
|
||||||
|
if ([[MGMSIP sharedSIP] isStarted]) {
|
||||||
|
[[MGMSIP sharedSIP] stop];
|
||||||
|
response = NSTerminateLater;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
@end
|
38
Classes/VoiceMac/MGMNumberOptions.h
Normal file
38
Classes/VoiceMac/MGMNumberOptions.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// MGMNumberOptions.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "MGMContactsController.h"
|
||||||
|
|
||||||
|
@class MGMController, MGMWhitePages;
|
||||||
|
|
||||||
|
@interface MGMContactsController (MGMSMS)
|
||||||
|
- (IBAction)sms:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMNumberOptions : NSObject {
|
||||||
|
MGMContactsController *contactsController;
|
||||||
|
MGMController *controller;
|
||||||
|
MGMWhitePages *whitePages;
|
||||||
|
IBOutlet NSWindow *optionsWindow;
|
||||||
|
IBOutlet NSTextField *phoneField;
|
||||||
|
IBOutlet NSTextField *nameField;
|
||||||
|
IBOutlet NSPopUpButton *accountPopUp;
|
||||||
|
IBOutlet NSButton *smsButton;
|
||||||
|
IBOutlet NSButton *callButton;
|
||||||
|
IBOutlet NSButton *cancelButton;
|
||||||
|
}
|
||||||
|
- (id)initWithContactsController:(MGMContactsController *)theContactsController controller:(MGMController *)theController number:(NSString *)theNumber;
|
||||||
|
|
||||||
|
- (void)updateAccounts;
|
||||||
|
- (IBAction)setAccount:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)call:(id)sender;
|
||||||
|
- (IBAction)sms:(id)sender;
|
||||||
|
- (IBAction)cancel:(id)sender;
|
||||||
|
@end
|
116
Classes/VoiceMac/MGMNumberOptions.m
Normal file
116
Classes/VoiceMac/MGMNumberOptions.m
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
//
|
||||||
|
// MGMNumberOptions.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMNumberOptions.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@implementation MGMNumberOptions
|
||||||
|
- (id)initWithContactsController:(MGMContactsController *)theContactsController controller:(MGMController *)theController number:(NSString *)theNumber {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"NumberOptions" owner:self]) {
|
||||||
|
NSLog(@"Unable to load the Number Options Window");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
contactsController = theContactsController;
|
||||||
|
controller = theController;
|
||||||
|
[phoneField setStringValue:[theNumber readableNumber]];
|
||||||
|
NSString *name = [[contactsController contacts] nameForNumber:theNumber];
|
||||||
|
if (name==nil || [name isEqual:[phoneField stringValue]]) {
|
||||||
|
whitePages = [MGMWhitePages new];
|
||||||
|
[whitePages reverseLookup:theNumber delegate:self];
|
||||||
|
[nameField setStringValue:@"Loading..."];
|
||||||
|
} else {
|
||||||
|
[nameField setStringValue:name];
|
||||||
|
}
|
||||||
|
if (![contactsController respondsToSelector:@selector(sms:)])
|
||||||
|
[smsButton setEnabled:NO];
|
||||||
|
|
||||||
|
[self updateAccounts];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAccounts) name:MGMContactsControllersChangedNotification object:nil];
|
||||||
|
|
||||||
|
[optionsWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (whitePages!=nil)
|
||||||
|
[whitePages release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateAccounts {
|
||||||
|
NSArray *contactsControllers = [controller contactsControllers];
|
||||||
|
NSMenu *accounts = [[NSMenu new] autorelease];
|
||||||
|
int currentAccount = -1;
|
||||||
|
for (int i=0; i<[contactsControllers count]; i++) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[[contactsControllers objectAtIndex:i] menuTitle]];
|
||||||
|
if ([contactsControllers objectAtIndex:i]==contactsController)
|
||||||
|
currentAccount = i;
|
||||||
|
if (i<10)
|
||||||
|
[item setKeyEquivalent:[[NSNumber numberWithInt:i+1] stringValue]];
|
||||||
|
[item setTag:i];
|
||||||
|
[item setTarget:self];
|
||||||
|
[item setAction:@selector(setAccount:)];
|
||||||
|
[accounts addItem:item];
|
||||||
|
}
|
||||||
|
if (currentAccount==-1) {
|
||||||
|
currentAccount = 0;
|
||||||
|
contactsController = [[controller contactsControllers] objectAtIndex:currentAccount];
|
||||||
|
if (![contactsController respondsToSelector:@selector(sms:)])
|
||||||
|
[smsButton setEnabled:NO];
|
||||||
|
else
|
||||||
|
[smsButton setEnabled:YES];
|
||||||
|
}
|
||||||
|
[accountPopUp setMenu:accounts];
|
||||||
|
[accountPopUp selectItemAtIndex:currentAccount];
|
||||||
|
}
|
||||||
|
- (IBAction)setAccount:(id)sender {
|
||||||
|
contactsController = [[controller contactsControllers] objectAtIndex:[sender tag]];
|
||||||
|
if (![contactsController respondsToSelector:@selector(sms:)])
|
||||||
|
[smsButton setEnabled:NO];
|
||||||
|
else
|
||||||
|
[smsButton setEnabled:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)call:(id)sender {
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
[[contactsController phoneField] setStringValue:[phoneField stringValue]];
|
||||||
|
[contactsController call:sender];
|
||||||
|
[self cancel:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)sms:(id)sender {
|
||||||
|
if ([contactsController respondsToSelector:@selector(sms:)]) {
|
||||||
|
[contactsController showContactsWindow];
|
||||||
|
[[contactsController phoneField] setStringValue:[phoneField stringValue]];
|
||||||
|
[contactsController sms:sender];
|
||||||
|
[self cancel:sender];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)cancel:(id)sender {
|
||||||
|
if (whitePages!=nil)
|
||||||
|
[whitePages cancelAll];
|
||||||
|
[optionsWindow close];
|
||||||
|
[self release];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseLookupDidFindInfo:(NSDictionary *)theInfo forRequest:(NSDictionary *)theRequest {
|
||||||
|
if ([theInfo objectForKey:MGMWPName]!=nil) {
|
||||||
|
[nameField setStringValue:[theInfo objectForKey:MGMWPName]];
|
||||||
|
} else if ([theInfo objectForKey:MGMWPLocation]!=nil) {
|
||||||
|
[nameField setStringValue:[theInfo objectForKey:MGMWPLocation]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
40
Classes/VoiceMac/MGMVMAddons.h
Normal file
40
Classes/VoiceMac/MGMVMAddons.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// MGMVMAddons.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
extern const float MGMHLKSRed;
|
||||||
|
extern const float MGMHLKSGreen;
|
||||||
|
extern const float MGMHLKSBlue;
|
||||||
|
extern const float MGMHLKERed;
|
||||||
|
extern const float MGMHLKEGreen;
|
||||||
|
extern const float MGMHLKEBlue;
|
||||||
|
|
||||||
|
extern const float MGMHLSRed;
|
||||||
|
extern const float MGMHLSGreen;
|
||||||
|
extern const float MGMHLSBlue;
|
||||||
|
extern const float MGMHLERed;
|
||||||
|
extern const float MGMHLEGreen;
|
||||||
|
extern const float MGMHLEBlue;
|
||||||
|
|
||||||
|
@interface NSBezierPath (MGMVMAddons)
|
||||||
|
+ (NSBezierPath *)pathWithRect:(NSRect)theRect radiusX:(float)theRadiusX radiusY:(float)theRadiusY;
|
||||||
|
- (void)fillGradientFrom:(NSColor *)theStartColor to:(NSColor *)theEndColor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSWorkspace (MGMVMAddons)
|
||||||
|
- (NSArray *)installedPhones;
|
||||||
|
- (NSString *)defaultPhoneIdentifier;
|
||||||
|
- (void)setDefaultPhoneWithIdentifier:(NSString*)bundleID;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSAttributedString (MGMVMAddons)
|
||||||
|
- (NSSize)sizeForWidth:(float)width height:(float)height;
|
||||||
|
- (float)heightForWidth:(float)width;
|
||||||
|
- (float)widthForHeight:(float)height;
|
||||||
|
@end
|
143
Classes/VoiceMac/MGMVMAddons.m
Normal file
143
Classes/VoiceMac/MGMVMAddons.m
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
//
|
||||||
|
// MGMVMAddons.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
const float MGMHLKSRed = 0.505882;
|
||||||
|
const float MGMHLKSGreen = 0.639215;
|
||||||
|
const float MGMHLKSBlue = 0.772549;
|
||||||
|
const float MGMHLKERed = 0.337254;
|
||||||
|
const float MGMHLKEGreen = 0.450980;
|
||||||
|
const float MGMHLKEBlue = 0.658823;
|
||||||
|
|
||||||
|
const float MGMHLSRed = 0.756862;
|
||||||
|
const float MGMHLSGreen = 0.756862;
|
||||||
|
const float MGMHLSBlue = 0.756862;
|
||||||
|
const float MGMHLERed = 0.607843;
|
||||||
|
const float MGMHLEGreen = 0.607843;
|
||||||
|
const float MGMHLEBlue = 0.607843;
|
||||||
|
|
||||||
|
@implementation NSBezierPath (MGMVMAddons)
|
||||||
|
+ (NSBezierPath *)pathWithRect:(NSRect)theRect radiusX:(float)theRadiusX radiusY:(float)theRadiusY {
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||||
|
|
||||||
|
float maxRadiusX = theRect.size.width / 2.0;
|
||||||
|
float maxRadiusY = theRect.size.height / 2.0;
|
||||||
|
theRadiusX = (theRadiusX<maxRadiusX ? theRadiusX : maxRadiusX);
|
||||||
|
theRadiusY = (theRadiusY<maxRadiusY ? theRadiusY : maxRadiusY);
|
||||||
|
float ellipse = 0.55228474983079;
|
||||||
|
float controlX = theRadiusX * ellipse;
|
||||||
|
float controlY = theRadiusY * ellipse;
|
||||||
|
NSRect edges = NSInsetRect(theRect, theRadiusX, theRadiusY);
|
||||||
|
|
||||||
|
// bottom right corner
|
||||||
|
[path moveToPoint:NSMakePoint(edges.origin.x, theRect.origin.y)];
|
||||||
|
[path lineToPoint:NSMakePoint(NSMaxX(edges), theRect.origin.y)];
|
||||||
|
[path curveToPoint:NSMakePoint(NSMaxX(theRect), edges.origin.y) controlPoint1:NSMakePoint(NSMaxX(edges) + controlX, theRect.origin.y) controlPoint2:NSMakePoint(NSMaxX(theRect), edges.origin.y - controlY)];
|
||||||
|
|
||||||
|
// top right corner
|
||||||
|
[path lineToPoint:NSMakePoint(NSMaxX(theRect), NSMaxY(edges))];
|
||||||
|
[path curveToPoint:NSMakePoint(NSMaxX(edges), NSMaxY(theRect)) controlPoint1:NSMakePoint(NSMaxX(theRect), NSMaxY(edges) + controlY) controlPoint2:NSMakePoint(NSMaxX(edges) + controlX, NSMaxY(theRect))];
|
||||||
|
|
||||||
|
// top left corner
|
||||||
|
[path lineToPoint:NSMakePoint(edges.origin.x, NSMaxY(theRect))];
|
||||||
|
[path curveToPoint:NSMakePoint(theRect.origin.x, NSMaxY(edges)) controlPoint1:NSMakePoint(edges.origin.x - controlX, NSMaxY(theRect)) controlPoint2:NSMakePoint(theRect.origin.x, NSMaxY(edges) + controlY)];
|
||||||
|
|
||||||
|
// bottom left corner
|
||||||
|
[path lineToPoint:NSMakePoint(theRect.origin.x, edges.origin.y)];
|
||||||
|
[path curveToPoint:NSMakePoint(edges.origin.x, theRect.origin.y) controlPoint1:NSMakePoint(theRect.origin.x, edges.origin.y - controlY) controlPoint2:NSMakePoint(edges.origin.x - controlX, theRect.origin.y)];
|
||||||
|
|
||||||
|
[path closePath];
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fillGradientFrom:(NSColor *)theStartColor to:(NSColor *)theEndColor {
|
||||||
|
CIFilter *filter = [CIFilter filterWithName:@"CILinearGradient"];
|
||||||
|
|
||||||
|
theStartColor = [theStartColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
|
||||||
|
theEndColor = [theEndColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
|
||||||
|
if (![[NSGraphicsContext currentContext] isFlipped]) {
|
||||||
|
NSColor *start = theStartColor;
|
||||||
|
NSColor *end = theEndColor;
|
||||||
|
theEndColor = start;
|
||||||
|
theStartColor = end;
|
||||||
|
}
|
||||||
|
CIColor *startColor = [CIColor colorWithRed:[theStartColor redComponent] green:[theStartColor greenComponent] blue:[theStartColor blueComponent] alpha:[theStartColor alphaComponent]];
|
||||||
|
CIColor *endColor = [CIColor colorWithRed:[theEndColor redComponent] green:[theEndColor greenComponent] blue:[theEndColor blueComponent] alpha:[theEndColor alphaComponent]];
|
||||||
|
[filter setValue:startColor forKey:@"inputColor0"];
|
||||||
|
[filter setValue:endColor forKey:@"inputColor1"];
|
||||||
|
|
||||||
|
CIVector *startVector = [CIVector vectorWithX:0.0 Y:0.0];
|
||||||
|
[filter setValue:startVector forKey:@"inputPoint0"];
|
||||||
|
CIVector *endVector = [CIVector vectorWithX:0.0 Y:[self bounds].size.height];
|
||||||
|
[filter setValue:endVector forKey:@"inputPoint1"];
|
||||||
|
|
||||||
|
CIImage *coreimage = [filter valueForKey:@"outputImage"];
|
||||||
|
|
||||||
|
[[NSGraphicsContext currentContext] saveGraphicsState];
|
||||||
|
|
||||||
|
[self setClip];
|
||||||
|
CIContext *context = [[NSGraphicsContext currentContext] CIContext];
|
||||||
|
[context drawImage:coreimage atPoint:CGPointMake([self bounds].origin.x, [self bounds].origin.y) fromRect:CGRectMake(0.0, 0.0, [self bounds].size.width, [self bounds].size.height)];
|
||||||
|
|
||||||
|
[[NSGraphicsContext currentContext] restoreGraphicsState];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSWorkspace (MGMVMAddons)
|
||||||
|
- (NSArray *)installedPhones {
|
||||||
|
NSArray *apps = [(NSArray *)LSCopyAllHandlersForURLScheme(CFSTR("tel")) autorelease];
|
||||||
|
|
||||||
|
NSString *defaultHandler = [self defaultPhoneIdentifier];
|
||||||
|
if (![apps indexOfObject:defaultHandler])
|
||||||
|
apps = [apps arrayByAddingObject:defaultHandler];
|
||||||
|
|
||||||
|
return apps;
|
||||||
|
}
|
||||||
|
- (NSString *)defaultPhoneIdentifier {
|
||||||
|
NSString *defaultBundleId = [(NSString *)LSCopyDefaultHandlerForURLScheme(CFSTR("tel")) autorelease];
|
||||||
|
if (!defaultBundleId)
|
||||||
|
defaultBundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||||
|
return defaultBundleId;
|
||||||
|
}
|
||||||
|
- (void)setDefaultPhoneWithIdentifier:(NSString*)bundleID {
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("tel"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("telephone"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("phone"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("phonenumber"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("call"), (CFStringRef)bundleID);
|
||||||
|
LSSetDefaultHandlerForURLScheme(CFSTR("sms"), (CFStringRef)bundleID);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSAttributedString (MGMVMAddons)
|
||||||
|
- (NSSize)sizeForWidth:(float)width height:(float)height {
|
||||||
|
NSSize size = NSZeroSize;
|
||||||
|
if ([self length]>0) {
|
||||||
|
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(width, height)];
|
||||||
|
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self];
|
||||||
|
NSLayoutManager *layoutManager = [NSLayoutManager new];
|
||||||
|
[layoutManager addTextContainer:textContainer];
|
||||||
|
[textStorage addLayoutManager:layoutManager];
|
||||||
|
[layoutManager setHyphenationFactor:0.0];
|
||||||
|
[layoutManager glyphRangeForTextContainer:textContainer];
|
||||||
|
size = [layoutManager usedRectForTextContainer:textContainer].size;
|
||||||
|
[textStorage release];
|
||||||
|
[textContainer release];
|
||||||
|
[layoutManager release];
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
- (float)heightForWidth:(float)width {
|
||||||
|
return [self sizeForWidth:width height:FLT_MAX].height;
|
||||||
|
}
|
||||||
|
- (float)widthForHeight:(float)height {
|
||||||
|
return [self sizeForWidth:FLT_MAX height:height].width;
|
||||||
|
}
|
||||||
|
@end
|
50
Classes/VoiceMac/MGMVoiceUser.h
Normal file
50
Classes/VoiceMac/MGMVoiceUser.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// MGMVoiceUser.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "MGMContactsController.h"
|
||||||
|
|
||||||
|
extern NSString *MGMLastUserPhoneKey;
|
||||||
|
|
||||||
|
@class MGMController, MGMUser, MGMInstance, MGMInboxWindow, MGMProgressView, MGMPhoneField, MGMPhoneFieldView, MGMContactsTableView;
|
||||||
|
|
||||||
|
@interface MGMVoiceUser : MGMContactsController {
|
||||||
|
MGMInstance *instance;
|
||||||
|
MGMUser *user;
|
||||||
|
MGMInboxWindow *inboxWindow;
|
||||||
|
|
||||||
|
MGMProgressView *progressView;
|
||||||
|
NSViewAnimation *progressFadeAnimation;
|
||||||
|
IBOutlet NSTextField *creditField;
|
||||||
|
IBOutlet NSButton *userNumberButton;
|
||||||
|
IBOutlet NSPopUpButton *userPhonesButton;
|
||||||
|
IBOutlet NSButton *callButton;
|
||||||
|
IBOutlet NSButton *smsButton;
|
||||||
|
|
||||||
|
BOOL placingCall;
|
||||||
|
NSTimer *callTimer;
|
||||||
|
}
|
||||||
|
+ (id)voiceUser:(MGMUser *)theUser controller:(MGMController *)theController;
|
||||||
|
+ (id)voiceUser:(MGMUser *)theUser controller:(MGMController *)theController instance:(MGMInstance *)theInstance;
|
||||||
|
- (id)initUser:(MGMUser *)theUser controller:(MGMController *)theController instance:(MGMInstance *)theInstance;
|
||||||
|
|
||||||
|
- (void)registerSettings;
|
||||||
|
|
||||||
|
- (MGMInstance *)instance;
|
||||||
|
- (MGMUser *)user;
|
||||||
|
- (MGMInboxWindow *)inboxWindow;
|
||||||
|
|
||||||
|
- (void)loginSuccessful;
|
||||||
|
- (void)setInstanceInfo;
|
||||||
|
|
||||||
|
- (BOOL)isPlacingCall;
|
||||||
|
|
||||||
|
- (IBAction)sms:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)viewSettings:(id)sender;
|
||||||
|
@end
|
310
Classes/VoiceMac/MGMVoiceUser.m
Normal file
310
Classes/VoiceMac/MGMVoiceUser.m
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
//
|
||||||
|
// MGMVoiceUser.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMProgressView.h"
|
||||||
|
#import "MGMContactView.h"
|
||||||
|
#import "MGMPhoneFeild.h"
|
||||||
|
#import "MGMSMSManager.h"
|
||||||
|
#import "MGMInboxWindow.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString *MGMLastUserPhoneKey = @"MGMLastUserPhone";
|
||||||
|
|
||||||
|
@implementation MGMVoiceUser
|
||||||
|
+ (id)voiceUser:(MGMUser *)theUser controller:(MGMController *)theController {
|
||||||
|
return [[[self alloc] initUser:theUser controller:theController instance:nil] autorelease];
|
||||||
|
}
|
||||||
|
+ (id)voiceUser:(MGMUser *)theUser controller:(MGMController *)theController instance:(MGMInstance *)theInstance {
|
||||||
|
return [[[self alloc] initUser:theUser controller:theController instance:theInstance] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initUser:(MGMUser *)theUser controller:(MGMController *)theController instance:(MGMInstance *)theInstance {
|
||||||
|
if (self = [super initWithController:theController]) {
|
||||||
|
user = [theUser retain];
|
||||||
|
[self registerSettings];
|
||||||
|
if (theInstance==nil) {
|
||||||
|
instance = [[MGMInstance instanceWithUser:user delegate:self] retain];
|
||||||
|
} else {
|
||||||
|
instance = [theInstance retain];
|
||||||
|
[instance setDelegate:self];
|
||||||
|
if ([instance isLoggedIn])
|
||||||
|
[self loginSuccessful];
|
||||||
|
}
|
||||||
|
inboxWindow = [[MGMInboxWindow windowWithInstance:instance] retain];
|
||||||
|
if ([[user settingForKey:MGMContactsWindowOpen] boolValue])
|
||||||
|
[self showContactsWindow];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
[contactsWindow setFrameAutosaveName:[@"contactsWindow" stringByAppendingString:[user settingForKey:MGMUserID]]];
|
||||||
|
|
||||||
|
if (![instance isLoggedIn]) {
|
||||||
|
NSSize contentSize = [[contactsWindow contentView] frame].size;
|
||||||
|
progressView = [[MGMProgressView alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)];
|
||||||
|
[progressView setProgressTitle:@"Logging In"];
|
||||||
|
[[contactsWindow contentView] addSubview:progressView];
|
||||||
|
[progressView startProgess];
|
||||||
|
[contactsWindow makeFirstResponder:progressView];
|
||||||
|
} else {
|
||||||
|
[self setInstanceInfo];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[super dealloc];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (user!=nil)
|
||||||
|
[user release];
|
||||||
|
if (instance!=nil) {
|
||||||
|
[instance stop];
|
||||||
|
[instance release];
|
||||||
|
}
|
||||||
|
if (inboxWindow!=nil) {
|
||||||
|
[inboxWindow closeWindow];
|
||||||
|
[inboxWindow release];
|
||||||
|
}
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView removeFromSuperview];
|
||||||
|
[progressView release];
|
||||||
|
}
|
||||||
|
if (callTimer!=nil) {
|
||||||
|
[callTimer invalidate];
|
||||||
|
[callTimer release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerSettings {
|
||||||
|
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
|
||||||
|
[settings setObject:[NSNumber numberWithInt:0] forKey:MGMLastUserPhoneKey];
|
||||||
|
[settings setObject:[NSNumber numberWithBool:YES] forKey:MGMContactsWindowOpen];
|
||||||
|
[user registerSettings:settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)menuTitle {
|
||||||
|
return [user settingForKey:MGMUserName];
|
||||||
|
}
|
||||||
|
- (void)showContactsWindow {
|
||||||
|
if (contactsWindow==nil) {
|
||||||
|
if (![NSBundle loadNibNamed:@"VoiceUser" owner:self]) {
|
||||||
|
NSLog(@"Error: Unable to load Voice User!");
|
||||||
|
} else {
|
||||||
|
[user setSetting:[NSNumber numberWithBool:YES] forKey:MGMContactsWindowOpen];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contactsWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (MGMInstance *)instance {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
- (MGMUser *)user {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
- (MGMInboxWindow *)inboxWindow {
|
||||||
|
return inboxWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loginError:(NSError *)theError {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error logging in"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView stopProgess];
|
||||||
|
[progressView removeFromSuperview];
|
||||||
|
[progressView release];
|
||||||
|
progressView = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)loginSuccessful {
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView stopProgess];
|
||||||
|
[progressView display];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setInstanceInfo];
|
||||||
|
|
||||||
|
if (progressView!=nil) {
|
||||||
|
NSMutableDictionary *animationInfo = [NSMutableDictionary dictionary];
|
||||||
|
[animationInfo setObject:progressView forKey:NSViewAnimationTargetKey];
|
||||||
|
[animationInfo setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
|
||||||
|
progressFadeAnimation = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:animationInfo]];
|
||||||
|
[progressFadeAnimation setDuration:1.0];
|
||||||
|
[progressFadeAnimation setDelegate:self];
|
||||||
|
[progressFadeAnimation startAnimation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)setInstanceInfo {
|
||||||
|
if (contactsWindow==nil) return;
|
||||||
|
if ([instance isLoggedIn]) {
|
||||||
|
[userNumberButton setTitle:[[instance userNumber] readableNumber]];
|
||||||
|
[userPhonesButton removeAllItems];
|
||||||
|
NSArray *phones = [instance userPhoneNumbers];
|
||||||
|
for (int i=0; i<[phones count]; i++) {
|
||||||
|
NSDictionary *phone = [phones objectAtIndex:i];
|
||||||
|
[userPhonesButton addItemWithTitle:[NSString stringWithFormat:@"%@ [%@]", [[phone objectForKey:MGMPhoneNumber] readableNumber], [phone objectForKey:MGMName]]];
|
||||||
|
[userPhonesButton selectItemAtIndex:0];
|
||||||
|
}
|
||||||
|
[userPhonesButton selectItemAtIndex:[[user settingForKey:MGMLastUserPhoneKey] intValue]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)animationDidEnd:(NSAnimation *)animation {
|
||||||
|
if (progressFadeAnimation!=nil) {
|
||||||
|
[progressFadeAnimation release];
|
||||||
|
progressFadeAnimation = nil;
|
||||||
|
}
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView removeFromSuperview];
|
||||||
|
[progressView release];
|
||||||
|
progressView = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMContacts *)contacts {
|
||||||
|
return [instance contacts];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadData {
|
||||||
|
[super reloadData];
|
||||||
|
if (progressView!=nil) [progressView display];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)areaCode {
|
||||||
|
if (![instance isLoggedIn])
|
||||||
|
return nil;
|
||||||
|
return [instance userAreaCode];
|
||||||
|
}
|
||||||
|
- (NSString *)currentPhoneNumber {
|
||||||
|
NSString *phoneNumber = nil;
|
||||||
|
if ([[NSApplication sharedApplication] mainWindow]==[inboxWindow inboxWindow])
|
||||||
|
phoneNumber = [inboxWindow currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil)
|
||||||
|
phoneNumber = [super currentPhoneNumber];
|
||||||
|
return phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isPlacingCall {
|
||||||
|
return (callTimer!=nil);
|
||||||
|
}
|
||||||
|
- (IBAction)runAction:(id)sender {
|
||||||
|
if ([[user settingForKey:MGMSContactsActionKey] intValue]==0) {
|
||||||
|
[self call:sender];
|
||||||
|
} else {
|
||||||
|
[self sms:sender];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)call:(id)sender {
|
||||||
|
if (callTimer!=nil) {
|
||||||
|
[callTimer invalidate];
|
||||||
|
[callTimer release];
|
||||||
|
callTimer = nil;
|
||||||
|
if (placingCall)
|
||||||
|
[[instance connectionManager] cancelAll];
|
||||||
|
[callButton setImage:[NSImage imageNamed:@"placeCall"]];
|
||||||
|
[instance cancelCallWithDelegate:self];
|
||||||
|
} else {
|
||||||
|
if ([userPhonesButton indexOfSelectedItem]==-1) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *phoneNumber = [controller currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil || [phoneNumber isEqual:@""]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[user setSetting:[NSNumber numberWithInt:[userPhonesButton indexOfSelectedItem]] forKey:MGMLastUserPhoneKey];
|
||||||
|
|
||||||
|
placingCall = YES;
|
||||||
|
[callButton setImage:[NSImage imageNamed:@"cancelCall"]];
|
||||||
|
callTimer = [[NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(callTimer) userInfo:nil repeats:NO] retain];
|
||||||
|
[instance placeCall:phoneNumber usingPhone:[userPhonesButton indexOfSelectedItem] delegate:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)call:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Call Failed"];
|
||||||
|
[alert setInformativeText:[theError localizedDescription]];
|
||||||
|
[alert runModal];
|
||||||
|
placingCall = NO;
|
||||||
|
if (callTimer!=nil)
|
||||||
|
[callTimer fire];
|
||||||
|
}
|
||||||
|
- (void)callDidFinish:(NSDictionary *)theInfo {
|
||||||
|
placingCall = NO;
|
||||||
|
NSLog(@"YEA! We Made The Call!");
|
||||||
|
}
|
||||||
|
- (void)callCancel:(NSDictionary *)theInfo didFailWithError:(NSError *)theError {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Call Cancel Failed"];
|
||||||
|
[alert setInformativeText:[theError localizedDescription]];
|
||||||
|
[alert runModal];
|
||||||
|
}
|
||||||
|
- (void)callTimer {
|
||||||
|
if (callTimer!=nil) {
|
||||||
|
[callTimer invalidate];
|
||||||
|
[callTimer release];
|
||||||
|
callTimer = nil;
|
||||||
|
}
|
||||||
|
[callButton setImage:[NSImage imageNamed:@"placeCall"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)sms:(id)sender {
|
||||||
|
NSString *phoneNumber = nil;
|
||||||
|
if (![[phoneField stringValue] isPhoneComplete]) {
|
||||||
|
if ([contactViews count]>0) {
|
||||||
|
[self selectFirstContact];
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
NSBeep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (phoneNumber==nil)
|
||||||
|
phoneNumber = [[phoneField stringValue] phoneFormatWithAreaCode:[instance userAreaCode]];
|
||||||
|
|
||||||
|
[[controller SMSManager] messageWithNumber:phoneNumber instance:instance];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateUnreadCount:(int)theCount {
|
||||||
|
[controller setBadge:theCount forInstance:instance];
|
||||||
|
}
|
||||||
|
- (void)updateVoicemail {
|
||||||
|
[inboxWindow checkVoicemail];
|
||||||
|
}
|
||||||
|
- (void)updateSMS {
|
||||||
|
[[controller SMSManager] checkSMSMessagesForInstance:instance];
|
||||||
|
}
|
||||||
|
- (void)updateCredit:(NSString *)credit {
|
||||||
|
[creditField setStringValue:credit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)viewSettings:(id)sender {
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.google.com/voice/#phones"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
if (![controller isQuitting])
|
||||||
|
[user setSetting:[NSNumber numberWithBool:NO] forKey:MGMContactsWindowOpen];
|
||||||
|
[super windowWillClose:notification];
|
||||||
|
if (progressFadeAnimation!=nil) {
|
||||||
|
[progressFadeAnimation stopAnimation];
|
||||||
|
[progressFadeAnimation release];
|
||||||
|
progressFadeAnimation = nil;
|
||||||
|
}
|
||||||
|
creditField = nil;
|
||||||
|
userNumberButton = nil;
|
||||||
|
userPhonesButton = nil;
|
||||||
|
callButton = nil;
|
||||||
|
smsButton = nil;
|
||||||
|
}
|
||||||
|
@end
|
66
Classes/VoiceMac/Preferences/MGMAccountsPane.h
Normal file
66
Classes/VoiceMac/Preferences/MGMAccountsPane.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// MGMAccountsPane.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/21/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@class MGMInstance;
|
||||||
|
|
||||||
|
@interface MGMAccountsPane : MGMPreferencesPane {
|
||||||
|
IBOutlet NSView *mainView;
|
||||||
|
IBOutlet NSTabView *settingsTab;
|
||||||
|
|
||||||
|
MGMInstance *checkInstance;
|
||||||
|
|
||||||
|
IBOutlet NSTableView *usersTable;
|
||||||
|
IBOutlet NSButton *loginoutButton;
|
||||||
|
IBOutlet NSButton *addButton;
|
||||||
|
IBOutlet NSButton *removeButton;
|
||||||
|
|
||||||
|
//Google Voice Settings
|
||||||
|
IBOutlet NSMatrix *GVContactsMatrix;
|
||||||
|
IBOutlet NSPopUpButton *GVGoogleContactsPopUp;
|
||||||
|
IBOutlet NSMatrix *GVActionMatrix;
|
||||||
|
IBOutlet NSTextField *GVUserNameField;
|
||||||
|
IBOutlet NSTextField *GVPasswordField;
|
||||||
|
|
||||||
|
//Google Contacts Settings
|
||||||
|
IBOutlet NSTextField *GCUserNameField;
|
||||||
|
IBOutlet NSTextField *GCPasswordField;
|
||||||
|
|
||||||
|
//Session Initiation Protocol Settings
|
||||||
|
IBOutlet NSTextField *SIPFullNameField;
|
||||||
|
IBOutlet NSTextField *SIPDomainField;
|
||||||
|
IBOutlet NSTextField *SIPRegistrarField;
|
||||||
|
IBOutlet NSTextField *SIPUserNameField;
|
||||||
|
IBOutlet NSTextField *SIPPasswordField;
|
||||||
|
IBOutlet NSTextField *SIPAreaCodeField;
|
||||||
|
IBOutlet NSTextField *SIPProxyHostField;
|
||||||
|
IBOutlet NSTextField *SIPProxyPortField;
|
||||||
|
IBOutlet NSTextField *SIPSIPAddressField;
|
||||||
|
IBOutlet NSTextField *SIPRegistrarTimeoutField;
|
||||||
|
IBOutlet NSMatrix *SIPContactsMatrix;
|
||||||
|
IBOutlet NSPopUpButton *SIPGoogleContactsPopUp;
|
||||||
|
}
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
|
||||||
|
+ (NSString *)title;
|
||||||
|
- (NSView *)preferencesView;
|
||||||
|
|
||||||
|
- (IBAction)loginout:(id)sender;
|
||||||
|
- (IBAction)add:(id)sender;
|
||||||
|
- (IBAction)remove:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)saveGV:(id)sender;
|
||||||
|
- (IBAction)saveGC:(id)sender;
|
||||||
|
- (IBAction)saveSIP:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)saveContacts:(id)sender;
|
||||||
|
- (IBAction)saveGoogleContactsUser:(id)sender;
|
||||||
|
- (IBAction)saveAction:(id)sender;
|
||||||
|
@end
|
419
Classes/VoiceMac/Preferences/MGMAccountsPane.m
Normal file
419
Classes/VoiceMac/Preferences/MGMAccountsPane.m
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
//
|
||||||
|
// MGMAccountsPane.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/21/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMAccountsPane.h"
|
||||||
|
#import "MGMAccountSetup.h"
|
||||||
|
#import "MGMContactsController.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
NSString * const MGMLogin = @"Login";
|
||||||
|
NSString * const MGMLogout = @"Logout";
|
||||||
|
|
||||||
|
@implementation MGMAccountsPane
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
|
||||||
|
if (self = [super initWithPreferences:thePreferences]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"AccountsPane" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Nib for Account Preferences");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:usersTable selector:@selector(reloadData) name:MGMUserStartNotification object:nil];
|
||||||
|
[notificationCenter addObserver:usersTable selector:@selector(reloadData) name:MGMUserDoneNotification object:nil];
|
||||||
|
[usersTable setTarget:self];
|
||||||
|
[usersTable setDoubleAction:@selector(loginout:)];
|
||||||
|
[loginoutButton setEnabled:NO];
|
||||||
|
[removeButton setEnabled:NO];
|
||||||
|
[GVContactsMatrix setEnabled:NO];
|
||||||
|
[GVGoogleContactsPopUp setEnabled:NO];
|
||||||
|
[GVActionMatrix setEnabled:NO];
|
||||||
|
[GVUserNameField setEnabled:NO];
|
||||||
|
[GVPasswordField setEnabled:NO];
|
||||||
|
[GCUserNameField setEnabled:NO];
|
||||||
|
[GCPasswordField setEnabled:NO];
|
||||||
|
[SIPFullNameField setEnabled:NO];
|
||||||
|
[SIPDomainField setEnabled:NO];
|
||||||
|
[SIPRegistrarField setEnabled:NO];
|
||||||
|
[SIPUserNameField setEnabled:NO];
|
||||||
|
[SIPPasswordField setEnabled:NO];
|
||||||
|
[SIPAreaCodeField setEnabled:NO];
|
||||||
|
[SIPProxyHostField setEnabled:NO];
|
||||||
|
[SIPProxyPortField setEnabled:NO];
|
||||||
|
[SIPSIPAddressField setEnabled:NO];
|
||||||
|
[SIPRegistrarTimeoutField setEnabled:NO];
|
||||||
|
[SIPContactsMatrix setEnabled:NO];
|
||||||
|
[SIPGoogleContactsPopUp setEnabled:NO];
|
||||||
|
[settingsTab selectTabViewItemAtIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:usersTable];
|
||||||
|
if (checkInstance!=nil)
|
||||||
|
[checkInstance release];
|
||||||
|
if (mainView!=nil)
|
||||||
|
[mainView release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
|
||||||
|
[theItem setLabel:[self title]];
|
||||||
|
[theItem setPaletteLabel:[theItem label]];
|
||||||
|
[theItem setImage:[NSImage imageNamed:@"Accounts"]];
|
||||||
|
}
|
||||||
|
+ (NSString *)title {
|
||||||
|
return @"Accounts";
|
||||||
|
}
|
||||||
|
- (NSView *)preferencesView {
|
||||||
|
return mainView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||||
|
return [[MGMUser userNames] count];
|
||||||
|
}
|
||||||
|
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||||
|
if ([[tableColumn identifier] isEqual:@"username"]) {
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:row]];
|
||||||
|
if ([[user settingForKey:MGMSAccountType] isEqual:MGMSSIP]) {
|
||||||
|
if ([user settingForKey:MGMSIPAccountFullName]!=nil && ![[user settingForKey:MGMSIPAccountFullName] isEqual:@""])
|
||||||
|
return [user settingForKey:MGMSIPAccountFullName];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return [[MGMUser userNames] objectAtIndex:row];
|
||||||
|
} else if ([[tableColumn identifier] isEqual:@"state"]) {
|
||||||
|
NSDictionary *users = [MGMUser usersPlist];
|
||||||
|
return ([[users objectForKey:[[users allKeys] objectAtIndex:row]] boolValue] ? @"✓" : @"");
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)loginout:(id)sender {
|
||||||
|
if ([usersTable selectedRow]==-1) return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:[usersTable selectedRow]]];
|
||||||
|
if ([[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts])
|
||||||
|
return;
|
||||||
|
if ([user isStarted]) {
|
||||||
|
[user done];
|
||||||
|
[user setSetting:[NSNumber numberWithBool:YES] forKey:MGMContactsWindowOpen];
|
||||||
|
[loginoutButton setTitle:MGMLogin];
|
||||||
|
} else {
|
||||||
|
[user start];
|
||||||
|
[loginoutButton setTitle:MGMLogout];
|
||||||
|
}
|
||||||
|
[usersTable reloadData];
|
||||||
|
[self tableViewSelectionDidChange:nil];
|
||||||
|
}
|
||||||
|
- (IBAction)add:(id)sender {
|
||||||
|
[[MGMAccountSetup new] attachToWindow:[preferences preferencesWindow]]; // The Account Setup will automatically release it self when user is done.
|
||||||
|
}
|
||||||
|
- (IBAction)remove:(id)sender {
|
||||||
|
if ([usersTable selectedRow]==-1) return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:[usersTable selectedRow]]];
|
||||||
|
if ([user isStarted]) {
|
||||||
|
[user done];
|
||||||
|
if ([user isStarted])
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[user remove];
|
||||||
|
[usersTable reloadData];
|
||||||
|
[self tableViewSelectionDidChange:nil];
|
||||||
|
}
|
||||||
|
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
|
||||||
|
int selected = [usersTable selectedRow];
|
||||||
|
[loginoutButton setEnabled:NO];
|
||||||
|
[removeButton setEnabled:NO];
|
||||||
|
[GVContactsMatrix setEnabled:NO];
|
||||||
|
[GVGoogleContactsPopUp setEnabled:NO];
|
||||||
|
[GVActionMatrix setEnabled:NO];
|
||||||
|
[GVUserNameField setEnabled:NO];
|
||||||
|
[GVPasswordField setEnabled:NO];
|
||||||
|
[GCUserNameField setEnabled:NO];
|
||||||
|
[GCPasswordField setEnabled:NO];
|
||||||
|
[SIPFullNameField setEnabled:NO];
|
||||||
|
[SIPDomainField setEnabled:NO];
|
||||||
|
[SIPRegistrarField setEnabled:NO];
|
||||||
|
[SIPUserNameField setEnabled:NO];
|
||||||
|
[SIPPasswordField setEnabled:NO];
|
||||||
|
[SIPAreaCodeField setEnabled:NO];
|
||||||
|
[SIPProxyHostField setEnabled:NO];
|
||||||
|
[SIPProxyPortField setEnabled:NO];
|
||||||
|
[SIPSIPAddressField setEnabled:NO];
|
||||||
|
[SIPRegistrarTimeoutField setEnabled:NO];
|
||||||
|
[SIPContactsMatrix setEnabled:NO];
|
||||||
|
[SIPGoogleContactsPopUp setEnabled:NO];
|
||||||
|
if (selected==-1)
|
||||||
|
return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:selected]];
|
||||||
|
if ([user isStarted])
|
||||||
|
[loginoutButton setTitle:MGMLogout];
|
||||||
|
else
|
||||||
|
[loginoutButton setTitle:MGMLogin];
|
||||||
|
if (![[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts])
|
||||||
|
[loginoutButton setEnabled:YES];
|
||||||
|
else
|
||||||
|
[loginoutButton setEnabled:NO];
|
||||||
|
[removeButton setEnabled:YES];
|
||||||
|
if ([[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleVoice]) {
|
||||||
|
[settingsTab selectTabViewItemAtIndex:0];
|
||||||
|
|
||||||
|
NSArray *users = [MGMUser users];
|
||||||
|
NSMenu *menu = [[NSMenu new] autorelease];
|
||||||
|
|
||||||
|
int selectedGC = 0;
|
||||||
|
int cCount = 0;
|
||||||
|
for (int i=0; i<[users count]; i++) {
|
||||||
|
MGMUser *gcUser = [MGMUser userWithID:[users objectAtIndex:i]];
|
||||||
|
if ([[gcUser settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts]) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[gcUser settingForKey:MGMUserName]];
|
||||||
|
[item setRepresentedObject:[gcUser settingForKey:MGMUserID]];
|
||||||
|
if ([[user settingForKey:MGMCGoogleContactsUser] isEqual:[gcUser settingForKey:MGMUserID]])
|
||||||
|
selectedGC = cCount;
|
||||||
|
[menu addItem:item];
|
||||||
|
cCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSString *contactsSource = [user settingForKey:MGMSContactsSourceKey];
|
||||||
|
if ([contactsSource isEqual:NSStringFromClass([MGMAddressBook class])]) {
|
||||||
|
[GVContactsMatrix selectCellAtRow:0 column:0];
|
||||||
|
[GVGoogleContactsPopUp setEnabled:NO];
|
||||||
|
} else if ([contactsSource isEqual:NSStringFromClass([MGMGoogleContacts class])]) {
|
||||||
|
if (cCount!=0) {
|
||||||
|
[GVContactsMatrix selectCellAtRow:1 column:0];
|
||||||
|
[GVGoogleContactsPopUp setEnabled:YES];
|
||||||
|
} else {
|
||||||
|
[user setSetting:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[GVContactsMatrix selectCellAtRow:0 column:0];
|
||||||
|
[GVGoogleContactsPopUp setEnabled:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[GVContactsMatrix setEnabled:YES];
|
||||||
|
[GVGoogleContactsPopUp setMenu:menu];
|
||||||
|
[GVGoogleContactsPopUp selectItemAtIndex:selectedGC];
|
||||||
|
if ([[GVGoogleContactsPopUp selectedItem] representedObject]!=nil)
|
||||||
|
[user setSetting:[[GVGoogleContactsPopUp selectedItem] representedObject] forKey:MGMCGoogleContactsUser];
|
||||||
|
|
||||||
|
[GVActionMatrix setEnabled:YES];
|
||||||
|
[GVActionMatrix selectCellAtRow:[[user settingForKey:MGMSContactsActionKey] intValue] column:0];
|
||||||
|
|
||||||
|
if (![user isStarted]) {
|
||||||
|
[GVUserNameField setEnabled:YES];
|
||||||
|
[GVPasswordField setEnabled:YES];
|
||||||
|
}
|
||||||
|
[GVUserNameField setStringValue:[user settingForKey:MGMUserName]];
|
||||||
|
[GVPasswordField setStringValue:[user password]];
|
||||||
|
} else if ([[user settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts]) {
|
||||||
|
[settingsTab selectTabViewItemAtIndex:1];
|
||||||
|
|
||||||
|
if (![user isStarted]) {
|
||||||
|
[GCUserNameField setEnabled:YES];
|
||||||
|
[GCPasswordField setEnabled:YES];
|
||||||
|
}
|
||||||
|
[GCUserNameField setStringValue:[user settingForKey:MGMUserName]];
|
||||||
|
[GCPasswordField setStringValue:[user password]];
|
||||||
|
}
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
else if ([[user settingForKey:MGMSAccountType] isEqual:MGMSSIP]) {
|
||||||
|
[settingsTab selectTabViewItemAtIndex:2];
|
||||||
|
if (![user isStarted]) {
|
||||||
|
[SIPFullNameField setEnabled:YES];
|
||||||
|
[SIPDomainField setEnabled:YES];
|
||||||
|
[SIPRegistrarField setEnabled:YES];
|
||||||
|
[SIPUserNameField setEnabled:YES];
|
||||||
|
[SIPPasswordField setEnabled:YES];
|
||||||
|
[SIPAreaCodeField setEnabled:YES];
|
||||||
|
[SIPProxyHostField setEnabled:YES];
|
||||||
|
[SIPProxyPortField setEnabled:YES];
|
||||||
|
[SIPSIPAddressField setEnabled:YES];
|
||||||
|
[SIPRegistrarTimeoutField setEnabled:YES];
|
||||||
|
}
|
||||||
|
if ([user settingForKey:MGMSIPAccountFullName]!=nil)
|
||||||
|
[SIPFullNameField setStringValue:[user settingForKey:MGMSIPAccountFullName]];
|
||||||
|
else
|
||||||
|
[SIPFullNameField setStringValue:@""];
|
||||||
|
if ([user settingForKey:MGMSIPAccountDomain]==nil || [[user settingForKey:MGMSIPAccountDomain] isEqual:@""]) {
|
||||||
|
[[SIPRegistrarField cell] setPlaceholderString:MGMSIPDefaultDomain];
|
||||||
|
[SIPDomainField setStringValue:@""];
|
||||||
|
} else {
|
||||||
|
[[SIPRegistrarField cell] setPlaceholderString:[user settingForKey:MGMSIPAccountDomain]];
|
||||||
|
[SIPDomainField setStringValue:[user settingForKey:MGMSIPAccountDomain]];
|
||||||
|
}
|
||||||
|
if ([user settingForKey:MGMSIPAccountRegistrar]!=nil)
|
||||||
|
[SIPRegistrarField setStringValue:[user settingForKey:MGMSIPAccountRegistrar]];
|
||||||
|
else
|
||||||
|
[SIPRegistrarField setStringValue:@""];
|
||||||
|
if ([user settingForKey:MGMSIPAccountUserName]!=nil)
|
||||||
|
[SIPUserNameField setStringValue:[user settingForKey:MGMSIPAccountUserName]];
|
||||||
|
else
|
||||||
|
[SIPUserNameField setStringValue:@""];
|
||||||
|
[SIPPasswordField setStringValue:[user password]];
|
||||||
|
if ([user settingForKey:MGMSIPUserAreaCode]!=nil)
|
||||||
|
[SIPAreaCodeField setStringValue:[user settingForKey:MGMSIPUserAreaCode]];
|
||||||
|
else
|
||||||
|
[SIPAreaCodeField setStringValue:@""];
|
||||||
|
if ([user settingForKey:MGMSIPAccountProxy]!=nil)
|
||||||
|
[SIPProxyHostField setStringValue:[user settingForKey:MGMSIPAccountProxy]];
|
||||||
|
else
|
||||||
|
[SIPProxyHostField setStringValue:@""];
|
||||||
|
if ([user settingForKey:MGMSIPAccountProxyPort]!=nil && [[user settingForKey:MGMSIPAccountProxyPort] intValue]!=0)
|
||||||
|
[SIPProxyPortField setIntValue:[[user settingForKey:MGMSIPAccountProxyPort] intValue]];
|
||||||
|
else
|
||||||
|
[SIPProxyPortField setStringValue:@""];
|
||||||
|
if ([user settingForKey:MGMSIPAccountSIPAddress]!=nil)
|
||||||
|
[SIPSIPAddressField setStringValue:[user settingForKey:MGMSIPAccountSIPAddress]];
|
||||||
|
else
|
||||||
|
[SIPSIPAddressField setStringValue:@""];
|
||||||
|
[[SIPSIPAddressField cell] setPlaceholderString:[NSString stringWithFormat:@"%@@%@", [user settingForKey:MGMSIPAccountUserName], [user settingForKey:MGMSIPAccountDomain]]];
|
||||||
|
if ([user settingForKey:MGMSIPAccountRegisterTimeout]!=nil && [[user settingForKey:MGMSIPAccountRegisterTimeout] intValue]!=0)
|
||||||
|
[SIPRegistrarTimeoutField setIntValue:[[user settingForKey:MGMSIPAccountRegisterTimeout] intValue]];
|
||||||
|
else
|
||||||
|
[SIPRegistrarTimeoutField setStringValue:@""];
|
||||||
|
|
||||||
|
NSArray *users = [MGMUser users];
|
||||||
|
NSMenu *menu = [[NSMenu new] autorelease];
|
||||||
|
|
||||||
|
int selectedGC = 0;
|
||||||
|
int cCount = 0;
|
||||||
|
for (int i=0; i<[users count]; i++) {
|
||||||
|
MGMUser *gcUser = [MGMUser userWithID:[users objectAtIndex:i]];
|
||||||
|
if ([[gcUser settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts]) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[gcUser settingForKey:MGMUserName]];
|
||||||
|
[item setRepresentedObject:[gcUser settingForKey:MGMUserID]];
|
||||||
|
if ([[user settingForKey:MGMCGoogleContactsUser] isEqual:[gcUser settingForKey:MGMUserID]])
|
||||||
|
selectedGC = cCount;
|
||||||
|
[menu addItem:item];
|
||||||
|
cCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSString *contactsSource = [user settingForKey:MGMSContactsSourceKey];
|
||||||
|
if ([contactsSource isEqual:NSStringFromClass([MGMAddressBook class])]) {
|
||||||
|
[SIPContactsMatrix selectCellAtRow:0 column:0];
|
||||||
|
[SIPGoogleContactsPopUp setEnabled:NO];
|
||||||
|
} else if ([contactsSource isEqual:NSStringFromClass([MGMGoogleContacts class])]) {
|
||||||
|
if ([[menu itemArray] count]!=0) {
|
||||||
|
[SIPContactsMatrix selectCellAtRow:1 column:0];
|
||||||
|
[SIPGoogleContactsPopUp setEnabled:YES];
|
||||||
|
} else {
|
||||||
|
[user setSetting:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[SIPContactsMatrix selectCellAtRow:0 column:0];
|
||||||
|
[SIPGoogleContactsPopUp setEnabled:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[SIPContactsMatrix setEnabled:YES];
|
||||||
|
[SIPGoogleContactsPopUp setMenu:menu];
|
||||||
|
[SIPGoogleContactsPopUp selectItemAtIndex:selectedGC];
|
||||||
|
if ([[SIPGoogleContactsPopUp selectedItem] representedObject]!=nil)
|
||||||
|
[user setSetting:[[SIPGoogleContactsPopUp selectedItem] representedObject] forKey:MGMCGoogleContactsUser];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)saveGV:(id)sender {
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:[usersTable selectedRow]]];
|
||||||
|
if ([[GVUserNameField stringValue] isEqual:@""] || [[GVPasswordField stringValue] isEqual:@""]) {
|
||||||
|
NSBeep();
|
||||||
|
[GVUserNameField setStringValue:[user settingForKey:MGMUserName]];
|
||||||
|
[GVPasswordField setStringValue:[user password]];
|
||||||
|
} else {
|
||||||
|
[user setSetting:[GVUserNameField stringValue] forKey:MGMUserName];
|
||||||
|
[user setPassword:[GVPasswordField stringValue]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)saveGC:(id)sender {
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:[usersTable selectedRow]]];
|
||||||
|
if ([[GCUserNameField stringValue] isEqual:@""] || [[GCPasswordField stringValue] isEqual:@""]) {
|
||||||
|
NSBeep();
|
||||||
|
[GCUserNameField setStringValue:[user settingForKey:MGMUserName]];
|
||||||
|
[GCPasswordField setStringValue:[user password]];
|
||||||
|
} else {
|
||||||
|
[user setSetting:[GCUserNameField stringValue] forKey:MGMUserName];
|
||||||
|
[user setPassword:[GCPasswordField stringValue]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)saveSIP:(id)sender {
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:[usersTable selectedRow]]];
|
||||||
|
[user setSetting:[SIPFullNameField stringValue] forKey:MGMSIPAccountFullName];
|
||||||
|
if ([[SIPDomainField stringValue] isEqual:@""]) {
|
||||||
|
[[SIPRegistrarField cell] setPlaceholderString:MGMSIPDefaultDomain];
|
||||||
|
[user setSetting:MGMSIPDefaultDomain forKey:MGMSIPAccountDomain];
|
||||||
|
} else {
|
||||||
|
[[SIPRegistrarField cell] setPlaceholderString:[SIPDomainField stringValue]];
|
||||||
|
[user setSetting:[SIPDomainField stringValue] forKey:MGMSIPAccountDomain];
|
||||||
|
}
|
||||||
|
[user setSetting:[SIPRegistrarField stringValue] forKey:MGMSIPAccountRegistrar];
|
||||||
|
if ([[SIPUserNameField stringValue] isEqual:@""] || [[SIPPasswordField stringValue] isEqual:@""]) {
|
||||||
|
NSBeep();
|
||||||
|
if ([user settingForKey:MGMSIPAccountUserName]!=nil) {
|
||||||
|
[SIPUserNameField setStringValue:[user settingForKey:MGMSIPAccountUserName]];
|
||||||
|
} else {
|
||||||
|
[SIPUserNameField setStringValue:@""];
|
||||||
|
}
|
||||||
|
[SIPPasswordField setStringValue:[user password]];
|
||||||
|
} else {
|
||||||
|
[user setSetting:[SIPUserNameField stringValue] forKey:MGMSIPAccountUserName];
|
||||||
|
[user setSetting:[SIPUserNameField stringValue] forKey:MGMUserName];
|
||||||
|
[user setPassword:[SIPPasswordField stringValue]];
|
||||||
|
}
|
||||||
|
[user setSetting:[SIPAreaCodeField stringValue] forKey:MGMSIPUserAreaCode];
|
||||||
|
[user setSetting:[SIPProxyHostField stringValue] forKey:MGMSIPAccountProxy];
|
||||||
|
[user setSetting:[NSNumber numberWithInt:[SIPProxyPortField intValue]] forKey:MGMSIPAccountProxyPort];
|
||||||
|
[user setSetting:[SIPSIPAddressField stringValue] forKey:MGMSIPAccountSIPAddress];
|
||||||
|
[[SIPSIPAddressField cell] setPlaceholderString:[NSString stringWithFormat:@"%@@%@", [user settingForKey:MGMSIPAccountUserName], [user settingForKey:MGMSIPAccountDomain]]];
|
||||||
|
[user setSetting:[NSNumber numberWithInt:[SIPRegistrarTimeoutField intValue]] forKey:MGMSIPAccountRegisterTimeout];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)saveContacts:(id)sender {
|
||||||
|
int selected = [usersTable selectedRow];
|
||||||
|
if (selected==-1) return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:selected]];
|
||||||
|
NSPopUpButton *googleContacts = nil;
|
||||||
|
if (sender==GVContactsMatrix)
|
||||||
|
googleContacts = GVGoogleContactsPopUp;
|
||||||
|
else if (sender==SIPContactsMatrix)
|
||||||
|
googleContacts = SIPGoogleContactsPopUp;
|
||||||
|
if ([sender selectedRow]==0) {
|
||||||
|
[user setSetting:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[googleContacts setEnabled:NO];
|
||||||
|
} else if ([sender selectedRow]==1) {
|
||||||
|
NSArray *users = [MGMUser users];
|
||||||
|
int cCount = 0;
|
||||||
|
for (int i=0; i<[users count]; i++) {
|
||||||
|
MGMUser *gcUser = [MGMUser userWithID:[users objectAtIndex:i]];
|
||||||
|
if ([[gcUser settingForKey:MGMSAccountType] isEqual:MGMSGoogleContacts])
|
||||||
|
cCount++;
|
||||||
|
}
|
||||||
|
if (cCount>0) {
|
||||||
|
[user setSetting:NSStringFromClass([MGMGoogleContacts class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[googleContacts setEnabled:YES];
|
||||||
|
} else {
|
||||||
|
[user setSetting:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[sender selectCellAtRow:0 column:0];
|
||||||
|
[googleContacts setEnabled:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)saveGoogleContactsUser:(id)sender {
|
||||||
|
int selected = [usersTable selectedRow];
|
||||||
|
if (selected==-1) return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:selected]];
|
||||||
|
[user setSetting:[[sender selectedItem] representedObject] forKey:MGMCGoogleContactsUser];
|
||||||
|
}
|
||||||
|
- (IBAction)saveAction:(id)sender {
|
||||||
|
int selected = [usersTable selectedRow];
|
||||||
|
if (selected==-1) return;
|
||||||
|
MGMUser *user = [MGMUser userWithID:[[MGMUser users] objectAtIndex:selected]];
|
||||||
|
[user setSetting:[NSNumber numberWithInt:[GVActionMatrix selectedRow]] forKey:MGMSContactsActionKey];
|
||||||
|
}
|
||||||
|
@end
|
70
Classes/VoiceMac/Preferences/MGMSIPPane.h
Normal file
70
Classes/VoiceMac/Preferences/MGMSIPPane.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPPane.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/16/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@interface MGMSIPPane : MGMPreferencesPane {
|
||||||
|
IBOutlet NSView *mainView;
|
||||||
|
BOOL shouldRestart;
|
||||||
|
|
||||||
|
//Sound Tab
|
||||||
|
IBOutlet NSSlider *volumeSlider;
|
||||||
|
IBOutlet NSSlider *micVolumeSlider;
|
||||||
|
IBOutlet NSPopUpButton *audioOutputPopUp;
|
||||||
|
IBOutlet NSPopUpButton *audioInputPopUp;
|
||||||
|
IBOutlet NSButton *echoCancelationButton;
|
||||||
|
IBOutlet NSButton *voiceActivityDetectionButton;
|
||||||
|
|
||||||
|
//Network Tab
|
||||||
|
IBOutlet NSTextField *localPortField;
|
||||||
|
IBOutlet NSTextField *outboundProxyHostField;
|
||||||
|
IBOutlet NSTextField *outboundProxyPortField;
|
||||||
|
IBOutlet NSTextField *STUNServerField;
|
||||||
|
IBOutlet NSTextField *STUNServerPortField;
|
||||||
|
IBOutlet NSButton *nameServersButton;
|
||||||
|
IBOutlet NSButton *ICEButton;
|
||||||
|
|
||||||
|
//Advanced Tab
|
||||||
|
IBOutlet NSTextField *logFileField;
|
||||||
|
IBOutlet NSButton *logFileButton;
|
||||||
|
IBOutlet NSTextField *logFileLevelField;
|
||||||
|
IBOutlet NSTextField *consoleLogLevelField;
|
||||||
|
IBOutlet NSTextField *publicAddressField;
|
||||||
|
}
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
|
||||||
|
+ (NSString *)title;
|
||||||
|
- (NSView *)preferencesView;
|
||||||
|
|
||||||
|
//Sound
|
||||||
|
- (IBAction)volume:(id)sender;
|
||||||
|
- (IBAction)micVolume:(id)sender;
|
||||||
|
- (void)audioChanged:(NSNotification *)theNotificaiton;
|
||||||
|
- (IBAction)audio:(id)sender;
|
||||||
|
- (IBAction)echoCancelation:(id)sender;
|
||||||
|
- (IBAction)voiceActivityDetection:(id)sender;
|
||||||
|
|
||||||
|
//Network
|
||||||
|
- (IBAction)localPort:(id)sender;
|
||||||
|
- (IBAction)outboundProxyHost:(id)sender;
|
||||||
|
- (IBAction)outboundProxyPort:(id)sender;
|
||||||
|
- (IBAction)STUNServer:(id)sender;
|
||||||
|
- (IBAction)STUNServerPort:(id)sender;
|
||||||
|
- (IBAction)nameServer:(id)sender;
|
||||||
|
- (IBAction)ICE:(id)sender;
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
- (IBAction)logFile:(id)sender;
|
||||||
|
- (IBAction)chooseLogFile:(id)sender;
|
||||||
|
- (IBAction)logFileLevel:(id)sender;
|
||||||
|
- (IBAction)consoleLogLevel:(id)sender;
|
||||||
|
- (IBAction)publicAddress:(id)sender;
|
||||||
|
@end
|
||||||
|
#endif
|
232
Classes/VoiceMac/Preferences/MGMSIPPane.m
Normal file
232
Classes/VoiceMac/Preferences/MGMSIPPane.m
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPPane.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/16/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPPane.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
@implementation MGMSIPPane
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
|
||||||
|
if (self = [super initWithPreferences:thePreferences]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SIPPane" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Nib for SIP Preferences");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
shouldRestart = NO;
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
//Sound
|
||||||
|
[volumeSlider setFloatValue:[[MGMSIP sharedSIP] volume]];
|
||||||
|
[micVolumeSlider setFloatValue:[[MGMSIP sharedSIP] micVolume]];
|
||||||
|
[self audioChanged:nil];
|
||||||
|
[echoCancelationButton setState:([defaults boolForKey:MGMSIPEchoCacnellationEnabled] ? NSOnState : NSOffState)];
|
||||||
|
[voiceActivityDetectionButton setState:([defaults boolForKey:MGMSIPVoiceActivityDetection] ? NSOnState : NSOffState)];
|
||||||
|
|
||||||
|
//Network
|
||||||
|
[[localPortField cell] setPlaceholderString:[[NSNumber numberWithInt:[[MGMSIP sharedSIP] port]] stringValue]];
|
||||||
|
if ([defaults integerForKey:MGMSIPPort]!=0)
|
||||||
|
[localPortField setIntValue:[defaults integerForKey:MGMSIPPort]];
|
||||||
|
if ([defaults objectForKey:MGMSIPOutboundProxy]!=nil && ![[defaults objectForKey:MGMSIPOutboundProxy] isEqual:@""])
|
||||||
|
[outboundProxyHostField setStringValue:[defaults objectForKey:MGMSIPOutboundProxy]];
|
||||||
|
if ([defaults integerForKey:MGMSIPOutboundProxyPort]!=0)
|
||||||
|
[outboundProxyPortField setIntValue:[defaults integerForKey:MGMSIPOutboundProxyPort]];
|
||||||
|
if ([defaults objectForKey:MGMSIPSTUN]!=nil && ![[defaults objectForKey:MGMSIPSTUN] isEqual:@""])
|
||||||
|
[STUNServerField setStringValue:[defaults objectForKey:MGMSIPSTUN]];
|
||||||
|
if ([defaults integerForKey:MGMSIPSTUNPort]!=0)
|
||||||
|
[STUNServerPortField setIntValue:[defaults integerForKey:MGMSIPSTUNPort]];
|
||||||
|
[nameServersButton setState:([defaults boolForKey:MGMSIPNameServersEnabled] ? NSOnState : NSOffState)];
|
||||||
|
[ICEButton setState:([defaults boolForKey:MGMSIPInteractiveConnectivityEstablishment] ? NSOnState : NSOffState)];
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
if ([defaults objectForKey:MGMSIPLogFile]!=nil && ![[defaults objectForKey:MGMSIPLogFile] isEqual:@""])
|
||||||
|
[logFileField setStringValue:[defaults objectForKey:MGMSIPLogFile]];
|
||||||
|
[logFileLevelField setIntValue:[defaults integerForKey:MGMSIPLogLevel]];
|
||||||
|
[consoleLogLevelField setIntValue:[defaults integerForKey:MGMSIPConsoleLogLevel]];
|
||||||
|
if ([defaults objectForKey:MGMSIPPublicAddress]!=nil && ![[defaults objectForKey:MGMSIPPublicAddress] isEqual:@""])
|
||||||
|
[publicAddressField setStringValue:[defaults objectForKey:MGMSIPPublicAddress]];
|
||||||
|
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(volumeChanged:) name:MGMSIPVolumeChangedNotification object:nil];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(micVolumeChanged:) name:MGMSIPMicVolumeChangedNotification object:nil];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(audioChanged:) name:MGMSIPAudioChangedNotification object:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (shouldRestart) {
|
||||||
|
NSAlert *alert = [[NSAlert new] autorelease];
|
||||||
|
[alert setMessageText:@"Restart Required"];
|
||||||
|
[alert setInformativeText:@"You have changed some settings that requires you to restart VoiceMac for them to take place, do you want to restart VoiceMac now?"];
|
||||||
|
[alert addButtonWithTitle:@"Yes"];
|
||||||
|
[alert addButtonWithTitle:@"No"];
|
||||||
|
int result = [alert runModal];
|
||||||
|
if (result==1000) {
|
||||||
|
//Took from Sparkle.
|
||||||
|
NSString *pathToRelaunch = [[NSBundle mainBundle] bundlePath];
|
||||||
|
NSString *relaunchPath = [[[NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"] resourcePath] stringByAppendingPathComponent:@"relaunch"];
|
||||||
|
[NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], nil]];
|
||||||
|
[[NSApplication sharedApplication] terminate:self];
|
||||||
|
}
|
||||||
|
//[[MGMSIP sharedSIP] restart];
|
||||||
|
}
|
||||||
|
if (mainView!=nil)
|
||||||
|
[mainView release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
|
||||||
|
[theItem setLabel:[self title]];
|
||||||
|
[theItem setPaletteLabel:[theItem label]];
|
||||||
|
[theItem setImage:[NSImage imageNamed:@"SIP"]];
|
||||||
|
}
|
||||||
|
+ (NSString *)title {
|
||||||
|
return @"SIP Options";
|
||||||
|
}
|
||||||
|
- (NSView *)preferencesView {
|
||||||
|
return mainView;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sound
|
||||||
|
- (void)volumeChanged:(NSNotification *)theNotification {
|
||||||
|
[volumeSlider setFloatValue:[[theNotification object] floatValue]];
|
||||||
|
}
|
||||||
|
- (IBAction)volume:(id)sender {
|
||||||
|
[[MGMSIP sharedSIP] setVolume:[volumeSlider floatValue]];
|
||||||
|
}
|
||||||
|
- (void)micVolumeChanged:(NSNotification *)theNotification {
|
||||||
|
[micVolumeSlider setFloatValue:[[theNotification object] floatValue]];
|
||||||
|
}
|
||||||
|
- (IBAction)micVolume:(id)sender {
|
||||||
|
[[MGMSIP sharedSIP] setMicVolume:[micVolumeSlider floatValue]];
|
||||||
|
}
|
||||||
|
- (void)audioChanged:(NSNotification *)theNotificaiton {
|
||||||
|
if (![[MGMSIP sharedSIP] isStarted]) {
|
||||||
|
[[MGMSIP sharedSIP] start];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSArray *devices = nil;
|
||||||
|
if (theNotificaiton==nil || [theNotificaiton object]==nil)
|
||||||
|
devices = [[MGMSIP sharedSIP] audioDevices];
|
||||||
|
else
|
||||||
|
devices = [theNotificaiton object];
|
||||||
|
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSMenu *outputMenu = [[NSMenu new] autorelease];
|
||||||
|
int outputIndex = 0;
|
||||||
|
int outputCount = 0;
|
||||||
|
NSMenu *inputMenu = [[NSMenu new] autorelease];
|
||||||
|
int inputIndex = 0;
|
||||||
|
int inputCount = 0;
|
||||||
|
for (int i=0; i<[devices count]; i++) {
|
||||||
|
NSDictionary *device = [devices objectAtIndex:i];
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceIndex] intValue]==-1 || [[device objectForKey:MGMSIPADeviceOutputCount] intValue]>0) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[device objectForKey:MGMSIPADeviceName]];
|
||||||
|
[item setTag:[[device objectForKey:MGMSIPADeviceIndex] intValue]];
|
||||||
|
[outputMenu addItem:item];
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceUID] isEqual:[defaults objectForKey:MGMSIPACurrentOutputDevice]])
|
||||||
|
outputIndex = outputCount;
|
||||||
|
outputCount++;
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceIndex] intValue]==-1) {
|
||||||
|
[outputMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
outputCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceIndex] intValue]==-1 || [[device objectForKey:MGMSIPADeviceInputCount] intValue]>0) {
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[device objectForKey:MGMSIPADeviceName]];
|
||||||
|
[item setTag:[[device objectForKey:MGMSIPADeviceIndex] intValue]];
|
||||||
|
[inputMenu addItem:item];
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceUID] isEqual:[defaults objectForKey:MGMSIPACurrentInputDevice]])
|
||||||
|
inputIndex = inputCount;
|
||||||
|
inputCount++;
|
||||||
|
if ([[device objectForKey:MGMSIPADeviceIndex] intValue]==-1) {
|
||||||
|
[inputMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
inputCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[audioOutputPopUp setMenu:outputMenu];
|
||||||
|
[audioOutputPopUp selectItemAtIndex:outputIndex];
|
||||||
|
[audioInputPopUp setMenu:inputMenu];
|
||||||
|
[audioInputPopUp selectItemAtIndex:inputIndex];
|
||||||
|
}
|
||||||
|
- (IBAction)audio:(id)sender {
|
||||||
|
[[MGMSIP sharedSIP] setInputSoundDevice:[[audioInputPopUp selectedItem] tag] outputSoundDevice:[[audioOutputPopUp selectedItem] tag]];
|
||||||
|
}
|
||||||
|
- (IBAction)echoCancelation:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:([echoCancelationButton state]==NSOnState) forKey:MGMSIPEchoCacnellationEnabled];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)voiceActivityDetection:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:([voiceActivityDetectionButton state]==NSOnState) forKey:MGMSIPVoiceActivityDetection];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Network
|
||||||
|
- (IBAction)localPort:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:[localPortField intValue] forKey:MGMSIPPort];
|
||||||
|
[[MGMSIP sharedSIP] setPort:[localPortField intValue]];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)outboundProxyHost:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[outboundProxyHostField stringValue] forKey:MGMSIPOutboundProxy];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)outboundProxyPort:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:[outboundProxyPortField intValue] forKey:MGMSIPOutboundProxyPort];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)STUNServer:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[STUNServerField stringValue] forKey:MGMSIPSTUN];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)STUNServerPort:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:[STUNServerPortField intValue] forKey:MGMSIPSTUNPort];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)nameServer:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:([nameServersButton state]==NSOnState) forKey:MGMSIPNameServersEnabled];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)ICE:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:([ICEButton state]==NSOnState) forKey:MGMSIPInteractiveConnectivityEstablishment];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
- (IBAction)logFile:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[logFileField stringValue] forKey:MGMSIPLogFile];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)chooseLogFile:(id)sender {
|
||||||
|
NSSavePanel *panel = [NSSavePanel savePanel];
|
||||||
|
int returnCode;
|
||||||
|
returnCode = [panel runModal];
|
||||||
|
if (returnCode==NSOKButton) {
|
||||||
|
NSString *path = [[panel URL] path];
|
||||||
|
[logFileField setStringValue:path];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:path forKey:MGMSIPLogFile];
|
||||||
|
}
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)logFileLevel:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:[logFileLevelField intValue] forKey:MGMSIPLogLevel];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)consoleLogLevel:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:[consoleLogLevelField intValue] forKey:MGMSIPConsoleLogLevel];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
- (IBAction)publicAddress:(id)sender {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[publicAddressField stringValue] forKey:MGMSIPPublicAddress];
|
||||||
|
shouldRestart = YES;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
41
Classes/VoiceMac/Preferences/MGMSMSThemesPane.h
Normal file
41
Classes/VoiceMac/Preferences/MGMSMSThemesPane.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSThemesPane.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@class MGMThemeManager, WebView;
|
||||||
|
|
||||||
|
@interface MGMSMSThemesPane : MGMPreferencesPane {
|
||||||
|
MGMThemeManager *themeManager;
|
||||||
|
NSMutableArray *testMessages;
|
||||||
|
NSMutableDictionary *testMessageInfo;
|
||||||
|
NSArray *themes;
|
||||||
|
IBOutlet NSView *mainView;
|
||||||
|
IBOutlet WebView *SMSView;
|
||||||
|
IBOutlet NSPopUpButton *themePopUp;
|
||||||
|
IBOutlet NSPopUpButton *variantPopUp;
|
||||||
|
IBOutlet NSButton *authorButton;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *browserWindow;
|
||||||
|
IBOutlet WebView *browser;
|
||||||
|
}
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
|
||||||
|
+ (NSString *)title;
|
||||||
|
- (NSView *)preferencesView;
|
||||||
|
|
||||||
|
- (IBAction)reload:(id)sender;
|
||||||
|
- (void)buildHTML;
|
||||||
|
|
||||||
|
- (IBAction)changeTheme:(id)sender;
|
||||||
|
- (IBAction)changeVariant:(id)sender;
|
||||||
|
- (IBAction)authorSite:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)showBrowser:(id)sender;
|
||||||
|
@end
|
139
Classes/VoiceMac/Preferences/MGMSMSThemesPane.m
Normal file
139
Classes/VoiceMac/Preferences/MGMSMSThemesPane.m
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSThemesPane.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSMSThemesPane.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
NSString * const MGMTestTYPhoto = @"yPhoto";
|
||||||
|
NSString * const MGMTestTTPhoto = @"tPhoto";
|
||||||
|
|
||||||
|
@implementation MGMSMSThemesPane
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
|
||||||
|
if (self = [super initWithPreferences:thePreferences]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SMSThemesPane" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Nib for SMS Themes Preferences");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
themeManager = [MGMThemeManager new];
|
||||||
|
testMessages = [NSMutableArray new];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Hey, you got the message?", MGMIText, @"5:56 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No, can you resend it?", MGMIText, @"5:57 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No, all local copies were destroyed, because we don't want this to get out.", MGMIText, @"5:58 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Oh, yea, right, that thing.", MGMIText, @"5:59 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"I can't send you on SMS because your cell phone company spy's on you.", MGMIText, @"6:00 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"True. We can meet in the secret spot.", MGMIText, @"6:00 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"No thanks, I think we should meet at my house.", MGMIText, @"6:01 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Would you like to come for dinner?", MGMIText, @"6:01 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"I'd love, but my girl needs me more.", MGMIText, @"6:02 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Well why not make it a double date? I bring my wife and you bring yours.", MGMIText, @"6:03 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Sure I pick Mucha Pizza. What time should we meet?", MGMIText, @"6:05 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"7PM?", MGMIText, @"6:05 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"That sounds good.", MGMIText, @"6:06 PM", MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil]];
|
||||||
|
[testMessages addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Great, meet you then.", MGMIText, @"6:07 PM", MGMITime, [NSNumber numberWithBool:NO], MGMIYou, nil]];
|
||||||
|
testMessageInfo = [NSMutableDictionary new];
|
||||||
|
[testMessageInfo setObject:[NSDate dateWithNaturalLanguageString:@"8/31/20 6:07:25 PM"] forKey:MGMITime];
|
||||||
|
[testMessageInfo setObject:@"Noah Jonson" forKey:MGMTInName];
|
||||||
|
[testMessageInfo setObject:@"+15555555555" forKey:MGMIPhoneNumber];
|
||||||
|
[testMessageInfo setObject:@"+17204325686" forKey:MGMTUserNumber];
|
||||||
|
[testMessageInfo setObject:@"673bd22599231d1a9ba78760f2df085a7237b4b3" forKey:MGMIID];
|
||||||
|
[SMSView setResourceLoadDelegate:self];
|
||||||
|
[self reload:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (themeManager!=nil)
|
||||||
|
[themeManager release];
|
||||||
|
if (testMessages!=nil)
|
||||||
|
[testMessages release];
|
||||||
|
if (testMessageInfo!=nil)
|
||||||
|
[testMessageInfo release];
|
||||||
|
if (mainView!=nil)
|
||||||
|
[mainView release];
|
||||||
|
if (browserWindow!=nil)
|
||||||
|
[browserWindow release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
|
||||||
|
[theItem setLabel:[self title]];
|
||||||
|
[theItem setPaletteLabel:[theItem label]];
|
||||||
|
[theItem setImage:[NSImage imageNamed:@"SMSThemes"]];
|
||||||
|
}
|
||||||
|
+ (NSString *)title {
|
||||||
|
return @"SMS Themes";
|
||||||
|
}
|
||||||
|
- (NSView *)preferencesView {
|
||||||
|
return mainView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)reload:(id)sender {
|
||||||
|
[testMessageInfo setObject:[[themeManager outgoingIconPath] filePath] forKey:MGMTestTYPhoto];
|
||||||
|
[testMessageInfo setObject:[[themeManager incomingIconPath] filePath] forKey:MGMTestTTPhoto];
|
||||||
|
[self buildHTML];
|
||||||
|
themes = [[themeManager themes] copy];
|
||||||
|
[themePopUp removeAllItems];
|
||||||
|
for (int i=0; i<[themes count]; i++) {
|
||||||
|
[themePopUp addItemWithTitle:[[themes objectAtIndex:i] objectForKey:MGMTName]];
|
||||||
|
if ([[[themes objectAtIndex:i] objectForKey:MGMTThemePath] isEqual:[themeManager currentThemePath]])
|
||||||
|
[themePopUp selectItemAtIndex:i];
|
||||||
|
}
|
||||||
|
NSDictionary *theme = [themeManager theme];
|
||||||
|
NSArray *variants = [theme objectForKey:MGMTVariants];
|
||||||
|
[variantPopUp removeAllItems];
|
||||||
|
for (int i=0; i<[variants count]; i++) {
|
||||||
|
[variantPopUp addItemWithTitle:[[variants objectAtIndex:i] objectForKey:MGMTName]];
|
||||||
|
if ([[[variants objectAtIndex:i] objectForKey:MGMTName] isEqual:[[themeManager variant] objectForKey:MGMTName]])
|
||||||
|
[variantPopUp selectItemAtIndex:i];
|
||||||
|
}
|
||||||
|
[authorButton setTitle:[theme objectForKey:MGMTAuthor]];
|
||||||
|
}
|
||||||
|
- (void)buildHTML {
|
||||||
|
NSMutableArray *messageArray = [NSMutableArray array];
|
||||||
|
for (unsigned int i=0; i<[testMessages count]; i++) {
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionaryWithDictionary:[testMessages objectAtIndex:i]];
|
||||||
|
[message setObject:[[NSNumber numberWithInt:i] stringValue] forKey:MGMIID];
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
[message setObject:[testMessageInfo objectForKey:MGMTestTYPhoto] forKey:MGMTPhoto];
|
||||||
|
[message setObject:NSFullUserName() forKey:MGMTName];
|
||||||
|
[message setObject:[testMessageInfo objectForKey:MGMTUserNumber] forKey:MGMIPhoneNumber];
|
||||||
|
} else {
|
||||||
|
[message setObject:[testMessageInfo objectForKey:MGMTestTTPhoto] forKey:MGMTPhoto];
|
||||||
|
[message setObject:[testMessageInfo objectForKey:MGMTInName] forKey:MGMTName];
|
||||||
|
[message setObject:[testMessageInfo objectForKey:MGMIPhoneNumber] forKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
[messageArray addObject:message];
|
||||||
|
}
|
||||||
|
NSString *html = [themeManager buildHTMLWithMessages:messageArray messageInfo:testMessageInfo];
|
||||||
|
[[SMSView mainFrame] loadHTMLString:html baseURL:[NSURL fileURLWithPath:[themeManager currentThemeVariantPath]]];
|
||||||
|
}
|
||||||
|
- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource {
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:@"scrollToBottom();"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)changeTheme:(id)sender {
|
||||||
|
NSDictionary *theme = [themes objectAtIndex:[themePopUp indexOfSelectedItem]];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:MGMTCurrentThemeVariant];
|
||||||
|
[themeManager setTheme:theme];
|
||||||
|
[self reload:self];
|
||||||
|
}
|
||||||
|
- (IBAction)changeVariant:(id)sender {
|
||||||
|
[themeManager setVariant:[variantPopUp titleOfSelectedItem]];
|
||||||
|
[self reload:self];
|
||||||
|
}
|
||||||
|
- (IBAction)authorSite:(id)sender {
|
||||||
|
if ([[themeManager theme] objectForKey:MGMTSite]!=nil)
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[[themeManager theme] objectForKey:MGMTSite]]];
|
||||||
|
}
|
||||||
|
- (IBAction)showBrowser:(id)sender {
|
||||||
|
[[browser mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://mrgeckosmedia.com/voicemac/themes/"]]];
|
||||||
|
[browserWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
@end
|
56
Classes/VoiceMac/Preferences/MGMSoundsPane.h
Normal file
56
Classes/VoiceMac/Preferences/MGMSoundsPane.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// MGMSoundsPane.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/7/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@class MGMThemeManager, WebView;
|
||||||
|
|
||||||
|
@interface MGMSoundsPane : MGMPreferencesPane {
|
||||||
|
MGMThemeManager *themeManager;
|
||||||
|
IBOutlet NSView *mainView;
|
||||||
|
IBOutlet NSPopUpButton *SMSMessagePopUp;
|
||||||
|
IBOutlet NSButton *SMSMessageAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *voicemailPopUp;
|
||||||
|
IBOutlet NSButton *voicemailAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPRingtonePopUp;
|
||||||
|
IBOutlet NSButton *SIPRingtoneAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPHoldMusicPopUp;
|
||||||
|
IBOutlet NSButton *SIPHoldMusicAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPConnectedPopUp;
|
||||||
|
IBOutlet NSButton *SIPConnectedAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPDisconnectedPopUp;
|
||||||
|
IBOutlet NSButton *SIPDisconnectedAuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPSound1PopUp;
|
||||||
|
IBOutlet NSButton *SIPSound1AuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPSound2PopUp;
|
||||||
|
IBOutlet NSButton *SIPSound2AuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPSound3PopUp;
|
||||||
|
IBOutlet NSButton *SIPSound3AuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPSound4PopUp;
|
||||||
|
IBOutlet NSButton *SIPSound4AuthorButton;
|
||||||
|
IBOutlet NSPopUpButton *SIPSound5PopUp;
|
||||||
|
IBOutlet NSButton *SIPSound5AuthorButton;
|
||||||
|
NSMutableDictionary *sounds;
|
||||||
|
NSSound *soundPlayer;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *browserWindow;
|
||||||
|
IBOutlet WebView *browser;
|
||||||
|
}
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
|
||||||
|
+ (NSString *)title;
|
||||||
|
- (NSView *)preferencesView;
|
||||||
|
|
||||||
|
- (void)reload:(NSString *)theSound;
|
||||||
|
- (IBAction)selectSound:(id)sender;
|
||||||
|
- (IBAction)stopSound:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)authorSite:(id)sender;
|
||||||
|
- (IBAction)showBrowser:(id)sender;
|
||||||
|
@end
|
258
Classes/VoiceMac/Preferences/MGMSoundsPane.m
Normal file
258
Classes/VoiceMac/Preferences/MGMSoundsPane.m
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
//
|
||||||
|
// MGMSoundsPane.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/7/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSoundsPane.h"
|
||||||
|
#import "MGMSIPWavConverter.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
NSString * const MGMNoAuthor = @"No Author Found";
|
||||||
|
|
||||||
|
@implementation MGMSoundsPane
|
||||||
|
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
|
||||||
|
if (self = [super initWithPreferences:thePreferences]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SoundsPane" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Nib for Sounds Preferences");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
themeManager = [MGMThemeManager new];
|
||||||
|
sounds = [[themeManager sounds] copy];
|
||||||
|
[self reload:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[self stopSound:self];
|
||||||
|
if (themeManager!=nil)
|
||||||
|
[themeManager release];
|
||||||
|
if (mainView!=nil)
|
||||||
|
[mainView release];
|
||||||
|
if (sounds!=nil)
|
||||||
|
[sounds release];
|
||||||
|
if (browserWindow!=nil)
|
||||||
|
[browserWindow release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
|
||||||
|
[theItem setLabel:[self title]];
|
||||||
|
[theItem setPaletteLabel:[theItem label]];
|
||||||
|
[theItem setImage:[NSImage imageNamed:@"Sounds"]];
|
||||||
|
}
|
||||||
|
+ (NSString *)title {
|
||||||
|
return @"Sounds";
|
||||||
|
}
|
||||||
|
- (NSView *)preferencesView {
|
||||||
|
return mainView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)setMenuForPopUp:(NSPopUpButton *)thePopUp authorButton:(NSButton *)theAuthorButton withCurrentPath:(NSString *)thePath {
|
||||||
|
NSArray *soundsKeys = [sounds allKeys];
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSMenu *soundsMenu = [[NSMenu new] autorelease];
|
||||||
|
NSMenuItem *noSound = [[NSMenuItem new] autorelease];
|
||||||
|
[noSound setTitle:@"No Sound"];
|
||||||
|
[noSound setTag:-1];
|
||||||
|
[noSound setTarget:self];
|
||||||
|
[noSound setAction:@selector(selectSound:)];
|
||||||
|
[noSound setRepresentedObject:thePopUp];
|
||||||
|
[soundsMenu addItem:noSound];
|
||||||
|
[soundsMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
NSString *currentMenuName = nil;
|
||||||
|
for (int i=0; i<[soundsKeys count]; i++) {
|
||||||
|
NSMenuItem *menuItem = [[NSMenuItem new] autorelease];
|
||||||
|
[menuItem setTitle:[soundsKeys objectAtIndex:i]];
|
||||||
|
[menuItem setTag:i];
|
||||||
|
NSMenu *menu = [[NSMenu new] autorelease];
|
||||||
|
for (int s=0; s<[[sounds objectForKey:[soundsKeys objectAtIndex:i]] count]; s++) {
|
||||||
|
NSMenuItem *menuItem = [[NSMenuItem new] autorelease];
|
||||||
|
[menuItem setTitle:[[[sounds objectForKey:[soundsKeys objectAtIndex:i]] objectAtIndex:s] objectForKey:MGMTSName]];
|
||||||
|
[menuItem setTag:s];
|
||||||
|
[menuItem setTarget:self];
|
||||||
|
[menuItem setAction:@selector(selectSound:)];
|
||||||
|
[menuItem setRepresentedObject:thePopUp];
|
||||||
|
if ([[[[sounds objectForKey:[soundsKeys objectAtIndex:i]] objectAtIndex:s] objectForKey:MGMTSPath] isEqual:thePath]) {
|
||||||
|
currentMenuName = [[[sounds objectForKey:[soundsKeys objectAtIndex:i]] objectAtIndex:s] objectForKey:MGMTSName];
|
||||||
|
|
||||||
|
BOOL author = NO;
|
||||||
|
if ([manager fileExistsAtPath:[[thePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]]) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[[thePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
if ([info objectForKey:MGMTAuthor]!=nil) {
|
||||||
|
[theAuthorButton setTitle:[info objectForKey:MGMTAuthor]];
|
||||||
|
author = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!author)
|
||||||
|
[theAuthorButton setTitle:MGMNoAuthor];
|
||||||
|
[theAuthorButton setEnabled:author];
|
||||||
|
}
|
||||||
|
[menu addItem:menuItem];
|
||||||
|
}
|
||||||
|
[menuItem setSubmenu:menu];
|
||||||
|
[soundsMenu addItem:menuItem];
|
||||||
|
}
|
||||||
|
if (currentMenuName!=nil) {
|
||||||
|
[soundsMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
NSMenuItem *selected = [[NSMenuItem new] autorelease];
|
||||||
|
[selected setTitle:currentMenuName];
|
||||||
|
[soundsMenu addItem:selected];
|
||||||
|
}
|
||||||
|
[thePopUp setMenu:soundsMenu];
|
||||||
|
if (currentMenuName!=nil)
|
||||||
|
[thePopUp selectItem:[thePopUp lastItem]];
|
||||||
|
else {
|
||||||
|
[theAuthorButton setTitle:MGMNoAuthor];
|
||||||
|
[theAuthorButton setEnabled:NO];
|
||||||
|
[thePopUp selectItemAtIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)reload:(NSString *)theSound {
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSMSMessage])
|
||||||
|
[self setMenuForPopUp:SMSMessagePopUp authorButton:SMSMessageAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSMSMessage]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSVoicemail])
|
||||||
|
[self setMenuForPopUp:voicemailPopUp authorButton:voicemailAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSVoicemail]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPRingtone])
|
||||||
|
[self setMenuForPopUp:SIPRingtonePopUp authorButton:SIPRingtoneAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPRingtone]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPHoldMusic])
|
||||||
|
[self setMenuForPopUp:SIPHoldMusicPopUp authorButton:SIPHoldMusicAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPHoldMusic]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPConnected])
|
||||||
|
[self setMenuForPopUp:SIPConnectedPopUp authorButton:SIPConnectedAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPConnected]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPDisconnected])
|
||||||
|
[self setMenuForPopUp:SIPDisconnectedPopUp authorButton:SIPDisconnectedAuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPDisconnected]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPSound1])
|
||||||
|
[self setMenuForPopUp:SIPSound1PopUp authorButton:SIPSound1AuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPSound1]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPSound2])
|
||||||
|
[self setMenuForPopUp:SIPSound2PopUp authorButton:SIPSound2AuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPSound2]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPSound3])
|
||||||
|
[self setMenuForPopUp:SIPSound3PopUp authorButton:SIPSound3AuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPSound3]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPSound4])
|
||||||
|
[self setMenuForPopUp:SIPSound4PopUp authorButton:SIPSound4AuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPSound4]];
|
||||||
|
if (theSound==nil || [theSound isEqual:MGMTSSIPSound5])
|
||||||
|
[self setMenuForPopUp:SIPSound5PopUp authorButton:SIPSound5AuthorButton withCurrentPath:[themeManager currentSoundPath:MGMTSSIPSound5]];
|
||||||
|
}
|
||||||
|
- (IBAction)selectSound:(id)sender {
|
||||||
|
NSString *soundName = nil;
|
||||||
|
if ([sender representedObject]==SMSMessagePopUp)
|
||||||
|
soundName = MGMTSSMSMessage;
|
||||||
|
else if ([sender representedObject]==voicemailPopUp)
|
||||||
|
soundName = MGMTSVoicemail;
|
||||||
|
else if ([sender representedObject]==SIPRingtonePopUp)
|
||||||
|
soundName = MGMTSSIPRingtone;
|
||||||
|
else if ([sender representedObject]==SIPHoldMusicPopUp)
|
||||||
|
soundName = MGMTSSIPHoldMusic;
|
||||||
|
else if ([sender representedObject]==SIPConnectedPopUp)
|
||||||
|
soundName = MGMTSSIPConnected;
|
||||||
|
else if ([sender representedObject]==SIPDisconnectedPopUp)
|
||||||
|
soundName = MGMTSSIPDisconnected;
|
||||||
|
else if ([sender representedObject]==SIPSound1PopUp)
|
||||||
|
soundName = MGMTSSIPSound1;
|
||||||
|
else if ([sender representedObject]==SIPSound2PopUp)
|
||||||
|
soundName = MGMTSSIPSound2;
|
||||||
|
else if ([sender representedObject]==SIPSound3PopUp)
|
||||||
|
soundName = MGMTSSIPSound3;
|
||||||
|
else if ([sender representedObject]==SIPSound4PopUp)
|
||||||
|
soundName = MGMTSSIPSound4;
|
||||||
|
else if ([sender representedObject]==SIPSound5PopUp)
|
||||||
|
soundName = MGMTSSIPSound5;
|
||||||
|
if (soundName==nil) return;
|
||||||
|
if ([sender tag]==-1) {
|
||||||
|
[themeManager setSound:soundName withPath:MGMTNoSound];
|
||||||
|
if ([soundName isEqual:MGMTSSIPHoldMusic] || [soundName isEqual:MGMTSSIPSound1] || [soundName isEqual:MGMTSSIPSound2] || [soundName isEqual:MGMTSSIPSound3] || [soundName isEqual:MGMTSSIPSound4] || [soundName isEqual:MGMTSSIPSound5]) {
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *finalPath = [[[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:MGMTCallSoundsFolder] stringByAppendingPathComponent:soundName] stringByAppendingPathExtension:MGMWavExt];
|
||||||
|
if ([manager fileExistsAtPath:finalPath]) {
|
||||||
|
if ([manager respondsToSelector:@selector(removeFileAtPath:)])
|
||||||
|
[manager removeFileAtPath:finalPath handler:nil];
|
||||||
|
else
|
||||||
|
[manager removeItemAtPath:finalPath error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSMenuItem *soundsMenuItem = nil;
|
||||||
|
NSArray *items = [[sender representedObject] itemArray];
|
||||||
|
for (int i=0; i<[items count]; i++) {
|
||||||
|
if ([[items objectAtIndex:i] submenu]==[sender menu]) {
|
||||||
|
soundsMenuItem = [items objectAtIndex:i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (soundsMenuItem==nil)
|
||||||
|
return;
|
||||||
|
NSDictionary *sound = [[sounds objectForKey:[[sounds allKeys] objectAtIndex:[soundsMenuItem tag]]] objectAtIndex:[sender tag]];
|
||||||
|
if (sound!=nil) {
|
||||||
|
if (![themeManager setSound:soundName withPath:[sound objectForKey:MGMTSPath]]) {
|
||||||
|
NSBeep();
|
||||||
|
} else {
|
||||||
|
if (soundPlayer!=nil) {
|
||||||
|
[soundPlayer stop];
|
||||||
|
[soundPlayer release];
|
||||||
|
soundPlayer = nil;
|
||||||
|
}
|
||||||
|
soundPlayer = [themeManager playSound:soundName];
|
||||||
|
[soundPlayer setDelegate:self];
|
||||||
|
}
|
||||||
|
if ([soundName isEqual:MGMTSSIPHoldMusic] || [soundName isEqual:MGMTSSIPSound1] || [soundName isEqual:MGMTSSIPSound2] || [soundName isEqual:MGMTSSIPSound3] || [soundName isEqual:MGMTSSIPSound4] || [soundName isEqual:MGMTSSIPSound5])
|
||||||
|
[[MGMSIPWavConverter alloc] initWithSoundName:soundName fileConverting:[sound objectForKey:MGMTSPath]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self reload:soundName];
|
||||||
|
}
|
||||||
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
|
||||||
|
if (finishedPlaying) {
|
||||||
|
if (soundPlayer!=nil) {
|
||||||
|
[soundPlayer release];
|
||||||
|
soundPlayer = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)stopSound:(id)sender {
|
||||||
|
if (soundPlayer!=nil) {
|
||||||
|
[soundPlayer stop];
|
||||||
|
[soundPlayer release];
|
||||||
|
soundPlayer = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)authorSite:(id)sender {
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *path = nil;
|
||||||
|
if (sender==SMSMessageAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSMSMessage];
|
||||||
|
else if (sender==voicemailAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSVoicemail];
|
||||||
|
else if (sender==SIPRingtoneAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPRingtone];
|
||||||
|
else if (sender==SIPHoldMusicAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPHoldMusic];
|
||||||
|
else if (sender==SIPConnectedAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPConnected];
|
||||||
|
else if (sender==SIPDisconnectedAuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPDisconnected];
|
||||||
|
else if (sender==SIPSound1AuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPSound1];
|
||||||
|
else if (sender==SIPSound2AuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPSound2];
|
||||||
|
else if (sender==SIPSound3AuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPSound3];
|
||||||
|
else if (sender==SIPSound4AuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPSound4];
|
||||||
|
else if (sender==SIPSound5AuthorButton)
|
||||||
|
path = [themeManager currentSoundPath:MGMTSSIPSound5];
|
||||||
|
if ([manager fileExistsAtPath:[[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]]) {
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:MGMTInfoPlist]];
|
||||||
|
if ([info objectForKey:MGMTSite]!=nil)
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[info objectForKey:MGMTSite]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)showBrowser:(id)sender {
|
||||||
|
[[browser mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://mrgeckosmedia.com/voicemac/sounds/"]]];
|
||||||
|
[browserWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
@end
|
101
Classes/VoiceMac/SIP/MGMSIPCallWindow.h
Normal file
101
Classes/VoiceMac/SIP/MGMSIPCallWindow.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPCallWindow.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/14/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMSIPCall, MGMSIPAccount, MGMSIPUser, MGMWhitePages, QTMovie;
|
||||||
|
|
||||||
|
@interface MGMSIPCallWindow : NSObject {
|
||||||
|
MGMSIPCall *call;
|
||||||
|
MGMSIPAccount *account;
|
||||||
|
MGMSIPUser *SIPUser;
|
||||||
|
MGMWhitePages *whitePages;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *incomingWindow;
|
||||||
|
IBOutlet NSTextField *phoneField;
|
||||||
|
IBOutlet NSTextField *nameField;
|
||||||
|
IBOutlet NSButton *answerButton;
|
||||||
|
IBOutlet NSButton *ignoreButton;
|
||||||
|
NSString *fullName;
|
||||||
|
NSString *phoneNumber;
|
||||||
|
|
||||||
|
NSSound *ringtone;
|
||||||
|
|
||||||
|
NSDate *startTime;
|
||||||
|
NSTimer *durationUpdater;
|
||||||
|
|
||||||
|
IBOutlet NSWindow *callWindow;
|
||||||
|
IBOutlet NSTextField *titleField;
|
||||||
|
IBOutlet NSTextField *durationField;
|
||||||
|
IBOutlet NSTextField *statusField;
|
||||||
|
IBOutlet NSSlider *volumeSlider;
|
||||||
|
IBOutlet NSSlider *micVolumeSlider;
|
||||||
|
IBOutlet NSButton *holdButton;
|
||||||
|
IBOutlet NSButton *showPadButton;
|
||||||
|
IBOutlet NSButton *hangUpButton;
|
||||||
|
|
||||||
|
IBOutlet NSView *numberPadView;
|
||||||
|
NSSize callWindowSize;
|
||||||
|
NSSize callWindowPadSize;
|
||||||
|
IBOutlet NSButton *recordingButton;
|
||||||
|
IBOutlet NSButton *muteMicrophoneButton;
|
||||||
|
IBOutlet NSButton *muteSpeakersButton;
|
||||||
|
IBOutlet NSButton *sound1Button;
|
||||||
|
IBOutlet NSButton *sound2Button;
|
||||||
|
IBOutlet NSButton *sound3Button;
|
||||||
|
IBOutlet NSButton *sound4Button;
|
||||||
|
IBOutlet NSButton *sound5Button;
|
||||||
|
IBOutlet NSButton *n1Button;
|
||||||
|
IBOutlet NSButton *n2Button;
|
||||||
|
IBOutlet NSButton *n3Button;
|
||||||
|
IBOutlet NSButton *n4Button;
|
||||||
|
IBOutlet NSButton *n5Button;
|
||||||
|
IBOutlet NSButton *n6Button;
|
||||||
|
IBOutlet NSButton *n7Button;
|
||||||
|
IBOutlet NSButton *n8Button;
|
||||||
|
IBOutlet NSButton *n9Button;
|
||||||
|
IBOutlet NSButton *n0Button;
|
||||||
|
IBOutlet NSButton *nStarButton;
|
||||||
|
IBOutlet NSButton *nPoundButton;
|
||||||
|
}
|
||||||
|
+ (id)windowWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser;
|
||||||
|
- (id)initWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser;
|
||||||
|
|
||||||
|
- (void)fillCallWindow;
|
||||||
|
- (IBAction)answer:(id)sender;
|
||||||
|
- (IBAction)ignore:(id)sender;
|
||||||
|
|
||||||
|
- (void)setTitle:(NSString *)theTitle;
|
||||||
|
|
||||||
|
- (IBAction)volume:(id)sender;
|
||||||
|
- (IBAction)micVolume:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)hold:(id)sender;
|
||||||
|
- (void)hidePad;
|
||||||
|
- (IBAction)showPad:(id)sender;
|
||||||
|
- (IBAction)hangUp:(id)sender;
|
||||||
|
|
||||||
|
- (IBAction)startRecording:(id)sender;
|
||||||
|
- (IBAction)muteMicrophone:(id)sender;
|
||||||
|
- (IBAction)muteSpeakers:(id)sender;
|
||||||
|
- (IBAction)sound:(id)sender;
|
||||||
|
- (IBAction)n1:(id)sender;
|
||||||
|
- (IBAction)n2:(id)sender;
|
||||||
|
- (IBAction)n3:(id)sender;
|
||||||
|
- (IBAction)n4:(id)sender;
|
||||||
|
- (IBAction)n5:(id)sender;
|
||||||
|
- (IBAction)n6:(id)sender;
|
||||||
|
- (IBAction)n7:(id)sender;
|
||||||
|
- (IBAction)n8:(id)sender;
|
||||||
|
- (IBAction)n9:(id)sender;
|
||||||
|
- (IBAction)n0:(id)sender;
|
||||||
|
- (IBAction)nStar:(id)sender;
|
||||||
|
- (IBAction)nPound:(id)sender;
|
||||||
|
@end
|
||||||
|
#endif
|
390
Classes/VoiceMac/SIP/MGMSIPCallWindow.m
Normal file
390
Classes/VoiceMac/SIP/MGMSIPCallWindow.m
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPCallWindow.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/14/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPCallWindow.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <QTKit/QTKit.h>
|
||||||
|
|
||||||
|
NSString * const MGMSCTitleFormat = @"Call With %@ %@";
|
||||||
|
NSString * const MGMSCTitleNoNameFormat = @"Call With %@";
|
||||||
|
|
||||||
|
@implementation MGMSIPCallWindow
|
||||||
|
+ (id)windowWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser {
|
||||||
|
return [[[self alloc] initWithCall:theCall SIPUser:theSIPUser] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SIPCallWindow" owner:self]) {
|
||||||
|
NSLog(@"Unable to load SIP Call Window!");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
call = [theCall retain];
|
||||||
|
[call setDelegate:self];
|
||||||
|
[call setHoldMusicPath:[[[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTCallSoundsFolder] stringByAppendingPathComponent:MGMTSSIPHoldMusic] stringByAppendingPathExtension:MGMWavExt]];
|
||||||
|
account = [call account];
|
||||||
|
SIPUser = theSIPUser;
|
||||||
|
[callWindow setLevel:NSNormalWindowLevel];
|
||||||
|
[callWindow setExcludedFromWindowsMenu:NO];
|
||||||
|
[[callWindow contentView] addSubview:numberPadView];
|
||||||
|
NSRect padFrame = [numberPadView frame];
|
||||||
|
callWindowSize = [callWindow frame].size;
|
||||||
|
callWindowPadSize = [callWindow frame].size;
|
||||||
|
padFrame.origin.y -= callWindowSize.height;
|
||||||
|
callWindowPadSize.height += padFrame.size.height;
|
||||||
|
[numberPadView setFrame:padFrame];
|
||||||
|
[incomingWindow setLevel:NSStatusWindowLevel];
|
||||||
|
[incomingWindow setExcludedFromWindowsMenu:YES];
|
||||||
|
|
||||||
|
BOOL autoAnswer = [SIPUser autoAnswer];
|
||||||
|
|
||||||
|
if ([call isIncoming] && !autoAnswer) {
|
||||||
|
if ([[[call remoteURL] userName] isPhone]) {
|
||||||
|
NSString *number = [[[call remoteURL] userName] phoneFormat];
|
||||||
|
phoneNumber = [[number readableNumber] copy];
|
||||||
|
[phoneField setStringValue:phoneNumber];
|
||||||
|
NSString *name = [[SIPUser contacts] nameForNumber:number];
|
||||||
|
if (name==nil || [name isEqual:phoneNumber]) {
|
||||||
|
whitePages = [MGMWhitePages new];
|
||||||
|
[whitePages reverseLookup:number delegate:self];
|
||||||
|
[nameField setStringValue:@"Loading..."];
|
||||||
|
} else {
|
||||||
|
fullName = [name copy];
|
||||||
|
[nameField setStringValue:fullName];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
phoneNumber = [[[call remoteURL] SIPAddress] copy];
|
||||||
|
[phoneField setStringValue:phoneNumber];
|
||||||
|
if ([[call remoteURL] fullName]!=nil && ![[[call remoteURL] fullName] isEqual:@""]) {
|
||||||
|
fullName = [[[call remoteURL] fullName] copy];
|
||||||
|
[nameField setStringValue:fullName];
|
||||||
|
} else {
|
||||||
|
[nameField setStringValue:@"Unknown"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[incomingWindow makeKeyAndOrderFront:self];
|
||||||
|
[call sendRingingNotification];
|
||||||
|
[self performSelectorOnMainThread:@selector(startRingtone) withObject:nil waitUntilDone:NO];
|
||||||
|
} else {
|
||||||
|
if ([[[call remoteURL] userName] isPhone]) {
|
||||||
|
NSString *number = [[[call remoteURL] userName] phoneFormat];
|
||||||
|
phoneNumber = [[number readableNumber] copy];
|
||||||
|
NSString *name = [[SIPUser contacts] nameForNumber:number];
|
||||||
|
if (name==nil || [name isEqual:phoneNumber]) {
|
||||||
|
whitePages = [MGMWhitePages new];
|
||||||
|
[whitePages reverseLookup:number delegate:self];
|
||||||
|
} else {
|
||||||
|
fullName = [name copy];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
phoneNumber = [[[call remoteURL] SIPAddress] copy];
|
||||||
|
if ([[call remoteURL] fullName]!=nil && ![[[call remoteURL] fullName] isEqual:@""])
|
||||||
|
fullName = [[[call remoteURL] fullName] copy];
|
||||||
|
}
|
||||||
|
[self fillCallWindow];
|
||||||
|
if (autoAnswer)
|
||||||
|
[call answer];
|
||||||
|
[callWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(soundChanged:) name:MGMTSoundChangedNotification object:nil];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(volumeChanged:) name:MGMSIPVolumeChangedNotification object:nil];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(micVolumeChanged:) name:MGMSIPMicVolumeChangedNotification object:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[self hidePad];
|
||||||
|
if (call!=nil) {
|
||||||
|
[call setDelegate:nil];
|
||||||
|
[call release];
|
||||||
|
}
|
||||||
|
if (whitePages!=nil)
|
||||||
|
[whitePages release];
|
||||||
|
if (incomingWindow!=nil)
|
||||||
|
[incomingWindow release];
|
||||||
|
if (callWindow!=nil)
|
||||||
|
[callWindow release];
|
||||||
|
if (fullName!=nil)
|
||||||
|
[fullName release];
|
||||||
|
if (phoneNumber!=nil)
|
||||||
|
[phoneNumber release];
|
||||||
|
if (ringtone!=nil) {
|
||||||
|
[ringtone stop];
|
||||||
|
[ringtone release];
|
||||||
|
}
|
||||||
|
if (startTime!=nil)
|
||||||
|
[startTime release];
|
||||||
|
if (durationUpdater!=nil) {
|
||||||
|
[durationUpdater invalidate];
|
||||||
|
[durationUpdater release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startRingtone {
|
||||||
|
NSString *ringtonePath = [[[SIPUser controller] themeManager] currentSoundPath:MGMTSSIPRingtone];
|
||||||
|
if (![ringtonePath isEqual:MGMTNoSound]) {
|
||||||
|
ringtone = [[NSSound alloc] initWithContentsOfFile:ringtonePath byReference:YES];
|
||||||
|
[ringtone setDelegate:self];
|
||||||
|
[ringtone play];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
|
||||||
|
if (finishedPlaying && sound==ringtone)
|
||||||
|
[ringtone play];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)disconnected:(MGMSIPCall *)theCall {
|
||||||
|
if (ringtone!=nil) {
|
||||||
|
[ringtone stop];
|
||||||
|
[ringtone release];
|
||||||
|
ringtone = nil;
|
||||||
|
}
|
||||||
|
if ([callWindow isVisible]) {
|
||||||
|
if (durationUpdater!=nil) {
|
||||||
|
[durationUpdater invalidate];
|
||||||
|
[durationUpdater release];
|
||||||
|
durationUpdater = nil;
|
||||||
|
}
|
||||||
|
if (startTime!=nil) {
|
||||||
|
[startTime release];
|
||||||
|
startTime = nil;
|
||||||
|
}
|
||||||
|
[statusField setStringValue:@"Disconnected"];
|
||||||
|
[[[SIPUser controller] themeManager] playSound:MGMTSSIPDisconnected];
|
||||||
|
} else {
|
||||||
|
if ([incomingWindow isVisible])
|
||||||
|
[incomingWindow close];
|
||||||
|
[SIPUser callDone:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)confirmed:(MGMSIPCall *)theCall {
|
||||||
|
[statusField setStringValue:@"Connected"];
|
||||||
|
[[[SIPUser controller] themeManager] playSound:MGMTSSIPConnected];
|
||||||
|
[self performSelectorOnMainThread:@selector(startDurationTimer) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
- (void)startDurationTimer {
|
||||||
|
startTime = [NSDate new];
|
||||||
|
durationUpdater = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateDuration) userInfo:nil repeats:YES] retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)soundChanged:(NSNotification *)theNotification {
|
||||||
|
if ([[theNotification object] isEqual:MGMTSSIPSound1])
|
||||||
|
[sound1Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound1]];
|
||||||
|
if ([[theNotification object] isEqual:MGMTSSIPSound2])
|
||||||
|
[sound2Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound2]];
|
||||||
|
if ([[theNotification object] isEqual:MGMTSSIPSound3])
|
||||||
|
[sound3Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound3]];
|
||||||
|
if ([[theNotification object] isEqual:MGMTSSIPSound4])
|
||||||
|
[sound4Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound4]];
|
||||||
|
if ([[theNotification object] isEqual:MGMTSSIPSound5])
|
||||||
|
[sound5Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound5]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fillCallWindow {
|
||||||
|
if (fullName==nil)
|
||||||
|
[self setTitle:[NSString stringWithFormat:MGMSCTitleNoNameFormat, phoneNumber]];
|
||||||
|
else
|
||||||
|
[self setTitle:[NSString stringWithFormat:MGMSCTitleFormat, fullName, phoneNumber]];
|
||||||
|
[durationField setStringValue:[NSString stringWithSeconds:0]];
|
||||||
|
[volumeSlider setFloatValue:[[MGMSIP sharedSIP] volume]];
|
||||||
|
[micVolumeSlider setFloatValue:[[MGMSIP sharedSIP] micVolume]];
|
||||||
|
if ([call state]!=MGMSIPCallConfirmedState)
|
||||||
|
[statusField setStringValue:@"Connecting..."];
|
||||||
|
else
|
||||||
|
[self confirmed:call];
|
||||||
|
|
||||||
|
[sound1Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound1]];
|
||||||
|
[sound2Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound2]];
|
||||||
|
[sound3Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound3]];
|
||||||
|
[sound4Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound4]];
|
||||||
|
[sound5Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound5]];
|
||||||
|
}
|
||||||
|
- (IBAction)answer:(id)sender {
|
||||||
|
if (ringtone!=nil) {
|
||||||
|
[ringtone stop];
|
||||||
|
[ringtone release];
|
||||||
|
ringtone = nil;
|
||||||
|
}
|
||||||
|
[incomingWindow close];
|
||||||
|
[call answer];
|
||||||
|
[self fillCallWindow];
|
||||||
|
[callWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (IBAction)ignore:(id)sender {
|
||||||
|
if (ringtone!=nil) {
|
||||||
|
[ringtone stop];
|
||||||
|
[ringtone release];
|
||||||
|
ringtone = nil;
|
||||||
|
}
|
||||||
|
[incomingWindow close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateDuration {
|
||||||
|
int time = [[NSDate date] timeIntervalSinceDate:startTime];
|
||||||
|
[durationField setStringValue:[NSString stringWithSeconds:time]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitle:(NSString *)theTitle {
|
||||||
|
[titleField setStringValue:theTitle];
|
||||||
|
[callWindow setTitle:theTitle];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)volumeChanged:(NSNotification *)theNotification {
|
||||||
|
[volumeSlider setFloatValue:[[theNotification object] floatValue]];
|
||||||
|
}
|
||||||
|
- (IBAction)volume:(id)sender {
|
||||||
|
[[MGMSIP sharedSIP] setVolume:[volumeSlider floatValue]];
|
||||||
|
}
|
||||||
|
- (void)micVolumeChanged:(NSNotification *)theNotification {
|
||||||
|
[micVolumeSlider setFloatValue:[[theNotification object] floatValue]];
|
||||||
|
}
|
||||||
|
- (IBAction)micVolume:(id)sender {
|
||||||
|
[[MGMSIP sharedSIP] setMicVolume:[micVolumeSlider floatValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)hold:(id)sender {
|
||||||
|
[call hold];
|
||||||
|
[holdButton setImage:[NSImage imageNamed:([call isLocalOnHold] ? @"unholdButton" : @"holdButton")]];
|
||||||
|
}
|
||||||
|
- (void)hidePad {
|
||||||
|
if (NSEqualSizes([callWindow frame].size, callWindowPadSize)) {
|
||||||
|
NSRect frame = [callWindow frame];
|
||||||
|
frame.origin.y -= callWindowSize.height-frame.size.height;
|
||||||
|
frame.size = callWindowSize;
|
||||||
|
[callWindow setFrame:frame display:NO animate:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)showPad:(id)sender {
|
||||||
|
if (NSEqualSizes([callWindow frame].size, callWindowSize)) {
|
||||||
|
NSRect frame = [callWindow frame];
|
||||||
|
frame.origin.y -= callWindowPadSize.height-frame.size.height;
|
||||||
|
frame.size = callWindowPadSize;
|
||||||
|
[callWindow setFrame:frame display:YES animate:YES];
|
||||||
|
} else {
|
||||||
|
NSRect frame = [callWindow frame];
|
||||||
|
frame.origin.y -= callWindowSize.height-frame.size.height;
|
||||||
|
frame.size = callWindowSize;
|
||||||
|
[callWindow setFrame:frame display:YES animate:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)hangUp:(id)sender {
|
||||||
|
[callWindow close];
|
||||||
|
if (durationUpdater!=nil) {
|
||||||
|
[durationUpdater invalidate];
|
||||||
|
[durationUpdater release];
|
||||||
|
durationUpdater = nil;
|
||||||
|
}
|
||||||
|
if (startTime!=nil) {
|
||||||
|
[startTime release];
|
||||||
|
startTime = nil;
|
||||||
|
}
|
||||||
|
[call hangUp];
|
||||||
|
[SIPUser callDone:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)startRecording:(id)sender {
|
||||||
|
if ([call isRecording]) {
|
||||||
|
[call stopRecording];
|
||||||
|
} else {
|
||||||
|
NSFileManager *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *baseName = [[NSString stringWithFormat:@"~/Desktop/Call With %@ - ", phoneNumber] stringByExpandingTildeInPath];
|
||||||
|
NSString *name = nil;
|
||||||
|
for (int i=1; i<50; i++) { // Not like someone will have 50 recordings with one person on their desktop...
|
||||||
|
name = [[baseName stringByAppendingFormat:@"%02d", i] stringByAppendingPathExtension:MGMWavExt];
|
||||||
|
if (![manager fileExistsAtPath:name])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[call startRecording:name];
|
||||||
|
}
|
||||||
|
[recordingButton setTitle:([call isRecording] ? @"Stop Recording" : @"Start Recording")];
|
||||||
|
}
|
||||||
|
- (IBAction)muteMicrophone:(id)sender {
|
||||||
|
[call muteMic];
|
||||||
|
[muteMicrophoneButton setTitle:([call isMicMuted] ? @"Unmute Microphone" : @"Mute Microphone")];
|
||||||
|
}
|
||||||
|
- (IBAction)muteSpeakers:(id)sender {
|
||||||
|
[call mute];
|
||||||
|
[muteSpeakersButton setTitle:([call isMuted] ? @"Unmute Speakers" : @"Mute Speakers")];
|
||||||
|
}
|
||||||
|
- (IBAction)sound:(id)sender {
|
||||||
|
NSString *soundName = nil;
|
||||||
|
if (sender==sound1Button)
|
||||||
|
soundName = MGMTSSIPSound1;
|
||||||
|
else if (sender==sound2Button)
|
||||||
|
soundName = MGMTSSIPSound2;
|
||||||
|
else if (sender==sound3Button)
|
||||||
|
soundName = MGMTSSIPSound3;
|
||||||
|
else if (sender==sound4Button)
|
||||||
|
soundName = MGMTSSIPSound4;
|
||||||
|
else if (sender==sound5Button)
|
||||||
|
soundName = MGMTSSIPSound5;
|
||||||
|
NSString *soundFile = [[[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTCallSoundsFolder] stringByAppendingPathComponent:soundName] stringByAppendingPathExtension:MGMWavExt];
|
||||||
|
[call playSound:soundFile];
|
||||||
|
[[[SIPUser controller] themeManager] performSelector:@selector(playSound:) withObject:soundName afterDelay:0.2]; // The phone has a delay, so why not delay this so you hear it at the same time?
|
||||||
|
}
|
||||||
|
- (IBAction)n1:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"1"];
|
||||||
|
}
|
||||||
|
- (IBAction)n2:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"2"];
|
||||||
|
}
|
||||||
|
- (IBAction)n3:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"3"];
|
||||||
|
}
|
||||||
|
- (IBAction)n4:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"4"];
|
||||||
|
}
|
||||||
|
- (IBAction)n5:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"5"];
|
||||||
|
}
|
||||||
|
- (IBAction)n6:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"6"];
|
||||||
|
}
|
||||||
|
- (IBAction)n7:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"7"];
|
||||||
|
}
|
||||||
|
- (IBAction)n8:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"8"];
|
||||||
|
}
|
||||||
|
- (IBAction)n9:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"9"];
|
||||||
|
}
|
||||||
|
- (IBAction)n0:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"0"];
|
||||||
|
}
|
||||||
|
- (IBAction)nStar:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"*"];
|
||||||
|
}
|
||||||
|
- (IBAction)nPound:(id)sender {
|
||||||
|
[call sendDTMFDigits:@"#"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseLookupDidFindInfo:(NSDictionary *)theInfo forRequest:(NSDictionary *)theRequest {
|
||||||
|
if ([theInfo objectForKey:MGMWPName]!=nil) {
|
||||||
|
fullName = [[theInfo objectForKey:MGMWPName] copy];
|
||||||
|
if ([callWindow isVisible])
|
||||||
|
[self setTitle:[NSString stringWithFormat:MGMSCTitleFormat, fullName, phoneNumber]];
|
||||||
|
else
|
||||||
|
[nameField setStringValue:fullName];
|
||||||
|
} else if ([theInfo objectForKey:MGMWPLocation]!=nil) {
|
||||||
|
if ([incomingWindow isVisible])
|
||||||
|
[nameField setStringValue:[theInfo objectForKey:MGMWPLocation]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
48
Classes/VoiceMac/SIP/MGMSIPUser.h
Normal file
48
Classes/VoiceMac/SIP/MGMSIPUser.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPUser.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "MGMContactsController.h"
|
||||||
|
|
||||||
|
@class MGMUser, MGMContacts, MGMProgressView, MGMSIPAccount, MGMSIPCall, MGMSIPCallWindow;
|
||||||
|
|
||||||
|
extern NSString * const MGMSIPUserAreaCode;
|
||||||
|
|
||||||
|
@interface MGMSIPUser : MGMContactsController {
|
||||||
|
MGMUser *user;
|
||||||
|
MGMSIPAccount *account;
|
||||||
|
NSMutableArray *calls;
|
||||||
|
MGMContacts *contacts;
|
||||||
|
|
||||||
|
BOOL loggingIn;
|
||||||
|
BOOL acountRegistered;
|
||||||
|
NSTimer *SIPRegistrationTimeout;
|
||||||
|
|
||||||
|
MGMProgressView *progressView;
|
||||||
|
NSViewAnimation *progressFadeAnimation;
|
||||||
|
|
||||||
|
IBOutlet NSButton *callButton;
|
||||||
|
IBOutlet NSTextField *userNameField;
|
||||||
|
}
|
||||||
|
+ (id)SIPUser:(MGMUser *)theUser controller:(MGMController *)theController;
|
||||||
|
- (id)initUser:(MGMUser *)theUser controller:(MGMController *)theController;
|
||||||
|
|
||||||
|
- (void)registerSettings;
|
||||||
|
|
||||||
|
- (MGMUser *)user;
|
||||||
|
- (NSArray *)calls;
|
||||||
|
|
||||||
|
- (void)removeLoginProgress;
|
||||||
|
- (void)loginErrored;
|
||||||
|
|
||||||
|
- (BOOL)autoAnswer;
|
||||||
|
- (void)gotNewCall:(MGMSIPCall *)theCall;
|
||||||
|
- (void)callDone:(MGMSIPCallWindow *)theCall;
|
||||||
|
@end
|
||||||
|
#endif
|
255
Classes/VoiceMac/SIP/MGMSIPUser.m
Normal file
255
Classes/VoiceMac/SIP/MGMSIPUser.m
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPUser.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#if MGMSIPENABLED
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import "MGMSIPCallWindow.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMProgressView.h"
|
||||||
|
#import "MGMPhoneFeild.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
NSString * const MGMSIPUserAreaCode = @"MGMVSIPUserAreaCode";
|
||||||
|
|
||||||
|
@implementation MGMSIPUser
|
||||||
|
+ (id)SIPUser:(MGMUser *)theUser controller:(MGMController *)theController {
|
||||||
|
return [[[self alloc] initUser:theUser controller:theController] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initUser:(MGMUser *)theUser controller:(MGMController *)theController {
|
||||||
|
if (self = [super initWithController:theController]) {
|
||||||
|
user = [theUser retain];
|
||||||
|
[user setDelegate:self];
|
||||||
|
[self registerSettings];
|
||||||
|
account = [[MGMSIPAccount alloc] initWithSettings:[user settings]];
|
||||||
|
[account setDelegate:self];
|
||||||
|
calls = [NSMutableArray new];
|
||||||
|
loggingIn = YES;
|
||||||
|
acountRegistered = NO;
|
||||||
|
[NSThread detachNewThreadSelector:@selector(login) toTarget:account withObject:nil];
|
||||||
|
contacts = [[MGMContacts contactsWithClass:NSClassFromString([user settingForKey:MGMSContactsSourceKey]) delegate:self] retain];
|
||||||
|
[contacts updateContacts];
|
||||||
|
if ([[user settingForKey:MGMContactsWindowOpen] boolValue])
|
||||||
|
[self showContactsWindow];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[contactsWindow setFrameAutosaveName:[@"contactsWindow" stringByAppendingString:[user settingForKey:MGMUserID]]];
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
NSString *userName = [user settingForKey:MGMUserName];
|
||||||
|
if ([userName isPhoneComplete])
|
||||||
|
userName = [userName readableNumber];
|
||||||
|
else if ([user settingForKey:MGMSIPAccountFullName]!=nil && ![[user settingForKey:MGMSIPAccountFullName] isEqual:@""])
|
||||||
|
userName = [user settingForKey:MGMSIPAccountFullName];
|
||||||
|
[userNameField setStringValue:userName];
|
||||||
|
|
||||||
|
if (![account isLoggedIn]) {
|
||||||
|
NSSize contentSize = [[contactsWindow contentView] frame].size;
|
||||||
|
progressView = [[MGMProgressView alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)];
|
||||||
|
[progressView setProgressTitle:@"Logging In"];
|
||||||
|
[[contactsWindow contentView] addSubview:progressView];
|
||||||
|
[progressView startProgess];
|
||||||
|
[contactsWindow makeFirstResponder:progressView];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[super dealloc];
|
||||||
|
if (contacts!=nil) {
|
||||||
|
[contacts stop];
|
||||||
|
[contacts release];
|
||||||
|
}
|
||||||
|
if (user!=nil)
|
||||||
|
[user release];
|
||||||
|
if (account!=nil) {
|
||||||
|
[account setDelegate:nil];
|
||||||
|
[account logout];
|
||||||
|
[account release];
|
||||||
|
}
|
||||||
|
if (calls!=nil) {
|
||||||
|
[calls removeAllObjects];
|
||||||
|
[calls release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerSettings {
|
||||||
|
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
|
||||||
|
[settings setObject:NSStringFromClass([MGMAddressBook class]) forKey:MGMSContactsSourceKey];
|
||||||
|
[settings setObject:[NSNumber numberWithBool:YES] forKey:MGMContactsWindowOpen];
|
||||||
|
[user registerSettings:settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)menuTitle {
|
||||||
|
NSString *userName = [user settingForKey:MGMUserName];
|
||||||
|
if ([user settingForKey:MGMSIPAccountFullName]!=nil && ![[user settingForKey:MGMSIPAccountFullName] isEqual:@""])
|
||||||
|
userName = [user settingForKey:MGMSIPAccountFullName];
|
||||||
|
if ([userName isPhone])
|
||||||
|
userName = [userName readableNumber];
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
- (void)showContactsWindow {
|
||||||
|
if (contactsWindow==nil) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SIPUser" owner:self]) {
|
||||||
|
NSLog(@"Error: Unable to load SIP User!");
|
||||||
|
} else {
|
||||||
|
[user setSetting:[NSNumber numberWithBool:YES] forKey:MGMContactsWindowOpen];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[contactsWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (MGMUser *)user {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
- (NSArray *)calls {
|
||||||
|
return calls;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)password {
|
||||||
|
return [user password];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registrationChanged {
|
||||||
|
if (SIPRegistrationTimeout!=nil) {
|
||||||
|
[SIPRegistrationTimeout invalidate];
|
||||||
|
[SIPRegistrationTimeout release];
|
||||||
|
SIPRegistrationTimeout = nil;
|
||||||
|
}
|
||||||
|
if (!acountRegistered) {
|
||||||
|
if (![account isRegistered]) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error logging in"];
|
||||||
|
[theAlert setInformativeText:@"Unable to Register with Server. Please check your credentials."];
|
||||||
|
[theAlert runModal];
|
||||||
|
}
|
||||||
|
acountRegistered = YES;
|
||||||
|
[self performSelectorOnMainThread:@selector(removeLoginProgress) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)loggedIn {
|
||||||
|
loggingIn = NO;
|
||||||
|
[self performSelectorOnMainThread:@selector(startRegistrationTimeoutTimer) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
- (void)startRegistrationTimeoutTimer {
|
||||||
|
if (!acountRegistered)
|
||||||
|
SIPRegistrationTimeout = [[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(SIPTimeout) userInfo:nil repeats:NO] retain];
|
||||||
|
}
|
||||||
|
- (void)SIPTimeout {
|
||||||
|
if (SIPRegistrationTimeout!=nil) {
|
||||||
|
[SIPRegistrationTimeout invalidate];
|
||||||
|
[SIPRegistrationTimeout release];
|
||||||
|
SIPRegistrationTimeout = nil;
|
||||||
|
}
|
||||||
|
[account setLastError:@"Registration Timeout."];
|
||||||
|
[self loginErrored];
|
||||||
|
}
|
||||||
|
- (void)removeLoginProgress {
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView stopProgess];
|
||||||
|
[progressView display];
|
||||||
|
|
||||||
|
NSMutableDictionary *animationInfo = [NSMutableDictionary dictionary];
|
||||||
|
[animationInfo setObject:progressView forKey:NSViewAnimationTargetKey];
|
||||||
|
[animationInfo setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
|
||||||
|
progressFadeAnimation = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:animationInfo]];
|
||||||
|
[progressFadeAnimation setDuration:1.0];
|
||||||
|
[progressFadeAnimation setDelegate:self];
|
||||||
|
[progressFadeAnimation startAnimation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)loginErrored {
|
||||||
|
loggingIn = NO;
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error logging in"];
|
||||||
|
[theAlert setInformativeText:[account lastError]];
|
||||||
|
[theAlert runModal];
|
||||||
|
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView stopProgess];
|
||||||
|
[progressView removeFromSuperview];
|
||||||
|
[progressView release];
|
||||||
|
progressView = nil;
|
||||||
|
}
|
||||||
|
[self performSelectorOnMainThread:@selector(removeLoginProgress) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
- (void)logoutErrored {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error logging out"];
|
||||||
|
[theAlert setInformativeText:[account lastError]];
|
||||||
|
[theAlert runModal];
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)animationDidEnd:(NSAnimation *)animation {
|
||||||
|
if (progressFadeAnimation!=nil) {
|
||||||
|
[progressFadeAnimation release];
|
||||||
|
progressFadeAnimation = nil;
|
||||||
|
}
|
||||||
|
if (progressView!=nil) {
|
||||||
|
[progressView removeFromSuperview];
|
||||||
|
[progressView release];
|
||||||
|
progressView = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMContacts *)contacts {
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadData {
|
||||||
|
[super reloadData];
|
||||||
|
if (progressView!=nil) [progressView display];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)areaCode {
|
||||||
|
return [user settingForKey:MGMSIPUserAreaCode];
|
||||||
|
}
|
||||||
|
- (IBAction)runAction:(id)sender {
|
||||||
|
[self call:sender];
|
||||||
|
}
|
||||||
|
- (IBAction)call:(id)sender {
|
||||||
|
NSString *phoneNumber = [controller currentPhoneNumber];
|
||||||
|
if (phoneNumber==nil || [phoneNumber isEqual:@""]) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[account makeCallToNumber:phoneNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)autoAnswer {
|
||||||
|
for (int i=0; i<[[controller contactsControllers] count]; i++) {
|
||||||
|
if ([[[controller contactsControllers] objectAtIndex:i] isKindOfClass:[MGMVoiceUser class]] && [[[controller contactsControllers] objectAtIndex:i] isPlacingCall])
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
- (void)gotNewCall:(MGMSIPCall *)theCall {
|
||||||
|
[calls addObject:[MGMSIPCallWindow windowWithCall:theCall SIPUser:self]];
|
||||||
|
}
|
||||||
|
- (void)callDone:(MGMSIPCallWindow *)theCall {
|
||||||
|
[calls removeObject:theCall];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isUserDone:(MGMUser *)theUser {
|
||||||
|
return !loggingIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
if (![controller isQuitting])
|
||||||
|
[user setSetting:[NSNumber numberWithBool:NO] forKey:MGMContactsWindowOpen];
|
||||||
|
[super windowWillClose:notification];
|
||||||
|
if (progressFadeAnimation!=nil) {
|
||||||
|
[progressFadeAnimation stopAnimation];
|
||||||
|
[progressFadeAnimation release];
|
||||||
|
progressFadeAnimation = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
#endif
|
21
Classes/VoiceMac/SIP/MGMSIPWavConverter.h
Normal file
21
Classes/VoiceMac/SIP/MGMSIPWavConverter.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPWavConverter.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class QTMovie;
|
||||||
|
|
||||||
|
@interface MGMSIPWavConverter : NSObject {
|
||||||
|
NSString *fileConverting;
|
||||||
|
NSString *soundName;
|
||||||
|
QTMovie *movie;
|
||||||
|
NSThread *backgroundThread;
|
||||||
|
BOOL cancel;
|
||||||
|
}
|
||||||
|
- (id)initWithSoundName:(NSString *)theSoundname fileConverting:(NSString *)theFile;
|
||||||
|
@end
|
97
Classes/VoiceMac/SIP/MGMSIPWavConverter.m
Normal file
97
Classes/VoiceMac/SIP/MGMSIPWavConverter.m
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// MGMSIPWavConverter.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSIPWavConverter.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <QTKit/QTKit.h>
|
||||||
|
|
||||||
|
@implementation MGMSIPWavConverter
|
||||||
|
- (id)initWithSoundName:(NSString *)theSoundname fileConverting:(NSString *)theFile {
|
||||||
|
if (self = [super init]) {
|
||||||
|
fileConverting = [theFile copy];
|
||||||
|
soundName = [theSoundname copy];
|
||||||
|
cancel = NO;
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self selector:@selector(soundChanged:) name:MGMTSoundChangedNotification object:nil];
|
||||||
|
movie = [[QTMovie movieWithFile:fileConverting error:NULL] retain];
|
||||||
|
if (movie==nil) {
|
||||||
|
NSLog(@"Unable to open audio %@", fileConverting);
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else if ([[movie attributeForKey:QTMovieLoadStateAttribute] longValue]==2000 || [[movie attributeForKey:QTMovieLoadStateAttribute] longValue]==100000L) {
|
||||||
|
[NSThread detachNewThreadSelector:@selector(convertBackground) toTarget:self withObject:nil];
|
||||||
|
} else {
|
||||||
|
[notificationCenter addObserver:self selector:@selector(movieLoadStateChanged:) name:QTMovieLoadStateDidChangeNotification object:movie];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (fileConverting!=nil)
|
||||||
|
[fileConverting release];
|
||||||
|
if (soundName!=nil)
|
||||||
|
[soundName release];
|
||||||
|
if (movie!=nil)
|
||||||
|
[movie release];
|
||||||
|
if (backgroundThread!=nil) {
|
||||||
|
while (backgroundThread!=nil) [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)soundChanged:(NSNotification *)theNotification {
|
||||||
|
if ([[theNotification object] isEqual:soundName]) {
|
||||||
|
cancel = YES;
|
||||||
|
[self release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)movieLoadStateChanged:(NSNotification *)theNotification {
|
||||||
|
if ([[movie attributeForKey:QTMovieLoadStateAttribute] longValue]==2000 || [[movie attributeForKey:QTMovieLoadStateAttribute] longValue]==100000L)
|
||||||
|
[NSThread detachNewThreadSelector:@selector(convertBackground) toTarget:self withObject:nil];
|
||||||
|
}
|
||||||
|
- (void)convertBackground {
|
||||||
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||||
|
backgroundThread = [[NSThread currentThread] retain];
|
||||||
|
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
|
||||||
|
NSFileManager<NSFileManagerProtocol> *manager = [NSFileManager defaultManager];
|
||||||
|
NSString *finalPath = [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTCallSoundsFolder];
|
||||||
|
if (![manager fileExistsAtPath:finalPath]) {
|
||||||
|
if ([manager respondsToSelector:@selector(createDirectoryAtPath:attributes:)])
|
||||||
|
[manager createDirectoryAtPath:finalPath attributes:nil];
|
||||||
|
else
|
||||||
|
[manager createDirectoryAtPath:finalPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
}
|
||||||
|
finalPath = [finalPath stringByAppendingPathComponent:soundName];
|
||||||
|
NSString *convertFinalPath = [[finalPath stringByAppendingPathExtension:@".tmp"] stringByAppendingPathExtension:MGMWavExt];
|
||||||
|
finalPath = [finalPath stringByAppendingPathExtension:MGMWavExt];
|
||||||
|
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieExport, [NSNumber numberWithLong:kQTFileTypeWave], QTMovieExportType, [NSNumber numberWithLong:SoundMediaType], QTMovieExportManufacturer, nil];
|
||||||
|
if (!cancel) {
|
||||||
|
if (![movie writeToFile:convertFinalPath withAttributes:dictionary])
|
||||||
|
NSLog(@"Could not convert audio %@", fileConverting);
|
||||||
|
}
|
||||||
|
if ([manager fileExistsAtPath:finalPath]) {
|
||||||
|
if ([manager respondsToSelector:@selector(removeFileAtPath:)])
|
||||||
|
[manager removeFileAtPath:finalPath handler:nil];
|
||||||
|
else
|
||||||
|
[manager removeItemAtPath:finalPath error:nil];
|
||||||
|
}
|
||||||
|
if (!cancel) {
|
||||||
|
if ([manager respondsToSelector:@selector(movePath:toPath:handler:)])
|
||||||
|
[manager movePath:convertFinalPath toPath:finalPath handler:nil];
|
||||||
|
else
|
||||||
|
[manager moveItemAtPath:convertFinalPath toPath:finalPath error:nil];
|
||||||
|
}
|
||||||
|
[pool drain];
|
||||||
|
[backgroundThread release];
|
||||||
|
backgroundThread = nil;
|
||||||
|
if (!cancel)
|
||||||
|
[self release];
|
||||||
|
}
|
||||||
|
@end
|
34
Classes/VoiceMac/SMS/MGMMultiSMS.h
Normal file
34
Classes/VoiceMac/SMS/MGMMultiSMS.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// MGMMultiSMS.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/30/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMInstance, MGMController, MGMSMSTextView;
|
||||||
|
|
||||||
|
@interface MGMMultiSMS : NSObject {
|
||||||
|
MGMInstance *instance;
|
||||||
|
MGMController *controller;
|
||||||
|
IBOutlet NSWindow *SMSWindow;
|
||||||
|
IBOutlet NSPopUpButton *groupsPopUp;
|
||||||
|
IBOutlet NSTokenField *additionalField;
|
||||||
|
IBOutlet MGMSMSTextView *SMSTextView;
|
||||||
|
IBOutlet NSButton *sendButton;
|
||||||
|
IBOutlet NSButton *cancelButton;
|
||||||
|
|
||||||
|
BOOL sendingMessage;
|
||||||
|
}
|
||||||
|
+ (id)SMSWithInstance:(MGMInstance *)theInstance controller:(MGMController *)theController;
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance controller:(MGMController *)theController;
|
||||||
|
|
||||||
|
- (MGMInstance *)instance;
|
||||||
|
- (MGMController *)controller;
|
||||||
|
- (NSWindow *)SMSWindow;
|
||||||
|
|
||||||
|
- (IBAction)sendMessage:(id)sender;
|
||||||
|
- (IBAction)cancel:(id)sender;
|
||||||
|
@end
|
155
Classes/VoiceMac/SMS/MGMMultiSMS.m
Normal file
155
Classes/VoiceMac/SMS/MGMMultiSMS.m
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
//
|
||||||
|
// MGMMultiSMS.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/30/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMMultiSMS.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import "MGMSMSTextView.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
|
||||||
|
@implementation MGMMultiSMS
|
||||||
|
+ (id)SMSWithInstance:(MGMInstance *)theInstance controller:(MGMController *)theController {
|
||||||
|
return [[[self alloc] initWithInstance:theInstance controller:theController] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithInstance:(MGMInstance *)theInstance controller:(MGMController *)theController {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"MultiSMS" owner:self]) {
|
||||||
|
NSLog(@"Unable to load Multiple SMS Window.");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
instance = theInstance;
|
||||||
|
controller = theController;
|
||||||
|
[SMSWindow setFrameAutosaveName:[@"multipleSMS" stringByAppendingString:[[instance user] settingForKey:MGMUserID]]];
|
||||||
|
[SMSWindow setTitle:[NSString stringWithFormat:@"%@ (%@)", [SMSWindow title], [[instance userNumber] readableNumber]]];
|
||||||
|
NSArray *groups = [[instance contacts] groups];
|
||||||
|
NSMenu *menu = [[NSMenu new] autorelease];
|
||||||
|
NSMenuItem *noneMenuItem = [[NSMenuItem new] autorelease];
|
||||||
|
[noneMenuItem setTitle:@"None"];
|
||||||
|
[noneMenuItem setTag:-1];
|
||||||
|
[menu addItem:noneMenuItem];
|
||||||
|
if ([groups count]>0) {
|
||||||
|
[menu addItem:[NSMenuItem separatorItem]];
|
||||||
|
for (int i=0; i<[groups count]; i++) {
|
||||||
|
NSDictionary *group = [groups objectAtIndex:i];
|
||||||
|
NSMenuItem *item = [[NSMenuItem new] autorelease];
|
||||||
|
[item setTitle:[NSString stringWithFormat:@"%@ (%@)", [group objectForKey:MGMCName], [[instance contacts] membersCountOfGroup:group]]];
|
||||||
|
[item setTag:[[group objectForKey:MGMCDocID] longValue]];
|
||||||
|
[menu addItem:item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[groupsPopUp setMenu:menu];
|
||||||
|
[SMSWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMInstance *)instance {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
- (MGMController *)controller {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
- (NSWindow *)SMSWindow {
|
||||||
|
return SMSWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(NSInteger *)selectedIndex {
|
||||||
|
return [[instance contacts] contactCompletionsMatching:substring];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)sendMessage:(id)sender {
|
||||||
|
NSMutableArray *SMSNumbers = [NSMutableArray array];
|
||||||
|
if ([[groupsPopUp selectedItem] tag]!=-1) {
|
||||||
|
NSArray *members = [[instance contacts] membersOfGroupID:[NSNumber numberWithInt:[[groupsPopUp selectedItem] tag]]];
|
||||||
|
for (unsigned int i=0; i<[members count]; i++) {
|
||||||
|
[SMSNumbers addObject:[[members objectAtIndex:i] objectForKey:MGMCNumber]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (![[[additionalField stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqual:@""]) {
|
||||||
|
NSArray *numbers = [[additionalField stringValue] componentsSeparatedByString:@","];
|
||||||
|
for (unsigned int i=0; i<[numbers count]; i++) {
|
||||||
|
NSString *number = [numbers objectAtIndex:i];
|
||||||
|
if ([number containsString:@"<"]) {
|
||||||
|
NSRange range = [number rangeOfString:@"<"];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
NSString *string = [number substringFromIndex:range.location+range.length];
|
||||||
|
range = [string rangeOfString:@">"];
|
||||||
|
if (range.location==NSNotFound) {
|
||||||
|
NSLog(@"failed 0017");
|
||||||
|
} else {
|
||||||
|
number = [[string substringWithRange:NSMakeRange(0, range.location)] phoneFormat];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ([number hasPrefix:@"("]) {
|
||||||
|
number = [number phoneFormatWithAreaCode:[instance userAreaCode]];
|
||||||
|
} else {
|
||||||
|
NSRange range = [number rangeOfString:@"("];
|
||||||
|
if (range.location!=NSNotFound) {
|
||||||
|
number = [number substringToIndex:range.location-1];
|
||||||
|
}
|
||||||
|
number = [number phoneFormatWithAreaCode:[instance userAreaCode]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[SMSNumbers addObject:number];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ([SMSNumbers count]<=0) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:@"You need to at least have 1 contact to send to."];
|
||||||
|
[theAlert runModal];
|
||||||
|
} else {
|
||||||
|
if ([[SMSTextView string] isEqual:@""])
|
||||||
|
return;
|
||||||
|
sendingMessage = YES;
|
||||||
|
[sendButton setTitle:@"Sending..."];
|
||||||
|
[sendButton setEnabled:NO];
|
||||||
|
[cancelButton setEnabled:NO];
|
||||||
|
[[instance inbox] sendMessage:[SMSTextView string] phoneNumbers:SMSNumbers smsID:@"" delegate:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)message:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
sendingMessage = NO;
|
||||||
|
[SMSTextView setEditable:YES];
|
||||||
|
[sendButton setTitle:@"Send"];
|
||||||
|
[sendButton setEnabled:YES];
|
||||||
|
[cancelButton setEnabled:YES];
|
||||||
|
[SMSWindow makeFirstResponder:SMSTextView];
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert addButtonWithTitle:@"Ok"];
|
||||||
|
[theAlert setMessageText:@"Error sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert setAlertStyle:2];
|
||||||
|
[theAlert runModal];
|
||||||
|
}
|
||||||
|
- (void)messageDidFinish:(NSDictionary *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
sendingMessage = NO;
|
||||||
|
[SMSWindow close];
|
||||||
|
}
|
||||||
|
- (IBAction)cancel:(id)sender {
|
||||||
|
[SMSWindow close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)windowShouldClose:(id)sender {
|
||||||
|
if (sendingMessage) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:@"Your SMS Message is currently being sent, please wait for it to be sent."];
|
||||||
|
[theAlert runModal];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
[SMSWindow setDelegate:nil];
|
||||||
|
[controller removeMultiSMS:self];
|
||||||
|
}
|
||||||
|
@end
|
43
Classes/VoiceMac/SMS/MGMSMSManager.h
Normal file
43
Classes/VoiceMac/SMS/MGMSMSManager.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSManager.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMController, MGMSplitView, MGMThemeManager, MGMInstance, MGMSMSMessageView;
|
||||||
|
|
||||||
|
@interface MGMSMSManager : NSObject {
|
||||||
|
MGMController *controller;
|
||||||
|
IBOutlet NSWindow *SMSWindow;
|
||||||
|
IBOutlet MGMSplitView *splitView;
|
||||||
|
IBOutlet NSView *messageView;
|
||||||
|
IBOutlet NSTableView *messagesTable;
|
||||||
|
NSMutableArray *SMSMessages;
|
||||||
|
NSMutableDictionary *lastDates;
|
||||||
|
NSTimer *updateTimer;
|
||||||
|
|
||||||
|
float rightMax;
|
||||||
|
float leftMax;
|
||||||
|
}
|
||||||
|
+ (id)managerWithController:(MGMController *)theController;
|
||||||
|
- (id)initWithController:(MGMController *)theController;
|
||||||
|
|
||||||
|
- (NSWindow *)SMSWindow;
|
||||||
|
- (MGMController *)controller;
|
||||||
|
- (MGMThemeManager *)themeManager;
|
||||||
|
- (NSMutableArray *)SMSMessages;
|
||||||
|
|
||||||
|
- (IBAction)showWindow:(id)sender;
|
||||||
|
|
||||||
|
- (void)reloadData;
|
||||||
|
- (void)closeSMSMessage:(MGMSMSMessageView *)theMessage;
|
||||||
|
|
||||||
|
- (void)checkSMSMessagesForInstance:(MGMInstance *)theInstance;
|
||||||
|
- (void)messageWithNumber:(NSString *)theNumber instance:(MGMInstance *)theInstance;
|
||||||
|
- (void)messageWithData:(NSDictionary *)theData instance:(MGMInstance *)theInstance;
|
||||||
|
- (NSString *)currentPhoneNumber;
|
||||||
|
@end
|
303
Classes/VoiceMac/SMS/MGMSMSManager.m
Normal file
303
Classes/VoiceMac/SMS/MGMSMSManager.m
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSManager.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSMSManager.h"
|
||||||
|
#import "MGMSMSMessageView.h"
|
||||||
|
#import "MGMViewCell.h"
|
||||||
|
#import "MGMSplitView.h"
|
||||||
|
#import "MGMSMSTextView.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMSIPUser.h"
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
const float updateTimeInterval = 300.0;
|
||||||
|
|
||||||
|
@implementation MGMSMSManager
|
||||||
|
+ (id)managerWithController:(MGMController *)theController {
|
||||||
|
return [[[self alloc] initWithController:theController] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithController:(MGMController *)theController {
|
||||||
|
if (self = [super init]) {
|
||||||
|
controller = theController;
|
||||||
|
SMSMessages = [NSMutableArray new];
|
||||||
|
lastDates = [NSMutableDictionary new];
|
||||||
|
updateTimer = [[NSTimer scheduledTimerWithTimeInterval:updateTimeInterval target:self selector:@selector(update) userInfo:nil repeats:YES] retain];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[[[messagesTable tableColumns] objectAtIndex:0] setDataCell:[[[MGMViewCell alloc] initGradientCell] autorelease]];
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (SMSWindow!=nil)
|
||||||
|
[SMSWindow close];
|
||||||
|
if (updateTimer!=nil) {
|
||||||
|
[updateTimer invalidate];
|
||||||
|
[updateTimer release];
|
||||||
|
}
|
||||||
|
if (SMSMessages!=nil)
|
||||||
|
[SMSMessages release];
|
||||||
|
if (lastDates!=nil)
|
||||||
|
[lastDates release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSWindow *)SMSWindow {
|
||||||
|
return SMSWindow;
|
||||||
|
}
|
||||||
|
- (MGMController *)controller {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
- (MGMThemeManager *)themeManager {
|
||||||
|
return [controller themeManager];
|
||||||
|
}
|
||||||
|
- (NSMutableArray *)SMSMessages {
|
||||||
|
return SMSMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadWindow {
|
||||||
|
if (SMSWindow==nil) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SMSWindow" owner:self]) {
|
||||||
|
NSLog(@"Error: Unable to load SMS Window!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)showWindow:(id)sender {
|
||||||
|
[self loadWindow];
|
||||||
|
[SMSWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)update {
|
||||||
|
if ([SMSMessages count]>0) {
|
||||||
|
NSMutableArray *instances = [NSMutableArray array];
|
||||||
|
for (unsigned int i=0; i<[SMSMessages count]; i++) {
|
||||||
|
MGMSMSMessageView *message = [SMSMessages objectAtIndex:i];
|
||||||
|
if (![instances containsObject:[message instance]]) {
|
||||||
|
[instances addObject:[message instance]];
|
||||||
|
[self checkSMSMessagesForInstance:[message instance]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadData {
|
||||||
|
while ([[messagesTable subviews] count]>0)
|
||||||
|
[[[messagesTable subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay];
|
||||||
|
[messagesTable reloadData];
|
||||||
|
}
|
||||||
|
- (int)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||||
|
return [SMSMessages count];
|
||||||
|
}
|
||||||
|
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row {
|
||||||
|
[(MGMViewCell *)cell addSubview:[[SMSMessages objectAtIndex:row] view]];
|
||||||
|
}
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row {
|
||||||
|
while ([[messageView subviews] count]>0)
|
||||||
|
[[[messageView subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay];
|
||||||
|
MGMSMSMessageView *message = [SMSMessages objectAtIndex:row];
|
||||||
|
[[message SMSSplitView] setFrame:NSMakeRect(0, 0, [messageView frame].size.width, [messageView frame].size.height)];
|
||||||
|
[messageView addSubview:[message SMSSplitView]];
|
||||||
|
[SMSWindow makeFirstResponder:[message SMSTextField]];
|
||||||
|
[(MGMVoiceUser *)[[message instance] delegate] windowDidBecomeKey:nil];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)closeSMSMessage:(MGMSMSMessageView *)theMessage {
|
||||||
|
unsigned int message = [SMSMessages indexOfObject:theMessage];
|
||||||
|
if (messagesTable!=nil) {
|
||||||
|
if (message==[messagesTable selectedRow])
|
||||||
|
[[theMessage SMSSplitView] removeFromSuperviewWithoutNeedingDisplay];
|
||||||
|
}
|
||||||
|
[SMSMessages removeObjectAtIndex:message];
|
||||||
|
if (SMSWindow!=nil) {
|
||||||
|
if ([SMSMessages count]<=0) {
|
||||||
|
[self reloadData];
|
||||||
|
[SMSWindow close];
|
||||||
|
} else {
|
||||||
|
[self reloadData];
|
||||||
|
[messagesTable selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||||
|
[self tableView:messagesTable shouldSelectRow:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)checkSMSMessagesForInstance:(MGMInstance *)theInstance {
|
||||||
|
[[theInstance inbox] getSMSForPage:1 delegate:self];
|
||||||
|
}
|
||||||
|
- (void)inbox:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
NSLog(@"SMS Error: %@ for instance: %@", theError, theInstance);
|
||||||
|
}
|
||||||
|
- (void)inboxGotInfo:(NSArray *)theMessages instance:(MGMInstance *)theInstance {
|
||||||
|
if (updateTimer!=nil) {
|
||||||
|
[updateTimer invalidate];
|
||||||
|
[updateTimer release];
|
||||||
|
updateTimer = [[NSTimer scheduledTimerWithTimeInterval:updateTimeInterval target:self selector:@selector(update) userInfo:nil repeats:YES] retain];
|
||||||
|
}
|
||||||
|
NSDate *newestDate = [NSDate distantPast];
|
||||||
|
BOOL newMessage = NO;
|
||||||
|
for (unsigned int i=0; i<[theMessages count]; i++) {
|
||||||
|
if ([lastDates objectForKey:[theInstance userNumber]]==nil || (![[lastDates objectForKey:[theInstance userNumber]] isEqual:[[theMessages objectAtIndex:i] objectForKey:MGMITime]] && [[lastDates objectForKey:[theInstance userNumber]] earlierDate:[[theMessages objectAtIndex:i] objectForKey:MGMITime]]==[lastDates objectForKey:[theInstance userNumber]])) {
|
||||||
|
NSMutableDictionary *messageInfo = [NSMutableDictionary dictionaryWithDictionary:[theMessages objectAtIndex:i]];
|
||||||
|
NSArray *messages = [[[messageInfo objectForKey:MGMIMessages] retain] autorelease];
|
||||||
|
[messageInfo removeObjectForKey:MGMIMessages];
|
||||||
|
[messageInfo setObject:[[theInstance contacts] nameForNumber:[messageInfo objectForKey:MGMIPhoneNumber]] forKey:MGMTInName];
|
||||||
|
[messageInfo setObject:[theInstance userNumber] forKey:MGMTUserNumber];
|
||||||
|
BOOL window = NO;
|
||||||
|
for (unsigned int m=0; m<[SMSMessages count]; m++) {
|
||||||
|
if ([[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIPhoneNumber] isEqual:[messageInfo objectForKey:MGMIPhoneNumber]] && ([[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIID] isEqual:[messageInfo objectForKey:MGMIID]] || [[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIID] isEqual:@""]) && [[SMSMessages objectAtIndex:m] instance]==theInstance) {
|
||||||
|
window = YES;
|
||||||
|
[[SMSMessages objectAtIndex:m] updateWithMessages:messages messageInfo:messageInfo];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window && ![[[theMessages objectAtIndex:i] objectForKey:MGMIRead] boolValue]) {
|
||||||
|
newMessage = YES;
|
||||||
|
[SMSMessages addObject:[MGMSMSMessageView viewWithManager:self messages:messages messageInfo:messageInfo instance:theInstance]];
|
||||||
|
}
|
||||||
|
if ([newestDate earlierDate:[[theMessages objectAtIndex:i] objectForKey:MGMITime]]==newestDate)
|
||||||
|
newestDate = [[theMessages objectAtIndex:i] objectForKey:MGMITime];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newMessage) {
|
||||||
|
[self loadWindow];
|
||||||
|
[lastDates setObject:newestDate forKey:[theInstance userNumber]];
|
||||||
|
[self reloadData];
|
||||||
|
[[controller themeManager] playSound:MGMTSSMSMessage];
|
||||||
|
[SMSWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)messageWithNumber:(NSString *)theNumber instance:(MGMInstance *)theInstance {
|
||||||
|
[self loadWindow];
|
||||||
|
NSMutableDictionary *messageInfo = [NSMutableDictionary dictionary];
|
||||||
|
[messageInfo setObject:[NSDate date] forKey:MGMITime];
|
||||||
|
[messageInfo setObject:[[theInstance contacts] nameForNumber:theNumber] forKey:MGMTInName];
|
||||||
|
[messageInfo setObject:theNumber forKey:MGMIPhoneNumber];
|
||||||
|
[messageInfo setObject:[theInstance userNumber] forKey:MGMTUserNumber];
|
||||||
|
[messageInfo setObject:@"" forKey:MGMIID];
|
||||||
|
[messageInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMIRead];
|
||||||
|
BOOL window = NO;
|
||||||
|
for (unsigned int m=0; m<[SMSMessages count]; m++) {
|
||||||
|
if ([[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIPhoneNumber] isEqual:[messageInfo objectForKey:MGMIPhoneNumber]] && [[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIID] isEqual:@""] && [[[SMSMessages objectAtIndex:m] instance] isEqual:theInstance]) {
|
||||||
|
window = YES;
|
||||||
|
[messagesTable selectRowIndexes:[NSIndexSet indexSetWithIndex:m] byExtendingSelection:NO];
|
||||||
|
[self tableView:messagesTable shouldSelectRow:m];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window) {
|
||||||
|
[SMSMessages addObject:[MGMSMSMessageView viewWithManager:self messages:[NSArray array] messageInfo:messageInfo instance:theInstance]];
|
||||||
|
[self reloadData];
|
||||||
|
[messagesTable selectRowIndexes:[NSIndexSet indexSetWithIndex:[SMSMessages count]-1] byExtendingSelection:NO];
|
||||||
|
[self tableView:messagesTable shouldSelectRow:[SMSMessages count]-1];
|
||||||
|
}
|
||||||
|
[SMSWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (void)messageWithData:(NSDictionary *)theData instance:(MGMInstance *)theInstance {
|
||||||
|
[self loadWindow];
|
||||||
|
NSMutableDictionary *messageInfo = [NSMutableDictionary dictionaryWithDictionary:theData];
|
||||||
|
NSArray *messages = [[[messageInfo objectForKey:MGMIMessages] retain] autorelease];
|
||||||
|
[messageInfo removeObjectForKey:MGMIMessages];
|
||||||
|
[messageInfo setObject:[[theInstance contacts] nameForNumber:[messageInfo objectForKey:MGMIPhoneNumber]] forKey:MGMTInName];
|
||||||
|
[messageInfo setObject:[theInstance userNumber] forKey:MGMTUserNumber];
|
||||||
|
BOOL window = NO;
|
||||||
|
for (unsigned int m=0; m<[SMSMessages count]; m++) {
|
||||||
|
if ([[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIPhoneNumber] isEqual:[messageInfo objectForKey:MGMIPhoneNumber]] && ([[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIID] isEqual:[messageInfo objectForKey:MGMIID]] || [[[[SMSMessages objectAtIndex:m] messageInfo] objectForKey:MGMIID] isEqual:@""]) && [[SMSMessages objectAtIndex:m] instance]==theInstance) {
|
||||||
|
window = YES;
|
||||||
|
[[SMSMessages objectAtIndex:m] updateWithMessages:messages messageInfo:messageInfo];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window) {
|
||||||
|
[SMSMessages addObject:[MGMSMSMessageView viewWithManager:self messages:messages messageInfo:messageInfo instance:theInstance]];
|
||||||
|
[self reloadData];
|
||||||
|
[messagesTable selectRowIndexes:[NSIndexSet indexSetWithIndex:[SMSMessages count]-1] byExtendingSelection:NO];
|
||||||
|
[self tableView:messagesTable shouldSelectRow:[SMSMessages count]-1];
|
||||||
|
}
|
||||||
|
[SMSWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
|
- (NSString *)currentPhoneNumber {
|
||||||
|
if (messagesTable==nil)
|
||||||
|
return nil;
|
||||||
|
return [[[SMSMessages objectAtIndex:[messagesTable selectedRow]] messageInfo] objectForKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)offset {
|
||||||
|
leftMax = [[[sender subviews] objectAtIndex:0] frame].size.width;
|
||||||
|
rightMax = [[[sender subviews] objectAtIndex:1] frame].size.width;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)offset{
|
||||||
|
leftMax = [[[sender subviews] objectAtIndex:0] frame].size.width;
|
||||||
|
rightMax = [[[sender subviews] objectAtIndex:1] frame].size.width;
|
||||||
|
return proposedMax - 150.0;
|
||||||
|
}
|
||||||
|
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
|
||||||
|
NSRect newFrame = [sender frame];
|
||||||
|
if (newFrame.size.width == oldSize.width) {
|
||||||
|
[sender adjustSubviews];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rightMax==0.0)
|
||||||
|
[self splitView:sender constrainMinCoordinate:0.0 ofSubviewAt:0];
|
||||||
|
|
||||||
|
NSView *left = [[sender subviews] objectAtIndex:0];
|
||||||
|
NSRect leftFrame = [left frame];
|
||||||
|
NSView *right = [[sender subviews] objectAtIndex:1];
|
||||||
|
NSRect rightFrame = [right frame];
|
||||||
|
|
||||||
|
if (rightFrame.size.width<150.0) {
|
||||||
|
rightMax = newFrame.size.width-(150.0+[sender dividerThickness]);
|
||||||
|
rightFrame.size.width = rightMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightMax<150.0)
|
||||||
|
rightMax = 150.0;
|
||||||
|
|
||||||
|
NSSize minSize = [SMSWindow minSize];
|
||||||
|
minSize.width = leftMax+150.0;
|
||||||
|
[SMSWindow setMinSize:minSize];
|
||||||
|
|
||||||
|
if (leftFrame.size.width<leftMax || leftFrame.size.width>leftMax)
|
||||||
|
leftFrame.size.width = leftMax;
|
||||||
|
[left setFrame:leftFrame];
|
||||||
|
[right setFrame:rightFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||||
|
[(MGMVoiceUser *)[[[SMSMessages objectAtIndex:[messagesTable selectedRow]] instance] delegate] windowDidBecomeKey:notification];
|
||||||
|
}
|
||||||
|
- (BOOL)windowShouldClose:(id)sender {
|
||||||
|
if ([SMSMessages count]>1) {
|
||||||
|
[[SMSMessages objectAtIndex:[messagesTable selectedRow]] close:self];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if ([SMSMessages count]==1) {
|
||||||
|
if (![[SMSMessages objectAtIndex:0] shouldClose]) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:@"You currently have a SMS Message being sent, please wait for it to be sent."];
|
||||||
|
[theAlert runModal];
|
||||||
|
return NO;
|
||||||
|
} else {
|
||||||
|
[[SMSMessages objectAtIndex:0] close:self];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
SMSWindow = nil;
|
||||||
|
splitView = nil;
|
||||||
|
messageView = nil;
|
||||||
|
messagesTable = nil;
|
||||||
|
}
|
||||||
|
@end
|
52
Classes/VoiceMac/SMS/MGMSMSMessageView.h
Normal file
52
Classes/VoiceMac/SMS/MGMSMSMessageView.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSMessageView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMSMSManager, MGMInstance, MGMSplitView, WebView, MGMSMSTextView, MGMSMSView;
|
||||||
|
|
||||||
|
@interface MGMSMSMessageView : NSObject {
|
||||||
|
MGMSMSManager *manager;
|
||||||
|
MGMInstance *instance;
|
||||||
|
IBOutlet MGMSplitView *SMSSplitView;
|
||||||
|
IBOutlet WebView *SMSView;
|
||||||
|
IBOutlet MGMSMSTextView *SMSTextView;
|
||||||
|
MGMSMSView *view;
|
||||||
|
|
||||||
|
NSMutableArray *messages;
|
||||||
|
NSMutableDictionary *messageInfo;
|
||||||
|
BOOL sendingMessage;
|
||||||
|
|
||||||
|
BOOL marking;
|
||||||
|
|
||||||
|
float bottomMax;
|
||||||
|
}
|
||||||
|
+ (id)viewWithManager:(MGMSMSManager *)theManager messages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo instance:(MGMInstance *)theInstance;
|
||||||
|
- (id)initWithManager:(MGMSMSManager *)theManager messages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo instance:(MGMInstance *)theInstance;
|
||||||
|
|
||||||
|
- (MGMSMSManager *)manager;
|
||||||
|
- (MGMInstance *)instance;
|
||||||
|
- (MGMSplitView *)SMSSplitView;
|
||||||
|
- (WebView *)SMSView;
|
||||||
|
- (MGMSMSTextView *)SMSTextField;
|
||||||
|
- (MGMSMSView *)view;
|
||||||
|
|
||||||
|
- (NSArray *)messages;
|
||||||
|
- (NSMutableDictionary *)messageInfo;
|
||||||
|
|
||||||
|
- (void)sendNotifications;
|
||||||
|
|
||||||
|
- (void)updateWithMessages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo;
|
||||||
|
|
||||||
|
- (void)buildHTML;
|
||||||
|
- (void)addMessage:(NSDictionary *)theMessage;
|
||||||
|
|
||||||
|
- (IBAction)sendMessage:(id)sender;
|
||||||
|
- (IBAction)close:(id)sender;
|
||||||
|
- (BOOL)shouldClose;
|
||||||
|
@end
|
294
Classes/VoiceMac/SMS/MGMSMSMessageView.m
Normal file
294
Classes/VoiceMac/SMS/MGMSMSMessageView.m
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSMessageView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSMSMessageView.h"
|
||||||
|
#import "MGMSMSManager.h"
|
||||||
|
#import "MGMSMSView.h"
|
||||||
|
#import "MGMSMSTextView.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
#import <MGMUsers/MGMUsers.h>
|
||||||
|
#import <Growl/GrowlApplicationBridge.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
@implementation MGMSMSMessageView
|
||||||
|
+ (id)viewWithManager:(MGMSMSManager *)theManager messages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo instance:(MGMInstance *)theInstance {
|
||||||
|
return [[[self alloc] initWithManager:theManager messages:theMessages messageInfo:theMessageInfo instance:theInstance] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithManager:(MGMSMSManager *)theManager messages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo instance:(MGMInstance *)theInstance {
|
||||||
|
if (self = [super init]) {
|
||||||
|
if (![NSBundle loadNibNamed:@"SMSMessageView" owner:self]) {
|
||||||
|
NSLog(@"Error: Unable to load SMS Message View.");
|
||||||
|
[self release];
|
||||||
|
self = nil;
|
||||||
|
} else {
|
||||||
|
manager = theManager;
|
||||||
|
instance = theInstance;
|
||||||
|
messages = [theMessages mutableCopy];
|
||||||
|
messageInfo = [theMessageInfo mutableCopy];
|
||||||
|
BOOL read = [[messageInfo objectForKey:MGMIRead] boolValue];
|
||||||
|
sendingMessage = NO;
|
||||||
|
|
||||||
|
marking = NO;
|
||||||
|
|
||||||
|
[SMSView setResourceLoadDelegate:self];
|
||||||
|
view = [[MGMSMSView viewWithMessageView:self] retain];
|
||||||
|
[view setRead:read];
|
||||||
|
[self buildHTML];
|
||||||
|
if (!read)
|
||||||
|
[self sendNotifications];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatedTheme:) name:MGMTUpdatedSMSThemeNotification object:[manager themeManager]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
if (SMSSplitView!=nil)
|
||||||
|
[SMSSplitView release];
|
||||||
|
if (messages!=nil)
|
||||||
|
[messages release];
|
||||||
|
if (messageInfo!=nil)
|
||||||
|
[messageInfo release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRead:(BOOL)isRead {
|
||||||
|
[messageInfo setObject:[NSNumber numberWithBool:isRead] forKey:MGMIRead];
|
||||||
|
[view setRead:isRead];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MGMSMSManager *)manager {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
- (MGMInstance *)instance {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
- (MGMSplitView *)SMSSplitView {
|
||||||
|
return SMSSplitView;
|
||||||
|
}
|
||||||
|
- (WebView *)SMSView {
|
||||||
|
return SMSView;
|
||||||
|
}
|
||||||
|
- (MGMSMSTextView *)SMSTextField {
|
||||||
|
return SMSTextView;
|
||||||
|
}
|
||||||
|
- (MGMSMSView *)view {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)messages {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
- (NSMutableDictionary *)messageInfo {
|
||||||
|
return messageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendNotifications {
|
||||||
|
for (unsigned int i=[messages count]-1; i>=0; i--) {
|
||||||
|
if (![[[messages objectAtIndex:i] objectForKey:MGMIYou] boolValue]) {
|
||||||
|
[GrowlApplicationBridge notifyWithTitle:[NSString stringWithFormat:@"SMS from %@", [messageInfo objectForKey:MGMTInName]] description:[[[messages objectAtIndex:i] objectForKey:MGMIText] flattenHTML] notificationName:@"SMS" iconData:[[instance contacts] photoDataForNumber:[messageInfo objectForKey:MGMIPhoneNumber]] priority:0 isSticky:NO clickContext:nil];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateWithMessages:(NSArray *)theMessages messageInfo:(NSDictionary *)theMessageInfo {
|
||||||
|
if (![[theMessageInfo objectForKey:MGMITime] isEqual:[messageInfo objectForKey:MGMITime]]) {
|
||||||
|
if (messageInfo!=nil) [messageInfo release];
|
||||||
|
messageInfo = [theMessageInfo mutableCopy];
|
||||||
|
BOOL read = [[messageInfo objectForKey:MGMIRead] boolValue];
|
||||||
|
[self setRead:read];
|
||||||
|
|
||||||
|
BOOL rebuild = [[[[manager themeManager] variant] objectForKey:MGMTRebuild] boolValue];
|
||||||
|
BOOL newMessages = NO;
|
||||||
|
for (unsigned int i=[messages count]; i<[theMessages count]; i++) {
|
||||||
|
newMessages = YES;
|
||||||
|
[messages addObject:[theMessages objectAtIndex:i]];
|
||||||
|
if (!rebuild)
|
||||||
|
[self addMessage:[messages lastObject]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMessages && rebuild)
|
||||||
|
[self buildHTML];
|
||||||
|
if (!read)
|
||||||
|
[self sendNotifications];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatedTheme:(NSNotification *)theNotification {
|
||||||
|
[self buildHTML];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)buildHTML {
|
||||||
|
NSString *yPhotoPath = [[instance contacts] cachedPhotoForNumber:[messageInfo objectForKey:MGMTUserNumber]];
|
||||||
|
if (yPhotoPath==nil)
|
||||||
|
yPhotoPath = [[[manager themeManager] outgoingIconPath] filePath];
|
||||||
|
NSString *tPhotoPath = [[instance contacts] cachedPhotoForNumber:[messageInfo objectForKey:MGMIPhoneNumber]];
|
||||||
|
if (tPhotoPath==nil)
|
||||||
|
tPhotoPath = [[[manager themeManager] incomingIconPath] filePath];
|
||||||
|
NSMutableArray *messageArray = [NSMutableArray array];
|
||||||
|
for (unsigned int i=0; i<[messages count]; i++) {
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionaryWithDictionary:[messages objectAtIndex:i]];
|
||||||
|
[message setObject:[[NSNumber numberWithInt:i] stringValue] forKey:MGMIID];
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
[message setObject:yPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:NSFullUserName() forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTUserNumber] forKey:MGMIPhoneNumber];
|
||||||
|
} else {
|
||||||
|
[message setObject:tPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTInName] forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMIPhoneNumber] forKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
[messageArray addObject:message];
|
||||||
|
}
|
||||||
|
NSString *html = [[manager themeManager] buildHTMLWithMessages:messageArray messageInfo:messageInfo];
|
||||||
|
[[SMSView mainFrame] loadHTMLString:html baseURL:[NSURL fileURLWithPath:[[manager themeManager] currentThemeVariantPath]]];
|
||||||
|
}
|
||||||
|
- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource {
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:@"scrollToBottom();"];
|
||||||
|
}
|
||||||
|
- (void)addMessage:(NSDictionary *)theMessage {
|
||||||
|
NSString *yPhotoPath = [[instance contacts] cachedPhotoForNumber:[messageInfo objectForKey:MGMTUserNumber]];
|
||||||
|
if (yPhotoPath==nil)
|
||||||
|
yPhotoPath = [[[manager themeManager] outgoingIconPath] filePath];
|
||||||
|
NSString *tPhotoPath = [[instance contacts] cachedPhotoForNumber:[messageInfo objectForKey:MGMIPhoneNumber]];
|
||||||
|
if (tPhotoPath==nil)
|
||||||
|
tPhotoPath = [[[manager themeManager] incomingIconPath] filePath];
|
||||||
|
NSMutableDictionary *message = [NSMutableDictionary dictionaryWithDictionary:theMessage];
|
||||||
|
[message setObject:[[NSNumber numberWithInt:[messages count]-1] stringValue] forKey:MGMIID];
|
||||||
|
int type = 1;
|
||||||
|
if ([[message objectForKey:MGMIYou] boolValue]) {
|
||||||
|
type = (([[message objectForKey:MGMIID] intValue]==0 || ![[[messages objectAtIndex:[[message objectForKey:MGMIID] intValue]-1] objectForKey:MGMIYou] boolValue]) ? 1 : 2);
|
||||||
|
[message setObject:yPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:NSFullUserName() forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTUserNumber] forKey:MGMIPhoneNumber];
|
||||||
|
} else {
|
||||||
|
type = (([[message objectForKey:MGMIID] intValue]==0 || [[[messages objectAtIndex:[[message objectForKey:MGMIID] intValue]-1] objectForKey:MGMIYou] boolValue]) ? 3 : 4);
|
||||||
|
[message setObject:tPhotoPath forKey:MGMTPhoto];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMTInName] forKey:MGMTName];
|
||||||
|
[message setObject:[messageInfo objectForKey:MGMIPhoneNumber] forKey:MGMIPhoneNumber];
|
||||||
|
}
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:[[[manager themeManager] variant] objectForKey:MGMTDate]];
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"newMessage('%@', '%@', '%@', %@, '%@', '%@', '%@', %d);", [[message objectForKey:MGMIText] escapeSMS], [[message objectForKey:MGMTPhoto] escapeSMS], [[message objectForKey:MGMITime] escapeSMS], [message objectForKey:MGMIID], [[message objectForKey:MGMTName] escapeSMS], [[[message objectForKey:MGMIPhoneNumber] readableNumber] escapeSMS], [formatter stringFromDate:[messageInfo objectForKey:MGMITime]], type]];
|
||||||
|
[SMSView stringByEvaluatingJavaScriptFromString:@"scrollToBottom();"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)sendMessage:(id)sender {
|
||||||
|
if ([[SMSTextView string] isEqual:@""])
|
||||||
|
return;
|
||||||
|
sendingMessage = YES;
|
||||||
|
[SMSTextView setEditable:NO];
|
||||||
|
[[instance inbox] sendMessage:[SMSTextView string] phoneNumbers:[NSArray arrayWithObject:[messageInfo objectForKey:MGMIPhoneNumber]] smsID:[messageInfo objectForKey:MGMIID] delegate:self];
|
||||||
|
}
|
||||||
|
- (void)message:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
sendingMessage = NO;
|
||||||
|
[SMSTextView setEditable:YES];
|
||||||
|
[[manager SMSWindow] makeFirstResponder:SMSTextView];
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
}
|
||||||
|
- (void)messageDidFinish:(NSDictionary *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
sendingMessage = NO;
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
|
||||||
|
[formatter setDateFormat:@"h:mm a"];
|
||||||
|
NSDictionary *message = [NSDictionary dictionaryWithObjectsAndKeys:[SMSTextView string], MGMIText, [formatter stringFromDate:[NSDate date]], MGMITime, [NSNumber numberWithBool:YES], MGMIYou, nil];
|
||||||
|
[messages addObject:message];
|
||||||
|
[messageInfo setObject:[NSDate date] forKey:MGMITime];
|
||||||
|
if ([[[[manager themeManager] variant] objectForKey:MGMTRebuild] boolValue]) {
|
||||||
|
[self buildHTML];
|
||||||
|
} else {
|
||||||
|
[self addMessage:message];
|
||||||
|
}
|
||||||
|
[SMSTextView setString:@""];
|
||||||
|
[SMSTextView setEditable:YES];
|
||||||
|
[SMSTextView count];
|
||||||
|
NSRect frame = [SMSSplitView frame];
|
||||||
|
NSView *top = [[SMSSplitView subviews] objectAtIndex:0];
|
||||||
|
NSRect topFrame = [top frame];
|
||||||
|
NSView *bottom = [[SMSSplitView subviews] objectAtIndex:1];
|
||||||
|
NSRect bottomFrame = [bottom frame];
|
||||||
|
bottomFrame.size.height = 33.0;
|
||||||
|
topFrame.size.height = frame.size.height-(bottomFrame.size.height+[SMSSplitView dividerThickness]);
|
||||||
|
[top setFrame:topFrame];
|
||||||
|
[bottom setFrame:bottomFrame];
|
||||||
|
[[manager SMSWindow] makeFirstResponder:SMSTextView];
|
||||||
|
[self setRead:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)close:(id)sender {
|
||||||
|
if (sendingMessage) {
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Sending a SMS Message"];
|
||||||
|
[theAlert setInformativeText:@"Your SMS Message is currently being sent, please wait for it to be sent."];
|
||||||
|
[theAlert runModal];
|
||||||
|
} else if (marking) {
|
||||||
|
|
||||||
|
} else if (![[messageInfo objectForKey:MGMIRead] boolValue]) {
|
||||||
|
marking = YES;
|
||||||
|
[[instance inbox] markEntries:[NSArray arrayWithObject:[messageInfo objectForKey:MGMIID]] read:YES delegate:self];
|
||||||
|
} else {
|
||||||
|
[manager closeSMSMessage:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (BOOL)shouldClose {
|
||||||
|
return (!sendingMessage);
|
||||||
|
}
|
||||||
|
- (void)mark:(NSDictionary *)theInfo didFailWithError:(NSError *)theError instance:(MGMInstance *)theInstance {
|
||||||
|
marking = NO;
|
||||||
|
NSAlert *theAlert = [[NSAlert new] autorelease];
|
||||||
|
[theAlert setMessageText:@"Error marking as read"];
|
||||||
|
[theAlert setInformativeText:[theError localizedDescription]];
|
||||||
|
[theAlert runModal];
|
||||||
|
}
|
||||||
|
- (void)markDidFinish:(NSDictionary *)theInfo instance:(MGMInstance *)theInstance {
|
||||||
|
marking = NO;
|
||||||
|
[messageInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMIRead];
|
||||||
|
[self close:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)offset {
|
||||||
|
bottomMax = [[[sender subviews] objectAtIndex:1] frame].size.height;
|
||||||
|
return 50.0;
|
||||||
|
}
|
||||||
|
- (float)splitView:(NSSplitView *)sender constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)offset{
|
||||||
|
bottomMax = [[[sender subviews] objectAtIndex:1] frame].size.height;
|
||||||
|
return proposedMax - 33.0;
|
||||||
|
}
|
||||||
|
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
|
||||||
|
NSRect newFrame = [sender frame];
|
||||||
|
if (newFrame.size.height == oldSize.height) {
|
||||||
|
[sender adjustSubviews];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSView *top = [[sender subviews] objectAtIndex:0];
|
||||||
|
NSRect topFrame = [top frame];
|
||||||
|
NSView *bottom = [[sender subviews] objectAtIndex:1];
|
||||||
|
NSRect bottomFrame = [bottom frame];
|
||||||
|
if (bottomMax==0.0)
|
||||||
|
[self splitView:sender constrainMinCoordinate:0.0 ofSubviewAt:0];
|
||||||
|
|
||||||
|
if (topFrame.size.height<50.0) {
|
||||||
|
bottomMax = newFrame.size.height-(50.0+[sender dividerThickness]);
|
||||||
|
bottomFrame.size.width = bottomMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottomMax<33.0)
|
||||||
|
bottomMax = 33.0;
|
||||||
|
|
||||||
|
if (bottomFrame.size.height < bottomMax || bottomFrame.size.height > bottomMax) {
|
||||||
|
bottomFrame.size.height = bottomMax;
|
||||||
|
}
|
||||||
|
topFrame.size.height = newFrame.size.height-(bottomFrame.size.height+[sender dividerThickness]);
|
||||||
|
[top setFrame:topFrame];
|
||||||
|
[bottom setFrame:bottomFrame];
|
||||||
|
}
|
||||||
|
@end
|
25
Classes/VoiceMac/SMS/MGMSMSTextView.h
Normal file
25
Classes/VoiceMac/SMS/MGMSMSTextView.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSTextView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class WebView, MGMSplitView;
|
||||||
|
|
||||||
|
@protocol MGMSMSTextViewProtocol <NSObject>
|
||||||
|
- (WebView *)SMSView;
|
||||||
|
- (MGMSplitView *)SMSSplitView;
|
||||||
|
- (IBAction)sendMessage:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface MGMSMSTextView : NSTextView {
|
||||||
|
IBOutlet id<MGMSMSTextViewProtocol> messageView;
|
||||||
|
IBOutlet NSTextField *count;
|
||||||
|
}
|
||||||
|
- (void)count;
|
||||||
|
@end
|
50
Classes/VoiceMac/SMS/MGMSMSTextView.m
Normal file
50
Classes/VoiceMac/SMS/MGMSMSTextView.m
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSTextView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSMSTextView.h"
|
||||||
|
#import "MGMSplitView.h"
|
||||||
|
|
||||||
|
@implementation MGMSMSTextView
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent {
|
||||||
|
int keycode = [theEvent keyCode];
|
||||||
|
int modifierFlags = [theEvent modifierFlags];
|
||||||
|
if (modifierFlags & NSAlternateKeyMask) {
|
||||||
|
[super keyDown:theEvent];
|
||||||
|
} else if (keycode==36) {
|
||||||
|
if ([messageView respondsToSelector:@selector(sendMessage:)]) [messageView sendMessage:self];
|
||||||
|
} else {
|
||||||
|
[super keyDown:theEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)keyUp:(NSEvent *)theEvent {
|
||||||
|
[self count];
|
||||||
|
[super keyUp:theEvent];
|
||||||
|
}
|
||||||
|
- (void)count {
|
||||||
|
[count setIntValue:160-[[self string] length]];
|
||||||
|
if ([messageView respondsToSelector:@selector(SMSSplitView)]) {
|
||||||
|
MGMSplitView *splitView = [messageView SMSSplitView];
|
||||||
|
NSView *bottom = [[splitView subviews] objectAtIndex:1];
|
||||||
|
NSRect bottomFrame = [bottom frame];
|
||||||
|
bottomFrame.size.height = [self bounds].size.height+16.0;
|
||||||
|
[bottom setFrame:bottomFrame];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (IBAction)print:(id)sender {
|
||||||
|
NSLog(@"Printing");
|
||||||
|
if ([messageView respondsToSelector:@selector(SMSView)]) [[messageView SMSView] print:sender];
|
||||||
|
}
|
||||||
|
- (void)paste:(id)sender {
|
||||||
|
[super paste:sender];
|
||||||
|
[self count];
|
||||||
|
}
|
||||||
|
- (void)cut:(id)sender {
|
||||||
|
[super cut:sender];
|
||||||
|
[self count];
|
||||||
|
}
|
||||||
|
@end
|
25
Classes/VoiceMac/SMS/MGMSMSView.h
Normal file
25
Classes/VoiceMac/SMS/MGMSMSView.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMSMSMessageView;
|
||||||
|
|
||||||
|
@interface MGMSMSView : NSView {
|
||||||
|
MGMSMSMessageView *messageView;
|
||||||
|
NSImageView *photoView;
|
||||||
|
NSTextField *nameField;
|
||||||
|
NSButton *closeButton;
|
||||||
|
|
||||||
|
BOOL read;
|
||||||
|
}
|
||||||
|
+ (id)viewWithMessageView:(MGMSMSMessageView *)theMessageView;
|
||||||
|
- (id)initWithMessageView:(MGMSMSMessageView *)theMessageView;
|
||||||
|
|
||||||
|
- (void)setRead:(BOOL)isRead;
|
||||||
|
@end
|
90
Classes/VoiceMac/SMS/MGMSMSView.m
Normal file
90
Classes/VoiceMac/SMS/MGMSMSView.m
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// MGMSMSView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSMSView.h"
|
||||||
|
#import "MGMSMSMessageView.h"
|
||||||
|
#import "MGMVoiceUser.h"
|
||||||
|
#import "MGMController.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
@implementation MGMSMSView
|
||||||
|
+ (id)viewWithMessageView:(MGMSMSMessageView *)theMessageView {
|
||||||
|
return [[[self alloc] initWithMessageView:theMessageView] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithMessageView:(MGMSMSMessageView *)theMessageView {
|
||||||
|
if (self = [super initWithFrame:NSMakeRect(0, 0, 100, 40)]) {
|
||||||
|
messageView = theMessageView;
|
||||||
|
[self setToolTip:[[messageView messageInfo] objectForKey:MGMTInName]];
|
||||||
|
NSRect frameRect = [self frame];
|
||||||
|
photoView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, frameRect.size.height, frameRect.size.height)];
|
||||||
|
[photoView setRefusesFirstResponder:YES];
|
||||||
|
[self addSubview:photoView];
|
||||||
|
NSData *photoData = [[[messageView instance] contacts] photoDataForNumber:[[messageView messageInfo] objectForKey:MGMIPhoneNumber]];
|
||||||
|
if (photoData==nil) {
|
||||||
|
[photoView setImage:[[[NSImage alloc] initWithContentsOfFile:[[[(MGMVoiceUser *)[[messageView instance] delegate] controller] themeManager] incomingIconPath]] autorelease]];
|
||||||
|
} else {
|
||||||
|
[photoView setImage:[[[NSImage alloc] initWithData:photoData] autorelease]];
|
||||||
|
}
|
||||||
|
read = NO;
|
||||||
|
int size = 12;
|
||||||
|
nameField = [[NSTextField alloc] initWithFrame:NSMakeRect(frameRect.size.height+4, (frameRect.size.height/2)-4, frameRect.size.width-(frameRect.size.height+20), size)];
|
||||||
|
[nameField setEditable:NO];
|
||||||
|
[nameField setSelectable:NO];
|
||||||
|
[nameField setBezeled:NO];
|
||||||
|
[nameField setBordered:NO];
|
||||||
|
[nameField setDrawsBackground:NO];
|
||||||
|
[nameField setFont:[NSFont boldSystemFontOfSize:10]];
|
||||||
|
[[nameField cell] setLineBreakMode:NSLineBreakByTruncatingTail];
|
||||||
|
[self addSubview:nameField];
|
||||||
|
[nameField setStringValue:[[messageView messageInfo] objectForKey:MGMTInName]];
|
||||||
|
|
||||||
|
closeButton = [[NSButton alloc] initWithFrame:NSMakeRect(frameRect.size.width-14, (frameRect.size.height/2)-6, 14, 14)];
|
||||||
|
[closeButton setButtonType:NSMomentaryChangeButton];
|
||||||
|
[closeButton setBezelStyle:NSRegularSquareBezelStyle];
|
||||||
|
[closeButton setBordered:NO];
|
||||||
|
[closeButton setImagePosition:NSImageOnly];
|
||||||
|
[closeButton setImage:[NSImage imageNamed:@"Close"]];
|
||||||
|
[closeButton setAlternateImage:[NSImage imageNamed:@"ClosePressed"]];
|
||||||
|
[closeButton setTarget:messageView];
|
||||||
|
[closeButton setAction:@selector(close:)];
|
||||||
|
[self addSubview:closeButton];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (photoView!=nil)
|
||||||
|
[photoView release];
|
||||||
|
if (nameField!=nil)
|
||||||
|
[nameField release];
|
||||||
|
if (closeButton!=nil)
|
||||||
|
[closeButton release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRead:(BOOL)isRead {
|
||||||
|
read = isRead;
|
||||||
|
[nameField setFont:[NSFont boldSystemFontOfSize:(isRead ? 10 : 12)]];
|
||||||
|
[self resizeSubviewsWithOldSize:[self frame].size];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
|
||||||
|
[super resizeSubviewsWithOldSize:oldBoundsSize];
|
||||||
|
NSRect frameRect = [self frame];
|
||||||
|
[photoView setFrame:NSMakeRect(0, 0, frameRect.size.height, frameRect.size.height)];
|
||||||
|
int size = 0;
|
||||||
|
if (read)
|
||||||
|
size = 12;
|
||||||
|
else
|
||||||
|
size = 14;
|
||||||
|
[nameField setFrame:NSMakeRect(frameRect.size.height+4, (frameRect.size.height/2)-4, frameRect.size.width-(frameRect.size.height+20), size)];
|
||||||
|
[closeButton setFrame:NSMakeRect(frameRect.size.width-14, (frameRect.size.height/2)-6, 14, 14)];
|
||||||
|
}
|
||||||
|
- (void)setFontColor:(NSColor *)theColor {
|
||||||
|
[nameField setTextColor:theColor];
|
||||||
|
}
|
||||||
|
@end
|
15
Classes/VoiceMac/Views/MGMBlackWindow.h
Normal file
15
Classes/VoiceMac/Views/MGMBlackWindow.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// MGMBlackWindow.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMBlackWindow : NSWindow {
|
||||||
|
BOOL forceDisplay;
|
||||||
|
}
|
||||||
|
- (NSColor *)blackBackground;
|
||||||
|
@end
|
68
Classes/VoiceMac/Views/MGMBlackWindow.m
Normal file
68
Classes/VoiceMac/Views/MGMBlackWindow.m
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// MGMBlackWindow.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/6/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMBlackWindow.h"
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
|
||||||
|
@implementation MGMBlackWindow
|
||||||
|
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation {
|
||||||
|
if (self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:deferCreation]) {
|
||||||
|
forceDisplay = NO;
|
||||||
|
[self setLevel:NSStatusWindowLevel];
|
||||||
|
[self setBackgroundColor:[NSColor clearColor]];
|
||||||
|
[self setOpaque:NO];
|
||||||
|
[self setHasShadow:YES];
|
||||||
|
[self setAlphaValue:1.0];
|
||||||
|
[self setMovableByWindowBackground:YES];
|
||||||
|
[self setBackgroundColor:[self blackBackground]];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification *)aNotification {
|
||||||
|
[self setBackgroundColor:[self blackBackground]];
|
||||||
|
if (forceDisplay)
|
||||||
|
[self display];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(NSRect)frameRect display:(BOOL)displayFlag animate:(BOOL)animationFlag {
|
||||||
|
forceDisplay = YES;
|
||||||
|
[super setFrame:frameRect display:displayFlag animate:animationFlag];
|
||||||
|
forceDisplay = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSColor *)blackBackground {
|
||||||
|
float alpha = 0.8;
|
||||||
|
NSImage *bg = [[NSImage alloc] initWithSize:[self frame].size];
|
||||||
|
[bg lockFocus];
|
||||||
|
|
||||||
|
float radius = 6.0;
|
||||||
|
float stroke = 3.0;
|
||||||
|
NSRect bgRect = NSMakeRect(stroke/2, stroke/2, [bg size].width-stroke, [bg size].height-stroke);
|
||||||
|
NSBezierPath *bgPath = [NSBezierPath pathWithRect:bgRect radiusX:radius radiusY:radius];
|
||||||
|
[bgPath setLineWidth:stroke];
|
||||||
|
|
||||||
|
[[NSColor colorWithCalibratedWhite:0.0 alpha:alpha] set];
|
||||||
|
[bgPath fill];
|
||||||
|
[[NSColor colorWithCalibratedWhite:1.0 alpha:alpha] set];
|
||||||
|
[bgPath stroke];
|
||||||
|
|
||||||
|
[bg unlockFocus];
|
||||||
|
|
||||||
|
return [NSColor colorWithPatternImage:[bg autorelease]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyWindow {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
@end
|
15
Classes/VoiceMac/Views/MGMBottomView.h
Normal file
15
Classes/VoiceMac/Views/MGMBottomView.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// MGMBottomView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMBottomView : NSView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
17
Classes/VoiceMac/Views/MGMBottomView.m
Normal file
17
Classes/VoiceMac/Views/MGMBottomView.m
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// MGMBottomView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMBottomView.h"
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
|
||||||
|
@implementation MGMBottomView
|
||||||
|
- (void)drawRect:(NSRect)rect {
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
|
||||||
|
[path fillGradientFrom:[NSColor colorWithCalibratedWhite:0.992156 alpha:1.0] to:[NSColor colorWithCalibratedWhite:0.886274 alpha:1.0]];
|
||||||
|
}
|
||||||
|
@end
|
24
Classes/VoiceMac/Views/MGMContactView.h
Normal file
24
Classes/VoiceMac/Views/MGMContactView.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// MGMContactView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/20/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@class MGMThemeManager;
|
||||||
|
|
||||||
|
@interface MGMContactView : NSView {
|
||||||
|
MGMThemeManager *themeManager;
|
||||||
|
NSImageView *photoView;
|
||||||
|
NSTextField *nameField;
|
||||||
|
NSTextField *phoneField;
|
||||||
|
NSMutableDictionary *contact;
|
||||||
|
}
|
||||||
|
+ (id)viewWithFrame:(NSRect)frameRect themeManager:(MGMThemeManager *)theThemeManager;
|
||||||
|
- (id)initWithFrame:(NSRect)frameRect themeManager:(MGMThemeManager *)theThemeManager;
|
||||||
|
- (NSDictionary *)contact;
|
||||||
|
- (void)setContact:(NSDictionary *)theContact;
|
||||||
|
@end
|
86
Classes/VoiceMac/Views/MGMContactView.m
Normal file
86
Classes/VoiceMac/Views/MGMContactView.m
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// MGMContactView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/20/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMContactView.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
@implementation MGMContactView
|
||||||
|
+ (id)viewWithFrame:(NSRect)frameRect themeManager:(MGMThemeManager *)theThemeManager {
|
||||||
|
return [[[self alloc] initWithFrame:frameRect themeManager:theThemeManager] autorelease];
|
||||||
|
}
|
||||||
|
- (id)initWithFrame:(NSRect)frameRect themeManager:(MGMThemeManager *)theThemeManager {
|
||||||
|
themeManager = theThemeManager;
|
||||||
|
if (self = [super initWithFrame:frameRect]) {
|
||||||
|
photoView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, frameRect.size.height, frameRect.size.height)];
|
||||||
|
[photoView setRefusesFirstResponder:YES];
|
||||||
|
[self addSubview:photoView];
|
||||||
|
nameField = [[NSTextField alloc] initWithFrame:NSMakeRect(frameRect.size.height+8, frameRect.size.height-27, frameRect.size.width-(frameRect.size.height+12), 18)];
|
||||||
|
[nameField setEditable:NO];
|
||||||
|
[nameField setSelectable:NO];
|
||||||
|
[nameField setBezeled:NO];
|
||||||
|
[nameField setBordered:NO];
|
||||||
|
[nameField setDrawsBackground:NO];
|
||||||
|
[nameField setFont:[NSFont boldSystemFontOfSize:14]];
|
||||||
|
[self addSubview:nameField];
|
||||||
|
phoneField = [[NSTextField alloc] initWithFrame:NSMakeRect(frameRect.size.height+8, 10, frameRect.size.width-(frameRect.size.height+12), 17)];
|
||||||
|
[phoneField setEditable:NO];
|
||||||
|
[phoneField setSelectable:NO];
|
||||||
|
[phoneField setBezeled:NO];
|
||||||
|
[phoneField setBordered:NO];
|
||||||
|
[phoneField setDrawsBackground:NO];
|
||||||
|
[phoneField setFont:[NSFont systemFontOfSize:13]];
|
||||||
|
[self addSubview:phoneField];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (photoView!=nil)
|
||||||
|
[photoView release];
|
||||||
|
if (nameField!=nil)
|
||||||
|
[nameField release];
|
||||||
|
if (phoneField!=nil)
|
||||||
|
[phoneField release];
|
||||||
|
if (contact!=nil)
|
||||||
|
[contact release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
|
||||||
|
[super resizeSubviewsWithOldSize:oldBoundsSize];
|
||||||
|
NSRect frameRect = [self frame];
|
||||||
|
[photoView setFrame:NSMakeRect(0, 0, frameRect.size.height, frameRect.size.height)];
|
||||||
|
[nameField setFrame:NSMakeRect(frameRect.size.height+8, frameRect.size.height-27, frameRect.size.width-(frameRect.size.height+12), 18)];
|
||||||
|
[phoneField setFrame:NSMakeRect(frameRect.size.height+8, 10, frameRect.size.width-(frameRect.size.height+12), 17)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)contact {
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
- (void)setContact:(NSDictionary *)theContact {
|
||||||
|
if (contact!=nil) [contact release];
|
||||||
|
contact = [theContact mutableCopy];
|
||||||
|
if ([contact objectForKey:MGMCPhoto]==nil || [[contact objectForKey:MGMCPhoto] isKindOfClass:[NSNull class]]) {
|
||||||
|
[photoView setImage:[[[NSImage alloc] initWithContentsOfFile:[themeManager incomingIconPath]] autorelease]];
|
||||||
|
} else {
|
||||||
|
[photoView setImage:[[[NSImage alloc] initWithData:[contact objectForKey:MGMCPhoto]] autorelease]];
|
||||||
|
}
|
||||||
|
if ([[contact objectForKey:MGMCName] isEqual:@""])
|
||||||
|
[nameField setStringValue:[contact objectForKey:MGMCCompany]];
|
||||||
|
else
|
||||||
|
[nameField setStringValue:[contact objectForKey:MGMCName]];
|
||||||
|
if ([[contact objectForKey:MGMCLabel] isEqual:@""]) {
|
||||||
|
[phoneField setStringValue:[[contact objectForKey:MGMCNumber] readableNumber]];
|
||||||
|
} else {
|
||||||
|
[phoneField setStringValue:[NSString stringWithFormat:@"%@ %@", [[contact objectForKey:MGMCNumber] readableNumber], [contact objectForKey:MGMCLabel]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFontColor:(NSColor *)theColor {
|
||||||
|
[nameField setTextColor:theColor];
|
||||||
|
[phoneField setTextColor:theColor];
|
||||||
|
}
|
||||||
|
@end
|
27
Classes/VoiceMac/Views/MGMGradiantView.h
Normal file
27
Classes/VoiceMac/Views/MGMGradiantView.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// MGMGradiantView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMGradiantTableView : NSTableView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMGradiantOutlineView : NSOutlineView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMTextCell : NSTextFieldCell {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
159
Classes/VoiceMac/Views/MGMGradiantView.m
Normal file
159
Classes/VoiceMac/Views/MGMGradiantView.m
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
//
|
||||||
|
// MGMGradiantView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/27/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMGradiantView.h"
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
#import <VoiceBase/VoiceBase.h>
|
||||||
|
|
||||||
|
@implementation MGMGradiantTableView
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
|
||||||
|
|
||||||
|
NSTableColumn *column = [[self tableColumns] objectAtIndex:0];
|
||||||
|
if ([[column dataCell] isKindOfClass:[NSTextFieldCell class]]) {
|
||||||
|
MGMTextCell *theTextCell = [[MGMTextCell new] autorelease];
|
||||||
|
[column setDataCell:theTextCell];
|
||||||
|
[[column dataCell] setFont:[NSFont labelFontOfSize:[NSFont labelFontSize]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)highlightSelectionInClipRect:(NSRect)clipRect {
|
||||||
|
int selectedRow = [self selectedRow];
|
||||||
|
if(selectedRow == -1)
|
||||||
|
return;
|
||||||
|
[self lockFocus];
|
||||||
|
|
||||||
|
NSColor *startColor = nil;
|
||||||
|
NSColor *endColor = nil;
|
||||||
|
if ([[self window] isKeyWindow]) {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLKSRed green:MGMHLKSGreen blue:MGMHLKSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLKERed green:MGMHLKEGreen blue:MGMHLKEBlue alpha:1.0];
|
||||||
|
} else {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLSRed green:MGMHLSGreen blue:MGMHLSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLERed green:MGMHLEGreen blue:MGMHLEBlue alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRect drawingRect = [self rectOfRow:selectedRow];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:drawingRect];
|
||||||
|
[path fillGradientFrom:startColor to:endColor];
|
||||||
|
path = [NSBezierPath bezierPathWithRect:NSMakeRect(drawingRect.origin.x, drawingRect.origin.y, drawingRect.size.width, 1.0)];
|
||||||
|
[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.15] set];
|
||||||
|
[path fill];
|
||||||
|
|
||||||
|
[self unlockFocus];
|
||||||
|
}
|
||||||
|
- (void)viewWillDraw {
|
||||||
|
if ([[self window] isKeyWindow]) {
|
||||||
|
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.863389 green:0.892058 blue:0.9205 alpha:1.0]];
|
||||||
|
} else {
|
||||||
|
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.929412 green:0.929412 blue:0.929412 alpha:1.0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMGradiantOutlineView
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
|
||||||
|
|
||||||
|
NSTableColumn *column = [[self tableColumns] objectAtIndex:0];
|
||||||
|
if ([[column dataCell] isKindOfClass:[NSTextFieldCell class]]) {
|
||||||
|
MGMTextCell *theTextCell = [[MGMTextCell new] autorelease];
|
||||||
|
[column setDataCell:theTextCell];
|
||||||
|
[[column dataCell] setFont:[NSFont labelFontOfSize:[NSFont labelFontSize]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void)highlightSelectionInClipRect:(NSRect)clipRect {
|
||||||
|
int selectedRow = [self selectedRow];
|
||||||
|
if(selectedRow == -1)
|
||||||
|
return;
|
||||||
|
[self lockFocus];
|
||||||
|
|
||||||
|
NSColor *startColor = nil;
|
||||||
|
NSColor *endColor = nil;
|
||||||
|
if ([[self window] isKeyWindow]) {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLKSRed green:MGMHLKSGreen blue:MGMHLKSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLKERed green:MGMHLKEGreen blue:MGMHLKEBlue alpha:1.0];
|
||||||
|
} else {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLSRed green:MGMHLSGreen blue:MGMHLSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLERed green:MGMHLEGreen blue:MGMHLEBlue alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRect drawingRect = [self rectOfRow:selectedRow];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:drawingRect];
|
||||||
|
[path fillGradientFrom:startColor to:endColor];
|
||||||
|
path = [NSBezierPath bezierPathWithRect:NSMakeRect(drawingRect.origin.x, drawingRect.origin.y, drawingRect.size.width, 1.0)];
|
||||||
|
[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.15] set];
|
||||||
|
[path fill];
|
||||||
|
|
||||||
|
[self unlockFocus];
|
||||||
|
}
|
||||||
|
- (void)viewWillDraw {
|
||||||
|
if ([[self window] isKeyWindow]) {
|
||||||
|
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.863389 green:0.892058 blue:0.9205 alpha:1.0]];
|
||||||
|
} else {
|
||||||
|
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.929412 green:0.929412 blue:0.929412 alpha:1.0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMTextCell
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
[self setWraps:NO];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
|
||||||
|
[controlView lockFocus];
|
||||||
|
if ([self isHighlighted]) {
|
||||||
|
NSColor *startColor = nil;
|
||||||
|
NSColor *endColor = nil;
|
||||||
|
if ([[controlView window] isKeyWindow]) {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLKSRed green:MGMHLKSGreen blue:MGMHLKSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLKERed green:MGMHLKEGreen blue:MGMHLKEBlue alpha:1.0];
|
||||||
|
} else {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLSRed green:MGMHLSGreen blue:MGMHLSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLERed green:MGMHLEGreen blue:MGMHLEBlue alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRect drawingRect = [super drawingRectForBounds:cellFrame];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:drawingRect];
|
||||||
|
[path fillGradientFrom:startColor to:endColor];
|
||||||
|
path = [NSBezierPath bezierPathWithRect:NSMakeRect(drawingRect.origin.x, drawingRect.origin.y, drawingRect.size.width, 1.0)];
|
||||||
|
[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.15] set];
|
||||||
|
[path fill];
|
||||||
|
}
|
||||||
|
cellFrame.size.width += 10;
|
||||||
|
NSRect textRect = [self drawingRectForBounds:cellFrame];
|
||||||
|
|
||||||
|
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:[[self attributedStringValue] attributesAtIndex:0 effectiveRange:NULL]];
|
||||||
|
if ([self isHighlighted]) {
|
||||||
|
[attributes setObject:[NSFont fontWithName:[NSString stringWithFormat:@"%@ Bold", [[self font] displayName]] size:[[self font] pointSize]] forKey:NSFontAttributeName];
|
||||||
|
[attributes setValue:[NSColor whiteColor] forKey:@"NSColor"];
|
||||||
|
} else {
|
||||||
|
[attributes setObject:[self font] forKey:NSFontAttributeName];
|
||||||
|
}
|
||||||
|
NSString *displayString = [[self stringValue] truncateForWidth:textRect.size.width attributes:attributes];
|
||||||
|
[displayString drawAtPoint:textRect.origin withAttributes:attributes];
|
||||||
|
|
||||||
|
[controlView unlockFocus];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRect)drawingRectForBounds:(NSRect)theRect {
|
||||||
|
NSRect newRect = [super drawingRectForBounds:theRect];
|
||||||
|
NSSize textSize = [self cellSizeForBounds:theRect];
|
||||||
|
float heightDifference = newRect.size.height - textSize.height;
|
||||||
|
if (heightDifference > 0) {
|
||||||
|
newRect.size.height -= heightDifference;
|
||||||
|
newRect.origin.y += (heightDifference / 2);
|
||||||
|
}
|
||||||
|
newRect.origin.x += 4;
|
||||||
|
newRect.size.width -= 14;
|
||||||
|
return newRect;
|
||||||
|
}
|
||||||
|
@end
|
36
Classes/VoiceMac/Views/MGMPhoneFeild.h
Normal file
36
Classes/VoiceMac/Views/MGMPhoneFeild.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// MGMPhoneFeild.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 7/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@protocol MGMPhoneFieldDelegate <NSObject>
|
||||||
|
- (void)filterContacts;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface MGMPhoneField : NSTextField {
|
||||||
|
IBOutlet id<MGMPhoneFieldDelegate> phoneDelegate;
|
||||||
|
}
|
||||||
|
- (void)setPhoneDelegate:(id)thePhoneDelegate;
|
||||||
|
- (id<MGMPhoneFieldDelegate>)phoneDelegate;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMPhoneFieldCell : NSTextFieldCell {
|
||||||
|
NSButtonCell *clearButton;
|
||||||
|
}
|
||||||
|
- (NSButtonCell *)clearButton;
|
||||||
|
- (NSRect)clearButtonRectForBounds:(NSRect)bounds;
|
||||||
|
- (NSRect)textRectForBounds:(NSRect)bounds includeButtons:(BOOL)buttons;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMPhoneFieldView : NSTextView {
|
||||||
|
IBOutlet id<MGMPhoneFieldDelegate> phoneDelegate;
|
||||||
|
}
|
||||||
|
- (void)setPhoneDelegate:(id)thePhoneDelegate;
|
||||||
|
- (id<MGMPhoneFieldDelegate>)phoneDelegate;
|
||||||
|
@end
|
199
Classes/VoiceMac/Views/MGMPhoneFeild.m
Normal file
199
Classes/VoiceMac/Views/MGMPhoneFeild.m
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
//
|
||||||
|
// MGMPhoneFeild.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 7/15/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMPhoneFeild.h"
|
||||||
|
|
||||||
|
@implementation MGMPhoneField
|
||||||
|
- (id)initWithCoder:(NSCoder*)coder {
|
||||||
|
if (self = [super initWithCoder:coder]) {
|
||||||
|
NSTextFieldCell *cell = [self cell];
|
||||||
|
MGMPhoneFieldCell *phoneCell = [[MGMPhoneFieldCell alloc] initTextCell:[cell stringValue]];
|
||||||
|
//NSTextFieldCell
|
||||||
|
[phoneCell setTextColor:[cell textColor]];
|
||||||
|
[phoneCell setBezelStyle:[cell bezelStyle]];
|
||||||
|
[phoneCell setBackgroundColor:[cell backgroundColor]];
|
||||||
|
[phoneCell setDrawsBackground:[cell drawsBackground]];
|
||||||
|
[phoneCell setPlaceholderString:[cell placeholderString]];
|
||||||
|
|
||||||
|
//NSActionCell
|
||||||
|
[phoneCell setTarget:[cell target]];
|
||||||
|
[phoneCell setAction:[cell action]];
|
||||||
|
[phoneCell setTag:[cell tag]];
|
||||||
|
|
||||||
|
//NSCell
|
||||||
|
[phoneCell setEnabled:[cell isEnabled]];
|
||||||
|
[phoneCell setAllowsUndo:[cell allowsUndo]];
|
||||||
|
[phoneCell setBordered:[cell isBordered]];
|
||||||
|
[phoneCell setBezeled:[cell isBezeled]];
|
||||||
|
[phoneCell setAllowsMixedState:[cell allowsMixedState]];
|
||||||
|
[phoneCell setState:[cell state]];
|
||||||
|
[phoneCell setEditable:[cell isEditable]];
|
||||||
|
[phoneCell setSelectable:[cell isSelectable]];
|
||||||
|
[phoneCell setScrollable:[cell isScrollable]];
|
||||||
|
[phoneCell setAlignment:[cell alignment]];
|
||||||
|
[phoneCell setFont:[cell font]];
|
||||||
|
[phoneCell setLineBreakMode:[cell lineBreakMode]];
|
||||||
|
[phoneCell setWraps:[cell wraps]];
|
||||||
|
[phoneCell setBaseWritingDirection:[cell baseWritingDirection]];
|
||||||
|
[phoneCell setAllowsEditingTextAttributes:[cell allowsEditingTextAttributes]];
|
||||||
|
[phoneCell setImportsGraphics:[cell importsGraphics]];
|
||||||
|
[phoneCell setContinuous:[cell isContinuous]];
|
||||||
|
[phoneCell setFormatter:[cell formatter]];
|
||||||
|
[phoneCell setMenu:[cell menu]];
|
||||||
|
[phoneCell setShowsFirstResponder:[cell showsFirstResponder]];
|
||||||
|
[phoneCell setRefusesFirstResponder:[cell refusesFirstResponder]];
|
||||||
|
[phoneCell setRepresentedObject:[cell representedObject]];
|
||||||
|
[phoneCell setFocusRingType:[cell focusRingType]];
|
||||||
|
[phoneCell setControlSize:[cell controlSize]];
|
||||||
|
[phoneCell setControlView:[cell controlView]];
|
||||||
|
[phoneCell setControlTint:[cell controlTint]];
|
||||||
|
[phoneCell setSendsActionOnEndEditing:[cell sendsActionOnEndEditing]];
|
||||||
|
|
||||||
|
[self setCell:phoneCell];
|
||||||
|
[phoneCell release];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)setPhoneDelegate:(id)thePhoneDelegate {
|
||||||
|
phoneDelegate = thePhoneDelegate;
|
||||||
|
}
|
||||||
|
- (id<MGMPhoneFieldDelegate>)phoneDelegate {
|
||||||
|
return phoneDelegate;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent *)event {
|
||||||
|
NSPoint location = [event locationInWindow];
|
||||||
|
NSRect bounds = [self bounds];
|
||||||
|
MGMPhoneFieldCell *cell = [self cell];
|
||||||
|
|
||||||
|
if (!NSPointInRect(location, [cell textRectForBounds:bounds includeButtons:YES])) {
|
||||||
|
NSRect clearRect = [self convertRect:[cell clearButtonRectForBounds:bounds] toView:nil];
|
||||||
|
if (NSPointInRect(location, clearRect)) {
|
||||||
|
[[cell clearButton] setHighlighted:YES];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[super mouseDown:event];
|
||||||
|
}
|
||||||
|
- (void)mouseUp:(NSEvent *)event {
|
||||||
|
NSPoint location = [event locationInWindow];
|
||||||
|
NSRect bounds = [self bounds];
|
||||||
|
MGMPhoneFieldCell *cell = [self cell];
|
||||||
|
|
||||||
|
NSButtonCell *clearButton = [cell clearButton];
|
||||||
|
[clearButton setHighlighted:NO];
|
||||||
|
if (!NSPointInRect(location, [cell textRectForBounds:bounds includeButtons:YES])) {
|
||||||
|
NSRect clearRect = [self convertRect:[cell clearButtonRectForBounds:bounds] toView:nil];
|
||||||
|
if (NSPointInRect(location, clearRect)) {
|
||||||
|
[self setStringValue:@""];
|
||||||
|
if (phoneDelegate!=nil && [phoneDelegate respondsToSelector:@selector(filterContacts)]) [phoneDelegate filterContacts];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[super mouseUp:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(NSEvent *)theEvent {
|
||||||
|
int keyCode = [theEvent keyCode];
|
||||||
|
if (keyCode==125 || keyCode==36 || keyCode==76) {
|
||||||
|
[super keyUp:theEvent];
|
||||||
|
} else {
|
||||||
|
if (phoneDelegate!=nil && [phoneDelegate respondsToSelector:@selector(filterContacts)]) [phoneDelegate filterContacts];
|
||||||
|
[super keyUp:theEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMPhoneFieldCell
|
||||||
|
- (id)initTextCell:(NSString *)aString {
|
||||||
|
if (self = [super initTextCell:aString]) {
|
||||||
|
clearButton = [[NSButtonCell alloc] initImageCell:nil];
|
||||||
|
[clearButton setButtonType:NSMomentaryChangeButton];
|
||||||
|
[clearButton setBezelStyle:NSRegularSquareBezelStyle];
|
||||||
|
[clearButton setBordered:NO];
|
||||||
|
[clearButton setImagePosition:NSImageOnly];
|
||||||
|
[clearButton setImage:[NSImage imageNamed:@"Close"]];
|
||||||
|
[clearButton setAlternateImage:[NSImage imageNamed:@"ClosePressed"]];
|
||||||
|
[clearButton setKeyEquivalent:@"\e"];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
[clearButton release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSButtonCell *)clearButton {
|
||||||
|
return clearButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define offset 4
|
||||||
|
- (NSRect)clearButtonRectForBounds:(NSRect)bounds {
|
||||||
|
NSRect clearRect = NSZeroRect;
|
||||||
|
clearRect.size = [clearButton cellSize];
|
||||||
|
clearRect.size.height = bounds.size.height;
|
||||||
|
clearRect.origin.x = bounds.size.width - clearRect.size.width - offset;
|
||||||
|
return clearRect;
|
||||||
|
}
|
||||||
|
- (NSRect)textRectForBounds:(NSRect)bounds includeButtons:(BOOL)buttons {
|
||||||
|
NSRect rect = NSInsetRect(bounds, 2, 2);
|
||||||
|
rect.size.height = [super drawingRectForBounds:bounds].size.height;
|
||||||
|
if (buttons) {
|
||||||
|
rect.size.width -= [clearButton cellSize].width;
|
||||||
|
rect.size.width -= offset;
|
||||||
|
rect.origin.x += offset;
|
||||||
|
}
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
- (NSRect)drawingRectForBounds:(NSRect)bounds {
|
||||||
|
return [self textRectForBounds:bounds includeButtons:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
|
||||||
|
[super drawWithFrame:cellFrame inView:controlView];
|
||||||
|
[clearButton drawWithFrame:[self clearButtonRectForBounds:cellFrame] inView:controlView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetCursorRect:(NSRect)cellFrame inView:(NSView *)controlView {
|
||||||
|
[super resetCursorRect:[self textRectForBounds:cellFrame includeButtons:YES] inView:controlView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObject delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength {
|
||||||
|
[super selectWithFrame:[self textRectForBounds:aRect includeButtons:NO] inView:controlView editor:textObject delegate:anObject start:selStart length:selLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)trackMouse:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp {
|
||||||
|
NSRect clearRect = [self clearButtonRectForBounds:cellFrame];
|
||||||
|
if ([controlView mouse:[controlView convertPoint:[event locationInWindow] fromView:nil] inRect:clearRect]) {
|
||||||
|
return [clearButton trackMouse:event inRect:clearRect ofView:controlView untilMouseUp:untilMouseUp];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [super trackMouse:event inRect:[self textRectForBounds:cellFrame includeButtons:YES] ofView:controlView untilMouseUp:untilMouseUp];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MGMPhoneFieldView
|
||||||
|
- (void)setPhoneDelegate:(id)thePhoneDelegate {
|
||||||
|
phoneDelegate = thePhoneDelegate;
|
||||||
|
}
|
||||||
|
- (id<MGMPhoneFieldDelegate>)phoneDelegate {
|
||||||
|
return phoneDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)paste:(id)sender {
|
||||||
|
[super paste:sender];
|
||||||
|
if (phoneDelegate!=nil && [phoneDelegate respondsToSelector:@selector(filterContacts)]) [phoneDelegate filterContacts];
|
||||||
|
}
|
||||||
|
- (void)cut:(id)sender {
|
||||||
|
[super cut:sender];
|
||||||
|
if (phoneDelegate!=nil && [phoneDelegate respondsToSelector:@selector(filterContacts)]) [phoneDelegate filterContacts];
|
||||||
|
}
|
||||||
|
@end
|
19
Classes/VoiceMac/Views/MGMProgressView.h
Normal file
19
Classes/VoiceMac/Views/MGMProgressView.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// MGMLoginProcessView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMProgressView : NSView {
|
||||||
|
NSProgressIndicator *progress;
|
||||||
|
NSTextField *pleaseWaitField;
|
||||||
|
NSTextField *progressField;
|
||||||
|
}
|
||||||
|
- (void)startProgess;
|
||||||
|
- (void)stopProgess;
|
||||||
|
- (void)setProgressTitle:(NSString *)theTitle;
|
||||||
|
@end
|
95
Classes/VoiceMac/Views/MGMProgressView.m
Normal file
95
Classes/VoiceMac/Views/MGMProgressView.m
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// MGMLoginProcessView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/19/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMProgressView.h"
|
||||||
|
|
||||||
|
@implementation MGMProgressView
|
||||||
|
- (id)initWithFrame:(NSRect)frameRect {
|
||||||
|
if (self = [super initWithFrame:frameRect]) {
|
||||||
|
progress = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect((frameRect.size.width-32)/2, (frameRect.size.height-32)/2, 32, 32)];
|
||||||
|
[progress setStyle:NSProgressIndicatorSpinningStyle];
|
||||||
|
[progress setControlSize:NSRegularControlSize];
|
||||||
|
[self addSubview:progress];
|
||||||
|
pleaseWaitField = [[NSTextField alloc] initWithFrame:NSMakeRect(17, (((frameRect.size.height-32)/2)+32)+8, frameRect.size.width-34, 17)];
|
||||||
|
[pleaseWaitField setTextColor:[NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0]];
|
||||||
|
[pleaseWaitField setAlignment:NSCenterTextAlignment];
|
||||||
|
[pleaseWaitField setEditable:NO];
|
||||||
|
[pleaseWaitField setSelectable:NO];
|
||||||
|
[pleaseWaitField setBezeled:NO];
|
||||||
|
[pleaseWaitField setBordered:NO];
|
||||||
|
[pleaseWaitField setDrawsBackground:NO];
|
||||||
|
[pleaseWaitField setStringValue:@"Please Wait..."];
|
||||||
|
[self addSubview:pleaseWaitField];
|
||||||
|
progressField = [[NSTextField alloc] initWithFrame:NSMakeRect(17, ((frameRect.size.height-32)/2)-25, frameRect.size.width-34, 17)];
|
||||||
|
[progressField setTextColor:[NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0]];
|
||||||
|
[progressField setAlignment:NSCenterTextAlignment];
|
||||||
|
[progressField setEditable:NO];
|
||||||
|
[progressField setSelectable:NO];
|
||||||
|
[progressField setBezeled:NO];
|
||||||
|
[progressField setBordered:NO];
|
||||||
|
[progressField setDrawsBackground:NO];
|
||||||
|
[progressField setStringValue:@"Progress"];
|
||||||
|
[self addSubview:progressField];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)dealloc {
|
||||||
|
if (progress)
|
||||||
|
[progress release];
|
||||||
|
if (pleaseWaitField!=nil)
|
||||||
|
[pleaseWaitField release];
|
||||||
|
if (progressField!=nil)
|
||||||
|
[progressField release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
|
||||||
|
[super resizeSubviewsWithOldSize:oldBoundsSize];
|
||||||
|
NSRect frameRect = [self frame];
|
||||||
|
[progress setFrame:NSMakeRect((frameRect.size.width-32)/2, (frameRect.size.height-32)/2, 32, 32)];
|
||||||
|
[pleaseWaitField setFrame:NSMakeRect(17, (((frameRect.size.height-32)/2)+32)+8, frameRect.size.width-34, 17)];
|
||||||
|
[progressField setFrame:NSMakeRect(17, ((frameRect.size.height-32)/2)-25, frameRect.size.width-34, 17)];
|
||||||
|
}
|
||||||
|
- (void)startProgess {
|
||||||
|
[progress startAnimation:self];
|
||||||
|
}
|
||||||
|
- (void)stopProgess {
|
||||||
|
[progress stopAnimation:self];
|
||||||
|
}
|
||||||
|
- (void)setProgressTitle:(NSString *)theTitle {
|
||||||
|
[progressField setStringValue:theTitle];
|
||||||
|
}
|
||||||
|
- (void)drawRect:(NSRect)rect {
|
||||||
|
NSBezierPath *backgroundPath = [NSBezierPath bezierPathWithRect:rect];
|
||||||
|
[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.5] set];
|
||||||
|
[backgroundPath fill];
|
||||||
|
}
|
||||||
|
- (void)mouseDown:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)mouseUp:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)mouseDragged:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)mouseEntered:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)mouseExited:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)mouseMoved:(NSEvent *)theEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
- (BOOL)canBecomeKeyView {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (BOOL)acceptsFirstResponder {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
@end
|
15
Classes/VoiceMac/Views/MGMSplitView.h
Normal file
15
Classes/VoiceMac/Views/MGMSplitView.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// MGMSplitView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMSplitView : NSSplitView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
19
Classes/VoiceMac/Views/MGMSplitView.m
Normal file
19
Classes/VoiceMac/Views/MGMSplitView.m
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// MGMSplitView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/25/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMSplitView.h"
|
||||||
|
|
||||||
|
@implementation MGMSplitView
|
||||||
|
- (CGFloat)dividerThickness {
|
||||||
|
return 2.0;
|
||||||
|
}
|
||||||
|
- (void)drawDividerInRect:(NSRect)aRect {
|
||||||
|
[[NSColor lightGrayColor] set];
|
||||||
|
NSRectFill(aRect);
|
||||||
|
}
|
||||||
|
@end
|
15
Classes/VoiceMac/Views/MGMTranslucentTabView.h
Normal file
15
Classes/VoiceMac/Views/MGMTranslucentTabView.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// MGMTranslucentTabView.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MGMTranslucentTabView : NSTabView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
38
Classes/VoiceMac/Views/MGMTranslucentTabView.m
Normal file
38
Classes/VoiceMac/Views/MGMTranslucentTabView.m
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// MGMTranslucentTabView.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 9/13/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMTranslucentTabView.h"
|
||||||
|
|
||||||
|
@implementation MGMTranslucentTabView
|
||||||
|
- (id)initWithFrame:(NSRect)frameRect {
|
||||||
|
if (self = [super initWithFrame:frameRect]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[self setTabViewType:NSNoTabsNoBorder];
|
||||||
|
[self setDrawsBackground:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(NSRect)frameRect {
|
||||||
|
NSRect bounds = [self bounds];
|
||||||
|
float lineSize = 2.0;
|
||||||
|
float transparency = 0.87;
|
||||||
|
NSBezierPath *strokePath = [NSBezierPath bezierPathWithRect:bounds];
|
||||||
|
[strokePath setLineWidth:lineSize];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:bounds];
|
||||||
|
|
||||||
|
[[NSColor colorWithCalibratedWhite:1.0 alpha:transparency] set];
|
||||||
|
[path fill];
|
||||||
|
[[NSColor colorWithCalibratedWhite:transparency-0.3 alpha:1.0] set];
|
||||||
|
[strokePath stroke];
|
||||||
|
[super drawRect:frameRect];
|
||||||
|
}
|
||||||
|
@end
|
23
Classes/VoiceMac/Views/MGMViewCell.h
Normal file
23
Classes/VoiceMac/Views/MGMViewCell.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// MGMViewCell.h
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/20/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@protocol MGMViewCellProtocol
|
||||||
|
- (void)setFontColor:(NSColor *)theColor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MGMViewCell : NSCell {
|
||||||
|
NSView<MGMViewCellProtocol> *subview;
|
||||||
|
BOOL gradient;
|
||||||
|
}
|
||||||
|
- (id)initGradientCell;
|
||||||
|
|
||||||
|
- (void)addSubview:(NSView *)theView;
|
||||||
|
- (NSView *)view;
|
||||||
|
@end
|
64
Classes/VoiceMac/Views/MGMViewCell.m
Normal file
64
Classes/VoiceMac/Views/MGMViewCell.m
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// MGMViewCell.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 8/20/10.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMViewCell.h"
|
||||||
|
#import "MGMVMAddons.h"
|
||||||
|
|
||||||
|
@implementation MGMViewCell
|
||||||
|
- (id)initGradientCell {
|
||||||
|
if (self = [super init]) {
|
||||||
|
gradient = YES;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addSubview:(NSView *)theView {
|
||||||
|
subview = theView;
|
||||||
|
}
|
||||||
|
- (NSView *)view {
|
||||||
|
return subview;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
|
||||||
|
[super drawWithFrame:cellFrame inView:controlView];
|
||||||
|
|
||||||
|
[subview setFrame:cellFrame];
|
||||||
|
if ([subview superview]!=controlView)
|
||||||
|
[controlView addSubview:subview];
|
||||||
|
}
|
||||||
|
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
|
||||||
|
if ([self isHighlighted])
|
||||||
|
[subview setFontColor:[NSColor whiteColor]];
|
||||||
|
else
|
||||||
|
[subview setFontColor:[NSColor blackColor]];
|
||||||
|
if (!gradient || ![self isHighlighted]) {
|
||||||
|
[super drawInteriorWithFrame:cellFrame inView:controlView];
|
||||||
|
} else {
|
||||||
|
[controlView lockFocus];
|
||||||
|
|
||||||
|
NSColor *startColor = nil;
|
||||||
|
NSColor *endColor = nil;
|
||||||
|
if ([[controlView window] isKeyWindow]) {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLKSRed green:MGMHLKSGreen blue:MGMHLKSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLKERed green:MGMHLKEGreen blue:MGMHLKEBlue alpha:1.0];
|
||||||
|
} else {
|
||||||
|
startColor = [NSColor colorWithCalibratedRed:MGMHLSRed green:MGMHLSGreen blue:MGMHLSBlue alpha:1.0];
|
||||||
|
endColor = [NSColor colorWithCalibratedRed:MGMHLERed green:MGMHLEGreen blue:MGMHLEBlue alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRect drawingRect = [self drawingRectForBounds:cellFrame];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect:drawingRect];
|
||||||
|
[path fillGradientFrom:startColor to:endColor];
|
||||||
|
path = [NSBezierPath bezierPathWithRect:NSMakeRect(drawingRect.origin.x, drawingRect.origin.y, drawingRect.size.width, 1.0)];
|
||||||
|
[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.15] set];
|
||||||
|
[path fill];
|
||||||
|
|
||||||
|
[controlView unlockFocus];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
7
Classes/VoiceMac/VoiceMac_Prefix.pch
Normal file
7
Classes/VoiceMac/VoiceMac_Prefix.pch
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//
|
||||||
|
// Prefix header for all source files of the 'VoiceMac' target in the 'VoiceMac' project
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
13
Classes/VoiceMac/main.m
Normal file
13
Classes/VoiceMac/main.m
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// VoiceMac
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 7/24/09.
|
||||||
|
// Copyright Mr. Gecko's Media 2009. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return NSApplicationMain(argc, (const char **)argv);
|
||||||
|
}
|
7
Contributing.txt
Normal file
7
Contributing.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Contributing to VoiceMac.
|
||||||
|
Contributing to MGMSIP is exactly the same as VoiceMac. However there may not be an about box.
If you want to contribute to VoiceMac, here is what I will do:
1. Add your name (and email if provided) to the change describing what you changed.
2. Add your name (and email/website if provided) to the contributors section.
|
||||||
|
|
||||||
|
Terms for adding:
|
||||||
|
1. The patch must not disrupt up the functionality of VoiceMac.
2. The patch must provide useful changes.
|
||||||
|
3. Anything that you add to the source code of VoiceMac will be under the terms of my licenses.
|
||||||
|
4. If you add changes to VoiceMac's main source code, you may not have them removed, but you will get credit for the changes in the history of the application.
To contribute:
1. Create a patch file using this command “diff -crB VoiceMacOriginal VoiceMac > VoiceMac.patch”.
2. Send the patch to voicemac@mrgeckosmedia.com with your name, email/website (if you want that information), and what you changed so I can add it to the about and change.
|
1
Frameworks/GeckoReporter.framework/GeckoReporter
Symbolic link
1
Frameworks/GeckoReporter.framework/GeckoReporter
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
Versions/Current/GeckoReporter
|
1
Frameworks/GeckoReporter.framework/Headers
Symbolic link
1
Frameworks/GeckoReporter.framework/Headers
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Headers
|
1
Frameworks/GeckoReporter.framework/Resources
Symbolic link
1
Frameworks/GeckoReporter.framework/Resources
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Resources
|
BIN
Frameworks/GeckoReporter.framework/Versions/A/GeckoReporter
Executable file
BIN
Frameworks/GeckoReporter.framework/Versions/A/GeckoReporter
Executable file
Binary file not shown.
@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// GeckoReporter.h
|
||||||
|
// GeckoReporter
|
||||||
|
//
|
||||||
|
// Created by Mr. Gecko on 12/27/09.
|
||||||
|
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MGMReporter.h"
|
||||||
|
#import "MGMSender.h"
|
||||||
|
#import "MGMSystemInfo.h"
|
||||||
|
#import "MGMLog.h"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user