//
//  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