Skip to content
Snippets Groups Projects
sipvoiplink.cpp 43.9 KiB
Newer Older
llea's avatar
llea committed
/**
 *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
yanmorin's avatar
 
yanmorin committed
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
llea's avatar
llea committed
 *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *                                                                              
 *  Portions Copyright (C) 2002,2003   Aymeric Moizard <jack@atosc.org>
 *
llea's avatar
llea committed
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *                                                                              
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *                                                                              
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
yanmorin's avatar
 
yanmorin committed
#include <eXosip2/eXosip.h>
llea's avatar
llea committed
#include <osip2/osip.h>

llea's avatar
llea committed
#include "sipvoiplink.h"
yanmorin's avatar
 
yanmorin committed
#include "global.h"
jpbl's avatar
jpbl committed
#include "audio/codecDescriptor.h"
llea's avatar
llea committed
#include "manager.h"
#include "sipcall.h"
#include "user_cfg.h"
yanmorin's avatar
 
yanmorin committed
#include "eventthread.h"

llea's avatar
llea committed
#define DEFAULT_SIP_PORT	5060
#define RANDOM_SIP_PORT		rand() % 64000 + 1024
#define	DEFAULT_LOCAL_PORT	10500
#define	RANDOM_LOCAL_PORT	((rand() % 27250) + 5250)*2

#define VOICE_MSG			"Voice-Message"
#define LENGTH_VOICE_MSG	15
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
SipVoIPLink::SipVoIPLink() : VoIPLink()
llea's avatar
llea committed
{
yanmorin's avatar
 
yanmorin committed
  // default _audioRTP object initialization
  _evThread = new EventThread(this);
jpbl's avatar
jpbl committed
  _localPort = 0;
  _nMsgVoicemail = 0;
yanmorin's avatar
 
yanmorin committed
  _reg_id = -1;
  // defautlt _sipcallVector object initialization
yanmorin's avatar
 
yanmorin committed

  _registrationSend = false;
yanmorin's avatar
 
yanmorin committed
  _started = false;
llea's avatar
llea committed
}

yanmorin's avatar
 
yanmorin committed
SipVoIPLink::~SipVoIPLink(void) {
yanmorin's avatar
 
yanmorin committed
  endSipCalls();
yanmorin's avatar
 
yanmorin committed
  delete _evThread; _evThread = NULL;
yanmorin's avatar
 
yanmorin committed
  if (_started) {
    eXosip_quit();
  }
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed
// for voIPLink interface
yanmorin's avatar
 
yanmorin committed
void
SipVoIPLink::terminate(void) 
{
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed
bool
SipVoIPLink::checkNetwork (void)
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  // Set IP address
yanmorin's avatar
 
yanmorin committed
  return getSipLocalIp();
llea's avatar
llea committed
}

yanmorin's avatar
 
yanmorin committed
bool
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::init(void)
llea's avatar
llea committed
{
yanmorin's avatar
 
yanmorin committed
  if (0 != eXosip_init()) {
jpbl's avatar
jpbl committed
    _debug("Could not initialize eXosip\n");
yanmorin's avatar
 
yanmorin committed
    return false;
jpbl's avatar
jpbl committed
  }
yanmorin's avatar
 
yanmorin committed
  _started = true;

jpbl's avatar
jpbl committed
  srand (time(NULL));
yanmorin's avatar
yanmorin committed
  // second parameter, NULL is "::" for ipv6 and "0.0.0.0" for ipv4, we can put INADDR_ANY
yanmorin's avatar
 
yanmorin committed
  int i;
yanmorin's avatar
yanmorin committed
  i = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, DEFAULT_SIP_PORT, AF_INET, 0);
jpbl's avatar
jpbl committed
  if (i != 0) {
yanmorin's avatar
yanmorin committed
    i = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, RANDOM_SIP_PORT, AF_INET, 0);
jpbl's avatar
jpbl committed
    if (i != 0) {
      _debug("Could not initialize transport layer\n");
yanmorin's avatar
 
yanmorin committed
      return false;
yanmorin's avatar
 
yanmorin committed
    } else {
      _debug("VoIP Link listen on random port %d\n", RANDOM_SIP_PORT);
jpbl's avatar
jpbl committed
    }
yanmorin's avatar
 
yanmorin committed
  } else {
   _debug("VoIP Link listen on port %d\n", DEFAULT_SIP_PORT);
jpbl's avatar
jpbl committed
  }
yanmorin's avatar
 
yanmorin committed
  // Set user agent
yanmorin's avatar
 
yanmorin committed
  std::string tmp = std::string(PROGNAME_GLOBAL) + "/" + std::string(SFLPHONED_VERSION);
yanmorin's avatar
 
yanmorin committed
  eXosip_set_user_agent(tmp.data());

jpbl's avatar
jpbl committed
  // If use STUN server, firewall address setup
  if (Manager::instance().useStun()) {
    if (behindNat() != 1) {
yanmorin's avatar
 
yanmorin committed
      return false;
jpbl's avatar
jpbl committed
    }
yanmorin's avatar
 
yanmorin committed
    // This method is used to replace contact address with the public address of your NAT
yanmorin's avatar
 
yanmorin committed
    eXosip_masquerade_contact((Manager::instance().getFirewallAddress()).data(), Manager::instance().getFirewallPort());
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  if ( !checkNetwork() ) {
    return false;
  }
yanmorin's avatar
 
yanmorin committed
  _debug("SIP VoIP Link: listen to SIP Events\n");
jpbl's avatar
jpbl committed
  _evThread->start();
yanmorin's avatar
 
yanmorin committed
  return true;
yanmorin's avatar
 
yanmorin committed
/**
 * Subscibe to message-summary notify
 * It allows eXosip to not send ' 481 Subcription Does Not Exist ' response
 */
void
SipVoIPLink::subscribeMessageSummary()
{
  osip_message_t *subscribe;
  const char *route= NULL;

  // from/to
  ManagerImpl& manager = Manager::instance();
  std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART));

  // to
  std::string to;
  to = manager.getConfigString(SIGNALISATION, PROXY);
  if (!to.empty()) {
    to = toHeader(manager.getConfigString(SIGNALISATION, USER_PART)) + "@" + to;
  } else {
    to = from;
  }
  

  // like in http://www.faqs.org/rfcs/rfc3842.html
  const char *event="message-summary";
  int expires = 86400;

  // return 0 if no error
  // the first from is the to... but we send the same
yanmorin's avatar
 
yanmorin committed
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  int error = eXosip_subscribe_build_initial_request(&subscribe, to.c_str(), from.c_str(), route, event, expires);
yanmorin's avatar
 
yanmorin committed
  eXosip_unlock();
yanmorin's avatar
 
yanmorin committed

  if (error == 0) {
    // Accept: application/simple-message-summary
    osip_message_set_header (subscribe, "Accept", "application/simple-message-summary");

    _debug("Sending Message-summary subscription");
    // return 0 if ok
yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    error = eXosip_subscribe_send_initial_request (subscribe);
    eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
    _debug(" and return %d\n", error);
yanmorin's avatar
 
yanmorin committed
  }
}

llea's avatar
llea committed
bool
SipVoIPLink::isInRtpmap (int index, int payload, CodecDescriptorVector* cdv) {
jpbl's avatar
jpbl committed
  for (int i = 0; i < index; i++) {
    if (cdv->at(i)->getPayload() == payload) {
      return true;
llea's avatar
llea committed
    }
jpbl's avatar
jpbl committed
  }
  return false;
llea's avatar
llea committed
}

int
SipVoIPLink::setRegister (void) 
{
yanmorin's avatar
 
yanmorin committed
  ManagerImpl& manager = Manager::instance();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  if (_reg_id != -1) {
    manager.displayError("Registration already sent. Try to unregister");
    return -1;
  }

yanmorin's avatar
 
yanmorin committed
  // all this will be inside the profil associate with the voip link
yanmorin's avatar
 
yanmorin committed
  std::string proxy = "sip:" + manager.getConfigString(SIGNALISATION, PROXY);
  std::string hostname = "sip:" + manager.getConfigString(SIGNALISATION, HOST_PART);
  std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART));
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  if (manager.getConfigString(SIGNALISATION, HOST_PART).empty()) {
yanmorin's avatar
 
yanmorin committed
    manager.displayConfigError("Fill host part field");
jpbl's avatar
jpbl committed
    return -1;
  }
yanmorin's avatar
 
yanmorin committed
  if (manager.getConfigString(SIGNALISATION, USER_PART).empty()) {
yanmorin's avatar
 
yanmorin committed
    manager.displayConfigError("Fill user part field");
jpbl's avatar
jpbl committed
    return -1;
  }
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  _debug("REGISTER From: %s\n", from.data());
yanmorin's avatar
 
yanmorin committed
  osip_message_t *reg = NULL;
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  if (!manager.getConfigString(SIGNALISATION, PROXY).empty()) {
jpbl's avatar
jpbl committed
    _reg_id = eXosip_register_build_initial_register ((char*)from.data(), 
						      (char*)proxy.data(), NULL, EXPIRES_VALUE, &reg);
  } else {
    _reg_id = eXosip_register_build_initial_register ((char*)from.data(), 
						      (char*)hostname.data(), NULL, EXPIRES_VALUE, &reg);
  }
yanmorin's avatar
 
yanmorin committed
  eXosip_unlock();
jpbl's avatar
jpbl committed
  if (_reg_id < 0) {
    return -1;
yanmorin's avatar
 
yanmorin committed
  }

  if (setAuthentication() == -1) {
    _debug("No authentication\n");
    return -1;
  }
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
  osip_message_set_header (reg, "Event", "Registration");
  osip_message_set_header (reg, "Allow-Events", "presence");

yanmorin's avatar
 
yanmorin committed
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  int i = eXosip_register_send_register (_reg_id, reg);
jpbl's avatar
jpbl committed
  if (i == -2) {
yanmorin's avatar
 
yanmorin committed
    _debug("Cannot build registration, check the setup\n"); 
jpbl's avatar
jpbl committed
    eXosip_unlock();
    return -1;
  }
  if (i == -1) {
yanmorin's avatar
 
yanmorin committed
    _debug("Registration sending failed\n");
jpbl's avatar
jpbl committed
    eXosip_unlock();
    return -1;
  }
  eXosip_unlock();
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  // subscribe to message one time?
yanmorin's avatar
 
yanmorin committed
  // subscribeMessageSummary();
  _registrationSend = true;
jpbl's avatar
jpbl committed
  return i;
llea's avatar
llea committed
}
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
/**
 * setUnregister 
 * unregister if we already send the first registration
 * @return -1 if there is an error
 */
llea's avatar
llea committed
int 
SipVoIPLink::setUnregister (void)
{
yanmorin's avatar
 
yanmorin committed
  if ( _registrationSend ) {
    int i = 0;
    osip_message_t *reg = NULL;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    if (_reg_id > 0) {
      i = eXosip_register_build_register (_reg_id, 0, &reg);
    }
yanmorin's avatar
 
yanmorin committed
    eXosip_unlock();
    if (i < 0) {
yanmorin's avatar
 
yanmorin committed
      return -1;
yanmorin's avatar
 
yanmorin committed
    }

    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    _debug("< Sending REGISTER (expire=0)\n");
yanmorin's avatar
 
yanmorin committed
    i = eXosip_register_send_register (_reg_id, reg);
    if (i == -2) {
yanmorin's avatar
 
yanmorin committed
      _debug("  Cannot build registration (unregister), check the setup\n"); 
yanmorin's avatar
 
yanmorin committed
      eXosip_unlock();
      return -1;
    }
    if (i == -1) {
yanmorin's avatar
 
yanmorin committed
      _debug("  Registration (unregister) Failed\n");
yanmorin's avatar
 
yanmorin committed
    }
jpbl's avatar
jpbl committed
    eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
    _reg_id = -1;
yanmorin's avatar
 
yanmorin committed
    return i;
  } else {
    // no registration send before
jpbl's avatar
jpbl committed
    return -1;
  }
llea's avatar
llea committed
}

llea's avatar
llea committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::outgoingInvite (CALLID id, const std::string& to_url) 
llea's avatar
llea committed
{
yanmorin's avatar
 
yanmorin committed
  bool has_ip = checkNetwork();
yanmorin's avatar
 
yanmorin committed
  std::string from;
  std::string to;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  // TODO: should be inside account settings
  ManagerImpl& manager = Manager::instance();
jpbl's avatar
jpbl committed
  // Form the From header field basis on configuration panel
yanmorin's avatar
 
yanmorin committed
  std::string host = manager.getConfigString(SIGNALISATION, HOST_PART);
yanmorin's avatar
 
yanmorin committed
  std::string hostFrom = host;
  if ( hostFrom.empty() ) {
    hostFrom = getLocalIpAddress();
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), hostFrom);
llea's avatar
llea committed
	
jpbl's avatar
jpbl committed
  to = toHeader(to_url);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  if (to.find("@") == std::string::npos and 
yanmorin's avatar
 
yanmorin committed
      manager.getConfigInt(SIGNALISATION, AUTO_REGISTER)) {
yanmorin's avatar
 
yanmorin committed
    if(!host.empty()) {
      to = to + "@" + manager.getConfigString(SIGNALISATION, HOST_PART);
    }
jpbl's avatar
jpbl committed
  }
llea's avatar
llea committed
		
yanmorin's avatar
 
yanmorin committed
  _debug("            From: %s\n", from.data());
  _debug("            To: %s\n", to.data());
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
  if (manager.getConfigString(SIGNALISATION, PROXY).empty()) {
jpbl's avatar
jpbl committed
    // If no SIP proxy setting for direct call with only IP address
yanmorin's avatar
 
yanmorin committed
    if (has_ip) {
jpbl's avatar
jpbl committed
      if (startCall(id, from, to, "", "") <= 0) {
yanmorin's avatar
 
yanmorin committed
    	 _debug("Warning SipVoIPLink: call not started\n");
	     return -1;
jpbl's avatar
jpbl committed
      }
    } else {
yanmorin's avatar
 
yanmorin committed
      manager.displayErrorText(id, "No network found\n");
jpbl's avatar
jpbl committed
      return -1;
    }
    return 0;
  } else {
    // If SIP proxy setting
yanmorin's avatar
 
yanmorin committed
    std::string route = "<sip:" + 
yanmorin's avatar
 
yanmorin committed
      manager.getConfigString(SIGNALISATION, PROXY) + ";lr>";
yanmorin's avatar
 
yanmorin committed
    if (has_ip) {
jpbl's avatar
jpbl committed
      if (startCall(id, from, to, "", route) <= 0) {
yanmorin's avatar
 
yanmorin committed
	     _debug("Warning SipVoIPLink: call not started\n");
	     return -1;
jpbl's avatar
jpbl committed
      }
    } else {
yanmorin's avatar
 
yanmorin committed
      manager.displayErrorText(id, "No network found\n");
jpbl's avatar
jpbl committed
      return -1;
    }
    return 0;
  }
yanmorin's avatar
 
yanmorin committed
/**
 * @return 0 is good, -1 is bad
 */
llea's avatar
llea committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::answer (CALLID id) 
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  int i;
  int port;
  char tmpbuf[64];
  bzero (tmpbuf, 64);
  // Get  port   
  snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort());
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Answer call [cid = %d, did = %d]\n", id, getSipCall(id)->getCid(), getSipCall(id)->getDid());
jpbl's avatar
jpbl committed
  port = getSipCall(id)->getLocalAudioPort();
yanmorin's avatar
 
yanmorin committed
  _debug("            Local audio port: %d\n", port);
yanmorin's avatar
 
yanmorin committed

  osip_message_t *answerMessage = NULL;
jpbl's avatar
jpbl committed
  SipCall* ca = getSipCall(id);

  // Send 180 RINGING
yanmorin's avatar
 
yanmorin committed
  _debug("< Send 180 Ringing\n");
jpbl's avatar
jpbl committed
  eXosip_lock ();
  eXosip_call_send_answer (ca->getTid(), RINGING, NULL);
  eXosip_unlock ();

  // Send 200 OK
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  i = eXosip_call_build_answer (ca->getTid(), OK, &answerMessage);
jpbl's avatar
jpbl committed
  if (i != 0) {
yanmorin's avatar
 
yanmorin committed
   _debug("< Send 400 Bad Request\n");
jpbl's avatar
jpbl committed
    eXosip_call_send_answer (ca->getTid(), BAD_REQ, NULL);
  } else {
yanmorin's avatar
 
yanmorin committed
    // use exosip, bug locked
yanmorin's avatar
 
yanmorin committed
    i = sdp_complete_200ok (ca->getDid(), answerMessage, port);
jpbl's avatar
jpbl committed
    if (i != 0) {
yanmorin's avatar
 
yanmorin committed
      osip_message_free (answerMessage);
yanmorin's avatar
 
yanmorin committed
      _debug("< Send 415 Unsupported Media Type\n");
jpbl's avatar
jpbl committed
      eXosip_call_send_answer (ca->getTid(), UNSUP_MEDIA_TYPE, NULL);
    } else {
yanmorin's avatar
 
yanmorin committed
      _debug("< Send 200 OK\n");
yanmorin's avatar
 
yanmorin committed
      eXosip_call_send_answer (ca->getTid(), OK, answerMessage);
jpbl's avatar
jpbl committed
    }
  }
  eXosip_unlock();

  // Incoming call is answered, start the sound channel.
yanmorin's avatar
 
yanmorin committed
  _debug("          Starting AudioRTP\n");
jpbl's avatar
jpbl committed
  if (_audiortp.createNewSession (getSipCall(id)) < 0) {
jpbl's avatar
jpbl committed
    _debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
yanmorin's avatar
 
yanmorin committed
    i = -1;
jpbl's avatar
jpbl committed
  }
  return i;
yanmorin's avatar
 
yanmorin committed

/**
 * @return > 0 is good, -1 is bad
 */
llea's avatar
llea committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::hangup (CALLID id) 
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  int i = 0;
yanmorin's avatar
 
yanmorin committed
  SipCall* sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
  if (sipcall == NULL) { return -1; }
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Hang up call [cid = %d, did = %d]\n", 
yanmorin's avatar
 
yanmorin committed
    id, sipcall->getCid(), sipcall->getDid());	
  // Release SIP stack.
  eXosip_lock();
  i = eXosip_call_terminate (sipcall->getCid(), sipcall->getDid());
  eXosip_unlock();
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
  // Release RTP channels
yanmorin's avatar
 
yanmorin committed
  if (id == Manager::instance().getCurrentCallId()) {
    _audiortp.closeRtpSession();
  }
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
  deleteSipCall(id);
  return i;
jpbl's avatar
jpbl committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::cancel (CALLID id) 
jpbl's avatar
jpbl committed
{
jpbl's avatar
jpbl committed
  int i = 0;
yanmorin's avatar
 
yanmorin committed
  SipCall* sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Cancel call [cid = %d]\n", id, sipcall->getCid());
yanmorin's avatar
 
yanmorin committed
  // Release SIP stack.
  eXosip_lock();
  i = eXosip_call_terminate (sipcall->getCid(), -1);
  eXosip_unlock();

jpbl's avatar
jpbl committed
  deleteSipCall(id);
  return i;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/*
 * @return -1 = sipcall not present
 */
llea's avatar
llea committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::onhold (CALLID id) 
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  osip_message_t *invite;
  int i;
  int did;
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  sdp_message_t *local_sdp = NULL;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  SipCall *sipcall = getSipCall(id);
  if ( sipcall == NULL ) { return -1; }

  did = sipcall->getDid();

jpbl's avatar
jpbl committed
  eXosip_lock ();
  local_sdp = eXosip_get_local_sdp (did);
  eXosip_unlock ();
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
  if (local_sdp == NULL) {
    return -1;
  }
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  // Build INVITE_METHOD for put call on-hold
yanmorin's avatar
 
yanmorin committed
  eXosip_lock ();
jpbl's avatar
jpbl committed
  i = eXosip_call_build_request (did, INVITE_METHOD, &invite);
  eXosip_unlock ();
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  if (i != 0) {
    sdp_message_free(local_sdp);
    return -1;
  }
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  /* add sdp body */
llea's avatar
llea committed
  {
    char *tmp = NULL;
yanmorin's avatar
 
yanmorin committed

llea's avatar
llea committed
    i = sdp_hold_call (local_sdp);
    if (i != 0) {
jpbl's avatar
jpbl committed
      sdp_message_free (local_sdp);
      osip_message_free (invite);
      return -1;
llea's avatar
llea committed
    }
    
    i = sdp_message_to_str (local_sdp, &tmp);
    sdp_message_free (local_sdp);
    if (i != 0) {
jpbl's avatar
jpbl committed
      osip_message_free (invite);
yanmorin's avatar
 
yanmorin committed
      osip_free (tmp);
jpbl's avatar
jpbl committed
      return -1;
llea's avatar
llea committed
    }
    osip_message_set_body (invite, tmp, strlen (tmp));
    osip_free (tmp);
    osip_message_set_content_type (invite, "application/sdp");
  }
  
jpbl's avatar
jpbl committed
  // Send request
yanmorin's avatar
 
yanmorin committed
  _audiortp.closeRtpSession();

yanmorin's avatar
 
yanmorin committed
  eXosip_lock ();
jpbl's avatar
jpbl committed
  i = eXosip_call_send_request (did, invite);
  eXosip_unlock ();
llea's avatar
llea committed
  
jpbl's avatar
jpbl committed
  // Disable audio
  return i;
yanmorin's avatar
 
yanmorin committed
/**
 * @return 0 is good, -1 is bad
 */
llea's avatar
llea committed
int
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::offhold (CALLID id) 
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  osip_message_t *invite;
  int i;
  int did;

  sdp_message_t *local_sdp = NULL;

  did = getSipCall(id)->getDid();
  eXosip_lock ();
  local_sdp = eXosip_get_local_sdp (did);
  eXosip_unlock ();
  if (local_sdp == NULL) {
    return -1;
  }
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  // Build INVITE_METHOD for put call off-hold
yanmorin's avatar
 
yanmorin committed
  eXosip_lock ();
jpbl's avatar
jpbl committed
  i = eXosip_call_build_request (did, INVITE_METHOD, &invite);
  eXosip_unlock ();
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  if (i != 0) {
    sdp_message_free(local_sdp);
    return -1;
  }
llea's avatar
llea committed

  /* add sdp body */
  {
    char *tmp = NULL;
    
    i = sdp_off_hold_call (local_sdp);
    if (i != 0) {
jpbl's avatar
jpbl committed
      sdp_message_free (local_sdp);
      osip_message_free (invite);
      return -1;
llea's avatar
llea committed
    }
    
    i = sdp_message_to_str (local_sdp, &tmp);
    sdp_message_free (local_sdp);
    if (i != 0) {
jpbl's avatar
jpbl committed
      osip_message_free (invite);
yanmorin's avatar
 
yanmorin committed
      osip_free (tmp);
jpbl's avatar
jpbl committed
      return -1;
llea's avatar
llea committed
    }
    osip_message_set_body (invite, tmp, strlen (tmp));
    osip_free (tmp);
    osip_message_set_content_type (invite, "application/sdp");
  }

jpbl's avatar
jpbl committed
  // Send request
yanmorin's avatar
 
yanmorin committed
  _debug("< Send off hold request\n");
yanmorin's avatar
 
yanmorin committed
  eXosip_lock ();
jpbl's avatar
jpbl committed
  i = eXosip_call_send_request (did, invite);
  eXosip_unlock ();
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
  // Enable audio
yanmorin's avatar
 
yanmorin committed
  _debug("          Starting AudioRTP\n");
yanmorin's avatar
 
yanmorin committed
  if (_audiortp.createNewSession (getSipCall(id)) < 0) {
    _debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
    i = -1;
  }
jpbl's avatar
jpbl committed
  return i;
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::transfer (CALLID id, const std::string& to)
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  osip_message_t *refer;
  int i;
yanmorin's avatar
 
yanmorin committed
  std::string tmp_to;
jpbl's avatar
jpbl committed
  tmp_to = toHeader(to);
yanmorin's avatar
 
yanmorin committed
  if (tmp_to.find("@") == std::string::npos) {
yanmorin's avatar
 
yanmorin committed
    tmp_to = tmp_to + "@" + Manager::instance().getConfigString(SIGNALISATION,
HOST_PART);
jpbl's avatar
jpbl committed
  }
llea's avatar
llea committed

jpbl's avatar
jpbl committed
  eXosip_lock();
  // Build transfer request
  i = eXosip_call_build_refer (getSipCall(id)->getDid(), (char*)tmp_to.data(),
			       &refer);
  if (i == 0) {
    // Send transfer request
    i = eXosip_call_send_request (getSipCall(id)->getDid(), refer);
  }
  eXosip_unlock();
  return i;
yanmorin's avatar
 
yanmorin committed
SipVoIPLink::refuse (CALLID id)
llea's avatar
llea committed
{
jpbl's avatar
jpbl committed
  int i;
  char tmpbuf[64];
  bzero (tmpbuf, 64);
  // Get local port   
  snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort());
llea's avatar
llea committed
	
yanmorin's avatar
 
yanmorin committed
  osip_message_t *answerMessage = NULL;
jpbl's avatar
jpbl committed
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  // not BUSY.. where decline the invitation!
yanmorin's avatar
 
yanmorin committed
  i = eXosip_call_build_answer (getSipCall(id)->getTid(), SIP_DECLINE, &answerMessage);
jpbl's avatar
jpbl committed
  if (i == 0) {
yanmorin's avatar
 
yanmorin committed
    i = eXosip_call_send_answer (getSipCall(id)->getTid(), SIP_DECLINE, answerMessage);
jpbl's avatar
jpbl committed
  }
  eXosip_unlock();
  return i;
llea's avatar
llea committed
}

int
SipVoIPLink::getEvent (void)
{
yanmorin's avatar
 
yanmorin committed
  // wait for 0 s, 50 ms
  eXosip_event_t* event = eXosip_event_wait (0, 50);
jpbl's avatar
jpbl committed
  eXosip_lock();
  eXosip_automatic_action();
  eXosip_unlock();

  if (event == NULL) {
    return -1;
yanmorin's avatar
 
yanmorin committed
  }

yanmorin's avatar
 
yanmorin committed
  SipCall* sipcall = NULL;
  CALLID id = 0;
yanmorin's avatar
 
yanmorin committed
  int returnValue = 0;
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
  _debug("Receive SipEvent #%d %s\n", event->type, event->textinfo);
jpbl's avatar
jpbl committed
  switch (event->type) {
    // IP-Phone user receives a new call
  case EXOSIP_CALL_INVITE: //
yanmorin's avatar
 
yanmorin committed
    _debug("> INVITE (receive)\n");
yanmorin's avatar
 
yanmorin committed
    checkNetwork();

jpbl's avatar
jpbl committed
    // Set local random port for incoming call
    if (!Manager::instance().useStun()) {
      setLocalPort(RANDOM_LOCAL_PORT);
    } else {
      // If there is a firewall
      if (behindNat() != 0) {
yanmorin's avatar
 
yanmorin committed
        setLocalPort(Manager::instance().getFirewallPort());
jpbl's avatar
jpbl committed
      } else {
yanmorin's avatar
 
yanmorin committed
        returnValue = -1;
        break;
yanmorin's avatar
 
yanmorin committed
      }
jpbl's avatar
jpbl committed
    }
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
    // Generate id
    id = Manager::instance().generateNewCallId();
yanmorin's avatar
 
yanmorin committed
    Manager::instance().pushBackNewCall(id, Incoming);
yanmorin's avatar
 
yanmorin committed
    _debug("%10d: [cid = %d, did = %d]\n", id, event->cid, event->did);
jpbl's avatar
jpbl committed

    // Associate an audio port with a call
yanmorin's avatar
 
yanmorin committed
    sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
    sipcall->setLocalAudioPort(_localPort);
    sipcall->setLocalIp(getLocalIpAddress());
yanmorin's avatar
 
yanmorin committed
    _debug("            Local listening port: %d\n", _localPort);
    _debug("            Local listening IP: %s\n", getLocalIpAddress().c_str());
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    if (sipcall->newIncomingCall(event) == 0 ) {
      if (Manager::instance().incomingCall(id, sipcall->getName(), sipcall->getNumber()) == -1) {
yanmorin's avatar
 
yanmorin committed
        Manager::instance().displayError("            Incoming Call Failed");
yanmorin's avatar
 
yanmorin committed
        deleteSipCall(id);
      }
    } else {
      Manager::instance().peerHungupCall(id);
      deleteSipCall(id);
yanmorin's avatar
 
yanmorin committed
      Manager::instance().displayError("            Incoming Call Failed");
jpbl's avatar
jpbl committed
    }
    break;

  case EXOSIP_CALL_REINVITE:
yanmorin's avatar
 
yanmorin committed
    _debug("> INVITE (reinvite)\n");
yanmorin's avatar
 
yanmorin committed
    //eXosip_call_send_answer(event->tid, 403, NULL);
    //488 as http://www.atosc.org/pipermail/public/osip/2005-June/005385.html
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    id = findCallId(event);
    if (id != 0) {
      sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
      if (sipcall != 0) {
yanmorin's avatar
 
yanmorin committed
        _debug("%10d: Receive Reinvite [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did,sipcall->getLocalAudioPort());
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
        if ( id == Manager::instance().getCurrentCallId() ) {
yanmorin's avatar
 
yanmorin committed
          Manager::instance().stopTone();
yanmorin's avatar
 
yanmorin committed
          _audiortp.closeRtpSession();
        }
yanmorin's avatar
 
yanmorin committed
        sipcall->newReinviteCall(event);
        // we should receive an ack after that...
yanmorin's avatar
 
yanmorin committed
      }
    } else {
yanmorin's avatar
 
yanmorin committed
      _debug("< Send 488 Not Acceptable Here");
yanmorin's avatar
 
yanmorin committed
      eXosip_lock();
yanmorin's avatar
 
yanmorin committed
      eXosip_call_send_answer(event->tid, 488, NULL);
yanmorin's avatar
 
yanmorin committed
      eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
    }
jpbl's avatar
jpbl committed
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_PROCEEDING: // 8
    // proceeding call...
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_RINGING: // 9 peer call is ringing
    id = findCallIdInitial(event);
yanmorin's avatar
 
yanmorin committed
    _debug("%10d: Receive Call Ringing [cid = %d, did = %d]\n", id, event->cid, event->did);
yanmorin's avatar
 
yanmorin committed
    if (id != 0) {
      getSipCall(id)->ringingCall(event);
      Manager::instance().peerRingingCall(id);
    } else {
      returnValue = -1;
    }
    break;

  // The peer-user answers
yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_ANSWERED: // 10
  {
yanmorin's avatar
 
yanmorin committed
    id = findCallIdInitial(event);
    if ( id != 0) {
      sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
      if ( sipcall != 0 ) {
yanmorin's avatar
 
yanmorin committed
        _debug("%10d: Receive Call Answer [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did, sipcall->getLocalAudioPort());
yanmorin's avatar
 
yanmorin committed

        // Answer
        if (Manager::instance().callCanBeAnswered(id)) {
          sipcall->setStandBy(false);
          if (sipcall->answeredCall(event) != -1) {
            sipcall->answeredCall_without_hold(event);
            Manager::instance().peerAnsweredCall(id);
  
yanmorin's avatar
 
yanmorin committed
            if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) {
yanmorin's avatar
 
yanmorin committed
              // Outgoing call is answered, start the sound channel.
yanmorin's avatar
 
yanmorin committed
              _debug("            Starting AudioRTP\n");
yanmorin's avatar
 
yanmorin committed
              if (_audiortp.createNewSession(sipcall) < 0) {
yanmorin's avatar
 
yanmorin committed
                _debug("            FATAL: Unable to start sound (%s:%d)\n", 
yanmorin's avatar
 
yanmorin committed
                __FILE__, __LINE__);
                returnValue = -1;
              }
yanmorin's avatar
 
yanmorin committed
            }
yanmorin's avatar
 
yanmorin committed
          }
yanmorin's avatar
 
yanmorin committed
        } else {
          // Answer to on/off hold to send ACK
yanmorin's avatar
 
yanmorin committed
          _debug("            Answering call\n");
yanmorin's avatar
 
yanmorin committed
          sipcall->answeredCall(event);
yanmorin's avatar
 
yanmorin committed
        }
jpbl's avatar
jpbl committed
      }
yanmorin's avatar
 
yanmorin committed
    } else {
      returnValue = -1;
jpbl's avatar
jpbl committed
    }
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
   break;
yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_REDIRECTED: // 11
jpbl's avatar
jpbl committed
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_ACK: // 15
yanmorin's avatar
yanmorin committed
    id = findCallId(event); 
yanmorin's avatar
 
yanmorin committed
    _debug("%10d: Receive ACK [cid = %d, did = %d]\n", id, event->cid, event->did);
yanmorin's avatar
 
yanmorin committed
    if (id != 0 ) {
      sipcall = getSipCall(id);
      if(sipcall != 0 ) { 
        sipcall->receivedAck(event);
        if (sipcall->isReinvite()) {
          sipcall->endReinvite();
yanmorin's avatar
 
yanmorin committed
          if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) {
yanmorin's avatar
 
yanmorin committed
            _debug("            Starting AudioRTP\n");
yanmorin's avatar
 
yanmorin committed
            _audiortp.createNewSession(sipcall);
yanmorin's avatar
 
yanmorin committed
          } else {
            _debug("            Didn't start RTP because it's on hold or it's not the current call id\n");
yanmorin's avatar
 
yanmorin committed
          }
        }
      }
jpbl's avatar
jpbl committed
    } else {
yanmorin's avatar
 
yanmorin committed
      returnValue = -1;
jpbl's avatar
jpbl committed
    }
    break;
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
    // The peer-user closed the phone call(we received BYE).
yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_CLOSED: // 25
jpbl's avatar
jpbl committed
    id = findCallId(event);
yanmorin's avatar
yanmorin committed
    if (id==0) { id = findCallIdInitial(event); }
yanmorin's avatar
 
yanmorin committed
    _debug("%10d: Receive BYE [cid = %d, did = %d]\n", id, event->cid, event->did);	
yanmorin's avatar
 
yanmorin committed
    if (id != 0) {
      if (Manager::instance().callCanBeClosed(id)) {
yanmorin's avatar
 
yanmorin committed
         sipcall = getSipCall(id);
yanmorin's avatar
 
yanmorin committed
         _audiortp.closeRtpSession();
jpbl's avatar
jpbl committed
      }
      Manager::instance().peerHungupCall(id);
      deleteSipCall(id);
    } else {
yanmorin's avatar
 
yanmorin committed
      returnValue = -1;
jpbl's avatar
jpbl committed
    }	
    break;
yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_RELEASED:
yanmorin's avatar
 
yanmorin committed
    if (event) {
      _debug("SIP call released: [cid = %d, did = %d]\n", event->cid, event->did);
yanmorin's avatar
 
yanmorin committed
      id = findCallId(event);
      if (id!=0) {
        // not supposed to be execute on a current call...
        Manager::instance().callFailure(id);
        deleteSipCall(id);
      }

yanmorin's avatar
 
yanmorin committed
    }
yanmorin's avatar
 
yanmorin committed
    break;
jpbl's avatar
jpbl committed
  case EXOSIP_CALL_REQUESTFAILURE:
    id = findCallId(event);

    // Handle 4XX errors
    switch (event->response->status_code) {
    case AUTH_REQUIRED:
yanmorin's avatar
 
yanmorin committed
      _debug("SIP Server ask required authentification: logging...\n");
yanmorin's avatar
 
yanmorin committed
      setAuthentication();
jpbl's avatar
jpbl committed
      eXosip_lock();
      eXosip_automatic_action();
      eXosip_unlock();
      break;
    case UNAUTHORIZED:
yanmorin's avatar
 
yanmorin committed
      _debug("Request is unauthorized. SIP Server ask authentification: logging...\n");
jpbl's avatar
jpbl committed
      setAuthentication();
      break;

    case BAD_REQ:
    case FORBIDDEN:
    case NOT_FOUND:
    case NOT_ALLOWED:
    case NOT_ACCEPTABLE:
    case REQ_TIMEOUT:
    case TEMP_UNAVAILABLE:
    case ADDR_INCOMPLETE:
yanmorin's avatar
 
yanmorin committed
    case NOT_ACCEPTABLE_HERE: // 488
jpbl's avatar
jpbl committed
      // Display error on the screen phone
yanmorin's avatar
 
yanmorin committed
      //Manager::instance().displayError(event->response->reason_phrase);
      Manager::instance().displayErrorText(id, event->response->reason_phrase);
yanmorin's avatar
 
yanmorin committed
      Manager::instance().callFailure(id);
yanmorin's avatar
 
yanmorin committed
      deleteSipCall(id);
yanmorin's avatar
 
yanmorin committed
    break;
    case BUSY_HERE:
      Manager::instance().displayErrorText(id, event->response->reason_phrase);
yanmorin's avatar
 
yanmorin committed
      Manager::instance().callBusy(id);
yanmorin's avatar
 
yanmorin committed
      deleteSipCall(id);
jpbl's avatar
jpbl committed
      break;
    case REQ_TERMINATED:
      break;
    default:
      break;
    }
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
    break; 

  case EXOSIP_CALL_SERVERFAILURE:
    // Handle 5XX errors
    switch (event->response->status_code) {
    case SERVICE_UNAVAILABLE:
yanmorin's avatar
 
yanmorin committed
      id = findCallId(event);
      Manager::instance().callFailure(id);
jpbl's avatar
jpbl committed
      break;
    default:
      break;
    }
    break;

  case EXOSIP_CALL_GLOBALFAILURE:
    // Handle 6XX errors
    switch (event->response->status_code) {
    case BUSY_EVERYWHERE:
    case DECLINE:
yanmorin's avatar
 
yanmorin committed
      id = findCallId(event);
      Manager::instance().callFailure(id);
jpbl's avatar
jpbl committed
      break;
    default:
      break;
    }
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_CALL_MESSAGE_NEW: // 18
yanmorin's avatar
yanmorin committed
    if (0 == event->request) break;
    if (MSG_IS_INFO(event->request)) {
      _debug("Receive a call message request info\n");
      osip_content_type_t* c_t = event->request->content_type;
      if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) {
        _debug("  Content Type of the message: %s/%s\n", c_t->type, c_t->subtype);
        // application/dtmf-relay
        if (strcmp(c_t->type, "application") == 0 && strcmp(c_t->subtype, "dtmf-relay") == 0) {
          handleDtmfRelay(event);
        }
      }
    }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
yanmorin committed
    osip_message_t *answerOKNewMessage;
    eXosip_lock();
    if ( 0 == eXosip_call_build_answer(event->tid, OK, &answerOKNewMessage)) {
      _debug("< Sending 200 OK\n");
      eXosip_call_send_answer(event->tid, OK, answerOKNewMessage);
    } else {
      _debug("Could not sent an OK message\n");
    }
    eXosip_unlock();
    break;
 
yanmorin's avatar
 
yanmorin committed
  case EXOSIP_REGISTRATION_SUCCESS: // 1
yanmorin's avatar
 
yanmorin committed
    // Manager::instance().displayStatus(LOGGED_IN_STATUS);
yanmorin's avatar
 
yanmorin committed
    Manager::instance().registrationSucceed();
jpbl's avatar
jpbl committed
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_REGISTRATION_FAILURE: // 2
yanmorin's avatar
 
yanmorin committed
    //Manager::instance().displayError("getEvent : Registration Failure");
yanmorin's avatar
 
yanmorin committed
    Manager::instance().registrationFailed();
jpbl's avatar
jpbl committed
    break;

yanmorin's avatar
 
yanmorin committed
  case EXOSIP_MESSAGE_NEW: //27
yanmorin's avatar
 
yanmorin committed

    if ( event->request == NULL) {
      break; // do nothing
    }
jpbl's avatar
jpbl committed
    unsigned int k;
llea's avatar
llea committed
				
yanmorin's avatar
 
yanmorin committed
    if (MSG_IS_OPTIONS(event->request)) {
jpbl's avatar
jpbl committed
      for (k = 0; k < _sipcallVector.size(); k++) {
yanmorin's avatar
 
yanmorin committed
        if (_sipcallVector.at(k)->getCid() == event->cid) { 
          break;
        }
jpbl's avatar
jpbl committed
      }
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
      // TODO: Que faire si rien trouve??
      eXosip_lock();
jpbl's avatar
jpbl committed
      if (k == _sipcallVector.size()) {
yanmorin's avatar
 
yanmorin committed
        /* answer 200 ok */
        eXosip_options_send_answer (event->tid, OK, NULL);
jpbl's avatar
jpbl committed
      } else if (_sipcallVector.at(k)->getCid() == event->cid) {
yanmorin's avatar
 
yanmorin committed
        /* already answered! */
jpbl's avatar
jpbl committed
      } else {
yanmorin's avatar
 
yanmorin committed
        /* answer 486 ok */
      	eXosip_options_send_answer (event->tid, BUSY_HERE, NULL);
jpbl's avatar
jpbl committed
      }
      eXosip_unlock();
    } 
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
    // Voice message 
yanmorin's avatar
 
yanmorin committed
    else if (MSG_IS_NOTIFY(event->request)){
yanmorin's avatar
 
yanmorin committed
      _debug("> NOTIFY Voice message\n");
jpbl's avatar
jpbl committed
      int ii;
      unsigned int pos;
      unsigned int pos_slash;

yanmorin's avatar
 
yanmorin committed
      osip_body_t *body = NULL;
jpbl's avatar
jpbl committed
      // Get the message body
      ii = osip_message_get_body(event->request, 0, &body);
      if (ii != 0) {
yanmorin's avatar
 
yanmorin committed
        _debug("  Cannot get body in a new EXOSIP_MESSAGE_NEW event\n");
yanmorin's avatar
 
yanmorin committed
        returnValue = -1;
        break;
jpbl's avatar
jpbl committed
      }
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
      // Analyse message body
yanmorin's avatar
 
yanmorin committed
      if (!body || !body->body) {
        returnValue = -1;
        break;
      }
      std::string str(body->body);
      pos = str.find(VOICE_MSG);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
      if (pos == std::string::npos) {
yanmorin's avatar
 
yanmorin committed
	     // If the string is not found
yanmorin's avatar
 
yanmorin committed
        returnValue = -1;
        break;
jpbl's avatar
jpbl committed
      } 
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
      pos_slash = str.find ("/");
yanmorin's avatar
 
yanmorin committed
      std::string nb_msg = str.substr(pos + LENGTH_VOICE_MSG, 
yanmorin's avatar
 
yanmorin committed
      pos_slash - (pos + LENGTH_VOICE_MSG));
jpbl's avatar
jpbl committed

      // Set the number of voice-message
      setMsgVoicemail(atoi(nb_msg.data()));

      if (getMsgVoicemail() != 0) {
yanmorin's avatar
 
yanmorin committed
        // If there is at least one voice-message, start notification
yanmorin's avatar
 
yanmorin committed
        Manager::instance().startVoiceMessageNotification(nb_msg);
jpbl's avatar
jpbl committed
      } else {
yanmorin's avatar
 
yanmorin committed
        // Stop notification when there is 0 voice message
yanmorin's avatar
 
yanmorin committed
        Manager::instance().stopVoiceMessageNotification();
jpbl's avatar
jpbl committed
      }
yanmorin's avatar
 
yanmorin committed
    // http://www.jdrosen.net/papers/draft-ietf-simple-im-session-00.txt
    } else if (MSG_IS_MESSAGE(event->request)) {
      _debug("> MESSAGE received\n");
      // osip_content_type_t* osip_message::content_type
      osip_content_type_t* c_t = event->request->content_type;
yanmorin's avatar
yanmorin committed
      if (c_t != 0 &&  c_t->type != 0 && c_t->subtype != 0 ) {
yanmorin's avatar
 
yanmorin committed
        _debug("  Content Type of the message: %s/%s\n", c_t->type, c_t->subtype);

        osip_body_t *body = NULL;
        // Get the message body
        if (0 == osip_message_get_body(event->request, 0, &body)) {