diff --git a/.gitignore b/.gitignore index 123da9aae877b89bf3a2d1f659a422bf1fe292c4..9b50f67f10d2b6e59dfb4137d2c73babf22fa0db 100644 --- a/.gitignore +++ b/.gitignore @@ -69,5 +69,9 @@ config_auto.h # Ignore temp files *~ +# Cscope/Ctags files +cscope.* +tags + # IDE stuffs nbproject diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp index af0b0689d7505b4b951704dce1c1919a00c85029..094eb1afc20d46ecf743ebf1df6c43599a40181b 100644 --- a/daemon/src/account.cpp +++ b/daemon/src/account.cpp @@ -32,8 +32,9 @@ #include "account.h" #include "manager.h" +#include "dbus/configurationmanager.h" -Account::Account(const std::string& accountID, const std::string &type) : +Account::Account(const std::string &accountID, const std::string &type) : accountID_(accountID) , username_() , hostname_() @@ -54,8 +55,7 @@ Account::Account(const std::string& accountID, const std::string &type) : } Account::~Account() -{ -} +{} void Account::setRegistrationState(const RegistrationState &state) { @@ -63,7 +63,8 @@ void Account::setRegistrationState(const RegistrationState &state) registrationState_ = state; // Notify the client - Manager::instance().connectionStatusNotification(); + ConfigurationManager *c(Manager::instance().getDbusManager()->getConfigurationManager()); + c->registrationStateChanged(accountID_, registrationState_); } } diff --git a/daemon/src/audio/audiortp/audio_rtp_factory.cpp b/daemon/src/audio/audiortp/audio_rtp_factory.cpp index 5ce37ce1f53c08fc342d4b60daff3beefc3173dd..2170b06e52a77e238fa1c4241ec4cc4bac363218 100644 --- a/daemon/src/audio/audiortp/audio_rtp_factory.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_factory.cpp @@ -43,17 +43,19 @@ namespace sfl { AudioRtpFactory::AudioRtpFactory(SIPCall *ca) : rtpSession_(NULL), - audioRtpThreadMutex_(), srtpEnabled_(false), - keyExchangeProtocol_(Symmetric), helloHashEnabled_(false), - remoteContext_(NULL), localContext_(NULL), ca_(ca) + audioRtpThreadMutex_(), srtpEnabled_(false), helloHashEnabled_(false), + cachedRemoteContext_(0), cachedLocalContext_(0), ca_(ca), + keyExchangeProtocol_(NONE) {} AudioRtpFactory::~AudioRtpFactory() { delete rtpSession_; + delete cachedLocalContext_; + delete cachedRemoteContext_; } -void AudioRtpFactory::initAudioRtpConfig() +void AudioRtpFactory::initConfig() { if (rtpSession_ != NULL) stop(); @@ -65,48 +67,48 @@ void AudioRtpFactory::initAudioRtpConfig() if (account) { srtpEnabled_ = account->getSrtpEnabled(); std::string key(account->getSrtpKeyExchange()); - - if (key == "sdes") - keyExchangeProtocol_ = Sdes; - else if (key == "zrtp") - keyExchangeProtocol_ = Zrtp; - else - keyExchangeProtocol_ = Symmetric; - + if (srtpEnabled_) { + if (key == "sdes") + keyExchangeProtocol_ = SDES; + else if (key == "zrtp") + keyExchangeProtocol_ = ZRTP; + } else { + keyExchangeProtocol_ = NONE; + } helloHashEnabled_ = account->getZrtpHelloHash(); } else { srtpEnabled_ = false; - keyExchangeProtocol_ = Symmetric; + keyExchangeProtocol_ = NONE; helloHashEnabled_ = false; } } -void AudioRtpFactory::initAudioSymmetricRtpSession() +void AudioRtpFactory::initSession() { ost::MutexLock m(audioRtpThreadMutex_); if (srtpEnabled_) { - std::string zidFilename(Manager::instance().voipPreferences.getZidFile()); + const std::string zidFilename(Manager::instance().voipPreferences.getZidFile()); switch (keyExchangeProtocol_) { - case Zrtp: - rtpSession_ = new AudioZrtpSession(ca_, zidFilename); + case ZRTP: + rtpSession_ = new AudioZrtpSession(*ca_, zidFilename); // TODO: be careful with that. The hello hash is computed asynchronously. Maybe it's // not even available at that point. if (helloHashEnabled_) ca_->getLocalSDP()->setZrtpHash(static_cast<AudioZrtpSession *>(rtpSession_)->getHelloHash()); break; - case Sdes: - rtpSession_ = new AudioSrtpSession(ca_); + case SDES: + rtpSession_ = new AudioSrtpSession(*ca_); break; default: throw UnsupportedRtpSessionType("Unsupported Rtp Session Exception Type!"); } } else - rtpSession_ = new AudioSymmetricRtpSession(ca_); + rtpSession_ = new AudioSymmetricRtpSession(*ca_); } void AudioRtpFactory::start(AudioCodec* audiocodec) @@ -114,26 +116,17 @@ void AudioRtpFactory::start(AudioCodec* audiocodec) if (rtpSession_ == NULL) throw AudioRtpFactoryException("AudioRtpFactory: Error: RTP session was null when trying to start audio thread"); - if (rtpSession_->getAudioRtpType() == Sdes) - if (localContext_ and remoteContext_) - static_cast<AudioSrtpSession *>(rtpSession_)->restoreCryptoContext(localContext_, remoteContext_); + if (keyExchangeProtocol_ == SDES and cachedLocalContext_ and cachedRemoteContext_) + static_cast<AudioSrtpSession *>(rtpSession_)->restoreCryptoContext(cachedLocalContext_, cachedRemoteContext_); - if (rtpSession_->startRtpThread(audiocodec) != 0) - throw AudioRtpFactoryException("AudioRtpFactory: Error: Failed to start AudioZrtpSession thread"); + if (rtpSession_->startRtpThread(*audiocodec) != 0) + throw AudioRtpFactoryException("AudioRtpFactory: Error: Failed to start AudioRtpSession thread"); } void AudioRtpFactory::stop() { ost::MutexLock mutex(audioRtpThreadMutex_); - if (rtpSession_ == NULL) - return; - - if (rtpSession_->getAudioRtpType() == Sdes) { - localContext_ = static_cast<AudioSrtpSession*>(rtpSession_)->localCryptoCtx_; - remoteContext_ = static_cast<AudioSrtpSession*>(rtpSession_)->remoteCryptoCtx_; - } - delete rtpSession_; rtpSession_ = NULL; } @@ -151,7 +144,7 @@ void AudioRtpFactory::updateSessionMedia(AudioCodec *audiocodec) if (rtpSession_ == NULL) throw AudioRtpFactoryException("AudioRtpFactory: Error: rtpSession_ was null when trying to update IP address"); - rtpSession_->updateSessionMedia(audiocodec); + rtpSession_->updateSessionMedia(*audiocodec); } void AudioRtpFactory::updateDestinationIpAddress() @@ -162,7 +155,7 @@ void AudioRtpFactory::updateDestinationIpAddress() sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession() { - if (rtpSession_->getAudioRtpType() == Zrtp) + if (keyExchangeProtocol_ == ZRTP) return static_cast<AudioZrtpSession *>(rtpSession_); else throw AudioRtpFactoryException("RTP: Error: rtpSession_ is NULL in getAudioZrtpSession"); @@ -170,17 +163,20 @@ sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession() void sfl::AudioRtpFactory::initLocalCryptoInfo() { - if (rtpSession_ && rtpSession_->getAudioRtpType() == Sdes) { - static_cast<AudioSrtpSession *>(rtpSession_)->initLocalCryptoInfo(); - ca_->getLocalSDP()->setLocalSdpCrypto(static_cast<AudioSrtpSession *>(rtpSession_)->getLocalCryptoInfo()); + if (rtpSession_ && keyExchangeProtocol_ == SDES) { + AudioSrtpSession *srtp = static_cast<AudioSrtpSession*>(rtpSession_); + // the context is invalidated and deleted by the call to initLocalCryptoInfo + cachedLocalContext_ = srtp->initLocalCryptoInfo(); + ca_->getLocalSDP()->setLocalSdpCrypto(srtp->getLocalCryptoInfo()); } } void AudioRtpFactory::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) { - if (rtpSession_ && rtpSession_->getAudioRtpType() == Sdes) - static_cast<AudioSrtpSession *>(rtpSession_)->setRemoteCryptoInfo(nego); - else + if (rtpSession_ and keyExchangeProtocol_ == SDES) { + AudioSrtpSession *srtp = static_cast<AudioSrtpSession *>(rtpSession_); + cachedRemoteContext_ = srtp->setRemoteCryptoInfo(nego); + } else throw AudioRtpFactoryException("RTP: Error: rtpSession_ is NULL in setRemoteCryptoInfo"); } diff --git a/daemon/src/audio/audiortp/audio_rtp_factory.h b/daemon/src/audio/audiortp/audio_rtp_factory.h index c91f0e18641c6d47b8fe67cc7345f4fc4e7c7b35..9aa90d3b4d1a13112edb8623770b515c2003eb5d 100644 --- a/daemon/src/audio/audiortp/audio_rtp_factory.h +++ b/daemon/src/audio/audiortp/audio_rtp_factory.h @@ -62,15 +62,15 @@ class AudioRtpFactory { AudioRtpFactory(SIPCall *ca); ~AudioRtpFactory(); - void initAudioRtpConfig(); + void initConfig(); /** * Lazy instantiation method. Create a new RTP session of a given * type according to the content of the configuration file. * @param ca A pointer on a SIP call - * @return A new AudioSymmetricRtpSession object + * @return A new AudioRtpSession object */ - void initAudioSymmetricRtpSession(); + void initSession(); /** * Start the audio rtp thread of the type specified in the configuration @@ -103,7 +103,7 @@ class AudioRtpFactory { void updateDestinationIpAddress(); bool isSdesEnabled() const { - return srtpEnabled_ and keyExchangeProtocol_ == sfl::Sdes; + return srtpEnabled_ and keyExchangeProtocol_ == SDES; } /** @@ -140,28 +140,26 @@ class AudioRtpFactory { private: NON_COPYABLE(AudioRtpFactory); + enum KeyExchangeProtocol { NONE, SDES, ZRTP }; AudioRtpSession *rtpSession_; ost::Mutex audioRtpThreadMutex_; - // Field used when initializinga udio rtp session + // Field used when initializing audio rtp session // May be set manually or from config using initAudioRtpConfig bool srtpEnabled_; - // Field used when initializinga udio rtp session - // May be set manually or from config using initAudioRtpConfig - RtpMethod keyExchangeProtocol_; - // Field used when initializinga udio rtp session // May be set manually or from config using initAudioRtpConfig bool helloHashEnabled_; /** Remote srtp crypto context to be set into incoming data queue. */ - ost::CryptoContext *remoteContext_; + ost::CryptoContext *cachedRemoteContext_; /** Local srtp crypto context to be set into outgoing data queue. */ - ost::CryptoContext *localContext_; + ost::CryptoContext *cachedLocalContext_; SIPCall *ca_; + KeyExchangeProtocol keyExchangeProtocol_; }; } #endif // __AUDIO_RTP_FACTORY_H__ diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp index 8ce03be48914e6902196162e5b23d51cba85c0d1..99c5064d94a00d36bcfba5c137f3a9ff1848e312 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp @@ -67,13 +67,17 @@ AudioRtpRecord::~AudioRtpRecord() } -AudioRtpRecordHandler::AudioRtpRecordHandler(SIPCall *ca) : audioRtpRecord_(), id_(ca->getCallId()), echoCanceller(ca->getMemoryPool()), gainController(8000, -10.0) +AudioRtpRecordHandler::AudioRtpRecordHandler(SIPCall &call) : + audioRtpRecord_(), + id_(call.getCallId()), + echoCanceller(call.getMemoryPool()), + gainController(8000, -10.0) {} AudioRtpRecordHandler::~AudioRtpRecordHandler() {} -void AudioRtpRecordHandler::setRtpMedia(AudioCodec* audioCodec) +void AudioRtpRecordHandler::setRtpMedia(AudioCodec *audioCodec) { ost::MutexLock lock(audioRtpRecord_.audioCodecMutex_); diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.h b/daemon/src/audio/audiortp/audio_rtp_record_handler.h index 9012049a133d1b279448835ba31e3c5d7bcb4a75..ac630e2872aac936f7aa05f8c73897c80e6b1296 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.h +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.h @@ -103,7 +103,7 @@ class AudioRtpRecord { class AudioRtpRecordHandler { public: - AudioRtpRecordHandler(SIPCall *); + AudioRtpRecordHandler(SIPCall &); virtual ~AudioRtpRecordHandler(); /** diff --git a/daemon/src/audio/audiortp/audio_rtp_session.cpp b/daemon/src/audio/audiortp/audio_rtp_session.cpp index a334d063c642eb2b0fae2005435d8d547b19525c..7a34d7ba82d94d4557502af243526e83d81154c4 100644 --- a/daemon/src/audio/audiortp/audio_rtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_session.cpp @@ -43,29 +43,27 @@ #include "manager.h" namespace sfl { -AudioRtpSession::AudioRtpSession(SIPCall * sipcall, RtpMethod type, ost::RTPDataQueue *queue, ost::Thread *thread) : - AudioRtpRecordHandler(sipcall) - , ca_(sipcall) - , type_(type) - , remote_ip_() - , remote_port_(0) +AudioRtpSession::AudioRtpSession(SIPCall &call, ost::RTPDataQueue &queue, ost::Thread &thread) : + AudioRtpRecordHandler(call) + , call_(call) , timestamp_(0) , timestampIncrement_(0) - , timestampCount_(0) - , isStarted_(false) , queue_(queue) + , isStarted_(false) + , remote_ip_() + , remote_port_(0) + , timestampCount_(0) , thread_(thread) { - assert(ca_); - queue_->setTypeOfService(ost::RTPDataQueue::tosEnhanced); + queue_.setTypeOfService(ost::RTPDataQueue::tosEnhanced); } AudioRtpSession::~AudioRtpSession() { - queue_->disableStack(); + queue_.disableStack(); } -void AudioRtpSession::updateSessionMedia(AudioCodec *audioCodec) +void AudioRtpSession::updateSessionMedia(AudioCodec &audioCodec) { int lastSamplingRate = audioRtpRecord_.codecSampleRate_; @@ -80,9 +78,9 @@ void AudioRtpSession::updateSessionMedia(AudioCodec *audioCodec) } -void AudioRtpSession::setSessionMedia(AudioCodec *audioCodec) +void AudioRtpSession::setSessionMedia(AudioCodec &audioCodec) { - setRtpMedia(audioCodec); + setRtpMedia(&audioCodec); // store codec info locally int payloadType = getCodecPayloadType(); @@ -96,26 +94,28 @@ void AudioRtpSession::setSessionMedia(AudioCodec *audioCodec) else timestampIncrement_ = frameSize; - DEBUG("AudioRptSession: Codec payload: %d", payloadType); - DEBUG("AudioSymmetricRtpSession: Codec sampling rate: %d", smplRate); - DEBUG("AudioSymmetricRtpSession: Codec frame size: %d", frameSize); - DEBUG("AudioSymmetricRtpSession: RTP timestamp increment: %d", timestampIncrement_); + DEBUG("AudioRtpSession: Codec payload: %d", payloadType); + DEBUG("AudioRtpSession: Codec sampling rate: %d", smplRate); + DEBUG("AudioRtpSession: Codec frame size: %d", frameSize); + DEBUG("AudioRtpSession: RTP timestamp increment: %d", timestampIncrement_); if (payloadType == g722PayloadType) { - DEBUG("AudioSymmetricRtpSession: Setting G722 payload format"); - queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, g722RtpClockRate)); + DEBUG("AudioRtpSession: Setting G722 payload format"); + queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, g722RtpClockRate)); } else { if (dynamic) { - DEBUG("AudioSymmetricRtpSession: Setting dynamic payload format"); - queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, smplRate)); + DEBUG("AudioRtpSession: Setting dynamic payload format"); + queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, smplRate)); } else { - DEBUG("AudioSymmetricRtpSession: Setting static payload format"); - queue_->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) payloadType)); + DEBUG("AudioRtpSession: Setting static payload format"); + queue_.setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) payloadType)); } } +} - if (type_ != Zrtp) - ca_->setRecordingSmplRate(getCodecSampleRate()); +void AudioRtpSession::incrementTimestampForDTMF() +{ + timestamp_ += timestampIncrement_; } void AudioRtpSession::sendDtmfEvent() @@ -131,26 +131,26 @@ void AudioRtpSession::sendDtmfEvent() DEBUG("AudioRtpSession: Send RTP Dtmf (%d)", payload.event); - timestamp_ += (type_ == Zrtp) ? 160 : timestampIncrement_; + incrementTimestampForDTMF(); // discard equivalent size of audio processDataEncode(); // change Payload type for DTMF payload - queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) getDtmfPayloadType(), 8000)); + queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) getDtmfPayloadType(), 8000)); - queue_->setMark(true); - queue_->sendImmediate(timestamp_, (const unsigned char *)(&payload), sizeof(payload)); - queue_->setMark(false); + queue_.setMark(true); + queue_.sendImmediate(timestamp_, (const unsigned char *)(&payload), sizeof(payload)); + queue_.setMark(false); // get back the payload to audio - queue_->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) getCodecPayloadType())); + queue_.setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) getCodecPayloadType())); } void AudioRtpSession::receiveSpeakerData() { - const ost::AppDataUnit* adu = queue_->getData(queue_->getFirstTimestamp()); + const ost::AppDataUnit* adu = queue_.getData(queue_.getFirstTimestamp()); if (!adu) return; @@ -166,23 +166,19 @@ void AudioRtpSession::receiveSpeakerData() } - void AudioRtpSession::sendMicData() { int compSize = processDataEncode(); // if no data return - if (!compSize) + if (compSize == 0) return; // Increment timestamp for outgoing packet timestamp_ += timestampIncrement_; - if (type_ == Zrtp) - queue_->putData(timestamp_, getMicDataEncoded(), compSize); - - // putData put the data on RTP queue, sendImmediate bypass this queue - queue_->sendImmediate(timestamp_, getMicDataEncoded(), compSize); + // putData puts the data on RTP queue, sendImmediate bypass this queue + queue_.sendImmediate(timestamp_, getMicDataEncoded(), compSize); } @@ -190,28 +186,28 @@ void AudioRtpSession::setSessionTimeouts() { DEBUG("AudioRtpSession: Set session scheduling timeout (%d) and expireTimeout (%d)", sfl::schedulingTimeout, sfl::expireTimeout); - queue_->setSchedulingTimeout(sfl::schedulingTimeout); - queue_->setExpireTimeout(sfl::expireTimeout); + queue_.setSchedulingTimeout(sfl::schedulingTimeout); + queue_.setExpireTimeout(sfl::expireTimeout); } void AudioRtpSession::setDestinationIpAddress() { // Store remote ip in case we would need to forget current destination - remote_ip_ = ost::InetHostAddress(ca_->getLocalSDP()->getRemoteIP().c_str()); + remote_ip_ = ost::InetHostAddress(call_.getLocalSDP()->getRemoteIP().c_str()); if (!remote_ip_) { WARN("AudioRtpSession: Target IP address (%s) is not correct!", - ca_->getLocalSDP()->getRemoteIP().data()); + call_.getLocalSDP()->getRemoteIP().data()); return; } // Store remote port in case we would need to forget current destination - remote_port_ = (unsigned short) ca_->getLocalSDP()->getRemoteAudioPort(); + remote_port_ = (unsigned short) call_.getLocalSDP()->getRemoteAudioPort(); DEBUG("AudioRtpSession: New remote address for session: %s:%d", - ca_->getLocalSDP()->getRemoteIP().data(), remote_port_); + call_.getLocalSDP()->getRemoteIP().data(), remote_port_); - if (!queue_->addDestination(remote_ip_, remote_port_)) { + if (!queue_.addDestination(remote_ip_, remote_port_)) { WARN("AudioRtpSession: Can't add new destination to session!"); return; } @@ -224,7 +220,7 @@ void AudioRtpSession::updateDestinationIpAddress() // Destination address are stored in a list in ccrtp // This method remove the current destination entry - if (!queue_->forgetDestination(remote_ip_, remote_port_, remote_port_ + 1)) + if (!queue_.forgetDestination(remote_ip_, remote_port_, remote_port_ + 1)) DEBUG("AudioRtpSession: Did not remove previous destination"); // new destination is stored in call @@ -233,12 +229,12 @@ void AudioRtpSession::updateDestinationIpAddress() } -int AudioRtpSession::startRtpThread(AudioCodec* audiocodec) +int AudioRtpSession::startRtpThread(AudioCodec &audiocodec) { if (isStarted_) return 0; - DEBUG("AudioSymmetricRtpSession: Starting main thread"); + DEBUG("AudioRtpSession: Starting main thread"); isStarted_ = true; setSessionTimeouts(); @@ -246,16 +242,9 @@ int AudioRtpSession::startRtpThread(AudioCodec* audiocodec) initBuffers(); initNoiseSuppress(); - queue_->enableStack(); - thread_->start(); - - int ret = 0; - if (type_ == Zrtp) - return ret; - - AudioSymmetricRtpSession *self = dynamic_cast<AudioSymmetricRtpSession*>(this); - assert(self); - return self->startSymmetricRtpThread(); + queue_.enableStack(); + thread_.start(); + return 0; } diff --git a/daemon/src/audio/audiortp/audio_rtp_session.h b/daemon/src/audio/audiortp/audio_rtp_session.h index 4f8723b234f0897490cadd65faa237518d02bbfc..c6baca3f29fd81b9899922e6b1aef87a767a0478 100644 --- a/daemon/src/audio/audiortp/audio_rtp_session.h +++ b/daemon/src/audio/audiortp/audio_rtp_session.h @@ -31,44 +31,35 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ -#ifndef SFL_AUDIO_RTP_SESSION_H_ -#define SFL_AUDIO_RTP_SESSION_H_ +#ifndef AUDIO_RTP_SESSION_H_ +#define AUDIO_RTP_SESSION_H_ #include "audio_rtp_record_handler.h" -#include <audio/codecs/audiocodec.h> #include <ccrtp/rtp.h> #include <ccrtp/formats.h> #include "noncopyable.h" class SIPCall; +namespace ost { + class Thread; +} namespace sfl { class AudioCodec; -// Possible kind of rtp session -typedef enum RtpMethod { - Symmetric, - Zrtp, - Sdes -} RtpMethod; - - class AudioRtpSession : public AudioRtpRecordHandler { public: /** * Constructor * @param sipcall The pointer on the SIP call */ - AudioRtpSession(SIPCall* sipcall, RtpMethod type, ost::RTPDataQueue *queue, ost::Thread *thread); + AudioRtpSession(SIPCall &sipcall, ost::RTPDataQueue &queue, ost::Thread &thread); virtual ~AudioRtpSession(); - RtpMethod getAudioRtpType() { - return type_; - } - void updateSessionMedia(AudioCodec *audioCodec); + void updateSessionMedia(AudioCodec &audioCodec); - int startRtpThread(AudioCodec*); + virtual int startRtpThread(AudioCodec&); /** * Used mostly when receiving a reinvite @@ -76,6 +67,11 @@ class AudioRtpSession : public AudioRtpRecordHandler { void updateDestinationIpAddress(); protected: + /** + * Set the audio codec for this RTP session + */ + virtual void setSessionMedia(AudioCodec &codec) = 0; + bool onRTPPacketRecv(ost::IncomingRTPPkt&); @@ -90,19 +86,26 @@ class AudioRtpSession : public AudioRtpRecordHandler { /** * Send encoded data to peer */ - void sendMicData(); - - SIPCall *ca_; + virtual void sendMicData(); - RtpMethod type_; + SIPCall &call_; - private: - NON_COPYABLE(AudioRtpSession); + /** + * Timestamp for this session + */ + int timestamp_; /** - * Set the audio codec for this RTP session + * Timestamp incrementation value based on codec period length (framesize) + * except for G722 which require a 8 kHz incrementation. */ - void setSessionMedia(AudioCodec*); + int timestampIncrement_; + + ost::RTPDataQueue &queue_; + + bool isStarted_; + private: + NON_COPYABLE(AudioRtpSession); /** * Set RTP Sockets send/receive timeouts @@ -119,6 +122,11 @@ class AudioRtpSession : public AudioRtpRecordHandler { */ void receiveSpeakerData(); + /** + * Increment timestamp for DTMF event + */ + virtual void incrementTimestampForDTMF(); + // Main destination address for this rtp session. // Stored in case or reINVITE, which may require to forget // this destination and update a new one. @@ -129,27 +137,12 @@ class AudioRtpSession : public AudioRtpRecordHandler { // this destination and update a new one unsigned short remote_port_; - /** - * Timestamp for this session - */ - int timestamp_; - - /** - * Timestamp incrementation value based on codec period length (framesize) - * except for G722 which require a 8 kHz incrementation. - */ - int timestampIncrement_; - /** * Timestamp reset frequency specified in number of packet sent */ short timestampCount_; - bool isStarted_; - - ost::RTPDataQueue *queue_; - - ost::Thread *thread_; + ost::Thread &thread_; }; } diff --git a/daemon/src/audio/audiortp/audio_srtp_session.cpp b/daemon/src/audio/audiortp/audio_srtp_session.cpp index ed8a637fc07953ce9a04e3879bab053b62084f5a..fb14463dbb0983fa9e669a9fb03f4fa2ed6021b8 100644 --- a/daemon/src/audio/audiortp/audio_srtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_srtp_session.cpp @@ -29,8 +29,6 @@ */ #include "audio_srtp_session.h" -#include "sip/sipcall.h" - #include <openssl/sha.h> #include <openssl/hmac.h> #include <openssl/evp.h> @@ -44,10 +42,82 @@ namespace sfl { -AudioSrtpSession::AudioSrtpSession(SIPCall * sipcall) : - AudioSymmetricRtpSession(sipcall), - remoteCryptoCtx_(NULL), - localCryptoCtx_(NULL), +namespace { + std::string + encodeBase64(unsigned char *input, int length) + { + // init decoder + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // init internal buffer + BIO *bmem = BIO_new(BIO_s_mem()); + + // create decoder chain + b64 = BIO_push(b64, bmem); + + BIO_write(b64, input, length); + // BIO_flush (b64); + + // get pointer to data + BUF_MEM *bptr = 0; + BIO_get_mem_ptr(b64, &bptr); + + std::string output(bptr->data, bptr->length); + + BIO_free_all(bmem); + + return output; + } + + std::vector<char> decodeBase64(unsigned char *input, int length) + { + BIO *b64, *bmem; + + // init decoder and read-only BIO buffer + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // init internal buffer + bmem = BIO_new_mem_buf(input, length); + + // create encoder chain + bmem = BIO_push(b64, bmem); + + std::vector<char> buffer(length, 0); + BIO_read(bmem, &(*buffer.begin()), length); + + BIO_free_all(bmem); + + return buffer; + } + + // Fills the array dest with length random bytes + void buffer_fill(unsigned char dest [], size_t length) + { + DEBUG("AudioSrtp: Init local master key"); + + // @TODO key may have different length depending on cipher suite + // Allocate memory for key + std::vector<unsigned char> random_key(length); + + // Generate ryptographically strong pseudo-random bytes + int err; + + if ((err = RAND_bytes(&(*random_key.begin()), length)) != 1) + DEBUG("Error occured while generating cryptographically strong pseudo-random key"); + + assert((sizeof dest / sizeof dest[0]) <= length); + memcpy(dest, &(*random_key.begin()), length); + } +} + + + +AudioSrtpSession::AudioSrtpSession(SIPCall &call) : + AudioSymmetricRtpSession(call), + remoteCryptoCtx_(0), + localCryptoCtx_(0), localCryptoSuite_(0), remoteCryptoSuite_(0), localMasterKey_(), @@ -59,16 +129,10 @@ AudioSrtpSession::AudioSrtpSession(SIPCall * sipcall) : remoteMasterSalt_(), remoteMasterSaltLength_(0), remoteOfferIsSet_(false) -{ - type_ = Sdes; -} +{} -AudioSrtpSession::~AudioSrtpSession() -{ - DEBUG("AudioSrtp: Destroy audio srtp session"); -} -void AudioSrtpSession::initLocalCryptoInfo() +ost::CryptoContext* AudioSrtpSession::initLocalCryptoInfo() { DEBUG("AudioSrtp: Set cryptographic info for this rtp session"); @@ -81,6 +145,7 @@ void AudioSrtpSession::initLocalCryptoInfo() localCryptoCtx_->deriveSrtpKeys(0); setOutQueueCryptoContext(localCryptoCtx_); + return localCryptoCtx_; } std::vector<std::string> AudioSrtpSession::getLocalCryptoInfo() @@ -115,7 +180,8 @@ std::vector<std::string> AudioSrtpSession::getLocalCryptoInfo() return crypto_vector; } -void AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) +ost::CryptoContext* +AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) { if (not remoteOfferIsSet_) { DEBUG("%s", nego.getKeyInfo().c_str()); @@ -134,49 +200,26 @@ void AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) initializeRemoteCryptoContext(); setInQueueCryptoContext(remoteCryptoCtx_); - // initLocalCryptoInfo(); remoteOfferIsSet_ = true; } + return remoteCryptoCtx_; } void AudioSrtpSession::initializeLocalMasterKey() { DEBUG("AudioSrtp: Init local master key"); - // @TODO key may have different length depending on cipher suite localMasterKeyLength_ = sfl::CryptoSuites[localCryptoSuite_].masterKeyLength / 8; - DEBUG("AudioSrtp: Local master key length %d", localMasterKeyLength_); - - // Allocate memory for key - unsigned char *random_key = new unsigned char[localMasterKeyLength_]; - - // Generate ryptographically strong pseudo-random bytes - int err; - - if ((err = RAND_bytes(random_key, localMasterKeyLength_)) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); - - memcpy(localMasterKey_, random_key, localMasterKeyLength_); + buffer_fill(localMasterKey_, localMasterKeyLength_); } void AudioSrtpSession::initializeLocalMasterSalt() { // @TODO key may have different length depending on cipher suite localMasterSaltLength_ = sfl::CryptoSuites[localCryptoSuite_].masterSaltLength / 8; - - // Allocate memory for key - unsigned char *random_key = new unsigned char[localMasterSaltLength_]; - DEBUG("AudioSrtp: Local master salt length %d", localMasterSaltLength_); - - // Generate ryptographically strong pseudo-random bytes - int err; - - if ((err = RAND_bytes(random_key, localMasterSaltLength_)) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); - - memcpy(localMasterSalt_, random_key, localMasterSaltLength_); + buffer_fill(localMasterSalt_, localMasterSaltLength_); } std::string AudioSrtpSession::getBase64ConcatenatedKeys() @@ -207,13 +250,11 @@ void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys) char *dataptr = (char*) base64keys.data(); // decode concatenated binary keys - char *output = decodeBase64((unsigned char*) dataptr, strlen(dataptr)); + std::vector<char> output(decodeBase64((unsigned char*) dataptr, strlen(dataptr))); // copy master and slt respectively - memcpy((void*) remoteMasterKey_, (void*) output, remoteMasterKeyLength_); - memcpy((void*) remoteMasterSalt_, (void*)(output + remoteMasterKeyLength_), remoteMasterSaltLength_); - - delete[] output; + memcpy((void*) remoteMasterKey_, &(*output.begin()), remoteMasterKeyLength_); + memcpy((void*) remoteMasterSalt_, &(*output.begin()) + remoteMasterKeyLength_, remoteMasterSaltLength_); } void AudioSrtpSession::initializeRemoteCryptoContext() @@ -222,24 +263,20 @@ void AudioSrtpSession::initializeRemoteCryptoContext() CryptoSuiteDefinition crypto = sfl::CryptoSuites[remoteCryptoSuite_]; - if (remoteCryptoCtx_) { - delete remoteCryptoCtx_; - remoteCryptoCtx_ = NULL; - } - + delete remoteCryptoCtx_; remoteCryptoCtx_ = new ost::CryptoContext(0x0, - 0, // roc, - 0L, // keydr, - SrtpEncryptionAESCM, // encryption algo - SrtpAuthenticationSha1Hmac, // authtication algo - remoteMasterKey_, - remoteMasterKeyLength_, - remoteMasterSalt_, - remoteMasterSaltLength_, - crypto.encryptionKeyLength / 8, - crypto.srtpAuthKeyLength / 8, - crypto.masterSaltLength / 8, // session salt len - crypto.srtpAuthTagLength / 8); + 0, // roc, + 0L, // keydr, + SrtpEncryptionAESCM, + SrtpAuthenticationSha1Hmac, + remoteMasterKey_, + remoteMasterKeyLength_, + remoteMasterSalt_, + remoteMasterSaltLength_, + crypto.encryptionKeyLength / 8, + crypto.srtpAuthKeyLength / 8, + crypto.masterSaltLength / 8, + crypto.srtpAuthTagLength / 8); } @@ -249,81 +286,31 @@ void AudioSrtpSession::initializeLocalCryptoContext() CryptoSuiteDefinition crypto = sfl::CryptoSuites[localCryptoSuite_]; - if (localCryptoCtx_) { - delete localCryptoCtx_; - localCryptoCtx_ = NULL; - } - + delete localCryptoCtx_; localCryptoCtx_ = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(), - 0, // roc, - 0L, // keydr, - SrtpEncryptionAESCM, // encryption algo - SrtpAuthenticationSha1Hmac, // authtication algo - localMasterKey_, - localMasterKeyLength_, - localMasterSalt_, - localMasterSaltLength_, - crypto.encryptionKeyLength / 8, - crypto.srtpAuthKeyLength / 8, - crypto.masterSaltLength / 8, // session salt len - crypto.srtpAuthTagLength / 8); + 0, // roc, + 0L, // keydr, + SrtpEncryptionAESCM, + SrtpAuthenticationSha1Hmac, + localMasterKey_, + localMasterKeyLength_, + localMasterSalt_, + localMasterSaltLength_, + crypto.encryptionKeyLength / 8, + crypto.srtpAuthKeyLength / 8, + crypto.masterSaltLength / 8, + crypto.srtpAuthTagLength / 8); } -void AudioSrtpSession::restoreCryptoContext(ost::CryptoContext *localContext, ost::CryptoContext *remoteContext) +void AudioSrtpSession::restoreCryptoContext(ost::CryptoContext *localContext, + ost::CryptoContext *remoteContext) { - setInQueueCryptoContext(remoteContext); - setOutQueueCryptoContext(localContext); -} - -std::string AudioSrtpSession::encodeBase64(unsigned char *input, int length) -{ - BIO *b64, *bmem; - BUF_MEM *bptr ; - - // init decoder - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - // init internal buffer - bmem = BIO_new(BIO_s_mem()); - - // create decoder chain - b64 = BIO_push(b64, bmem); - - BIO_write(b64, input, length); - // BIO_flush (b64); - - // get pointer to data - BIO_get_mem_ptr(b64, &bptr); - - std::string output(bptr->data, bptr->length); - - BIO_free_all(bmem); - - return output; + delete remoteCryptoCtx_; + remoteCryptoCtx_ = remoteContext; + delete localCryptoCtx_; + localCryptoCtx_ = localContext; + setInQueueCryptoContext(remoteCryptoCtx_); + setOutQueueCryptoContext(localCryptoCtx_); } -char* AudioSrtpSession::decodeBase64(unsigned char *input, int length) -{ - BIO *b64, *bmem; - - // init decoder and read-only BIO buffer - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - // init internal buffer - bmem = BIO_new_mem_buf(input, length); - - // create encoder chain - bmem = BIO_push(b64, bmem); - - char *buffer = new char[length]; - memset(buffer, 0, length); - - BIO_read(bmem, buffer, length); - - BIO_free_all(bmem); - - return buffer; -} } diff --git a/daemon/src/audio/audiortp/audio_srtp_session.h b/daemon/src/audio/audiortp/audio_srtp_session.h index f641e8eaa55b21065e7efcee35eb87f3543f93eb..97b9b2ce675dbd848ea6c76c235a2f50e2e33dc3 100644 --- a/daemon/src/audio/audiortp/audio_srtp_session.h +++ b/daemon/src/audio/audiortp/audio_srtp_session.h @@ -27,10 +27,9 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ -#ifndef __AUDIO_SRTP_SESSION_H__ -#define __AUDIO_SRTP_SESSION_H__ +#ifndef AUDIO_SRTP_SESSION_H_ +#define AUDIO_SRTP_SESSION_H_ -#include "audio_rtp_session.h" #include "audio_symmetric_rtp_session.h" #include "sip/sdes_negotiator.h" #include "noncopyable.h" @@ -73,9 +72,7 @@ class AudioSrtpSession : public AudioSymmetricRtpSession { /** * Constructor for this rtp session */ - AudioSrtpSession(SIPCall * sipcall); - - ~AudioSrtpSession(); + AudioSrtpSession(SIPCall &call); /** * Used to get sdp crypto header to be included in sdp session. This @@ -86,15 +83,17 @@ class AudioSrtpSession : public AudioSymmetricRtpSession { /** * Set remote crypto header from incoming sdp offer + * @return The new remote crypto context, to be cached by the caller */ - void setRemoteCryptoInfo(sfl::SdesNegotiator& nego); + ost::CryptoContext* setRemoteCryptoInfo(sfl::SdesNegotiator &nego); /** * Init local crypto context for outgoing data - * this method must be called before sending first Invite request - * with SDP offer. - */ - void initLocalCryptoInfo(); + * this method must be called before sending first Invite request + * with SDP offer. + * @return The new local crypto context, to be cached by the caller + */ + ost::CryptoContext* initLocalCryptoInfo(); /** * Restore the cryptographic context. most likely useful to restore @@ -102,6 +101,8 @@ class AudioSrtpSession : public AudioSymmetricRtpSession { */ void restoreCryptoContext(ost::CryptoContext *, ost::CryptoContext *); + private: + NON_COPYABLE(AudioSrtpSession); /** Remote srtp crypto context to be set into incoming data queue. */ ost::CryptoContext* remoteCryptoCtx_; @@ -109,9 +110,6 @@ class AudioSrtpSession : public AudioSymmetricRtpSession { /** Local srtp crypto context to be set into outgoing data queue. */ ost::CryptoContext* localCryptoCtx_; - private: - NON_COPYABLE(AudioSrtpSession); - /** * Init local master key according to current crypto context * as defined in SdesNegotiator.h @@ -146,16 +144,6 @@ class AudioSrtpSession : public AudioSymmetricRtpSession { */ void unBase64ConcatenatedKeys(std::string base64keys); - /** - * Encode input data as base64 - */ - std::string encodeBase64(unsigned char *input, int length); - - /** - * Decode base64 data - */ - char* decodeBase64(unsigned char *input, int length); - /** Default local crypto suite is AES_CM_128_HMAC_SHA1_80*/ int localCryptoSuite_; diff --git a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp index a4499aa0310f8755094db80cff3694a3e70c13a2..3324f22ff4358f7713cf8e024decb2eff9f4abc1 100644 --- a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp @@ -41,24 +41,25 @@ namespace sfl { -AudioSymmetricRtpSession::AudioSymmetricRtpSession(SIPCall * sipcall) : +AudioSymmetricRtpSession::AudioSymmetricRtpSession(SIPCall &call) : ost::TimerPort() - , ost::SymmetricRTPSession(ost::InetHostAddress(sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()) - , AudioRtpSession(sipcall, Symmetric, this, this) - , echoCanceller() - , rtpThread_(new AudioRtpThread(this)) + , ost::SymmetricRTPSession(ost::InetHostAddress(call.getLocalIp().c_str()), call.getLocalAudioPort()) + , AudioRtpSession(call, *this, *this) + , rtpThread_(*this) { - DEBUG("AudioSymmetricRtpSession: Setting new RTP session with destination %s:%d", ca_->getLocalIp().c_str(), ca_->getLocalAudioPort()); - audioRtpRecord_.callId_ = ca_->getCallId(); + DEBUG("AudioSymmetricRtpSession: Setting new RTP session with destination %s:%d", call_.getLocalIp().c_str(), call_.getLocalAudioPort()); + audioRtpRecord_.callId_ = call_.getCallId(); } AudioSymmetricRtpSession::~AudioSymmetricRtpSession() { - rtpThread_->running = false; - delete rtpThread_; + if (rtpThread_.running_) { + rtpThread_.running_ = false; + rtpThread_.join(); + } } -AudioSymmetricRtpSession::AudioRtpThread::AudioRtpThread(AudioSymmetricRtpSession *session) : running(true), rtpSession(session) +AudioSymmetricRtpSession::AudioRtpThread::AudioRtpThread(AudioSymmetricRtpSession &session) : running_(true), rtpSession_(session) {} void AudioSymmetricRtpSession::AudioRtpThread::run() @@ -69,20 +70,35 @@ void AudioSymmetricRtpSession::AudioRtpThread::run() DEBUG("AudioRtpThread: Entering Audio rtp thread main loop"); - while (running) { + while (running_) { // Send session - if (rtpSession->DtmfPending()) - rtpSession->sendDtmfEvent(); + if (rtpSession_.DtmfPending()) + rtpSession_.sendDtmfEvent(); else - rtpSession->sendMicData(); + rtpSession_.sendMicData(); Thread::sleep(TimerPort::getTimer()); TimerPort::incTimer(threadSleep); - DEBUG("Main Loop Running"); } DEBUG("AudioRtpThread: Leaving audio rtp thread loop"); } +void AudioSymmetricRtpSession::setSessionMedia(AudioCodec &audioCodec) +{ + AudioRtpSession::setSessionMedia(audioCodec); + call_.setRecordingSmplRate(getCodecSampleRate()); +} + +int AudioSymmetricRtpSession::startRtpThread(AudioCodec &audiocodec) +{ + DEBUG("AudioSymmetricRtpSession: Starting main thread"); + if (isStarted_) + return 0; + + AudioRtpSession::startRtpThread(audiocodec); + return startSymmetricRtpThread(); +} + } diff --git a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h index 7d9fc21b826ac0852d0aadd0ea383fccdb34ea29..c89d39143b9f0412533b4bc6c2f5b1a81ac5bbb7 100644 --- a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h +++ b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h @@ -56,10 +56,9 @@ class AudioSymmetricRtpSession : public ost::TimerPort, public ost::SymmetricRTP public: /** * Constructor - * @param sipcall The pointer on the SIP call + * @param call The SIP call */ - AudioSymmetricRtpSession(SIPCall* sipcall); - + AudioSymmetricRtpSession(SIPCall &call); ~AudioSymmetricRtpSession(); virtual bool onRTPPacketRecv(ost::IncomingRTPPkt& pkt) { @@ -67,8 +66,7 @@ class AudioSymmetricRtpSession : public ost::TimerPort, public ost::SymmetricRTP } int startSymmetricRtpThread() { - assert(rtpThread_); - rtpThread_->start(); + rtpThread_.start(); return 0; } @@ -77,21 +75,20 @@ class AudioSymmetricRtpSession : public ost::TimerPort, public ost::SymmetricRTP class AudioRtpThread : public ost::Thread, public ost::TimerPort { public: - AudioRtpThread(AudioSymmetricRtpSession *session); - ~AudioRtpThread(){} + AudioRtpThread(AudioSymmetricRtpSession &session); virtual void run(); - bool running; + bool running_; private: NON_COPYABLE(AudioRtpThread); - AudioSymmetricRtpSession *rtpSession; + AudioSymmetricRtpSession &rtpSession_; }; - SpeexEchoCancel echoCanceller; + void setSessionMedia(AudioCodec &codec); + int startRtpThread(AudioCodec &audiocodec); - private: - AudioRtpThread *rtpThread_; + AudioRtpThread rtpThread_; }; } diff --git a/daemon/src/audio/audiortp/audio_zrtp_session.cpp b/daemon/src/audio/audiortp/audio_zrtp_session.cpp index 741fe39367d34b52b9fdfa9a820f7d030be23e55..d03767ead8c84cd0abfd9a1c6b58b36bd9f30e18 100644 --- a/daemon/src/audio/audiortp/audio_zrtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_zrtp_session.cpp @@ -49,26 +49,27 @@ namespace sfl { -AudioZrtpSession::AudioZrtpSession(SIPCall * sipcall, const std::string& zidFilename) : - AudioRtpSession(sipcall, Zrtp, this, this), - ost::TRTPSessionBase<ost::SymmetricRTPChannel, ost::SymmetricRTPChannel, ost::ZrtpQueue>(ost::InetHostAddress(sipcall->getLocalIp().c_str()), - sipcall->getLocalAudioPort(), - 0, - ost::MembershipBookkeeping::defaultMembersHashSize, - ost::defaultApplication()), +AudioZrtpSession::AudioZrtpSession(SIPCall &call, const std::string& zidFilename) : + AudioRtpSession(call, *this, *this), + ost::TRTPSessionBase<ost::SymmetricRTPChannel, ost::SymmetricRTPChannel, ost::ZrtpQueue>(ost::InetHostAddress(call_.getLocalIp().c_str()), + call_.getLocalAudioPort(), + 0, + ost::MembershipBookkeeping::defaultMembersHashSize, + ost::defaultApplication()), zidFilename_(zidFilename) { DEBUG("AudioZrtpSession initialized"); initializeZid(); - DEBUG("AudioZrtpSession: Setting new RTP session with destination %s:%d", ca_->getLocalIp().c_str(), ca_->getLocalAudioPort()); + DEBUG("AudioZrtpSession: Setting new RTP session with destination %s:%d", + call_.getLocalIp().c_str(), call_.getLocalAudioPort()); } AudioZrtpSession::~AudioZrtpSession() { ost::Thread::terminate(); - Manager::instance().getMainBuffer()->unBindAll(ca_->getCallId()); + Manager::instance().getMainBuffer()->unBindAll(call_.getCallId()); } void AudioZrtpSession::final() @@ -101,7 +102,7 @@ void AudioZrtpSession::initializeZid() if (initialize(zidCompleteFilename.c_str()) >= 0) { DEBUG("Register callbacks"); setEnableZrtp(true); - setUserCallback(new ZrtpSessionCallback(ca_)); + setUserCallback(new ZrtpSessionCallback(call_)); return; } @@ -116,11 +117,29 @@ void AudioZrtpSession::initializeZid() return; } +void AudioZrtpSession::sendMicData() +{ + int compSize = processDataEncode(); + + // if no data return + if (compSize == 0) + return; + + // Increment timestamp for outgoing packet + timestamp_ += timestampIncrement_; + + // this step is only needed for ZRTP + queue_.putData(timestamp_, getMicDataEncoded(), compSize); + + // putData puts the data on RTP queue, sendImmediate bypasses this queue + queue_.sendImmediate(timestamp_, getMicDataEncoded(), compSize); +} + void AudioZrtpSession::run() { // Set recording sampling rate - ca_->setRecordingSmplRate(getCodecSampleRate()); - DEBUG("AudioZrtpSession: Entering mainloop for call %s", ca_->getCallId().c_str()); + call_.setRecordingSmplRate(getCodecSampleRate()); + DEBUG("AudioZrtpSession: Entering mainloop for call %s", call_.getCallId().c_str()); uint32 timeout = 0; @@ -146,7 +165,8 @@ void AudioZrtpSession::run() // dispatchDataPacket(); timerTick(); } else { - if (isPendingData(timeout/1000)) { + if (isPendingData(timeout / 1000)) { + if (isActive()) takeInDataPacket(); } @@ -154,6 +174,17 @@ void AudioZrtpSession::run() } } - DEBUG("AudioZrtpSession: Left main loop for call %s", ca_->getCallId().c_str()); + DEBUG("AudioZrtpSession: Left main loop for call %s", call_.getCallId().c_str()); +} + +void AudioZrtpSession::incrementTimestampForDTMF() +{ + timestamp_ += 160; +} + +void AudioZrtpSession::setSessionMedia(AudioCodec &audioCodec) +{ + AudioRtpSession::setSessionMedia(audioCodec); } + } diff --git a/daemon/src/audio/audiortp/audio_zrtp_session.h b/daemon/src/audio/audiortp/audio_zrtp_session.h index aed4aa79fc4e805cd336bc933a15c280391a6d96..c635349efe74dd3bf11e8100eea34eabd2afa367 100644 --- a/daemon/src/audio/audiortp/audio_zrtp_session.h +++ b/daemon/src/audio/audiortp/audio_zrtp_session.h @@ -43,19 +43,21 @@ using std::ptrdiff_t; // #include <commoncpp/numbers.h> // OST::Time class SIPCall; +class AudioCodec; namespace sfl { -class ZrtpZidException: public std::runtime_error { +class ZrtpZidException : public std::runtime_error { public: ZrtpZidException(const std::string& str = "") : std::runtime_error("ZRTP ZID initialization failed." + str) {} }; -// class AudioZrtpSession : public ost::TimerPort, public ost::SymmetricZRTPSession, public AudioRtpRecordHandler -class AudioZrtpSession : public AudioRtpSession, protected ost::Thread, public ost::TRTPSessionBase<ost::SymmetricRTPChannel, ost::SymmetricRTPChannel, ost::ZrtpQueue> { +class AudioZrtpSession : + public AudioRtpSession, protected ost::Thread, + public ost::TRTPSessionBase<ost::SymmetricRTPChannel, ost::SymmetricRTPChannel, ost::ZrtpQueue> { public: - AudioZrtpSession(SIPCall * sipcall, const std::string& zidFilename); + AudioZrtpSession(SIPCall &call, const std::string& zidFilename); ~AudioZrtpSession(); virtual void final(); @@ -63,13 +65,16 @@ class AudioZrtpSession : public AudioRtpSession, protected ost::Thread, public o // Thread associated method virtual void run(); - virtual bool onRTPPacketRecv(ost::IncomingRTPPkt& pkt) { + virtual bool onRTPPacketRecv(ost::IncomingRTPPkt &pkt) { return AudioRtpSession::onRTPPacketRecv(pkt); } private: + void sendMicData(); void initializeZid(); std::string zidFilename_; + void incrementTimestampForDTMF(); + void setSessionMedia(AudioCodec &codec); }; } diff --git a/daemon/src/audio/audiortp/zrtp_session_callback.cpp b/daemon/src/audio/audiortp/zrtp_session_callback.cpp index 270468a80ea2a8fc8e683d515610d31dce7d0a17..061cf1c64c22b66f270e80302085e149d5328de8 100644 --- a/daemon/src/audio/audiortp/zrtp_session_callback.cpp +++ b/daemon/src/audio/audiortp/zrtp_session_callback.cpp @@ -45,8 +45,8 @@ using namespace ost; namespace sfl { -ZrtpSessionCallback::ZrtpSessionCallback(SIPCall *sipcall) : - sipcall_(sipcall) +ZrtpSessionCallback::ZrtpSessionCallback(SIPCall &call) : + call_(call) { using std::pair; using std::string; @@ -112,21 +112,21 @@ void ZrtpSessionCallback::secureOn(std::string cipher) { DEBUG("Zrtp: Secure mode is on with cipher %s", cipher.c_str()); - Manager::instance().getDbusManager()->getCallManager()->secureZrtpOn(sipcall_->getCallId(), cipher); + Manager::instance().getDbusManager()->getCallManager()->secureZrtpOn(call_.getCallId(), cipher); } void ZrtpSessionCallback::secureOff() { DEBUG("Zrtp: Secure mode is off"); - Manager::instance().getDbusManager()->getCallManager()->secureZrtpOff(sipcall_->getCallId()); + Manager::instance().getDbusManager()->getCallManager()->secureZrtpOff(call_.getCallId()); } void ZrtpSessionCallback::showSAS(std::string sas, bool verified) { DEBUG("Zrtp: SAS is: %s", sas.c_str()); - Manager::instance().getDbusManager()->getCallManager()->showSAS(sipcall_->getCallId(), sas, verified); + Manager::instance().getDbusManager()->getCallManager()->showSAS(call_.getCallId(), sas, verified); } @@ -134,7 +134,7 @@ void ZrtpSessionCallback::zrtpNotSuppOther() { DEBUG("Zrtp: Callee does not support ZRTP"); - Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(sipcall_->getCallId()); + Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); } @@ -163,13 +163,13 @@ ZrtpSessionCallback::zrtpNegotiationFailed(MessageSeverity severity, int subCode std::map<int32, std::string>::const_iterator iter = zrtpMap_.find(subCode); if (iter != zrtpMap_.end()) { DEBUG("%s", iter->second.c_str()); - Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(sipcall_->getCallId(), iter->second, "ZRTP"); + Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "ZRTP"); } } else { std::map<int32, std::string>::const_iterator iter = severeMap_.find(subCode); if (iter != severeMap_.end()) { DEBUG("%s", iter->second.c_str()); - Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(sipcall_->getCallId(), iter->second, "severe"); + Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "severe"); } } } @@ -178,7 +178,7 @@ void ZrtpSessionCallback::confirmGoClear() { DEBUG("Zrtp: Received go clear message. Until confirmation, ZRTP won't send any data"); - Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(sipcall_->getCallId()); + Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); } std::map<int32, std::string> ZrtpSessionCallback::infoMap_; diff --git a/daemon/src/audio/audiortp/zrtp_session_callback.h b/daemon/src/audio/audiortp/zrtp_session_callback.h index 08bb9cf4fb4c9bffd2f9fbc49d50520dda88a6c3..e9e92a9c2cda8c02dec10a562bb9831dd410cef4 100644 --- a/daemon/src/audio/audiortp/zrtp_session_callback.h +++ b/daemon/src/audio/audiortp/zrtp_session_callback.h @@ -28,8 +28,8 @@ * as that of the covered work. */ -#ifndef __ZRTP_SESSION_CALLBACK_H__ -#define __ZRTP_SESSION_CALLBACK_H__ +#ifndef ZRTP_SESSION_CALLBACK_H_ +#define ZRTP_SESSION_CALLBACK_H_ #include <cstddef> using std::ptrdiff_t; @@ -39,7 +39,6 @@ using std::ptrdiff_t; #include <libzrtpcpp/ZrtpUserCallback.h> #include <exception> #include <map> -#include "noncopyable.h" class SIPCall; @@ -47,7 +46,7 @@ namespace sfl { class ZrtpSessionCallback: public ZrtpUserCallback { public: - ZrtpSessionCallback(SIPCall *sipcall); + ZrtpSessionCallback(SIPCall &call); void secureOn(std::string cipher); void secureOff(); @@ -58,12 +57,11 @@ class ZrtpSessionCallback: public ZrtpUserCallback { void confirmGoClear(); private: - NON_COPYABLE(ZrtpSessionCallback); - SIPCall* sipcall_; + SIPCall &call_; static std::map<int32, std::string> infoMap_; static std::map<int32, std::string> warningMap_; static std::map<int32, std::string> severeMap_; static std::map<int32, std::string> zrtpMap_; }; } -#endif // __ZRTP_SESSION_CALLBACK_H__ +#endif // ZRTP_SESSION_CALLBACK_H_ diff --git a/daemon/src/dbus/configurationmanager-introspec.xml b/daemon/src/dbus/configurationmanager-introspec.xml index 6c8f27da36474bb1c61bd1e1c9fadf826e7131b7..a990a0be463994ea5c61a68778e615f23be1c61c 100644 --- a/daemon/src/dbus/configurationmanager-introspec.xml +++ b/daemon/src/dbus/configurationmanager-introspec.xml @@ -447,6 +447,11 @@ <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> </signal> + <signal name="registrationStateChanged" tp:name-for-bindings="registrationStateChanged"> + <arg type="s" name="accountID"/> + <arg type="i" name="registration_state"/> + </signal> + <signal name="stunStatusFailure" tp:name-for_bindings="stunStatusFailure"> <arg type="s" name="reason"> </arg> diff --git a/daemon/src/eventthread.cpp b/daemon/src/eventthread.cpp index c0865a94fb0270a24ee0d6e02736419238316d1f..b712837fc84aeb7719f78f361165e428a4048cd9 100644 --- a/daemon/src/eventthread.cpp +++ b/daemon/src/eventthread.cpp @@ -32,16 +32,11 @@ #include "voiplink.h" EventThread::EventThread(VoIPLink *link) : Thread(), link_(link) -{ -} - -EventThread::~EventThread() { - ost::Thread::terminate(); -} +{} void EventThread::run() { - while (1) + while (isRunning()) link_->getEvent(); } diff --git a/daemon/src/eventthread.h b/daemon/src/eventthread.h index f3c04963e7f7994e9718ce844aca9f9116eea151..58676b9f5350c73ab6a12b06ca9471e56d083abf 100644 --- a/daemon/src/eventthread.h +++ b/daemon/src/eventthread.h @@ -44,7 +44,6 @@ class VoIPLink; class EventThread : public ost::Thread { public: EventThread(VoIPLink* link); - ~EventThread(); virtual void run(); private: diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index a22b5c698923376a7a8c2a7cad2a3641a8e25b2d..04428236e551c2c7741daee7509bd4fd264b5533 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -1628,11 +1628,6 @@ void ManagerImpl::startVoiceMessageNotification(const std::string& accountId, dbus_.getCallManager()->voiceMailNotify(accountId, nb_msg); } -void ManagerImpl::connectionStatusNotification() -{ - dbus_.getConfigurationManager()->accountsChanged(); -} - /** * Multi Thread */ diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index c26160d306e9b244e3aaa58e533af43ffd6127d6..2fd9665b92353b8e52916757113beafc14ba9935 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -399,11 +399,6 @@ class ManagerImpl { */ void startVoiceMessageNotification(const std::string& accountId, int nb_msg); - /** - * Notify the client through DBus that registration state has been updated - */ - void connectionStatusNotification(); - /** * ConfigurationManager - Send registration request * @param accountId The account to register/unregister diff --git a/daemon/src/sip/sdes_negotiator.h b/daemon/src/sip/sdes_negotiator.h index 7fb4213555d670af6bd32f68073584107a886c09..416f940b011eecd97d00e196a44e07cb146e688f 100644 --- a/daemon/src/sip/sdes_negotiator.h +++ b/daemon/src/sip/sdes_negotiator.h @@ -80,7 +80,7 @@ struct CryptoSuiteDefinition { * List of accepted Crypto-Suites * as defined in RFC4568 (6.2) */ -const CryptoSuiteDefinition CryptoSuites[3] = { +static const CryptoSuiteDefinition CryptoSuites[] = { { (char*) "AES_CM_128_HMAC_SHA1_80", 128, 112, 48, 31, AESCounterMode, 128, HMACSHA1, 80, 80, 160, 160 }, { (char*) "AES_CM_128_HMAC_SHA1_32", 128, 112, 48, 31, AESCounterMode, 128, HMACSHA1, 32, 80, 160, 160 }, { (char*) "F8_128_HMAC_SHA1_80", 128, 112, 48, 31, AESF8Mode, 128, HMACSHA1, 80, 80, 160, 160 } diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index a59aaf39e0f02489bc39a45cfc3d05b0ee4567a1..404622ae49d565599f55295db136988f017bf986 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -607,7 +607,7 @@ void SIPAccount::startKeepAliveTimer() { keepAliveDelay_.sec = 60; } else { - DEBUG("Regsitration Expire == %d", registrationExpire_); + DEBUG("Registration Expire == %d", registrationExpire_); keepAliveDelay_.sec = registrationExpire_; } diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp index 6ce022bc8e293488a0605246654520c0a8f8d09c..b08f7c3017194152235fe28b765eb147d38e504a 100644 --- a/daemon/src/sip/siptransport.cpp +++ b/daemon/src/sip/siptransport.cpp @@ -43,7 +43,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> -// #include <linux/if.h> +#include <unistd.h> #include <arpa/inet.h> #include "siptransport.h" @@ -373,28 +373,21 @@ void SipTransport::createDefaultSipUdpTransport() localUDPTransport_ = account->transport_; } - -pjsip_transport *SipTransport::createUdpTransport(std::string interface, unsigned int port) +pjsip_transport * +SipTransport::createUdpTransport(const std::string &interface, unsigned int port) { // init socket to bind this transport to - pj_sockaddr_in bound_addr; - pj_bzero(&bound_addr, sizeof(bound_addr)); pj_uint16_t listeningPort = (pj_uint16_t) port; - bound_addr.sin_port = pj_htons(listeningPort); - bound_addr.sin_family = PJ_AF_INET; DEBUG("SipTransport: Create UDP transport on %s:%d", interface.c_str(), port); // determine the ip address for this transport static const char * const DEFAULT_INTERFACE = "default"; std::string listeningAddress; - if (interface == DEFAULT_INTERFACE) { + if (interface == DEFAULT_INTERFACE) listeningAddress = getSIPLocalIP(); - bound_addr.sin_addr.s_addr = pj_htonl(PJ_INADDR_ANY); - } else { + else listeningAddress = getInterfaceAddrFromName(interface); - bound_addr.sin_addr = pj_inet_addr2(listeningAddress.c_str()); - } if (listeningAddress.empty()) { ERROR("SipTransport: Could not determine ip address for this transport"); @@ -406,20 +399,27 @@ pjsip_transport *SipTransport::createUdpTransport(std::string interface, unsigne return NULL; } - DEBUG("SipTransport: Listening address %s, listening port %d", listeningAddress.c_str(), listeningPort); - // The published address for this transport - const pjsip_host_port a_name = { - pj_str((char*) listeningAddress.c_str()), - listeningPort - }; - + pj_sockaddr boundAddr; + pj_str_t udpString; + pj_cstr(&udpString, listeningAddress.c_str()); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr); + pj_status_t status; pjsip_transport *transport = NULL; - pj_status_t status = pjsip_udp_transport_start(endpt_, &bound_addr, &a_name, 1, &transport); - if (status != PJ_SUCCESS) { - ERROR("SipTransport: Could not create UDP transport for port %u", port); - return NULL; + if (boundAddr.addr.sa_family == pj_AF_INET()) { + status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, NULL, 1, &transport); + if (status != PJ_SUCCESS) { + ERROR("Failed to create IPv4 UDP transport"); + return NULL; + } + } else if (boundAddr.addr.sa_family == pj_AF_INET6()) { + status = pjsip_udp_transport_start6(endpt_, &boundAddr.ipv6, NULL, 1, &transport); + if (status != PJ_SUCCESS) { + ERROR("Failed to create IPv6 UDP transport"); + return NULL; + } } + DEBUG("SipTransport: Listening address %s, listening port %d", listeningAddress.c_str(), listeningPort); // dump debug information to stdout pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_)); transportMap_[listeningPort] = transport; diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h index 5928a2200f74c84f979a3bae15f6ba26a05878d2..21e2c8780157f153f81f01f5357afca75a97a0fd 100644 --- a/daemon/src/sip/siptransport.h +++ b/daemon/src/sip/siptransport.h @@ -117,7 +117,8 @@ class SipTransport { * Create SIP UDP transport from account's setting * @param account The account for which a transport must be created. */ - pjsip_transport *createUdpTransport(std::string interface, unsigned int port); + pjsip_transport *createUdpTransport(const std::string &interface, + unsigned int port); /** * Initialize the transport selector diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index af567807b57bc5bd76ca85bd38c741acc3a2e493..34003068e50a1da008f3e724953c5b54870b28c8 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -318,8 +318,8 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) call->getLocalSDP()->setLocalIP(addrSdp); - call->getAudioRtp().initAudioRtpConfig(); - call->getAudioRtp().initAudioSymmetricRtpSession(); + call->getAudioRtp().initConfig(); + call->getAudioRtp().initSession(); if (rdata->msg_info.msg->body) { char sdpbuffer[1000]; @@ -336,7 +336,7 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) CryptoOffer crypto_offer; crypto_offer.push_back(std::string(sdpoffer.substr(start, (sdpoffer.size() - start) - 1))); - std::vector<sfl::CryptoSuiteDefinition>localCapabilities; + std::vector<sfl::CryptoSuiteDefinition> localCapabilities; for (int i = 0; i < 3; i++) localCapabilities.push_back(sfl::CryptoSuites[i]); @@ -409,7 +409,7 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) /*************************************************************************************************/ -SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), evThread_(new EventThread(this)) +SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), evThread_(this) { #define TRY(ret) do { \ if (ret != PJ_SUCCESS) \ @@ -481,12 +481,13 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), evThread_(new Eve TRY(pjsip_replaces_init_module(endpt_)); #undef TRY - evThread_->start(); + evThread_.detach(); } SIPVoIPLink::~SIPVoIPLink() { - delete evThread_; + if (evThread_.isRunning()) + evThread_.join(); pj_thread_join(thread); pj_thread_destroy(thread); @@ -695,8 +696,8 @@ Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toU } try { - call->getAudioRtp().initAudioRtpConfig(); - call->getAudioRtp().initAudioSymmetricRtpSession(); + call->getAudioRtp().initConfig(); + call->getAudioRtp().initSession(); call->getAudioRtp().initLocalCryptoInfo(); call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec)); } catch (...) { @@ -830,8 +831,8 @@ SIPVoIPLink::offhold(const std::string& id) if (audiocodec == NULL) throw VoipLinkException("Could not instantiate codec"); - call->getAudioRtp().initAudioRtpConfig(); - call->getAudioRtp().initAudioSymmetricRtpSession(); + call->getAudioRtp().initConfig(); + call->getAudioRtp().initSession(); call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec)); } catch (const SdpException &e) { ERROR("UserAgent: Exception: %s", e.what()); @@ -1164,8 +1165,8 @@ bool SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to) // Audio Rtp Session must be initialized before creating initial offer in SDP session // since SDES require crypto attribute. - call->getAudioRtp().initAudioRtpConfig(); - call->getAudioRtp().initAudioSymmetricRtpSession(); + call->getAudioRtp().initConfig(); + call->getAudioRtp().initSession(); call->getAudioRtp().initLocalCryptoInfo(); call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec)); @@ -1412,7 +1413,7 @@ void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status) std::string accountID = Manager::instance().getAccountFromCall(call->getCallId()); if (dynamic_cast<SIPAccount*>(Manager::instance().getAccount(accountID))->getSrtpFallback()) - call->getAudioRtp().initAudioSymmetricRtpSession(); + call->getAudioRtp().initSession(); } if (!sdpSession) diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h index c7f65aa731a21aa24c249ee1c0d7e7b4fe817e58..dd2701075c70cd2c7a2efa4cc42da905e62e88ec 100644 --- a/daemon/src/sip/sipvoiplink.h +++ b/daemon/src/sip/sipvoiplink.h @@ -46,7 +46,7 @@ #include <pjnath.h> #include <pjnath/stun_config.h> /////////////////////////////// - +#include "eventthread.h" #include "sipaccount.h" #include "voiplink.h" #include "siptransport.h" @@ -246,7 +246,7 @@ class SIPVoIPLink : public VoIPLink { /** * Threading object */ - EventThread *evThread_; + EventThread evThread_; friend class SIPTest; }; diff --git a/daemon/test/sflphoned-sample.yml b/daemon/test/sflphoned-sample.yml index 942b1541229737aa284302e7a7c0239b30c02b2f..3bac267c832a84b794e539dc90e7fa26c9550b35 100644 --- a/daemon/test/sflphoned-sample.yml +++ b/daemon/test/sflphoned-sample.yml @@ -1,5 +1,54 @@ --- accounts: +- alias: SFL test + codecs: 0/3/8/9/110/111/112/ + credential: + - Account.password: 1234 + Account.realm: + Account.username: sfltest + displayName: + dtmfType: overrtp + enable: false + hostname: localhost + id: Account:1334389473 + interface: default + mailbox: + port: 5060 + publishAddr: 0.0.0.0 + publishPort: 5060 + registrationexpire: 600 + ringtoneEnabled: true + ringtonePath: /usr/share/sflphone/ringtones/konga.ul + sameasLocal: true + serviceRoute: + srtp: + enable: false + keyExchange: + rtpFallback: false + stunEnabled: false + stunServer: stun.sflphone.org + tls: + calist: + certificate: + ciphers: + enable: false + method: TLSv1 + password: + privateKey: + requireCertif: true + server: + timeout: 2 + tlsPort: 5061 + verifyClient: true + verifyServer: true + type: SIP + updateContact: false + username: sfltest + zrtp: + displaySas: true + displaySasOnce: false + helloHashEnabled: true + notSuppWarning: true - alias: codecs: 0/ credential: diff --git a/gnome/src/accountlist.c b/gnome/src/accountlist.c index 44c79b011b3ea89f57d8a02f8c87c193c9500de5..91b649826b84b6265244fc50a6763472fbb780c7 100644 --- a/gnome/src/accountlist.c +++ b/gnome/src/accountlist.c @@ -33,6 +33,7 @@ #include "str_utils.h" #include "dbus.h" #include "accountlist.h" +#include "logger.h" #include "actions.h" #include "unused.h" @@ -75,6 +76,7 @@ static gint get_state_struct(gconstpointer a, gconstpointer b) void account_list_init() { + account_list_free(); accountQueue = g_queue_new(); } @@ -98,6 +100,7 @@ account_list_get_by_state(account_state_t state) account_t * account_list_get_by_id(const gchar * const accountID) { + g_assert(accountID); GList * c = g_queue_find_custom(accountQueue, accountID, is_accountID_struct); if (c) @@ -125,9 +128,7 @@ account_list_get_current() // if we are here, it means that we have at least one registered account in the list // So we get the first one - account_t *current = account_list_get_by_state(ACCOUNT_STATE_REGISTERED); - - return current; + return account_list_get_by_state(ACCOUNT_STATE_REGISTERED); } void account_list_set_current(account_t *current) @@ -146,45 +147,30 @@ void account_list_set_current(account_t *current) const gchar * account_state_name(account_state_t s) { - gchar * state; - switch (s) { case ACCOUNT_STATE_REGISTERED: - state = _("Registered"); - break; + return _("Registered"); case ACCOUNT_STATE_UNREGISTERED: - state = _("Not Registered"); - break; + return _("Not Registered"); case ACCOUNT_STATE_TRYING: - state = _("Trying..."); - break; + return _("Trying..."); case ACCOUNT_STATE_ERROR: - state = _("Error"); - break; + return _("Error"); case ACCOUNT_STATE_ERROR_AUTH: - state = _("Authentication Failed"); - break; + return _("Authentication Failed"); case ACCOUNT_STATE_ERROR_NETWORK: - state = _("Network unreachable"); - break; + return _("Network unreachable"); case ACCOUNT_STATE_ERROR_HOST: - state = _("Host unreachable"); - break; + return _("Host unreachable"); case ACCOUNT_STATE_ERROR_CONF_STUN: - state = _("Stun configuration error"); - break; + return _("Stun configuration error"); case ACCOUNT_STATE_ERROR_EXIST_STUN: - state = _("Stun server invalid"); - break; - case IP2IP_PROFILE_STATUS: - state = _("Ready"); - break; + return _("Stun server invalid"); + case ACCOUNT_STATE_IP2IP_READY: + return _("Ready"); default: - state = _("Invalid"); - break; + return _("Invalid"); } - - return state; } void account_list_free_elm(gpointer elm, gpointer data UNUSED) @@ -197,8 +183,11 @@ void account_list_free_elm(gpointer elm, gpointer data UNUSED) void account_list_free() { - g_queue_foreach(accountQueue, account_list_free_elm, NULL); - g_queue_free(accountQueue); + if (accountQueue) { + g_queue_foreach(accountQueue, account_list_free_elm, NULL); + g_queue_free(accountQueue); + accountQueue = NULL; + } } void @@ -225,7 +214,7 @@ account_list_get_registered_accounts(void) guint res = 0; for (guint i = 0; i < account_list_get_size(); i++) - if (account_list_get_nth(i) -> state == (ACCOUNT_STATE_REGISTERED)) + if (account_list_get_nth(i)->state == (ACCOUNT_STATE_REGISTERED)) res++; return res; @@ -241,6 +230,20 @@ const gchar* account_list_get_current_id(void) return NULL; } +void account_list_remove(const gchar *accountID) +{ + account_t *target = account_list_get_by_id(accountID); + if (target) { +#if GLIB_CHECK_VERSION(2, 30, 0) + if (!g_queue_remove(accountQueue, target)) + ERROR("Could not remove account with ID %s", accountID); +#else + g_queue_remove(accountQueue, target); +#endif + } + +} + gchar * account_list_get_ordered_list(void) { gchar *order = strdup(""); @@ -298,7 +301,7 @@ gboolean current_account_has_new_message(void) gboolean account_is_IP2IP(const account_t *account) { g_assert(account); - return g_strcmp0(account->accountID, IP2IP_PROFILE); + return g_strcmp0(account->accountID, IP2IP_PROFILE) == 0; } static gboolean is_type(const account_t *account, const gchar *type) @@ -320,10 +323,20 @@ gboolean account_is_IAX(const account_t *account) account_t *create_default_account() { account_t *account = g_new0(account_t, 1); - account->properties = dbus_get_account_details(NULL); - account->accountID = g_strdup("new"); //FIXME : replace with NULL for new accounts - account->credential_information = NULL; + account->accountID = g_strdup("new"); // FIXME: maybe replace with NULL? + account->properties = dbus_get_account_details(""); + sflphone_fill_codec_list_per_account(account); + initialize_credential_information(account); + return account; +} + +account_t *create_account_with_ID(const gchar *ID) +{ + account_t *account = g_new0(account_t, 1); + account->accountID = g_strdup(ID); + account->properties = dbus_get_account_details(ID); sflphone_fill_codec_list_per_account(account); + initialize_credential_information(account); return account; } @@ -341,16 +354,18 @@ void initialize_credential_information(account_t *account) void account_replace(account_t *account, const gchar *key, const gchar *value) { + g_assert(account && account->properties); g_hash_table_replace(account->properties, g_strdup(key), g_strdup(value)); } void account_insert(account_t *account, const gchar *key, const gchar *value) { + g_assert(account && account->properties); g_hash_table_insert(account->properties, g_strdup(key), g_strdup(value)); } gpointer account_lookup(const account_t *account, gconstpointer key) { - g_assert(account->properties); + g_assert(account && account->properties); return g_hash_table_lookup(account->properties, key); } diff --git a/gnome/src/accountlist.h b/gnome/src/accountlist.h index 8665e570b1ddfab4519de8157fc01cb33897c897..08d8ef917701b2b57c462358724a6a8363ab5491 100644 --- a/gnome/src/accountlist.h +++ b/gnome/src/accountlist.h @@ -29,8 +29,8 @@ * as that of the covered work. */ -#ifndef __ACCOUNTLIST_H__ -#define __ACCOUNTLIST_H__ +#ifndef ACCOUNTLIST_H__ +#define ACCOUNTLIST_H__ #include <gtk/gtk.h> /** @file accountlist.h @@ -41,14 +41,12 @@ * This enum have all the states an account can take. */ typedef enum { - /** Invalid state */ - ACCOUNT_STATE_INVALID = 0, - /** The account is registered */ - ACCOUNT_STATE_REGISTERED, /** The account is not registered */ ACCOUNT_STATE_UNREGISTERED, /** The account is trying to register */ ACCOUNT_STATE_TRYING, + /** The account is registered */ + ACCOUNT_STATE_REGISTERED, /** Error state. The account is not registered */ ACCOUNT_STATE_ERROR, /** An authentification error occured. Wrong password or wrong username. The account is not registered */ @@ -57,12 +55,14 @@ typedef enum { ACCOUNT_STATE_ERROR_NETWORK, /** Host is unreachable. The account is not registered */ ACCOUNT_STATE_ERROR_HOST, - /** Stun server configuration error. The account is not registered */ - ACCOUNT_STATE_ERROR_CONF_STUN, /** Stun server is not existing. The account is not registered */ ACCOUNT_STATE_ERROR_EXIST_STUN, - /** IP profile status **/ - IP2IP_PROFILE_STATUS + /** Stun server configuration error. The account is not registered */ + ACCOUNT_STATE_ERROR_CONF_STUN, + /** IP2IP Account is always ready */ + ACCOUNT_STATE_IP2IP_READY, + /** Invalid state */ + ACCOUNT_STATE_INVALID } account_state_t; /** @struct account_t @@ -188,11 +188,13 @@ gboolean account_is_SIP(const account_t *account); gboolean account_is_IAX(const account_t *account); account_t *create_default_account(); +account_t *create_account_with_ID(const gchar *ID); void initialize_credential_information(account_t *account); void account_replace(account_t *account, const gchar *key, const gchar *value); void account_insert(account_t *account, const gchar *key, const gchar *value); gpointer account_lookup(const account_t *account, gconstpointer key); +void account_list_remove(const gchar *accountID); #endif diff --git a/gnome/src/actions.c b/gnome/src/actions.c index fb385e924b89e61acb7a0173e98d0ff23fda31ad..d74a3987709ab3454eba7e42acdbe1798c7ae472 100644 --- a/gnome/src/actions.c +++ b/gnome/src/actions.c @@ -78,7 +78,8 @@ sflphone_notify_voice_mail(const gchar* accountID , guint count) DEBUG("sflphone_notify_voice_mail begin"); - if (g_ascii_strcasecmp(id, current_id) != 0 || account_list_get_size() == 0) + if (g_ascii_strcasecmp(id, current_id) != 0 || + account_list_get_size() == 0) return; // Set the number of voice messages for the current account @@ -121,18 +122,17 @@ static gboolean is_direct_call(callable_obj_t * c) void status_bar_display_account() { - gchar* msg; - statusbar_pop_message(__MSG_ACCOUNT_DEFAULT); account_t *acc = account_list_get_current(); status_tray_icon_online(acc != NULL); + gchar* msg; if (acc) { msg = g_markup_printf_escaped("%s %s (%s)" , _("Using account"), - (gchar*) g_hash_table_lookup(acc->properties, ACCOUNT_ALIAS), - (gchar*) g_hash_table_lookup(acc->properties, ACCOUNT_TYPE)); + (gchar*) account_lookup(acc, ACCOUNT_ALIAS), + (gchar*) account_lookup(acc, ACCOUNT_TYPE)); } else { msg = g_markup_printf_escaped(_("No registered accounts")); } @@ -202,85 +202,56 @@ sflphone_hung_up(callable_obj_t * c) statusbar_update_clock(""); } -/** Internal to actions: Fill account list */ void sflphone_fill_account_list(void) { - int count = current_account_get_message_number(); - - account_list_free(); account_list_init(); - gchar **array = dbus_account_list(); - if (array) { - for (gchar **accountID = array; accountID && *accountID; accountID++) { - account_t * a = g_new0(account_t, 1); - a->accountID = g_strdup(*accountID); - a->credential_information = NULL; - account_list_add(a); - } - - g_strfreev(array); - } - - for (unsigned i = 0; i < account_list_get_size(); i++) { - account_t * a = account_list_get_nth(i); - - if (a == NULL) { - ERROR("SFLphone: Error: Could not find account %d in list", i); + for (gchar **accountID = array; accountID && *accountID; ++accountID) { + account_t *acc = create_account_with_ID(*accountID); + if (acc->properties == NULL) { + ERROR("SFLphone: Error: Could not fetch details for account %s", + accountID); break; } - - GHashTable * details = (GHashTable *) dbus_get_account_details(a->accountID); - - if (details == NULL) { - ERROR("SFLphone: Error: Could not fetch detais for account %s", a->accountID); - break; - } - - a->properties = details; - + account_list_add(acc); /* Fill the actual array of credentials */ - dbus_get_credentials(a); - - gchar * status = g_hash_table_lookup(details, REGISTRATION_STATUS); + dbus_get_credentials(acc); + gchar * status = account_lookup(acc, REGISTRATION_STATUS); if (g_strcmp0(status, "REGISTERED") == 0) - a->state = ACCOUNT_STATE_REGISTERED; + acc->state = ACCOUNT_STATE_REGISTERED; else if (g_strcmp0(status, "UNREGISTERED") == 0) - a->state = ACCOUNT_STATE_UNREGISTERED; + acc->state = ACCOUNT_STATE_UNREGISTERED; else if (g_strcmp0(status, "TRYING") == 0) - a->state = ACCOUNT_STATE_TRYING; + acc->state = ACCOUNT_STATE_TRYING; else if (g_strcmp0(status, "ERROR") == 0) - a->state = ACCOUNT_STATE_ERROR; + acc->state = ACCOUNT_STATE_ERROR; else if (g_strcmp0(status , "ERROR_AUTH") == 0) - a->state = ACCOUNT_STATE_ERROR_AUTH; + acc->state = ACCOUNT_STATE_ERROR_AUTH; else if (g_strcmp0(status , "ERROR_NETWORK") == 0) - a->state = ACCOUNT_STATE_ERROR_NETWORK; + acc->state = ACCOUNT_STATE_ERROR_NETWORK; else if (g_strcmp0(status , "ERROR_HOST") == 0) - a->state = ACCOUNT_STATE_ERROR_HOST; + acc->state = ACCOUNT_STATE_ERROR_HOST; else if (g_strcmp0(status , "ERROR_CONF_STUN") == 0) - a->state = ACCOUNT_STATE_ERROR_CONF_STUN; + acc->state = ACCOUNT_STATE_ERROR_CONF_STUN; else if (g_strcmp0(status , "ERROR_EXIST_STUN") == 0) - a->state = ACCOUNT_STATE_ERROR_EXIST_STUN; - else if (g_strcmp0(status, "READY") == 0) - a->state = IP2IP_PROFILE_STATUS; + acc->state = ACCOUNT_STATE_ERROR_EXIST_STUN; + else if (g_strcmp0(status , "ACCOUNT_STATE_IP2IP_READY") == 0) + acc->state = ACCOUNT_STATE_IP2IP_READY; else - a->state = ACCOUNT_STATE_INVALID; - - gchar * code = g_hash_table_lookup(details, REGISTRATION_STATE_CODE); + acc->state = ACCOUNT_STATE_INVALID; + gchar * code = account_lookup(acc, REGISTRATION_STATE_CODE); if (code != NULL) - a->protocol_state_code = atoi(code); - - g_free(a->protocol_state_description); - a->protocol_state_description = g_hash_table_lookup(details, REGISTRATION_STATE_DESCRIPTION); + acc->protocol_state_code = atoi(code); + acc->protocol_state_description = account_lookup(acc, REGISTRATION_STATE_DESCRIPTION); } - // Set the current account message number - current_account_set_message_number(count); + g_strfreev(array); - sflphone_fill_codec_list(); + // Set the current account message number + current_account_set_message_number(current_account_get_message_number()); } gboolean sflphone_init(GError **error) @@ -297,7 +268,6 @@ gboolean sflphone_init(GError **error) contacts_tab = calltab_init(TRUE, CONTACTS); history_tab = calltab_init(TRUE, HISTORY); - account_list_init(); codec_capabilities_load(); conferencelist_init(current_calls_tab); @@ -965,22 +935,9 @@ sflphone_mute_call() toggle_slider_mute_microphone(); } -void sflphone_fill_codec_list() -{ - guint account_list_size = account_list_get_size(); - - for (guint i = 0; i < account_list_size; i++) { - account_t *current = account_list_get_nth(i); - - if (current) - sflphone_fill_codec_list_per_account(current); - } -} - void sflphone_fill_codec_list_per_account(account_t *account) { GArray *order = dbus_get_active_audio_codec_list(account->accountID); - GQueue *codeclist = account->codecs; // First clean the list diff --git a/gnome/src/actions.h b/gnome/src/actions.h index 145ba402505d43bfdbfa9c2c7a424af1e0cca032..4c3899836a2eab2e4140838b0a0344db18677391 100644 --- a/gnome/src/actions.h +++ b/gnome/src/actions.h @@ -52,27 +52,27 @@ * Initialize lists and configurations * @return TRUE if succeeded, FALSE otherwise */ -gboolean sflphone_init () ; +gboolean sflphone_init(); /** * Steps when closing the application. Will ask for confirmation if a call is in progress. */ -void sflphone_quit () ; +void sflphone_quit(); /** * Hang up / refuse the current call */ -void sflphone_hang_up (); +void sflphone_hang_up(); /** * Put the selected call on hold */ -void sflphone_on_hold (); +void sflphone_on_hold(); /** * Put the selected call off hold */ -void sflphone_off_hold (); +void sflphone_off_hold(); /** * Open a new call @@ -85,7 +85,7 @@ callable_obj_t * sflphone_new_call(); * @param accountID The account the voice mails are for * @param count The number of voice mails */ -void sflphone_notify_voice_mail (const gchar* accountID , guint count); +void sflphone_notify_voice_mail(const gchar* accountID, guint count); /** * Prepare SFLphone to transfer a call and wait for the user to dial the number to transfer to @@ -101,49 +101,49 @@ void sflphone_unset_transfer(); /** * Accept / dial the current call */ -void sflphone_pick_up (); +void sflphone_pick_up(); /** * Put the call on hold state * @param c The current call */ -void sflphone_hold (callable_obj_t * c); +void sflphone_hold(callable_obj_t * c); /** * Put the call in Ringing state * @param c* The current call */ -void sflphone_ringing (callable_obj_t * c); +void sflphone_ringing(callable_obj_t * c); /** * Put the call in Busy state * @param c* The current call */ -void sflphone_busy (callable_obj_t * c); +void sflphone_busy(callable_obj_t * c); /** * Put the call in Failure state * @param c* The current call */ -void sflphone_fail (callable_obj_t * c); +void sflphone_fail(callable_obj_t * c); /** * Put the call in Current state * @param c The current call */ -void sflphone_current (callable_obj_t * c); +void sflphone_current(callable_obj_t * c); /** * The callee has hung up * @param c The current call */ -void sflphone_hung_up (callable_obj_t * c); +void sflphone_hung_up(callable_obj_t * c); /** * Incoming call * @param c The incoming call */ -void sflphone_incoming_call (callable_obj_t * c); +void sflphone_incoming_call(callable_obj_t * c); /** * Dial the number @@ -151,19 +151,19 @@ void sflphone_incoming_call (callable_obj_t * c); * @param keyval The unique int representing the key * @param key The char value of the key */ -void sflphone_keypad (guint keyval, gchar * key); +void sflphone_keypad(guint keyval, gchar * key); /** * Place a call with a filled callable_obj_t.to * @param c A call in CALL_STATE_DIALING state */ -void sflphone_place_call (callable_obj_t * c); +void sflphone_place_call(callable_obj_t * c); /** * Fetch the ip2ip profile through dbus and fill * the internal hash table. */ -void sflphone_fill_ip2ip_profile (void); +void sflphone_fill_ip2ip_profile(void); /** * @return The internal hash table representing @@ -172,53 +172,52 @@ void sflphone_fill_ip2ip_profile (void); GHashTable *sflphone_get_ip2ip_properties(void); /** - * Initialize the accounts data structure + * Get a list of accounts from the daemon and load them into account_t + * structures. */ -void sflphone_fill_account_list (); +void sflphone_fill_account_list(); -void sflphone_fill_call_list (void); +void sflphone_fill_call_list(void); /** * Set an account as current. The current account is to one used to place calls with by default - * The current account is the first in the account list ( index 0 ) + * The current account is the first in the account list( index 0 ) */ void sflphone_set_current_account(); /** * Initialialize the codecs data structure */ -void sflphone_fill_codec_list (); - -void sflphone_fill_codec_list_per_account (account_t *); +void sflphone_fill_codec_list_per_account(account_t *); void sflphone_add_participant(); -void sflphone_record (callable_obj_t *c); +void sflphone_record(callable_obj_t *c); -void sflphone_rec_call (void); +void sflphone_rec_call(void); -void sflphone_mute_call (void); +void sflphone_mute_call(void); -void status_bar_display_account (); +void status_bar_display_account(); -void sflphone_fill_history (void); +void sflphone_fill_history(void); /** * Action called when a new participant is dragged in */ -void sflphone_add_participant (const gchar* callID, const gchar* confID); +void sflphone_add_participant(const gchar* callID, const gchar* confID); /** * Action called when a conference participant is draged out */ -void sflphone_detach_participant (const gchar* callID); +void sflphone_detach_participant(const gchar* callID); /** * Nofity that the communication is * now secured using SRTP/SDES. * @param c* The current call */ -void sflphone_srtp_sdes_on (callable_obj_t * c); +void sflphone_srtp_sdes_on(callable_obj_t * c); /** * Notify that the SRTP/SDES session @@ -230,14 +229,14 @@ void sflphone_srtp_sdes_on (callable_obj_t * c); * now secured using ZRTP. * @param c* The current call */ -void sflphone_srtp_zrtp_on (callable_obj_t * c); +void sflphone_srtp_zrtp_on(callable_obj_t * c); /** * Called when the ZRTP session goes * unsecured. * @param c* The current call */ -void sflphone_srtp_zrtp_off (callable_obj_t * c); +void sflphone_srtp_zrtp_off(callable_obj_t * c); /** * Called when the sas has been computed @@ -246,13 +245,14 @@ void sflphone_srtp_zrtp_off (callable_obj_t * c); * @param sas* The Short Authentication String * @param verified* Weather the SAS was confirmed or not. */ -void sflphone_srtp_zrtp_show_sas (callable_obj_t * c, const gchar* sas, const gboolean verified); +void sflphone_srtp_zrtp_show_sas(callable_obj_t * c, const gchar* sas, const gboolean verified); /** * Called when user wants to clear. * @param c* The call on which to go clear */ -void sflphone_request_go_clear (void); + +void sflphone_request_go_clear(void); /** * Called when the UI needs to be refreshed to @@ -262,12 +262,12 @@ void sflphone_request_go_clear (void); * @param description A textual description of the code * @param code The status code as in SIP or IAX */ -void sflphone_call_state_changed (callable_obj_t * c, const gchar * description, const guint code); +void sflphone_call_state_changed(callable_obj_t * c, const gchar * description, const guint code); -void sflphone_add_main_participant (const conference_obj_t * c); +void sflphone_add_main_participant(const conference_obj_t * c); -void sflphone_srtp_sdes_off (callable_obj_t * c); +void sflphone_srtp_sdes_off(callable_obj_t * c); -void sflphone_fill_conference_list (void); +void sflphone_fill_conference_list(void); #endif diff --git a/gnome/src/codeclist.c b/gnome/src/codeclist.c index 9a83e5f42d1cf80b8b1a7ac801d65bce4048ffe2..6662cfe018464ca8e59d6f9f292b35958f0f6024 100644 --- a/gnome/src/codeclist.c +++ b/gnome/src/codeclist.c @@ -217,7 +217,7 @@ void codec_list_update_to_daemon(const account_t *acc) int c = 0; int i; - for (i = 0; i < length; i++) { + for (i = 0; i < length; ++i) { codec_t* currentCodec = codec_list_get_nth(i, acc->codecs); if (currentCodec) { @@ -240,14 +240,14 @@ void codec_list_update_to_daemon(const account_t *acc) // Allocate NULL array at the end for Dbus codecList = (void*) g_realloc(codecList, (c + 1) * sizeof(void*)); - *(codecList+c) = NULL; + *(codecList + c) = NULL; // call dbus function with array of strings dbus_set_active_audio_codec_list(codecList, acc->accountID); // Delete memory for (i = 0; i < c; i++) - g_free((gchar*) *(codecList+i)); + g_free((gchar*) *(codecList + i) ); g_free(codecList); } diff --git a/gnome/src/config/accountconfigdialog.c b/gnome/src/config/accountconfigdialog.c index 8acc9c5d8ce61fa495eb4311807b27665b8c557f..3ef15b51a39bc946bd2c34ed37619a931a508b2f 100644 --- a/gnome/src/config/accountconfigdialog.c +++ b/gnome/src/config/accountconfigdialog.c @@ -206,7 +206,7 @@ static GtkWidget* create_basic_tab(const account_t *account) password = g_hash_table_lookup(element, ACCOUNT_PASSWORD); } } else - password = g_hash_table_lookup(account->properties, ACCOUNT_PASSWORD); + password = account_lookup(account, ACCOUNT_PASSWORD); GtkWidget *frame = gnome_main_section_new(_("Account Parameters")); gtk_widget_show(frame); @@ -214,7 +214,7 @@ static GtkWidget* create_basic_tab(const account_t *account) GtkWidget *table = NULL; if (account_is_SIP(account)) - table = gtk_table_new(9, 2, FALSE/* homogeneous */); + table = gtk_table_new(9, 2, FALSE /* homogeneous */); else if (account_is_IAX(account)) table = gtk_table_new(8, 2, FALSE); else { @@ -234,7 +234,7 @@ static GtkWidget* create_basic_tab(const account_t *account) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); entry_alias = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_alias); - gchar *alias = g_hash_table_lookup(account->properties, ACCOUNT_ALIAS); + gchar *alias = account_lookup(account, ACCOUNT_ALIAS); gtk_entry_set_text(GTK_ENTRY(entry_alias), alias); gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -276,8 +276,7 @@ static GtkWidget* create_basic_tab(const account_t *account) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); entry_hostname = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_hostname); - const gchar *hostname = g_hash_table_lookup(account->properties, - ACCOUNT_HOSTNAME); + const gchar *hostname = account_lookup(account, ACCOUNT_HOSTNAME); gtk_entry_set_text(GTK_ENTRY(entry_hostname), hostname); gtk_table_attach(GTK_TABLE(table), entry_hostname, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -293,7 +292,7 @@ static GtkWidget* create_basic_tab(const account_t *account) GTK_ENTRY_ICON_PRIMARY, gdk_pixbuf_new_from_file(PERSON_IMG, NULL)); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_username); - gchar *username = g_hash_table_lookup(account->properties, ACCOUNT_USERNAME); + gchar *username = account_lookup(account, ACCOUNT_USERNAME); gtk_entry_set_text(GTK_ENTRY(entry_username), username); gtk_table_attach(GTK_TABLE(table), entry_username, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -337,7 +336,7 @@ static GtkWidget* create_basic_tab(const account_t *account) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); entry_route_set = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_route_set); - gchar *route_set = g_hash_table_lookup(account->properties, ACCOUNT_ROUTE); + gchar *route_set = account_lookup(account, ACCOUNT_ROUTE); gtk_entry_set_text(GTK_ENTRY(entry_route_set), route_set); gtk_table_attach(GTK_TABLE(table), entry_route_set, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -347,7 +346,7 @@ static GtkWidget* create_basic_tab(const account_t *account) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); entry_mailbox = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_mailbox); - gchar *mailbox = g_hash_table_lookup(account->properties, ACCOUNT_MAILBOX); + gchar *mailbox = account_lookup(account, ACCOUNT_MAILBOX); mailbox = mailbox ? mailbox : ""; gtk_entry_set_text(GTK_ENTRY(entry_mailbox), mailbox); gtk_table_attach(GTK_TABLE(table), entry_mailbox, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -358,7 +357,7 @@ static GtkWidget* create_basic_tab(const account_t *account) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); entry_user_agent = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry_user_agent); - gchar *user_agent = g_hash_table_lookup(account->properties, ACCOUNT_USERAGENT); + gchar *user_agent = account_lookup(account, ACCOUNT_USERAGENT); gtk_entry_set_text(GTK_ENTRY(entry_user_agent), user_agent); gtk_table_attach(GTK_TABLE(table), entry_user_agent, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -418,7 +417,6 @@ delete_credential_cb(GtkWidget *button UNUSED, gpointer data) GtkTreePath *path; path = gtk_tree_model_get_path(model, &iter); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); - gtk_tree_path_free(path); } } @@ -662,7 +660,7 @@ static GtkWidget* create_credential_widget(const account_t *account) G_TYPE_STRING, // Username G_TYPE_STRING, // Password G_TYPE_POINTER // Pointer to the Objectc - ); + ); treeview_credential = gtk_tree_view_new_with_model(GTK_TREE_MODEL(credential_store)); GtkTreeSelection * tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_credential)); @@ -726,17 +724,16 @@ create_security_widget(const account_t *account) // Load from SIP/IAX/Unknown ? if (account && account->properties) { - curKeyExchange = g_hash_table_lookup(account->properties, - ACCOUNT_KEY_EXCHANGE); + curKeyExchange = account_lookup(account, ACCOUNT_KEY_EXCHANGE); if (curKeyExchange == NULL) curKeyExchange = "none"; - curSRTPEnabled = g_hash_table_lookup(account->properties, ACCOUNT_SRTP_ENABLED); + curSRTPEnabled = account_lookup(account, ACCOUNT_SRTP_ENABLED); if (curSRTPEnabled == NULL) curSRTPEnabled = "false"; - curTLSEnabled = g_hash_table_lookup(account->properties, TLS_ENABLE); + curTLSEnabled = account_lookup(account, TLS_ENABLE); if (curTLSEnabled == NULL) curTLSEnabled = "false"; @@ -830,7 +827,7 @@ static GtkWidget* create_registration_expire(const account_t *account) &orig_key, (gpointer) &account_expire)) ERROR("Could not retrieve %s from account properties", ACCOUNT_REGISTRATION_EXPIRE); - + GtkWidget *table, *frame; gnome_main_section_new_with_table(_("Registration"), &frame, &table, 2, 3); gtk_container_set_border_width(GTK_CONTAINER(table), 10); @@ -854,8 +851,8 @@ create_network(const account_t *account) gchar *local_port = NULL; if (account) { - local_interface = g_hash_table_lookup(account->properties, LOCAL_INTERFACE); - local_port = g_hash_table_lookup(account->properties, LOCAL_PORT); + local_interface = account_lookup(account, LOCAL_INTERFACE); + local_port = account_lookup(account, LOCAL_PORT); } GtkWidget *table, *frame; @@ -922,20 +919,20 @@ GtkWidget* create_published_address(const account_t *account) // Get the user configuration if (account) { - use_tls = g_hash_table_lookup(account->properties, TLS_ENABLE); - published_sameas_local = g_hash_table_lookup(account->properties, PUBLISHED_SAMEAS_LOCAL); + use_tls = account_lookup(account, TLS_ENABLE); + published_sameas_local = account_lookup(account, PUBLISHED_SAMEAS_LOCAL); if (utf8_case_equal(published_sameas_local, "true")) { - published_address = dbus_get_address_from_interface_name(g_hash_table_lookup(account->properties, LOCAL_INTERFACE)); - published_port = g_hash_table_lookup(account->properties, LOCAL_PORT); + published_address = dbus_get_address_from_interface_name(account_lookup(account, LOCAL_INTERFACE)); + published_port = account_lookup(account, LOCAL_PORT); } else { - published_address = g_hash_table_lookup(account->properties, PUBLISHED_ADDRESS); - published_port = g_hash_table_lookup(account->properties, PUBLISHED_PORT); + published_address = account_lookup(account, PUBLISHED_ADDRESS); + published_port = account_lookup(account, PUBLISHED_PORT); } - stun_enable = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_ENABLED); - stun_server = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_SERVER); - published_sameas_local = g_hash_table_lookup(account->properties, PUBLISHED_SAMEAS_LOCAL); + stun_enable = account_lookup(account, ACCOUNT_SIP_STUN_ENABLED); + stun_server = account_lookup(account, ACCOUNT_SIP_STUN_SERVER); + published_sameas_local = account_lookup(account, PUBLISHED_SAMEAS_LOCAL); } gnome_main_section_new_with_table(_("Published address"), &frame, &table, 2, 3); @@ -1061,7 +1058,7 @@ create_audiocodecs_configuration(const account_t *account) gtk_widget_show(dtmf); overrtp = gtk_radio_button_new_with_label(NULL, _("RTP")); - const gchar * const dtmf_type = g_hash_table_lookup(account->properties, ACCOUNT_DTMF_TYPE); + const gchar * const dtmf_type = account_lookup(account, ACCOUNT_DTMF_TYPE); const gboolean dtmf_are_rtp = utf8_case_equal(dtmf_type, OVERRTP); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overrtp), dtmf_are_rtp); gtk_table_attach(GTK_TABLE(table), overrtp, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -1079,7 +1076,7 @@ create_audiocodecs_configuration(const account_t *account) file_chooser = gtk_file_chooser_button_new(_("Choose a ringtone"), GTK_FILE_CHOOSER_ACTION_OPEN); - gpointer ptr = g_hash_table_lookup(account->properties, CONFIG_RINGTONE_ENABLED); + gpointer ptr = account_lookup(account, CONFIG_RINGTONE_ENABLED); enable_tone = gtk_check_button_new_with_mnemonic(_("_Enable ringtones")); const gboolean ringtone_enabled = g_strcmp0(ptr, "true") == 0; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_tone), ringtone_enabled); @@ -1088,7 +1085,7 @@ create_audiocodecs_configuration(const account_t *account) // file chooser button gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser) , g_get_home_dir()); - ptr = g_hash_table_lookup(account->properties, CONFIG_RINGTONE_PATH); + ptr = account_lookup(account, CONFIG_RINGTONE_PATH); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser) , ptr); gtk_widget_set_sensitive(file_chooser, ringtone_enabled); @@ -1236,7 +1233,44 @@ static void update_account_from_basic_tab(account_t *account) g_free(proto); } -void show_account_window(account_t *account) +void update_account_from_dialog(GtkWidget *dialog, account_t *account) +{ + if (!dialog) + return; + + const gboolean IS_IP2IP = account_is_IP2IP(account); + if (!IS_IP2IP) + update_account_from_basic_tab(account); + + // Get current protocol for this account + gchar *current_protocol; + if (protocol_combo) + current_protocol = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(protocol_combo)); + else + current_protocol = g_strdup("SIP"); + + if (!IS_IP2IP && g_strcmp0(current_protocol, "SIP") == 0) + account->credential_information = get_new_credential(); + + /** @todo Verify if it's the best condition to check */ + if (g_strcmp0(account->accountID, "new") == 0) { + dbus_add_account(account); + if (account->credential_information) + dbus_set_credentials(account); + } else { + if (account->credential_information) + dbus_set_credentials(account); + dbus_set_account_details(account); + } + + // propagate changes to the daemon + codec_list_update_to_daemon(account); + + g_free(current_protocol); + gtk_widget_destroy(dialog); +} + +GtkWidget *show_account_window(const account_t *account) { // First we reset reset(); @@ -1256,9 +1290,10 @@ void show_account_window(account_t *account) gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), notebook, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(notebook), 10); gtk_widget_show(notebook); + const gboolean IS_IP2IP = account_is_IP2IP(account); // We do not need the global settings for the IP2IP account - if (!account_is_IP2IP(account)) { + if (!IS_IP2IP) { /* General Settings */ GtkWidget *basic_tab = create_basic_tab(account); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), basic_tab, gtk_label_new(_("Basic"))); @@ -1270,22 +1305,14 @@ void show_account_window(account_t *account) gtk_notebook_append_page(GTK_NOTEBOOK(notebook), audiocodecs_tab, gtk_label_new(_("Audio"))); gtk_notebook_page_num(GTK_NOTEBOOK(notebook), audiocodecs_tab); - // Get current protocol for this account - gchar *current_protocol; - if (protocol_combo) - current_protocol = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(protocol_combo)); - else - current_protocol = g_strdup("SIP"); - // Do not need advanced or security one for the IP2IP account - if (!account_is_IP2IP(account)) { + if (!IS_IP2IP) { /* Advanced */ advanced_tab = create_advanced_tab(account); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), advanced_tab, gtk_label_new(_("Advanced"))); gtk_notebook_page_num(GTK_NOTEBOOK(notebook), advanced_tab); /* Security */ - initialize_credential_information(account); security_tab = create_security_tab(account); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), security_tab, gtk_label_new(_("Security"))); gtk_notebook_page_num(GTK_NOTEBOOK(notebook), security_tab); @@ -1302,41 +1329,15 @@ void show_account_window(account_t *account) gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0); - /* Run dialog */ + /* Run dialog, this blocks */ gint response = gtk_dialog_run(GTK_DIALOG(dialog)); - // If cancel button is pressed - if (response == GTK_RESPONSE_CANCEL) { + // If anything but "Apply" button is pressed + if (response != GTK_RESPONSE_ACCEPT) { gtk_widget_destroy(dialog); - return; - } - - if (!account_is_IP2IP(account)) - update_account_from_basic_tab(account); - - /** @todo Verify if it's the best condition to check */ - if (utf8_case_equal(account->accountID, "new")) - dbus_add_account(account); - else - dbus_set_account_details(account); - - if (g_strcmp0(current_protocol, "SIP") == 0) { - /* Set new credentials if any */ - DEBUG("Config: Setting credentials"); - - if (!account_is_IP2IP(account)) { - DEBUG("Config: Get new credentials"); - account->credential_information = get_new_credential(); - - if (account->credential_information) - dbus_set_credentials(account); - } + return NULL; + } else { + return dialog; } - - // propagate changes to the daemon - codec_list_update_to_daemon(account); - - gtk_widget_destroy(dialog); - g_free(current_protocol); } diff --git a/gnome/src/config/accountconfigdialog.h b/gnome/src/config/accountconfigdialog.h index 1683b269c294942f13acd85399639f4be68cf253..43cfe666e6c6fd57ece795a41bbc113280138b27 100644 --- a/gnome/src/config/accountconfigdialog.h +++ b/gnome/src/config/accountconfigdialog.h @@ -40,7 +40,18 @@ /** * Display the main account widget * @param a The account you want to display + * @return The dialog with the pertinent account information */ -void show_account_window(account_t *a); +GtkWidget *show_account_window(const account_t *a); + +/* + * @param dialog The dialog the account will be update from + * @param a The account you want to display + */ +void update_account_from_dialog(GtkWidget *dialog, account_t *a); + +/** + * Resets local cache of account pointers */ +void reset_account_store(); #endif diff --git a/gnome/src/config/accountlistconfigdialog.c b/gnome/src/config/accountlistconfigdialog.c index 31de47d48c02e6528c5bda9dd6ba43d523fa60cf..27560b0200c74d898e506bc36f84768f53563fb5 100644 --- a/gnome/src/config/accountlistconfigdialog.c +++ b/gnome/src/config/accountlistconfigdialog.c @@ -44,15 +44,13 @@ static const int CONTEXT_ID_REGISTRATION = 0; -static GtkWidget *add_button; static GtkWidget *edit_button; static GtkWidget *delete_button; static GtkWidget *move_down_button; static GtkWidget *move_up_button; -static GtkWidget *status_bar; +static GtkWidget *account_list_status_bar; static GtkListStore *account_store; static GtkDialog *account_list_dialog; -static account_t *selected_account; // Account properties enum { @@ -60,72 +58,125 @@ enum { COLUMN_ACCOUNT_TYPE, COLUMN_ACCOUNT_STATUS, COLUMN_ACCOUNT_ACTIVE, - COLUMN_ACCOUNT_DATA, + COLUMN_ACCOUNT_ID, COLUMN_ACCOUNT_COUNT }; -static void delete_account_cb(void) +/* Get selected account ID from treeview + * @return copied selected_accountID, must be freed by caller */ +static gchar * +get_selected_accountID(GtkTreeView *tree_view) { - RETURN_IF_NULL(selected_account, "No selected account in delete action"); - dbus_remove_account(selected_account->accountID); - selected_account = NULL; + GtkTreeModel *model = gtk_tree_view_get_model(tree_view); + GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); + + // Find selected iteration and create a copy + GtkTreeIter iter; + gtk_tree_selection_get_selected(selection, &model, &iter); + // The Gvalue will be initialized in the following function + GValue val; + memset(&val, 0, sizeof(val)); + gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_ID, &val); + + gchar *selected_accountID = g_strdup(g_value_get_string(&val)); + g_value_unset(&val); + return selected_accountID; } -static void row_activated_cb(GtkTreeView *view UNUSED, - GtkTreePath *path UNUSED, - GtkTreeViewColumn *col UNUSED, - gpointer user_data UNUSED) +static gboolean +find_account_in_account_store(const gchar *accountID, GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean valid = gtk_tree_model_get_iter_first(model, iter); + gboolean found = FALSE; + while (valid && !found) { + gchar *id; + gtk_tree_model_get(model, iter, COLUMN_ACCOUNT_ID, &id, -1); + if (g_strcmp0(id, accountID) == 0) + found = TRUE; + else + valid = gtk_tree_model_iter_next(model, iter); + g_free(id); + } + return found; +} + + +static void delete_account_cb(GtkButton *button UNUSED, gpointer data) { - RETURN_IF_NULL(selected_account, "No selected account in edit action"); - DEBUG("%s: accountID=%s\n", __PRETTY_FUNCTION__, selected_account->accountID); - show_account_window(selected_account); + gchar *selected_accountID = get_selected_accountID(data); + RETURN_IF_NULL(selected_accountID, "No selected account in delete action"); + GtkTreeModel *model = GTK_TREE_MODEL(account_store); + GtkTreeIter iter; + if (find_account_in_account_store(selected_accountID, model, &iter)) + gtk_list_store_remove(account_store, &iter); + + dbus_remove_account(selected_accountID); + g_free(selected_accountID); } -static void edit_account_cb(GtkButton *button UNUSED, gpointer data UNUSED) +static void +run_account_dialog(const gchar *selected_accountID) { - RETURN_IF_NULL(selected_account, "No selected account in edit action"); - DEBUG("%s: accountID=%s\n", __PRETTY_FUNCTION__, selected_account->accountID); - show_account_window(selected_account); + account_t *account = account_list_get_by_id(selected_accountID); + GtkWidget *dialog = show_account_window(account); + update_account_from_dialog(dialog, account); } -static void add_account_cb(void) +static void row_activated_cb(GtkTreeView *view, + GtkTreePath *path UNUSED, + GtkTreeViewColumn *col UNUSED, + gpointer user_data UNUSED) { - account_t *new_account = create_default_account(); - show_account_window(new_account); + gchar *selected_accountID = get_selected_accountID(view); + RETURN_IF_NULL(selected_accountID, "No selected account ID"); + run_account_dialog(selected_accountID); + g_free(selected_accountID); } -static void account_store_fill(GtkTreeIter *iter, account_t *a) +static void edit_account_cb(GtkButton *button UNUSED, gpointer data) { - const gchar *enabled = g_hash_table_lookup(a->properties, ACCOUNT_ENABLED); - const gchar *type = g_hash_table_lookup(a->properties, ACCOUNT_TYPE); - DEBUG("Config: Filling accounts: Account is enabled :%s", enabled); + gchar *selected_accountID = get_selected_accountID(data); + RETURN_IF_NULL(selected_accountID, "No selected account ID"); + run_account_dialog(selected_accountID); + g_free(selected_accountID); +} + +static void account_store_add(GtkTreeIter *iter, account_t *account) +{ + const gchar *enabled = account_lookup(account, ACCOUNT_ENABLED); + const gchar *type = account_lookup(account, ACCOUNT_TYPE); + DEBUG("Config: Adding account: Account is enabled :%s", enabled); + const gchar *state_name = account_state_name(account->state); - gtk_list_store_set(account_store, iter, COLUMN_ACCOUNT_ALIAS, - g_hash_table_lookup(a->properties, ACCOUNT_ALIAS), + gtk_list_store_set(account_store, iter, + COLUMN_ACCOUNT_ALIAS, account_lookup(account, ACCOUNT_ALIAS), COLUMN_ACCOUNT_TYPE, type, - COLUMN_ACCOUNT_STATUS, account_state_name(a->state), + COLUMN_ACCOUNT_STATUS, state_name, COLUMN_ACCOUNT_ACTIVE, utf8_case_equal(enabled, "true"), - COLUMN_ACCOUNT_DATA, a, -1); + COLUMN_ACCOUNT_ID, account->accountID, -1); } + + /** - * Fills the treelist with accounts + * Fills the treelist with accounts, should be called whenever the account + * list is modified. */ -void account_list_config_dialog_fill() +static void account_store_fill() { RETURN_IF_NULL(account_list_dialog, "No account dialog"); - gtk_list_store_clear(account_store); // IP2IP account must be first - account_t *ip2ip = account_list_get_by_id("IP2IP"); - + account_t *ip2ip = account_list_get_by_id(IP2IP_PROFILE); + ip2ip->state = ACCOUNT_STATE_IP2IP_READY; RETURN_IF_NULL(ip2ip, "Could not find IP2IP account"); GtkTreeIter iter; gtk_list_store_append(account_store, &iter); - account_store_fill(&iter, ip2ip); + account_store_add(&iter, ip2ip); for (size_t i = 0; i < account_list_get_size(); ++i) { account_t *a = account_list_get_nth(i); @@ -134,11 +185,19 @@ void account_list_config_dialog_fill() // we don't want to process the IP2IP twice if (a != ip2ip) { gtk_list_store_append(account_store, &iter); - account_store_fill(&iter, a); + account_store_add(&iter, a); } } } +static void add_account_cb(void) +{ + account_t *new_account = create_default_account(); + account_list_add(new_account); + run_account_dialog(new_account->accountID); + account_store_fill(); +} + /** * Call back when the user click on an account in the list */ @@ -147,7 +206,6 @@ select_account_cb(GtkTreeSelection *selection, GtkTreeModel *model) { GtkTreeIter iter; if (!gtk_tree_selection_get_selected(selection, &model, &iter)) { - selected_account = NULL; gtk_widget_set_sensitive(move_up_button, FALSE); gtk_widget_set_sensitive(move_down_button, FALSE); gtk_widget_set_sensitive(edit_button, FALSE); @@ -158,13 +216,14 @@ select_account_cb(GtkTreeSelection *selection, GtkTreeModel *model) // The Gvalue will be initialized in the following function GValue val; memset(&val, 0, sizeof(val)); - gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_DATA, &val); + gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_ID, &val); - selected_account = (account_t*) g_value_get_pointer(&val); + gchar *selected_accountID = g_value_dup_string(&val); g_value_unset(&val); + DEBUG("Selected account has accountID %s", selected_accountID); + account_t *selected_account = account_list_get_by_id(selected_accountID); RETURN_IF_NULL(selected_account, "Selected account is NULL"); - DEBUG("Selected account has accountID %s", selected_account->accountID); gtk_widget_set_sensitive(edit_button, TRUE); @@ -174,33 +233,13 @@ select_account_cb(GtkTreeSelection *selection, GtkTreeModel *model) gtk_widget_set_sensitive(delete_button, TRUE); /* Update status bar about current registration state */ - gtk_statusbar_pop(GTK_STATUSBAR(status_bar), CONTEXT_ID_REGISTRATION); - - const gchar *state_name = account_state_name(selected_account->state); - if (selected_account->protocol_state_description != NULL - && selected_account->protocol_state_code != 0) { - - gchar * response = g_strdup_printf( - _("Server returned \"%s\" (%d)"), - selected_account->protocol_state_description, - selected_account->protocol_state_code); - gchar * message = g_strconcat(state_name, ". ", response, NULL); - gtk_statusbar_push(GTK_STATUSBAR(status_bar), - CONTEXT_ID_REGISTRATION, message); - - g_free(response); - g_free(message); - - } else { - gtk_statusbar_push(GTK_STATUSBAR(status_bar), - CONTEXT_ID_REGISTRATION, state_name); - } + update_account_list_status_bar(selected_account); } else { gtk_widget_set_sensitive(move_up_button, FALSE); gtk_widget_set_sensitive(move_down_button, FALSE); gtk_widget_set_sensitive(delete_button, FALSE); } - DEBUG("Selecting account in account window"); + g_free(selected_accountID); } static void @@ -208,7 +247,7 @@ enable_account_cb(GtkCellRendererToggle *rend UNUSED, gchar* path, gpointer data) { // The IP2IP profile can't be disabled - if (utf8_case_equal(path, "0")) + if (g_strcmp0(path, "0") == 0) return; // Get pointer on object @@ -217,24 +256,24 @@ enable_account_cb(GtkCellRendererToggle *rend UNUSED, gchar* path, GtkTreeIter iter; gtk_tree_model_get_iter(model, &iter, tree_path); gboolean enable; - account_t* acc; + gchar *id; gtk_tree_model_get(model, &iter, COLUMN_ACCOUNT_ACTIVE, &enable, - COLUMN_ACCOUNT_DATA, &acc, -1); + COLUMN_ACCOUNT_ID, &id, -1); + + account_t *account = account_list_get_by_id(id); + g_assert(account); enable = !enable; - DEBUG("Account is %d enabled", enable); // Store value gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_ACCOUNT_ACTIVE, enable, -1); // Modify account state - gchar * registration_state = enable ? g_strdup("true") : g_strdup("false"); - - DEBUG("Replacing registration state with %s", registration_state); - g_hash_table_replace(acc->properties, g_strdup(ACCOUNT_ENABLED), - registration_state); + const gchar * enabled_str = enable ? "true" : "false"; + DEBUG("Account is enabled: %s", enabled_str); - dbus_send_register(acc->accountID, enable); + account_replace(account, ACCOUNT_ENABLED, enabled_str); + dbus_send_register(account->accountID, enable); } /** @@ -243,7 +282,7 @@ enable_account_cb(GtkCellRendererToggle *rend UNUSED, gchar* path, static void account_move(gboolean move_up, gpointer data) { - // Get view, model and selection of codec store + // Get view, model and selection of account GtkTreeView *tree_view = GTK_TREE_VIEW(data); GtkTreeModel *model = gtk_tree_view_get_model(tree_view); GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); @@ -259,7 +298,7 @@ account_move(gboolean move_up, gpointer data) // The first real account in the list can't move up because of the IP2IP account // It can still move down though - if (utf8_case_equal(path, "1") && move_up) + if (g_strcmp0(path, "1") == 0 && move_up) return; GtkTreePath *tree_path = gtk_tree_path_new_from_string(path); @@ -343,13 +382,12 @@ highlight_ip_profile(GtkTreeViewColumn *col UNUSED, GtkCellRenderer *rend, { GValue val; memset(&val, 0, sizeof(val)); - gtk_tree_model_get_value(tree_model, iter, COLUMN_ACCOUNT_DATA, &val); - account_t *current = (account_t*) g_value_get_pointer(&val); - + gtk_tree_model_get_value(tree_model, iter, COLUMN_ACCOUNT_ID, &val); + account_t *current = account_list_get_by_id(g_value_get_string(&val)); g_value_unset(&val); - if (current != NULL) { - // Make the first line appear differently + // Make the IP2IP account appear differently + if (current) { if (account_is_IP2IP(current)) { g_object_set(G_OBJECT(rend), "weight", PANGO_WEIGHT_THIN, "style", PANGO_STYLE_ITALIC, "stretch", @@ -381,8 +419,8 @@ highlight_registration(GtkTreeViewColumn *col UNUSED, GtkCellRenderer *rend, { GValue val; memset(&val, 0, sizeof(val)); - gtk_tree_model_get_value(tree_model, iter, COLUMN_ACCOUNT_DATA, &val); - account_t *current = (account_t*) g_value_get_pointer(&val); + gtk_tree_model_get_value(tree_model, iter, COLUMN_ACCOUNT_ID, &val); + account_t *current = account_list_get_by_id(g_value_get_string(&val)); g_value_unset(&val); if (current) @@ -395,7 +433,6 @@ highlight_registration(GtkTreeViewColumn *col UNUSED, GtkCellRenderer *rend, static GtkWidget* create_account_list() { - selected_account = NULL; GtkWidget *table = gtk_table_new(1, 2, FALSE /* homogeneous */); gtk_table_set_col_spacings(GTK_TABLE(table), 10); gtk_container_set_border_width(GTK_CONTAINER(table), 10); @@ -413,23 +450,22 @@ create_account_list() G_TYPE_STRING, // Protocol G_TYPE_STRING, // Status G_TYPE_BOOLEAN, // Enabled / Disabled - G_TYPE_POINTER // Pointer to the Object + G_TYPE_STRING // AccountID ); - account_list_config_dialog_fill(); + account_store_fill(); GtkTreeView * tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(account_store))); GtkTreeSelection *tree_selection = gtk_tree_view_get_selection(tree_view); g_signal_connect(G_OBJECT(tree_selection), "changed", - G_CALLBACK(select_account_cb), - account_store); + G_CALLBACK(select_account_cb), NULL); GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new(); GtkTreeViewColumn *tree_view_column = gtk_tree_view_column_new_with_attributes("Enabled", renderer, "active", COLUMN_ACCOUNT_ACTIVE , NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), tree_view_column); - g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(enable_account_cb), (gpointer) tree_view); + g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(enable_account_cb), tree_view); renderer = gtk_cell_renderer_text_new(); tree_view_column = gtk_tree_view_column_new_with_attributes("Alias", @@ -457,8 +493,7 @@ create_account_list() renderer = gtk_cell_renderer_text_new(); tree_view_column = gtk_tree_view_column_new_with_attributes(_("Status"), renderer, - "markup", COLUMN_ACCOUNT_STATUS, - NULL); + "markup", COLUMN_ACCOUNT_STATUS, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), tree_view_column); // Highlight IP profile gtk_tree_view_column_set_cell_data_func(tree_view_column, renderer, @@ -491,20 +526,20 @@ create_account_list() g_signal_connect(G_OBJECT(move_down_button), "clicked", G_CALLBACK(move_down_cb), tree_view); - add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); + GtkWidget *add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); g_signal_connect_swapped(G_OBJECT(add_button), "clicked", G_CALLBACK(add_account_cb), NULL); gtk_box_pack_start(GTK_BOX(button_box), add_button, FALSE, FALSE, 0); edit_button = gtk_button_new_from_stock(GTK_STOCK_EDIT); gtk_widget_set_sensitive(edit_button, FALSE); - g_signal_connect(G_OBJECT(edit_button), "clicked", G_CALLBACK(edit_account_cb), NULL); + g_signal_connect(G_OBJECT(edit_button), "clicked", G_CALLBACK(edit_account_cb), tree_view); gtk_box_pack_start(GTK_BOX(button_box), edit_button, FALSE, FALSE, 0); delete_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); gtk_widget_set_sensitive(delete_button, FALSE); - g_signal_connect_swapped(G_OBJECT(delete_button), "clicked", - G_CALLBACK(delete_account_cb), NULL); + g_signal_connect(G_OBJECT(delete_button), "clicked", + G_CALLBACK(delete_account_cb), tree_view); gtk_box_pack_start(GTK_BOX(button_box), delete_button, FALSE, FALSE, 0); /* help and close buttons */ @@ -539,6 +574,39 @@ create_account_list() return table; } +void update_account_list_status_bar(account_t *account) +{ + if (!account || !account_list_status_bar) + return; + + /* Update status bar about current registration state */ + gtk_statusbar_pop(GTK_STATUSBAR(account_list_status_bar), + CONTEXT_ID_REGISTRATION); + + const gchar *state_name = account_state_name(account->state); + if (account->protocol_state_description != NULL && + account->protocol_state_code != 0) { + + gchar * response = g_strdup_printf(_("Server returned \"%s\" (%d)"), + account->protocol_state_description, + account->protocol_state_code); + gchar * message = g_strconcat(state_name, ". ", response, NULL); + gtk_statusbar_push(GTK_STATUSBAR(account_list_status_bar), + CONTEXT_ID_REGISTRATION, message); + + g_free(response); + g_free(message); + } else { + gtk_statusbar_push(GTK_STATUSBAR(account_list_status_bar), + CONTEXT_ID_REGISTRATION, state_name); + } + + GtkTreeModel *model = GTK_TREE_MODEL(account_store); + GtkTreeIter iter; + if (find_account_in_account_store(account->accountID, model, &iter)) + gtk_list_store_set(account_store, &iter, COLUMN_ACCOUNT_STATUS, state_name, -1); +} + void show_account_list_config_dialog(void) { account_list_dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(_("Accounts"), @@ -561,9 +629,9 @@ void show_account_list_config_dialog(void) gtk_container_add(GTK_CONTAINER(accountFrame), tab); /* Status bar for the account list */ - status_bar = gtk_statusbar_new(); - gtk_widget_show(status_bar); - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(account_list_dialog)), status_bar, TRUE, TRUE, 0); + account_list_status_bar = gtk_statusbar_new(); + gtk_widget_show(account_list_status_bar); + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(account_list_dialog)), account_list_status_bar, TRUE, TRUE, 0); const gint num_accounts = account_list_get_registered_accounts(); @@ -571,11 +639,11 @@ void show_account_list_config_dialog(void) gchar * message = g_strdup_printf(n_("There is %d active account", "There are %d active accounts", num_accounts), num_accounts); - gtk_statusbar_push(GTK_STATUSBAR(status_bar), CONTEXT_ID_REGISTRATION, + gtk_statusbar_push(GTK_STATUSBAR(account_list_status_bar), CONTEXT_ID_REGISTRATION, message); g_free(message); } else { - gtk_statusbar_push(GTK_STATUSBAR(status_bar), CONTEXT_ID_REGISTRATION, + gtk_statusbar_push(GTK_STATUSBAR(account_list_status_bar), CONTEXT_ID_REGISTRATION, _("You have no active account")); } @@ -584,7 +652,16 @@ void show_account_list_config_dialog(void) status_bar_display_account(); gtk_widget_destroy(GTK_WIDGET(account_list_dialog)); + + /* Invalidate static pointers */ account_list_dialog = NULL; + account_list_status_bar = NULL; + edit_button = NULL; + delete_button = NULL; + move_down_button = NULL; + move_up_button = NULL; + account_store = NULL; + update_actions(); } diff --git a/gnome/src/config/accountlistconfigdialog.h b/gnome/src/config/accountlistconfigdialog.h index 40e58526dbaab07a3ad233e8ddebdb7640eb1fb5..bae376b6d92152cd13c6dc43fcb0dc3765a34cca 100644 --- a/gnome/src/config/accountlistconfigdialog.h +++ b/gnome/src/config/accountlistconfigdialog.h @@ -29,12 +29,12 @@ */ -#ifndef __SFL_ACCOUNTLISTDIALOG_H__ -#define __SFL_ACCOUNTLISTDIALOG_H__ +#ifndef ACCOUNTLISTDIALOG_H_ +#define ACCOUNTLISTDIALOG_H_ -#include <sflphone_const.h> +#include "accountlist.h" void show_account_list_config_dialog(void); -void account_list_config_dialog_fill(void); +void update_account_list_status_bar(account_t *account); -#endif +#endif // ACCOUNTLISTDIALOG_H_ diff --git a/gnome/src/dbus/configurationmanager-introspec.xml b/gnome/src/dbus/configurationmanager-introspec.xml index f22a7ead0c531f917e37e800d4c46fc56f2314da..a990a0be463994ea5c61a68778e615f23be1c61c 100644 --- a/gnome/src/dbus/configurationmanager-introspec.xml +++ b/gnome/src/dbus/configurationmanager-introspec.xml @@ -21,6 +21,7 @@ The available keys / parameters are: <ul> <li>CONFIG_ACCOUNT_ENABLE: True or False (Default: True)</li> + <li>CONFIG_ACCOUNT_RESOLVE_ONCE</li> <li>CONFIG_ACCOUNT_TYPE: SIP or IAX2 (Default: SIP)</li> <li>HOSTNAME: The IP adress or hostname of the registrar</li> <li>USERNAME: The username (or extension) of the account</li> @@ -446,6 +447,11 @@ <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> </signal> + <signal name="registrationStateChanged" tp:name-for-bindings="registrationStateChanged"> + <arg type="s" name="accountID"/> + <arg type="i" name="registration_state"/> + </signal> + <signal name="stunStatusFailure" tp:name-for_bindings="stunStatusFailure"> <arg type="s" name="reason"> </arg> diff --git a/gnome/src/dbus/dbus.c b/gnome/src/dbus/dbus.c index e68d4455913946ad8e25d0c6b42cac8a2b828a77..e2b184b3f30c67617441055784d3f8d8bc1de535 100644 --- a/gnome/src/dbus/dbus.c +++ b/gnome/src/dbus/dbus.c @@ -29,7 +29,10 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + #include <glib/gi18n.h> #include "str_utils.h" #include "logger.h" @@ -38,12 +41,12 @@ #include "configurationmanager-glue.h" #include "instance-glue.h" #include "preferencesdialog.h" -#include "accountlistconfigdialog.h" #include "mainwindow.h" #include "marshaller.h" #include "sliders.h" #include "statusicon.h" #include "assistant.h" +#include "accountlistconfigdialog.h" #include "dbus.h" #include "actions.h" @@ -422,12 +425,24 @@ record_playback_stopped_cb(DBusGProxy *proxy UNUSED, const gchar *filepath) update_actions(); } +static void +registration_state_changed_cb(DBusGProxy *proxy UNUSED, const gchar *accountID, + guint state, void *foo UNUSED) +{ + DEBUG("DBus: Registration state changed to %s for account %s", + account_state_name(state), accountID); + account_t *acc = account_list_get_by_id(accountID); + if (acc) { + acc->state = state; + update_account_list_status_bar(acc); + } +} + static void accounts_changed_cb(DBusGProxy *proxy UNUSED, void *foo UNUSED) { sflphone_fill_account_list(); sflphone_fill_ip2ip_profile(); - account_list_config_dialog_fill(); status_bar_display_account(); statusicon_set_tooltip(); } @@ -735,6 +750,11 @@ gboolean dbus_connect(GError **error) dbus_g_proxy_connect_signal(call_proxy, "voiceMailNotify", G_CALLBACK(voice_mail_cb), NULL, NULL); + dbus_g_proxy_add_signal(config_proxy, "registrationStateChanged", G_TYPE_STRING, + G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(config_proxy, "registrationStateChanged", + G_CALLBACK(registration_state_changed_cb), NULL, NULL); + dbus_g_proxy_add_signal(call_proxy, "incomingMessage", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal(call_proxy, "incomingMessage", @@ -1076,6 +1096,7 @@ dbus_remove_account(const gchar *accountID) { GError *error = NULL; org_sflphone_SFLphone_ConfigurationManager_remove_account(config_proxy, accountID, &error); + account_list_remove(accountID); check_error(error); } @@ -1093,10 +1114,10 @@ void dbus_add_account(account_t *a) { g_assert(a); + g_assert(a->accountID); g_assert(a->properties); - DEBUG("Adding %s account", a->accountID); - GError *error = NULL; g_free(a->accountID); + GError *error = NULL; a->accountID = NULL; org_sflphone_SFLphone_ConfigurationManager_add_account(config_proxy, a->properties, &a->accountID, &error); diff --git a/gnome/src/logger.h b/gnome/src/logger.h index a5020c822878f9d0c1bd58adbf3dec6cf30551b3..330503be82bd3be8a2dca855d7ee087498c5c431 100644 --- a/gnome/src/logger.h +++ b/gnome/src/logger.h @@ -28,8 +28,8 @@ * as that of the covered work. */ -#ifndef __LOGGER_H -#define __LOGGER_H +#ifndef LOGGER_H_ +#define LOGGER_H_ void internal_log (const int level, const char* format, ...); void set_log_level (const int level); @@ -44,7 +44,8 @@ void set_log_level (const int level); #define INFO(...) internal_log(LOG_INFO, __VA_ARGS__) #define DEBUG(...) internal_log(LOG_DEBUG, __VA_ARGS__) +/* Prints an error message and returns if the pointer A is NULL */ #define RETURN_IF_NULL(A, M, ...) \ - if ((A) == NULL) { ERROR(M, ##__VA_ARGS__); return; } + if (!(A)) { ERROR(M, ##__VA_ARGS__); return; } -#endif +#endif // LOGGER_H_ diff --git a/gnome/src/main.c b/gnome/src/main.c index 8590e276f6f648721bd0e316c65d7e34fd9c1a84..c6dc14ab2ea85938be3a701f0ff43a51790027a9 100644 --- a/gnome/src/main.c +++ b/gnome/src/main.c @@ -112,7 +112,6 @@ main(int argc, char *argv[]) set_minimized(TRUE); } - status_bar_display_account(); sflphone_fill_history(); diff --git a/gnome/src/uimanager.c b/gnome/src/uimanager.c index 25a45352eb320f218dae3bfb50d7b45990c07bce..b2b16d5d2ef0b42687a0e2d0130a300161348942 100644 --- a/gnome/src/uimanager.c +++ b/gnome/src/uimanager.c @@ -67,29 +67,33 @@ void show_edit_number(callable_obj_t *call); static GtkWidget *toolbar_; -static guint transferButtonConnId_; // The button toggled signal connection ID -static guint recordButtonConnId_; // The button toggled signal connection ID +// store the signal ID in case we need to +// intercept this signal +static guint transferButtonConnId_; +static guint recordButtonConnId_; static GtkAction * pickUpAction_; -static GtkWidget * pickUpWidget_; static GtkAction * newCallAction_; -static GtkWidget * newCallWidget_; static GtkAction * hangUpAction_; +static GtkAction * copyAction_; +static GtkAction * pasteAction_; +static GtkAction * recordAction_; +static GtkAction * muteAction_; +static GtkAction * voicemailAction_; +static GtkAction * imAction_; + +static GtkWidget * pickUpWidget_; +static GtkWidget * newCallWidget_; static GtkWidget * hangUpWidget_; static GtkWidget * holdMenu_; static GtkWidget * holdToolbar_; static GtkWidget * offHoldToolbar_; static GtkWidget * transferToolbar_; -static GtkAction * copyAction_; -static GtkAction * pasteAction_; -static GtkAction * recordAction_; -static GtkAction * muteAction_; static GtkWidget * recordWidget_; static GtkWidget * muteWidget_; -static GtkAction * voicemailAction_; static GtkWidget * voicemailToolbar_; static GtkWidget * imToolbar_; -static GtkAction * imAction_; + static GtkWidget * playRecordWidget_; static GtkWidget * stopRecordWidget_; @@ -130,69 +134,332 @@ call_mute(void) sflphone_mute_call(); } + +static void +update_toolbar_for_call(callable_obj_t *selectedCall, gboolean instant_messaging_enabled) { + int pos = 0; + + DEBUG("UIManager: Update actions for call %s", selectedCall->_callID); + + if(selectedCall == NULL) { + ERROR("Selected call is NULL while updating toolbar"); + return; + } + + // update icon in systray + show_status_hangup_icon(); + + gtk_action_set_sensitive(copyAction_, TRUE); + + switch (selectedCall->_state) { + case CALL_STATE_INCOMING: + { + DEBUG("UIManager: Call State Incoming"); + // Make the button toolbar clickable + gtk_action_set_sensitive(pickUpAction_, TRUE); + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_action_set_sensitive(muteAction_, TRUE); + // Replace the dial button with the hangup button + g_object_ref(newCallWidget_); + remove_from_toolbar(newCallWidget_); + pos = 0; + add_to_toolbar(toolbar_, pickUpWidget_, pos++); + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, muteWidget_, pos++); + break; + } + case CALL_STATE_HOLD: + { + DEBUG("UIManager: Call State Hold"); + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_widget_set_sensitive(holdMenu_, TRUE); + gtk_widget_set_sensitive(offHoldToolbar_, TRUE); + gtk_widget_set_sensitive(newCallWidget_, TRUE); + + // Replace the hold button with the off-hold button + pos = 1; + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, offHoldToolbar_, pos++); + + if (instant_messaging_enabled) { + gtk_action_set_sensitive(imAction_, TRUE); + add_to_toolbar(toolbar_, imToolbar_, pos++); + } + + break; + } + case CALL_STATE_RINGING: + { + DEBUG("UIManager: Call State Ringing"); + gtk_action_set_sensitive(pickUpAction_, TRUE); + gtk_action_set_sensitive(hangUpAction_, TRUE); + pos = 1; + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, muteWidget_, pos++); + break; + } + case CALL_STATE_DIALING: + { + DEBUG("UIManager: Call State Dialing"); + gtk_action_set_sensitive(pickUpAction_, TRUE); + + if (active_calltree_tab == current_calls_tab) + gtk_action_set_sensitive(hangUpAction_, TRUE); + + g_object_ref(newCallWidget_); + remove_from_toolbar(newCallWidget_); + pos = 0; + add_to_toolbar(toolbar_, pickUpWidget_, pos++); + + if (active_calltree_tab == current_calls_tab) + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + else if (active_calltree_tab == history_tab) { + if (is_non_empty(selectedCall->_recordfile)) { + if (selectedCall->_record_is_playing) + add_to_toolbar(toolbar_, stopRecordWidget_, pos++); + else + add_to_toolbar(toolbar_, playRecordWidget_, pos++); + } + } + break; + } + case CALL_STATE_CURRENT: + { + DEBUG("UIManager: Call State Current"); + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_action_set_sensitive(recordAction_, TRUE); + gtk_action_set_sensitive(muteAction_, TRUE); + gtk_widget_set_sensitive(holdMenu_, TRUE); + gtk_widget_set_sensitive(holdToolbar_, TRUE); + gtk_widget_set_sensitive(transferToolbar_, TRUE); + gtk_widget_set_sensitive(muteWidget_, TRUE); + if (instant_messaging_enabled) + gtk_action_set_sensitive(imAction_, TRUE); + + pos = 1; + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, holdToolbar_, pos++); + add_to_toolbar(toolbar_, transferToolbar_, pos++); + add_to_toolbar(toolbar_, recordWidget_, pos++); + add_to_toolbar(toolbar_, muteWidget_, pos++); + if (instant_messaging_enabled) { + add_to_toolbar(toolbar_, imToolbar_, pos++); + + g_signal_handler_block(transferToolbar_, transferButtonConnId_); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), FALSE); + g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); + g_signal_handler_block(recordWidget_, recordButtonConnId_); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(recordWidget_), FALSE); + g_signal_handler_unblock(recordWidget_, recordButtonConnId_); + break; + } + + case CALL_STATE_RECORD: + { + DEBUG("UIManager: Call State Record"); + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_action_set_sensitive(recordAction_, TRUE); + gtk_action_set_sensitive(muteAction_, TRUE); + gtk_widget_set_sensitive(holdMenu_, TRUE); + gtk_widget_set_sensitive(holdToolbar_, TRUE); + gtk_widget_set_sensitive(transferToolbar_, TRUE); + gtk_widget_set_sensitive(muteWidget_, TRUE); + if (instant_messaging_enabled) + gtk_action_set_sensitive(imAction_, TRUE); + + pos = 1; + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, holdToolbar_, pos++); + add_to_toolbar(toolbar_, transferToolbar_, pos++); + add_to_toolbar(toolbar_, recordWidget_, pos++); + add_to_toolbar(toolbar_, muteWidget_, pos++); + if (instant_messaging_enabled) + add_to_toolbar(toolbar_, imToolbar_, pos++); + + g_signal_handler_block(transferToolbar_, transferButtonConnId_); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), FALSE); + g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); + g_signal_handler_block(recordWidget_, recordButtonConnId_); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(recordWidget_), TRUE); + g_signal_handler_unblock(recordWidget_, recordButtonConnId_); + break; + } + case CALL_STATE_BUSY: + case CALL_STATE_FAILURE: + { + pos = 1; + DEBUG("UIManager: Call State Busy/Failure"); + gtk_action_set_sensitive(hangUpAction_, TRUE); + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + break; + } + case CALL_STATE_TRANSFER: + { + pos = 1; + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_action_set_sensitive(muteAction_, TRUE); + gtk_widget_set_sensitive(holdMenu_, TRUE); + gtk_widget_set_sensitive(holdToolbar_, TRUE); + gtk_widget_set_sensitive(transferToolbar_, TRUE); + gtk_widget_set_sensitive(transferToolbar_, TRUE); + gtk_widget_set_sensitive(muteWidget_, TRUE); + + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, transferToolbar_, pos++); + g_signal_handler_block(transferToolbar_, transferButtonConnId_); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), TRUE); + g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); + add_to_toolbar(toolbar_, muteWidget_, pos++); + break; + } + default: + ERROR("UIMAnager: Error: Unknown state in action update!"); + break; + } + } +} + +static void +update_toolbar_for_conference(conference_obj_t * selectedConf, gboolean instant_messaging_enabled) { + int pos = 0; + + DEBUG("UIManager: Update actions for conference"); + + // update icon in systray + show_status_hangup_icon(); + + switch (selectedConf->_state) { + + case CONFERENCE_STATE_ACTIVE_ATTACHED: + case CONFERENCE_STATE_ACTIVE_DETACHED: + DEBUG("UIManager: Conference State Active"); + + if (active_calltree_tab == current_calls_tab) { + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_widget_set_sensitive(holdToolbar_, TRUE); + gtk_action_set_sensitive(recordAction_, TRUE); + pos = 1; + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, holdToolbar_, pos++); + add_to_toolbar(toolbar_, recordWidget_, pos++); + + if (instant_messaging_enabled) { + gtk_action_set_sensitive(imAction_, TRUE); + add_to_toolbar(toolbar_, imToolbar_, pos); + } + } else if (active_calltree_tab == history_tab) { + if (is_non_empty(selectedConf->_recordfile)) { + pos = 2; + if (selectedConf->_record_is_playing) + add_to_toolbar(toolbar_, stopRecordWidget_, pos); + else + add_to_toolbar(toolbar_, playRecordWidget_, pos); + } + } + + break; + case CONFERENCE_STATE_ACTIVE_ATTACHED_RECORD: + case CONFERENCE_STATE_ACTIVE_DETACHED_RECORD: { + pos = 1; + DEBUG("UIManager: Conference State Record"); + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_widget_set_sensitive(holdToolbar_, TRUE); + gtk_action_set_sensitive(recordAction_, TRUE); + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, holdToolbar_, pos++); + add_to_toolbar(toolbar_, recordWidget_, pos++); + + if (instant_messaging_enabled) { + gtk_action_set_sensitive(imAction_, TRUE); + add_to_toolbar(toolbar_, imToolbar_, pos); + } + + break; + } + case CONFERENCE_STATE_HOLD: + case CONFERENCE_STATE_HOLD_RECORD: { + DEBUG("UIManager: Conference State Hold"); + pos = 1; + gtk_action_set_sensitive(hangUpAction_, TRUE); + gtk_widget_set_sensitive(offHoldToolbar_, TRUE); + gtk_action_set_sensitive(recordAction_, TRUE); + add_to_toolbar(toolbar_, hangUpWidget_, pos++); + add_to_toolbar(toolbar_, offHoldToolbar_, pos++); + add_to_toolbar(toolbar_, recordWidget_, pos++); + + if (instant_messaging_enabled) { + gtk_action_set_sensitive(imAction_, TRUE); + add_to_toolbar(toolbar_, imToolbar_, pos); + } + + break; + } + default: + WARN("UIManager: Error: Should not happen in action update!"); + break; + } + +} + void update_actions() { - int pos = 0; - gtk_action_set_sensitive(newCallAction_, TRUE); gtk_action_set_sensitive(pickUpAction_, FALSE); gtk_action_set_sensitive(hangUpAction_, FALSE); + gtk_action_set_sensitive(recordAction_, FALSE); + gtk_action_set_sensitive(muteAction_, FALSE); + gtk_action_set_sensitive(copyAction_, FALSE); gtk_action_set_sensitive(imAction_, FALSE); + gtk_widget_set_sensitive(holdMenu_, FALSE); + gtk_widget_set_sensitive(holdToolbar_, FALSE); + gtk_widget_set_sensitive(offHoldToolbar_, FALSE); + gtk_widget_set_sensitive(recordWidget_, FALSE); + gtk_widget_set_sensitive(muteWidget_, FALSE); + gtk_widget_set_sensitive(historyButton_, FALSE); + + // Increment the reference counter g_object_ref(hangUpWidget_); g_object_ref(recordWidget_); g_object_ref(muteWidget_); g_object_ref(holdToolbar_); g_object_ref(offHoldToolbar_); - - if (addrbook) - g_object_ref(contactButton_); - g_object_ref(historyButton_); g_object_ref(transferToolbar_); g_object_ref(voicemailToolbar_); g_object_ref(imToolbar_); + if (addrbook) + g_object_ref(contactButton_); + + // Make sure the toolbar is reinitialized + // Widget will be added according to the state + // of the selected call remove_from_toolbar(hangUpWidget_); remove_from_toolbar(recordWidget_); remove_from_toolbar(muteWidget_); remove_from_toolbar(transferToolbar_); remove_from_toolbar(historyButton_); - - if (addrbook) - remove_from_toolbar(contactButton_); - remove_from_toolbar(voicemailToolbar_); remove_from_toolbar(imToolbar_); - - gtk_widget_set_sensitive(holdMenu_, FALSE); - gtk_widget_set_sensitive(holdToolbar_, FALSE); - gtk_widget_set_sensitive(offHoldToolbar_, FALSE); - gtk_action_set_sensitive(recordAction_, FALSE); - gtk_action_set_sensitive(muteAction_, FALSE); - gtk_widget_set_sensitive(recordWidget_, FALSE); - gtk_widget_set_sensitive(muteWidget_, FALSE); - gtk_action_set_sensitive(copyAction_, FALSE); - - if (addrbook) - gtk_widget_set_sensitive(contactButton_, FALSE); - - gtk_widget_set_sensitive(historyButton_, FALSE); - - if (addrbook) - gtk_widget_set_tooltip_text(contactButton_, _("No address book selected")); - remove_from_toolbar(holdToolbar_); remove_from_toolbar(offHoldToolbar_); remove_from_toolbar(newCallWidget_); remove_from_toolbar(pickUpWidget_); - - add_to_toolbar(toolbar_, newCallWidget_, 0); - remove_from_toolbar(playRecordWidget_); remove_from_toolbar(stopRecordWidget_); + if (addrbook) { + remove_from_toolbar(contactButton_); + gtk_widget_set_sensitive(contactButton_, FALSE); + gtk_widget_set_tooltip_text(contactButton_, _("No address book selected")); + } + + // New call widget always present + add_to_toolbar(toolbar_, newCallWidget_, 0); + + // Add the history button and set it to sensitive if enabled if (eel_gconf_get_integer(HISTORY_ENABLED)) { add_to_toolbar(toolbar_, historyButton_, -1); gtk_widget_set_sensitive(historyButton_, TRUE); @@ -200,9 +467,7 @@ update_actions() GtkToolItem *separator = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar_), separator, -1); - // add mute button - add_to_toolbar(toolbar_, muteWidget_, -1); - gtk_action_set_sensitive(muteAction_, TRUE); + // If addressbook support has been enabled and all addressbooks are loaded, display the icon if (addrbook && addrbook->is_ready() && addressbook_config_load_parameters()->enable) { @@ -224,242 +489,9 @@ update_actions() instant_messaging_enabled = eel_gconf_get_integer(INSTANT_MESSAGING_ENABLED); if (selectedCall) { - DEBUG("UIManager: Update actions for call %s", selectedCall->_callID); - - // update icon in systray - show_status_hangup_icon(); - - gtk_action_set_sensitive(copyAction_, TRUE); - - switch (selectedCall->_state) { - case CALL_STATE_INCOMING: - { - DEBUG("UIManager: Call State Incoming"); - // Make the button toolbar clickable - gtk_action_set_sensitive(pickUpAction_, TRUE); - gtk_action_set_sensitive(hangUpAction_, TRUE); - // Replace the dial button with the hangup button - g_object_ref(newCallWidget_); - remove_from_toolbar(newCallWidget_); - pos = 0; - add_to_toolbar(toolbar_, pickUpWidget_, pos++); - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - break; - } - case CALL_STATE_HOLD: - { - DEBUG("UIManager: Call State Hold"); - gtk_action_set_sensitive(hangUpAction_, TRUE); - gtk_widget_set_sensitive(holdMenu_, TRUE); - gtk_widget_set_sensitive(offHoldToolbar_, TRUE); - gtk_widget_set_sensitive(newCallWidget_, TRUE); - - // Replace the hold button with the off-hold button - pos = 1; - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - add_to_toolbar(toolbar_, offHoldToolbar_, pos++); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos++); - } - - break; - } - case CALL_STATE_RINGING: - { - DEBUG("UIManager: Call State Ringing"); - gtk_action_set_sensitive(pickUpAction_, TRUE); - gtk_action_set_sensitive(hangUpAction_, TRUE); - pos = 1; - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - break; - } - case CALL_STATE_DIALING: - { - DEBUG("UIManager: Call State Dialing"); - gtk_action_set_sensitive(pickUpAction_, TRUE); - - if (active_calltree_tab == current_calls_tab) - gtk_action_set_sensitive(hangUpAction_, TRUE); - - g_object_ref(newCallWidget_); - remove_from_toolbar(newCallWidget_); - pos = 0; - add_to_toolbar(toolbar_, pickUpWidget_, pos++); - - if (active_calltree_tab == current_calls_tab) - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - else if (active_calltree_tab == history_tab) { - if (is_non_empty(selectedCall->_recordfile)) { - if (selectedCall->_record_is_playing) - add_to_toolbar(toolbar_, stopRecordWidget_, pos++); - else - add_to_toolbar(toolbar_, playRecordWidget_, pos++); - } - } - break; - } - case CALL_STATE_CURRENT: - { - DEBUG("UIManager: Call State Current"); - gtk_action_set_sensitive(hangUpAction_, TRUE); - pos = 1; - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - gtk_widget_set_sensitive(holdMenu_, TRUE); - gtk_widget_set_sensitive(holdToolbar_, TRUE); - gtk_widget_set_sensitive(transferToolbar_, TRUE); - gtk_action_set_sensitive(recordAction_, TRUE); - add_to_toolbar(toolbar_, holdToolbar_, pos++); - add_to_toolbar(toolbar_, transferToolbar_, pos++); - add_to_toolbar(toolbar_, recordWidget_, pos++); - g_signal_handler_block(transferToolbar_, transferButtonConnId_); - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), FALSE); - g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); - g_signal_handler_block(recordWidget_, recordButtonConnId_); - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(recordWidget_), FALSE); - g_signal_handler_unblock(recordWidget_, recordButtonConnId_); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos++); - } - - break; - } - - case CALL_STATE_RECORD: - { - DEBUG("UIManager: Call State Record"); - pos = 1; - gtk_action_set_sensitive(hangUpAction_, TRUE); - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - gtk_widget_set_sensitive(holdMenu_, TRUE); - gtk_widget_set_sensitive(holdToolbar_, TRUE); - gtk_widget_set_sensitive(transferToolbar_, TRUE); - gtk_action_set_sensitive(recordAction_, TRUE); - add_to_toolbar(toolbar_, holdToolbar_, pos++); - add_to_toolbar(toolbar_, transferToolbar_, pos++); - add_to_toolbar(toolbar_, recordWidget_, pos++); - g_signal_handler_block(transferToolbar_, transferButtonConnId_); - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), FALSE); - g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); - g_signal_handler_block(recordWidget_, recordButtonConnId_); - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(recordWidget_), TRUE); - g_signal_handler_unblock(recordWidget_, recordButtonConnId_); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos++); - } - - break; - } - case CALL_STATE_BUSY: - case CALL_STATE_FAILURE: - { - pos = 1; - DEBUG("UIManager: Call State Busy/Failure"); - gtk_action_set_sensitive(hangUpAction_, TRUE); - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - break; - } - case CALL_STATE_TRANSFER: - { - pos = 1; - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - add_to_toolbar(toolbar_, transferToolbar_, pos++); - g_signal_handler_block(transferToolbar_, transferButtonConnId_); - gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(transferToolbar_), TRUE); - g_signal_handler_unblock(transferToolbar_, transferButtonConnId_); - gtk_action_set_sensitive(hangUpAction_, TRUE); - gtk_widget_set_sensitive(holdMenu_, TRUE); - gtk_widget_set_sensitive(holdToolbar_, TRUE); - gtk_widget_set_sensitive(transferToolbar_, TRUE); - break; - } - default: - ERROR("UIMAnager: Error: Unknown state in action update!"); - break; - } - + update_toolbar_for_call(selectedCall, instant_messaging_enabled); } else if (selectedConf) { - - DEBUG("UIManager: Update actions for conference"); - - // update icon in systray - show_status_hangup_icon(); - - switch (selectedConf->_state) { - - case CONFERENCE_STATE_ACTIVE_ATTACHED: - case CONFERENCE_STATE_ACTIVE_DETACHED: - DEBUG("UIManager: Conference State Active"); - - if (active_calltree_tab == current_calls_tab) { - gtk_action_set_sensitive(hangUpAction_, TRUE); - gtk_widget_set_sensitive(holdToolbar_, TRUE); - gtk_action_set_sensitive(recordAction_, TRUE); - pos = 1; - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - add_to_toolbar(toolbar_, holdToolbar_, pos++); - add_to_toolbar(toolbar_, recordWidget_, pos++); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos); - } - } else if (active_calltree_tab == history_tab) { - if (is_non_empty(selectedConf->_recordfile)) { - pos = 2; - if (selectedConf->_record_is_playing) - add_to_toolbar(toolbar_, stopRecordWidget_, pos); - else - add_to_toolbar(toolbar_, playRecordWidget_, pos); - } - } - - break; - case CONFERENCE_STATE_ACTIVE_ATTACHED_RECORD: - case CONFERENCE_STATE_ACTIVE_DETACHED_RECORD: { - pos = 1; - DEBUG("UIManager: Conference State Record"); - gtk_action_set_sensitive(hangUpAction_, TRUE); - gtk_widget_set_sensitive(holdToolbar_, TRUE); - gtk_action_set_sensitive(recordAction_, TRUE); - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - add_to_toolbar(toolbar_, holdToolbar_, pos++); - add_to_toolbar(toolbar_, recordWidget_, pos++); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos); - } - - break; - } - case CONFERENCE_STATE_HOLD: - case CONFERENCE_STATE_HOLD_RECORD: { - DEBUG("UIManager: Conference State Hold"); - pos = 1; - gtk_action_set_sensitive(hangUpAction_, TRUE); - gtk_widget_set_sensitive(offHoldToolbar_, TRUE); - gtk_action_set_sensitive(recordAction_, TRUE); - add_to_toolbar(toolbar_, hangUpWidget_, pos++); - add_to_toolbar(toolbar_, offHoldToolbar_, pos++); - add_to_toolbar(toolbar_, recordWidget_, pos++); - - if (instant_messaging_enabled) { - gtk_action_set_sensitive(imAction_, TRUE); - add_to_toolbar(toolbar_, imToolbar_, pos); - } - - break; - } - default: - WARN("UIManager: Error: Should not happen in action update!"); - break; - } + update_toolbar_for_conference(selectedConf, instant_messaging_enabled); } else { // update icon in systray hide_status_hangup_icon(); @@ -554,7 +586,7 @@ help_about(void * foo UNUSED) "artists", artists, "authors", authors, "comments", _("SFLphone is a VoIP client compatible with SIP and IAX2 protocols."), - "copyright", "Copyright © 2004-2011 Savoir-faire Linux Inc.", + "copyright", "Copyright © 2004-2012 Savoir-faire Linux Inc.", "name", PACKAGE, "title", _("About SFLphone"), "version", VERSION,