//
// The contents of this file are subject to the Mozilla Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
// the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CPhone, a cross platform voip gui.
//
// The Initial Developer of the Original Code is Derek Smithies.
//
// Copyright (C) 2002 Indranet Technologies Ltd,
// http://www.indranet-technologies.com
// All Rights Reserved.
//
// Contributor(s): _______________
/*
*
* $Log: main.cxx,v $
* Revision 1.20 2004/06/02 04:56:43 dereksmithies
* Bring up to date with CVS as of today, Uses codec plugins now.
* You may need to set the PWLIBPLUGINPATH environment variable.
*
* Revision 1.19 2004/04/23 08:30:33 dereksmithies
* Fixes for windows etc.
*
* Revision 1.18 2004/04/23 05:09:59 dereksmithies
* Fixes so it works with latest openh323 lib, and not lock X display.
*
* Revision 1.17 2004/04/21 22:08:39 dereksmithies
* Fixes to bring up to date with current openh323 CVS. Thanks to Peter Nixon.
*
* Revision 1.16 2004/04/14 07:25:19 dereksmithies
* Updates, so it compiles on windows XP. Big Thanks to Francisco Huerta
*
* Revision 1.15 2003/09/02 04:54:55 dereksmithies
* Fix handling of logging messages to file: switch on/off process now works
*
* Revision 1.14 2003/09/02 03:37:32 dereksmithies
* Add statistics, new icons, toolbuttons (icon + name)
*
* Revision 1.13 2003/08/26 04:48:02 dereksmithies
* Fixes to get statistics working right, add icons, add ok,cancel,apply buttons
*
* Revision 1.12 2003/08/11 01:48:14 dereksmithies
* Fix windows compile errors
*
* Revision 1.11 2003/05/20 03:32:28 dereksmithies
* Better handling of ixj handset states, and call progress states.
*
* Revision 1.10 2003/05/09 03:08:24 dereksmithies
* Fix Microtelco handling, and message display
*
* Revision 1.9 2003/05/06 22:40:36 dereksmithies
* Fixes to get it working correctly on microtelco.
*
* Revision 1.8 2003/04/27 22:30:06 dereksmithies
* Changes to make compatible with current pwlib code
*
* Revision 1.7 2003/04/11 01:08:35 dereksmithies
* Add speed dial support for Quicknet cards.
*
* Revision 1.6 2003/04/04 04:37:49 dereksmithies
* Major upgrade.
* Ixj & microtelco support added. Fix threading issues.
*
* Revision 1.5 2002/11/27 23:52:48 dereksmithies
* Changes to make compatible with current openh323 library code.
*
* Revision 1.4 2002/10/30 00:58:35 dereksmithies
* Fix startup problem, in passing command line arguments to the application
*
* Revision 1.3 2002/10/30 00:57:12 dereksmithies
* *** empty log message ***
*
* Revision 1.2 2002/10/30 00:53:50 dereksmithies
* i
*
* Revision 1.1.1.1 2002/05/12 22:55:01 dereksmithies
* Initial release.
*
*
*
*/
#include <ptlib.h>
#include <qapplication.h>
#include "addressbookSub.h"
#include "h261codec.h"
#include "h323pdu.h"
#include "keys.h"
#include "main.h"
#include "mainwindowSub.h"
#include "version.h"
PCREATE_PROCESS(CPhone);
#define new PNEW
#ifdef HAS_IXJ
#include <ixjlid.h>
#endif
///////////////////////////////////////////////////////////////
CPhone::CPhone()
: PProcess("Cross platform voip gui.", "CPhone",
MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
{
for (PINDEX i = 0; i < eNumWindows; i++)
isActive[(enum WindowName)i] = FALSE;
}
CPhone::~CPhone()
{
}
void CPhone::Main()
{
PConfigArgs args(GetArguments());
PStringArray arrayArgs = args.GetParameters();
char ** argV = arrayArgs.ToCharArray();
int argCount = arrayArgs.GetSize();
QApplication *app = new QApplication(argCount, argV);
mainUi = new MainUi();
app->setMainWidget(mainUi); //Open the main widget for display.
mainUi->show(); //Create Label widgets to render data to.
app->connect(app, SIGNAL(lastWindowClosed()), app, SLOT(quit()));
app->exec();
}
QWidget *CPhone::GetWindow(enum WindowName winName)
{
PWaitAndSignal m(accessMutex);
if (!isActive[winName])
return NULL;
WId id = windowIds[winName];
return QWidget::find(id);
}
void CPhone::SetWindowId(enum WindowName winName, WId newId)
{
PWaitAndSignal m(accessMutex);
windowIds[winName] = newId;
isActive[winName] = TRUE;
}
BOOL CPhone::ForgetExists(enum WindowName winName, WId winId)
{
PWaitAndSignal m(accessMutex);
if (windowIds[winName] == winId) {
isActive[winName] = FALSE;
return TRUE;
}
return FALSE;
}
void CPhone::ForgetCallAnswer()
{
PWaitAndSignal m(accessMutex);
windowIds[eCallAnswer] = windowIds[eMainUi];
isActive[eCallAnswer] = FALSE;
}
///////////////////////////////////////////////////////////////
ConnectOptions::ConnectOptions()
{
myTraceFile = NULL;
}
ConnectOptions::~ConnectOptions()
{
}
void ConnectOptions::CloseCurrentTraceFile()
{
#if PTRACING
PWaitAndSignal m(traceAccess);
PTrace::SetStream(NULL);
PTrace::SetLevel(0);
if (myTraceFile != NULL) {
myTraceFile->Close();
delete myTraceFile;
}
myTraceFile = NULL;
#endif
}
void ConnectOptions::InstallOneTraceOption(BOOL useOption, unsigned option)
{
#if PTRACING
if (useOption)
PTrace::SetOptions(option);
else
PTrace::ClearOptions(option);
#endif
}
void ConnectOptions::InstallLogging()
{
#if PTRACING
PWaitAndSignal m(traceAccess);
if (!doLogInternalActivity) {
CloseCurrentTraceFile();
return;
}
PTrace::SetLevel(logLevel);
InstallOneTraceOption(logBlocks, PTrace::Blocks);
InstallOneTraceOption(logDateTime, PTrace::DateAndTime);
InstallOneTraceOption(logFileLine, PTrace::FileAndLine);
InstallOneTraceOption(logLevelNumber, PTrace::TraceLevel);
InstallOneTraceOption(logThreadAddress, PTrace::ThreadAddress);
InstallOneTraceOption(logThreadNames, PTrace::Thread);
InstallOneTraceOption(logTimestamp, PTrace::Timestamp);
if (myTraceFile != NULL) {
if (myTraceFile->GetFilePath() != PFilePath(logFileName))
CloseCurrentTraceFile();
}
if (myTraceFile == NULL) {
PTextFile * traceFile = new PTextFile;
if (!traceFile->Open(logFileName, PFile::WriteOnly)) {
delete traceFile;
PString errMessage = "Failed to open \"" + logFileName + "\" for logging";
CPhone::GetUi().DisplayCriticalError(errMessage);
return;
}
myTraceFile = traceFile;
PTrace::SetStream(traceFile);
#if 0
PProcess & process = PProcess::Current();
// PTRACE(0, process.GetName());
<< " by " << process.GetManufacturer()
<< " on " << process.GetOSClass() << ' ' << process.GetOSName()
<< " Version " << process.GetVersion(TRUE)
<< " (" << process.GetOSVersion() << '-' << process.GetOSHardware() << ')');
#endif
}
#endif
}
BOOL ConnectOptions::Initialise()
{
PConfig *config = new PConfig(SETTINGS_CONFIG);
noFastStart = config->GetBoolean(CHECKBOXDISABLEFASTSTART_KEY);
autoAnswer = config->GetBoolean(CHECKBOXAUTOANSWER_KEY);
noH245Tunnelling = config->GetBoolean(CHECKBOXDISABLEH245TUNNEL_KEY);
searchForGatekeeper = config->GetBoolean(CHECKBOXSEARCHFORAGATEKEEPER_KEY);
gatekeeperName = config->GetString(LINEEDITGATEKEEPER_KEY);
useDefaultAudioBandwidth = config->GetBoolean(CHECKBOXDEFAULTAUDIO_KEY);
useDefaultVideoBandwidth = config->GetBoolean(CHECKBOXDEFAULTVIDEO_KEY);
audioBandwidth = config->GetInteger(SPINBOXBANDWIDTHAUDIO_KEY);
videoBandwidth = config->GetInteger(SPINBOXBANDWIDTHVIDEO_KEY);
packetUtilization = config->GetInteger(SPINBOXFRAMESETHERNETPACKET_KEY);
userName = config->GetString(LINEEDITUSERNAME_KEY);
doNatTraversal = config->GetBoolean(DONATTRAVERSAL_KEY);
externalNatAddress = config->GetString(EXTERNALNATADDRESS_KEY);
videoReceptionEnabled = config->GetBoolean(CHECKBOXVIDEORECEPTIONENABLED_KEY, TRUE);
videoTransmissionEnabled = config->GetBoolean(CHECKBOXVIDEOTRANSMISSIONENABLED_KEY, TRUE);
doMicroTelco = config->GetBoolean(DOMICROTELCO_KEY);
microTelcoAccount = config->GetString(MICROTELCOACCOUNT_KEY);
microTelcoPassword = config->GetString(MICROTELCOPASSWORD_KEY);
lowUdpPort = config->GetInteger(SPINBOXLOWUDPPORT_KEY, 5000);
highUdpPort = config->GetInteger(SPINBOXHIGHUDPPORT_KEY, 6000);
logLevel = config->GetInteger(SPINBOXLOGLEVEL_KEY);
logFileName = config->GetString(LOGFILENAME_KEY);
doLogInternalActivity = config->GetBoolean(DOLOGINTERNALACTIVITY_KEY);
logBlocks = config->GetBoolean(DOLOGBLOCKS_KEY);
logDateTime = config->GetBoolean(DOLOGDATETIME_KEY);
logFileLine = config->GetBoolean(DOLOGFILELINE_KEY);
logLevelNumber = config->GetBoolean(DOLOGLEVELNUMBER_KEY);
logThreadAddress = config->GetBoolean(DOLOGTHREADADDRESS_KEY);
logThreadNames = config->GetBoolean(DOLOGTHREADNAMES_KEY);
logTimestamp = config->GetBoolean(DOLOGTIMESTAMP_KEY);
audioStats = config->GetBoolean(WINDOWAUDIOSTATS_KEY);
videoStats = config->GetBoolean(WINDOWVIDEOSTATS_KEY);
////////////////////////////////
delete config;
if (userName.IsEmpty())
userName = CPhone::GetUi().GetLocalUserName();
if (doLogInternalActivity)
InstallLogging();
return TRUE;
}
void ConnectOptions::LoadCapabilitiesFromDisk()
{
PWaitAndSignal m(access);
PConfig *config = new PConfig(CODECS_CONFIG);
PStringList codecKeys = config->GetKeys();
PINDEX i;
for (i = 0; i < codecKeys.GetSize(); i++)
if ((availableCapabilities.GetStringsIndex(codecKeys[i]) != P_MAX_INDEX) && config->GetBoolean(codecKeys[i]))
enabledCapabilities.AppendString(codecKeys[i]);
UpdateDisabledCapabilities();
delete config;
}
BOOL ConnectOptions::SaveSettings()
{
PWaitAndSignal m(access);
PConfig *config = new PConfig(SETTINGS_CONFIG);
config->SetBoolean(CHECKBOXDISABLEFASTSTART_KEY,noFastStart);
config->SetBoolean(CHECKBOXAUTOANSWER_KEY, autoAnswer);
config->SetBoolean(CHECKBOXDISABLEH245TUNNEL_KEY, noH245Tunnelling);
config->SetBoolean(CHECKBOXSEARCHFORAGATEKEEPER_KEY, searchForGatekeeper);
config->SetString(LINEEDITGATEKEEPER_KEY, gatekeeperName);
config->SetBoolean(CHECKBOXDEFAULTAUDIO_KEY, useDefaultAudioBandwidth);
config->SetBoolean(CHECKBOXDEFAULTVIDEO_KEY, useDefaultVideoBandwidth);
config->SetInteger(SPINBOXBANDWIDTHAUDIO_KEY, audioBandwidth);
config->SetInteger(SPINBOXBANDWIDTHVIDEO_KEY, videoBandwidth);
config->SetInteger(SPINBOXFRAMESETHERNETPACKET_KEY, packetUtilization);
config->SetString(LINEEDITUSERNAME_KEY, userName);
config->SetBoolean(CHECKBOXVIDEORECEPTIONENABLED_KEY, videoReceptionEnabled);
config->SetBoolean(CHECKBOXVIDEOTRANSMISSIONENABLED_KEY, videoTransmissionEnabled);
config->SetBoolean(DONATTRAVERSAL_KEY, doNatTraversal);
config->SetString(EXTERNALNATADDRESS_KEY, externalNatAddress);
config->SetBoolean(DOMICROTELCO_KEY, doMicroTelco );
config->SetString(MICROTELCOACCOUNT_KEY, microTelcoAccount );
config->SetString(MICROTELCOPASSWORD_KEY, microTelcoPassword);
config->SetInteger(SPINBOXLOWUDPPORT_KEY, lowUdpPort);
config->SetInteger(SPINBOXHIGHUDPPORT_KEY, highUdpPort);
config->SetBoolean(DOLOGINTERNALACTIVITY_KEY, doLogInternalActivity);
config->SetString(LOGFILENAME_KEY, logFileName);
config->SetInteger(SPINBOXLOGLEVEL_KEY, logLevel);
config->SetBoolean(DOLOGBLOCKS_KEY, logBlocks);
config->SetBoolean(DOLOGDATETIME_KEY, logDateTime);
config->SetBoolean(DOLOGFILELINE_KEY, logFileLine);
config->SetBoolean(DOLOGLEVELNUMBER_KEY, logLevelNumber);
config->SetBoolean(DOLOGTHREADADDRESS_KEY, logThreadAddress);
config->SetBoolean(DOLOGTHREADNAMES_KEY, logThreadNames);
config->SetBoolean(DOLOGTIMESTAMP_KEY, logTimestamp);
config->SetBoolean(WINDOWAUDIOSTATS_KEY, audioStats);
config->SetBoolean(WINDOWVIDEOSTATS_KEY, videoStats);
delete config;
////////////////////////////////
config = new PConfig(CODECS_CONFIG);
PINDEX i;
PStringList codecKeys = config->GetKeys();
for (i = 0; i < codecKeys.GetSize(); i++)
config->DeleteKey(codecKeys[i]);
for(i = 0; i < enabledCapabilities.GetSize(); i++)
config->SetBoolean(enabledCapabilities[i], TRUE);
delete config;
return TRUE;
}
PStringList ConnectOptions::GetAvailableCapabilities()
{
PWaitAndSignal m(access);
return availableCapabilities;
}
PStringList ConnectOptions::GetDisabledCapabilities()
{
PWaitAndSignal m(access);
return disabledCapabilities;
}
PStringList ConnectOptions::GetEnabledCapabilities()
{
PWaitAndSignal m(access);
return enabledCapabilities;
}
void ConnectOptions::SetAvailableCapabilities(PStringList newCapabilities)
{
PWaitAndSignal m(access);
availableCapabilities = newCapabilities;
UpdateDisabledCapabilities();
}
void ConnectOptions::SetEnabledCapabilities(PStringList newCapabilities)
{
PWaitAndSignal m(access);
enabledCapabilities = newCapabilities;
UpdateDisabledCapabilities();
}
void ConnectOptions::UpdateDisabledCapabilities()
{
PWaitAndSignal m(access);
disabledCapabilities.RemoveAll();
for (PINDEX i = 0; i < availableCapabilities.GetSize(); i++) {
PINDEX loc = enabledCapabilities.GetStringsIndex(availableCapabilities[i]);
if (loc == P_MAX_INDEX)
disabledCapabilities.AppendString(availableCapabilities[i]);
}
}
void ConnectOptions::PrintOn(ostream & strm) const
{
strm << "-------------------------------------------------------" << endl
<< "search for Gatekeeper is " << searchForGatekeeper << endl
<< "gatekeeper Name is " << gatekeeperName << endl
<< endl
<< "autoAnswer is " << autoAnswer << endl
<< "noFastStart is " << noFastStart << endl
<< "noH245Tunnelling is " << noH245Tunnelling << endl
<< endl
<< "useDefaultAudioBandwidth is " << useDefaultAudioBandwidth << endl
<< "useDefaultVideoBandwidth is " << useDefaultVideoBandwidth << endl
<< "audio Bandwidth is " << audioBandwidth << endl
<< "video Bandwidth is " << videoBandwidth << endl
<< "packet utilization is " << packetUtilization << endl
<< endl
<< "video reception enabled is " << videoReceptionEnabled << endl
<< "video transmission enabled is " << videoTransmissionEnabled << endl
<< endl
<< "user Name is " << userName << endl
<< endl
<< "Enabled codecs are " << endl
<< enabledCapabilities << endl
<< "Disabled codecs are " << endl
<< disabledCapabilities << endl
<< endl
<< "Micro telco on is " << doMicroTelco << endl
<< "Nat traversal on is " << doNatTraversal << endl
<< endl
<< "Log internal activity " << doLogInternalActivity << endl
<< "Log level " << logLevel << endl
<< "Log file name " << logFileName << endl
<< "Log Blocks " << logBlocks << endl
<< "Log Date & Time " << logDateTime << endl
<< "Log File Line " << logFileLine << endl
<< "Log Level Number " << logLevelNumber << endl
<< "Log Thread Address " << logThreadAddress << endl
<< "Log Thread Names " << logThreadNames << endl
<< "Log Timestamp " << logTimestamp << endl
<< endl
<< "AudioStats " << audioStats << endl
<< "VideoStats " << videoStats << endl
<< "-------------------------------------------------------" << endl;
}
///////////////////////////////////////////////////////////////
CpConnection::CpConnection(unsigned callReference,
unsigned options)
: H323Connection(CPhone::GetUi(), callReference, options)
{
}
BOOL CpConnection::OnSendSignalSetup(H323SignalPDU & setupPDU)
{
if (!CPhone::GetUi().setupInformation) {
setupPDU.m_h323_uu_pdu.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardData);
setupPDU.m_h323_uu_pdu.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard);
endpoint.SetH221NonStandardInfo(setupPDU.m_h323_uu_pdu.m_nonStandardData.m_nonStandardIdentifier);
setupPDU.m_h323_uu_pdu.m_nonStandardData.m_data = CPhone::GetUi().setupInformation;
}
return TRUE;
}
H323Connection::AnswerCallResponse
CpConnection::OnAnswerCall(const PString & caller,
const H323SignalPDU &,
H323SignalPDU &)
{
return CPhone::GetUi().AnswerCallConditional(caller, GetCallToken());
}
BOOL CpConnection::OnStartLogicalChannel(H323Channel & channel)
{
if (!H323Connection::OnStartLogicalChannel(channel))
return FALSE;
int videoQuality = CPhone::GetUi().videoOpts.GetReceiveQuality();
if ( (channel.GetDirection() == H323Channel::IsReceiver) &&
(PIsDescendant(channel.GetCodec(), H323VideoCodec)) &&
(videoQuality >= 0) )
{
PThread::Current()->Sleep(3000);
H323ControlPDU pdu;
H245_CommandMessage & command = pdu.Build(H245_CommandMessage::e_miscellaneousCommand);
H245_MiscellaneousCommand & miscCommand = command;
miscCommand.m_logicalChannelNumber = (unsigned)channel.GetNumber();
miscCommand.m_type.SetTag(H245_MiscellaneousCommand_type::e_videoTemporalSpatialTradeOff);
PASN_Integer & value = miscCommand.m_type;
value = videoQuality;
WriteControlPDU(pdu);
}
return TRUE;
}
BOOL CpConnection::OnAlerting(const H323SignalPDU & /*alertingPDU*/,
const PString & username)
{
PAssert((CPhone::GetUi().epState == MainUi::epConnectingCall) ||
(CPhone::GetUi().epState == MainUi::epWaitingForAnswer) ,
psprintf("Have received an alerting. However, am in in state %i ",
CPhone::GetUi().epState));
CPhone::GetUi().DisplayMessage("Requesting \"" + username + "\"");
CPhone::GetUi().epState = MainUi::epWaitingForAnswer;
return TRUE;
}
void CpConnection::OnUserInputString(const PString & value)
{
cerr << "UNknown :: User input received: \"" << value << '"' << endl;
}
//////////////////////////////////////////////////////////////////////
#ifdef HAS_IXJ
LidHandlerThread::LidHandlerThread()
: PThread(1000, NoAutoDeleteThread)
{
playingTone = FALSE;
Resume();
}
LidHandlerThread::~LidHandlerThread()
{
}
void LidHandlerThread::TerminateThread()
{
exitFlag.Signal();
}
BOOL LidHandlerThread::SetEchoCancellation(PINDEX i)
{
return lid.SetAEC(OpalIxJDevice::POTSLine, (OpalLineInterfaceDevice::AECLevels)i);
}
BOOL LidHandlerThread::SetRecordVolume(PINDEX i)
{
return lid.SetRecordVolume(OpalIxJDevice::POTSLine, i);
}
BOOL LidHandlerThread::SetPlayVolume(PINDEX i)
{
return lid.SetPlayVolume(OpalIxJDevice::POTSLine, i);
}
BOOL LidHandlerThread::SetPhoneDevice(PString name)
{
lid.Close();
if (!lid.Open(name)) {
CPhone::GetUi().DisplayMessage("Failed to Open " + name);
return FALSE;
}
lidNameMutex.Wait();
lidName = name;
lidNameMutex.Signal();
CPhone::GetUi().DisplayMessage("Open " + name + " fine....");
lid.SetLineToLineDirect(0, 1, FALSE);
lid.EnableAudio(OpalIxJDevice::POTSLine, TRUE);
oldIsOffHook = lid.IsLineOffHook(OpalIxJDevice::POTSLine);
return TRUE;
}
void LidHandlerThread::PlayTone(OpalLineInterfaceDevice::CallProgressTones newTone)
{
playingTone = TRUE;
lid.PlayTone(OpalIxJDevice::POTSLine, newTone);
}
void LidHandlerThread::StopTone()
{
if (!playingTone)
return;
playingTone = FALSE;
lid.StopTone(OpalIxJDevice::POTSLine);
}
void LidHandlerThread::AddIxjCapabilities(H323Capabilities &caps)
{
if (lid.IsOpen())
H323_LIDCapability::AddAllCapabilities(lid, caps, 0, 0);
}
PString LidHandlerThread::GetDeviceName()
{
PWaitAndSignal m(lidNameMutex);
return lidName;
}
void LidHandlerThread::RingPhone(BOOL isOn)
{
if (!lid.IsOpen())
return;
lid.RingLine(OpalIxJDevice::POTSLine, isOn ? 0x1010 : 0);
}
void LidHandlerThread::Main()
{
BOOL newIsOffHook = FALSE;
BOOL oldIsOffHook = FALSE;
MainUi::States oldState, newState;
PString destAddress;
char digit;
startFlag.Wait();
oldState = CPhone::GetUi().GetEpState();
while (!exitFlag.Wait(100)) {
if (!lid.IsOpen())
continue;
newState = CPhone::GetUi().GetEpState();
newIsOffHook = lid.IsLineOffHook(OpalIxJDevice::POTSLine);
if (newIsOffHook != oldIsOffHook)
CPhone::GetUi().HandleHandsetDown(!newIsOffHook);
oldIsOffHook = newIsOffHook;
if (newState != oldState) {
StopTone();
switch(newState) {
case MainUi::epDialTone:
PlayTone(OpalLineInterfaceDevice::DialTone);
case MainUi::epNoTone:
remoteFullAddress = PString();
break;
case MainUi::epAnsweringCall:
case MainUi::epConnectingCall:
case MainUi::epWaitingForAnswer:
if (!remoteFullAddress.IsEmpty()) {
if (remoteFullAddress.FindRegEx("[^0-9]") != P_MAX_INDEX)
PlayTone(OpalLineInterfaceDevice::RingTone); /*Not calling a phone number */
}
break;
case MainUi::epCallInProgress:
break;
case MainUi::epCallHungup:
PlayTone(OpalLineInterfaceDevice::BusyTone);
break;
default:
break;
}
}
oldState = newState;
if (newState == MainUi::epDialTone) {
digit = lid.ReadDTMF(OpalIxJDevice::POTSLine);
if (digit) {
StopTone();
if (digit == '#') {
PString name;
AddressBook::GetNameAddressForSpeedDial(name, remoteFullAddress, destAddress);
CPhone::GetUi().DisplayMessage("Start call to " + name);
CPhone::GetUi().StartCall(remoteFullAddress);
destAddress = PString();
} else {
destAddress += digit;
CPhone::GetUi().DisplayMessage("Speed dial " + destAddress);
}
}
}
}
}
#endif
// End of File ///////////////////////////////////////////////////////////////
syntax highlighted by Code2HTML, v. 0.9.1