diff --git a/src/call.cpp b/src/call.cpp
index d98aac8dfdb0888df61a0c9480154ae4313ac8aa..5ffb2a685aebe9a0ab4bbb7f5c7a9ecf8cbfdda1 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -44,6 +44,10 @@ Call::Call(Account& account, const std::string& id, Call::CallType type)
     , type_(type)
     , account_(account)
 {
+    addStateListener([this](UNUSED Call::CallState call_state,
+                            UNUSED Call::ConnectionState cnx_state,
+                            UNUSED int code) { checkPendingIM(); });
+
     time(&timestamp_start_);
     account_.attachCall(id_);
 }
@@ -159,21 +163,6 @@ Call::setState(CallState call_state, ConnectionState cnx_state, signed code)
     connectionState_ = cnx_state;
     auto new_client_state = getStateStr();
 
-    if (call_state == CallState::OVER) {
-        RING_DBG("[call:%s] %lu subcalls %lu listeners", id_.c_str(), subcalls.size(), stateChangedListeners_.size());
-        if (not subcalls.empty()) {
-            auto subs = std::move(subcalls);
-            for (auto c : subs)
-                c->hangup(0);
-            pendingInMessages_.clear();
-            pendingOutMessages_.clear();
-        }
-    } else if (call_state == CallState::ACTIVE and connectionState_ == ConnectionState::CONNECTED and not pendingOutMessages_.empty()) {
-        for (const auto& msg : pendingOutMessages_)
-            sendTextMessage(msg.first, msg.second);
-        pendingOutMessages_.clear();
-    }
-
     for (auto& l : stateChangedListeners_)
         l(callState_, connectionState_, code);
 
@@ -486,5 +475,28 @@ Call::merge(const std::shared_ptr<Call>& scall)
     scall->removeCall();
 }
 
+void
+Call::checkPendingIM()
+{
+    using namespace DRing::Call;
+
+    auto state = getStateStr();
+    if (state == StateEvent::OVER) {
+        // Hangup device's call when parent is over
+        if (not subcalls.empty()) {
+            auto subs = std::move(subcalls);
+            for (auto c : subs)
+                c->hangup(0);
+            pendingInMessages_.clear();
+            pendingOutMessages_.clear();
+        }
+    } else if (state == StateEvent::CURRENT) {
+        // Peer connected, time to send pending IM
+        // TODO not thread safe
+        for (const auto& msg : pendingOutMessages_)
+            sendTextMessage(msg.first, msg.second);
+        pendingOutMessages_.clear();
+    }
+}
 
 } // namespace ring
diff --git a/src/call.h b/src/call.h
index 27784aa03e91c5cfa21c870e2455c69f03b5c563..b9da627dc11c47a1d6319b90103f122cb8bba1b6 100644
--- a/src/call.h
+++ b/src/call.h
@@ -354,6 +354,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
          */
         Call(Account& account, const std::string& id, Call::CallType type);
 
+        // TODO all these members are not protected against multi-thread access
+
         std::shared_ptr<IceTransport> iceTransport_ {};
 
         bool isAudioMuted_{false};
@@ -367,6 +369,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
 
         bool validStateTransition(CallState newState);
 
+        void checkPendingIM();
+
         /** Protect every attribute that can be changed by two threads */
         mutable std::recursive_mutex callMutex_ {};