diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
index 1f4b2e043009a398f464eee1f695614212500895..7446e2eef91af6da9ee606c300f72bd0e62223e3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
@@ -33,6 +33,7 @@ import de.kuschku.libquassel.connection.SocketAddress
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.QuasselFeatures
+import de.kuschku.libquassel.quassel.syncables.BufferSyncer
 import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
 import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.session.Session
@@ -40,7 +41,11 @@ import de.kuschku.libquassel.session.SessionManager
 import de.kuschku.libquassel.session.manager.ConnectionInfo
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
+import de.kuschku.libquassel.util.flag.Flags
+import de.kuschku.libquassel.util.flag.minus
 import de.kuschku.libquassel.util.helper.clampOf
+import de.kuschku.libquassel.util.helper.combineLatest
+import de.kuschku.libquassel.util.helper.getOr
 import de.kuschku.libquassel.util.helper.value
 import de.kuschku.malheur.CrashHandler
 import de.kuschku.quasseldroid.Backend
@@ -138,6 +143,11 @@ class QuasselService : DaggerLifecycleService(),
   }
 
   private var accountId: Long = -1
+    set(value) {
+      field = value
+      liveAccountId.onNext(value)
+    }
+  private var liveAccountId = BehaviorSubject.createDefault(-1L)
   private var reconnect: Boolean = false
 
   @Inject
@@ -410,6 +420,38 @@ class QuasselService : DaggerLifecycleService(),
       }
     })
 
+    var buffersWithNewActivity = emptySet<BufferId>()
+    combineLatest(
+      liveAccountId.switchMap { database.filtered().listenRx(it).toObservable() },
+      sessionManager.connectedSession
+        .map(ISession::bufferSyncer)
+        .switchMap(BufferSyncer::liveActivities)
+    ).map { (filteredList, bufferActivities) ->
+      val filtered = filteredList.map {
+        Pair(it.bufferId, it.filtered)
+      }.toMap()
+
+      bufferActivities.mapValues { (bufferId, activities) ->
+        activities.minus(filtered.getOr(bufferId, 0).toUInt())
+      }.filterValues(Flags<Message_Type>::isNotEmpty).keys
+    }.map {
+      val newlyChangedBuffers = it - buffersWithNewActivity
+      buffersWithNewActivity = it
+      newlyChangedBuffers
+    }.map {
+      val bufferSyncer = sessionManager.connectedSession.value?.bufferSyncer
+      Pair(bufferSyncer, it.mapNotNull {
+        bufferSyncer?.bufferInfo(it)
+      })
+    }.toLiveData().observe(this, Observer { (bufferSyncer, bufferInfos) ->
+      val bufferViewManager = sessionManager.connectedSession.value?.bufferViewManager
+      if (bufferSyncer != null && bufferViewManager != null) {
+        for (bufferInfo in bufferInfos) {
+          bufferViewManager.handleBuffer(bufferInfo, bufferSyncer, unhide = true)
+        }
+      }
+    })
+
     ReactiveNetwork
       .observeNetworkConnectivity(applicationContext)
       .toLiveData()
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
index dbf9104a4e88bc9d62527e3865707a91809f8a79..c3df0ced20f64ce99f30906957fee068d32546a1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
@@ -217,19 +217,9 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
               if (info != null && !forceJoin) {
                 ChatActivity.launch(this, bufferId = info.bufferId)
               } else {
-                modelHelper.allBuffers.map {
-                  listOfNotNull(it.find {
-                    it.networkId == networkId &&
-                    it.bufferName == channel &&
-                    it.type.hasFlag(Buffer_Type.ChannelBuffer)
-                  })
-                }.filter {
-                  it.isNotEmpty()
-                }.firstElement().toLiveData().observeForever {
-                  it?.firstOrNull()?.let { info ->
-                    ChatActivity.launch(this, bufferId = info.bufferId)
-                  }
-                }
+                modelHelper.chat.chatToJoin.onNext(Optional.of(
+                  Pair(networkId, channel)
+                ))
 
                 session.bufferSyncer.find(
                   networkId = networkId,
@@ -871,6 +861,28 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
       }
     )
 
+    combineLatest(modelHelper.allBuffers,
+                  modelHelper.chat.chatToJoin).map { (buffers, chatToJoinOptional) ->
+      val chatToJoin = chatToJoinOptional.orNull()
+      if (chatToJoin == null) {
+        emptyList()
+      } else {
+        val (networkId, channel) = chatToJoin
+
+        listOfNotNull(buffers.find {
+          it.networkId == networkId &&
+          it.bufferName == channel &&
+          it.type.hasFlag(Buffer_Type.ChannelBuffer)
+        })
+      }
+    }.filter {
+      it.isNotEmpty()
+    }.firstElement().toLiveData().observeForever {
+      it?.firstOrNull()?.let { info ->
+        launch(this, bufferId = info.bufferId)
+      }
+    }
+
     onNewIntent(intent)
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
index b755b7bba5b75211cb9e9e2f67f441a0300fa1fb..81d61762cbcd6bf98e51d7d5ec8418c33b6659cd 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
@@ -34,6 +34,7 @@ import butterknife.BindView
 import butterknife.ButterKnife
 import com.google.android.material.bottomsheet.BottomSheetBehavior
 import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
+import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.helper.invoke
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.AppearanceSettings
@@ -200,6 +201,19 @@ class ChatlineFragment : ServiceBoundFragment() {
               for ((_, formatted) in lines) {
                 session.aliasManager.processInput(bufferInfo, formatted, output)
               }
+              for (command in output) {
+                if (command.message.startsWith("/join", ignoreCase = true)) {
+                  val channel = command.message
+                    .substringAfter(' ')
+                    .substringBefore(' ')
+                    .split(",")
+                    .last()
+
+                  modelHelper.chat.chatToJoin.onNext(Optional.of(
+                    Pair(command.buffer.networkId, channel)
+                  ))
+                }
+              }
               for (command in output) {
                 session.rpcHandler.sendInput(command.buffer, command.message)
               }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
index 4d8303d2ceb649017973716fbc5796df5990a005..eb2a8ac12d315c7b7c4ae9e623ee811e721795dd 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
@@ -26,7 +26,6 @@ import de.kuschku.libquassel.quassel.syncables.interfaces.IBufferSyncer
 import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.session.NotificationManager
 import de.kuschku.libquassel.util.Optional
-import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import io.reactivex.Observable
 import io.reactivex.subjects.BehaviorSubject
@@ -278,13 +277,6 @@ class BufferSyncer constructor(
 
   fun setBufferActivity(buffer: BufferId, activity: Message_Types) {
     super.setBufferActivity(buffer, activity.toInt())
-    if (activity hasFlag Message_Type.Plain ||
-        activity hasFlag Message_Type.Notice ||
-        activity hasFlag Message_Type.Action) {
-      bufferInfo(buffer)?.let {
-        session.bufferViewManager.handleBuffer(it, this, true)
-      }
-    }
     _bufferActivities[buffer] = activity
     live_bufferActivities.onNext(Unit)
   }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/ChatViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/ChatViewModel.kt
index 4ff17b287eefd9e98e9dc320843e364bfee6d70b..2e182483ab65f5a7c33a6944ec960a7761b8c338 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/ChatViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/ChatViewModel.kt
@@ -23,6 +23,7 @@ import android.os.Bundle
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.MsgId
 import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
 import io.reactivex.subjects.BehaviorSubject
@@ -42,6 +43,8 @@ open class ChatViewModel : QuasselViewModel() {
   val expandedNetworks = BehaviorSubject.createDefault(emptyMap<NetworkId, Boolean>())
   val selectedBufferId = BehaviorSubject.createDefault(BufferId.MAX_VALUE)
 
+  val chatToJoin = BehaviorSubject.createDefault(Optional.empty<Pair<NetworkId, String>>())
+
   val stateReset = BehaviorSubject.create<Unit>()
   val bufferOpened = PublishSubject.create<Unit>()