diff --git a/daemon/src/sip/pres_sub_client.cpp b/daemon/src/sip/pres_sub_client.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7fc0963f3c6e68aff0cb68cb670ac48064067be7
--- /dev/null
+++ b/daemon/src/sip/pres_sub_client.cpp
@@ -0,0 +1,554 @@
+/*
+ *  Copyright (C) 2012, 2013 LOTES TM LLC
+ *  Author : Andrey Loukhnov <aol.nnov@gmail.com>
+ *
+ *  This file is a part of pult5-voip
+ *
+ *  pult5-voip 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.
+ *
+ *  pult5-voip 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 programm. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify pult5-voip, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, LOTES-TM LLC
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include <pj/log.h>
+#include <pj/rand.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_types.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_transaction.h>
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_endpoint.h>
+#include <string>
+#include <pj/pool.h>
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip-simple/evsub.h>
+#include <unistd.h>
+
+#include "pres_sub_client.h"
+#include "sipaccount.h"
+#include "sippresence.h"
+#include "sipvoiplink.h"
+
+#include "manager.h"
+
+#include "logger.h"
+
+#define BUDDY_SUB_TERM_REASON_LEN 32
+#define PRES_TIMER 300
+
+int modId;
+
+void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry) {
+    (void) th;
+    PresSubClient *b = (PresSubClient *) entry->user_data;
+    b->reportPresence();
+}
+
+/* Callback called when *client* subscription state has changed. */
+void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event) {
+    PresSubClient *buddy;
+
+    PJ_UNUSED_ARG(event);
+
+    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has
+     *   a dialog attached to it, lock_buddy() will use the dialog
+     *   lock, which we are currently holding!
+     */
+
+    buddy = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId);
+    if (buddy) {
+        buddy->incLock();
+        DEBUG("Presence subscription to '%s' is '%s'", buddy->getURI().c_str(),
+            pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null");
+
+        pjsip_evsub_state state = pjsip_evsub_get_state(sub);
+        if(state == PJSIP_EVSUB_STATE_ACCEPTED){
+            DEBUG("PresSubClient accepted.");
+            buddy->accept();
+        }
+        else if (state == PJSIP_EVSUB_STATE_TERMINATED) {
+            int resub_delay = -1;
+
+//            const pj_str_t *pjTermReason = pjsip_evsub_get_termination_reason(sub);
+//            std::string termReason(pjTermReason->ptr,
+//                    pjTermReason->slen > BUDDY_SUB_TERM_REASON_LEN?
+//                        BUDDY_SUB_TERM_REASON_LEN:
+//                        pjTermReason->slen
+//            );
+            pj_strdup_with_null(buddy->pool, &buddy->term_reason, pjsip_evsub_get_termination_reason(sub));
+//            buddy->setTermReason(termReason);
+//            buddy->setTermCode(200);
+            buddy->term_code = 200;
+
+            /* Determine whether to resubscribe automatically */
+            if (event && event->type == PJSIP_EVENT_TSX_STATE) {
+                const pjsip_transaction *tsx = event->body.tsx_state.tsx;
+                if (pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) {
+//		    buddy->setTermCode(tsx->status_code);
+                    buddy->term_code = tsx->status_code;
+                    switch (tsx->status_code) {
+                        case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST:
+                            /* 481: we refreshed too late? resubscribe
+                             * immediately.
+                             */
+                            /* But this must only happen when the 481 is received
+                             * on subscription refresh request. We MUST NOT try to
+                             * resubscribe automatically if the 481 is received
+                             * on the initial SUBSCRIBE (if server returns this
+                             * response for some reason).
+                             */
+                            if (buddy->dlg->remote.contact)
+                                resub_delay = 500;
+                            break;
+                    }
+                } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
+                    if (buddy->isTermReason("deactivated") || buddy->isTermReason("timeout")) {
+                     /* deactivated: The subscription has been terminated,
+                         * but the subscriber SHOULD retry immediately with
+                         * a new subscription.
+                         */
+                        /* timeout: The subscription has been terminated
+                         * because it was not refreshed before it expired.
+                         * Clients MAY re-subscribe immediately. The
+                         * "retry-after" parameter has no semantics for
+                         * "timeout".
+                         */
+                        resub_delay = 500;
+                    } else if (buddy->isTermReason("probation") || buddy->isTermReason("giveup")) {
+                        /* probation: The subscription has been terminated,
+                         * but the client SHOULD retry at some later time.
+                         * If a "retry-after" parameter is also present, the
+                         * client SHOULD wait at least the number of seconds
+                         * specified by that parameter before attempting to re-
+                         * subscribe.
+                         */
+                        /* giveup: The subscription has been terminated because
+                         * the notifier could not obtain authorization in a
+                         * timely fashion.  If a "retry-after" parameter is
+                         * also present, the client SHOULD wait at least the
+                         * number of seconds specified by that parameter before
+                         * attempting to re-subscribe; otherwise, the client
+                         * MAY retry immediately, but will likely get put back
+                         * into pending state.
+                         */
+                        const pjsip_sub_state_hdr *sub_hdr;
+                        pj_str_t sub_state = {"Subscription-State", 18 };
+                        const pjsip_msg *msg;
+
+                        msg = event->body.tsx_state.src.rdata->msg_info.msg;
+                        sub_hdr = (const pjsip_sub_state_hdr*) pjsip_msg_find_hdr_by_name(msg, &sub_state, NULL);
+                        if (sub_hdr && sub_hdr->retry_after > 0)
+                            resub_delay = sub_hdr->retry_after * 1000;
+                    }
+
+                }
+            }
+
+            /* For other cases of subscription termination, if resubscribe
+             * timer is not set, schedule with default expiration (plus minus
+             * some random value, to avoid sending SUBSCRIBEs all at once)
+             */
+            if (resub_delay == -1) {
+//		pj_assert(PRES_TIMER >= 3);
+                resub_delay = PRES_TIMER * 1000;// - 2500 + (pj_rand() % 5000);
+            }
+            buddy->sub = sub;
+            buddy->rescheduleTimer(PJ_TRUE, resub_delay);
+        }/* else {
+             This will clear the last termination code/reason
+            buddy->term_code = 0;
+            buddy->term_reason.ptr = NULL;
+        }*/
+
+        /* Clear subscription */
+       /* if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+            pjsip_evsub_terminate(buddy->sub, PJ_FALSE); // = NULL;
+            buddy->status.info_cnt = 0;
+            buddy->dlg = NULL;
+            buddy->rescheduleTimer(PJ_FALSE, 0);
+//            pjsip_evsub_set_mod_data(sub, modId, NULL);
+        }*/
+
+//	pj_log_pop_indent();
+        buddy->decLock();
+    }
+}
+
+/* Callback when transaction state has changed. */
+void buddy_evsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) {
+
+    PresSubClient *buddy;
+    pjsip_contact_hdr *contact_hdr;
+
+    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has
+     *   a dialog attached to it, lock_buddy() will use the dialog
+     *   lock, which we are currently holding!
+     */
+    buddy = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId);
+    if (!buddy) {
+        return;
+    }
+    buddy->incLock();
+
+    /* We only use this to update buddy's Contact, when it's not
+     * set.
+     */
+    if (buddy->contact.slen != 0) {
+        /* Contact already set */
+        buddy->decLock();
+        return;
+    }
+
+    /* Only care about 2xx response to outgoing SUBSCRIBE */
+    if (tsx->status_code / 100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG
+            || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method()) != 0) {
+        buddy->decLock();
+        return;
+    }
+
+    /* Find contact header. */
+    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT,
+            NULL);
+    if (!contact_hdr || !contact_hdr->uri) {
+        buddy->decLock();
+        return;
+    }
+
+    buddy->contact.ptr = (char*) pj_pool_alloc(buddy->pool, PJSIP_MAX_URL_SIZE);
+    buddy->contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, buddy->contact.ptr,
+            PJSIP_MAX_URL_SIZE);
+    if (buddy->contact.slen < 0)
+        buddy->contact.slen = 0;
+
+    buddy->decLock();
+}
+
+/* Callback called when we receive NOTIFY */
+static void buddy_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text,
+        pjsip_hdr *res_hdr, pjsip_msg_body **p_body) {
+    PresSubClient *buddy;
+
+    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has
+     *   a dialog attached to it, lock_buddy() will use the dialog
+     *   lock, which we are currently holding!
+     */
+    buddy = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId);
+    if (!buddy){
+        ERROR("Couldn't create new buddy");
+        return;
+    }
+
+    pjsip_pres_get_status(sub, &buddy->status);
+    buddy->reportPresence();
+
+    /* The default is to send 200 response to NOTIFY.
+     * Just leave it there..
+     */
+    PJ_UNUSED_ARG(rdata);
+    PJ_UNUSED_ARG(p_st_code);
+    PJ_UNUSED_ARG(p_st_text);
+    PJ_UNUSED_ARG(res_hdr);
+    PJ_UNUSED_ARG(p_body);
+
+    buddy->decLock();
+}
+
+PresSubClient::PresSubClient(const std::string& uri_, SIPAccount *acc_) :
+        acc(acc_),
+        uri(pj_str(strdup(uri_.c_str()))),
+        contact(pj_str(strdup(acc->getFromUri().c_str()))),
+        display(),
+        dlg(NULL),
+        monitor(false),
+        name(),
+        cp_(),
+        pool(0),
+        status(),
+        sub(NULL),
+        term_code(0),
+        term_reason(),
+        timer(),
+        user_data(NULL),
+        lock_count(0)
+{
+    pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0);
+    pool = pj_pool_create(&cp_.factory, "buddy", 512, 512, NULL);
+}
+
+PresSubClient::~PresSubClient() {
+    while(lock_count >0) {
+        usleep(200);
+    }
+    DEBUG("Destroying buddy object with uri %s", uri.ptr);
+    rescheduleTimer(PJ_FALSE, 0);
+    unsubscribe();
+
+    pj_pool_release(pool);
+}
+
+bool PresSubClient::isSubscribed() {
+    return this->monitor;
+}
+
+std::string PresSubClient::getURI() {
+    std::string buddyURI(uri.ptr, uri.slen);
+    return buddyURI;
+}
+
+bool PresSubClient::isTermReason(std::string reason) {
+    std::string myReason(term_reason.ptr, term_reason.slen);
+    return !myReason.compare(reason);
+}
+
+void PresSubClient::rescheduleTimer(bool reschedule, unsigned msec) {
+    if (timer.id) {
+        //	pjsua_cancel_timer(&timer);
+        pjsip_endpt_cancel_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer);
+        timer.id = PJ_FALSE;
+    }
+
+    if (reschedule) {
+        pj_time_val delay;
+
+        WARN("Resubscribing buddy  %.*s in %u ms (reason: %.*s)",
+              uri.slen, uri.ptr, msec, (int) term_reason.slen, term_reason.ptr);
+        monitor = PJ_TRUE;
+        pj_timer_entry_init(&timer, 0, this, &buddy_timer_cb);
+        delay.sec = 0;
+        delay.msec = msec;
+        pj_time_val_normalize(&delay);
+
+        //	if (pjsua_schedule_timer(&timer, &delay)==PJ_SUCCESS)
+
+        if (pjsip_endpt_schedule_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer, &delay) == PJ_SUCCESS) {
+//            timer.id = PJ_TRUE;
+        }
+    }
+}
+
+void PresSubClient::accept() {
+    acc->getPresence()->addPresSubClient(this);
+}
+
+void PresSubClient::reportPresence() {
+
+    //incLock();
+    /* callback*/
+    acc->getPresence()->reportPresSubClientNotification(getURI(),&status);
+    //decLock();
+}
+
+
+pj_status_t PresSubClient::updateSubscription() {
+
+    if (!monitor) {
+        /* unsubscribe */
+        pjsip_tx_data *tdata;
+        pj_status_t retStatus;
+
+        if (sub == NULL) {
+            WARN("PresSubClient already unsubscribed sub=NULL.");
+            return PJ_SUCCESS;
+        }
+
+        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+            WARN("PresSubClient already unsubscribed sub=TERMINATED.");
+            //pjsip_evsub_terminate(sub, PJ_FALSE); //
+            sub = NULL;
+            return PJ_SUCCESS;
+        }
+
+        WARN("PresSubClient %s: unsubscribing..", uri.ptr);
+        retStatus = pjsip_pres_initiate(sub, 0, &tdata);
+        if (retStatus == PJ_SUCCESS) {
+            acc->getPresence()->fillDoc(tdata, NULL);
+            /*if (tdata->msg->type == PJSIP_REQUEST_MSG) {
+                const pj_str_t STR_USER_AGENT = {"User-Agent", 10};
+                pj_str_t ua = pj_str(strdup(acc->getUserAgentName().c_str()));
+                pjsip_hdr *h;
+                h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &ua);
+                pjsip_msg_add_hdr(tdata->msg, h);
+            }*/
+            retStatus = pjsip_pres_send_request(sub, tdata);
+        }
+
+        if (retStatus != PJ_SUCCESS && sub) {
+            pjsip_pres_terminate(sub, PJ_FALSE);
+            pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL;
+            WARN("Unable to unsubscribe presence", status);
+        }
+
+        pjsip_evsub_set_mod_data(sub, modId, NULL);   // Not interested with further events
+
+        return PJ_SUCCESS;
+    }
+
+//#if 0
+    if (sub && dlg) { //do not bother if already subscribed
+//        return PJ_SUCCESS;
+        pjsip_evsub_terminate(sub, PJ_FALSE);
+        DEBUG("Terminate existing sub.");
+    }
+//#endif
+
+    //subscribe
+    pjsip_evsub_user pres_callback;
+//    pj_pool_t *tmp_pool = NULL; // related to "contact field. TODO: check if this is necessary"
+
+    pjsip_tx_data *tdata;
+    pj_status_t status;
+
+    /* Event subscription callback. */
+    pj_bzero(&pres_callback, sizeof(pres_callback));
+    pres_callback.on_evsub_state = &buddy_evsub_on_state;
+    pres_callback.on_tsx_state = &buddy_evsub_on_tsx_state;
+    pres_callback.on_rx_notify = &buddy_evsub_on_rx_notify;
+
+    DEBUG("PresSubClient %s: subscribing presence,using account %s..",
+          uri.ptr, acc->getAccountID().c_str());
+
+    /* Generate suitable Contact header unless one is already set in
+     * the account
+     */
+#if 0
+    if (acc->contact.slen) {
+        contact = acc->contact;
+    } else {
+        tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256);
+
+        status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
+                acc_id, &buddy->uri);
+        if (status != PJ_SUCCESS) {
+            pjsua_perror(THIS_FILE, "Unable to generate Contact header",
+                    status);
+            pj_pool_release(tmp_pool);
+            pj_log_pop_indent();
+            return;
+        }
+    }
+#endif
+    /* Create UAC dialog */
+    pj_str_t from = pj_str(strdup(acc->getFromUri().c_str()));
+    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from, &contact, &uri, NULL, &dlg);
+    if (status != PJ_SUCCESS) {
+        ERROR("Unable to create dialog \n");
+        return PJ_FALSE;
+    }
+    // Add credential for auth.
+    if (acc->hasCredentials() and pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) {
+      ERROR("Could not initialize credentials for subscribe session authentication");
+    }
+
+    /* Increment the dialog's lock otherwise when presence session creation
+     * fails the dialog will be destroyed prematurely.
+     */
+    pjsip_dlg_inc_lock(dlg);
+
+    status = pjsip_pres_create_uac(dlg, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &sub);
+    if (status != PJ_SUCCESS) {
+        pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL;
+        WARN("Unable to create presence client", status);
+        /* This should destroy the dialog since there's no session
+         * referencing it
+         */
+        if (dlg) {
+            pjsip_dlg_dec_lock(dlg);
+        }
+//        if (tmp_pool) pj_pool_release(tmp_pool);
+//        pj_log_pop_indent();
+        return PJ_SUCCESS;
+    }
+#if 0
+    /* If account is locked to specific transport, then lock dialog
+     * to this transport too.
+     */
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
+        pjsip_tpselector tp_sel;
+        pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
+        pjsip_dlg_set_transport(buddy->dlg, &tp_sel);
+    }
+
+    /* Set route-set */
+    if (!pj_list_empty(&acc->route_set)) {
+        pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set);
+    }
+
+    /* Set credentials */
+    if (acc->cred_cnt) {
+        pjsip_auth_clt_set_credentials(&buddy->dlg->auth_sess
+                acc->cred_cnt, acc->cred);
+    }
+
+    /* Set authentication preference */
+    pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref);
+#endif
+    modId = ((SIPVoIPLink*) acc->getVoIPLink())->getModId();
+    pjsip_evsub_set_mod_data(sub, modId, this);
+
+    status = pjsip_pres_initiate(sub, -1, &tdata);
+    if (status != PJ_SUCCESS) {
+        if (dlg)
+            pjsip_dlg_dec_lock(dlg);
+        if (sub) {
+            pjsip_pres_terminate(sub, PJ_FALSE);
+        }
+        pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL;
+        WARN("Unable to create initial SUBSCRIBE", status);
+//        if (tmp_pool) pj_pool_release(tmp_pool);
+        return PJ_SUCCESS;
+    }
+
+//    pjsua_process_msg_data(tdata, NULL);
+
+    status = pjsip_pres_send_request(sub, tdata);
+    if (status != PJ_SUCCESS) {
+        if (dlg)
+            pjsip_dlg_dec_lock(dlg);
+        if (sub) {
+            pjsip_pres_terminate(sub, PJ_FALSE);
+            sub = NULL;
+        }
+
+        WARN("Unable to send initial SUBSCRIBE", status);
+//        if (tmp_pool) pj_pool_release(tmp_pool);
+        return PJ_SUCCESS;
+    }
+
+    pjsip_dlg_dec_lock(dlg);
+//    if (tmp_pool) pj_pool_release(tmp_pool);
+    return PJ_SUCCESS;
+}
+
+bool PresSubClient::subscribe() {
+    monitor = true;
+    return ((updateSubscription() == PJ_SUCCESS))? true : false;
+}
+
+bool PresSubClient::unsubscribe() {
+    monitor = false;
+    return ((updateSubscription() == PJ_SUCCESS))? true : false;
+}
+
+bool PresSubClient::match(PresSubClient *b){
+    //return !(strcmp(b->getURI(),getURI()));
+    return (b->getURI()==getURI());
+}
diff --git a/daemon/src/sip/pres_sub_client.h b/daemon/src/sip/pres_sub_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..7667155983c85c1341b0b73f003f858f59e6bf73
--- /dev/null
+++ b/daemon/src/sip/pres_sub_client.h
@@ -0,0 +1,171 @@
+/*
+ *  Copyright (C) 2012, 2013 LOTES TM LLC
+ *  Author : Andrey Loukhnov <aol.nnov@gmail.com>
+ *  Author : Patrick Keroulas <patrick.keroulas@savoirfairelinux.com>
+ *  This file is a part of pult5-voip
+ *
+ *  pult5-voip 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.
+ *
+ *  pult5-voip 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 programm. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify pult5-voip, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, LOTES-TM LLC
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef SIPBUDDY_H
+#define SIPBUDDY_H
+
+#include <pjsip-simple/presence.h>
+#include <pj/timer.h>
+#include <pj/pool.h>
+#include <string>
+
+#include <pjsip-simple/evsub.h>
+#include <pjsip-simple/evsub_msg.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_transport.h>
+#include "noncopyable.h"
+
+class SIPAccount;
+
+/**
+ * Transaction functions of event subscription client side.
+ */
+static void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event);
+static void buddy_evsub_on_tsx_state(pjsip_evsub *sub,
+                                     pjsip_transaction *tsx,
+                                     pjsip_event *event);
+static void buddy_evsub_on_rx_notify(pjsip_evsub *sub,
+                                     pjsip_rx_data *rdata,
+                                     int *p_st_code,
+                                     pj_str_t **p_st_text,
+                                     pjsip_hdr *res_hdr,
+                                     pjsip_msg_body **p_body);
+static void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
+
+
+class PresSubClient {
+
+    public:
+        /**
+         * Constructor
+         * @param uri   SIP uri of remote user that we want to subscribe,
+         */
+        PresSubClient(const std::string &uri, SIPAccount *acc);
+        /**
+         * Destructor.
+         * Process the the unsubscription before the destruction.
+         */
+        ~PresSubClient();
+        /**
+         * Compare with another buddy's uris.
+         * @param b     Other buddy pointer
+         */
+        bool match(PresSubClient *b);
+        /**
+         * The PBX must approve the subrciption before the buddy is added in the buddy list.
+         */
+        void accept();
+        /**
+         * Send a SUBCRIBE to the PXB or directly to a buddy in the IP2IP context.
+         */
+        bool subscribe();
+        /**
+         * Send a SUBCRIBE to the PXB or directly to a buddy in the IP2IP context but
+         * the 0s timeout make the dialog expire immediatly.
+         */
+        bool unsubscribe();
+        /**
+         * Return  the monitor variable.
+         */
+        bool isSubscribed();
+        /**
+         * Return the buddy URI
+         */
+        std::string getURI();
+
+
+        friend void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event);
+        friend void buddy_evsub_on_tsx_state(pjsip_evsub *sub,
+                                             pjsip_transaction *tsx,
+                                             pjsip_event *event);
+        friend void buddy_evsub_on_rx_notify(pjsip_evsub *sub,
+                                             pjsip_rx_data *rdata,
+                                             int *p_st_code,
+                                             pj_str_t **p_st_text,
+                                             pjsip_hdr *res_hdr,
+                                             pjsip_msg_body **p_body);
+        friend void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
+
+        /**
+         * TODO: explain this:
+         */
+        void incLock() {
+            lock_count++;
+        }
+        void decLock() {
+            lock_count--;
+        }
+
+    private:
+
+        NON_COPYABLE(PresSubClient);
+        /**
+         * Plan a retry or a renew a subscription.
+         * @param reschedule    Allow for reschedule.
+         * @param msec          Delay value in milliseconds.
+         */
+        void rescheduleTimer(bool reschedule, unsigned msec);
+        /**
+         * Callback after a presence notification was received.
+         * Tranfert info to the SIP account.
+         */
+        void reportPresence();
+        /**
+         * Process the un/subscribe request transmission.
+         */
+        pj_status_t updateSubscription();
+        /*
+         * Compare the reason of a transaction end with the given string.
+         */
+        bool isTermReason(std::string);
+        /**
+         * return the code after a transaction is terminated.
+         */
+        unsigned getTermCode();
+
+        SIPAccount      *acc;       /**< Associated SIP account pointer */
+        pj_str_t         uri;        /**< Buddy URI.            */
+        pj_str_t         contact;   /**< Contact learned from subscrp.    */
+        pj_str_t         display;   /**< Buddy display name.        */
+        pjsip_dialog    *dlg;        /**< The underlying dialog.        */
+        pj_bool_t        monitor;   /**< Should we monitor?        */
+        pj_str_t         name;        /**< Buddy name.            */
+        pj_caching_pool  cp_;
+        pj_pool_t       *pool;        /**< Pool for this buddy.        */
+        pjsip_pres_status     status;    /**< Buddy presence status.        */
+        pjsip_evsub     *sub;        /**< Buddy presence subscription    */
+        unsigned         term_code; /**< Subscription termination code    */
+        pj_str_t         term_reason;/**< Subscription termination reason */
+        pj_timer_entry   timer;        /**< Resubscription timer        */
+        void        *user_data; /**< Application data. */
+        int lock_count;
+};
+
+#endif    /* SIPBUDDY_H */
diff --git a/daemon/src/sip/pres_sub_server.cpp b/daemon/src/sip/pres_sub_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..efc8ebd4122cbfc2ce747e18440386f35ce125ab
--- /dev/null
+++ b/daemon/src/sip/pres_sub_server.cpp
@@ -0,0 +1,291 @@
+/*
+ *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ *  Author: Patrick Keroulas  <patrick.keroulas@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+
+#include "pjsip/sip_multipart.h"
+
+#include "sipvoiplink.h"
+#include "manager.h"
+#include "sippresence.h"
+#include "logger.h"
+#include "pres_sub_server.h"
+
+/* Callback called when *server* subscription state has changed. */
+void pres_evsub_on_srv_state(pjsip_evsub *sub, pjsip_event *event) {
+    pjsip_rx_data *rdata = event->body.rx_msg.rdata;
+    if(!rdata) {
+        DEBUG("Presence_subscription_server estate has changed but no rdata.");
+        return;
+    }
+
+    PJ_UNUSED_ARG(event);
+    SIPPresence * pres = Manager::instance().getSipAccount("IP2IP")->getPresence();
+    pres->lock();
+    PresSubServer *presSubServer = (PresSubServer *) pjsip_evsub_get_mod_data(sub,pres->getModId());
+    DEBUG("Presence_subscription_server to %s is %s", presSubServer->remote, pjsip_evsub_get_state_name(sub));
+
+    if (presSubServer) {
+        pjsip_evsub_state state;
+
+        state = pjsip_evsub_get_state(sub);
+
+        if (state == PJSIP_EVSUB_STATE_TERMINATED) {
+            pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
+            pres->removePresSubServer(presSubServer);
+        }
+        /* TODO check if other cases should be handled*/
+    }
+    pres->unlock();
+}
+
+pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata) {
+
+    pjsip_method *method = &rdata->msg_info.msg->line.req.method;
+    pj_str_t *str = &method->name;
+    std::string request(str->ptr, str->slen);
+//    pj_str_t contact;
+    pj_status_t status;
+    pjsip_dialog *dlg;
+    pjsip_evsub *sub;
+    pjsip_evsub_user pres_cb;
+    pjsip_tx_data *tdata;
+    pjsip_expires_hdr *expires_hdr;
+    pjsip_status_code st_code;
+    pj_str_t reason;
+    pres_msg_data msg_data;
+    pjsip_evsub_state ev_state;
+
+
+    /* Only hande incoming subscribe messages should be processed here.
+     * Otherwise we return FALSE to let other modules handle it */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0)
+        return PJ_FALSE;
+
+    /* debug msg */
+    std::string name(rdata->msg_info.to->name.ptr, rdata->msg_info.to->name.slen);
+    std::string server(rdata->msg_info.from->name.ptr, rdata->msg_info.from->name.slen);
+    DEBUG("Incomming pres_on_rx_subscribe_request for %s, name:%s, server:%s."
+            , request.c_str()
+            , name.c_str()
+            , server.c_str());
+
+    /* get parents*/
+    std::string accountId = "IP2IP"; /* this code is only used for IP2IP accounts */
+    SIPAccount *acc = (SIPAccount *) Manager::instance().getSipAccount(accountId);
+    pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
+    SIPPresence * pres = acc->getPresence();
+    pres->lock();
+
+    /* Create UAS dialog: */
+    std::string c(acc->getContactHeader());
+    const pj_str_t contact = pj_str((char*) c.c_str());
+    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
+    if (status != PJ_SUCCESS) {
+        char errmsg[PJ_ERR_MSG_SIZE];
+        pj_strerror(status, errmsg, sizeof(errmsg));
+        WARN("Unable to create UAS dialog for subscription: %s [status=%d]", errmsg, status);
+        pres->unlock();
+        pjsip_endpt_respond_stateless(endpt, rdata, 400, NULL, NULL, NULL);
+        return PJ_TRUE;
+    }
+
+    /* Init callback: */
+    pj_bzero(&pres_cb, sizeof(pres_cb));
+    pres_cb.on_evsub_state = &pres_evsub_on_srv_state;
+
+    /* Create server presence subscription: */
+    status = pjsip_pres_create_uas(dlg, &pres_cb, rdata, &sub);
+    if (status != PJ_SUCCESS) {
+        int code = PJSIP_ERRNO_TO_SIP_STATUS(status);
+        pjsip_tx_data *tdata;
+
+        WARN("Unable to create server subscription %d", status);
+
+        if (code == 599 || code > 699 || code < 300) {
+            code = 400;
+        }
+
+        status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata);
+        if (status == PJ_SUCCESS) {
+            status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
+        }
+
+        pres->unlock();
+        return PJ_FALSE;
+    }
+
+    /* Attach our data to the subscription: */
+    char* remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE);
+    status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, remote, PJSIP_MAX_URL_SIZE);
+    if (status < 1)
+        pj_ansi_strcpy(remote, "<-- url is too long-->");
+    else
+        remote[status] = '\0';
+    //pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, dlg->local.info->uri, contact.ptr, PJSIP_MAX_URL_SIZE);
+
+    /* Create a new PresSubServer server and wait for client approve */
+    PresSubServer *presSubServer = new PresSubServer(pres, sub, remote, dlg);
+    pjsip_evsub_set_mod_data(sub, pres->getModId(), presSubServer);
+    pres->reportNewPresSubServerRequest(presSubServer); // Notify the client.
+    pres->addPresSubServer(presSubServer);
+
+    /* Capture the value of Expires header. */
+    expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
+    if (expires_hdr)
+        presSubServer->setExpires(expires_hdr->ivalue);
+    else
+        presSubServer->setExpires(-1);
+
+    st_code = (pjsip_status_code) 200;
+    reason = pj_str("OK");
+    pj_bzero(&msg_data, sizeof(msg_data));
+    pj_list_init(&msg_data.hdr_list);
+    pjsip_media_type_init(&msg_data.multipart_ctype, NULL, NULL);
+    pj_list_init(&msg_data.multipart_parts);
+
+    /* Create and send 2xx response to the SUBSCRIBE request: */
+    status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list);
+    if (status != PJ_SUCCESS) {
+        WARN("Unable to accept presence subscription %d", status);
+        pjsip_pres_terminate(sub, PJ_FALSE);
+        pres->unlock();
+        return PJ_FALSE;
+    }
+
+    // Unsubscribe case
+    ev_state = PJSIP_EVSUB_STATE_ACTIVE;
+    if (presSubServer->getExpires() == 0){
+        ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+        pres->unlock();
+        return PJ_TRUE;
+    }
+
+    /*Send notify immediatly. Replace real status with fake.*/
+
+    // pjsip_pres_set_status(sub, pres->getStatus()); // real status
+
+    // fake temporary status
+    pjrpid_element rpid = {
+            PJRPID_ELEMENT_TYPE_PERSON,
+            pj_str("20"),
+            PJRPID_ACTIVITY_UNKNOWN,
+            pj_str("Your subscription was received and waits for approval.")
+    };
+    pjsip_pres_status fake_status_data;
+    pj_bzero(&fake_status_data, sizeof(pjsip_pres_status));
+    fake_status_data.info_cnt = 1;
+    fake_status_data.info[0].basic_open = false;
+    fake_status_data.info[0].id = pj_str("0"); /* todo: tuplie_id*/
+    pj_memcpy(&fake_status_data.info[0].rpid, &rpid,sizeof(pjrpid_element));
+    pjsip_pres_set_status(sub, &fake_status_data);
+
+    /* Create and send the the first NOTIFY to active subscription: */
+    pj_str_t stateStr = pj_str("");
+    tdata = NULL;
+    status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata);
+    if (status == PJ_SUCCESS) {
+        pres->fillDoc(tdata, &msg_data);
+        status = pjsip_pres_send_request(sub, tdata);
+    }
+
+    if (status != PJ_SUCCESS) {
+        WARN("Unable to create/send NOTIFY %d", status);
+        pjsip_pres_terminate(sub, PJ_FALSE);
+        pres->unlock();
+        return status;
+    }
+    pres->unlock();
+    return PJ_TRUE;
+}
+
+
+
+PresSubServer::PresSubServer(SIPPresence * pres, pjsip_evsub *evsub, char *r, pjsip_dialog *d)
+    : pres_(pres)
+    , sub(evsub)
+    , remote(r)
+    , dlg(d)
+    , expires(-1)
+    , approved(false)
+{}
+
+PresSubServer::~PresSubServer(){
+    //TODO: check if evsub needs to be forced TERMINATED.
+}
+
+void PresSubServer::setExpires(int ms) {
+    expires = ms;
+}
+
+int PresSubServer::getExpires(){
+    return expires;
+}
+
+/*SIPPresence *  PresSubServer::getPresence(){
+    return pres_;
+}*/
+
+bool PresSubServer::matches(char *s){
+    // servers match if they have the same remote uri and the account ID.
+  return (!(strcmp(remote,s))) ;
+}
+
+void PresSubServer::approve(const bool& flag){
+    approved = flag;
+    // attach the real status data
+    pjsip_pres_set_status(sub, pres_->getStatus());
+}
+
+
+void PresSubServer::notify() {
+     /* Only send NOTIFY once subscription is active. Some subscriptions
+     * may still be in NULL (when app is adding a new buddy while in the
+     * on_incoming_subscribe() callback) or PENDING (when user approval is
+     * being requested) state and we don't send NOTIFY to these subs until
+     * the user accepted the request.
+     */
+    if ((pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE) && (approved)) {
+        DEBUG("Notifying %s.", remote);
+
+        pjsip_tx_data *tdata;
+        pjsip_pres_set_status(sub, pres_->getStatus());
+
+        if (pjsip_pres_current_notify(sub, &tdata) == PJ_SUCCESS) {
+            // add msg header and send
+            pres_->fillDoc(tdata, NULL);
+            pjsip_pres_send_request(sub, tdata);
+        }
+        else{
+            WARN("Unable to create/send NOTIFY");
+            pjsip_pres_terminate(sub, PJ_FALSE);
+        }
+    }
+}
diff --git a/daemon/src/sip/pres_sub_server.h b/daemon/src/sip/pres_sub_server.h
new file mode 100644
index 0000000000000000000000000000000000000000..4375ba58f67f685ae8a5b97dc9eafbe4683513c7
--- /dev/null
+++ b/daemon/src/sip/pres_sub_server.h
@@ -0,0 +1,108 @@
+/*
+ *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ *  Author: Patrick Keroulas  <patrick.keroulas@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+
+#ifndef SERVERPRESENCESUB_H
+#define	SERVERPRESENCESUB_H
+
+#include <pj/string.h>
+#include <pjsip/sip_types.h>
+#include <pjsip-simple/evsub.h>
+#include <pjsip-simple/presence.h>
+#include <pjsip/sip_module.h>
+
+#include "src/noncopyable.h"
+
+extern pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata);
+
+static pjsip_module mod_presence_server = {
+    NULL, NULL, /* prev, next.		*/
+    pj_str("mod-presence-server"), /* Name.		*/
+    -1, /* Id			*/
+    PJSIP_MOD_PRIORITY_DIALOG_USAGE,
+    NULL, /* load()		*/
+    NULL, /* start()		*/
+    NULL, /* stop()		*/
+    NULL, /* unload()		*/
+    &pres_on_rx_subscribe_request, /* on_rx_request()	*/
+    NULL, /* on_rx_response()	*/
+    NULL, /* on_tx_request.	*/
+    NULL, /* on_tx_response()	*/
+    NULL, /* on_tsx_state()	*/
+
+};
+
+
+class SIPpresence;
+
+class PresSubServer {
+
+public:
+
+    PresSubServer(SIPPresence * pres, pjsip_evsub *evsub, char *r,pjsip_dialog *d);
+    ~PresSubServer();
+    /* TODO: add '< >' to URI for consistance*/
+    char *remote;    /**< Remote URI.			    */
+    /*
+     * Acces to the evsub expire variable.
+     * It was recieved in the SUBSCRIBE request.
+     */
+    void setExpires(int ms);
+    int getExpires();
+    /*
+     * Match method
+     * s is the URI (remote)
+     */
+    bool matches(char *s);
+    /*
+     * Allow the subscriber for being notified.
+     */
+    void approve(const bool& flag);
+    /*
+     * Notify subscriber with the pres_status_date of the account
+     */
+    void notify();
+
+    friend void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event);
+    friend pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata);
+
+private:
+
+    NON_COPYABLE(PresSubServer);
+    SIPPresence     *pres_;
+    pjsip_evsub	    *sub;	    /**< The evsub.			    */
+    pjsip_dialog    *dlg;	    /**< Dialog.			    */
+    int		    expires;	    /**< "expires" value in the request.    */
+    bool            approved;        /**< The client approved this subscription*/
+};
+
+
+#endif	/* SERVERPRESENCESUB_H */