diff --git a/.gitignore b/.gitignore
index fa550e5..6c5fc87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,8 +54,9 @@ atlassian-ide-plugin.xml
# Editor-based Rest Client
.idea/httpRequests
-local.properties
-
+bin
deploy
+local.properties
logs
mobibot.properties
+out
diff --git a/bin/main/log4j2.xml b/bin/main/log4j2.xml
deleted file mode 100644
index 265c88f..0000000
--- a/bin/main/log4j2.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/bin/main/net/thauvin/erik/mobibot/Addons.kt b/bin/main/net/thauvin/erik/mobibot/Addons.kt
deleted file mode 100644
index 2c5f05d..0000000
--- a/bin/main/net/thauvin/erik/mobibot/Addons.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Addons.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot
-
-import net.thauvin.erik.mobibot.Utils.notContains
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.links.LinksManager
-import net.thauvin.erik.mobibot.modules.AbstractModule
-import org.pircbotx.hooks.events.PrivateMessageEvent
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.util.*
-
-/**
- * Modules and Commands addons.
- */
-class Addons(private val props: Properties) {
- private val logger: Logger = LoggerFactory.getLogger(Addons::class.java)
- private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH)
- private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH)
-
- val commands: MutableList = mutableListOf()
- val modules: MutableList = mutableListOf()
- val names = Names
-
- /**
- * Add a module with properties.
- */
- fun add(module: AbstractModule): Boolean {
- var enabled = false
- with(module) {
- if (disabledModules.notContains(name, true)) {
- if (hasProperties()) {
- propertyKeys.forEach {
- setProperty(it, props.getProperty(it, ""))
- }
- }
-
- if (isEnabled) {
- modules.add(this)
- names.modules.add(name)
- names.commands.addAll(commands)
- enabled = true
- } else {
- if (logger.isDebugEnabled) {
- logger.debug("Module $name is disabled.")
- }
- names.disabledModules.add(name)
- }
- } else {
- names.disabledModules.add(name)
- }
- }
- return enabled
- }
-
- /**
- * Add a command with properties.
- */
- fun add(command: AbstractCommand): Boolean {
- var enabled = false
- with(command) {
- if (disableCommands.notContains(name, true)) {
- if (properties.isNotEmpty()) {
- properties.keys.forEach {
- setProperty(it, props.getProperty(it, ""))
- }
- }
- if (isEnabled()) {
- commands.add(this)
- if (isVisible) {
- if (isOpOnly) {
- names.ops.add(name)
- } else {
- names.commands.add(name)
- }
- }
- enabled = true
- } else {
- if (logger.isDebugEnabled) {
- logger.debug("Command $name is disabled.")
- }
- names.disabledCommands.add(name)
- }
- } else {
- names.disabledCommands.add(name)
- }
- }
- return enabled
- }
-
- /**
- * Execute a command or module.
- */
- fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean {
- val cmds = if (event is PrivateMessageEvent) commands else commands.filter { it.isPublic }
- for (command in cmds) {
- if (command.name.startsWith(cmd)) {
- command.commandResponse(channel, args, event)
- return true
- }
- }
- val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules
- for (module in mods) {
- if (module.commands.contains(cmd)) {
- module.commandResponse(channel, cmd, args, event)
- return true
- }
- }
- return false
- }
-
- /**
- * Match a command.
- */
- fun match(channel: String, event: GenericMessageEvent): Boolean {
- for (command in commands) {
- if (command.matches(event.message)) {
- command.commandResponse(channel, event.message, event)
- return true
- }
- }
- return false
- }
-
- /**
- * Commands and Modules help.
- */
- fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean {
- for (command in commands) {
- if (command.isVisible && command.name.startsWith(topic)) {
- return command.helpResponse(channel, topic, event)
- }
- }
- for (module in modules) {
- if (module.commands.contains(topic)) {
- return module.helpResponse(event)
- }
- }
- return false
- }
-
- /**
- * Holds commands and modules names.
- */
- object Names {
- val modules: MutableList = mutableListOf()
- val disabledModules: MutableList = mutableListOf()
- val commands: MutableList = mutableListOf()
- val disabledCommands: MutableList = mutableListOf()
- val ops: MutableList = mutableListOf()
-
- fun sort() {
- modules.sort()
- disabledModules.sort()
- commands.sort()
- disabledCommands.sort()
- ops.sort()
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/Constants.kt b/bin/main/net/thauvin/erik/mobibot/Constants.kt
deleted file mode 100644
index 98ef74a..0000000
--- a/bin/main/net/thauvin/erik/mobibot/Constants.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Constants.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot
-
-/**
- * The `Constants`.
- */
-object Constants {
- /**
- * The connect/read timeout in ms.
- */
- const val CONNECT_TIMEOUT = 5000
-
- /**
- * Debug command line argument.
- */
- const val DEBUG_ARG = "debug"
-
- /**
- * Default IRC Port.
- */
- const val DEFAULT_PORT = 6667
-
- /**
- * Default IRC Server.
- */
- const val DEFAULT_SERVER = "irc.libera.chat"
-
- /**
- * CLI command for usage.
- */
- const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar"
-
- /**
- * User-Agent
- */
- const val USER_AGENT =
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
-
- /**
- * The help command.
- */
- const val HELP_CMD = "help"
-
- /**
- * The link command.
- */
- const val LINK_CMD = "L"
-
- /**
- * The empty title string.
- */
- const val NO_TITLE = "No Title"
-
- /**
- * Properties command line argument.
- */
- const val PROPS_ARG = "properties"
-
- /**
- * The tag command
- */
- const val TAG_CMD = "T"
-
- /**
- * The timer delay in minutes.
- */
- const val TIMER_DELAY = 10L
-
- /**
- * Properties version line argument.
- */
- const val VERSION_ARG = "version"
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt b/bin/main/net/thauvin/erik/mobibot/FeedReader.kt
deleted file mode 100644
index d82f011..0000000
--- a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * FeedReader.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot
-
-import com.rometools.rome.io.FeedException
-import com.rometools.rome.io.SyndFeedInput
-import com.rometools.rome.io.XmlReader
-import net.thauvin.erik.mobibot.Utils.green
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.entries.FeedsManager
-import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.mobibot.msg.NoticeMessage
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.io.IOException
-import java.net.URL
-
-/**
- * Reads an RSS feed.
- */
-class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable {
- private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java)
-
- /**
- * Fetches the Feed's items.
- */
- override fun run() {
- try {
- readFeed(url).forEach {
- event.sendMessage("", it)
- }
- } catch (e: FeedException) {
- if (logger.isWarnEnabled) logger.warn("Unable to parse the feed at $url", e)
- event.sendMessage("An error has occurred while parsing the feed: ${e.message}")
- } catch (e: IOException) {
- if (logger.isWarnEnabled) logger.warn("Unable to fetch the feed at $url", e)
- event.sendMessage("An IO error has occurred while fetching the feed: ${e.message}")
- }
- }
-
- companion object {
- @JvmStatic
- @Throws(FeedException::class, IOException::class)
- fun readFeed(url: String, maxItems: Int = 5): List {
- val messages = mutableListOf()
- val input = SyndFeedInput()
- XmlReader(URL(url).openStream()).use { reader ->
- val feed = input.build(reader)
- val items = feed.entries
- if (items.isEmpty()) {
- messages.add(NoticeMessage("There is currently nothing to view."))
- } else {
- items.take(maxItems).forEach {
- messages.add(NoticeMessage(it.title))
- messages.add(NoticeMessage(helpFormat(it.link.green(), false)))
- }
- }
- }
- return messages
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt b/bin/main/net/thauvin/erik/mobibot/Mobibot.kt
deleted file mode 100644
index f91c457..0000000
--- a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Mobibot.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot
-
-import kotlinx.cli.ArgParser
-import kotlinx.cli.ArgType
-import kotlinx.cli.default
-import net.thauvin.erik.mobibot.Utils.appendIfMissing
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.capitalise
-import net.thauvin.erik.mobibot.Utils.getIntProperty
-import net.thauvin.erik.mobibot.Utils.helpCmdSyntax
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.lastOrEmpty
-import net.thauvin.erik.mobibot.Utils.sendList
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
-import net.thauvin.erik.mobibot.commands.*
-import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap
-import net.thauvin.erik.mobibot.commands.links.*
-import net.thauvin.erik.mobibot.commands.seen.Seen
-import net.thauvin.erik.mobibot.commands.tell.Tell
-import net.thauvin.erik.mobibot.modules.*
-import net.thauvin.erik.semver.Version
-import org.pircbotx.Configuration
-import org.pircbotx.PircBotX
-import org.pircbotx.hooks.ListenerAdapter
-import org.pircbotx.hooks.events.*
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.io.*
-import java.nio.file.Files
-import java.nio.file.Paths
-import java.util.*
-import java.util.regex.Pattern
-import kotlin.system.exitProcess
-
-@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt")
-class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() {
- // The bot configuration.
- private val config: Configuration
-
- // Commands and Modules
- private val addons: Addons
-
- // Seen command
- private val seen: Seen
-
- // Tell command
- private val tell: Tell
-
- /** Logger. */
- val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java)
-
- /**
- * Connects to the server and joins the channel.
- */
- fun connect() {
- PircBotX(config).startBot()
- }
-
- /**
- * Responds with the default help.
- */
- private fun helpDefault(event: GenericMessageEvent) {
- event.sendMessage("Type a URL on $channel to post it.")
- event.sendMessage("For more information on a specific command, type:")
- event.sendMessage(
- helpFormat(
- helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent)
- )
- )
- event.sendMessage("The commands are:")
- event.sendList(addons.names.commands, 8, isBold = true, isIndent = true)
- if (event.isChannelOp(channel)) {
- if (addons.names.disabledCommands.isNotEmpty()) {
- event.sendMessage("The disabled commands are:")
- event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true)
- }
- event.sendMessage("The op commands are:")
- event.sendList(addons.names.ops, 8, isBold = true, isIndent = true)
- }
- }
-
- /**
- * Responds with the default, commands or modules help.
- */
- private fun helpResponse(event: GenericMessageEvent, topic: String) {
- if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) {
- helpDefault(event)
- }
- }
-
- override fun onAction(event: ActionEvent?) {
- event?.channel?.let {
- if (channel == it.name) {
- event.user?.let { user ->
- storeRecap(user.nick, event.action, true)
- }
- }
- }
- }
-
- override fun onDisconnect(event: DisconnectEvent?) {
- event?.let {
- with(event.getBot()) {
- LinksManager.socialManager.notification("$nick disconnected from $serverHostname")
- seen.add(userChannelDao.getChannel(channel).users)
- }
- }
- LinksManager.socialManager.shutdown()
- }
-
- override fun onPrivateMessage(event: PrivateMessageEvent?) {
- event?.user?.let { user ->
- if (logger.isTraceEnabled) logger.trace("<<< ${user.nick}: ${event.message}")
- val cmds = event.message.trim().split(" ".toRegex(), 2)
- val cmd = cmds[0].lowercase()
- val args = cmds.lastOrEmpty().trim()
- if (cmd.startsWith(Constants.HELP_CMD)) { // help
- helpResponse(event, args)
- } else if (!addons.exec(channel, cmd, args, event)) { // Execute command or module
- helpDefault(event)
- }
- }
- }
-
- override fun onJoin(event: JoinEvent?) {
- event?.user?.let { user ->
- with(event.getBot()) {
- if (user.nick == nick) {
- LinksManager.socialManager.notification(
- "$nick has joined ${event.channel.name} on $serverHostname"
- )
- seen.add(userChannelDao.getChannel(channel).users)
- } else {
- tell.send(event)
- seen.add(user.nick)
- }
- }
- }
- }
-
- override fun onMessage(event: MessageEvent?) {
- event?.user?.let { user ->
- tell.send(event)
- if (event.message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot:
- if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}")
- val cmds = event.message.substring(event.bot().nick.length + 1).trim().split(" ".toRegex(), 2)
- val cmd = cmds[0].lowercase()
- val args = cmds.lastOrEmpty().trim()
- if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help
- helpResponse(event, args)
- } else {
- // Execute module or command
- addons.exec(channel, cmd, args, event)
- }
- } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc.
- if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}")
- }
- storeRecap(user.nick, event.message, false)
- seen.add(user.nick)
- }
- }
-
- override fun onNickChange(event: NickChangeEvent?) {
- event?.let {
- tell.send(event)
- if (!it.oldNick.equals(it.newNick, true)) {
- seen.add(it.oldNick)
- }
- seen.add(it.newNick)
- }
- }
-
- override fun onPart(event: PartEvent?) {
- event?.user?.let { user ->
- with(event.getBot()) {
- if (user.nick == nick) {
- LinksManager.socialManager.notification(
- "$nick has left ${event.channel.name} on $serverHostname"
- )
- seen.add(userChannelDao.getChannel(channel).users)
- } else {
- seen.add(user.nick)
- }
- }
- }
- }
-
- override fun onQuit(event: QuitEvent?) {
- event?.user?.let { user ->
- seen.add(user.nick)
- }
- }
-
- companion object {
- @JvmStatic
- @Throws(Exception::class)
- fun main(args: Array) {
- // Set up the command line options
- val parser = ArgParser(Constants.CLI_CMD)
- val debug by parser.option(
- ArgType.Boolean,
- Constants.DEBUG_ARG,
- Constants.DEBUG_ARG.substring(0, 1),
- "Print debug & logging data directly to the console"
- ).default(false)
- val property by parser.option(
- ArgType.String,
- Constants.PROPS_ARG,
- Constants.PROPS_ARG.substring(0, 1),
- "Use alternate properties file"
- ).default("./${ReleaseInfo.PROJECT}.properties")
- val version by parser.option(
- ArgType.Boolean,
- Constants.VERSION_ARG,
- Constants.VERSION_ARG.substring(0, 1),
- "Print version info"
- ).default(false)
-
- // Parse the command line
- parser.parse(args)
-
- if (version) {
- // Output the version
- println(
- "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" +
- " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})"
- )
- println(ReleaseInfo.WEBSITE)
- } else {
- // Load the properties
- val p = Properties()
- try {
- Files.newInputStream(
- Paths.get(property)
- ).use { fis ->
- p.load(fis)
- }
- } catch (ignore: FileNotFoundException) {
- System.err.println("Unable to find properties file.")
- exitProcess(1)
- } catch (ignore: IOException) {
- System.err.println("Unable to open properties file.")
- exitProcess(1)
- }
- val nickname = p.getProperty("nick", Mobibot::class.java.name.lowercase())
- val channel = p.getProperty("channel")
- val logsDir = p.getProperty("logs", ".").appendIfMissing(File.separatorChar)
-
- // Redirect stdout and stderr
- if (!debug) {
- try {
- val stdout = PrintStream(
- BufferedOutputStream(
- FileOutputStream(
- logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true
- )
- ), true
- )
- System.setOut(stdout)
- } catch (ignore: IOException) {
- System.err.println("Unable to open output (stdout) log file.")
- exitProcess(1)
- }
- try {
- val stderr = PrintStream(
- BufferedOutputStream(
- FileOutputStream("$logsDir$nickname.err", true)
- ), true
- )
- System.setErr(stderr)
- } catch (ignore: IOException) {
- System.err.println("Unable to open error (stderr) log file.")
- exitProcess(1)
- }
- }
-
- // Start the bot
- Mobibot(nickname, channel, logsDir, p).connect()
- }
- }
- }
-
- /**
- * Initialize the bot.
- */
- init {
- val ircServer = p.getProperty("server", Constants.DEFAULT_SERVER)
- config = Configuration.Builder().apply {
- name = nickname
- login = p.getProperty("login", nickname)
- realName = p.getProperty("realname", nickname)
- addServer(
- ircServer,
- p.getIntProperty("port", Constants.DEFAULT_PORT)
- )
- addAutoJoinChannel(channel)
- addListener(this@Mobibot)
- version = "${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}"
- isAutoNickChange = true
- val identPwd = p.getProperty("ident")
- if (!identPwd.isNullOrBlank()) {
- nickservPassword = identPwd
- }
- val identNick = p.getProperty("ident-nick")
- if (!identNick.isNullOrBlank()) {
- nickservNick = identNick
- }
- val identMsg = p.getProperty("ident-msg")
- if (!identMsg.isNullOrBlank()) {
- nickservCustomMessage = identMsg
- }
- isAutoReconnect = true
-
- //socketConnectTimeout = Constants.CONNECT_TIMEOUT
- //socketTimeout = Constants.CONNECT_TIMEOUT
- //messageDelay = StaticDelay(500)
- }.buildConfiguration()
-
- // Load the current entries
- with(LinksManager) {
- entries.channel = channel
- entries.ircServer = ircServer
- entries.logsDir = logsDirPath
- entries.backlogs = p.getProperty("backlogs", "")
- entries.load()
-
- // Set up pinboard
- pinboard.setApiToken(p.getProperty("pinboard-api-token", ""))
- }
-
- addons = Addons(p)
-
- // Load the commands
- addons.add(ChannelFeed(channel.removePrefix("#")))
- addons.add(Comment())
- addons.add(Cycle())
- addons.add(Die())
- addons.add(Ignore())
- addons.add(LinksManager())
- addons.add(Me())
- addons.add(Modules(addons.names.modules, addons.names.disabledModules))
- addons.add(Msg())
- addons.add(Nick())
- addons.add(Posting())
- addons.add(Recap())
- addons.add(Say())
-
- // Seen command
- seen = Seen("${logsDirPath}${nickname}-seen.ser")
- addons.add(seen)
-
- addons.add(Tags())
-
- // Tell command
- tell = Tell("${logsDirPath}${nickname}.ser")
- addons.add(tell)
-
- addons.add(Users())
- addons.add(Versions())
- addons.add(View())
-
- // Load social modules
- LinksManager.socialManager.add(addons, Mastodon())
-
- // Load the modules
- addons.add(Calc())
- addons.add(ChatGpt())
- addons.add(CryptoPrices())
- addons.add(CurrencyConverter())
- addons.add(Dice())
- addons.add(GoogleSearch())
- addons.add(Info(tell, seen))
- addons.add(Joke())
- addons.add(Lookup())
- addons.add(Ping())
- addons.add(RockPaperScissors())
- addons.add(StockQuote())
- addons.add(War())
- addons.add(Weather2())
- addons.add(WolframAlpha())
- addons.add(WorldTime())
-
- // Sort the addons
- addons.names.sort()
- }
-}
-
diff --git a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt b/bin/main/net/thauvin/erik/mobibot/Pinboard.kt
deleted file mode 100644
index 7cb5aed..0000000
--- a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Pinboard.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot
-
-import net.thauvin.erik.mobibot.entries.EntryLink
-import net.thauvin.erik.pinboard.PinboardPoster
-import java.time.ZoneId
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
-import java.time.temporal.ChronoUnit
-import java.util.*
-
-/**
- * Handles posts to pinboard.in.
- */
-class Pinboard {
- private val poster = PinboardPoster()
-
- /**
- * Adds a pin.
- */
- fun addPin(ircServer: String, entry: EntryLink) {
- if (poster.apiToken.isNotBlank()) {
- with(entry) {
- poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp())
- }
- }
- }
-
- /**
- * Sets the pinboard API token.
- */
- fun setApiToken(apiToken: String) {
- poster.apiToken = apiToken
- }
-
- /**
- * Deletes a pin.
- */
- fun deletePin(entry: EntryLink) {
- if (poster.apiToken.isNotBlank()) {
- poster.deletePin(entry.link)
- }
-
- }
-
- /**
- * Updates a pin.
- */
- fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) {
- if (poster.apiToken.isNotBlank()) {
- with(entry) {
- if (oldUrl != link) {
- poster.deletePin(oldUrl)
- }
- poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp())
- }
- }
- }
-
- /**
- * Formats a date to a UTC timestamp.
- */
- private fun Date.toTimestamp(): String {
- return ZonedDateTime.ofInstant(
- toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault()
- ).format(DateTimeFormatter.ISO_INSTANT)
- }
-
- /**
- * Formats the tags for pinboard.
- */
- private fun EntryLink.formatTags(): String {
- return nick + formatTags(",", ",")
- }
-
- /**
- * Returns the pinboard.in extended attribution line.
- */
- private fun EntryLink.postedBy(ircServer: String): String {
- return "Posted by $nick on $channel ( $ircServer )"
- }
-}
-
diff --git a/bin/main/net/thauvin/erik/mobibot/Utils.kt b/bin/main/net/thauvin/erik/mobibot/Utils.kt
deleted file mode 100644
index e4760d2..0000000
--- a/bin/main/net/thauvin/erik/mobibot/Utils.kt
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Utils.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot
-
-import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR
-import net.thauvin.erik.urlencoder.UrlEncoderUtil
-import org.jsoup.Jsoup
-import org.pircbotx.Colors
-import org.pircbotx.PircBotX
-import org.pircbotx.hooks.events.PrivateMessageEvent
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.slf4j.Logger
-import java.io.*
-import java.net.HttpURLConnection
-import java.net.URL
-import java.nio.file.Files
-import java.nio.file.Paths
-import java.time.LocalDateTime
-import java.time.ZoneId
-import java.time.format.DateTimeFormatter
-import java.util.*
-import kotlin.io.path.exists
-import kotlin.io.path.fileSize
-
-/**
- * Miscellaneous utilities.
- */
-@Suppress("TooManyFunctions")
-object Utils {
- private val searchFlags = arrayOf("%c", "%n")
-
- /**
- * Prepends a prefix if not present.
- */
- @JvmStatic
- fun String.prefixIfMissing(prefix: Char): String {
- return if (first() != prefix) {
- "$prefix${this}"
- } else {
- this
- }
- }
-
- /**
- * Appends a suffix to the end of the String if not present.
- */
- @JvmStatic
- fun String.appendIfMissing(suffix: Char): String {
- return if (last() != suffix) {
- "$this${suffix}"
- } else {
- this
- }
- }
-
- /**
- * Makes the given int bold.
- */
- @JvmStatic
- fun Int.bold(): String = toString().bold()
-
- /**
- * Makes the given long bold.
- */
- @JvmStatic
- fun Long.bold(): String = toString().bold()
-
- /**
- * Makes the given string bold.
- */
- @JvmStatic
- fun String?.bold(): String = colorize(Colors.BOLD)
-
- /**
- * Returns the [PircBotX] instance.
- */
- fun GenericMessageEvent.bot(): PircBotX {
- return getBot() as PircBotX
- }
-
- /**
- * Capitalize a string.
- */
- @JvmStatic
- fun String.capitalise(): String = lowercase().replaceFirstChar { it.uppercase() }
-
- /**
- * Capitalize words
- */
- @JvmStatic
- fun String.capitalizeWords(): String = split(" ").joinToString(" ") { it.capitalise() }
-
- /**
- * Colorize a string.
- */
- @JvmStatic
- fun String?.colorize(color: String): String {
- return when {
- isNullOrEmpty() -> {
- ""
- }
-
- color == DEFAULT_COLOR -> {
- this
- }
-
- Colors.BOLD == color || Colors.REVERSE == color -> {
- color + this + color
- }
-
- else -> {
- color + this + Colors.NORMAL
- }
- }
- }
-
- /**
- * Makes the given string cyan.
- */
- @JvmStatic
- fun String?.cyan(): String = colorize(Colors.CYAN)
-
- /**
- * URL encodes the given string.
- */
- @JvmStatic
- fun String.encodeUrl(): String = UrlEncoderUtil.encode(this)
-
- /**
- * Returns a property as an int.
- */
- @JvmStatic
- fun Properties.getIntProperty(key: String, defaultValue: Int): Int {
- return getProperty(key)?.toIntOrDefault(defaultValue) ?: defaultValue
- }
-
- /**
- * Makes the given string green.
- */
- @JvmStatic
- fun String?.green(): String = colorize(Colors.DARK_GREEN)
-
- /**
- * Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's
- * nick.
- */
- @JvmStatic
- fun helpCmdSyntax(text: String, botNick: String, isPrivate: Boolean): String {
- val replace = arrayOf(if (isPrivate) "/msg $botNick" else "$botNick:", botNick)
- return text.replaceEach(searchFlags, replace)
- }
-
- /**
- * Returns a formatted help string.
- */
- @JvmStatic
- @JvmOverloads
- fun helpFormat(help: String, isBold: Boolean = true, isIndent: Boolean = true): String {
- val s = if (isBold) help.bold() else help
- return if (isIndent) s.prependIndent() else s
- }
-
- /**
- * Returns `true` if the specified user is an operator on the [channel].
- */
- @JvmStatic
- fun GenericMessageEvent.isChannelOp(channel: String): Boolean {
- return this.bot().userChannelDao.getChannel(channel).isOp(this.user)
- }
-
- /**
- * Returns `true` if a HTTP status code indicates a successful response.
- */
- @JvmStatic
- fun Int.isHttpSuccess() = this in 200..399
-
- /**
- * Returns the last item of a list of strings or empty if none.
- */
- @JvmStatic
- fun List.lastOrEmpty(): String {
- return if (this.size >= 2) {
- this.last()
- } else
- ""
- }
-
- /**
- * Load serial data from file.
- */
- @JvmStatic
- fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any {
- val serialFile = Paths.get(file)
- if (serialFile.exists() && serialFile.fileSize() > 0) {
- try {
- ObjectInputStream(
- BufferedInputStream(Files.newInputStream(serialFile))
- ).use { input ->
- if (logger.isDebugEnabled) logger.debug("Loading the ${description}.")
- return input.readObject()
- }
- } catch (e: IOException) {
- logger.error("An IO error occurred loading the ${description}.", e)
- } catch (e: ClassNotFoundException) {
- logger.error("An error occurred loading the ${description}.", e)
- }
- }
- return default
- }
-
- /**
- * Returns `true` if the list does not contain the given string.
- */
- @JvmStatic
- fun List.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) }
-
- /**
- * Obfuscates the given string.
- */
- @JvmStatic
- fun String.obfuscate(): String {
- return if (isNotBlank()) {
- "x".repeat(length)
- } else this
- }
-
- /**
- * Returns the plural form of a word, if count > 1.
- */
- @JvmStatic
- fun String.plural(count: Long): String {
- return if (count > 1) "${this}s" else this
- }
-
- /**
- * Makes the given string red.
- */
- @JvmStatic
- fun String?.red(): String = colorize(Colors.RED)
-
- /**
- * Replaces all occurrences of Strings within another String.
- */
- @JvmStatic
- fun String.replaceEach(search: Array, replace: Array): String {
- var result = this
- if (search.size == replace.size) {
- search.forEachIndexed { i, s ->
- result = result.replace(s, replace[i])
- }
- }
- return result
- }
-
- /**
- * Makes the given string reverse color.
- */
- @JvmStatic
- fun String?.reverseColor(): String = colorize(Colors.REVERSE)
-
- /**
- * Save data
- */
- @JvmStatic
- fun saveSerialData(file: String, data: Any, logger: Logger, description: String) {
- try {
- BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos ->
- ObjectOutputStream(bos).use { output ->
- if (logger.isDebugEnabled) logger.debug("Saving the ${description}.")
- output.writeObject(data)
- }
- }
- } catch (e: IOException) {
- logger.error("Unable to save the ${description}.", e)
- }
- }
-
- /**
- * Send a formatted commands/modules, etc. list.
- */
- @JvmStatic
- @JvmOverloads
- fun GenericMessageEvent.sendList(
- list: List,
- maxPerLine: Int,
- separator: String = " ",
- isBold: Boolean = false,
- isIndent: Boolean = false
- ) {
- var i = 0
- while (i < list.size) {
- sendMessage(
- helpFormat(
- list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""),
- isBold,
- isIndent
- ),
- )
- i += maxPerLine
- }
- }
-
- /**
- * Sends a [message].
- */
- @JvmStatic
- fun GenericMessageEvent.sendMessage(channel: String, message: Message) {
- if (message.isNotice) {
- bot().sendIRC().notice(user.nick, message.msg.colorize(message.color))
- } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) {
- respondPrivateMessage(message.msg.colorize(message.color))
- } else {
- bot().sendIRC().message(channel, message.msg.colorize(message.color))
- }
- }
-
- /**
- * Sends a response as a private message or notice.
- */
- @JvmStatic
- fun GenericMessageEvent.sendMessage(message: String) {
- if (this is PrivateMessageEvent) {
- respondPrivateMessage(message)
- } else {
- bot().sendIRC().notice(user.nick, message)
- }
- }
-
- /**
- * Returns today's date.
- */
- @JvmStatic
- fun today(): String = LocalDateTime.now().toIsoLocalDate()
-
- /**
- * Converts a string to an int.
- */
- @JvmStatic
- fun String.toIntOrDefault(defaultValue: Int): Int {
- return try {
- toInt()
- } catch (e: NumberFormatException) {
- defaultValue
- }
- }
-
- /**
- * Returns the specified date as an ISO local date string.
- */
- @JvmStatic
- fun Date.toIsoLocalDate(): String {
- return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toIsoLocalDate()
- }
-
- /**
- * Returns the specified date as an ISO local date string.
- */
- @JvmStatic
- fun LocalDateTime.toIsoLocalDate(): String = format(DateTimeFormatter.ISO_LOCAL_DATE)
-
- /**
- * Returns the specified date formatted as `yyyy-MM-dd HH:mm`.
- */
- @JvmStatic
- fun Date.toUtcDateTime(): String {
- return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toUtcDateTime()
- }
-
- /**
- * Returns the specified date formatted as `yyyy-MM-dd HH:mm`.
- */
- @JvmStatic
- fun LocalDateTime.toUtcDateTime(): String = format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
-
- /**
- * Makes the given string bold.
- */
- @JvmStatic
- fun String?.underline(): String = colorize(Colors.UNDERLINE)
-
-
- /**
- * Converts XML/XHTML entities to plain text.
- */
- @JvmStatic
- fun String.unescapeXml(): String = Jsoup.parse(this).text()
-
- /**
- * Reads contents of a URL.
- */
- @JvmStatic
- @Throws(IOException::class)
- fun URL.reader(): UrlReaderResponse {
- val connection = this.openConnection() as HttpURLConnection
- connection.setRequestProperty(
- "User-Agent",
- "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"
- )
- return if (connection.responseCode.isHttpSuccess()) {
- UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() })
- } else {
- UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() })
- }
- }
-
- /**
- * Holds the [URL.reader] response code and body text.
- */
- data class UrlReaderResponse(val responseCode: Int, val body: String)
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt
deleted file mode 100644
index 5f79472..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * AbstractCommand.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpCmdSyntax
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import org.pircbotx.hooks.events.PrivateMessageEvent
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-abstract class AbstractCommand {
- abstract val name: String
- abstract val help: List
- abstract val isOpOnly: Boolean
- abstract val isPublic: Boolean
- abstract val isVisible: Boolean
-
- val properties: MutableMap = mutableMapOf()
-
- abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent)
-
- open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
- if (!isOpOnly || isOpOnly == event.isChannelOp(channel)) {
- for (h in help) {
- event.sendMessage(helpCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic))
- }
- return true
- }
- return false
- }
-
- open fun initProperties(vararg keys: String) {
- keys.forEach {
- properties[it] = ""
- }
- }
-
- open fun isEnabled(): Boolean {
- return true
- }
-
- open fun matches(message: String): Boolean {
- return false
- }
-
- open fun setProperty(key: String, value: String) {
- properties[key] = value
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt
deleted file mode 100644
index 038e378..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * ChannelFeed.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.FeedReader
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class ChannelFeed(channel: String) : AbstractCommand() {
- override val name = channel
- override val help = listOf("To list the last 5 posts from the channel's weblog feed:", helpFormat("%c $channel"))
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val FEED_PROP = "feed"
- }
-
- init {
- initProperties(FEED_PROP)
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (isEnabled()) {
- properties[FEED_PROP]?.let { FeedReader(it, event).run() }
- }
- }
-
- override fun isEnabled(): Boolean {
- return !properties[FEED_PROP].isNullOrBlank()
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt b/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt
deleted file mode 100644
index 9608ca8..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Cycle.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Cycle : AbstractCommand() {
- private val wait = 10
- override val name = "cycle"
- override val help = listOf("To have the bot leave the channel and come back:", helpFormat("%c $name"))
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- with(event.bot()) {
- if (event.isChannelOp(channel)) {
- runBlocking {
- launch {
- sendIRC().message(channel, "${event.user.nick} asked me to leave. I'll be back!")
- userChannelDao.getChannel(channel).send().part()
- delay(wait * 1000L)
- sendIRC().joinChannel(channel)
- }
- }
- } else {
- helpResponse(channel, args, event)
- }
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt b/bin/main/net/thauvin/erik/mobibot/commands/Die.kt
deleted file mode 100644
index f271bfa..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Die.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Die : AbstractCommand() {
- override val name = "die"
- override val help = emptyList()
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = false
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- with(event.bot()) {
- if (event.isChannelOp(channel) && (properties[DIE_PROP].isNullOrBlank() || args == properties[DIE_PROP])) {
- sendIRC().message(channel, "${event.user?.nick} has just signed my death sentence.")
- stopBotReconnect()
- sendIRC().quitServer("The Bot is Out There!")
- }
- }
- }
-
- companion object {
- const val DIE_PROP = "die"
- }
-
- init {
- initProperties(DIE_PROP)
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt b/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt
deleted file mode 100644
index d083c10..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Ignore.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpCmdSyntax
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendList
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.links.LinksManager
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Ignore : AbstractCommand() {
- private val me = "me"
-
- init {
- initProperties(IGNORE_PROP)
- }
-
- override val name = IGNORE_CMD
- override val help = listOf(
- "To ignore a link posted to the channel:",
- helpFormat("https://www.foo.bar %n"),
- "To check your ignore status:",
- helpFormat("%c $name"),
- "To toggle your ignore status:",
- helpFormat("%c $name $me")
- )
- private val helpOp = help.plus(
- arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]"))
- )
-
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val IGNORE_CMD = "ignore"
- const val IGNORE_PROP = IGNORE_CMD
- private val ignored = mutableSetOf()
-
- @JvmStatic
- fun isNotIgnored(nick: String): Boolean {
- return !ignored.contains(nick.lowercase())
- }
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val isMe = args.trim().equals(me, true)
- if (isMe || !event.isChannelOp(channel)) {
- val nick = event.user.nick.lowercase()
- ignoreNick(nick, isMe, event)
- } else {
- ignoreOp(args, event)
- }
- }
-
- override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
- return if (event.isChannelOp(channel)) {
- for (h in helpOp) {
- event.sendMessage(helpCmdSyntax(h, event.bot().nick, true))
- }
- true
- } else {
- super.helpResponse(channel, topic, event)
- }
- }
-
- private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) {
- if (isMe) {
- if (ignored.remove(sender)) {
- event.sendMessage("You are no longer ignored.")
- } else {
- ignored.add(sender)
- event.sendMessage("You are now ignored.")
- }
- } else {
- if (ignored.contains(sender)) {
- event.sendMessage("You are currently ignored.")
- } else {
- event.sendMessage("You are not currently ignored.")
- }
- }
- }
-
- private fun ignoreOp(args: String, event: GenericMessageEvent) {
- if (args.isNotEmpty()) {
- val nicks = args.lowercase().split(" ")
- for (nick in nicks) {
- val ignore = if (me == nick) {
- nick.lowercase()
- } else {
- nick
- }
- if (!ignored.remove(ignore)) {
- ignored.add(ignore)
- }
- }
- }
-
- if (ignored.isNotEmpty()) {
- event.sendMessage("The following nicks are ignored:")
- event.sendList(ignored.sorted(), 8, isIndent = true)
- } else {
- event.sendMessage("No one is currently ${"ignored".bold()}.")
- }
- }
-
- override fun setProperty(key: String, value: String) {
- super.setProperty(key, value)
- if (IGNORE_PROP == key) {
- ignored.addAll(value.split(LinksManager.TAG_MATCH))
- }
- }
-
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt b/bin/main/net/thauvin/erik/mobibot/commands/Info.kt
deleted file mode 100644
index ed0b6ef..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Info.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.ReleaseInfo
-import net.thauvin.erik.mobibot.Utils.capitalise
-import net.thauvin.erik.mobibot.Utils.green
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.plural
-import net.thauvin.erik.mobibot.Utils.sendList
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.links.LinksManager
-import net.thauvin.erik.mobibot.commands.seen.Seen
-import net.thauvin.erik.mobibot.commands.tell.Tell
-import org.pircbotx.hooks.types.GenericMessageEvent
-import java.lang.management.ManagementFactory
-import kotlin.time.DurationUnit
-import kotlin.time.toDuration
-
-class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() {
- private val allVersions = listOf(
- "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})",
- "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})"
- )
- override val name = "info"
- override val help = listOf("To view information about the bot:", helpFormat("%c $name"))
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- /**
- * Converts milliseconds to year month week day hour and minutes.
- */
- @JvmStatic
- fun Long.toUptime(): String {
- this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ ->
- val years = wholeDays / 365
- var days = wholeDays % 365
- val months = days / 30
- days %= 30
- val weeks = days / 7
- days %= 7
-
- with(StringBuffer()) {
- if (years > 0) {
- append(years).append(" year".plural(years)).append(' ')
- }
- if (months > 0) {
- append(months).append(" month".plural(months)).append(' ')
- }
- if (weeks > 0) {
- append(weeks).append(" week".plural(weeks)).append(' ')
- }
- if (days > 0) {
- append(days).append(" day".plural(days)).append(' ')
- }
- if (hours > 0) {
- append(hours).append(" hour".plural(hours.toLong())).append(' ')
- }
-
- if (minutes > 0) {
- append(minutes).append(" minute".plural(minutes.toLong()))
- } else {
- append(seconds).append(" second".plural(seconds.toLong()))
- }
-
- return toString()
- }
- }
- }
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- event.sendList(allVersions, 1)
- val info = StringBuilder()
- info.append("Uptime: ")
- .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime())
- .append(" [Entries: ")
- .append(LinksManager.entries.links.size)
- if (seen.isEnabled()) {
- info.append(", Seen: ").append(seen.count())
- }
- if (event.isChannelOp(channel)) {
- if (tell.isEnabled()) {
- info.append(", Messages: ").append(tell.size())
- }
- if (LinksManager.socialManager.entriesCount() > 0) {
- info.append(", Social: ").append(LinksManager.socialManager.entriesCount())
- }
- }
- info.append(", Recap: ").append(Recap.recaps.size).append(']')
- event.sendMessage(info.toString())
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt b/bin/main/net/thauvin/erik/mobibot/commands/Me.kt
deleted file mode 100644
index ec7823b..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Me.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Me : AbstractCommand() {
- override val name = "me"
- override val help = listOf("To have the bot perform an action:", helpFormat("%c $name "))
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- event.bot().sendIRC().action(channel, args)
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt b/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt
deleted file mode 100644
index b2293b0..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Modules.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendList
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Modules(private val modules: List, private val disabledModules: List) : AbstractCommand() {
- override val name = "modules"
- override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name"))
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- if (modules.isEmpty()) {
- event.respondPrivateMessage("There are no enabled modules.")
- } else {
- event.respondPrivateMessage("The enabled modules are: ")
- event.sendList(modules, 7, isIndent = true)
- }
- if (disabledModules.isNotEmpty()) {
- event.respondPrivateMessage("The disabled modules are: ")
- event.sendList(disabledModules, 7, isIndent = true)
- }
- } else {
- helpResponse(channel, args, event)
- }
- }
-}
-
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt b/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt
deleted file mode 100644
index 20a6635..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Msg.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Msg : AbstractCommand() {
- override val name = "msg"
- override val help = listOf(
- "To have the bot send a private message to someone:",
- helpFormat("%c $name ")
- )
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- val msg = args.split(" ", limit = 2)
- if (args.length > 2) {
- event.bot().sendIRC().message(msg[0], msg[1])
- event.respondPrivateMessage("A message was sent to ${msg[0]}")
- } else {
- helpResponse(channel, args, event)
- }
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt b/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt
deleted file mode 100644
index 85a03ab..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Nick.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Nick : AbstractCommand() {
- override val name = "nick"
- override val help = listOf("To change the bot's nickname:", helpFormat("%c $name "))
- override val isOpOnly = true
- override val isPublic = true
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- event.bot().sendIRC().changeNick(args)
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt b/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt
deleted file mode 100644
index 77154c7..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Recap.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.Utils.toUtcDateTime
-import org.pircbotx.hooks.types.GenericMessageEvent
-import java.time.Clock
-import java.time.LocalDateTime
-
-class Recap : AbstractCommand() {
- override val name = "recap"
- override val help = listOf(
- "To list the last 10 public channel messages:",
- helpFormat("%c $name")
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val MAX_RECAPS = 10
-
- @JvmField
- val recaps = mutableListOf()
-
- /**
- * Stores the last 10 public messages and actions.
- */
- @JvmStatic
- fun storeRecap(sender: String, message: String, isAction: Boolean) {
- recaps.add(
- LocalDateTime.now(Clock.systemUTC()).toUtcDateTime()
- + " - $sender" + (if (isAction) " " else ": ") + message
- )
- if (recaps.size > MAX_RECAPS) {
- recaps.removeFirst()
- }
- }
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (recaps.isNotEmpty()) {
- for (r in recaps) {
- event.sendMessage(r)
- }
- } else {
- event.sendMessage("Sorry, nothing to recap.")
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt b/bin/main/net/thauvin/erik/mobibot/commands/Say.kt
deleted file mode 100644
index 7f76d35..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Say.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Say : AbstractCommand() {
- override val name = "say"
- override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name "))
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- event.bot().sendIRC().message(channel, args)
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt b/bin/main/net/thauvin/erik/mobibot/commands/Users.kt
deleted file mode 100644
index 33d6fef..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Users.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.sendList
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Users : AbstractCommand() {
- override val name = "users"
- override val help = listOf("To list the users present on the channel:", helpFormat("%c $name"))
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val ch = event.bot().userChannelDao.getChannel(channel)
- event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8)
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt b/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt
deleted file mode 100644
index 896c569..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Versions.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.commands
-
-import net.thauvin.erik.mobibot.ReleaseInfo
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendList
-import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
-import org.pircbotx.PircBotX
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Versions : AbstractCommand() {
- private val allVersions = listOf(
- "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})",
- "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" +
- ", JVM ${System.getProperty("java.runtime.version")}",
- "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}"
- )
- override val name = "versions"
- override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name"))
- override val isOpOnly = true
- override val isPublic = false
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- event.sendList(allVersions, 1)
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt
deleted file mode 100644
index 1443d44..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Comment.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.links
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment
-import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel
-import net.thauvin.erik.mobibot.entries.EntryLink
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Comment : AbstractCommand() {
- override val name = COMMAND
- override val help = listOf(
- "To add a comment:",
- helpFormat("${Constants.LINK_CMD}1:This is a comment"),
- "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1",
- "To edit a comment, use its label: ",
- helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"),
- "To delete a comment, use its label and a minus sign: ",
- helpFormat("${Constants.LINK_CMD}1.1:-")
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val COMMAND = "comment"
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val cmds = args.substring(1).split("[.:]".toRegex(), 3)
- val entryIndex = cmds[0].toInt() - 1
-
- if (entryIndex < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) {
- val entry: EntryLink = LinksManager.entries.links[entryIndex]
- val commentIndex = cmds[1].toInt() - 1
- if (commentIndex < entry.comments.size) {
- when (val cmd = cmds[2].trim()) {
- "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1:
- "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:-
- else -> {
- if (cmd.startsWith('?')) { // L1.1:?
- changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event)
- } else { // L1.1:
- setComment(cmd, entry, entryIndex, commentIndex, event)
- }
- }
- }
- }
- }
- }
-
- override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
- if (super.helpResponse(channel, topic, event)) {
- if (event.isChannelOp(channel)) {
- event.sendMessage("To change a comment's author:")
- event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?"))
- }
- return true
- }
- return false
- }
-
- override fun matches(message: String): Boolean {
- return message.matches("^${Constants.LINK_CMD}\\d+\\.\\d+:.*".toRegex())
- }
-
- private fun changeAuthor(
- channel: String,
- cmd: String,
- entry: EntryLink,
- entryIndex: Int,
- commentIndex: Int,
- event: GenericMessageEvent
- ) {
- if (event.isChannelOp(channel) && cmd.length > 1) {
- val comment = entry.getComment(commentIndex)
- comment.nick = cmd.substring(1)
- event.sendMessage(printComment(entryIndex, commentIndex, comment))
- LinksManager.entries.save()
- } else {
- event.sendMessage("Please ask a channel op to change the author of this comment for you.")
- }
- }
-
- private fun deleteComment(
- channel: String,
- entry: EntryLink,
- entryIndex: Int,
- commentIndex: Int,
- event: GenericMessageEvent
- ) {
- if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) {
- entry.deleteComment(commentIndex)
- event.sendMessage("Comment ${entryIndex.toLinkLabel()}.${commentIndex + 1} removed.")
- LinksManager.entries.save()
- } else {
- event.sendMessage("Please ask a channel op to delete this comment for you.")
- }
- }
-
- private fun setComment(
- cmd: String,
- entry: EntryLink,
- entryIndex: Int,
- commentIndex: Int,
- event: GenericMessageEvent
- ) {
- entry.setComment(commentIndex, cmd, event.user.nick)
- event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex)))
- LinksManager.entries.save()
- }
-
- private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) {
- event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex)))
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt
deleted file mode 100644
index fba6b99..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * LinksManager.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.links
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Pinboard
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.Utils.today
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored
-import net.thauvin.erik.mobibot.entries.Entries
-import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink
-import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel
-import net.thauvin.erik.mobibot.entries.EntryLink
-import net.thauvin.erik.mobibot.social.SocialManager
-import org.jsoup.Jsoup
-import org.pircbotx.hooks.types.GenericMessageEvent
-import java.io.IOException
-
-class LinksManager : AbstractCommand() {
- private val defaultTags: MutableList = mutableListOf()
- private val keywords: MutableList = mutableListOf()
-
- override val name = Constants.LINK_CMD
- override val help = emptyList()
- override val isOpOnly = false
- override val isPublic = false
- override val isVisible = false
-
- init {
- initProperties(TAGS_PROP, KEYWORDS_PROP)
- }
-
- companion object {
- val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex()
- const val KEYWORDS_PROP = "tags-keywords"
- const val TAGS_PROP = "tags"
- val TAG_MATCH = ", *| +".toRegex()
-
- /**
- * Entries array
- */
- @JvmField
- val entries = Entries()
-
- /**
- * Pinboard handler.
- */
- @JvmField
- val pinboard = Pinboard()
-
- /**
- * Social Manager handler.
- */
- @JvmField
- val socialManager = SocialManager()
-
- /**
- * Let the user know if the entries are too old to be modified.
- */
- @JvmStatic
- fun isUpToDate(event: GenericMessageEvent): Boolean {
- if (entries.lastPubDate != today()) {
- event.sendMessage("The links are too old to be updated.")
- return false
- }
- return true
- }
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val cmds = args.split(" ".toRegex(), 2)
- val sender = event.user.nick
- val botNick = event.bot().nick
- val login = event.user.login
-
- if (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) {
- val link = cmds[0].trim()
- if (!isDupEntry(link, event)) {
- var title = ""
- val tags = ArrayList(defaultTags)
- if (cmds.size == 2) {
- val data = cmds[1].trim().split("${Tags.COMMAND}:", limit = 2)
- title = data[0].trim()
- if (data.size > 1) {
- tags.addAll(data[1].split(TAG_MATCH))
- }
- }
-
- if (title.isBlank()) {
- title = fetchTitle(link)
- }
-
- if (title != Constants.NO_TITLE) {
- matchTagKeywords(title, tags)
- }
-
- // Links are old, clear them
- if (entries.lastPubDate != today()) {
- entries.links.clear()
- }
-
- val entry = EntryLink(link, title, sender, login, channel, tags)
- entries.links.add(entry)
- val index = entries.links.lastIndexOf(entry)
- event.sendMessage(printLink(index, entry))
-
- pinboard.addPin(event.bot().serverHostname, entry)
-
- // Queue link for posting to social media.
- socialManager.queueEntry(index)
-
- entries.save()
-
- if (Constants.NO_TITLE == entry.title) {
- event.sendMessage("Please specify a title, by typing:")
- event.sendMessage(helpFormat("${index.toLinkLabel()}:|This is the title"))
- }
- }
- }
- }
-
- override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false
-
- override fun matches(message: String): Boolean {
- return message.matches(LINK_MATCH)
- }
-
- internal fun fetchTitle(link: String): String {
- try {
- val html = Jsoup.connect(link)
- .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0")
- .get()
- val title = html.title()
- if (title.isNotBlank()) {
- return title
- }
- } catch (ignore: IOException) {
- // Do nothing
- }
- return Constants.NO_TITLE
- }
-
- private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean {
- synchronized(entries) {
- return try {
- val match = entries.links.single { it.link == link }
- event.sendMessage(
- "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match)
- )
- true
- } catch (ignore: NoSuchElementException) {
- false
- }
- }
- }
-
- internal fun matchTagKeywords(title: String, tags: MutableList) {
- for (match in keywords) {
- val m = Regex.escape(match)
- if (title.matches("(?i).*\\b$m\\b.*".toRegex())) {
- tags.add(match)
- }
- }
- }
-
- override fun setProperty(key: String, value: String) {
- super.setProperty(key, value)
- if (KEYWORDS_PROP == key) {
- keywords.addAll(value.split(TAG_MATCH))
- } else if (TAGS_PROP == key) {
- defaultTags.addAll(value.split(TAG_MATCH))
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt
deleted file mode 100644
index ff4278d..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Posting.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.links
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries
-import net.thauvin.erik.mobibot.entries.EntriesUtils
-import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel
-import net.thauvin.erik.mobibot.entries.EntryLink
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Posting : AbstractCommand() {
- override val name = "posting"
- override val help = listOf(
- "Post a URL, by saying it on a line on its own:",
- helpFormat(" [] ${Tags.COMMAND}: <+tag> [...]]"),
- "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1",
- "To add a title, use its label and a pipe:",
- helpFormat("${Constants.LINK_CMD}1:|This is the title"),
- "To add a comment:",
- helpFormat("${Constants.LINK_CMD}1:This is a comment"),
- "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1",
- "To edit a comment, see: ",
- helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}")
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val cmds = args.substring(1).split(":", limit = 2)
- val entryIndex = cmds[0].toInt() - 1
-
- if (entryIndex < entries.links.size) {
- val cmd = cmds[1].trim()
- if (cmd.isBlank()) {
- showEntry(entryIndex, event) // L1:
- } else if (LinksManager.isUpToDate(event)) {
- if (cmd == "-") {
- removeEntry(channel, entryIndex, event) // L1:-
- } else {
- when (cmd[0]) {
- '|' -> changeTitle(cmd, entryIndex, event) // L1:|
- '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=
- '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?
- else -> addComment(cmd, entryIndex, event) // L1:
- }
- }
- }
- }
- }
-
- override fun matches(message: String): Boolean {
- return message.matches("${Constants.LINK_CMD}\\d+:.*".toRegex())
- }
-
- private fun addComment(cmd: String, entryIndex: Int, event: GenericMessageEvent) {
- val entry: EntryLink = entries.links[entryIndex]
- val commentIndex = entry.addComment(cmd, event.user.nick)
- val comment = entry.getComment(commentIndex)
- event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment))
- entries.save()
- }
-
- private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) {
- if (cmd.length > 1) {
- val entry: EntryLink = entries.links[entryIndex]
- entry.title = cmd.substring(1).trim()
- LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
- event.sendMessage(EntriesUtils.printLink(entryIndex, entry))
- entries.save()
- }
- }
-
- private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) {
- val entry: EntryLink = entries.links[entryIndex]
- if (entry.login == event.user.login || event.isChannelOp(channel)) {
- val link = cmd.substring(1)
- if (link.matches(LinksManager.LINK_MATCH)) {
- val oldLink = entry.link
- entry.link = link
- LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry)
- event.sendMessage(EntriesUtils.printLink(entryIndex, entry))
- entries.save()
- }
- }
- }
-
- private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) {
- if (event.isChannelOp(channel)) {
- if (cmd.length > 1) {
- val entry: EntryLink = entries.links[index]
- entry.nick = cmd.substring(1)
- LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
- event.sendMessage(EntriesUtils.printLink(index, entry))
- entries.save()
- }
- } else {
- event.sendMessage("Please ask a channel op to change the author of this link for you.")
- }
- }
-
- private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) {
- val entry: EntryLink = entries.links[index]
- if (entry.login == event.user.login || event.isChannelOp(channel)) {
- LinksManager.pinboard.deletePin(entry)
- LinksManager.socialManager.removeEntry(index)
- entries.links.removeAt(index)
- event.sendMessage("Entry ${index.toLinkLabel()} removed.")
- entries.save()
- } else {
- event.sendMessage("Please ask a channel op to remove this entry for you.")
- }
- }
-
- private fun showEntry(index: Int, event: GenericMessageEvent) {
- val entry: EntryLink = entries.links[index]
- event.sendMessage(EntriesUtils.printLink(index, entry))
- if (entry.tags.isNotEmpty()) {
- event.sendMessage(EntriesUtils.printTags(index, entry))
- }
- if (entry.comments.isNotEmpty()) {
- val comments = entry.comments
- for (i in comments.indices) {
- event.sendMessage(EntriesUtils.printComment(index, i, comments[i]))
- }
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt
deleted file mode 100644
index 1662857..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Tags.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.links
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.entries.EntriesUtils
-import net.thauvin.erik.mobibot.entries.EntryLink
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class Tags : AbstractCommand() {
- override val name = COMMAND
- override val help = listOf(
- "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:",
- helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]")
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val COMMAND = "tags"
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- val cmds = args.substring(1).split("${Constants.TAG_CMD}:", limit = 2)
- val index = cmds[0].toInt() - 1
-
- if (index < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) {
- val cmd = cmds[1].trim()
- val entry: EntryLink = LinksManager.entries.links[index]
- if (cmd.isNotEmpty()) {
- if (entry.login == event.user.login || event.isChannelOp(channel)) {
- entry.setTags(cmd)
- LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
- event.sendMessage(EntriesUtils.printTags(index, entry))
- LinksManager.entries.save()
- } else {
- event.sendMessage("Please ask a channel op to change the tags for you.")
- }
- } else {
- if (entry.tags.isNotEmpty()) {
- event.sendMessage(EntriesUtils.printTags(index, entry))
- } else {
- event.sendMessage("The entry has no tags. Why don't add some?")
- }
- }
- }
- }
-
- override fun matches(message: String): Boolean {
- return message.matches("^${Constants.LINK_CMD}\\d+${Constants.TAG_CMD}:.*".toRegex())
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt
deleted file mode 100644
index 825e374..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * View.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.links
-
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpCmdSyntax
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.lastOrEmpty
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries
-import net.thauvin.erik.mobibot.entries.EntriesUtils
-import net.thauvin.erik.mobibot.entries.EntryLink
-import org.pircbotx.hooks.events.PrivateMessageEvent
-import org.pircbotx.hooks.types.GenericMessageEvent
-
-class View : AbstractCommand() {
- override val name = VIEW_CMD
- override val help = listOf(
- "To list or search the current URL posts:",
- helpFormat("%c $name [] []")
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
- companion object {
- const val MAX_ENTRIES = 6
- const val VIEW_CMD = "view"
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (entries.links.isNotEmpty()) {
- val p = parseArgs(args)
- showPosts(p.first, p.second, event)
- } else {
- event.sendMessage("There is currently nothing to view. Why don't you post something?")
- }
- }
-
- internal fun parseArgs(args: String): Pair {
- var query = args.lowercase().trim()
- var start = 0
- if (query.isEmpty() && entries.links.size > MAX_ENTRIES) {
- start = entries.links.size - MAX_ENTRIES
- }
- if (query.matches("^\\d+(| .*)".toRegex())) { // view [] []
- val split = query.split(" ", limit = 2)
- try {
- start = split[0].toInt() - 1
- query = split.lastOrEmpty().trim()
- if (start > entries.links.size) {
- start = 0
- }
- } catch (ignore: NumberFormatException) {
- // Do nothing
- }
- }
- return Pair(start, query)
- }
-
- private fun showPosts(start: Int, query: String, event: GenericMessageEvent) {
- var index = start
- var entry: EntryLink
- var sent = 0
- while (index < entries.links.size && sent < MAX_ENTRIES) {
- entry = entries.links[index]
- if (query.isNotBlank()) {
- if (entry.matches(query)) {
- event.sendMessage(EntriesUtils.printLink(index, entry, true))
- sent++
- }
- } else {
- event.sendMessage(EntriesUtils.printLink(index, entry, true))
- sent++
- }
- index++
- if (sent == MAX_ENTRIES && index < entries.links.size) {
- event.sendMessage("To view more, try: ")
- event.sendMessage(
- helpFormat(
- helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent)
- )
- )
- }
- }
- if (sent == 0) {
- event.sendMessage("No matches. Please try again.")
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt
deleted file mode 100644
index cfd2c27..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * NickComparator.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.seen
-
-import java.io.Serializable
-
-class NickComparator : Comparator, Serializable {
- override fun compare(a: String, b: String): Int {
- return a.lowercase().compareTo(b.lowercase())
- }
-
- companion object {
- @Suppress("ConstPropertyName")
- private const val serialVersionUID = 1L
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt
deleted file mode 100644
index c9ee0f3..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Seen.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.seen
-
-import com.google.common.collect.ImmutableSortedSet
-import net.thauvin.erik.mobibot.Utils
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.loadSerialData
-import net.thauvin.erik.mobibot.Utils.saveSerialData
-import net.thauvin.erik.mobibot.Utils.sendList
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime
-import org.pircbotx.User
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.util.*
-
-
-class Seen(private val serialObject: String) : AbstractCommand() {
- private val logger: Logger = LoggerFactory.getLogger(Seen::class.java)
- private val allKeyword = "all"
- val seenNicks = TreeMap(NickComparator())
-
- override val name = "seen"
- override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name "))
- private val helpOp = help.plus(
- arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword"))
- )
- override val isOpOnly = false
- override val isPublic = true
- override val isVisible = true
-
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (isEnabled()) {
- if (args.isNotBlank() && !args.contains(' ')) {
- val ch = event.bot().userChannelDao.getChannel(channel)
- if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) {
- event.sendMessage("The ${"seen".bold()} nicks are:")
- event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true)
- return
- }
- ch.users.forEach {
- if (args.equals(it.nick, true)) {
- event.sendMessage("${it.nick} is on ${channel}.")
- return
- }
- }
- if (seenNicks.containsKey(args)) {
- val seenNick = seenNicks.getValue(args)
- val lastSeen = System.currentTimeMillis() - seenNick.lastSeen
- event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.")
- return
- }
- event.sendMessage("I haven't seen $args on $channel lately.")
- } else {
- helpResponse(channel, args, event)
- }
- }
- }
-
- fun add(nick: String) {
- if (isEnabled()) {
- seenNicks[nick] = SeenNick(nick, System.currentTimeMillis())
- save()
- }
- }
-
- fun add(users: ImmutableSortedSet) {
- if (isEnabled()) {
- users.forEach {
- seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis())
- }
- save()
- }
- }
-
- fun clear() {
- seenNicks.clear()
- }
-
- fun count(): Int = seenNicks.size
-
- override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
- return if (event.isChannelOp(channel)) {
- for (h in helpOp) {
- event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true))
- }
- true
- } else {
- super.helpResponse(channel, topic, event)
- }
- }
-
- fun load() {
- if (isEnabled()) {
- @Suppress("UNCHECKED_CAST")
- seenNicks.putAll(
- loadSerialData(
- serialObject,
- TreeMap(),
- logger,
- "seen nicknames"
- ) as TreeMap
- )
- }
- }
-
- fun save() {
- saveSerialData(serialObject, seenNicks, logger, "seen nicknames")
- }
-
- init {
- load()
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt
deleted file mode 100644
index 7924977..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SeenNick.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.commands.seen
-
-import java.io.Serializable
-
-data class SeenNick(val nick: String, val lastSeen: Long) : Serializable {
- companion object {
- @Suppress("ConstPropertyName")
- private const val serialVersionUID = 1L
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt
deleted file mode 100644
index 061ca6a..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Tell.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.commands.tell
-
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.bot
-import net.thauvin.erik.mobibot.Utils.helpCmdSyntax
-import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.Utils.isChannelOp
-import net.thauvin.erik.mobibot.Utils.plural
-import net.thauvin.erik.mobibot.Utils.reverseColor
-import net.thauvin.erik.mobibot.Utils.sendMessage
-import net.thauvin.erik.mobibot.Utils.toIntOrDefault
-import net.thauvin.erik.mobibot.Utils.toUtcDateTime
-import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.links.View
-import org.pircbotx.PircBotX
-import org.pircbotx.hooks.events.MessageEvent
-import org.pircbotx.hooks.types.GenericMessageEvent
-import org.pircbotx.hooks.types.GenericUserEvent
-
-/**
- * The `Tell` command.
- */
-class Tell(private val serialObject: String) : AbstractCommand() {
- // Messages queue
- private val messages: MutableList = mutableListOf()
-
- // Maximum number of days to keep messages
- private var maxDays = 7
-
- // Message maximum queue size
- private var maxSize = 50
-
- /**
- * The tell command.
- */
- override val name = "tell"
-
- override val help = listOf(
- "To send a message to someone when they join the channel:",
- helpFormat("%c $name "),
- "To view queued and sent messages:",
- helpFormat("%c $name ${View.VIEW_CMD}"),
- "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.'
- )
- override val isOpOnly: Boolean = false
- override val isPublic: Boolean = isEnabled()
- override val isVisible: Boolean = isEnabled()
-
- /**
- * Cleans the messages queue.
- */
- private fun clean(): Boolean {
- return TellManager.clean(messages, maxDays.toLong())
- }
-
- override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
- if (isEnabled()) {
- when {
- args.isBlank() -> {
- helpResponse(channel, args, event)
- }
-
- args.startsWith(View.VIEW_CMD) -> {
- if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
- viewAll(event)
- } else {
- viewMessages(event)
- }
- }
-
- args.startsWith("$TELL_DEL_KEYWORD ") -> {
- deleteMessage(channel, args, event)
- }
-
- else -> {
- newMessage(channel, args, event)
- }
- }
- if (clean()) {
- save()
- }
- }
- }
-
- // Delete message.
- private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) {
- val split = args.split(" ")
- if (split.size == 2) {
- val id = split[1]
- if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) {
- if (messages.removeIf { it.sender.equals(event.user.nick, true) && it.isReceived }) {
- save()
- event.sendMessage("Delivered messages have been deleted.")
- } else {
- event.sendMessage("No delivered messages were found.")
- }
- } else {
- if (messages.removeIf {
- it.id == id &&
- (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel))
- }) {
- save()
- event.sendMessage("The message was deleted from the queue.")
- } else {
- event.sendMessage("The specified message [ID $id] could not be found.")
- }
- }
- } else {
- helpResponse(channel, args, event)
- }
- }
-
- override fun isEnabled(): Boolean {
- return maxSize > 0 && maxDays > 0
- }
-
- override fun setProperty(key: String, value: String) {
- super.setProperty(key, value)
- if (MAX_DAYS_PROP == key) {
- maxDays = value.toIntOrDefault(maxDays)
- } else if (MAX_SIZE_PROP == key) {
- maxSize = value.toIntOrDefault(maxSize)
- }
- }
-
- // New message.
- private fun newMessage(channel: String, args: String, event: GenericMessageEvent) {
- val split = args.split(" ".toRegex(), 2)
- if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) {
- if (messages.size < maxSize) {
- val message = TellMessage(event.user.nick, split[0], split[1].trim())
- messages.add(message)
- save()
- event.sendMessage("Message [ID ${message.id}] was queued for ${message.recipient.bold()}")
- } else {
- event.sendMessage("Sorry, the messages queue is currently full.")
- }
- } else {
- helpResponse(channel, args, event)
- }
- }
-
- /**
- * Saves the messages queue.
- */
- private fun save() {
- TellManager.save(serialObject, messages)
- }
-
- /**
- * Checks and sends messages.
- */
- fun send(event: GenericUserEvent) {
- val nickname = event.user.nick
- if (isEnabled() && nickname != event.getBot().nick) {
- messages.filter { it.isMatch(nickname) }.forEach { message ->
- if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) {
- if (message.sender == nickname) {
- if (event !is MessageEvent) {
- event.user.send().message(
- "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}"
- )
- message.isReceived = true
- message.isNotified = true
- save()
- }
- } else {
- event.user.send().message(
- "${message.sender} wanted me to tell you: ${message.message.reverseColor()}"
- )
- message.isReceived = true
- save()
- }
- } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived
- && !message.isNotified
- ) {
- event.user.send().message(
- "Your message ${"[ID ${message.id}]".reverseColor()} was sent to "
- + "${message.recipient.bold()} on ${message.receptionDate}"
- )
- message.isNotified = true
- save()
- }
- }
- }
- }
-
- /**
- * Returns the messages queue size.
- *
- * @return The size.
- */
- fun size(): Int = messages.size
-
- // View all messages.
- private fun viewAll(event: GenericMessageEvent) {
- if (messages.isNotEmpty()) {
- for (message in messages) {
- event.sendMessage(
- "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " +
- (if (message.isReceived) "DELIVERED]" else "QUEUED]")
- )
- }
- } else {
- event.sendMessage("There are no messages in the queue.")
- }
- }
-
- // View messages.
- private fun viewMessages(event: GenericMessageEvent) {
- var hasMessage = false
- for (message in messages.filter { it.isMatch(event.user.nick) }) {
- if (!hasMessage) {
- hasMessage = true
- event.sendMessage("Here are your messages: ")
- }
- if (message.isReceived) {
- event.sendMessage(
- message.sender.bold() + ARROW + message.recipient.bold() +
- " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]"
- )
- } else {
- event.sendMessage(
- message.sender.bold() + ARROW + message.recipient.bold() +
- " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]"
- )
- }
- event.sendMessage(helpFormat(message.message))
- }
- if (!hasMessage) {
- event.sendMessage("You have no messages in the queue.")
- } else {
- event.sendMessage("To delete one or all delivered messages:")
- event.sendMessage(
- helpFormat(
- helpCmdSyntax("%c $name $TELL_DEL_KEYWORD ", event.bot().nick, true)
- )
- )
- event.sendMessage(help.last())
- }
- }
-
- companion object {
- /**
- * Max days property.
- */
- const val MAX_DAYS_PROP = "tell-max-days"
-
- /**
- * Max size property.
- */
- const val MAX_SIZE_PROP = "tell-max-size"
-
- // Arrow
- private const val ARROW = " --> "
-
- // All keyword
- private const val TELL_ALL_KEYWORD = "all"
-
- //T he delete command.
- private const val TELL_DEL_KEYWORD = "del"
- }
-
- /**
- * Creates a new instance.
- */
- init {
- initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP)
-
- // Load the message queue
- messages.addAll(TellManager.load(serialObject))
- if (clean()) {
- save()
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt
deleted file mode 100644
index b65a4da..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * TellManager.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.commands.tell
-
-import net.thauvin.erik.mobibot.Utils.loadSerialData
-import net.thauvin.erik.mobibot.Utils.saveSerialData
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.time.Clock
-import java.time.LocalDateTime
-
-/**
- * The Tell Messages Manager.
- */
-object TellManager {
- private val logger: Logger = LoggerFactory.getLogger(TellManager::class.java)
-
- /**
- * Cleans the messages queue.
- */
- @JvmStatic
- fun clean(tellMessages: MutableList, tellMaxDays: Long): Boolean {
- if (logger.isDebugEnabled) logger.debug("Cleaning the messages.")
- val today = LocalDateTime.now(Clock.systemUTC())
- return tellMessages.removeIf { o: TellMessage -> o.queued.plusDays(tellMaxDays).isBefore(today) }
- }
-
- /**
- * Loads the messages.
- */
- @JvmStatic
- fun load(file: String): List {
- @Suppress("UNCHECKED_CAST")
- return loadSerialData(file, emptyList(), logger, "message queue") as List
- }
-
- /**
- * Saves the messages.
- */
- @JvmStatic
- fun save(file: String, messages: List?) {
- if (messages != null) {
- saveSerialData(file, messages, logger, "messages")
- }
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt
deleted file mode 100644
index d17fbb5..0000000
--- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * TellMessage.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.commands.tell
-
-import java.io.Serializable
-import java.time.Clock
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
-
-/**
- * Tell Message.
- */
-class TellMessage(
- /**
- * Returns the message's sender.
- */
- val sender: String,
-
- /**
- * Returns the message's recipient.
- */
- val recipient: String,
-
- /**
- * Returns the message text.
- */
- val message: String
-) : Serializable {
- /**
- * Returns the queued date/time.
- */
- var queued: LocalDateTime = LocalDateTime.now(Clock.systemUTC())
-
- /**
- * Returns the message id.
- */
- var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
-
- /**
- * Returns `true` if a notification was sent.
- */
- var isNotified = false
-
- /**
- * Returns `true` if the message was received.
- */
- var isReceived = false
- set(value) {
- if (value) {
- receptionDate = LocalDateTime.now(Clock.systemUTC())
- }
- field = value
- }
-
- /**
- * Returns the message creating date.
- */
- var receptionDate: LocalDateTime = LocalDateTime.MIN
-
- /**
- * Matches the message sender or recipient.
- */
- fun isMatch(nick: String?): Boolean {
- return sender.equals(nick, ignoreCase = true) || recipient.equals(nick, ignoreCase = true)
- }
-
- override fun toString(): String {
- return ("TellMessage{id='$id', isNotified=$isNotified, isReceived=$isReceived, message='$message', " +
- "queued=$queued, received=$receptionDate, recipient='$recipient', sender='$sender'}")
- }
-
- companion object {
- @Suppress("ConstPropertyName")
- private const val serialVersionUID = 2L
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt b/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt
deleted file mode 100644
index e8676ec..0000000
--- a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Entries.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.mobibot.entries
-
-import net.thauvin.erik.mobibot.Utils.today
-
-class Entries(
- var channel: String = "",
- var ircServer: String = "",
- var logsDir: String = "",
- var backlogs: String = ""
-) {
- val links = mutableListOf()
-
- var lastPubDate = today()
-
- fun load() {
- lastPubDate = FeedsManager.loadFeed(this)
- }
-
- fun save() {
- lastPubDate = today()
- FeedsManager.saveFeed(this)
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt
deleted file mode 100644
index 9c09626..0000000
--- a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * EntriesUtils.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.entries
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Utils.bold
-import net.thauvin.erik.mobibot.Utils.green
-
-/**
- * Entries utilities.
- */
-object EntriesUtils {
- /**
- * Prints an entry's comment for display on the channel.
- */
- @JvmStatic
- fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String =
- ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}")
-
- /**
- * Prints an entry's link for display on the channel.
- */
- @JvmStatic
- @JvmOverloads
- fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String {
- val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ")
- .append('[').append(entry.nick).append(']')
- if (isView && entry.comments.isNotEmpty()) {
- buff.append("[+").append(entry.comments.size).append(']')
- }
- buff.append(' ')
- with(entry) {
- if (Constants.NO_TITLE == title) {
- buff.append(title)
- } else {
- buff.append(title.bold())
- }
- buff.append(" ( ").append(link.green()).append(" )")
- }
- return buff.toString()
- }
-
- /**
- * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2
- */
- @JvmStatic
- fun printTags(entryIndex: Int, entry: EntryLink): String =
- entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ")
-
- /**
- * Builds link label based on its index. e.g: L1
- */
- @JvmStatic
- fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1)
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt
deleted file mode 100644
index e18d692..0000000
--- a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * EntryComment.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.entries
-
-import java.io.Serializable
-import java.time.LocalDateTime
-
-/**
- * Entry comments data class.
- */
-data class EntryComment(var comment: String, var nick: String) : Serializable {
- /**
- * Creation date.
- */
- val date: LocalDateTime = LocalDateTime.now()
-
- override fun toString(): String = "EntryComment{comment='$comment', date=$date, nick='$nick'}"
-
- companion object {
- // Serial version UID
- @Suppress("ConstPropertyName")
- private const val serialVersionUID: Long = 1L
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt
deleted file mode 100644
index 4a69446..0000000
--- a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * EntryLink.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.entries
-
-import com.rometools.rome.feed.synd.SyndCategory
-import com.rometools.rome.feed.synd.SyndCategoryImpl
-import net.thauvin.erik.mobibot.commands.links.LinksManager
-import java.io.Serializable
-import java.util.*
-
-/**
- * The class used to store link entries.
- */
-class EntryLink(
- // Link's comments
- val comments: MutableList = mutableListOf(),
-
- // Tags/categories
- val tags: MutableList = mutableListOf(),
-
- // Channel
- var channel: String,
-
- // Creation date
- var date: Date = Calendar.getInstance().time,
-
- // Link's URL
- var link: String,
-
- // Author's login
- var login: String = "",
-
- // Author's nickname
- var nick: String,
-
- // Link's title
- var title: String
-) : Serializable {
- /**
- * Creates a new entry.
- */
- constructor(
- link: String,
- title: String,
- nick: String,
- login: String,
- channel: String,
- tags: List
- ) : this(link = link, title = title, nick = nick, login = login, channel = channel) {
- setTags(tags)
- }
-
- /**
- * Creates a new entry.
- */
- constructor(
- link: String,
- title: String,
- nick: String,
- channel: String,
- date: Date,
- tags: List
- ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) {
- this.tags.addAll(tags)
- }
-
- /**
- * Adds a new comment
- */
- fun addComment(comment: EntryComment): Int {
- comments.add(comment)
- return comments.lastIndex
- }
-
- /**
- * Adds a new comment.
- */
- fun addComment(comment: String, nick: String): Int {
- return addComment(EntryComment(comment, nick))
- }
-
- /**
- * Deletes a specific comment.
- */
- fun deleteComment(index: Int): Boolean {
- if (index < comments.size) {
- comments.removeAt(index)
- return true
- }
- return false
- }
-
- /**
- * Deletes a comment.
- */
- fun deleteComment(entryComment: EntryComment): Boolean {
- return comments.remove(entryComment)
- }
-
- /**
- * Formats the tags.
- */
- fun formatTags(sep: String, prefix: String = ""): String {
- return tags.joinToString(separator = sep, prefix = prefix) { it.name }
- }
-
- /**
- * Returns a comment.
- */
- fun getComment(index: Int): EntryComment = comments[index]
-
- /**
- * Returns true if a string is contained in the link, title, or nick.
- */
- fun matches(match: String?): Boolean {
- return if (match.isNullOrEmpty()) {
- false
- } else {
- link.contains(match, true) || title.contains(match, true) || nick.contains(match, true)
- }
- }
-
- /**
- * Sets a comment.
- */
- fun setComment(index: Int, comment: String?, nick: String?) {
- if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) {
- comments[index] = EntryComment(comment, nick)
- }
- }
-
- /**
- * Sets the tags.
- */
- fun setTags(tags: String) {
- setTags(tags.split(LinksManager.TAG_MATCH))
- }
-
- /**
- * Sets the tags.
- */
- private fun setTags(tags: List) {
- if (tags.isNotEmpty()) {
- var category: SyndCategoryImpl
- for (tag in tags) {
- if (!tag.isNullOrBlank()) {
- val t = tag.lowercase()
- val mod = t[0]
- if (mod == '-') {
- // Don't remove the channel tag
- if (channel.substring(1) != t.substring(1)) {
- category = SyndCategoryImpl()
- category.name = t.substring(1)
- this.tags.remove(category)
- }
- } else {
- category = SyndCategoryImpl()
- if (mod == '+') {
- category.name = t.substring(1)
- } else {
- category.name = t
- }
- if (!this.tags.contains(category)) {
- this.tags.add(category)
- }
- }
- }
- }
- }
- }
-
- /**
- * Returns a string representation of the object.
- */
- override fun toString(): String {
- return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," +
- "nick='$nick', tags=$tags, title='$title'}")
- }
-
- companion object {
- // Serial version UID
- @Suppress("ConstPropertyName")
- private const val serialVersionUID: Long = 1L
- }
-}
diff --git a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt
deleted file mode 100644
index f786cb2..0000000
--- a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * FeedsManager.kt
- *
- * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.mobibot.entries
-
-import com.rometools.rome.feed.synd.*
-import com.rometools.rome.io.FeedException
-import com.rometools.rome.io.SyndFeedInput
-import com.rometools.rome.io.SyndFeedOutput
-import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
-import net.thauvin.erik.mobibot.Utils.today
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import java.io.IOException
-import java.io.InputStreamReader
-import java.io.OutputStreamWriter
-import java.nio.charset.StandardCharsets
-import java.nio.file.Files
-import java.nio.file.Paths
-import java.util.*
-import kotlin.io.path.exists
-
-/**
- * Manages the RSS feeds.
- */
-class FeedsManager private constructor() {
- companion object {
- private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java)
-
- // The file containing the current entries.
- private const val CURRENT_XML = "current.xml"
-
- // The .xml extension.
- private const val DOT_XML = ".xml"
-
- /**
- * Loads the current feed.
- */
- @JvmStatic
- @Throws(IOException::class, FeedException::class)
- fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String {
- entries.links.clear()
- val xml = Paths.get("${entries.logsDir}${currentFile}")
- var pubDate = today()
- if (xml.exists()) {
- val input = SyndFeedInput()
- InputStreamReader(
- Files.newInputStream(xml), StandardCharsets.UTF_8
- ).use { reader ->
- val feed = input.build(reader)
- pubDate = feed.publishedDate.toIsoLocalDate()
- val items = feed.entries
- var entry: EntryLink
- for (i in items.indices.reversed()) {
- with(items[i]) {
- entry = EntryLink(
- link,
- title,
- author.substring(author.lastIndexOf('(') + 1, author.length - 1),
- entries.channel,
- publishedDate,
- categories
- )
- var split: List
- for (comment in description.value.split(" ")) {
- split = comment.split(": ".toRegex(), 2)
- if (split.size == 2) {
- entry.addComment(comment = split[1].trim(), nick = split[0].trim())
- }
- }
- }
- entries.links.add(entry)
- }
- }
- } else {
- // Create an empty feed.
- saveFeed(entries)
- }
- return pubDate
- }
-
- /**
- * Saves the feeds.
- */
- @JvmStatic
- fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) {
- if (logger.isDebugEnabled) logger.debug("Saving the feeds...")
- if (entries.logsDir.isNotBlank()) {
- try {
- val output = SyndFeedOutput()
- val rss: SyndFeed = SyndFeedImpl()
- val items: MutableList = mutableListOf()
- var item: SyndEntry
- OutputStreamWriter(
- Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8
- ).use { fw ->
- with(rss) {
- feedType = "rss_2.0"
- title = "${entries.channel} IRC Links"
- description = "Links from ${entries.ircServer} on ${entries.channel}"
- if (entries.backlogs.isNotBlank()) link = entries.backlogs
- publishedDate = Calendar.getInstance().time
- language = "en"
- }
- val buff: StringBuilder = StringBuilder()
- for (i in entries.links.indices.reversed()) {
- with(entries.links[i]) {
- buff.setLength(0)
- buff.append("Posted by ")
- .append(nick)
- .append(" on ")
- .append(channel)
- .append("")
- if (comments.isNotEmpty()) {
- buff.append("