From ecc3f4b4300b6d048120152e567c83a3ed64a082 Mon Sep 17 00:00:00 2001
From: Janne Mareike Koschinski <janne@kuschku.de>
Date: Mon, 15 Feb 2021 12:11:18 +0100
Subject: [PATCH] Improved documentation further

---
 .../client/io/FixedDeflaterOutputStream.kt    |   4 +
 .../libquassel/client/util/TlsInfo.kt         |  19 +++
 .../handshake/ClientInitAckSerializer.kt      |   4 +-
 .../serializers/qt/StringSerializer.kt        |   6 +
 .../protocol/types/HandshakeMessage.kt        | 125 +++++++++++++++++-
 .../libquassel/protocol/types/TimeSpec.kt     |  37 +++++-
 .../libquassel/protocol/variant/QtType.kt     | 123 ++++++++++++++++-
 .../protocol/variant/QuasselType.kt           |  79 +++++++++++
 8 files changed, 392 insertions(+), 5 deletions(-)

diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/io/FixedDeflaterOutputStream.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/io/FixedDeflaterOutputStream.kt
index 56eafab..ff09c58 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/io/FixedDeflaterOutputStream.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/io/FixedDeflaterOutputStream.kt
@@ -22,6 +22,10 @@ package de.justjanne.libquassel.client.io
 import java.io.OutputStream
 import java.util.zip.DeflaterOutputStream
 
+/**
+ * Wrapper class around a [DeflaterOutputStream] correctly handling closing of
+ * the current stream
+ */
 class FixedDeflaterOutputStream(
   stream: OutputStream
 ) : DeflaterOutputStream(stream, true) {
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/util/TlsInfo.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/util/TlsInfo.kt
index db0f048..f5f46ba 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/util/TlsInfo.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/util/TlsInfo.kt
@@ -23,10 +23,26 @@ import java.security.cert.Certificate
 import java.security.cert.X509Certificate
 import javax.net.ssl.SSLSession
 
+/**
+ * Model representing the metadata of a negotiated TLS session
+ */
 data class TlsInfo(
+  /**
+   * Name of the TLS protocol, e.g. TLSv1.3
+   */
   val protocol: String,
+  /**
+   * Negotiated cipher suite
+   */
   val cipherSuite: String,
+  /**
+   * Negotiated key exchange mechanism if applicable
+   * Deprecated in TLSv1.3
+   */
   val keyExchangeMechanism: String?,
+  /**
+   * Peer certificate chain
+   */
   val certificateChain: List<X509Certificate>,
 ) {
 
@@ -54,6 +70,9 @@ data class TlsInfo(
       }
     }
 
+    /**
+     * Obtain the TLS metadata of an existing [SSLSession]
+     */
     fun ofSession(session: SSLSession): TlsInfo? {
       val (cipherSuite, keyExchangeMechanism) = parseCipherSuite(
         session.protocol,
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializer.kt
index 5aa439a..f8655c6 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializer.kt
@@ -49,10 +49,10 @@ object ClientInitAckSerializer : HandshakeSerializer<HandshakeMessage.ClientInit
   )
 
   override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitAck(
-    coreFeatures = LegacyFeature.of(data["CoreFeatures"].into<UInt>()),
+    coreConfigured = data["Configured"].into(),
     backendInfo = data["StorageBackends"].into(emptyList()),
     authenticatorInfo = data["Authenticators"].into(emptyList()),
-    coreConfigured = data["Configured"].into(),
+    coreFeatures = LegacyFeature.of(data["CoreFeatures"].into<UInt>()),
     featureList = data["FeatureList"].into<QStringList>(emptyList())
       .filterNotNull()
       .map(::QuasselFeatureName),
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt
index 4174161..4de6d62 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt
@@ -71,6 +71,9 @@ abstract class StringSerializer(
     return result
   }
 
+  /**
+   * Serialize a string, without length prefix, as a byte size
+   */
   fun serializeRaw(data: String?): ByteBuffer {
     val result = encoder().encode(data)
     if (nullLimited) {
@@ -82,6 +85,9 @@ abstract class StringSerializer(
     return result
   }
 
+  /**
+   * Deserialize a string from a given byte slice
+   */
   fun deserializeRaw(data: ByteBuffer): String {
     if (nullLimited) {
       data.limit(removeNullBytes(data.limit()))
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/HandshakeMessage.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/HandshakeMessage.kt
index 7126e63..447e6a2 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/HandshakeMessage.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/HandshakeMessage.kt
@@ -24,63 +24,186 @@ import de.justjanne.libquassel.protocol.features.QuasselFeatureName
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
+/**
+ * Model classes for messages exchanged during handshake
+ */
 sealed class HandshakeMessage {
+  /**
+   * Client registration message containing metadata about the connecting client
+   * Core should respond with either [ClientInitAck] or [ClientInitReject]
+   */
   data class ClientInit(
+    /**
+     * Human readable (HTML formatted) version of the client
+     */
     val clientVersion: String?,
+    /**
+     * Build timestamp of the client
+     */
     val buildDate: String?,
+    /**
+     * Set of legacy features supported
+     */
     val clientFeatures: LegacyFeatures,
+    /**
+     * List of supported features. If a feature can also be represented as
+     * legacy feature, it is included in both.
+     */
     val featureList: List<QuasselFeatureName>
   ) : HandshakeMessage()
 
+  /**
+   * Message representing a successful client registration attempt
+   * Contains metadata about the core
+   * Client should proceed with either [ClientLogin] or [CoreSetupData]
+   */
   data class ClientInitAck(
-    val coreFeatures: LegacyFeatures,
+    /**
+     * Whether or not the core needs to be configured via the quassel protocol
+     */
     val coreConfigured: Boolean?,
+    /**
+     * If the core needs to be configured, this contains metadata about the
+     * supported storage backends
+     */
     val backendInfo: QVariantList,
+    /**
+     * If the core needs to be configured, this contains metadata about the
+     * supported authentication backends
+     */
     val authenticatorInfo: QVariantList,
+    /**
+     * Set of legacy features supported
+     */
+    val coreFeatures: LegacyFeatures,
+    /**
+     * List of supported features. If a feature can also be represented as
+     * legacy feature, it is included in both.
+     */
     val featureList: List<QuasselFeatureName>
   ) : HandshakeMessage()
 
+  /**
+   * Message representing a failed client registration attempt
+   * Client should abort the connection
+   */
   data class ClientInitReject(
+    /**Username
+     * HTML-formatted error message
+     */
     val errorString: String?
   ) : HandshakeMessage()
 
+  /**
+   * Client login message containing authentication data
+   * Core should respond with either [ClientLoginAck] or [ClientLoginReject]
+   */
   data class ClientLogin(
+    /**
+     * Username of the core account
+     */
     val user: String?,
+    /**
+     * Password of the core account
+     */
     val password: String?
   ) : HandshakeMessage()
 
+  /**
+   * Message representing a successful client login attempt
+   * Client will receive [SessionInit] immediately afterwards
+   */
   object ClientLoginAck : HandshakeMessage() {
     override fun toString(): String {
       return "ClientLoginAck"
     }
   }
 
+  /**
+   * Message representing a failed client login attempt
+   * Client should retry with different [ClientLogin] or abort the connection
+   */
   data class ClientLoginReject(
+    /**
+     * HTML-formatted error message
+     */
     val errorString: String?
   ) : HandshakeMessage()
 
+  /**
+   * Message representing a successful core configuration attempt
+   * Client should proceed with [ClientLogin]
+   */
   object CoreSetupAck : HandshakeMessage() {
     override fun toString(): String {
       return "CoreSetupAck"
     }
   }
 
+  /**
+   * Core configuration message containing initial configuration properties
+   * Configuration has to happen before login
+   * Core should respond with either [CoreSetupAck] or [CoreSetupReject]
+   */
   data class CoreSetupData(
+    /**
+     * Username of a new core account to be created
+     */
     val adminUser: String?,
+    /**
+     * Password of a new core account to be created
+     */
     val adminPassword: String?,
+    /**
+     * Chosen storage backend id
+     */
     val backend: String?,
+    /**
+     * Storage backend configuration data
+     */
     val setupData: QVariantMap?,
+    /**
+     * Chosen authenticator backend id
+     */
     val authenticator: String?,
+    /**
+     * Authenticator backend configuration data
+     */
     val authSetupData: QVariantMap?
   ) : HandshakeMessage()
 
+  /**
+   * Message representing a failed core configuration attempt
+   * Client should retry with different [CoreSetupData] or abort the connection
+   */
   data class CoreSetupReject(
+    /**
+     * HTML-formatted error message
+     */
     val errorString: String?
   ) : HandshakeMessage()
 
+  /**
+   * Initial session data for the client
+   */
   data class SessionInit(
+    /**
+     * List of Identity sync objects existing at the current time
+     * Identity objects created or modified after [SessionInit] will be defined
+     * via sync updates and RPC identity creation messages
+     */
     val identities: QVariantList?,
+    /**
+     * List of existing buffers at the current time
+     * Buffers created or deleted after [SessionInit] will be defined via RPC
+     * messages
+     */
     val bufferInfos: QVariantList?,
+    /**
+     * List of Ids of Network sync objects existing at the current time
+     * Network objects created or modified after [SessionInit] will be defined
+     * via sync updates and RPC identity creation messages
+     */
     val networkIds: QVariantList?
   ) : HandshakeMessage()
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/TimeSpec.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/TimeSpec.kt
index 6d9bcf3..2b06efd 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/TimeSpec.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/types/TimeSpec.kt
@@ -19,15 +19,50 @@
 
 package de.justjanne.libquassel.protocol.types
 
-enum class TimeSpec(val value: Byte) {
+/**
+ * Zoned definition for timestamps
+ */
+enum class TimeSpec(
+  /**
+   * Underlying representation
+   */
+  val value: Byte
+) {
+  /**
+   * Unknown zone data
+   * Should be treated like [LocalStandard]
+   */
   LocalUnknown(-1),
+
+  /**
+   * Local zone data
+   * Should be serialized as local time without DST
+   */
   LocalStandard(0),
+
+  /**
+   * Local zone data
+   * Should be serialized as local time with DST, if applicable
+   */
   LocalDST(1),
+
+  /**
+   * Universal Time Coordinated
+   * Should be treated as a zone offset of 0
+   */
   UTC(2),
+
+  /**
+   * Time with specified offset in seconds
+   */
   OffsetFromUTC(3);
 
   companion object {
     private val map = values().associateBy(TimeSpec::value)
+
+    /**
+     * Obtain a zone specification by its underlying representation
+     */
     fun of(type: Byte) = map[type]
   }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QtType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QtType.kt
index c99fc1a..95169e3 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QtType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QtType.kt
@@ -19,33 +19,154 @@
 
 package de.justjanne.libquassel.protocol.variant
 
-enum class QtType(val id: kotlin.Int) {
+/**
+ * Supported qt types for serialization
+ */
+enum class QtType(
+  /**
+   * Underlying representation
+   */
+  val id: kotlin.Int
+) {
+  /**
+   * Void, no data at all
+   */
   Void(0),
+
+  /**
+   * 8-bit boolean, 0 is false, everything else is true
+   * See [kotlin.Boolean]
+   */
   Bool(1),
+
+  /**
+   * 8-bit signed integer
+   * See [kotlin.Byte]
+   */
   Char(131),
+
+  /**
+   * 8-bit unsigned integer
+   * See [kotlin.UByte]
+   */
   UChar(134),
+
+  /**
+   * 16-bit signed integer
+   * See [kotlin.Short]
+   */
   Short(130),
+
+  /**
+   * 16-bit unsigned integer
+   * See [kotlin.UShort]
+   */
   UShort(133),
+
+  /**
+   * 32-bit signed integer
+   * See [kotlin.Int]
+   */
   Int(2),
+
+  /**
+   * 32-bit unsigned integer
+   * See [kotlin.UInt]
+   */
   UInt(3),
+
+  /**
+   * 64-bit signed integer
+   * See [kotlin.Long]
+   */
   Long(129),
+
+  /**
+   * 64-bit unsigned integer
+   * See [kotlin.ULong]
+   */
   ULong(132),
+
+  /**
+   * 32-bit IEEE 754 float
+   * See [kotlin.Float]
+   */
   Float(135),
+
+  /**
+   * 64-bit IEEE 754 float
+   * See [kotlin.Double]
+   */
   Double(6),
+
+  /**
+   * Date in the gregorian calender as julian date
+   * See [org.threeten.bp.LocalDate]
+   */
   QDate(14),
+
+  /**
+   * Relative time in milliseconds since midnight
+   * See [org.threeten.bp.LocalTime]
+   */
   QTime(15),
+
+  /**
+   * Timestamp composed out of QDate, QTime and a zone specifier
+   */
   QDateTime(16),
+
+  /**
+   * 16-bit unicode character
+   * See [kotlin.Char]
+   */
   QChar(7),
+
+  /**
+   * UTF-16 big endian string
+   * See [kotlin.String]
+   */
   QString(10),
+
+  /**
+   * Length prefixes list of UTF-16 big endian strings
+   */
   QStringList(11),
+
+  /**
+   * Length prefixed slice of binary data
+   * See [java.nio.ByteBuffer]
+   */
   QByteArray(12),
+
+  /**
+   * Typed box
+   * See [QVariant]
+   */
   QVariant(138),
+
+  /**
+   * Length prefixed map of [QString] to [QVariant]
+   */
   QVariantMap(8),
+
+  /**
+   * Length prefixed list of [QVariant]
+   */
   QVariantList(9),
+
+  /**
+   * Custom data with a special (de-)serializer
+   * See [QuasselType]
+   */
   UserType(127);
 
   companion object {
     private val values = values().associateBy(QtType::id)
+
+    /**
+     * Obtain a QtType by its underlying representation
+     */
     fun of(id: kotlin.Int): QtType? = values[id]
   }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QuasselType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QuasselType.kt
index b163618..fb20daf 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QuasselType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QuasselType.kt
@@ -19,28 +19,107 @@
 
 package de.justjanne.libquassel.protocol.variant
 
+/**
+ * Supported quassel types for serialization
+ */
 enum class QuasselType(
+  /**
+   * Standardized name of the type
+   */
   val typeName: String,
+  /**
+   * Actual underlying serialization type
+   */
   val qtType: QtType = QtType.UserType,
 ) {
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.BufferId]
+   */
   BufferId("BufferId"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.BufferInfo]
+   */
   BufferInfo("BufferInfo"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.DccIpDetectionMode]
+   */
   DccConfigIpDetectionMode("DccConfig::IpDetectionMode"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.DccPortSelectionMode]
+   */
   DccConfigPortSelectionMode("DccConfig::PortSelectionMode"),
+
+  /**
+   * Type for IrcUser objects
+   * Serialized as [QVariantMap]
+   */
   IrcUser("IrcUser"),
+  /**
+   * Type for IrcChannel objects
+   * Serialized as [QVariantMap]
+   */
   IrcChannel("IrcChannel"),
+  /**
+   * Type for Identity objects
+   * Serialized as [QVariantMap]
+   */
   Identity("Identity"),
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.IdentityId]
+   */
   IdentityId("IdentityId"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.Message]
+   */
   Message("Message"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.MsgId]
+   */
   MsgId("MsgId"),
+
+  /**
+   * Type for [de.justjanne.libquassel.protocol.types.NetworkId]
+   */
   NetworkId("NetworkId"),
+  /**
+   * Type for NetworkInfo objects
+   * Serialized as [QVariantMap]
+   */
   NetworkInfo("NetworkInfo"),
+  /**
+   * Type for NetworkServer objects
+   * Serialized as [QVariantMap]
+   */
   NetworkServer("Network::Server"),
+
+  /**
+   * Type for [java.net.InetAddress]
+   */
   QHostAddress("QHostAddress"),
+
+  /**
+   * Serialization type for PeerPtr.
+   *
+   * This type is only used as placeholder for values that should only be used
+   * internally. During serialization it is serialized as a zero-valued 64-bit
+   * unsigned integer, during deserialization it is replaced by an object
+   * representing the RPC interface of the remote peer.
+   *
+   * This is used in the core to return responses to the same client that made
+   * a request.
+   */
   PeerPtr("PeerPtr");
 
   companion object {
     private val values = values().associateBy(QuasselType::typeName)
+    /**
+     * Obtain a QtType by its standardized name
+     */
     fun of(typeName: String?): QuasselType? = values[typeName]
   }
 }
-- 
GitLab