Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • api-redesign
  • main
  • 0.10.0
  • 0.10.1
  • 0.10.2
  • 0.7.0
  • 0.8.0
  • 0.8.1
  • 0.9.0
  • 0.9.1
  • 0.9.2
11 results

Target

Select target project
  • justJanne/libquassel
1 result
Select Git revision
  • api-redesign
  • main
  • 0.10.0
  • 0.10.1
  • 0.10.2
  • 0.7.0
  • 0.8.0
  • 0.8.1
  • 0.9.0
  • 0.9.1
  • 0.9.2
11 results
Show changes
Showing
with 0 additions and 2206 deletions
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
data class ObjectIdentifier(
val className: String,
val objectName: String
) {
constructor(syncable: SyncableStub) : this(syncable.className, syncable.objectName)
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.util.StateHolder
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import kotlinx.coroutines.flow.MutableStateFlow
class ObjectRepository : StateHolder<ObjectRepositoryState> {
fun add(syncable: SyncableStub): Boolean {
val identifier = ObjectIdentifier(syncable)
if (syncable is StatefulSyncableStub) {
state.update {
copy(
syncables = syncables + Pair(
identifier,
syncable
),
waiting = waiting + syncable
)
}
return true
} else {
state.update {
copy(
syncables = syncables + Pair(
identifier,
syncable
)
)
}
return false
}
}
fun init(syncable: SyncableStub, properties: QVariantMap) {
if (syncable is StatefulSyncableStub) {
syncable.fromVariantMap(properties)
syncable.initialized = true
state.update {
copy(waiting = waiting - syncable)
}
}
}
fun rename(syncable: SyncableStub, newName: String) {
val identifier = ObjectIdentifier(syncable)
state.update {
copy(
syncables = syncables - identifier + Pair(
identifier.copy(objectName = newName),
syncable
)
)
}
}
fun remove(syncable: SyncableStub) {
val identifier = ObjectIdentifier(syncable)
syncable.initialized = false
state.update {
copy(syncables = syncables - identifier)
}
}
fun find(className: String, objectName: String): SyncableStub? {
return state().syncables[ObjectIdentifier(className, objectName)]
}
inline fun <reified T : SyncableStub> find(objectName: String): T? {
return find(T::class.java.simpleName, objectName) as? T
}
override fun state() = flow().value
override fun flow() = state
private val state = MutableStateFlow(ObjectRepositoryState())
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
data class ObjectRepositoryState(
val syncables: Map<ObjectIdentifier, SyncableStub> = emptyMap(),
val waiting: Set<SyncableStub> = emptySet()
)
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.util.StateHolder
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
abstract class StatefulSyncableObject<T>(
session: Session?,
className: String,
state: T
) : SyncableObject(session, className), StatefulSyncableStub, StateHolder<T> {
override fun toString(): String {
return "$className(objectName=$objectName, state=${state()})"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is StatefulSyncableObject<*>) return false
if (!super.equals(other)) return false
if (state() != other.state()) return false
return true
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + state().hashCode()
return result
}
final override fun state(): T = state.value
final override fun flow(): Flow<T> = state
protected val state = MutableStateFlow(state)
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.annotations.ProtocolSide
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.qVariant
interface StatefulSyncableStub : SyncableStub {
fun fromVariantMap(properties: QVariantMap)
fun toVariantMap(): QVariantMap
/**
* Replaces all properties of the object with the content of the
* "properties" parameter. This parameter is in network representation.
*/
fun update(properties: QVariantMap) {
fromVariantMap(properties)
sync(
target = ProtocolSide.CLIENT,
"update",
qVariant(properties, QtType.QVariantMap)
)
}
/**
* Replaces all properties of the object with the content of the
* "properties" parameter. This parameter is in network representation.
*/
fun requestUpdate(properties: QVariantMap = toVariantMap()) {
sync(
target = ProtocolSide.CORE,
"requestUpdate",
qVariant(properties, QtType.QVariantMap)
)
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.session.Session
abstract class SyncableObject(
override var session: Session?,
override val className: String
) : SyncableStub {
final override var objectName: String = ""
internal set
final override var initialized: Boolean = false
protected fun renameObject(
newName: String
) {
val oldName = objectName
if (!initialized) {
objectName = newName
} else if (oldName != newName) {
objectName = newName
session?.objectRepository?.rename(this, newName)
session?.rename(className, oldName, newName)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is SyncableObject) return false
if (className != other.className) return false
if (objectName != other.objectName) return false
return true
}
override fun hashCode(): Int {
var result = className.hashCode()
result = 31 * result + objectName.hashCode()
return result
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.annotations.ProtocolSide
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.variant.QVariant_
interface SyncableStub {
val className: String
val objectName: String
var initialized: Boolean
val session: Session?
fun sync(target: ProtocolSide, function: String, vararg arg: QVariant_) {
if (initialized) {
session?.proxy?.sync(target, className, objectName, function, arg.toList())
}
}
fun rpc(target: ProtocolSide, function: String, vararg arg: QVariant_) {
if (initialized) {
session?.proxy?.rpc(target, function, arg.toList())
}
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.alias.Alias
import de.justjanne.libquassel.protocol.models.alias.Command
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.AliasManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.AliasManagerStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class AliasManager(
session: Session? = null,
state: AliasManagerState = AliasManagerState()
) : StatefulSyncableObject<AliasManagerState>(session, "AliasManager", state),
AliasManagerStub {
override fun toVariantMap(): QVariantMap = mapOf(
"Aliases" to qVariant(
mapOf(
"names" to qVariant(aliases().map(Alias::name), QtType.QStringList),
"expansions" to qVariant(aliases().map(Alias::expansion), QtType.QStringList)
),
QtType.QVariantMap
)
)
override fun fromVariantMap(properties: QVariantMap) {
val aliases = properties["Aliases"].into<QVariantMap>().orEmpty()
val names = aliases["names"].into<QStringList>().orEmpty()
val expansions = aliases["expansions"].into<List<String>>().orEmpty()
require(names.size == expansions.size) {
"Sizes do not match: names=${names.size}, expansions=${expansions.size}"
}
state.update {
copy(aliases = names.zip(expansions, Alias::of))
}
initialized = true
}
override fun addAlias(name: String, expansion: String) {
if (contains(name)) {
return
}
state.update {
copy(aliases = aliases + Alias(name, expansion))
}
super.addAlias(name, expansion)
}
fun aliases() = state().aliases
fun indexOf(name: String?) = state().indexOf(name)
fun contains(name: String?) = state().contains(name)
fun processInput(
info: BufferInfo,
message: String
) = state().processInput(
info,
session?.network(info.networkId)?.state(),
message
)
fun processInput(
info: BufferInfo,
message: String,
previousCommands: MutableList<Command>
) = state().processInput(
info,
session?.network(info.networkId)?.state(),
message,
previousCommands
)
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.SyncableObject
import de.justjanne.libquassel.protocol.syncables.stubs.BacklogManagerStub
open class BacklogManager(
session: Session? = null
) : SyncableObject(session, "BacklogManager"), BacklogManagerStub {
init {
initialized = true
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.bitflags.none
import de.justjanne.bitflags.of
import de.justjanne.bitflags.toBits
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.flags.MessageType
import de.justjanne.libquassel.protocol.models.flags.MessageTypes
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.models.ids.isValid
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.BufferSyncerState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferSyncerStub
import de.justjanne.libquassel.protocol.util.collections.pairs
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class BufferSyncer(
session: Session? = null,
state: BufferSyncerState = BufferSyncerState()
) : StatefulSyncableObject<BufferSyncerState>(session, "BufferSyncer", state),
BufferSyncerStub {
override fun toVariantMap() = mapOf(
"Activities" to qVariant(
state().activities.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value.toBits(), QtType.UInt)
)
},
QtType.QVariantList
),
"HighlightCounts" to qVariant(
state().highlightCounts.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QtType.Int)
)
},
QtType.QVariantList
),
"LastSeenMsg" to qVariant(
state().lastSeenMsg.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QuasselType.MsgId)
)
},
QtType.QVariantList
),
"MarkerLines" to qVariant(
state().markerLines.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QuasselType.MsgId)
)
},
QtType.QVariantList
),
)
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
activities = properties["Activities"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
MessageType.of(b.into<UInt>() ?: return@pairs null)
)
}?.filterNotNull()?.toMap().orEmpty(),
highlightCounts = properties["HighlightCounts"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<Int>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty(),
lastSeenMsg = properties["LastSeenMsg"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<MsgId>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty(),
markerLines = properties["MarkerLines"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<MsgId>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty()
)
}
initialized = true
}
fun initializeBufferInfos(infos: List<BufferInfo>) {
state.update {
copy(bufferInfos = infos.associateBy(BufferInfo::bufferId))
}
}
fun lastSeenMsg(buffer: BufferId): MsgId = state().lastSeenMsg[buffer] ?: MsgId(0)
fun markerLine(buffer: BufferId): MsgId = state().markerLines[buffer] ?: MsgId(0)
fun activity(buffer: BufferId): MessageTypes =
state().activities[buffer] ?: MessageType.none()
fun highlightCount(buffer: BufferId): Int = state().highlightCounts[buffer] ?: 0
fun bufferInfo(bufferId: BufferId) = state().bufferInfos[bufferId]
fun bufferInfos(): Collection<BufferInfo> = state().bufferInfos.values.toList()
override fun mergeBuffersPermanently(buffer: BufferId, buffer2: BufferId) {
removeBuffer(buffer2)
super.mergeBuffersPermanently(buffer, buffer2)
}
override fun removeBuffer(buffer: BufferId) {
state.update {
copy(
activities = activities - buffer,
lastSeenMsg = lastSeenMsg - buffer,
markerLines = markerLines - buffer,
highlightCounts = highlightCounts - buffer,
bufferInfos = bufferInfos - buffer
)
}
super.removeBuffer(buffer)
}
override fun setLastSeenMsg(buffer: BufferId, msgId: MsgId) {
if (!msgId.isValid() || lastSeenMsg(buffer) >= msgId) {
return
}
state.update {
copy(lastSeenMsg = lastSeenMsg + Pair(buffer, msgId))
}
super.setLastSeenMsg(buffer, msgId)
}
override fun setMarkerLine(buffer: BufferId, msgId: MsgId) {
if (!msgId.isValid() || markerLine(buffer) >= msgId) {
return
}
state.update {
copy(markerLines = markerLines + Pair(buffer, msgId))
}
super.setMarkerLine(buffer, msgId)
}
override fun setBufferActivity(buffer: BufferId, types: Int) {
state.update {
copy(activities = activities + Pair(buffer, MessageType.of(types.toUInt())))
}
super.setBufferActivity(buffer, types)
}
fun setBufferActivity(buffer: BufferId, types: MessageTypes) {
val oldTypes = activity(buffer)
state.update {
copy(activities = activities + Pair(buffer, types))
}
if ((types - oldTypes).isNotEmpty()) {
val bufferInfo = bufferInfo(buffer)
if (bufferInfo != null) {
session?.bufferViewManager?.handleBuffer(bufferInfo, true)
}
}
super.setBufferActivity(buffer, types.toBits().toInt())
}
override fun setHighlightCount(buffer: BufferId, count: Int) {
state.update {
copy(highlightCounts = highlightCounts + Pair(buffer, count))
}
super.setHighlightCount(buffer, count)
}
fun bufferInfoUpdated(info: BufferInfo) {
val oldInfo = bufferInfo(info.bufferId)
if (info != oldInfo) {
state.update {
copy(bufferInfos = bufferInfos + Pair(info.bufferId, info))
}
if (oldInfo != null) {
session?.bufferViewManager?.handleBuffer(info)
}
}
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.bitflags.of
import de.justjanne.bitflags.toBits
import de.justjanne.libquassel.protocol.models.BufferActivity
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.flags.BufferType
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewConfigStub
import de.justjanne.libquassel.protocol.util.collections.insert
import de.justjanne.libquassel.protocol.util.collections.move
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class BufferViewConfig(
session: Session? = null,
state: BufferViewConfigState
) : StatefulSyncableObject<BufferViewConfigState>(session, "BufferViewConfig", state),
BufferViewConfigStub {
init {
renameObject(state().identifier())
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
buffers = properties["BufferList"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
.orEmpty(),
removedBuffers = properties["RemovedBuffers"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
?.toSet()
.orEmpty(),
hiddenBuffers = properties["TemporarilyRemovedBuffers"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
?.toSet()
.orEmpty(),
bufferViewName = properties["bufferViewName"].into(bufferViewName),
networkId = properties["networkId"].into(networkId),
addNewBuffersAutomatically = properties["addNewBuffersAutomatically"].into(addNewBuffersAutomatically),
sortAlphabetically = properties["sortAlphabetically"].into(sortAlphabetically),
hideInactiveBuffers = properties["hideInactiveBuffers"].into(hideInactiveBuffers),
hideInactiveNetworks = properties["hideInactiveNetworks"].into(hideInactiveNetworks),
disableDecoration = properties["disableDecoration"].into(disableDecoration),
allowedBufferTypes = properties["allowedBufferTypes"].into<Int>()
?.let(Int::toUShort)
?.let(BufferType.Companion::of)
?: allowedBufferTypes,
minimumActivity = properties["minimumActivity"].into<Int>()
?.let(BufferActivity.Companion::of)
?: minimumActivity,
showSearch = properties["showSearch"].into(showSearch),
)
}
initialized = true
}
override fun toVariantMap() = mapOf(
"BufferList" to qVariant(
buffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"RemovedBuffers" to qVariant(
removedBuffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"TemporarilyRemovedBuffers" to qVariant(
hiddenBuffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"bufferViewName" to qVariant(bufferViewName(), QtType.QString),
"networkId" to qVariant(networkId(), QuasselType.NetworkId),
"addNewBuffersAutomatically" to qVariant(addNewBuffersAutomatically(), QtType.Bool),
"sortAlphabetically" to qVariant(sortAlphabetically(), QtType.Bool),
"hideInactiveBuffers" to qVariant(hideInactiveBuffers(), QtType.Bool),
"hideInactiveNetworks" to qVariant(hideInactiveNetworks(), QtType.Bool),
"disableDecoration" to qVariant(disableDecoration(), QtType.Bool),
"allowedBufferTypes" to qVariant(allowedBufferTypes().toBits().toInt(), QtType.Int),
"minimumActivity" to qVariant(minimumActivity()?.value?.toInt() ?: 0, QtType.Int),
"showSearch" to qVariant(showSearch(), QtType.Bool)
)
fun bufferViewId() = state().bufferViewId
fun bufferViewName() = state().bufferViewName
fun networkId() = state().networkId
fun addNewBuffersAutomatically() = state().addNewBuffersAutomatically
fun sortAlphabetically() = state().sortAlphabetically
fun hideInactiveBuffers() = state().hideInactiveBuffers
fun hideInactiveNetworks() = state().hideInactiveNetworks
fun disableDecoration() = state().disableDecoration
fun allowedBufferTypes() = state().allowedBufferTypes
fun minimumActivity() = state().minimumActivity
fun showSearch() = state().showSearch
fun buffers() = state().buffers
fun removedBuffers() = state().removedBuffers
fun hiddenBuffers() = state().hiddenBuffers
override fun addBuffer(buffer: BufferId, pos: Int) {
if (buffers().contains(buffer)) {
return
}
state.update {
copy(
buffers = buffers.insert(buffer, pos),
removedBuffers = removedBuffers - buffer,
hiddenBuffers = hiddenBuffers - buffer
)
}
super.addBuffer(buffer, pos)
}
override fun hideBuffer(buffer: BufferId) {
state.update {
copy(
buffers = buffers - buffer,
removedBuffers = removedBuffers - buffer,
hiddenBuffers = hiddenBuffers + buffer
)
}
super.hideBuffer(buffer)
}
override fun removeBuffer(buffer: BufferId) {
state.update {
copy(
buffers = buffers - buffer,
removedBuffers = removedBuffers + buffer,
hiddenBuffers = hiddenBuffers - buffer
)
}
super.removeBuffer(buffer)
}
override fun moveBuffer(buffer: BufferId, pos: Int) {
if (!buffers().contains(buffer)) {
return
}
state.update {
copy(
buffers = buffers.move(buffer, pos),
removedBuffers = removedBuffers - buffer,
hiddenBuffers = hiddenBuffers - buffer
)
}
super.moveBuffer(buffer, pos)
}
override fun setBufferViewName(value: String) {
state.update {
copy(bufferViewName = value)
}
super.setBufferViewName(value)
}
override fun setAddNewBuffersAutomatically(value: Boolean) {
state.update {
copy(addNewBuffersAutomatically = value)
}
super.setAddNewBuffersAutomatically(value)
}
override fun setAllowedBufferTypes(value: Int) {
state.update {
copy(allowedBufferTypes = BufferType.of(value.toUShort()))
}
super.setAllowedBufferTypes(value)
}
override fun setDisableDecoration(value: Boolean) {
state.update {
copy(disableDecoration = value)
}
super.setDisableDecoration(value)
}
override fun setHideInactiveBuffers(value: Boolean) {
state.update {
copy(hideInactiveBuffers = value)
}
super.setHideInactiveBuffers(value)
}
override fun setHideInactiveNetworks(value: Boolean) {
state.update {
copy(hideInactiveNetworks = value)
}
super.setHideInactiveNetworks(value)
}
override fun setMinimumActivity(value: Int) {
state.update {
copy(minimumActivity = BufferActivity.of(value))
}
super.setMinimumActivity(value)
}
override fun setNetworkId(value: NetworkId) {
state.update {
copy(networkId = value)
}
super.setNetworkId(value)
}
override fun setShowSearch(value: Boolean) {
state.update {
copy(showSearch = value)
}
super.setShowSearch(value)
}
override fun setSortAlphabetically(value: Boolean) {
state.update {
copy(sortAlphabetically = value)
}
super.setSortAlphabetically(value)
}
fun insertBufferSorted(info: BufferInfo) {
requestAddBuffer(
info.bufferId,
buffers()
.asSequence()
.withIndex()
.mapNotNull { (index, value) ->
IndexedValue(
index,
session?.bufferSyncer?.bufferInfo(value)
?: return@mapNotNull null
)
}
.filter { (_, value) -> value.networkId == info.networkId }
.find { (_, value) ->
String.CASE_INSENSITIVE_ORDER.compare(value.bufferName, info.bufferName) >= 0
}?.index ?: buffers().size
)
}
fun handleBuffer(info: BufferInfo, unhide: Boolean = false) {
if (addNewBuffersAutomatically() &&
!buffers().contains(info.bufferId) &&
!hiddenBuffers().contains(info.bufferId) &&
!removedBuffers().contains(info.bufferId) &&
!info.type.contains(BufferType.Status)
) {
insertBufferSorted(info)
} else if (unhide &&
!buffers().contains(info.bufferId) &&
hiddenBuffers().contains(info.bufferId)
) {
insertBufferSorted(info)
}
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
import de.justjanne.libquassel.protocol.syncables.state.BufferViewManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewManagerStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.QVariant_
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class BufferViewManager(
session: Session? = null,
state: BufferViewManagerState = BufferViewManagerState()
) : StatefulSyncableObject<BufferViewManagerState>(session, "BufferViewManager", state),
BufferViewManagerStub {
override fun fromVariantMap(properties: QVariantMap) {
properties["BufferViewIds"].into<QVariantList>()
?.mapNotNull<QVariant_, Int>(QVariant_::into)
?.forEach(this::addBufferViewConfig)
initialized = true
}
override fun toVariantMap() = mapOf(
"BufferViewIds" to qVariant(
state().bufferViewConfigs.map {
qVariant(it.key, QtType.Int)
},
QtType.QVariantList
)
)
fun contains(bufferViewId: Int) = state().contains(bufferViewId)
fun bufferViewConfig(bufferViewId: Int) = state().bufferViewConfig(bufferViewId)
fun bufferViewConfigs() = state().bufferViewConfigs()
override fun addBufferViewConfig(bufferViewConfigId: Int) {
if (contains(bufferViewConfigId)) {
return
}
val config = BufferViewConfig(
session,
BufferViewConfigState(
bufferViewId = bufferViewConfigId
)
)
session?.proxy?.synchronize(config)
state.update {
copy(bufferViewConfigs = bufferViewConfigs + Pair(bufferViewConfigId, config))
}
super.addBufferViewConfig(bufferViewConfigId)
}
fun handleBuffer(info: BufferInfo, unhide: Boolean = false) {
for (bufferViewConfig in bufferViewConfigs()) {
bufferViewConfig.handleBuffer(info, unhide)
}
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.CertManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.CertManagerStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import java.nio.ByteBuffer
open class CertManager(
session: Session? = null,
state: CertManagerState
) : StatefulSyncableObject<CertManagerState>(session, "CertManager", state),
CertManagerStub {
init {
renameObject(state().identifier())
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
privateKeyPem = StringSerializerUtf8.deserializeRaw(properties["sslKey"].into()),
certificatePem = StringSerializerUtf8.deserializeRaw(properties["sslCert"].into())
)
}
renameObject(state().identifier())
initialized = true
}
override fun toVariantMap() = mapOf(
"sslKey" to qVariant(StringSerializerUtf8.serializeRaw(state().privateKeyPem), QtType.QByteArray),
"sslCert" to qVariant(StringSerializerUtf8.serializeRaw(state().certificatePem), QtType.QByteArray)
)
override fun setSslKey(encoded: ByteBuffer) {
val pem = StringSerializerUtf8.deserializeRaw(encoded)
state.update {
copy(privateKeyPem = pem)
}
super.setSslKey(encoded)
}
override fun setSslCert(encoded: ByteBuffer) {
val pem = StringSerializerUtf8.deserializeRaw(encoded)
state.update {
copy(certificatePem = pem)
}
super.setSslCert(encoded)
}
fun privateKey() = state().privateKey
fun privateKeyPem() = state().privateKeyPem
fun certificate() = state().certificate
fun certificatePem() = state().certificatePem
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.ConnectedClient
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.CoreInfoState
import de.justjanne.libquassel.protocol.syncables.stubs.CoreInfoStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.QVariant_
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import org.threeten.bp.Instant
import org.threeten.bp.ZoneOffset
open class CoreInfo(
session: Session? = null,
state: CoreInfoState = CoreInfoState()
) : StatefulSyncableObject<CoreInfoState>(session, "CoreInfo", state),
CoreInfoStub {
override fun fromVariantMap(properties: QVariantMap) {
val coreData = properties["coreData"].into<QVariantMap>().orEmpty()
state.update {
copy(
version = coreData["quasselVersion"].into(version),
versionDate = coreData["quasselBuildDate"].into("")
.toLongOrNull()
?.let(Instant::ofEpochSecond),
startTime = coreData["startTime"].into(startTime.atOffset(ZoneOffset.UTC)).toInstant(),
connectedClientCount = coreData["sessionConnectedClients"].into(connectedClientCount),
connectedClients = coreData["sessionConnectedClientData"].into<QVariantList>()
?.mapNotNull<QVariant_, QVariantMap>(QVariant_::into)
?.map(ConnectedClient.Companion::fromVariantMap)
.orEmpty()
)
}
initialized = true
}
override fun toVariantMap() = mapOf(
"coreData" to qVariant(
mapOf(
"quasselVersion" to qVariant(version(), QtType.QString),
"quasselBuildDate" to qVariant(versionDate()?.epochSecond?.toString(), QtType.QString),
"startTime" to qVariant(startTime().atOffset(ZoneOffset.UTC), QtType.QDateTime),
"sessionConnectedClients" to qVariant(connectedClientCount(), QtType.Int),
"sessionConnectedClientData" to qVariant(
connectedClients()
.map(ConnectedClient::toVariantMap)
.map { qVariant(it, QtType.QVariantMap) },
QtType.QVariantList
)
),
QtType.QVariantMap
)
)
fun version() = state().version
fun versionDate() = state().versionDate
fun startTime() = state().startTime
fun connectedClientCount() = state().connectedClientCount
fun connectedClients() = state().connectedClients
override fun setCoreData(data: QVariantMap) {
fromVariantMap(data)
super.setCoreData(data)
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.dcc.DccIpDetectionMode
import de.justjanne.libquassel.protocol.models.dcc.DccPortSelectionMode
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.DccConfigState
import de.justjanne.libquassel.protocol.syncables.stubs.DccConfigStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import java.net.InetAddress
open class DccConfig(
session: Session? = null,
state: DccConfigState = DccConfigState()
) : StatefulSyncableObject<DccConfigState>(session, "DccConfig", state),
DccConfigStub {
init {
renameObject("DccConfig")
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
dccEnabled = properties["dccEnabled"].into(dccEnabled),
outgoingIp = properties["outgoingIp"].into(outgoingIp),
ipDetectionMode = properties["ipDetectionMode"].into(ipDetectionMode),
portSelectionMode = properties["portSelectionMode"].into(portSelectionMode),
minPort = properties["minPort"].into(minPort),
maxPort = properties["maxPort"].into(maxPort),
chunkSize = properties["chunkSize"].into(chunkSize),
sendTimeout = properties["sendTimeout"].into(sendTimeout),
usePassiveDcc = properties["usePassiveDcc"].into(usePassiveDcc),
useFastSend = properties["useFastSend"].into(useFastSend),
)
}
initialized = true
}
override fun toVariantMap() = mapOf(
"dccEnabled" to qVariant(state().dccEnabled, QtType.Bool),
"outgoingIp" to qVariant(state().outgoingIp, QuasselType.QHostAddress),
"ipDetectionMode" to qVariant(state().ipDetectionMode, QuasselType.DccConfigIpDetectionMode),
"portSelectionMode" to qVariant(state().portSelectionMode, QuasselType.DccConfigPortSelectionMode),
"minPort" to qVariant(state().minPort, QtType.UShort),
"maxPort" to qVariant(state().maxPort, QtType.UShort),
"chunkSize" to qVariant(state().chunkSize, QtType.Int),
"sendTimeout" to qVariant(state().sendTimeout, QtType.Int),
"usePassiveDcc" to qVariant(state().usePassiveDcc, QtType.Bool),
"useFastSend" to qVariant(state().useFastSend, QtType.Bool)
)
override fun setDccEnabled(enabled: Boolean) {
state.update {
copy(dccEnabled = enabled)
}
super.setDccEnabled(enabled)
}
override fun setOutgoingIp(outgoingIp: InetAddress) {
state.update {
copy(outgoingIp = outgoingIp)
}
super.setOutgoingIp(outgoingIp)
}
override fun setIpDetectionMode(ipDetectionMode: DccIpDetectionMode) {
state.update {
copy(ipDetectionMode = ipDetectionMode)
}
super.setIpDetectionMode(ipDetectionMode)
}
override fun setPortSelectionMode(portSelectionMode: DccPortSelectionMode) {
state.update {
copy(portSelectionMode = portSelectionMode)
}
super.setPortSelectionMode(portSelectionMode)
}
override fun setMinPort(port: UShort) {
state.update {
copy(minPort = port)
}
super.setMinPort(port)
}
override fun setMaxPort(port: UShort) {
state.update {
copy(maxPort = port)
}
super.setMaxPort(port)
}
override fun setChunkSize(chunkSize: Int) {
state.update {
copy(chunkSize = chunkSize)
}
super.setChunkSize(chunkSize)
}
override fun setSendTimeout(timeout: Int) {
state.update {
copy(sendTimeout = timeout)
}
super.setSendTimeout(timeout)
}
override fun setUsePassiveDcc(use: Boolean) {
state.update {
copy(usePassiveDcc = use)
}
super.setUsePassiveDcc(use)
}
override fun setUseFastSend(use: Boolean) {
state.update {
copy(useFastSend = use)
}
super.setUseFastSend(use)
}
fun isDccEnabled() = state().dccEnabled
fun outgoingIp() = state().outgoingIp
fun ipDetectionMode() = state().ipDetectionMode
fun portSelectionMode() = state().portSelectionMode
fun minPort() = state().minPort
fun maxPort() = state().maxPort
fun chunkSize() = state().chunkSize
fun sendTimeout() = state().sendTimeout
fun usePassiveDcc() = state().usePassiveDcc
fun useFastSend() = state().useFastSend
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.rules.HighlightNickType
import de.justjanne.libquassel.protocol.models.rules.HighlightRule
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.HighlightRuleManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.HighlightRuleManagerStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class HighlightRuleManager(
session: Session? = null,
state: HighlightRuleManagerState = HighlightRuleManagerState()
) : StatefulSyncableObject<HighlightRuleManagerState>(session, "HighlightRuleManager", state),
HighlightRuleManagerStub {
override fun fromVariantMap(properties: QVariantMap) {
val highlightRules = properties["HighlightRuleList"].into<QVariantMap>().orEmpty()
val idList = highlightRules["id"].into<QVariantList>().orEmpty()
val nameList = highlightRules["name"].into<QStringList>().orEmpty()
val isRegExList = highlightRules["isRegEx"].into<QVariantList>().orEmpty()
val isCaseSensitiveList = highlightRules["isCaseSensitive"].into<QVariantList>().orEmpty()
val isEnabledList = highlightRules["isEnabled"].into<QVariantList>().orEmpty()
val isInverseList = highlightRules["isInverse"].into<QVariantList>().orEmpty()
val senderList = highlightRules["sender"].into<QStringList>().orEmpty()
val channelList = highlightRules["channel"].into<QStringList>().orEmpty()
require(idList.size == nameList.size) {
"Sizes do not match: ids=${idList.size}, nameList=${nameList.size}"
}
require(idList.size == isRegExList.size) {
"Sizes do not match: ids=${idList.size}, isRegExList=${isRegExList.size}"
}
require(idList.size == isCaseSensitiveList.size) {
"Sizes do not match: ids=${idList.size}, isCaseSensitiveList=${isCaseSensitiveList.size}"
}
require(idList.size == isEnabledList.size) {
"Sizes do not match: ids=${idList.size}, isEnabledList=${isEnabledList.size}"
}
require(idList.size == isInverseList.size) {
"Sizes do not match: ids=${idList.size}, isInverseList=${isInverseList.size}"
}
require(idList.size == senderList.size) {
"Sizes do not match: ids=${idList.size}, senderList=${senderList.size}"
}
require(idList.size == channelList.size) {
"Sizes do not match: ids=${idList.size}, channelList=${channelList.size}"
}
state.update {
copy(
highlightNickType = properties["highlightNick"].into<Int>()
?.let(HighlightNickType.Companion::of)
?: highlightNickType,
highlightNickCaseSensitive = properties["nicksCaseSensitive"].into(highlightNickCaseSensitive),
rules = List(idList.size) {
HighlightRule(
idList[it].into(0),
nameList[it] ?: "",
isRegEx = isRegExList[it].into(false),
isCaseSensitive = isCaseSensitiveList[it].into(false),
isEnabled = isEnabledList[it].into(false),
isInverse = isInverseList[it].into(false),
sender = senderList[it] ?: "",
channel = channelList[it] ?: ""
)
}
)
}
initialized = true
}
override fun toVariantMap() = mapOf(
"HighlightRuleList" to qVariant(
mapOf(
"id" to qVariant(
state().rules.map { qVariant(it.id, QtType.Int) },
QtType.QVariantList
),
"name" to qVariant(
state().rules.map(HighlightRule::content),
QtType.QStringList
),
"isRegEx" to qVariant(
state().rules.map { qVariant(it.isRegEx, QtType.Bool) },
QtType.QVariantList
),
"isCaseSensitive" to qVariant(
state().rules.map { qVariant(it.isCaseSensitive, QtType.Bool) },
QtType.QVariantList
),
"isEnabled" to qVariant(
state().rules.map { qVariant(it.isEnabled, QtType.Bool) },
QtType.QVariantList
),
"isInverse" to qVariant(
state().rules.map { qVariant(it.isInverse, QtType.Bool) },
QtType.QVariantList
),
"sender" to qVariant(
state().rules.map(HighlightRule::sender),
QtType.QStringList
),
"channel" to qVariant(
state().rules.map(HighlightRule::channel),
QtType.QStringList
),
),
QtType.QVariantMap
),
"highlightNick" to qVariant(state().highlightNickType.value, QtType.Int),
"nicksCaseSensitive" to qVariant(state().highlightNickCaseSensitive, QtType.Bool)
)
fun indexOf(id: Int): Int = state().indexOf(id)
fun contains(id: Int) = state().contains(id)
fun isEmpty() = state().isEmpty()
fun count() = state().count()
fun removeAt(index: Int) {
state.update {
copy(rules = rules.take(index) + rules.drop(index + 1))
}
}
override fun removeHighlightRule(highlightRule: Int) {
removeAt(indexOf(highlightRule))
super.removeHighlightRule(highlightRule)
}
override fun toggleHighlightRule(highlightRule: Int) {
state.update {
copy(
rules = rules.map {
if (it.id != highlightRule) it
else it.copy(isEnabled = !it.isEnabled)
}
)
}
super.toggleHighlightRule(highlightRule)
}
override fun addHighlightRule(
id: Int,
content: String?,
isRegEx: Boolean,
isCaseSensitive: Boolean,
isEnabled: Boolean,
isInverse: Boolean,
sender: String?,
channel: String?
) {
if (contains(id)) {
return
}
state.update {
copy(
rules = rules + HighlightRule(
id,
content ?: "",
isRegEx,
isCaseSensitive,
isEnabled,
isInverse,
sender ?: "",
channel ?: ""
)
)
}
super.addHighlightRule(id, content, isRegEx, isCaseSensitive, isEnabled, isInverse, sender, channel)
}
override fun setHighlightNick(highlightNick: Int) {
state.update {
copy(highlightNickType = HighlightNickType.of(highlightNick) ?: highlightNickType)
}
super.setHighlightNick(highlightNick)
}
override fun setNicksCaseSensitive(nicksCaseSensitive: Boolean) {
state.update {
copy(highlightNickCaseSensitive = nicksCaseSensitive)
}
super.setNicksCaseSensitive(nicksCaseSensitive)
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.ids.IdentityId
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.IdentityState
import de.justjanne.libquassel.protocol.syncables.stubs.IdentityStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class Identity(
session: Session? = null,
state: IdentityState = IdentityState()
) : StatefulSyncableObject<IdentityState>(session, "Identity", state),
IdentityStub {
init {
renameObject(state().identifier())
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
identityId = properties["identityId"].into(identityId),
identityName = properties["identityName"].into(identityName),
realName = properties["realName"].into(realName),
nicks = properties["nicks"].into(nicks),
awayNick = properties["awayNick"].into(awayNick),
awayNickEnabled = properties["awayNickEnabled"].into(awayNickEnabled),
awayReason = properties["awayReason"].into(awayReason),
awayReasonEnabled = properties["awayReasonEnabled"].into(awayReasonEnabled),
autoAwayEnabled = properties["autoAwayEnabled"].into(autoAwayEnabled),
autoAwayTime = properties["autoAwayTime"].into(autoAwayTime),
autoAwayReason = properties["autoAwayReason"].into(autoAwayReason),
autoAwayReasonEnabled = properties["autoAwayReasonEnabled"].into(autoAwayReasonEnabled),
detachAwayEnabled = properties["detachAwayEnabled"].into(detachAwayEnabled),
detachAwayReason = properties["detachAwayReason"].into(detachAwayReason),
detachAwayReasonEnabled = properties["detachAwayReasonEnabled"].into(detachAwayReasonEnabled),
ident = properties["ident"].into(ident),
kickReason = properties["kickReason"].into(kickReason),
partReason = properties["partReason"].into(partReason),
quitReason = properties["quitReason"].into(quitReason),
)
}
renameObject(state().identifier())
initialized = true
}
override fun toVariantMap() = mapOf(
"identityId" to qVariant(id(), QuasselType.IdentityId),
"identityName" to qVariant(identityName(), QtType.QString),
"realName" to qVariant(realName(), QtType.QString),
"nicks" to qVariant(nicks(), QtType.QStringList),
"awayNick" to qVariant(awayNick(), QtType.QString),
"awayNickEnabled" to qVariant(awayNickEnabled(), QtType.Bool),
"awayReason" to qVariant(awayReason(), QtType.QString),
"awayReasonEnabled" to qVariant(awayReasonEnabled(), QtType.Bool),
"autoAwayEnabled" to qVariant(autoAwayEnabled(), QtType.Bool),
"autoAwayTime" to qVariant(autoAwayTime(), QtType.Int),
"autoAwayReason" to qVariant(autoAwayReason(), QtType.QString),
"autoAwayReasonEnabled" to qVariant(autoAwayReasonEnabled(), QtType.Bool),
"detachAwayEnabled" to qVariant(detachAwayEnabled(), QtType.Bool),
"detachAwayReason" to qVariant(detachAwayReason(), QtType.QString),
"detachAwayReasonEnabled" to qVariant(detachAwayReasonEnabled(), QtType.Bool),
"ident" to qVariant(ident(), QtType.QString),
"kickReason" to qVariant(kickReason(), QtType.QString),
"partReason" to qVariant(partReason(), QtType.QString),
"quitReason" to qVariant(quitReason(), QtType.QString)
)
fun id() = state().identityId
fun identityName() = state().identityName
fun realName() = state().realName
fun nicks() = state().nicks
fun awayNick() = state().awayNick
fun awayNickEnabled() = state().awayNickEnabled
fun awayReason() = state().awayReason
fun awayReasonEnabled() = state().awayReasonEnabled
fun autoAwayEnabled() = state().autoAwayEnabled
fun autoAwayTime() = state().autoAwayTime
fun autoAwayReason() = state().autoAwayReason
fun autoAwayReasonEnabled() = state().autoAwayReasonEnabled
fun detachAwayEnabled() = state().detachAwayEnabled
fun detachAwayReason() = state().detachAwayReason
fun detachAwayReasonEnabled() = state().detachAwayReasonEnabled
fun ident() = state().ident
fun kickReason() = state().kickReason
fun partReason() = state().partReason
fun quitReason() = state().quitReason
override fun setAutoAwayEnabled(enabled: Boolean) {
state.update {
copy(autoAwayEnabled = enabled)
}
super.setAutoAwayEnabled(enabled)
}
override fun setAutoAwayReason(reason: String?) {
state.update {
copy(autoAwayReason = reason ?: "")
}
super.setAutoAwayReason(reason)
}
override fun setAutoAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(autoAwayReasonEnabled = enabled)
}
super.setAutoAwayReasonEnabled(enabled)
}
override fun setAutoAwayTime(time: Int) {
state.update {
copy(autoAwayTime = time)
}
super.setAutoAwayTime(time)
}
override fun setAwayNick(awayNick: String?) {
state.update {
copy(awayNick = awayNick ?: "")
}
super.setAwayNick(awayNick)
}
override fun setAwayNickEnabled(enabled: Boolean) {
state.update {
copy(awayNickEnabled = enabled)
}
super.setAwayNickEnabled(enabled)
}
override fun setAwayReason(awayReason: String?) {
state.update {
copy(awayReason = awayReason ?: "")
}
super.setAwayReason(awayReason)
}
override fun setAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(awayReasonEnabled = enabled)
}
super.setAwayReasonEnabled(enabled)
}
override fun setDetachAwayEnabled(enabled: Boolean) {
state.update {
copy(detachAwayEnabled = enabled)
}
super.setDetachAwayEnabled(enabled)
}
override fun setDetachAwayReason(reason: String?) {
state.update {
copy(detachAwayReason = reason ?: "")
}
super.setDetachAwayReason(reason)
}
override fun setDetachAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(detachAwayReasonEnabled = enabled)
}
super.setDetachAwayReasonEnabled(enabled)
}
override fun setId(id: IdentityId) {
state.update {
copy(identityId = id)
}
super.setId(id)
}
override fun setIdent(ident: String?) {
state.update {
copy(ident = ident ?: "")
}
super.setIdent(ident)
}
override fun setIdentityName(name: String?) {
state.update {
copy(identityName = name ?: "")
}
super.setIdentityName(name)
}
override fun setKickReason(reason: String?) {
state.update {
copy(kickReason = reason ?: "")
}
super.setKickReason(reason)
}
override fun setNicks(nicks: QStringList) {
state.update {
copy(nicks = nicks.map { it ?: "" })
}
super.setNicks(nicks)
}
override fun setPartReason(reason: String?) {
state.update {
copy(partReason = reason ?: "")
}
super.setPartReason(reason)
}
override fun setQuitReason(reason: String?) {
state.update {
copy(quitReason = reason ?: "")
}
super.setQuitReason(reason)
}
override fun setRealName(realName: String?) {
state.update {
copy(realName = realName ?: "")
}
super.setRealName(realName)
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.flags.MessageTypes
import de.justjanne.libquassel.protocol.models.rules.IgnoreRule
import de.justjanne.libquassel.protocol.models.rules.IgnoreType
import de.justjanne.libquassel.protocol.models.rules.ScopeType
import de.justjanne.libquassel.protocol.models.rules.StrictnessType
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.IgnoreListManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.IgnoreListManagerStub
import de.justjanne.libquassel.protocol.util.collections.removeAt
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
class IgnoreListManager(
session: Session? = null,
state: IgnoreListManagerState = IgnoreListManagerState()
) : StatefulSyncableObject<IgnoreListManagerState>(session, "IgnoreListManager", state),
IgnoreListManagerStub {
override fun toVariantMap() = mapOf(
"IgnoreList" to qVariant(
mapOf(
"ignoreType" to qVariant(
state().rules.map {
qVariant(it.type.value, QtType.Int)
},
QtType.QVariantList
),
"ignoreRule" to qVariant(
state().rules.map(IgnoreRule::ignoreRule),
QtType.QStringList
),
"isRegEx" to qVariant(
state().rules.map {
qVariant(it.isRegEx, QtType.Bool)
},
QtType.QVariantList
),
"strictness" to qVariant(
state().rules.map {
qVariant(it.strictness.value, QtType.Int)
},
QtType.QVariantList
),
"scope" to qVariant(
state().rules.map {
qVariant(it.scope.value, QtType.Int)
},
QtType.QVariantList
),
"isActive" to qVariant(
state().rules.map {
qVariant(it.isEnabled, QtType.Bool)
},
QtType.QVariantList
),
"scopeRule" to qVariant(
state().rules.map(IgnoreRule::scopeRule),
QtType.QStringList
),
),
QtType.QVariantMap
)
)
override fun fromVariantMap(properties: QVariantMap) {
val ignoreRules = properties["IgnoreList"].into<QVariantMap>().orEmpty()
val ignoreTypeList = ignoreRules["ignoreType"].into<QVariantList>().orEmpty()
val ignoreRuleList = ignoreRules["ignoreRule"].into<QStringList>().orEmpty()
val isRegExList = ignoreRules["isRegEx"].into<QVariantList>().orEmpty()
val strictnessList = ignoreRules["strictness"].into<QVariantList>().orEmpty()
val isEnabledList = ignoreRules["isActive"].into<QVariantList>().orEmpty()
val scopeList = ignoreRules["scope"].into<QVariantList>().orEmpty()
val scopeRuleList = ignoreRules["scopeRule"].into<QStringList>().orEmpty()
require(ignoreTypeList.size == ignoreRuleList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, ignoreRule=${ignoreRuleList.size}"
}
require(ignoreTypeList.size == isRegExList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, isRegExList=${isRegExList.size}"
}
require(ignoreTypeList.size == strictnessList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, strictnessList=${strictnessList.size}"
}
require(ignoreTypeList.size == isEnabledList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, isEnabledList=${isEnabledList.size}"
}
require(ignoreTypeList.size == scopeList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, scopeList=${scopeList.size}"
}
require(ignoreTypeList.size == scopeRuleList.size) {
"Sizes do not match: ids=${ignoreTypeList.size}, scopeRuleList=${scopeRuleList.size}"
}
state.update {
copy(
rules = List(ignoreTypeList.size) {
IgnoreRule(
type = ignoreTypeList[it].into<Int>()?.let(IgnoreType::of)
?: IgnoreType.SenderIgnore,
ignoreRule = ignoreRuleList[it] ?: "",
isRegEx = isRegExList[it].into(false),
strictness = strictnessList[it].into<Int>()?.let(StrictnessType::of)
?: StrictnessType.UnmatchedStrictness,
isEnabled = isEnabledList[it].into(false),
scope = scopeList[it].into<Int>()?.let(ScopeType::of)
?: ScopeType.GlobalScope,
scopeRule = scopeRuleList[it] ?: "",
)
}
)
}
initialized = true
}
fun indexOf(ignoreRule: String?): Int = state().indexOf(ignoreRule)
fun contains(ignoreRule: String?) = state().contains(ignoreRule)
fun isEmpty() = state().isEmpty()
fun count() = state().count()
fun removeAt(index: Int) {
state.update {
copy(rules = rules.removeAt(index))
}
}
override fun addIgnoreListItem(
type: Int,
ignoreRule: String?,
isRegEx: Boolean,
strictness: Int,
scope: Int,
scopeRule: String?,
isActive: Boolean
) {
if (contains(ignoreRule)) {
return
}
state.update {
copy(
rules = rules + IgnoreRule(
type = IgnoreType.of(type) ?: return,
ignoreRule = ignoreRule ?: "",
isRegEx = isRegEx,
strictness = StrictnessType.of(strictness) ?: return,
scope = ScopeType.of(scope) ?: return,
scopeRule = scopeRule ?: "",
isEnabled = isActive
)
)
}
super.addIgnoreListItem(type, ignoreRule, isRegEx, strictness, scope, scopeRule, isActive)
}
override fun removeIgnoreListItem(ignoreRule: String?) {
removeAt(indexOf(ignoreRule))
super.removeIgnoreListItem(ignoreRule)
}
override fun toggleIgnoreRule(ignoreRule: String?) {
state.update {
copy(
rules = rules.map {
if (it.ignoreRule != ignoreRule) it
else it.copy(isEnabled = !it.isEnabled)
}
)
}
super.toggleIgnoreRule(ignoreRule)
}
fun match(
msgContents: String,
msgSender: String,
msgType: MessageTypes,
network: String,
bufferName: String
) = state().match(msgContents, msgSender, msgType, network, bufferName)
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.network.ChannelModeType
import de.justjanne.libquassel.protocol.models.network.ChannelModes
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.StatefulSyncableObject
import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
import de.justjanne.libquassel.protocol.syncables.stubs.IrcChannelStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.indexed
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
open class IrcChannel(
session: Session? = null,
state: IrcChannelState
) : StatefulSyncableObject<IrcChannelState>(session, "IrcChannel", state),
IrcChannelStub {
init {
require(name().isNotEmpty()) {
"IrcChannel: channelName is empty"
}
renameObject(state().identifier())
}
override fun fromVariantMap(properties: QVariantMap) =
fromVariantMap(properties, null)
fun fromVariantMap(properties: QVariantMap, index: Int?) {
state.update {
copy(
name = properties["name"].indexed(index).into(name),
topic = properties["topic"].indexed(index).into(topic),
password = properties["password"].indexed(index).into(password),
encrypted = properties["encrypted"].indexed(index).into(encrypted),
channelModes = properties["ChanModes"].indexed(index).into<QVariantMap>()
?.let(ChannelModes.Companion::fromVariantMap) ?: channelModes,
userModes = properties["UserModes"].into<QVariantMap>()
?.mapValues { (_, value) -> value.into<String>()?.toSet().orEmpty() }
.orEmpty()
)
}
renameObject(state().identifier())
initialized = true
}
override fun toVariantMap(): QVariantMap {
return mapOf(
"name" to qVariant(name(), QtType.QString),
"topic" to qVariant(topic(), QtType.QString),
"password" to qVariant(password(), QtType.QString),
"encrypted" to qVariant(isEncrypted(), QtType.Bool),
"ChanModes" to qVariant(state().channelModes.toVariantMap(), QtType.QVariantMap),
"UserModes" to qVariant(
state().userModes.mapValues { (_, value) ->
qVariant(value.joinToString(), QtType.QString)
},
QtType.QVariantMap
)
)
}
fun network() = state().network
fun name() = state().name
fun topic() = state().topic
fun password() = state().password
fun isEncrypted() = state().encrypted
fun ircUsers() = state().ircUsers(session?.network(network())?.state())
fun userCount() = state().userModes.size
fun userModes(nick: String) = state().userModes[nick]
fun hasMode(mode: Char) = state().hasMode(session?.network(network())?.state(), mode)
fun modeValue(mode: Char) = state().modeValue(session?.network(network())?.state(), mode)
fun modeValues(mode: Char) = state().modeValues(session?.network(network())?.state(), mode)
fun channelModeString() = state().channelModeString()
override fun setTopic(topic: String) {
state.update {
copy(topic = topic)
}
super.setTopic(topic)
}
override fun setPassword(password: String) {
state.update {
copy(password = password)
}
super.setPassword(password)
}
override fun setEncrypted(encrypted: Boolean) {
state.update {
copy(encrypted = encrypted)
}
super.setEncrypted(encrypted)
}
override fun joinIrcUsers(nicks: QStringList, modes: QStringList) {
joinIrcUsers(
nicks.filterNotNull().zip(modes).map { (nick, mode) ->
Pair(nick, mode?.toSet().orEmpty())
}.toMap()
)
super.joinIrcUsers(nicks, modes)
}
private fun joinIrcUsers(map: Map<String, Set<Char>>) {
val network = session?.network(network())
val newNicks = map.keys - state().userModes.keys
state.update {
copy(
userModes = userModes + map.mapValues { (key, value) ->
value + userModes[key].orEmpty()
}
)
}
for (newNick in newNicks) {
network
?.ircUser(newNick)
?.joinChannel(this, skipChannelJoin = true)
}
}
fun joinIrcUser(user: IrcUser) = joinIrcUsers(
mapOf(
user.nick() to emptySet()
)
)
override fun part(nick: String) {
val network = session?.network(network())
val partingUser = network?.ircUser(nick)
if (partingUser != null) {
partingUser.partChannel(name())
if (network.isMe(partingUser) || state().userModes.isEmpty()) {
for (nickname in state().userModes.keys.toList()) {
network.ircUser(nickname)?.partChannel(this)
}
state.update {
copy(channelModes = ChannelModes())
}
network.removeIrcChannel(this)
session?.proxy?.stopSynchronize(this)
}
}
super.part(nick)
}
override fun setUserModes(nick: String, modes: String?) {
state.update {
copy(
userModes = userModes + Pair(
nick,
modes?.toSet().orEmpty()
)
)
}
super.setUserModes(nick, modes)
}
override fun addUserMode(nick: String, mode: String?) {
state.update {
copy(
userModes = userModes + Pair(
nick,
userModes[nick].orEmpty() + mode?.toSet().orEmpty()
)
)
}
super.addUserMode(nick, mode)
}
override fun removeUserMode(nick: String, mode: String?) {
state.update {
copy(
userModes = userModes + Pair(
nick,
userModes[nick].orEmpty() - mode?.toSet().orEmpty()
)
)
}
super.addUserMode(nick, mode)
}
override fun addChannelMode(mode: Char, value: String?) {
val network = session?.network(network())
state.update {
copy(
channelModes = channelModes.run {
when (network?.channelModeType(mode)) {
ChannelModeType.A_CHANMODE -> {
requireNotNull(value) {
"Mode $mode of ChannelModeType A must have a value"
}
copy(a = a + Pair(mode, a[mode].orEmpty() + value))
}
ChannelModeType.B_CHANMODE -> {
requireNotNull(value) {
"Mode $mode of ChannelModeType B must have a value"
}
copy(b = b + Pair(mode, value))
}
ChannelModeType.C_CHANMODE -> {
requireNotNull(value) {
"Mode $mode of ChannelModeType C must have a value"
}
copy(c = c + Pair(mode, value))
}
ChannelModeType.D_CHANMODE ->
copy(d = d + mode)
else -> channelModes
}
}
)
}
super.addChannelMode(mode, value)
}
override fun removeChannelMode(mode: Char, value: String?) {
val network = session?.network(network())
state.update {
copy(
channelModes = channelModes.run {
when (network?.channelModeType(mode)) {
ChannelModeType.A_CHANMODE -> {
requireNotNull(value) {
"Mode $mode of ChannelModeType A must have a value"
}
val result = Pair(mode, a[mode].orEmpty() - value)
if (result.second.isNotEmpty()) copy(a = a + result)
else copy(a = a - mode)
}
ChannelModeType.B_CHANMODE -> {
copy(b = b - mode)
}
ChannelModeType.C_CHANMODE -> {
copy(c = c - mode)
}
ChannelModeType.D_CHANMODE ->
copy(d = d - mode)
else -> channelModes
}
}
)
}
super.removeChannelMode(mode, value)
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.common
import de.justjanne.libquassel.protocol.session.Session
import de.justjanne.libquassel.protocol.syncables.SyncableObject
import de.justjanne.libquassel.protocol.syncables.stubs.IrcListHelperStub
open class IrcListHelper(
session: Session? = null
) : SyncableObject(session, "IrcListHelper"), IrcListHelperStub {
init {
initialized = true
}
}