diff --git a/sflphone-client-gnome/src/config/accountconfigdialog.c b/sflphone-client-gnome/src/config/accountconfigdialog.c
index 5fa496fe3d725e9ee018af1c04ee625a85bc821c..fbe634efa1f7b244a2217eb259f93fa98f60ab25 100644
--- a/sflphone-client-gnome/src/config/accountconfigdialog.c
+++ b/sflphone-client-gnome/src/config/accountconfigdialog.c
@@ -730,7 +730,7 @@ GtkWidget * create_security_tab(account_t **a)
     keyExchangeCombo = gtk_combo_box_new_text();
     gtk_label_set_mnemonic_widget (GTK_LABEL (label), keyExchangeCombo);
     gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "ZRTP");
-    //gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "SDES");
+    gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "SDES");
     gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), _("Disabled"));      
     
     advancedZrtpButton = gtk_button_new_from_stock(GTK_STOCK_PREFERENCES);
@@ -738,13 +738,17 @@ GtkWidget * create_security_tab(account_t **a)
         
     if (g_strcmp0(curSRTPEnabled, "false") == 0)
     {
-        gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 1);
+        gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 2);
         gtk_widget_set_sensitive(GTK_WIDGET(advancedZrtpButton), FALSE);
     } else {
         if (strcmp(curKeyExchange, ZRTP) == 0) {
             gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo),0);
-        } else {
-            gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 1);
+        } 
+	else if (strcmp(curKeyExchange, SDES) == 0) {
+	    gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo),1);
+	}
+	else {
+            gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 2);
             gtk_widget_set_sensitive(GTK_WIDGET(advancedZrtpButton), FALSE);
         }
     }
@@ -1157,7 +1161,12 @@ show_account_window (account_t * a)
 			if (g_strcasecmp(keyExchange, "ZRTP") == 0) {
 			  g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("true"));
 			  g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_KEY_EXCHANGE), g_strdup(ZRTP));
-			} else {
+			}
+			else if(g_strcasecmp(keyExchange, "SDES") == 0) {
+			    g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("true"));
+			    g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_KEY_EXCHANGE), g_strdup(SDES));
+			}
+			else {
 			  g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("false"));
 			}
     		
diff --git a/sflphone-client-gnome/src/config/preferencesdialog.c b/sflphone-client-gnome/src/config/preferencesdialog.c
index 791e4aaea6c2042c3f9bb4e6f7e27f558fe26e41..1a8bf8b9deb1eb56471808a463383005a464a7e9 100644
--- a/sflphone-client-gnome/src/config/preferencesdialog.c
+++ b/sflphone-client-gnome/src/config/preferencesdialog.c
@@ -120,10 +120,16 @@ static void key_exchange_changed_cb(GtkWidget *widget, gpointer data)
 {
 	DEBUG("Key exchange changed");
 	if (g_strcasecmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)), (gchar *) "ZRTP") == 0) {
-		gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
-		g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("true"));
-		g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_KEY_EXCHANGE), g_strdup(ZRTP));
-	} else {
+	    gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
+	    g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("true"));
+	    g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_KEY_EXCHANGE), g_strdup(ZRTP));
+	} 
+	else if (g_strcasecmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)), (gchar *) "SDES") == 0) {
+	    gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+	    g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("true"));
+	    g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_KEY_EXCHANGE), g_strdup(SDES));
+	}
+	else {
 		gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
 		DEBUG("Setting key exchange %s to %s\n", ACCOUNT_KEY_EXCHANGE, KEY_EXCHANGE_NONE);
 		g_hash_table_replace(directIpCallsProperties, g_strdup(ACCOUNT_SRTP_ENABLED), g_strdup("false"));
@@ -326,16 +332,20 @@ GtkWidget* create_direct_ip_calls_tab()
 	keyExchangeCombo = gtk_combo_box_new_text();
 	gtk_label_set_mnemonic_widget (GTK_LABEL (label), keyExchangeCombo);
 	gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "ZRTP");
-	//gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "SDES");
+	gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), "SDES");
 	gtk_combo_box_append_text(GTK_COMBO_BOX(keyExchangeCombo), _("Disabled"));      
 
 	advancedZrtpButton = gtk_button_new_from_stock(GTK_STOCK_PREFERENCES);
 	g_signal_connect(G_OBJECT(advancedZrtpButton), "clicked", G_CALLBACK(show_advanced_zrtp_options_cb), directIpCallsProperties);
 
 	if (g_strcasecmp(curKeyExchange, ZRTP) == 0) {
-		gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo),0);
-	} else {
-		gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 1);
+	    gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo),0);
+	}
+	else if(g_strcasecmp(curKeyExchange, SDES) == 0) {
+	    gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo),1);
+	}
+	else {
+		gtk_combo_box_set_active(GTK_COMBO_BOX(keyExchangeCombo), 2);
 		gtk_widget_set_sensitive(GTK_WIDGET(advancedZrtpButton), FALSE);
 	}
 
diff --git a/sflphone-client-gnome/src/sflphone_const.h b/sflphone-client-gnome/src/sflphone_const.h
index d8e7870b9efa49f0ee12d2a4b77e181a634851b9..52e786ade3e73803fe23fcf3943435c3fe7b7851 100644
--- a/sflphone-client-gnome/src/sflphone_const.h
+++ b/sflphone-client-gnome/src/sflphone_const.h
@@ -51,9 +51,9 @@
 #define UNUSED  __attribute__((__unused__))
 
 #define ACCOUNT_TYPE                       "Account.type"
-#define ACCOUNT_ALIAS		               "Account.alias"
-#define ACCOUNT_ENABLED		               "Account.enable"
-#define ACCOUNT_MAILBOX		               "Account.mailbox"
+#define ACCOUNT_ALIAS		           "Account.alias"
+#define ACCOUNT_ENABLED		           "Account.enable"
+#define ACCOUNT_MAILBOX		           "Account.mailbox"
 #define ACCOUNT_RESOLVE_ONCE               "Account.resolveOnce"
 #define ACCOUNT_REGISTRATION_EXPIRE        "Account.expire"
 #define ACCOUNT_SIP_STUN_SERVER	           "STUN.server"
@@ -71,7 +71,7 @@
 #define ACCOUNT_DISPLAY_SAS_ONCE           "ZRTP.displaySasOnce"
 #define KEY_EXCHANGE_NONE                  "0"
 #define ZRTP                               "1"
-#define SDES_TLS                           "2"
+#define SDES                               "2"
 
 #define TLS_ENABLE                          "TLS.enable"
 #define TLS_PORT                            "TLS.port"
diff --git a/sflphone-common/configure.ac b/sflphone-common/configure.ac
index 41bfe9221b850eb4ac988e88fd260feb978e5365..fe7cdfcc927b1878cab573e780f0984c19be50c1 100644
--- a/sflphone-common/configure.ac
+++ b/sflphone-common/configure.ac
@@ -284,7 +284,7 @@ fi
 xml_CFLAGS=
 xml_LIBS=-lexpat
 
-	AC_SUBST(xml_CFLAGS)
+AC_SUBST(xml_CFLAGS)
 AC_SUBST(xml_LIBS)
 
 AC_CHECK_LIB([pthread], pthread_create,
@@ -295,6 +295,22 @@ AC_CHECK_LIB([pthread], pthread_create,
 AC_MSG_ERROR([You need the POSIX Thread library (pthreads)])	
 	fi
 
+
+AC_CHECK_LIB([pcre], pcre_free,
+		[AC_CHECK_HEADERS(pcre.h, have_pcre=true, have_pcre=false)],
+		have_pcre=false)
+
+	if test "$have_pcre" = "false"; then
+AC_MSG_ERROR([You need the Perl-Compatible Regular Expressions library (pcre)])	
+	fi
+
+PCRE_LIBS=-lpcre
+PCRE_CFLAGS=
+AC_SUBST(PCRE_LIBS)
+AC_SUBST(PCRE_CFLAGS)
+
+
+
 # For the tools/, we need libdbus-c++ for the "build" architecture as well
 
 	AM_CONDITIONAL(CROSS_COMPILING, test "$cross_compiling" = "yes")
diff --git a/sflphone-common/src/Makefile.am b/sflphone-common/src/Makefile.am
index 0d2b2da9cc12f78d4bf4898061de9359e26a5da6..10d240d25e40a2b237f61cb2dae6d7420bd2de44 100644
--- a/sflphone-common/src/Makefile.am
+++ b/sflphone-common/src/Makefile.am
@@ -62,7 +62,7 @@ noinst_LTLIBRARIES = libsflphone.la
 
 noinst_HEADERS = \
 		conference.h \
-        	voiplink.h \
+		voiplink.h \
 		managerimpl.h \
 		manager.h \
 		global.h \
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp b/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp
index 318bf8c727e9bda938b106b1cf82000eced3c4a6..d9f88f1b55a5dbdcbd7d7c9fcf35a7aa5fda20e8 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp
+++ b/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp
@@ -20,11 +20,13 @@
 
 #include "AudioRtpFactory.h"
 #include "AudioZrtpSession.h"
+#include "AudioSrtpSession.h"
 #include "AudioSymmetricRtpSession.h"
 
 #include "manager.h"
 #include "account.h"
 #include "sip/sipcall.h"
+#include "sip/SdesNegotiator.h"
 
 #include <assert.h>
 
@@ -106,6 +108,12 @@ void AudioRtpFactory::initAudioRtpSession (SIPCall * ca)
 
             case Sdes:
 
+	        _rtpSession = new AudioSrtpSession (&Manager::instance(), ca);
+                _rtpSessionType = Sdes;
+
+		ca->getLocalSDP()->set_srtp_crypto(static_cast<AudioSrtpSession *> (_rtpSession)->getLocalCryptoInfo());
+		break;
+
             default:
                 throw UnsupportedRtpSessionType();
         }
@@ -125,6 +133,9 @@ void AudioRtpFactory::start (void)
     switch (_rtpSessionType) {
 
         case Sdes:
+	    if (static_cast<AudioSrtpSession *> (_rtpSession)->startRtpThread() != 0) {
+                throw AudioRtpFactoryException ("Failed to start AudioSRtpSession thread");
+            }
 	    break;
 
         case Symmetric:
@@ -160,6 +171,8 @@ void AudioRtpFactory::stop (void)
         switch (_rtpSessionType) {
 
             case Sdes:
+	        delete static_cast<AudioSrtpSession *> (_rtpSession);
+		break;
 
             case Symmetric:
                 delete static_cast<AudioSymmetricRtpSession *> (_rtpSession);
@@ -177,6 +190,29 @@ void AudioRtpFactory::stop (void)
     }
 }
 
+void AudioRtpFactory::updateDestinationIpAddress (void)
+{
+    _debug ("Updating IP address");
+    if (_rtpSession == NULL) {
+        throw AudioRtpFactoryException ("_rtpSession was null when trying to update IP address");
+    }
+
+    switch (_rtpSessionType) {
+
+        case Sdes:
+	    static_cast<AudioSrtpSession *> (_rtpSession)->updateDestinationIpAddress();
+	    break;
+
+        case Symmetric:
+            static_cast<AudioSymmetricRtpSession *> (_rtpSession)->updateDestinationIpAddress();
+            break;
+
+        case Zrtp:
+	    static_cast<AudioZrtpSession *> (_rtpSession)->updateDestinationIpAddress();
+            break;
+    }
+}
+
 sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession()
 {
     if ( (_rtpSessionType == Zrtp) && (_rtpSessionType != NULL)) {
@@ -185,4 +221,16 @@ sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession()
         throw AudioRtpFactoryException();
     }
 }
+
+  void AudioRtpFactory::setRemoteCryptoInfo(sfl::SdesNegotiator& nego)
+{
+    if ( (_rtpSessionType != NULL) && (_rtpSessionType == Sdes)) {
+        static_cast<AudioSrtpSession *> (_rtpSession)->setRemoteCryptoInfo(nego);
+    }
+    else {
+        throw AudioRtpFactoryException();
+    }
+}
 }
+
+
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpFactory.h b/sflphone-common/src/audio/audiortp/AudioRtpFactory.h
index 0eefcbfc8264339055a0cb98520fd95d1f7d9879..664bf3ae2cda5b2ae39804f6bfbcfc7b757413a7 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpFactory.h
+++ b/sflphone-common/src/audio/audiortp/AudioRtpFactory.h
@@ -22,14 +22,20 @@
 #include <stdexcept>
 #include <cc++/thread.h>
 
+#include "sip/SdesNegotiator.h"
+
+class SdesNegotiator;
 class SIPCall;
+
 namespace sfl {
     class AudioZrtpSession;
+    class AudioSrtpSession;
 }
 
 namespace sfl {
 
     class AudioZrtpSession;
+    class AudioSrtpSession;
 
     // Possible kind of rtp session
     typedef enum RtpMethod {
@@ -76,6 +82,12 @@ namespace sfl {
          * @param None
          */
         void stop();
+
+	/**
+         * Update current RTP destination address with one stored in call 
+         * @param None
+         */
+	void updateDestinationIpAddress (void);
           
         /** 
         * @param None
@@ -83,13 +95,28 @@ namespace sfl {
         * file. initAudioRtpSession must have been called prior to that. 
         */  
         inline void * getAudioRtpSession(void) { return _rtpSession; }
+
+	/** 
+        * @param None
+        * @return The internal audio rtp session type 
+	*         Symmetric = 0
+        *         Zrtp = 1
+        *         Sdes = 2 
+        */  
+        inline RtpMethod getAudioRtpType(void) { return _rtpSessionType; }
  
         /**
          * Get the current AudioZrtpSession. Throws an AudioRtpFactoryException
          * if the current rtp thread is null, or if it's not of the correct type.
          * @return The current AudioZrtpSession thread.
          */
-        sfl::AudioZrtpSession * getAudioZrtpSession();       
+        sfl::AudioZrtpSession * getAudioZrtpSession();  
+
+	/**
+         * Set remote cryptographic info. Should be called after negotiation in SDP
+	 * offer/answer session.
+         */
+        void setRemoteCryptoInfo(sfl::SdesNegotiator& nego);   
         
         private:
            void * _rtpSession;
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpSession.h b/sflphone-common/src/audio/audiortp/AudioRtpSession.h
index e1d8b536cb87083deb612096b4f2ab2e4d0c1442..d168cb8d750fef943960ef2e3b1c7999002a4bc3 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpSession.h
+++ b/sflphone-common/src/audio/audiortp/AudioRtpSession.h
@@ -66,7 +66,12 @@ namespace sfl {
             virtual void run ();
             
             int startRtpThread();
-    
+
+	    /**
+	     * Used mostly when receiving a reinvite
+	     */
+	    void updateDestinationIpAddress(void);
+
         private:
         
             void initBuffers(void);
@@ -98,6 +103,16 @@ namespace sfl {
             // it amounts to the same as doing
             // start() with no semaphore at all. 
             ost::Semaphore * _mainloopSemaphore;
+
+	    // Main destination address for this rtp session.
+	    // Stored in case or reINVITE, which may require to forget 
+	    // this destination and update a new one.
+	    ost::InetHostAddress _remote_ip;
+
+	    // Main destination port for this rtp session.
+	    // Stored in case reINVITE, which may require to forget
+	    // this destination and update a new one
+	    unsigned short _remote_port;
                      
             AudioCodec * _audiocodec;
             
@@ -292,20 +307,36 @@ namespace sfl {
         }
         
         _debug ("Setting IP address for the RTP session\n");
-        
-        ost::InetHostAddress remote_ip (_ca->getLocalSDP()->get_remote_ip().c_str());
+
+	// Store remote ip in case we would need to forget current destination
+        _remote_ip = ost::InetHostAddress(_ca->getLocalSDP()->get_remote_ip().c_str());
         _debug ("Init audio RTP session: remote ip %s\n", _ca->getLocalSDP()->get_remote_ip().data());
 
-        if (!remote_ip) {
+        if (!_remote_ip) {
             _debug ("Target IP address [%s] is not correct!\n", _ca->getLocalSDP()->get_remote_ip().data());
             return;
         }
 
-        if (! static_cast<D*>(this)->addDestination (remote_ip, (unsigned short) _ca->getLocalSDP()->get_remote_audio_port())) {
+	// Store remote port in case we would need to forget current destination
+	_remote_port = (unsigned short) _ca->getLocalSDP()->get_remote_audio_port();
+
+        if (! static_cast<D*>(this)->addDestination (_remote_ip, _remote_port)) {
             _debug ("Can't add destination to session!\n");
             return;
         }
     }
+
+    template <typename D>
+    void AudioRtpSession<D>::updateDestinationIpAddress(void)
+    {
+        // Destination address are stored in a list in ccrtp
+        // This method clear off this entry
+        static_cast<D*>(this)->forgetDestination(_remote_ip, _remote_port);
+
+	// new destination is stored in call
+	// we just need to recall this method
+        setDestinationIpAddress();
+    }
     
     template <typename D>
     int AudioRtpSession<D>::processDataEncode(void)
diff --git a/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp b/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4715587ff03b8e153f56aee346dd689468e0b440
--- /dev/null
+++ b/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp
@@ -0,0 +1,298 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
+ *
+ *  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 3 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.
+ */
+#include "AudioSrtpSession.h"
+#include "user_cfg.h"
+
+#include "sip/sipcall.h"
+
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+
+
+#include <cstdio>
+#include <cstring>
+#include <cerrno>
+
+static uint8 mk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+
+static uint8 ms[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d };
+
+
+namespace sfl
+{
+
+AudioSrtpSession::AudioSrtpSession (ManagerImpl * manager, SIPCall * sipcall) :
+        ost::SymmetricRTPSession (ost::InetHostAddress (sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()),
+	_localCryptoSuite(0),
+	_remoteCryptoSuite(0),
+        AudioRtpSession<AudioSrtpSession> (manager, sipcall)
+{
+
+    // Initialize local Crypto context
+    initializeLocalMasterKey();
+    initializeLocalMasterSalt();
+    initializeLocalCryptoContext();
+
+    // Set local crypto context in ccrtp
+    _localCryptoCtx->deriveSrtpKeys(0);
+
+    setOutQueueCryptoContext(_localCryptoCtx);
+}
+
+ 
+std::string AudioSrtpSession::getLocalCryptoInfo() {
+
+    _debug("Get Cryptographic info from this rtp session");
+
+    // @TODO we should return a vector containing supported 
+    // cryptographic context tagged 1, 2, 3...
+    std::string tag = "1";
+
+    std::string crypto_suite = sfl::CryptoSuites[_localCryptoSuite].name;
+
+    // srtp keys formated as the following  as the following
+    // inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32
+    std::string srtp_keys = "inline:";
+    srtp_keys += getBase64ConcatenatedKeys();
+    srtp_keys.append("|2^20|1:32");
+
+    // generate crypto attribute
+    std::string crypto = tag.append(" ");
+    crypto += crypto_suite.append(" ");
+    crypto += srtp_keys;
+
+    _debug("%s", crypto.c_str());
+
+    return crypto;
+}
+
+
+void AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) {
+
+    _debug("Set remote Cryptographic info for Srtp session");
+
+    // decode keys
+    unBase64ConcatenatedKeys(nego.getKeyInfo());
+
+    // init crypto content int Srtp session
+    initializeRemoteCryptoContext();
+    setInQueueCryptoContext(_remoteCryptoCtx);
+}
+
+
+void AudioSrtpSession::initializeLocalMasterKey(void)
+{
+
+    // @TODO key may have different length depending on cipher suite
+    _localMasterKeyLength = sfl::CryptoSuites[_localCryptoSuite].masterKeyLength / 8;
+
+    // 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);
+
+    printf("Local Master: ");
+    for(int i = 0; i < _localMasterKeyLength; i++){
+        printf("%d", _localMasterKey[i]);
+    }
+    printf("\n");
+
+    return;
+}
+
+
+void AudioSrtpSession::initializeLocalMasterSalt(void)
+{
+
+    // @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];
+
+    // 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);
+
+    return;
+
+}
+
+
+std::string AudioSrtpSession::getBase64ConcatenatedKeys()
+{
+
+    // compute concatenated master and salt length
+    int concatLength = _localMasterKeyLength + _localMasterSaltLength;
+
+    uint8 concatKeys[concatLength];
+
+    // concatenate keys
+    memcpy((void*)concatKeys, (void*)_localMasterKey, _localMasterKeyLength);
+    memcpy((void*)(concatKeys + _localMasterKeyLength), (void*)_localMasterSalt, _localMasterSaltLength);
+
+    // encode concatenated keys in base64
+    char *output = encodeBase64((unsigned char*)concatKeys, concatLength);
+
+    // init string containing encoded data
+    std::string keys(output);
+
+    free(output);
+
+    return keys;
+}
+
+
+void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys)
+{
+
+    
+    _remoteMasterKeyLength = sfl::CryptoSuites[1].masterKeyLength / 8;
+    _remoteMasterSaltLength = sfl::CryptoSuites[1].masterSaltLength / 8;
+
+    // length of decoded data data
+    int length;
+
+    // pointer to binary data
+    char *dataptr = (char*)base64keys.data();
+
+    // decode concatenated binary keys
+    char *output = decodeBase64((unsigned char*)dataptr, strlen(dataptr), &length);
+
+    // copy master and slt respectively
+    memcpy((void*)_remoteMasterKey, (void*)output, _remoteMasterKeyLength);
+    memcpy((void*)_remoteMasterSalt, (void*)(output + _remoteMasterKeyLength), _remoteMasterSaltLength);
+
+    free(output);
+}
+
+
+void AudioSrtpSession::initializeRemoteCryptoContext(void)
+{
+
+    _remoteCryptoCtx = new ost::CryptoContext(0x0,
+					     0,                           // roc,
+					     0L,                          // keydr,
+					     SrtpEncryptionAESCM,         // encryption algo
+					     SrtpAuthenticationSha1Hmac,  // authtication algo
+					     _remoteMasterKey,            // Master Key
+					     _remoteMasterKeyLength,      // Master Key length
+					     _remoteMasterSalt,           // Master Salt
+					     _remoteMasterSaltLength,     // Master Salt length
+					     128 / 8,                     // encryption keyl
+					     160 / 8,                     // authentication key len
+					     112 / 8,                     // session salt len
+					     80 / 8);                     // authentication tag len
+
+    
+}
+
+void AudioSrtpSession::initializeLocalCryptoContext(void)
+{
+
+    _localCryptoCtx = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(),
+					      0,                           // roc,
+					      0L,                          // keydr,
+					      SrtpEncryptionAESCM,         // encryption algo
+					      SrtpAuthenticationSha1Hmac,  // authtication algo
+					      _localMasterKey,             // Master Key
+					      _localMasterKeyLength,       // Master Key length
+					      _localMasterSalt,            // Master Salt
+					      _localMasterSaltLength,      // Master Salt length
+					      128 / 8,                     // encryption keyl
+					      160 / 8,                     // authentication key len
+					      112 / 8,                     // session salt len
+					      80 / 8);                     // authentication tag len
+
+
+}
+
+
+char* AudioSrtpSession::encodeBase64(unsigned char *input, int length)
+{
+    BIO *b64, *bmem;
+    BUF_MEM *bptr ;
+
+    char *buffer = (char *)malloc(2*length);
+    memset(buffer, 0, 2*length);
+
+    // 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);
+
+    // copy result in output buffer (-1 since we do not want the EOF character)
+    strncpy(buffer, (char*)(bptr->data), bptr->length);
+
+    BIO_free_all(bmem);
+
+    return buffer;    
+}
+
+char* AudioSrtpSession::decodeBase64(unsigned char *input, int length, int *length_out)
+{
+    BIO *b64, *bmem;
+
+    char *buffer = (char *)malloc(length);
+    memset(buffer, 0, length);
+
+    // 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);
+
+    *length_out = BIO_read(bmem, buffer, length);
+
+    BIO_free_all(bmem);
+
+    return buffer;
+
+}
+
+}
diff --git a/sflphone-common/src/audio/audiortp/AudioSrtpSession.h b/sflphone-common/src/audio/audiortp/AudioSrtpSession.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e94a62baedf636d46dc21f8ee47513ec54e9aa8
--- /dev/null
+++ b/sflphone-common/src/audio/audiortp/AudioSrtpSession.h
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
+ *
+ *  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 3 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.
+ */
+#ifndef __SFL_AUDIO_SRTP_SESSION_H__
+#define __SFL_AUDIO_SRTP_SESSION_H__
+
+#include "AudioRtpSession.h"
+#include "sip/SdesNegotiator.h"
+
+#include <ccrtp/CryptoContext.h>
+
+class SdesNegotiator;
+class ManagerImpl;
+class SIPCall;
+
+/* 
+   Table from RFC 4568 6.2. Crypto-Suites, which define key parameters for supported 
+   cipher suite
+
+   +---------------------+-------------+--------------+---------------+
+   |                     |AES_CM_128_  | AES_CM_128_  | F8_128_       |
+   |                     |HMAC_SHA1_80 | HMAC_SHA1_32 |  HMAC_SHA1_80 |
+   +---------------------+-------------+--------------+---------------+
+   | Master key length   |   128 bits  |   128 bits   |   128 bits    |
+   | Master salt length  |   112 bits  |   112 bits   |   112 bits    |
+   | SRTP lifetime       | 2^48 packets| 2^48 packets | 2^48 packets  |
+   | SRTCP lifetime      | 2^31 packets| 2^31 packets | 2^31 packets  |
+   | Cipher              | AES Counter | AES Counter  | AES F8 Mode   |
+   |                     | Mode        | Mode         |               |
+   | Encryption key      |   128 bits  |   128 bits   |   128 bits    |
+   | MAC                 |  HMAC-SHA1  |  HMAC-SHA1   |  HMAC-SHA1    |
+   | SRTP auth. tag      |    80 bits  |    32 bits   |    80 bits    |
+   | SRTCP auth. tag     |    80 bits  |    80 bits   |    80 bits    |
+   | SRTP auth. key len. |   160 bits  |   160 bits   |   160 bits    |
+   | SRTCP auth. key len.|   160 bits  |   160 bits   |   160 bits    |
+   +---------------------+-------------+--------------+---------------+
+*/
+
+
+namespace sfl {
+
+    class SrtpException: public std::exception
+    {
+        virtual const char* what() const throw()
+        {
+        return "ZRTP ZID initialization failed.";
+        }
+    };
+
+    class AudioSrtpSession : public ost::SymmetricRTPSession, public AudioRtpSession<AudioSrtpSession> 
+    {
+        public:
+
+            AudioSrtpSession(ManagerImpl * manager, SIPCall * sipcall);
+
+	    std::string getLocalCryptoInfo(void);
+
+	    void setRemoteCryptoInfo(sfl::SdesNegotiator& nego);
+
+        private:
+
+            void initializeLocalMasterKey(void);
+
+	    void initializeLocalMasterSalt(void);
+
+	    void initializeRemoteCryptoContext(void);
+
+	    void initializeLocalCryptoContext(void);
+
+	    std::string getBase64ConcatenatedKeys();
+
+	    void unBase64ConcatenatedKeys(std::string base64keys);
+
+	    char* encodeBase64(unsigned char *input, int length);
+
+	    char* decodeBase64(unsigned char *input, int length, int *length_out);
+
+	    /** Default local crypto suite is AES_CM_128_HMAC_SHA1_80*/
+	    int _localCryptoSuite;
+
+	    /** Remote crypto suite is initialized at AES_CM_128_HMAC_SHA1_80*/
+	    int _remoteCryptoSuite;
+
+            uint8 _localMasterKey[16];
+
+	    /** local master key length in byte */
+	    int _localMasterKeyLength;
+
+	    uint8 _localMasterSalt[14];
+
+	    /** local master salt length in byte */
+	    int _localMasterSaltLength;
+
+	    uint8 _remoteMasterKey[16];
+
+	    /** remote master key length in byte */
+	    int _remoteMasterKeyLength;
+
+	    uint8 _remoteMasterSalt[14];
+
+	    /** remote master salt length in byte */
+	    int _remoteMasterSaltLength;
+
+	    ost::CryptoContext* _remoteCryptoCtx;
+
+	    ost::CryptoContext* _localCryptoCtx;
+    };
+   
+}
+
+#endif // __AUDIO_SRTP_SESSION_H__
diff --git a/sflphone-common/src/audio/audiortp/Makefile.am b/sflphone-common/src/audio/audiortp/Makefile.am
index 502a17b9002aa0e0799d5219962d46cb05741f0c..d2ab3aaec714d9065241752748284fe4ea59a0c2 100644
--- a/sflphone-common/src/audio/audiortp/Makefile.am
+++ b/sflphone-common/src/audio/audiortp/Makefile.am
@@ -5,12 +5,14 @@ noinst_LTLIBRARIES = libaudiortp.la
 libaudiortp_la_SOURCES = \
 		AudioRtpFactory.cpp \
 		AudioZrtpSession.cpp \
-		ZrtpSessionCallback.cpp 
+		ZrtpSessionCallback.cpp \
+		AudioSrtpSession.cpp
 
 noinst_HEADERS = \
 		AudioRtpFactory.h \
 		AudioRtpSession.h \
 		AudioSymmetricRtpSession.h \
 		AudioZrtpSession.h \
-		ZrtpSessionCallback.h 
+		ZrtpSessionCallback.h \
+		AudioSrtpSession.h 
 
diff --git a/sflphone-common/src/hooks/urlhook.cpp b/sflphone-common/src/hooks/urlhook.cpp
index b50aa1febbf33ecaefc5d681f0d7330ffda035d8..3538602fb773a926d74162f49e9b8e6ff8942fe5 100644
--- a/sflphone-common/src/hooks/urlhook.cpp
+++ b/sflphone-common/src/hooks/urlhook.cpp
@@ -19,6 +19,7 @@
 
 #include "urlhook.h"
 #include <iostream>
+#include <vector>
 
 UrlHook::UrlHook () { }
 
@@ -28,9 +29,33 @@ int UrlHook::addAction (std::string field_value, std::string command)
 {
 
     std::string command_bg;
+	std::string temp;
+	std::vector <std::string> args;
+	size_t pos;
+	unsigned int i;
+
+	/* Escape the '&' char to not discard $_GET parameters in the URL - #2659 */ 
+	while ( (pos = field_value.find ("&", 0)) != std::string::npos) {
+        temp = field_value.substr (0, pos);
+        field_value.erase (0, pos + 1);
+		args.push_back (temp);
+		std::cout << temp << " " << std::endl;	
+	}
+
+    command_bg = command + " ";
+
+	pos = args.size ();
+	for (i=0; i<pos; i++) {
+		// Escape the "&"
+		command_bg += args[i] + "\\&";
+	}
+
+	// Retrieve the last argument
+	command_bg +=  field_value;
 
     /* Execute the command in the background to not block the application */
-    command_bg = command + " " + field_value + "&" ;
+	command_bg += "&";
+
     /* Execute a system call */
     return RUN_COMMAND (command_bg.c_str());
 
diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp
index 5fb236892e964303f8d13c537e3081d50662bd6d..1c87bb03c2dbaea8ae62578450df48cca7a4d6b6 100644
--- a/sflphone-common/src/managerimpl.cpp
+++ b/sflphone-common/src/managerimpl.cpp
@@ -3887,6 +3887,7 @@ ManagerImpl::addAccount (const std::map< std::string, std::string >& details)
 
     if (accountType == "SIP") {
         newAccount = AccountCreator::createAccount (AccountCreator::SIP_ACCOUNT, newAccountID);
+	newAccount->setVoIPLink();
     } else if (accountType == "IAX") {
         newAccount = AccountCreator::createAccount (AccountCreator::IAX_ACCOUNT, newAccountID);
     } else {
diff --git a/sflphone-common/src/sip/Makefile.am b/sflphone-common/src/sip/Makefile.am
index 778494b0b6874fdf3e723ee7838905830cfe2cbf..8cb4829edc3797aa8e107d2a2b8af0cdf87393ec 100644
--- a/sflphone-common/src/sip/Makefile.am
+++ b/sflphone-common/src/sip/Makefile.am
@@ -3,17 +3,23 @@ include $(top_srcdir)/globals.mak
 noinst_LTLIBRARIES = libsiplink.la
 
 libsiplink_la_SOURCES = \
+		Pattern.cpp \
+		SdesNegotiator.cpp \
 		sdp.cpp \
 		sdpmedia.cpp \
 		sipaccount.cpp \
 		sipcall.cpp \
-		sipvoiplink.cpp 
+		sipvoiplink.cpp
 
 
 noinst_HEADERS = \
+		Pattern.h \
+		SdesNegotiator.h \
 		sdp.h \
 		sdpmedia.h \
 		sipaccount.h \
 		sipcall.h \
 		sipvoiplink.h
 
+libsiplink_la_CXXFLAGS = \
+		@PCRE_LIBS@
\ No newline at end of file
diff --git a/sflphone-common/src/util/Pattern.cpp b/sflphone-common/src/sip/Pattern.cpp
similarity index 86%
rename from sflphone-common/src/util/Pattern.cpp
rename to sflphone-common/src/sip/Pattern.cpp
index 95186c5d689692cc30c1cf78d00e06e5aa66ebdb..71e093d13c96384877e71ca9ff65d721313a7e79 100644
--- a/sflphone-common/src/util/Pattern.cpp
+++ b/sflphone-common/src/sip/Pattern.cpp
@@ -23,8 +23,7 @@
 namespace sfl
 {
 
-namespace util {
-Pattern::Pattern (const std::string& pattern, const std::string& options = "") :
+Pattern::Pattern (const std::string& pattern, const std::string& options) :
         _pattern (pattern),
         _ovector (NULL),
         _ovectorSize (0),
@@ -32,6 +31,8 @@ Pattern::Pattern (const std::string& pattern, const std::string& options = "") :
         _count (0),
         _options (0)
 {
+
+    // printf("Pattern constructor called for %s!\n", pattern.c_str());
     // Set offsets
     _offset[0] = _offset[1] = 0;
 
@@ -125,7 +126,7 @@ std::vector<std::string> Pattern::groups (void)
 
     while (stringList[i] != NULL) {
         matchedSubstrings.push_back (stringList[i]);
-        printf ("Substr: <start>%s<end>", stringList[i]);
+        // printf ("Substr: <start>%s<end>", stringList[i]);
         i++;
     }
 
@@ -138,6 +139,8 @@ std::string Pattern::group (int groupNumber)
 {
     const char * stringPtr;
 
+    // printf("_subject.substr : %s\n", _subject.substr (_offset[0]).c_str());
+
     int rc = pcre_get_substring (
                  _subject.substr (_offset[0]).c_str(),
                  _ovector,
@@ -178,16 +181,22 @@ std::string Pattern::group (const std::string& groupName)
                  groupName.c_str(),
                  &stringPtr);
 
+    // printf("  _count : %i\n", _count);
+    // printf("stringPtr : %s\n", stringPtr);
+    
     if (rc < 0) {
         switch (rc) {
 
             case PCRE_ERROR_NOSUBSTRING:
+	        // printf("Pattern::PCRE_ERROR_NOSUBSTRING\n");
                 throw std::out_of_range ("Invalid group reference.");
 
             case PCRE_ERROR_NOMEMORY:
+	        // printf("Pattern::PCRE_ERROR_NOMEMORY\n");
                 throw match_error ("Memory exhausted.");
 
             default:
+	        // printf("Pattern::default match error\n");
                 throw match_error ("Failed to get named substring.");
         }
     }
@@ -241,13 +250,14 @@ size_t Pattern::end (void) const
 
 bool Pattern::matches (void) throw (match_error)
 {
-    matches (_subject);
+    return matches (_subject);
 }
 
 bool Pattern::matches (const std::string& subject) throw (match_error)
 {
-    //printf("Current offset: %d, old offset: %d", _offset[1], _offset[0]);
-    //printf("Trying <start>%s<end>", subject.substr(_offset[1]).c_str());
+    // printf("Pattern::matches\n");
+    // printf("  Current offset: %d, old offset: %d", _offset[1], _offset[0]);
+    // printf("  Trying <start>%s<end>\n", subject.substr(_offset[1]).c_str());
 
     // Try to find a match for this pattern
     int rc = pcre_exec (
@@ -264,7 +274,7 @@ bool Pattern::matches (const std::string& subject) throw (match_error)
 
     if (rc < 0) {
         _offset[0] = _offset[1] = 0;
-        //printf("Matching failed with %d", rc);
+        // printf("  Matching failed with %d\n", rc);
         return false;
     }
 
@@ -275,7 +285,7 @@ bool Pattern::matches (const std::string& subject) throw (match_error)
         _offset[1] =  _ovector[1] + _offset[0];
     }
 
-    //printf("Matching succeeded with %d to %d", (int) start(), (int) end());
+    // printf("  Matching succeeded with %d to %d\n", (int) start(), (int) end());
 
     // Matching succeded but not enough space.
     if (rc == 0) {
@@ -285,7 +295,8 @@ bool Pattern::matches (const std::string& subject) throw (match_error)
 
     // Matching succeeded. Keep the number of substrings for
     // subsequent calls to group().
-    _count = rc;
+    // printf("_count: %i = %i\n", _count, rc);
+      _count = rc;
 
     return true;
 }
@@ -301,14 +312,15 @@ std::vector<std::string> Pattern::split (void)
         tokenStart = start();
         substringSplitted.push_back (_subject.substr (tokenEnd + 1,
                                      tokenStart - tokenEnd - 1));
+	// printf("split: %s\n", _subject.substr (tokenEnd + 1,
+	// 					 tokenStart - tokenEnd - 1).c_str());
         tokenEnd = end();
     }
 
-    substringSplitted.push_back (_subject.substr (tokenEnd + 1,
+    substringSplitted.push_back (_subject.substr (tokenEnd + 1, tokenStart - tokenEnd - 1));
 
-                                 tokenStart - tokenEnd - 1));
     return substringSplitted;
 }
 }
-}
+
 
diff --git a/sflphone-common/src/sip/Pattern.h b/sflphone-common/src/sip/Pattern.h
new file mode 100644
index 0000000000000000000000000000000000000000..b07c92acddbfd4466710c83fb6ce7e40d38e1383
--- /dev/null
+++ b/sflphone-common/src/sip/Pattern.h
@@ -0,0 +1,339 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
+ *
+ *  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 3 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.
+ */
+#ifndef __SFL_PATTERN_H__
+#define __SFL_PATTERN_H__
+
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <pcre.h>
+
+namespace sfl  {
+
+    /** 
+     * Exception object that is thrown when
+     * an error occured while compiling the
+     * regular expression.
+     */
+    class compile_error : public std::invalid_argument 
+    {
+        public:     
+        explicit compile_error(const std::string& error) :  
+        std::invalid_argument(error) {}
+    };
+    
+    /** 
+     * Exception object that is thrown when
+     * an error occured while mathing a
+     * pattern to an expression.
+     */
+    class match_error : public std::invalid_argument      
+    {
+        public:     
+        match_error(const std::string& error) :
+        std::invalid_argument(error) {}
+    };
+	
+	 /**
+     * This class implements in its way
+     * some of the libpcre library.
+     */
+    
+    class Pattern {
+    
+        public:
+        
+        /**
+	 * Constructor for a regular expression
+	 * pattern evaluator/matcher. 
+	 *
+	 * @param pattern 
+	 *      The regular expression to 
+	 *      be used for this instance.
+	 */
+             
+         Pattern(const std::string& pattern, 
+		 const std::string& options = "");
+            
+	 /**
+	  * Destructor. Pcre pattern gets freed
+	  * here.
+	  */
+	 ~Pattern();
+            
+	 /**
+	  * Assignment operator overloading.
+	  * Set the regular expression 
+	  * to be used on subject strings
+	  * and compile the regular expression 
+	  * from that string. 
+	  * 
+	  * @param pattern The new pattern
+	  */
+	 void operator=(const std::string& pattern) {
+	     _pattern = pattern; 
+	     compile();            
+	 }
+            
+	 void operator=(const char * pattern) {
+	     _pattern = pattern; 
+	     compile();            
+	 }            
+              
+	 /**
+	  * Compile the regular expression
+	  * from the pattern that was set for 
+	  * this object.
+	  */
+	 void compile(void);
+             
+	 /**
+	  * Get the currently set regular expression 
+	  * that is used on subject strings
+	  * 
+	  * @return The currently set pattern
+	  */ 
+	 inline std::string getPattern(void) { return _pattern; }
+             
+	 /**
+	  * << operator overload. Sets the the subject
+	  * for latter use on the >> operator. 
+	  * 
+	  * @param subject 
+	  *      The expression to be evaluated
+	  *      by the pattern.
+	  *
+	  */
+	 void operator<<(const std::string& subject) {
+	     _subject = subject;
+	 }
+			
+	 /**
+	  * Get the start position of the overall match.
+	  * 
+	  * @return the start position of the overall match.  
+	  */
+	 size_t start(void) const;
+			
+	 /**
+	  * Get the start position of the specified match.
+	  * 
+	  * @param groupNumber The capturing group number.
+	  * 
+	  * @return the start position of the specified match.  
+	  */
+	 size_t start(unsigned int groupNumber) const;
+			
+	 /**
+	  * Get the start position of the specified match.
+	  * 
+	  * @param groupName The capturing group name.
+	  * 
+	  * @return the start position of the specified match.  
+	  */
+	 size_t start(const std::string& groupName) const;
+			
+	 /**
+	  * Get the end position of the overall match.
+	  * 
+	  * @return the end position of the overall match.  
+	  */			
+	 size_t end(void) const;
+			
+	 /**
+	  * Get the end position of the specified match.
+	  * 
+	  * @param groupNumber The capturing group number.
+	  * 
+	  * @return the end position of the specified match.  
+	  */			
+	 size_t end(unsigned int groupNumber) const;
+			
+	 /**
+	  * Get the end position of the specified match.
+	  * 
+	  * @param groupName The capturing group name.
+	  * 
+	  * @return the end position of the specified match.  
+	  */			
+	 size_t end(const std::string& groupName) const;
+			
+	 /**
+	  * Get the number of capturing groups in the 
+	  * compiled regex. 
+	  * 
+	  * @return The number of capture groups.
+	  * 
+	  * @pre The regular expression should have been 
+	  * 	    compiled prior to the execution of this method.
+	  */
+	 unsigned int getCaptureGroupCount(void);
+			
+	 /**
+	  * Get the substring matched in a capturing 
+	  * group (named or unnamed).
+	  *  
+	  * This methods only performs a basic lookup
+	  * inside its internal substring table. Thus,
+	  * matches() should have been called prior to 
+	  * this method in order to obtain the desired 
+	  * output. 
+	  *
+	  * @param groupName The name of the group  
+	  * 
+	  * @return the substring matched by the 
+	  *         regular expression designated
+	  *         the group name.
+	  */
+	 std::string group(const std::string& groupName);
+         
+	 /**
+	  * Get the substring matched in a named group.
+	  * 
+	  * This methods only performs a basic lookup
+	  * inside its internal substring table. Thus,
+	  * matches() should have been called prior to 
+	  * this method in order to obtain the desired 
+	  * output. 
+	  * 
+	  * @param groupNumber The number of the group. 
+	  * 
+	  * @return the substring matched by the 
+	  *         regular expression designated
+	  *         the group number.
+	  */
+	 std::string group(int groupNumber);
+	 
+	 /**
+	  * Similar to python's MatchObject.groups. Get all 
+	  * the substrings matched by the capture groups defined
+	  * in the pattern. The complete (implicit) capture group
+	  * is not returned : ie only groups from 1 up to the number
+	  * of groups in the pattern are returned.
+	  * 
+	  * @return A vector of stings that were matched by some
+	  * 		   capturing group in the pattern.
+	  * 
+	  * @pre The regular expression should have been 
+	  * 	    compiled prior to the execution of this method.
+	  */
+	 std::vector<std::string> groups(void);
+	 
+	 /**
+	  * Try to match the compiled pattern with a 
+	  * subject. 
+	  * 
+	  * @param subject Subject to be matched
+	  * 		          by the pattern. 
+	  * 
+	  * @return true If the subject matches the pattern, 
+	  *         false otherwise. 
+	  * 
+	  * @pre The regular expression should have been 
+	  * 	    compiled prior to the execution of this method.
+	  * 
+	  * @post The internal substring table will be updated
+	  *       with the new matches. Therefore, subsequent
+	  * 		 calls to group may return different results.
+	  */
+	 bool matches(const std::string& subject) throw(match_error);
+	 
+	 /**
+	  * Try to match the compiled pattern with the implicit 
+	  * subject. 
+	  * 
+	  * @return true If the subject matches the pattern, 
+	  *         false otherwise. 
+	  * 
+	  * @pre The regular expression should have been 
+	  * 	    compiled prior to the execution of this method.
+	  * 
+	  * @post The internal substring table will be updated
+	  *       with the new matches. Therefore, subsequent
+	  * 		 calls to group may return different results.
+	  */
+	 bool matches(void) throw(match_error); 	
+	 
+	 /**
+	  *  Split the subject into a list of substrings.
+	  * 
+	  * @return A vector of substrings. 
+	  * 
+	  * @pre The regular expression should have been 
+	  * 	    compiled prior to the execution of this method.
+	  * 
+	  * @post The internal subject won't be affected by this 
+	  * 	     by this operation. In other words: subject_before =
+	  * 		 subject_after.
+	  */
+	 std::vector<std::string> split(void); // throw(match_error);		
+
+    private:  
+	 /**
+	  * The regular expression that represents that pattern.
+	  */
+	 std::string _pattern;
+	 
+	 /** 
+	  * The optional subject string.
+	  */
+	 std::string _subject;
+	 
+	 /**
+	  * PCRE struct that
+	  * contains the compiled regular
+	  * expression
+            */
+	 pcre * _re;
+	 
+	 /**
+	  * The internal output vector used by PCRE. 
+	  */
+	 int * _ovector;
+	 
+	 /**
+	  * The size of the _ovector
+	  */
+	 int _ovectorSize;
+			
+	 /**
+	  * Current offset in the _ovector;
+	  */
+	 
+	 int _offset[2];
+	 
+	 /**
+	  * The number of substrings matched after calling
+	  * pcre_exec.
+	  */ 
+	 int _count;
+	 
+	 /**
+	  * PCRE options for this pattern.
+	  */
+	 int _options;
+	 
+	 /**
+	  * String representation of the options.
+	  */
+	 std::string _optionsDescription;
+    };
+}
+
+
+#endif
diff --git a/sflphone-common/src/sip/SdesNegotiator.cpp b/sflphone-common/src/sip/SdesNegotiator.cpp
index 74442abafee1aa5ca51b69cfec6e85c31f308b73..e8618e3ab8d80f0bfb9b13fc5205cda5c847c869 100644
--- a/sflphone-common/src/sip/SdesNegotiator.cpp
+++ b/sflphone-common/src/sip/SdesNegotiator.cpp
@@ -18,14 +18,15 @@
 
 #include "SdesNegotiator.h"
 
-#include "util/Pattern.h"
+#include "Pattern.h"
 
+#include <cstdio>
 #include <iostream>
 #include <sstream>
 #include <algorithm>
 #include <stdexcept>
 
-using namespace sfl::util;
+using namespace sfl;
 
 struct CryptoAttribute {
     std::string tag;
@@ -58,9 +59,12 @@ void SdesNegotiator::parse (void)
     * sessionParamPattern;
 
     try {
+
+        // used to match white space (which are used as separator) 
         generalSyntaxPattern = new Pattern ("[\x20\x09]+", "g");
 
-        tagPattern = new Pattern ("^a=crypto:(?P<tag>[0-9]{1,9})");
+        tagPattern = new Pattern ("^a=crypto:(?P<tag>[0-9]{1,9})", "g");
+	// tagPattern = new Pattern ("[0-9]");
 
         cryptoSuitePattern = new Pattern (
             "(?P<cryptoSuite>AES_CM_128_HMAC_SHA1_80|" \
@@ -81,7 +85,7 @@ void SdesNegotiator::parse (void)
             "UNENCRYPTED_SRTCP|" \
             "UNAUTHENTICATED_SRTP|" \
             "FEC_ORDER=(?P<fecOrder>FEC_SRTP|SRTP_FEC)|" \
-            "FEC_KEY=(?P<fecKey>" + keyParamsPattern.getPattern() + ")|" \
+            "FEC_KEY=(?P<fecKey>" + keyParamsPattern->getPattern() + ")|" \
             "WSH=(?P<wsh>[0-9]{1,2})|" \
             "(?<!\\-)[[:graph:]]+))*", "g"); // srtp-session-extension
 
@@ -89,10 +93,12 @@ void SdesNegotiator::parse (void)
         throw parse_error ("A compile exception occured on a pattern.");
 
     }
+      
 
     // Take each line from the vector
     // and parse its content
 
+    
     std::vector<std::string>::iterator iter;
 
     for (iter = _remoteAttribute.begin(); iter != _remoteAttribute.end(); iter++) {
@@ -101,12 +107,13 @@ void SdesNegotiator::parse (void)
 
         // Split the line into its component
         // that we will analyze further down.
-
-        generalSyntaxPattern << (*iter);
-        std::vector<std::string> sdesLine;
-
+	std::vector<std::string> sdesLine;
+	
+        *generalSyntaxPattern << (*iter);
+        
+	
         try {
-            sdesLine = generalSyntaxPattern.split();
+            sdesLine = generalSyntaxPattern->split();
 
             if (sdesLine.size() < 3) {
                 throw parse_error ("Missing components in SDES line");
@@ -114,13 +121,16 @@ void SdesNegotiator::parse (void)
         } catch (match_error& exception) {
             throw parse_error ("Error while analyzing the SDES line.");
         }
+	
 
         // Check if the attribute starts with a=crypto
         // and get the tag for this line
-        tagPattern << sdesLine.at (0);
+        *tagPattern << sdesLine.at (0);
+
+	tagPattern->matches();
 
         try {
-            std::string tag = tagPattern.group ("tag");
+            std::string tag = tagPattern->group ("tag");
             std::cout << "tag = " << tag << std::endl;
         } catch (match_error& exception) {
             throw parse_error ("Error while parsing the tag field");
@@ -128,40 +138,37 @@ void SdesNegotiator::parse (void)
 
         // Check if the crypto suite is valid and retreive
         // its value.
-        cryptoSuitePattern << sdesLine.at (1);
+        *cryptoSuitePattern << sdesLine.at (1);
+
+	cryptoSuitePattern->matches();
 
         try {
-            std::string cryptoSuite
-            cryptoSuite = cryptoSuitePattern.group ("cryptoSuite");
-            std::cout << "crypto-suite = " << cryptoSuite << std::endl;
+            _cryptoSuite = cryptoSuitePattern->group ("cryptoSuite");
+            std::cout << "crypto-suite = " << _cryptoSuite << std::endl;
         } catch (match_error& exception) {
             throw parse_error ("Error while parsing the crypto-suite field");
         }
 
         // Parse one or more key-params field.
-        keyParamsPattern << sdesLine.at (2);
+        *keyParamsPattern << sdesLine.at (2);
 
         try {
-            while (keyParamsPattern.matches()) {
-                std::string srtpKeyMethod;
-                srtpKeyMethod = keyParamsMatched.group ("srtpKeyMethod");
-                std::cout << "srtp-key-method = " << srtpKeyMethod << std::endl;
-
-                std::string srtpKeyInfo;
-                srtpKeyInfo = keyParamsPattern.group ("srtpKeyInfo");
-                std::cout << "srtp-key-info = " << srtpKeyInfo << std::endl;
-
-                std::string lifetime;
-                lifetime = keyParamsPattern.group ("lifetime");
-                std::cout << "lifetime = " << lifetime << std::endl;
-
-                std::string mkiValue
-                mkiValue = keyParamsPattern.group ("mkiValue");
-                std::cout << "mkiValue = " << mkiValue << std::endl;
-
-                std::string mkiLength;
-                mkiLength = keyParamsPattern.group ("mkiLength");
-                std::cout << "mkiLength = " << mkiLength << std::endl;
+            while (keyParamsPattern->matches()) {
+                
+                _srtpKeyMethod = keyParamsPattern->group ("srtpKeyMethod");
+                std::cout << "srtp-key-method = " << _srtpKeyMethod << std::endl;
+
+                _srtpKeyInfo = keyParamsPattern->group ("srtpKeyInfo");
+                std::cout << "srtp-key-info = " << _srtpKeyInfo << std::endl;
+
+                _lifetime = keyParamsPattern->group ("lifetime");
+                std::cout << "lifetime = " << _lifetime << std::endl;
+
+                _mkiValue = keyParamsPattern->group ("mkiValue");
+                std::cout << "mkiValue = " << _mkiValue << std::endl;
+
+                _mkiLength = keyParamsPattern->group ("mkiLength");
+                std::cout << "mkiLength = " << _mkiLength << std::endl;
             }
         } catch (match_error& exception) {
             throw parse_error ("Error while parsing the key-params field");
@@ -192,4 +199,6 @@ void SdesNegotiator::parse (void)
 bool SdesNegotiator::negotiate (void)
 {
     parse();
+
+    return true;
 }
diff --git a/sflphone-common/src/sip/SdesNegotiator.h b/sflphone-common/src/sip/SdesNegotiator.h
index 2dded5b1a7582002646dc07451ca8e8bb40fb107..08e32090ef5e64b5731f2fab2ace701135414fc0 100644
--- a/sflphone-common/src/sip/SdesNegotiator.h
+++ b/sflphone-common/src/sip/SdesNegotiator.h
@@ -97,9 +97,38 @@ namespace sfl {
             SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites, const std::vector<std::string>& remoteAttribute);
             ~SdesNegotiator() { };
             
-        public:
             bool negotiate(void);
 
+	    /**
+	     * Return crypto suite after negotiation
+	     */
+	    std::string getCryptoSuite(void) { return _cryptoSuite; }
+
+	    /**
+	     * Return key method after negotiation (most likely inline:)
+	     */
+	    std::string getKeyMethod(void) { return _srtpKeyMethod; }
+
+	    /**
+	     * Return crypto suite after negotiation
+	     */
+	    std::string getKeyInfo(void) { return _srtpKeyInfo; }
+
+	    /**
+	     * Return key lifetime after negotiation
+	     */
+	    std::string getLifeTime(void) { return _lifetime; }
+
+	    /**
+	     * Return mki value after negotiation
+	     */
+	    std::string getMkiValue(void) { return _mkiValue; }
+
+	    /**
+	     * Return mki length after negotiation
+	     */
+	    std::string getMkiLength(void) { return _mkiLength; }
+
         private:
             /**
              * A vector list containing the remote attributes.
@@ -107,12 +136,41 @@ namespace sfl {
              * prefered method is then chosen from that list.
              */
             std::vector<std::string> _remoteAttribute;
+
             std::vector<CryptoSuiteDefinition> _localCapabilities;
-            
 
+	    /**
+	     * Selected crypto suite after negotiation
+	     */
+	    std::string _cryptoSuite;
 
-        private:
+	    /**
+	     * Selected key method after negotiation (most likely inline:)
+	     */
+	    std::string _srtpKeyMethod;
+
+	    /**
+	     * Selected crypto suite after negotiation
+	     */
+	    std::string _srtpKeyInfo;
+
+	    /**
+	     * Selected key lifetime after negotiation
+	     */
+	    std::string _lifetime;
+
+	    /**
+	     * Selected mki value after negotiation
+	     */
+	    std::string _mkiValue;
+
+	    /**
+	     * Selected mki length after negotiation
+	     */
+	    std::string _mkiLength;
+            
             void parse(void);
+
             CryptoAttribute * tokenize(const std::string& attributeLine);
     };
 }
diff --git a/sflphone-common/src/sip/sdp.cpp b/sflphone-common/src/sip/sdp.cpp
index 1d60ce41f79f1d80736263d4af75f3455c996419..a18d82fb4709fff054fffa3abc7025658f3eb98f 100644
--- a/sflphone-common/src/sip/sdp.cpp
+++ b/sflphone-common/src/sip/sdp.cpp
@@ -32,6 +32,7 @@ static const pj_str_t STR_RTP_AVP = { (char*) "RTP/AVP", 7 };
 static const pj_str_t STR_SDP_NAME = { (char*) "sflphone", 8 };
 static const pj_str_t STR_SENDRECV = { (char*) "sendrecv", 8 };
 static const pj_str_t STR_RTPMAP = { (char*) "rtpmap", 6 };
+static const pj_str_t STR_CRYPTO = { (char*) "crypto", 6 };
 
 
 Sdp::Sdp (pj_pool_t *pool)
@@ -115,8 +116,6 @@ void Sdp::set_media_descriptor_line (sdpMedia *media, pjmedia_sdp_media** p_med)
         _warn ("No hash specified");
     }
 
-    sdp_add_sdes_attribute (med);
-
     *p_med = med;
 }
 
@@ -143,6 +142,12 @@ int Sdp::create_local_offer (CodecOrder selectedCodecs) {
     sdp_add_timing();
     sdp_add_media_description();
 
+    if(!_srtp_crypto.empty()) {
+        sdp_add_sdes_attribute(_srtp_crypto);
+    }
+
+    //toString ();
+
     // Validate the sdp session
     status = pjmedia_sdp_validate (this->_local_offer);
 
@@ -190,8 +195,6 @@ int Sdp::receiving_initial_offer (pjmedia_sdp_session* remote, CodecOrder select
 
     pj_status_t status;
 
-    _debug ("Receiving initial offer");
-
     // Create the SDP negociator instance by calling
     // pjmedia_sdp_neg_create_w_remote_offer with the remote offer, and by providing the local offer ( optional )
 
@@ -346,31 +349,29 @@ void Sdp::sdp_add_media_description()
 }
 
 
-void Sdp::sdp_add_sdes_attribute (pjmedia_sdp_media* media)
+void Sdp::sdp_add_sdes_attribute (std::string crypto)
 {
 
+    // temporary buffer used to store crypto attribute
     char tempbuf[256];
 
-    std::string tag = "1";
-    std::string crypto_suite = "AES_CM_128_HMAC_SHA1_32";
-    std::string application = "srtp";
-    std::string key = "inline:16/14/NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj/2^20/1:32";
-
+    // the attribute to add to sdp
     pjmedia_sdp_attr *attribute = (pjmedia_sdp_attr*) pj_pool_zalloc(_pool, sizeof(pjmedia_sdp_attr));
 
     attribute->name = pj_strdup3(_pool, "crypto");
 
-    int len = pj_ansi_snprintf(tempbuf, sizeof(tempbuf),
-			       "%.*s %.*s %.*s",
-			       (int)tag.size(), tag.c_str(),
-			       (int)crypto_suite.size(), crypto_suite.c_str(),
-			       (int)key.size(), key.c_str());
+    // _debug("crypto from sdp: %s", crypto.c_str());
 
+    
+    int len = pj_ansi_snprintf(tempbuf, sizeof(tempbuf),
+			       "%.*s",(int)crypto.size(), crypto.c_str());
+ 
     attribute->value.slen = len;
     attribute->value.ptr = (char*) pj_pool_alloc (_pool, attribute->value.slen+1);
     pj_memcpy (attribute->value.ptr, tempbuf, attribute->value.slen+1);
 
-    if(pjmedia_sdp_media_add_attr(media, attribute) != PJ_SUCCESS) {
+    // add crypto attribute to sdp session
+    if(pjmedia_sdp_attr_add(&(_local_offer->attr_count), _local_offer->attr, attribute) != PJ_SUCCESS){
         throw sdpException();
     }
 
@@ -622,12 +623,8 @@ void Sdp::set_media_transport_info_from_remote_sdp (const pjmedia_sdp_session *r
 
     pjmedia_sdp_media *r_media;
 
-    pjmedia_sdp_attr *attribute;
-
     this->get_remote_sdp_media_from_offer (remote_sdp, &r_media);
 
-    // this->get_remote_sdp_crypto_from_offer()
-
     if (r_media==NULL) {
         _debug ("SDP Failure: no remote sdp media found in the remote offer");
         return;
@@ -636,6 +633,7 @@ void Sdp::set_media_transport_info_from_remote_sdp (const pjmedia_sdp_session *r
     this->set_remote_audio_port_from_sdp (r_media);
 
     this->set_remote_ip_from_sdp (remote_sdp);
+
 }
 
 void Sdp::get_remote_sdp_media_from_offer (const pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media** r_media)
@@ -653,18 +651,45 @@ void Sdp::get_remote_sdp_media_from_offer (const pjmedia_sdp_session* remote_sdp
     }
 }
 
-void Sdp::get_remote_sdp_crypto_from_offer (const pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media** r_crypto)
+void Sdp::get_remote_sdp_crypto_from_offer (const pjmedia_sdp_session* remote_sdp, CryptoOffer& crypto_offer)
 {
-    int count, i;
 
-    count = remote_sdp->media_count;
-    *r_crypto =  NULL;
+    int i;
+    int attr_count;
+    pjmedia_sdp_attr *attribute;
 
-    for (i = 0; i < count; ++i) {
-        if (pj_stricmp2 (&remote_sdp->media[i]->desc.media, "crypto") == 0) {
-            *r_crypto = remote_sdp->media[i];
-            return;
+    // get the number of attribute for this sdp session
+    attr_count = remote_sdp->attr_count;
+
+    // *r_crypto= pjmedia_sdp_media_find_attr(attribute, &STR_CRYPTO, NULL);
+
+    _debug("****************** Parse for Crypto %i ********************", attr_count);
+
+    CryptoOffer remoteOffer;
+
+    // iterate over all atribute
+    for (i = 0; i < attr_count; ++i) {
+
+        _debug("%.*s", (int)remote_sdp->attr[i]->name.slen, remote_sdp->attr[i]->name.ptr);
+	_debug("%.*s", (int)remote_sdp->attr[i]->value.slen, remote_sdp->attr[i]->value.ptr);
+
+	// test if this attribute is a crypto
+        if (pj_stricmp2 (&remote_sdp->attr[i]->name, "crypto") == 0) {
+
+	    attribute = remote_sdp->attr[i];
+
+	    _debug("****************** Found a Crypto ********************");
+	    std::string attr(attribute->value.ptr, attribute->value.slen);
+
+	    // @TODO our parser require the "acrypto:" to be present
+	    std::string full_attr = "a=crypto:";
+	    full_attr += attr;
+
+	    crypto_offer.push_back(full_attr);
         }
     }
+
+    _debug("****************** Did not Found any Crypto ********************");
+    
 }
 
diff --git a/sflphone-common/src/sip/sdp.h b/sflphone-common/src/sip/sdp.h
index 7d10c4722bf5547fa0a42b184ca4b3e2d32da64a..1e0a40db2b5ac74ac074f36e4303a4366d485c16 100644
--- a/sflphone-common/src/sip/sdp.h
+++ b/sflphone-common/src/sip/sdp.h
@@ -29,6 +29,7 @@
 #include <pjmedia/errno.h>
 #include <pj/pool.h>
 #include <pj/assert.h>
+#include <vector>
 
 #include "audio/codecs/codecDescriptor.h"
 #include "sdpmedia.h"
@@ -43,6 +44,8 @@ class sdpException: public std::exception
   }
 };
 
+typedef std::vector<std::string> CryptoOffer;
+
 class Sdp {
 
     public:
@@ -101,6 +104,11 @@ class Sdp {
          * @param hash The hello hash of a rtp session. (Only audio at the moment)
          */
         inline void set_zrtp_hash(const std::string& hash) { _zrtp_hello_hash = hash; _debug("Zrtp hash set with %s\n", hash.c_str()); }
+
+	/* Set the srtp _master_key
+         * @param mk The Master Key of a srtp session.
+         */
+        inline void set_srtp_crypto(const std::string& mk) { _srtp_crypto = mk; }
         
         /*
          * On building an invite outside a dialog, build the local offer and create the
@@ -213,6 +221,8 @@ class Sdp {
 
         std::vector<sdpMedia*> get_session_media_list (void) { return _session_media; }
 
+	void get_remote_sdp_crypto_from_offer (const pjmedia_sdp_session* remote_sdp, CryptoOffer& crypto_offer);
+
     private:
         /** Codec Map */
         std::vector<sdpMedia*> _local_media_cap;
@@ -246,7 +256,10 @@ class Sdp {
         /** Remote's audio port */
         unsigned int _remote_audio_port;
 
-        std::string _zrtp_hello_hash; 
+        std::string _zrtp_hello_hash;
+
+	/** "a=crypto" sdes attribute obtained from AudioSrtpSession */
+	std::string _srtp_crypto;
         
         Sdp(const Sdp&); //No Copy Constructor
         Sdp& operator=(const Sdp&); //No Assignment Operator
@@ -336,15 +349,13 @@ class Sdp {
 
         void get_remote_sdp_media_from_offer (const pjmedia_sdp_session* r_sdp, pjmedia_sdp_media** r_media);
 
-	void get_remote_sdp_crypto_from_offer (const pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media** r_crypto);
-
 	
 	/* 
          * Adds a sdes attribute to the given media section.
          *
          * @param media The media to add the srtp attribute to 
 	 */
-	void sdp_add_sdes_attribute(pjmedia_sdp_media* media);
+	void sdp_add_sdes_attribute(std::string crypto);
 
         /* 
          * Adds a zrtp-hash  attribute to 
diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp
index 5d78a1f2ee5be34bb6812238c7b5d38ea9dc561f..ae7826fdf947f5905df37d36d0a09d987c96e4e3 100644
--- a/sflphone-common/src/sip/sipvoiplink.cpp
+++ b/sflphone-common/src/sip/sipvoiplink.cpp
@@ -28,6 +28,7 @@
 #include "sipcall.h"
 #include "sipaccount.h"
 #include "eventthread.h"
+#include "SdesNegotiator.h"
 
 #include "dbus/dbusmanager.h"
 #include "dbus/callmanager.h"
@@ -807,11 +808,13 @@ SIPVoIPLink::answer (const CallID& id)
 
     local_sdp = call->getLocalSDP();
 
+    /*
     try {
         call->getAudioRtp()->initAudioRtpSession (call);
     } catch (...) {
         _debug ("Failed to create rtp thread from answer");
     }
+    */
 
     inv_session = call->getInvSession();
 
@@ -1559,7 +1562,6 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to)
         setCallAudioLocal (call, localAddress);
 
         _debug ("toUri received in new_ip_to_ip call %s", to.c_str());
-
         std::string toUri = account->getToUri (to);
         call->setPeerNumber (toUri);
         _debug ("toUri in new_ip_to_ip call %s", toUri.c_str());
@@ -1567,12 +1569,18 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to)
         call->getLocalSDP()->set_ip_address (addrSdp);
         call->getLocalSDP()->create_initial_offer (account->getActiveCodecs ());
 
-        try {
+	// Audio Rtp Session must be initialized before creating initial offer in SDP session
+	// since SDES require crypto attribute.
+	try {
             call->getAudioRtp()->initAudioRtpSession (call);
         } catch (...) {
             _debug ("! SIP Failure: Unable to create RTP Session  in SIPVoIPLink::new_ip_to_ip_call (%s:%d)", __FILE__, __LINE__);
         }
 
+        // Building the local SDP offer
+        call->getLocalSDP()->set_ip_address (addrSdp);
+        call->getLocalSDP()->create_initial_offer();
+
         // If no account already set, use the default one created at pjsip initialization
         if (account->getAccountTransport() == NULL) {
             _debug ("No transport for this account, using the default one");
@@ -2948,6 +2956,7 @@ void set_voicemail_info (AccountID account, pjsip_msg_body *body)
 
 void SIPVoIPLink::handle_reinvite (SIPCall *call)
 {
+    /*
     // Close the previous RTP session
     call->getAudioRtp()->stop ();
     call->setAudioStart (false);
@@ -2959,6 +2968,12 @@ void SIPVoIPLink::handle_reinvite (SIPCall *call)
     } catch (...) {
         _debug ("! SIP Failure: Unable to create RTP Session (%s:%d)", __FILE__, __LINE__);
     }
+    */
+    _debug("******************************************");
+    _debug("*             handle_reinvite            *");
+    _debug("******************************************");
+
+    call->getAudioRtp()->updateDestinationIpAddress();
 }
 
 // This callback is called when the invite session state has changed
@@ -3210,6 +3225,30 @@ void call_on_media_update (pjsip_inv_session *inv, pj_status_t status)
     // Set remote ip / port
     call->getLocalSDP()->set_media_transport_info_from_remote_sdp (remote_sdp);
 
+    // Get the crypto attribute containing srtp's cryptographic context (keys, cipher)
+    CryptoOffer crypto_offer;
+    call->getLocalSDP()->get_remote_sdp_crypto_from_offer(remote_sdp, crypto_offer);
+
+    if(!crypto_offer.empty()) {
+
+        _debug("Crypto attribute in SDP: init Srtp session");
+
+	// init local cryptografic capabilities for negotiation
+	std::vector<sfl::CryptoSuiteDefinition>localCapabilities;
+	for(int i = 0; i < 3; i++) {
+	    localCapabilities.push_back(sfl::CryptoSuites[i]);
+	}
+
+	sfl::SdesNegotiator sdesnego(localCapabilities, crypto_offer);
+	
+	if(sdesnego.negotiate()) {
+	    _debug("SDES negociation successfull \n");
+
+	    call->getAudioRtp()->setRemoteCryptoInfo(sdesnego);
+	}
+
+    }
+
     try {
         call->setAudioStart (true);
         call->getAudioRtp()->start();
@@ -3592,6 +3631,12 @@ mod_on_rx_request (pjsip_rx_data *rdata)
     // We retrieve the remote sdp offer in the rdata struct to begin the negociation
     call->getLocalSDP()->set_ip_address (addrSdp);
 
+    try {
+        call->getAudioRtp()->initAudioRtpSession (call);
+    } catch (...) {
+        _debug ("Failed to create rtp thread from answer");
+    }
+
     get_remote_sdp_from_offer (rdata, &r_sdp);
 
     status = call->getLocalSDP()->receiving_initial_offer (r_sdp, account->getActiveCodecs ());
diff --git a/sflphone-common/src/util/Pattern.h b/sflphone-common/src/util/Pattern.h
deleted file mode 100644
index 676ecbd85ef966cdff2456b45ad03b3102aca18b..0000000000000000000000000000000000000000
--- a/sflphone-common/src/util/Pattern.h
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- *  Copyright (C) 2009 Savoir-Faire Linux inc.
- *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
- *
- *  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 3 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.
- */
-#ifndef __SFL_PATTERN_H__
-#define __SFL_PATTERN_H__
-
-#include <stdexcept>
-#include <string>
-#include <vector>
-#include <pcre.h>
-
-namespace sfl  {
-namespace util {
-	/** 
-     * Exception object that is thrown when
-     * an error occured while compiling the
-     * regular expression.
-     */
-    class compile_error : public std::invalid_argument 
-    {
-        public:     
-        explicit compile_error(const std::string& error) :  
-        std::invalid_argument(error) {}
-    };
-    
-    /** 
-     * Exception object that is thrown when
-     * an error occured while mathing a
-     * pattern to an expression.
-     */
-    class match_error : public std::invalid_argument      
-    {
-        public:     
-        match_error(const std::string& error) :
-        std::invalid_argument(error) {}
-    };
-	
-	 /**
-     * This class implements in its way
-     * some of the libpcre library.
-     */
-    
-    class Pattern {
-    
-        public:
-        
-            /**
-             * Constructor for a regular expression
-             * pattern evaluator/matcher. 
-             *
-             * @param pattern 
-             *      The regular expression to 
-             *      be used for this instance.
-             */
-             
-            Pattern(const std::string& pattern, 
-			        const std::string& options);
-            
-			/**
-			 * Destructor. Pcre pattern gets freed
-			 * here.
-			 */
-            ~Pattern();
-            
-            /**
-             * Assignment operator overloading.
-             * Set the regular expression 
-             * to be used on subject strings
-             * and compile the regular expression 
-             * from that string. 
-             * 
-             * @param pattern The new pattern
-             */
-            void operator=(const std::string& pattern) {
-                _pattern = pattern; 
-                compile();            
-            }
-            
-            void operator=(const char * pattern) {
-                _pattern = pattern; 
-                compile();            
-            }            
-              
-            /**
-             * Compile the regular expression
-             * from the pattern that was set for 
-             * this object.
-             */
-            void compile(void);
-             
-            /**
-             * Get the currently set regular expression 
-             * that is used on subject strings
-             * 
-             * @return The currently set pattern
-             */ 
-            inline std::string getPattern(void) { return _pattern; }
-             
-            /**
-             * << operator overload. Sets the the subject
-             * for latter use on the >> operator. 
-             * 
-             * @param subject 
-             *      The expression to be evaluated
-             *      by the pattern.
-             *
-             */
-            void operator<<(const std::string& subject) {
-                _subject = subject;
-            }
-			
-			/**
-			 * Get the start position of the overall match.
-			 * 
-			 * @return the start position of the overall match.  
-			 */
-			size_t start(void) const;
-			
-			/**
-			 * Get the start position of the specified match.
-			 * 
-			 * @param groupNumber The capturing group number.
-			 * 
-			 * @return the start position of the specified match.  
-			 */
-			size_t start(unsigned int groupNumber) const;
-			
-			/**
-			 * Get the start position of the specified match.
-			 * 
-			 * @param groupName The capturing group name.
-			 * 
-			 * @return the start position of the specified match.  
-			 */
-			size_t start(const std::string& groupName) const;
-			
-			/**
-			 * Get the end position of the overall match.
-			 * 
-			 * @return the end position of the overall match.  
-			 */			
-			size_t end(void) const;
-			
-			/**
-			 * Get the end position of the specified match.
-			 * 
-			 * @param groupNumber The capturing group number.
-			 * 
-			 * @return the end position of the specified match.  
-			 */			
-			size_t end(unsigned int groupNumber) const;
-			
-			/**
-			 * Get the end position of the specified match.
-			 * 
-			 * @param groupName The capturing group name.
-			 * 
-			 * @return the end position of the specified match.  
-			 */			
-			size_t end(const std::string& groupName) const;
-			
-			/**
-			 * Get the number of capturing groups in the 
-			 * compiled regex. 
-			 * 
-			 * @return The number of capture groups.
-			 * 
-			 * @pre The regular expression should have been 
-			 * 	    compiled prior to the execution of this method.
-			 */
-			unsigned int getCaptureGroupCount(void);
-			
-            /**
-             * Get the substring matched in a capturing 
-			 * group (named or unnamed).
-			 *  
-			 * This methods only performs a basic lookup
-			 * inside its internal substring table. Thus,
-			 * matches() should have been called prior to 
-			 * this method in order to obtain the desired 
-			 * output. 
-             *
-             * @param groupName The name of the group  
-			 * 
-             * @return the substring matched by the 
-             *         regular expression designated
-             *         the group name.
-             */
-            std::string group(const std::string& groupName);
-            
-			/**
-             * Get the substring matched in a named group.
-			 * 
-			 * This methods only performs a basic lookup
-			 * inside its internal substring table. Thus,
-			 * matches() should have been called prior to 
-			 * this method in order to obtain the desired 
-			 * output. 
-			 * 
-             * @param groupNumber The number of the group. 
-			 * 
-             * @return the substring matched by the 
-             *         regular expression designated
-             *         the group number.
-             */
-            std::string group(int groupNumber);
-			
-			/**
-			 * Similar to python's MatchObject.groups. Get all 
-			 * the substrings matched by the capture groups defined
-			 * in the pattern. The complete (implicit) capture group
-			 * is not returned : ie only groups from 1 up to the number
-			 * of groups in the pattern are returned.
-			 * 
-			 * @return A vector of stings that were matched by some
-			 * 		   capturing group in the pattern.
-			 * 
-			 * @pre The regular expression should have been 
-			 * 	    compiled prior to the execution of this method.
-			 */
-			std::vector<std::string> groups(void);
-			
-			/**
-			 * Try to match the compiled pattern with a 
-			 * subject. 
-			 * 
-			 * @param subject Subject to be matched
-			 * 		          by the pattern. 
-			 * 
-			 * @return true If the subject matches the pattern, 
-			 *         false otherwise. 
-			 * 
-			 * @pre The regular expression should have been 
-			 * 	    compiled prior to the execution of this method.
-			 * 
-			 * @post The internal substring table will be updated
-			 *       with the new matches. Therefore, subsequent
-			 * 		 calls to group may return different results.
-			 */
-			bool matches(const std::string& subject) throw(match_error);
-			
-			/**
-			 * Try to match the compiled pattern with the implicit 
-			 * subject. 
-			 * 
-			 * @return true If the subject matches the pattern, 
-			 *         false otherwise. 
-			 * 
-			 * @pre The regular expression should have been 
-			 * 	    compiled prior to the execution of this method.
-			 * 
-			 * @post The internal substring table will be updated
-			 *       with the new matches. Therefore, subsequent
-			 * 		 calls to group may return different results.
-			 */
-			bool matches(void) throw(match_error); 	
-			
-			/**
-			 *  Split the subject into a list of substrings.
-			 * 
-			 * @return A vector of substrings. 
-			 * 
-			 * @pre The regular expression should have been 
-			 * 	    compiled prior to the execution of this method.
-			 * 
-			 * @post The internal subject won't be affected by this 
-			 * 	     by this operation. In other words: subject_before =
-			 * 		 subject_after.
-			 */
-			std::vector<std::string> split(void) throw(match_error);		
-
-        private:  
-			/**
-             * The regular expression that represents that pattern.
-             */
-            std::string _pattern;
-
-            /** 
-            * The optional subject string.
-            */
-            std::string _subject;
-
-            /**
-            * PCRE struct that
-            * contains the compiled regular
-            * expression
-            */
-            pcre * _re;
-
-			/**
-			 * The internal output vector used by PCRE. 
-			 */
-			int * _ovector;
-			
-			/**
-			 * The size of the _ovector
-			 */
-			int _ovectorSize;
-			
-			/**
-			 * Current offset in the _ovector;
-			 */
-			
-			int _offset[2];
-			
-			/**
-			 * The number of substrings matched after calling
-			 * pcre_exec.
-			 */ 
-			int _count;
-			
-			/**
-			 * PCRE options for this pattern.
-			 */
-			int _options;
-			
-			/**
-			 * String representation of the options.
-			 */
-			std::string _optionsDescription;
-    };
-}
-}
-
-#endif
diff --git a/sflphone-common/test/Makefile.am b/sflphone-common/test/Makefile.am
index 87264309aa0f6008c2e6a5704122de0593a5d097..e3679eb678549f698cf3d25c20c994b7c10a4bdf 100644
--- a/sflphone-common/test/Makefile.am
+++ b/sflphone-common/test/Makefile.am
@@ -1,28 +1,31 @@
 include ../globals.mak
 
 
-noinst_PROGRAMS = numbercleanerTester pluginmanagerTester hookmanagerTester audiolayerTester historyTester mainbufferTester #rtpTester
+noinst_PROGRAMS = numbercleanerTester pluginmanagerTester hookmanagerTester audiolayerTester historyTester mainbufferTester sdesnegotiatorTester #rtpTester
 
 OBJECT_FILES= \
+	../src/sflphoned-logger.o \
 	../src/sflphoned-managerimpl.o \
+	../src/sflphoned-account.o\
 	../src/sflphoned-accountcreator.o \
 	../src/sflphoned-call.o \
-	../src/sip/sipcall.o \
-	../src/iax/libiaxlink_la-iaxcall.o \
+	../src/sflphoned-conference.o \
+	../src/sflphoned-eventthread.o \
+	../src/sflphoned-managerimpl_registration.o \
+	../src/sflphoned-numbercleaner.o \
+	../src/sflphoned-observer.o \
 	../src/sflphoned-voiplink.o \
-	../src/sip/sipvoiplink.o \
+	../src/sip/libsiplink_la-sipcall.o \
+	../src/iax/libiaxlink_la-iaxcall.o \
+	../src/sip/libsiplink_la-sipvoiplink.o \
 	../src/iax/libiaxlink_la-iaxvoiplink.o \
-	../src/sflphoned-account.o \
-	../src/sip/sipaccount.o \
+	../src/sip/libsiplink_la-sipaccount.o \
 	../src/iax/libiaxlink_la-iaxaccount.o \
-	../src/sflphoned-eventthread.o \
-	../src/sflphoned-conference.o \
+	../src/sip/libsiplink_la-sdp.o \
+	../src/sip/libsiplink_la-sdpmedia.o \
 	../src/plug-in/pluginmanager.o \
 	../src/plug-in/audiorecorder/audiorecord.o \
 	../src/audio/samplerateconverter.o \
-	../src/sip/sdp.o \
-	../src/sip/sdpmedia.o \
-	../src/sflphoned-numbercleaner.o \
         ../src/history/historymanager.o
 	../
 
@@ -65,7 +68,7 @@ pluginmanagerTester_LDADD = \
 		@SAMPLERATE_LIBS@ \
 		$(PJSIP_LIBS) \
 		$(OBJECT_FILES)
-						
+
 hookmanagerTester_SOURCES = \
 		hookmanagerTest.cpp \
 		TestMain.cpp
@@ -145,3 +148,23 @@ mainbufferTester_LDADD = \
 		@SAMPLERATE_LIBS@ \
 		$(PJSIP_LIBS) \
 		$(OBJECT_FILES)
+
+sdesnegotiatorTester_SOURCES = \
+		sdesnegotiatorTest.h \
+		sdesnegotiatorTest.cpp \
+		TestMain.cpp
+
+sdesnegotiatorTester_LDADD = \
+		../src/libsflphone.la  \
+		$(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) \
+		@ALSA_LIBS@ \
+		@PULSEAUDIO_LIBS@ \
+		@CPPUNIT_LIBS@ \
+		@CCEXT2_LIBS@ \
+		@CCGNU2_LIBS@ \
+		@CCRTP_LIBS@ \
+		@ZRTPCPP_LIBS@ \
+		@libssl_LIBS@ \
+		@SAMPLERATE_LIBS@ \
+		$(PJSIP_LIBS) \
+		$(OBJECT_FILES)
diff --git a/sflphone-common/test/hookmanagerTest.cpp b/sflphone-common/test/hookmanagerTest.cpp
index d5b8cb6a80a4a0fcca0e55c7440a0853d443b66f..817533a9277592570a8c2b5db7e5e7c0630dcd62 100644
--- a/sflphone-common/test/hookmanagerTest.cpp
+++ b/sflphone-common/test/hookmanagerTest.cpp
@@ -38,7 +38,7 @@ void HookManagerTest::testAddAction ()
 
     int status;
 
-    status = urlhook->addAction ("www.google.ca", "x-www-browser");
+    status = urlhook->addAction ("http://www.google.ca/?arg1=arg1&arg2=nvls&x=2&y=45&z=1", "x-www-browser");
     CPPUNIT_ASSERT (status == 0);
 }
 
diff --git a/sflphone-common/test/sdesnegotiatorTest.cpp b/sflphone-common/test/sdesnegotiatorTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..71b429a5eac0a74d4a011b4fd9bbdc8b84067808
--- /dev/null
+++ b/sflphone-common/test/sdesnegotiatorTest.cpp
@@ -0,0 +1,158 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *
+ *  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 3 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.
+ */
+
+#include <stdio.h>
+#include <sstream>
+#include <ccrtp/rtp.h>
+#include <assert.h>
+#include <string>
+#include <cstring>
+#include <math.h>
+#include <dlfcn.h>
+#include <iostream>
+#include <sstream>
+
+
+#include "sdesnegotiatorTest.h"
+
+#include <unistd.h>
+
+
+using std::cout;
+using std::endl;
+
+
+void SdesNegotiatorTest::setUp()
+{
+
+  std::string attr("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd|2^20|1:32");
+
+  // std::string attr("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32");
+
+    remoteOffer = new std::vector<std::string>();
+    remoteOffer->push_back(attr);
+
+    localCapabilities = new std::vector<sfl::CryptoSuiteDefinition>();
+    for(int i = 0; i < 3; i++) {
+        localCapabilities->push_back(sfl::CryptoSuites[i]);
+    }
+
+    sdesnego = new sfl::SdesNegotiator(*localCapabilities, *remoteOffer);
+
+}
+
+
+void SdesNegotiatorTest::tearDown()
+{
+
+    delete remoteOffer;
+    remoteOffer = NULL;
+
+    delete localCapabilities;
+    localCapabilities = NULL;
+
+    delete sdesnego;
+    sdesnego = NULL;
+
+}
+
+void SdesNegotiatorTest::testTagPattern()
+{
+    std::string subject = "a=crypto:4"; 
+
+    pattern = new sfl::Pattern("^a=crypto:(?P<tag>[0-9]{1,9})");
+    *pattern << subject;
+
+    CPPUNIT_ASSERT(pattern->matches());
+    CPPUNIT_ASSERT(pattern->group("tag").compare("4") == 0);
+
+    delete pattern;
+    pattern = NULL;
+}
+
+
+void SdesNegotiatorTest::testCryptoSuitePattern()
+{
+    std::string subject = "AES_CM_128_HMAC_SHA1_80"; 
+
+    pattern = new sfl::Pattern("(?P<cryptoSuite>AES_CM_128_HMAC_SHA1_80|" \
+			       "AES_CM_128_HMAC_SHA1_32|"		\
+			       "F8_128_HMAC_SHA1_80|"			\
+			       "[A-Za-z0-9_]+)");
+    *pattern << subject;
+
+    CPPUNIT_ASSERT(pattern->matches());
+    CPPUNIT_ASSERT(pattern->group("cryptoSuite").compare("AES_CM_128_HMAC_SHA1_80") == 0);
+
+    delete pattern;
+    pattern = NULL;
+}
+
+
+void SdesNegotiatorTest::testKeyParamsPattern()
+{
+
+    std::string subject = "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32";
+
+    pattern = new sfl::Pattern("(?P<srtpKeyMethod>inline|[A-Za-z0-9_]+)\\:" \
+			       "(?P<srtpKeyInfo>[A-Za-z0-9\x2B\x2F\x3D]+)\\|" \
+			       "2\\^(?P<lifetime>[0-9]+)\\|"		\
+			       "(?P<mkiValue>[0-9]+)\\:"		\
+			       "(?P<mkiLength>[0-9]{1,3})\\;?", "g");
+
+    *pattern << subject;
+
+    pattern->matches();
+    CPPUNIT_ASSERT(pattern->group("srtpKeyMethod").compare("inline:"));
+
+    /*
+    while (pattern->matches()) {
+                
+        std::string _srtpKeyMethod = pattern->group ("srtpKeyMethod");
+	std::string _srtpKeyInfo = pattern->group ("srtpKeyInfo");
+	std::string _lifetime = pattern->group ("lifetime");
+	std::string _mkiValue = pattern->group ("mkiValue");
+	std::string _mkiLength = pattern->group ("mkiLength");
+    }
+
+
+    CPPUNIT_ASSERT(pattern->group("srtpKeyMethod").compare("inline:"));
+    CPPUNIT_ASSERT(pattern->group("srtpKeyInfo").compare("d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj"));
+    CPPUNIT_ASSERT(pattern->group("lifetime").compare("20"));
+    CPPUNIT_ASSERT(pattern->group("mkivalue").compare("1"));
+    CPPUNIT_ASSERT(pattern->group("mkilength").compare("32"));
+    */
+
+    delete pattern;
+    pattern = NULL;
+}
+
+
+void SdesNegotiatorTest::testNegotiation()
+{
+    CPPUNIT_ASSERT(sdesnego->negotiate());
+    CPPUNIT_ASSERT(sdesnego->getCryptoSuite().compare("AES_CM_128_HMAC_SHA1_80") == 0);
+    CPPUNIT_ASSERT(sdesnego->getKeyMethod().compare("inline") == 0);
+    CPPUNIT_ASSERT(sdesnego->getKeyInfo().compare("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd") == 0);
+    CPPUNIT_ASSERT(sdesnego->getLifeTime().compare("20") == 0);
+    CPPUNIT_ASSERT(sdesnego->getMkiValue().compare("1") == 0);
+    CPPUNIT_ASSERT(sdesnego->getMkiLength().compare("32") == 0);
+}
+
+
diff --git a/sflphone-common/test/sdesnegotiatorTest.h b/sflphone-common/test/sdesnegotiatorTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e97a9d6dab6134e88fbfde693844e67a79c61e7
--- /dev/null
+++ b/sflphone-common/test/sdesnegotiatorTest.h
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *
+ *  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 3 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.
+ */
+
+// Cppunit import
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+
+#include <assert.h>
+
+#include <stdio.h>
+#include <sstream>
+#include <ccrtp/rtp.h>
+
+#include <vector>
+
+// pjsip import
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjsip_ua.h>
+#include <pjlib-util.h>
+#include <pjnath/stun_config.h>
+
+// Application import
+#include "sip/SdesNegotiator.h"
+#include "sip/Pattern.h"
+// #include "config/config.h"
+// #include "user_cfg.h"
+
+
+
+/*
+ * @file sdesnegotiationTest.cpp  
+ * @brief       Regroups unitary tests related to the plugin manager.
+ */
+
+#ifndef _SDESNEGOTIATOR_TEST_
+#define _SDESNEGOTIATOR_TEST_
+
+
+
+class SdesNegotiatorTest : public CppUnit::TestCase {
+
+    /*
+     * Use cppunit library macros to add unit test the factory
+     */
+    CPPUNIT_TEST_SUITE( SdesNegotiatorTest );
+    CPPUNIT_TEST( testTagPattern );
+    CPPUNIT_TEST( testCryptoSuitePattern );
+    CPPUNIT_TEST( testKeyParamsPattern );
+    CPPUNIT_TEST( testNegotiation );
+    CPPUNIT_TEST_SUITE_END();
+
+    public:
+
+        SdesNegotiatorTest() : CppUnit::TestCase("Sdes Tests") {}
+        
+        /*
+         * Code factoring - Common resources can be initialized here.
+         * This method is called by unitcpp before each test
+         */
+        void setUp();
+
+        /*
+         * Code factoring - Common resources can be released here.
+         * This method is called by unitcpp after each test
+         */
+        inline void tearDown();
+
+	void testTagPattern();
+
+	void testCryptoSuitePattern();
+
+	void testKeyParamsPattern();
+
+       	void testNegotiation();
+
+    private:
+
+	sfl::Pattern *pattern;
+
+	sfl::SdesNegotiator *sdesnego;
+
+	std::vector<std::string> *remoteOffer;
+
+	std::vector<sfl::CryptoSuiteDefinition> *localCapabilities;
+
+};
+
+/* Register our test module */
+CPPUNIT_TEST_SUITE_REGISTRATION( SdesNegotiatorTest );
+
+#endif