From 3c641a0d8350a015634d9015997932942b37e4f4 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Thu, 29 Mar 2018 02:59:46 +0200
Subject: [PATCH] Implement extended features

---
 .../quasseldroid/service/QuasselService.kt    |  8 +-
 .../kuschku/libquassel/protocol/ClientData.kt |  3 +-
 .../de/kuschku/libquassel/protocol/Message.kt |  2 +
 .../de/kuschku/libquassel/protocol/QTypes.kt  |  6 +-
 .../message/ClientInitAckSerializer.kt        |  6 +-
 .../protocol/message/ClientInitSerializer.kt  |  6 +-
 .../protocol/message/HandshakeMessage.kt      | 20 +++--
 .../primitive/serializer/BoolSerializer.kt    | 16 ++--
 .../serializer/BufferInfoSerializer.kt        |  6 +-
 .../serializer/ByteArraySerializer.kt         |  6 +-
 .../primitive/serializer/ByteSerializer.kt    |  6 +-
 .../primitive/serializer/CharSerializer.kt    | 56 ++++++------
 .../serializer/DateTimeSerializer.kt          |  6 +-
 .../DccConfig_IpDetectionModeSerializer.kt    |  6 +-
 .../DccConfig_PortSelectionModeSerializer.kt  |  6 +-
 .../HandshakeVariantMapSerializer.kt          | 10 ++-
 .../serializer/HostAddressSerializer.kt       |  6 +-
 .../primitive/serializer/IntSerializer.kt     |  6 +-
 .../primitive/serializer/LongSerializer.kt    |  6 +-
 .../primitive/serializer/MessageSerializer.kt | 15 ++--
 .../serializer/ProtocolInfoSerializer.kt      |  6 +-
 .../primitive/serializer/Serializer.kt        |  6 +-
 .../primitive/serializer/ShortSerializer.kt   |  6 +-
 .../serializer/StringListSerializer.kt        |  6 +-
 .../primitive/serializer/StringSerializer.kt  |  6 +-
 .../primitive/serializer/TimeSerializer.kt    |  6 +-
 .../serializer/VariantListSerializer.kt       |  7 +-
 .../serializer/VariantMapSerializer.kt        |  6 +-
 .../primitive/serializer/VariantSerializer.kt |  5 +-
 .../primitive/serializer/VoidSerializer.kt    |  6 +-
 .../kuschku/libquassel/quassel/BufferInfo.kt  |  2 +
 .../libquassel/quassel/ExtendedFeature.kt     | 35 ++++++++
 .../libquassel/quassel/LegacyFeature.kt       | 88 +++++++++++++++++++
 .../libquassel/quassel/ProtocolFeature.kt     |  1 +
 .../libquassel/quassel/QuasselFeature.kt      | 48 ----------
 .../libquassel/quassel/QuasselFeatures.kt     | 27 ++++++
 .../quassel/syncables/interfaces/INetwork.kt  |  1 +
 .../libquassel/session/CoreConnection.kt      |  3 +-
 .../de/kuschku/libquassel/session/Features.kt | 14 +--
 .../de/kuschku/libquassel/session/ISession.kt |  4 +-
 .../libquassel/session/MessageRunnable.kt     |  4 +-
 .../de/kuschku/libquassel/session/Session.kt  | 10 +--
 .../java/de/kuschku/libquassel/util/Flag.kt   | 10 ++-
 .../de/kuschku/libquassel/util/LongFlag.kt    |  8 +-
 .../de/kuschku/libquassel/util/ShortFlag.kt   |  5 ++
 .../kuschku/libquassel/ConnectionUnitTest.kt  |  4 +-
 46 files changed, 328 insertions(+), 198 deletions(-)
 create mode 100644 lib/src/main/java/de/kuschku/libquassel/quassel/ExtendedFeature.kt
 create mode 100644 lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
 delete mode 100644 lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeature.kt
 create mode 100644 lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeatures.kt

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 33a0e723e..73d59ca90 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
@@ -5,7 +5,11 @@ import android.arch.lifecycle.Observer
 import android.content.*
 import android.net.ConnectivityManager
 import android.os.Binder
-import de.kuschku.libquassel.protocol.*
+import de.kuschku.libquassel.protocol.ClientData
+import de.kuschku.libquassel.protocol.Protocol
+import de.kuschku.libquassel.protocol.Protocol_Feature
+import de.kuschku.libquassel.protocol.Protocol_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.session.*
 import de.kuschku.quasseldroid.BuildConfig
 import de.kuschku.quasseldroid.Keys
@@ -272,7 +276,7 @@ class QuasselService : DaggerLifecycleService(),
     clientData = ClientData(
       identifier = "${resources.getString(R.string.app_name)} ${BuildConfig.VERSION_NAME}",
       buildDate = Instant.ofEpochSecond(BuildConfig.GIT_COMMIT_DATE),
-      clientFeatures = Quassel_Features.of(*Quassel_Feature.validValues),
+      clientFeatures = QuasselFeatures.all(),
       protocolFeatures = Protocol_Features.of(
         Protocol_Feature.Compression,
         Protocol_Feature.TLS
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/ClientData.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/ClientData.kt
index cbd491c3f..1273ffa7d 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/ClientData.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/ClientData.kt
@@ -1,11 +1,12 @@
 package de.kuschku.libquassel.protocol
 
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import org.threeten.bp.Instant
 
 data class ClientData(
   val identifier: String,
   val buildDate: Instant,
-  val clientFeatures: Quassel_Features,
+  val clientFeatures: QuasselFeatures,
   val protocolFeatures: Protocol_Features,
   val supportedProtocols: List<Protocol>
 )
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
index cb8be217a..6853dc8b4 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
@@ -40,6 +40,7 @@ class Message(
       override val NONE = MessageType.of()
       override fun of(bit: Int) = Flags.of<MessageType>(bit)
       override fun of(vararg flags: MessageType) = Flags.of(*flags)
+      override fun of(flags: Iterable<MessageType>) = Flags.of(flags)
     }
   }
 
@@ -54,6 +55,7 @@ class Message(
       override val NONE = MessageFlag.of()
       override fun of(bit: Int) = Flags.of<MessageFlag>(bit)
       override fun of(vararg flags: MessageFlag) = Flags.of(*flags)
+      override fun of(flags: Iterable<MessageFlag>) = Flags.of(flags)
     }
   }
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
index a40e2a8f2..5b931a465 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
@@ -2,8 +2,8 @@ package de.kuschku.libquassel.protocol
 
 import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer
 import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.LegacyFeature
 import de.kuschku.libquassel.quassel.ProtocolFeature
-import de.kuschku.libquassel.quassel.QuasselFeature
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.Flags
 import de.kuschku.libquassel.util.ShortFlags
@@ -27,8 +27,8 @@ typealias Message_Types = Flags<Message_Type>
 typealias Message_Flag = Message.MessageFlag
 typealias Message_Flags = Flags<Message_Flag>
 
-typealias Quassel_Feature = QuasselFeature
-typealias Quassel_Features = Flags<Quassel_Feature>
+typealias Legacy_Feature = LegacyFeature
+typealias Legacy_Features = Flags<Legacy_Feature>
 
 typealias Protocol_Feature = ProtocolFeature
 typealias Protocol_Features = Flags<Protocol_Feature>
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
index c8b2c5970..5f45467c8 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
@@ -12,13 +12,15 @@ object ClientInitAckSerializer : HandshakeMessageSerializer<HandshakeMessage.Cli
     "CoreFeatures" to QVariant_(data.coreFeatures?.toInt(), Type.UInt),
     "StorageBackends" to QVariant_(data.backendInfo, Type.QVariantList),
     "Authenticator" to QVariant_(data.authenticatorInfo, Type.QVariantList),
-    "Configured" to QVariant_(data.coreConfigured, Type.Bool)
+    "Configured" to QVariant_(data.coreConfigured, Type.Bool),
+    "FeatureList" to QVariant_(data.featureList, Type.QStringList)
   )
 
   override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitAck(
     coreFeatures = Flags.Companion.of(data["CoreFeatures"].value(0)),
     backendInfo = data["StorageBackends"].value(),
     authenticatorInfo = data["Authenticators"].value(),
-    coreConfigured = data["Configured"].value()
+    coreConfigured = data["Configured"].value(),
+    featureList = data["FeatureList"].value(emptyList())
   )
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
index f82d5819c..9d7c44c0e 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
@@ -11,12 +11,14 @@ object ClientInitSerializer : HandshakeMessageSerializer<HandshakeMessage.Client
     "MsgType" to QVariant_("ClientInit", Type.QString),
     "ClientVersion" to QVariant_(data.clientVersion, Type.QString),
     "ClientDate" to QVariant_(data.buildDate, Type.QString),
-    "Features" to QVariant_(data.clientFeatures?.toInt(), Type.UInt)
+    "Features" to QVariant_(data.clientFeatures?.toInt(), Type.UInt),
+    "FeatureList" to QVariant_(data.featureList, Type.QStringList)
   )
 
   override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInit(
     clientVersion = data["ClientVersion"].value(),
     buildDate = data["ClientDate"].value(),
-    clientFeatures = Flags.of(data["Features"].value(0))
+    clientFeatures = Flags.of(data["Features"].value(0)),
+    featureList = data["FeatureList"].value(emptyList())
   )
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt
index 44b24598f..a4f584fa5 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt
@@ -1,16 +1,18 @@
 package de.kuschku.libquassel.protocol.message
 
+import de.kuschku.libquassel.protocol.Legacy_Features
 import de.kuschku.libquassel.protocol.QVariantList
 import de.kuschku.libquassel.protocol.QVariantMap
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.protocol.value
 
 
 sealed class HandshakeMessage {
-  class ClientInit(val clientVersion: String?, val buildDate: String?,
-                   val clientFeatures: Quassel_Features?) : HandshakeMessage() {
+  class ClientInit(
+    val clientVersion: String?, val buildDate: String?,
+    val clientFeatures: Legacy_Features?, val featureList: List<String>
+  ) : HandshakeMessage() {
     override fun toString(): String {
-      return "ClientInit(clientVersion=$clientVersion, buildDate=$buildDate, clientFeatures=$clientFeatures)"
+      return "ClientInit(clientVersion=$clientVersion, buildDate=$buildDate, clientFeatures=$clientFeatures, featureList=$featureList)"
     }
   }
 
@@ -20,11 +22,13 @@ sealed class HandshakeMessage {
     }
   }
 
-  class ClientInitAck(val coreFeatures: Quassel_Features?, val coreConfigured: Boolean?,
-                      val backendInfo: QVariantList?,
-                      val authenticatorInfo: QVariantList?) : HandshakeMessage() {
+  class ClientInitAck(
+    val coreFeatures: Legacy_Features?, val coreConfigured: Boolean?,
+    val backendInfo: QVariantList?, val authenticatorInfo: QVariantList?,
+    val featureList: List<String>
+  ) : HandshakeMessage() {
     override fun toString(): String {
-      return "ClientInitAck(coreFeatures=$coreFeatures, coreConfigured=$coreConfigured, backendInfo=$backendInfo, authenticatorInfo=$authenticatorInfo)"
+      return "ClientInitAck(coreFeatures=$coreFeatures, coreConfigured=$coreConfigured, backendInfo=$backendInfo, authenticatorInfo=$authenticatorInfo, featureList=$featureList)"
     }
   }
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializer.kt
index 3daf6f868..b08392ae6 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializer.kt
@@ -1,19 +1,13 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object BoolSerializer : Serializer<Boolean> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Boolean,
-                         features: Quassel_Features) = buffer.put(
-    if (data) {
-      0x01
-    } else {
-      0x00
-    }.toByte()
-  )
+  override fun serialize(buffer: ChainedByteBuffer, data: Boolean, features: QuasselFeatures) =
+    buffer.put((if (data) 0x01 else 0x00).toByte())
 
-  override fun deserialize(buffer: ByteBuffer,
-                           features: Quassel_Features) = buffer.get() != 0x00.toByte()
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures) =
+    buffer.get() != 0x00.toByte()
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializer.kt
index 0c8792133..46863a225 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializer.kt
@@ -1,13 +1,13 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object BufferInfoSerializer : Serializer<BufferInfo> {
-  override fun serialize(buffer: ChainedByteBuffer, data: BufferInfo, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: BufferInfo, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.bufferId, features)
     IntSerializer.serialize(buffer, data.networkId, features)
     ShortSerializer.serialize(buffer, data.type.toShort(), features)
@@ -15,7 +15,7 @@ object BufferInfoSerializer : Serializer<BufferInfo> {
     StringSerializer.UTF8.serialize(buffer, data.bufferName, features)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): BufferInfo {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): BufferInfo {
     val bufferId = IntSerializer.deserialize(buffer, features)
     val networkId = IntSerializer.deserialize(buffer, features)
     val type = Buffer_Type.of(ShortSerializer.deserialize(buffer, features))
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializer.kt
index b28d38e10..ec5fb51e7 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializer.kt
@@ -1,11 +1,11 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object ByteArraySerializer : Serializer<ByteBuffer?> {
-  override fun serialize(buffer: ChainedByteBuffer, data: ByteBuffer?, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: ByteBuffer?, features: QuasselFeatures) {
     if (data == null) {
       IntSerializer.serialize(buffer, -1, features)
     } else {
@@ -14,7 +14,7 @@ object ByteArraySerializer : Serializer<ByteBuffer?> {
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): ByteBuffer? {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): ByteBuffer? {
     val len = IntSerializer.deserialize(buffer, features)
     return if (len == -1) {
       null
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializer.kt
index 2772d82c9..e7611c12e 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializer.kt
@@ -1,15 +1,15 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object ByteSerializer : Serializer<Byte> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Byte, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Byte, features: QuasselFeatures) {
     buffer.put(data)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Byte {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Byte {
     return buffer.get()
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializer.kt
index b17c8a4bd..aa45a98d1 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializer.kt
@@ -1,44 +1,42 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 import java.nio.CharBuffer
 
 object CharSerializer : Serializer<Char> {
-  private val byteBuffer = ByteBuffer.allocateDirect(2)
-  private val charBuffer = CharBuffer.allocate(1)
+  private val byteBufferIn = ByteBuffer.allocateDirect(2)
+  private val byteBufferOut = ByteBuffer.allocateDirect(2)
+  private val charBufferIn = CharBuffer.allocate(1)
+  private val charBufferOut = CharBuffer.allocate(1)
   private val encoder = Charsets.UTF_16BE.newEncoder()
   private val decoder = Charsets.UTF_16BE.newDecoder()
 
-  override fun serialize(buffer: ChainedByteBuffer, data: Char, features: Quassel_Features) {
-    synchronized(this) {
-      charBuffer.clear()
-      charBuffer.put(data)
-      charBuffer.flip()
-      byteBuffer.clear()
-      encoder.encode(charBuffer, byteBuffer, true)
-      byteBuffer.flip()
-      if (byteBuffer.remaining() == 2) {
-        buffer.put(byteBuffer)
-      } else {
-        buffer.putShort(0)
-      }
+  override fun serialize(buffer: ChainedByteBuffer, data: Char, features: QuasselFeatures) {
+    charBufferIn.clear()
+    charBufferIn.put(data)
+    charBufferIn.flip()
+    byteBufferIn.clear()
+    encoder.encode(charBufferIn, byteBufferIn, true)
+    byteBufferIn.flip()
+    if (byteBufferIn.remaining() == 2) {
+      buffer.put(byteBufferIn)
+    } else {
+      buffer.putShort(0)
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Char {
-    synchronized(this) {
-      byteBuffer.clear()
-      byteBuffer.putShort(buffer.short)
-      byteBuffer.flip()
-      charBuffer.clear()
-      decoder.decode(byteBuffer, charBuffer, true)
-      charBuffer.flip()
-      return if (charBuffer.remaining() == 1)
-        charBuffer.get()
-      else
-        '\u0000'
-    }
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Char {
+    byteBufferOut.clear()
+    byteBufferOut.putShort(buffer.short)
+    byteBufferOut.flip()
+    charBufferOut.clear()
+    decoder.decode(byteBufferOut, charBufferOut, true)
+    charBufferOut.flip()
+    return if (charBufferOut.remaining() == 1)
+      charBufferOut.get()
+    else
+      '\u0000'
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt
index 1c7c30095..160109868 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt
@@ -1,6 +1,6 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import org.threeten.bp.*
 import org.threeten.bp.temporal.ChronoField
@@ -21,7 +21,7 @@ object DateTimeSerializer : Serializer<Temporal> {
     }
   }
 
-  override fun serialize(buffer: ChainedByteBuffer, data: Temporal, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Temporal, features: QuasselFeatures) {
     when (data) {
       is LocalDateTime  -> {
         IntSerializer.serialize(buffer, data.getLong(JulianFields.JULIAN_DAY).toInt(), features)
@@ -53,7 +53,7 @@ object DateTimeSerializer : Serializer<Temporal> {
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Temporal {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Temporal {
     val julianDay = IntSerializer.deserialize(buffer, features).toLong()
     val milliOfDay = IntSerializer.deserialize(buffer, features).toLong()
     val timeSpec = TimeSpec.of(ByteSerializer.deserialize(buffer, features))
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_IpDetectionModeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_IpDetectionModeSerializer.kt
index 88b5a8a28..a6efcada0 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_IpDetectionModeSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_IpDetectionModeSerializer.kt
@@ -1,18 +1,18 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.quassel.syncables.interfaces.IDccConfig
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object DccConfig_IpDetectionModeSerializer : Serializer<IDccConfig.IpDetectionMode> {
   override fun serialize(buffer: ChainedByteBuffer, data: IDccConfig.IpDetectionMode,
-                         features: Quassel_Features) {
+                         features: QuasselFeatures) {
     buffer.put(data.value)
   }
 
   override fun deserialize(buffer: ByteBuffer,
-                           features: Quassel_Features): IDccConfig.IpDetectionMode {
+                           features: QuasselFeatures): IDccConfig.IpDetectionMode {
     return IDccConfig.IpDetectionMode.of(buffer.get())
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_PortSelectionModeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_PortSelectionModeSerializer.kt
index f6b8ec28c..fc2530974 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_PortSelectionModeSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DccConfig_PortSelectionModeSerializer.kt
@@ -1,18 +1,18 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.quassel.syncables.interfaces.IDccConfig
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object DccConfig_PortSelectionModeSerializer : Serializer<IDccConfig.PortSelectionMode> {
   override fun serialize(buffer: ChainedByteBuffer, data: IDccConfig.PortSelectionMode,
-                         features: Quassel_Features) {
+                         features: QuasselFeatures) {
     buffer.put(data.value)
   }
 
   override fun deserialize(buffer: ByteBuffer,
-                           features: Quassel_Features): IDccConfig.PortSelectionMode {
+                           features: QuasselFeatures): IDccConfig.PortSelectionMode {
     return IDccConfig.PortSelectionMode.of(buffer.get())
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HandshakeVariantMapSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HandshakeVariantMapSerializer.kt
index c9bc28cef..f4da382ef 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HandshakeVariantMapSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HandshakeVariantMapSerializer.kt
@@ -1,11 +1,15 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.*
+import de.kuschku.libquassel.protocol.QVariantMap
+import de.kuschku.libquassel.protocol.QVariant_
+import de.kuschku.libquassel.protocol.Type
+import de.kuschku.libquassel.protocol.value
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object HandshakeVariantMapSerializer : Serializer<QVariantMap> {
-  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.size * 2, features)
     data.entries.forEach { (key, value) ->
       VariantSerializer.serialize(buffer, QVariant_(key, Type.QString), features)
@@ -13,7 +17,7 @@ object HandshakeVariantMapSerializer : Serializer<QVariantMap> {
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QVariantMap {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): QVariantMap {
     val range = 0 until IntSerializer.deserialize(buffer, features) / 2
     val pairs = range.map {
       val keyRaw: ByteBuffer? = VariantSerializer.deserialize(buffer, features).value()
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializer.kt
index ab1bc9a1f..ac45e38ea 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializer.kt
@@ -1,7 +1,7 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.NetworkLayerProtocol
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.net.Inet4Address
 import java.net.Inet6Address
@@ -9,7 +9,7 @@ import java.net.InetAddress
 import java.nio.ByteBuffer
 
 object HostAddressSerializer : Serializer<InetAddress> {
-  override fun serialize(buffer: ChainedByteBuffer, data: InetAddress, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: InetAddress, features: QuasselFeatures) {
     when (data) {
       is Inet4Address -> {
         ByteSerializer.serialize(buffer, NetworkLayerProtocol.IPv4Protocol.value, features)
@@ -29,7 +29,7 @@ object HostAddressSerializer : Serializer<InetAddress> {
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): InetAddress {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): InetAddress {
     val type = ByteSerializer.deserialize(buffer, features)
     return when (NetworkLayerProtocol.of(type)) {
       NetworkLayerProtocol.IPv4Protocol -> {
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializer.kt
index cf99f2398..f8ee2d849 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializer.kt
@@ -1,15 +1,15 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object IntSerializer : Serializer<Int> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Int, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Int, features: QuasselFeatures) {
     buffer.putInt(data)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Int {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Int {
     return buffer.int
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializer.kt
index 0cb80b3b2..fb82675fd 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializer.kt
@@ -1,15 +1,15 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object LongSerializer : Serializer<Long> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Long, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Long, features: QuasselFeatures) {
     buffer.putLong(data)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Long {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Long {
     return buffer.long
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
index 2dd02f8cb..89155782c 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
@@ -1,29 +1,26 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.Message
-import de.kuschku.libquassel.protocol.Quassel_Features
-import de.kuschku.libquassel.quassel.QuasselFeature
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.quassel.ExtendedFeature
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import org.threeten.bp.Instant
 import java.nio.ByteBuffer
 
 object MessageSerializer : Serializer<Message> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Message,
-                         features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Message, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.messageId, features)
     IntSerializer.serialize(buffer, data.time.epochSecond.toInt(), features)
     IntSerializer.serialize(buffer, data.type.toInt(), features)
     ByteSerializer.serialize(buffer, data.flag.toByte(), features)
     BufferInfoSerializer.serialize(buffer, data.bufferInfo, features)
     StringSerializer.UTF8.serialize(buffer, data.sender, features)
-    if (features.hasFlag(QuasselFeature.SenderPrefixes))
+    if (features.hasFeature(ExtendedFeature.SenderPrefixes))
       StringSerializer.UTF8.serialize(buffer, data.senderPrefixes, features)
     StringSerializer.UTF8.serialize(buffer, data.content, features)
   }
 
-  override fun deserialize(buffer: ByteBuffer,
-                           features: Quassel_Features): Message {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Message {
     return Message(
       messageId = IntSerializer.deserialize(buffer, features),
       time = Instant.ofEpochSecond(IntSerializer.deserialize(buffer, features).toLong()),
@@ -33,7 +30,7 @@ object MessageSerializer : Serializer<Message> {
       ),
       bufferInfo = BufferInfoSerializer.deserialize(buffer, features),
       sender = StringSerializer.UTF8.deserialize(buffer, features) ?: "",
-      senderPrefixes = if (features.hasFlag(QuasselFeature.SenderPrefixes))
+      senderPrefixes = if (features.hasFeature(ExtendedFeature.SenderPrefixes))
         StringSerializer.UTF8.deserialize(buffer, features) ?: "" else "",
       content = StringSerializer.UTF8.deserialize(buffer, features) ?: ""
     )
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
index aa2910614..fa585be55 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
@@ -1,20 +1,20 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.Protocol_Features
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.quassel.ProtocolInfo
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object ProtocolInfoSerializer : Serializer<ProtocolInfo> {
   override fun serialize(buffer: ChainedByteBuffer, data: ProtocolInfo,
-                         features: Quassel_Features) {
+                         features: QuasselFeatures) {
     ByteSerializer.serialize(buffer, data.flags.toByte(), features)
     ShortSerializer.serialize(buffer, data.data, features)
     ByteSerializer.serialize(buffer, data.version, features)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): ProtocolInfo {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): ProtocolInfo {
     return ProtocolInfo(
       Protocol_Features.of(ByteSerializer.deserialize(buffer, features).toInt()),
       ShortSerializer.deserialize(buffer, features),
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/Serializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/Serializer.kt
index 9181579fd..b83a10733 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/Serializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/Serializer.kt
@@ -17,11 +17,11 @@
 
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 interface Serializer<T> {
-  fun serialize(buffer: ChainedByteBuffer, data: T, features: Quassel_Features)
-  fun deserialize(buffer: ByteBuffer, features: Quassel_Features): T
+  fun serialize(buffer: ChainedByteBuffer, data: T, features: QuasselFeatures)
+  fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): T
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializer.kt
index f14967323..c450d2799 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializer.kt
@@ -1,15 +1,15 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object ShortSerializer : Serializer<Short> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Short, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Short, features: QuasselFeatures) {
     buffer.putShort(data)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Short {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Short {
     return buffer.short
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt
index 80589df3b..f896a2728 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt
@@ -1,20 +1,20 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.QStringList
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object StringListSerializer : Serializer<QStringList?> {
   override fun serialize(buffer: ChainedByteBuffer, data: QStringList?,
-                         features: Quassel_Features) {
+                         features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data?.size ?: 0, features)
     data?.forEach {
       StringSerializer.UTF16.serialize(buffer, it, features)
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QStringList {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): QStringList {
     val size = IntSerializer.deserialize(buffer, features)
     val res = ArrayList<String?>(size)
     for (i in 0 until size) {
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt
index 58e46597c..a9b2ef1d9 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt
@@ -1,6 +1,6 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.helpers.hexDump
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
@@ -46,7 +46,7 @@ abstract class StringSerializer(
     return buf
   }
 
-  override fun serialize(buffer: ChainedByteBuffer, data: String?, features: Quassel_Features) =
+  override fun serialize(buffer: ChainedByteBuffer, data: String?, features: QuasselFeatures) =
     try {
       if (data == null) {
         IntSerializer.serialize(buffer, -1, features)
@@ -99,7 +99,7 @@ abstract class StringSerializer(
     throw RuntimeException(e)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): String? = try {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): String? = try {
     val len = IntSerializer.deserialize(buffer, features)
     if (len == -1) {
       null
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/TimeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/TimeSerializer.kt
index 8de215d86..31679f738 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/TimeSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/TimeSerializer.kt
@@ -1,16 +1,16 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import org.threeten.bp.LocalTime
 import java.nio.ByteBuffer
 
 object TimeSerializer : Serializer<LocalTime> {
-  override fun serialize(buffer: ChainedByteBuffer, data: LocalTime, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: LocalTime, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, (data.toNanoOfDay() / 1000).toInt(), features)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): LocalTime {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): LocalTime {
     return LocalTime.ofNanoOfDay(IntSerializer.deserialize(buffer, features).toLong() * 1000)
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantListSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantListSerializer.kt
index f4c776ca6..c121938b3 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantListSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantListSerializer.kt
@@ -2,20 +2,19 @@ package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.QVariantList
 import de.kuschku.libquassel.protocol.QVariant_
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object VariantListSerializer : Serializer<QVariantList> {
-  override fun serialize(buffer: ChainedByteBuffer, data: QVariantList,
-                         features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantList, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.size, features)
     data.forEach {
       VariantSerializer.serialize(buffer, it, features)
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QVariantList {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): QVariantList {
     val length = IntSerializer.deserialize(buffer, features)
     val result = mutableListOf<QVariant_>()
     for (i in 0 until length) {
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantMapSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantMapSerializer.kt
index 916448afe..f8d1676f0 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantMapSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantMapSerializer.kt
@@ -1,12 +1,12 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.QVariantMap
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object VariantMapSerializer : Serializer<QVariantMap> {
-  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.size, features)
     data.entries.forEach { (key, value) ->
       StringSerializer.UTF16.serialize(buffer, key, features)
@@ -14,7 +14,7 @@ object VariantMapSerializer : Serializer<QVariantMap> {
     }
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QVariantMap {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): QVariantMap {
     return mutableMapOf(
       *(0 until IntSerializer.deserialize(buffer, features)).map {
         Pair(
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantSerializer.kt
index e54f80352..b57221a27 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VariantSerializer.kt
@@ -1,11 +1,12 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
 import de.kuschku.libquassel.protocol.*
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object VariantSerializer : Serializer<QVariant_> {
-  override fun serialize(buffer: ChainedByteBuffer, data: QVariant_, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariant_, features: QuasselFeatures) {
     IntSerializer.serialize(buffer, data.type.type.id, features)
     BoolSerializer.serialize(buffer, false, features)
     if (data.type.type == Type.UserType) {
@@ -17,7 +18,7 @@ object VariantSerializer : Serializer<QVariant_> {
     data.type.serializer.serialize(buffer, data.data, features)
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QVariant_ {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): QVariant_ {
     val rawType = IntSerializer.deserialize(buffer, features)
     val type = Type.of(rawType)
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VoidSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VoidSerializer.kt
index ff787e21f..cabd6a784 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VoidSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/VoidSerializer.kt
@@ -1,14 +1,14 @@
 package de.kuschku.libquassel.protocol.primitive.serializer
 
-import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import java.nio.ByteBuffer
 
 object VoidSerializer : Serializer<Any?> {
-  override fun serialize(buffer: ChainedByteBuffer, data: Any?, features: Quassel_Features) {
+  override fun serialize(buffer: ChainedByteBuffer, data: Any?, features: QuasselFeatures) {
   }
 
-  override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): Any? {
+  override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): Any? {
     return null
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
index bf9001455..b85e7ac3a 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
@@ -24,6 +24,7 @@ data class BufferInfo(
       val validValues = values().filter { it.bit != 0.toShort() }.toTypedArray()
       override fun of(bit: Short) = ShortFlags.of<Type>(bit)
       override fun of(vararg flags: Type) = ShortFlags.of(*flags)
+      override fun of(flags: Iterable<Type>) = ShortFlags.of(flags)
     }
   }
 
@@ -37,6 +38,7 @@ data class BufferInfo(
       override val NONE = Activity.of()
       override fun of(bit: Int) = Flags.of<Activity>(bit)
       override fun of(vararg flags: Activity) = Flags.of(*flags)
+      override fun of(flags: Iterable<Activity>) = Flags.of(flags)
     }
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/ExtendedFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/ExtendedFeature.kt
new file mode 100644
index 000000000..c9d0a62b3
--- /dev/null
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/ExtendedFeature.kt
@@ -0,0 +1,35 @@
+package de.kuschku.libquassel.quassel
+
+enum class ExtendedFeature {
+  SynchronizedMarkerLine,
+  SaslAuthentication,
+  SaslExternal,
+  HideInactiveNetworks,
+  PasswordChange,
+  /** IRCv3 capability negotiation, account tracking */
+  CapNegotiation,
+  /** IRC server SSL validation */
+  VerifyServerSSL,
+  /** IRC server custom message rate limits */
+  CustomRateLimits,
+  DccFileTransfer,
+  /** Timestamp formatting in away (e.g. %%hh:mm%%) */
+  AwayFormatTimestamp,
+  /** Whether or not the core supports auth backends. */
+  Authenticators,
+  /** Sync buffer activity status */
+  BufferActivitySync,
+  /** Core-Side highlight configuration and matching */
+  CoreSideHighlights,
+  /** Show prefixes for senders in backlog */
+  SenderPrefixes,
+  /** Supports RPC call disconnectFromCore to remotely disconnect a client */
+  RemoteDisconnect,
+  /** Transmit features as list of strings */
+  ExtendedFeatures;
+
+  companion object {
+    private val map = values().associateBy(ExtendedFeature::name)
+    fun of(name: String) = map[name]
+  }
+}
\ No newline at end of file
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
new file mode 100644
index 000000000..dd026c756
--- /dev/null
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
@@ -0,0 +1,88 @@
+package de.kuschku.libquassel.quassel
+
+import de.kuschku.libquassel.util.Flag
+import de.kuschku.libquassel.util.Flags
+
+/**
+ * A list of features that are optional in core and/or client, but need runtime checking
+ *
+ * Some features require an uptodate counterpart, but don't justify a protocol break.
+ * This is what we use this enum for. Add such features to it and check at runtime on the other
+ * side for their existence.
+ *
+ * This list should be cleaned up after every protocol break, as we can assume them to be present then.
+ */
+enum class LegacyFeature(override val bit: Int) : Flag<LegacyFeature> {
+  SynchronizedMarkerLine(0x0001),
+  SaslAuthentication(0x0002),
+  SaslExternal(0x0004),
+  HideInactiveNetworks(0x0008),
+  PasswordChange(0x0010),
+  /** IRCv3 capability negotiation, account tracking */
+  CapNegotiation(0x0020),
+  /** IRC server SSL validation */
+  VerifyServerSSL(0x0040),
+  /** IRC server custom message rate limits */
+  CustomRateLimits(0x0080),
+  DccFileTransfer(0x0100),
+  /** Timestamp formatting in away (e.g. %%hh:mm%%) */
+  AwayFormatTimestamp(0x0200),
+  /** Whether or not the core supports auth backends. */
+  Authenticators(0x0400),
+  /** Sync buffer activity status */
+  BufferActivitySync(0x0800),
+  /** Core-Side highlight configuration and matching */
+  CoreSideHighlights(0x1000),
+  /** Show prefixes for senders in backlog */
+  SenderPrefixes(0x2000),
+  /** Supports RPC call disconnectFromCore to remotely disconnect a client */
+  RemoteDisconnect(0x4000),
+  /** Transmit features as list of strings */
+  ExtendedFeatures(0x8000);
+
+  companion object : Flags.Factory<LegacyFeature> {
+    override val NONE: Flags<LegacyFeature> = LegacyFeature.of()
+    val validValues = values().filter { it.bit != 0 }.toTypedArray()
+    override fun of(bit: Int) = Flags.of<LegacyFeature>(bit)
+    override fun of(vararg flags: LegacyFeature) = Flags.of(*flags)
+    override fun of(flags: Iterable<LegacyFeature>) = Flags.of(flags)
+
+    fun fromExtended(it: ExtendedFeature) = when (it) {
+      ExtendedFeature.SynchronizedMarkerLine -> LegacyFeature.SynchronizedMarkerLine
+      ExtendedFeature.SaslAuthentication     -> LegacyFeature.SaslAuthentication
+      ExtendedFeature.SaslExternal           -> LegacyFeature.SaslExternal
+      ExtendedFeature.HideInactiveNetworks   -> LegacyFeature.HideInactiveNetworks
+      ExtendedFeature.PasswordChange         -> LegacyFeature.PasswordChange
+      ExtendedFeature.CapNegotiation         -> LegacyFeature.CapNegotiation
+      ExtendedFeature.VerifyServerSSL        -> LegacyFeature.VerifyServerSSL
+      ExtendedFeature.CustomRateLimits       -> LegacyFeature.CustomRateLimits
+      ExtendedFeature.DccFileTransfer        -> LegacyFeature.DccFileTransfer
+      ExtendedFeature.AwayFormatTimestamp    -> LegacyFeature.AwayFormatTimestamp
+      ExtendedFeature.Authenticators         -> LegacyFeature.Authenticators
+      ExtendedFeature.BufferActivitySync     -> LegacyFeature.BufferActivitySync
+      ExtendedFeature.CoreSideHighlights     -> LegacyFeature.CoreSideHighlights
+      ExtendedFeature.SenderPrefixes         -> LegacyFeature.SenderPrefixes
+      ExtendedFeature.RemoteDisconnect       -> LegacyFeature.RemoteDisconnect
+      ExtendedFeature.ExtendedFeatures       -> LegacyFeature.ExtendedFeatures
+    }
+  }
+
+  fun toExtended() = when (this) {
+    LegacyFeature.SynchronizedMarkerLine -> ExtendedFeature.SynchronizedMarkerLine
+    LegacyFeature.SaslAuthentication     -> ExtendedFeature.SaslAuthentication
+    LegacyFeature.SaslExternal           -> ExtendedFeature.SaslExternal
+    LegacyFeature.HideInactiveNetworks   -> ExtendedFeature.HideInactiveNetworks
+    LegacyFeature.PasswordChange         -> ExtendedFeature.PasswordChange
+    LegacyFeature.CapNegotiation         -> ExtendedFeature.CapNegotiation
+    LegacyFeature.VerifyServerSSL        -> ExtendedFeature.VerifyServerSSL
+    LegacyFeature.CustomRateLimits       -> ExtendedFeature.CustomRateLimits
+    LegacyFeature.DccFileTransfer        -> ExtendedFeature.DccFileTransfer
+    LegacyFeature.AwayFormatTimestamp    -> ExtendedFeature.AwayFormatTimestamp
+    LegacyFeature.Authenticators         -> ExtendedFeature.Authenticators
+    LegacyFeature.BufferActivitySync     -> ExtendedFeature.BufferActivitySync
+    LegacyFeature.CoreSideHighlights     -> ExtendedFeature.CoreSideHighlights
+    LegacyFeature.SenderPrefixes         -> ExtendedFeature.SenderPrefixes
+    LegacyFeature.RemoteDisconnect       -> ExtendedFeature.RemoteDisconnect
+    LegacyFeature.ExtendedFeatures       -> ExtendedFeature.ExtendedFeatures
+  }
+}
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
index 50bc4e18d..cadce1dd0 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
@@ -12,5 +12,6 @@ enum class ProtocolFeature(override val bit: Int) : Flag<ProtocolFeature> {
     override val NONE = ProtocolFeature.of()
     override fun of(bit: Int) = Flags.of<ProtocolFeature>(bit)
     override fun of(vararg flags: ProtocolFeature) = Flags.of(*flags)
+    override fun of(flags: Iterable<ProtocolFeature>) = Flags.of(flags)
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeature.kt
deleted file mode 100644
index fdda7bf83..000000000
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeature.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package de.kuschku.libquassel.quassel
-
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
-
-/**
- * A list of features that are optional in core and/or client, but need runtime checking
- *
- * Some features require an uptodate counterpart, but don't justify a protocol break.
- * This is what we use this enum for. Add such features to it and check at runtime on the other
- * side for their existence.
- *
- * This list should be cleaned up after every protocol break, as we can assume them to be present then.
- */
-enum class QuasselFeature(override val bit: Int) : Flag<QuasselFeature> {
-  None(0x0000),
-  SynchronizedMarkerLine(0x0001),
-  SaslAuthentication(0x0002),
-  SaslExternal(0x0004),
-  HideInactiveNetworks(0x0008),
-  PasswordChange(0x0010),
-  /** IRCv3 capability negotiation, account tracking */
-  CapNegotiation(0x0020),
-  /** IRC server SSL validation */
-  VerifyServerSSL(0x0040),
-  /** IRC server custom message rate limits */
-  CustomRateLimits(0x0080),
-  DccFileTransfer(0x0100),
-  /** Timestamp formatting in away (e.g. %%hh:mm%%) */
-  AwayFormatTimestamp(0x0200),
-  /** Whether or not the core supports auth backends. */
-  Authenticators(0x0400),
-  /** Sync buffer activity status */
-  BufferActivitySync(0x0800),
-  /** Core-Side highlight configuration and matching */
-  CoreSideHighlights(0x1000),
-  /** Show prefixes for senders in backlog */
-  SenderPrefixes(0x2000),
-  /** Supports RPC call disconnectFromCore to remotely disconnect a client */
-  RemoteDisconnect(0x4000);
-
-  companion object : Flags.Factory<QuasselFeature> {
-    override val NONE: Flags<QuasselFeature> = QuasselFeature.of()
-    val validValues = values().filter { it.bit != 0 }.toTypedArray()
-    override fun of(bit: Int) = Flags.of<QuasselFeature>(bit)
-    override fun of(vararg flags: QuasselFeature) = Flags.of(*flags)
-  }
-}
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeatures.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeatures.kt
new file mode 100644
index 000000000..6b61e4b66
--- /dev/null
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/QuasselFeatures.kt
@@ -0,0 +1,27 @@
+package de.kuschku.libquassel.quassel
+
+import de.kuschku.libquassel.protocol.Legacy_Feature
+import de.kuschku.libquassel.protocol.Legacy_Features
+
+class QuasselFeatures(
+  val enabledFeatures: Set<ExtendedFeature>,
+  val unknownFeatures: Set<String>
+) {
+  constructor(legacyFeatures: Legacy_Features?, extendedFeatures: Collection<String>) : this(
+    legacyFeatures?.enabledValues()?.map(Legacy_Feature::toExtended).orEmpty() union
+      extendedFeatures.mapNotNull { ExtendedFeature.of(it) },
+    extendedFeatures.filter { ExtendedFeature.of(it) == null }.toSet()
+  )
+
+  fun toInt() = LegacyFeature.of(enabledFeatures.map(LegacyFeature.Companion::fromExtended))
+
+  fun toStringList() = enabledFeatures.map(ExtendedFeature::name)
+
+  fun hasFeature(feature: ExtendedFeature) = enabledFeatures.contains(feature)
+
+  companion object {
+    fun empty() = QuasselFeatures(emptySet(), emptySet())
+    fun all() = QuasselFeatures(ExtendedFeature.values().toSet(), emptySet())
+  }
+}
+
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
index 9dc0caa42..e21882d7f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
@@ -267,6 +267,7 @@ interface INetwork : ISyncableObject {
       val validValues = values().filter { it.bit != 0 }.toTypedArray()
       override fun of(bit: Int) = Flags.of<ChannelModeType>(bit)
       override fun of(vararg flags: ChannelModeType) = Flags.of(*flags)
+      override fun of(flags: Iterable<ChannelModeType>) = Flags.of(flags)
     }
   }
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
index 5927e2264..90c2f3403 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
@@ -110,7 +110,8 @@ class CoreConnection(
             clientVersion = clientData.identifier,
             buildDate = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss")
               .format(clientData.buildDate.atOffset(ZoneOffset.UTC)),
-            clientFeatures = clientData.clientFeatures
+            clientFeatures = clientData.clientFeatures.toInt(),
+            featureList = clientData.clientFeatures.toStringList()
           )
         )
       }
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Features.kt b/lib/src/main/java/de/kuschku/libquassel/session/Features.kt
index 3c9b09535..ec68eac89 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/Features.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/Features.kt
@@ -1,12 +1,14 @@
 package de.kuschku.libquassel.session
 
-import de.kuschku.libquassel.protocol.Quassel_Features
-import de.kuschku.libquassel.util.and
+import de.kuschku.libquassel.quassel.QuasselFeatures
 
 data class Features(
-  var client: Quassel_Features,
-  var core: Quassel_Features
+  var client: QuasselFeatures,
+  var core: QuasselFeatures
 ) {
-  val negotiated: Quassel_Features
-    get() = core and client
+  val negotiated: QuasselFeatures
+    get() = QuasselFeatures(
+      core.enabledFeatures intersect client.enabledFeatures,
+      core.unknownFeatures union client.unknownFeatures
+    )
 }
\ No newline at end of file
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
index 427174783..a729f609f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
@@ -2,8 +2,8 @@ package de.kuschku.libquassel.session
 
 import de.kuschku.libquassel.protocol.IdentityId
 import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.quassel.syncables.*
 import io.reactivex.Observable
 import io.reactivex.subjects.BehaviorSubject
@@ -40,7 +40,7 @@ interface ISession : Closeable {
     val NULL = object : ISession {
       override val error = BehaviorSubject.create<HandshakeMessage>()
       override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED)
-      override val features: Features = Features(Quassel_Features.of(), Quassel_Features.of())
+      override val features: Features = Features(QuasselFeatures.empty(), QuasselFeatures.empty())
       override val sslSession: SSLSession? = null
 
       override val rpcHandler: RpcHandler? = null
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
index d253ac080..7f8cf765a 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
@@ -1,7 +1,7 @@
 package de.kuschku.libquassel.session
 
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.protocol.primitive.serializer.Serializer
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
 import de.kuschku.libquassel.util.helpers.write
@@ -14,7 +14,7 @@ class MessageRunnable<T>(
   private val serializer: Serializer<T>,
   private val chainedBuffer: ChainedByteBuffer,
   private val channel: WrappedChannel?,
-  private val features: Quassel_Features
+  private val features: QuasselFeatures
 ) : () -> Unit {
   override fun invoke() {
     try {
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
index 4c924616d..04f10cb53 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
@@ -3,13 +3,13 @@ package de.kuschku.libquassel.session
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.protocol.message.SignalProxyMessage
-import de.kuschku.libquassel.quassel.QuasselFeature
+import de.kuschku.libquassel.quassel.ExtendedFeature
+import de.kuschku.libquassel.quassel.QuasselFeatures
 import de.kuschku.libquassel.quassel.syncables.*
 import de.kuschku.libquassel.util.compatibility.HandlerService
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
-import de.kuschku.libquassel.util.hasFlag
 import io.reactivex.subjects.BehaviorSubject
 import org.threeten.bp.Instant
 import javax.net.ssl.X509TrustManager
@@ -23,7 +23,7 @@ class Session(
   private var userData: Pair<String, String>,
   val disconnectFromCore: () -> Unit
 ) : ProtocolHandler(), ISession {
-  override val features = Features(clientData.clientFeatures, Quassel_Features.of())
+  override val features = Features(clientData.clientFeatures, QuasselFeatures.empty())
 
   override val sslSession
     get() = coreConnection.sslSession
@@ -59,7 +59,7 @@ class Session(
   }
 
   override fun handle(f: HandshakeMessage.ClientInitAck): Boolean {
-    features.core = f.coreFeatures ?: Quassel_Feature.NONE
+    features.core = QuasselFeatures(f.coreFeatures, f.featureList)
 
     if (f.coreConfigured == true) {
       login()
@@ -132,7 +132,7 @@ class Session(
       synchronize(bufferSyncer, true)
       synchronize(bufferViewManager, true)
       synchronize(coreInfo, true)
-      if (features.negotiated.hasFlag(QuasselFeature.DccFileTransfer))
+      if (features.negotiated.hasFeature(ExtendedFeature.DccFileTransfer))
         synchronize(dccConfig, true)
       synchronize(ignoreListManager, true)
       synchronize(ircListHelper, true)
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt b/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt
index 9ab527903..7d0ae2df5 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt
@@ -49,16 +49,20 @@ data class Flags<E>(
     inline fun <reified T> of(int: Int): Flags<T>
       where T : Flag<T>, T : Enum<T> = Flags(int, enumValues())
 
-    inline fun <reified T> of(vararg flags: Flag<T>): Flags<T>
+    inline fun <reified T> of(vararg flags: T): Flags<T>
       where T : Flag<T>, T : Enum<T> =
-      Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues()
-      )
+      Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues())
+
+    inline fun <reified T> of(flags: Iterable<T>): Flags<T>
+      where T : Flag<T>, T : Enum<T> =
+      Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues())
   }
 
   interface Factory<E> where E : Flag<E>, E : Enum<E> {
     val NONE: Flags<E>
     fun of(bit: Int): Flags<E>
     fun of(vararg flags: E): Flags<E>
+    fun of(flags: Iterable<E>): Flags<E>
   }
 }
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt
index b30a6cd1d..7356adebc 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt
@@ -51,13 +51,17 @@ data class LongFlags<E>(
 
     inline fun <reified T> of(vararg flags: LongFlag<T>): LongFlags<T>
       where T : LongFlag<T>, T : Enum<T> =
-      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues()
-    )
+      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues())
+
+    inline fun <reified T> of(flags: Iterable<T>): LongFlags<T>
+      where T : LongFlag<T>, T : Enum<T> =
+      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues())
   }
 
   interface Factory<E> where E : LongFlag<E>, E : Enum<E> {
     fun of(bit: Long): LongFlags<E>
     fun of(vararg flags: E): LongFlags<E>
+    fun of(flags: Iterable<E>): LongFlags<E>
   }
 }
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt
index fd15fda6d..c7271d111 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt
@@ -57,11 +57,16 @@ data class ShortFlags<E>(
     inline fun <reified T> of(vararg flags: ShortFlag<T>): ShortFlags<T>
       where T : ShortFlag<T>, T : Enum<T> =
       ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues())
+
+    inline fun <reified T> of(flags: Iterable<T>): ShortFlags<T>
+      where T : ShortFlag<T>, T : Enum<T> =
+      ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues())
   }
 
   interface Factory<E> where E : ShortFlag<E>, E : Enum<E> {
     fun of(bit: Short): ShortFlags<E>
     fun of(vararg flags: E): ShortFlags<E>
+    fun of(flags: Iterable<E>): ShortFlags<E>
   }
 }
 
diff --git a/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt
index 53cbe7359..bf959c785 100644
--- a/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt
+++ b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt
@@ -1,8 +1,8 @@
 package de.kuschku.libquassel
 
 import de.kuschku.libquassel.protocol.*
+import de.kuschku.libquassel.quassel.LegacyFeature
 import de.kuschku.libquassel.quassel.ProtocolFeature
-import de.kuschku.libquassel.quassel.QuasselFeature
 import de.kuschku.libquassel.session.BacklogStorage
 import de.kuschku.libquassel.session.Session
 import de.kuschku.libquassel.session.SocketAddress
@@ -34,7 +34,7 @@ class ConnectionUnitTest {
       ClientData(
         identifier = "libquassel test",
         buildDate = Instant.EPOCH,
-        clientFeatures = Quassel_Feature.of(*QuasselFeature.validValues),
+        clientFeatures = Quassel_Feature.of(*LegacyFeature.validValues),
         protocolFeatures = Protocol_Feature.of(ProtocolFeature.TLS, ProtocolFeature.Compression),
         supportedProtocols = listOf(Protocol.Datastream),
         ), object : X509TrustManager {
-- 
GitLab