Converted Mobibot class to Kotlin.
This commit is contained in:
parent
a44b0c1f49
commit
69441f7006
30 changed files with 956 additions and 1134 deletions
11
.idea/compiler.xml
generated
11
.idea/compiler.xml
generated
|
@ -1,17 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<annotationProcessing>
|
|
||||||
<profile name="Gradle Imported" enabled="true">
|
|
||||||
<outputRelativeToContentRoot value="true" />
|
|
||||||
<option name="semver.project.dir" value="$PROJECT_DIR$" />
|
|
||||||
<processorPath useClasspath="false">
|
|
||||||
<entry name="$MAVEN_REPOSITORY$/net/thauvin/erik/semver/1.2.0/semver-1.2.0.jar" />
|
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/github/spullara/mustache/java/compiler/0.9.6/compiler-0.9.6.jar" />
|
|
||||||
</processorPath>
|
|
||||||
<module name="mobibot.main" />
|
|
||||||
</profile>
|
|
||||||
</annotationProcessing>
|
|
||||||
<bytecodeTargetLevel target="11" />
|
<bytecodeTargetLevel target="11" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
2
.idea/mobibot.iml
generated
2
.idea/mobibot.iml
generated
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.id="mobibot" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="0.8.0-beta+287" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="mobibot" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="0.8.0-beta+327" type="JAVA_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
|
|
83
.idea/modules/mobibot.main.iml
generated
83
.idea/modules/mobibot.main.iml
generated
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.id="mobibot:main" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="" external.system.module.type="sourceSet" external.system.module.version="0.8.0-beta+287" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="mobibot:main" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="" external.system.module.type="sourceSet" external.system.module.version="0.8.0-beta+327" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="kotlin-language" name="Kotlin">
|
<facet type="kotlin-language" name="Kotlin">
|
||||||
<configuration version="3" platform="JVM 11" allPlatforms="JVM [11]" useProjectSettings="false">
|
<configuration version="3" platform="JVM 11" allPlatforms="JVM [11]" useProjectSettings="false">
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
</compilerSettings>
|
</compilerSettings>
|
||||||
<compilerArguments>
|
<compilerArguments>
|
||||||
<option name="destination" value="$MODULE_DIR$/../../build/classes/kotlin/main" />
|
<option name="destination" value="$MODULE_DIR$/../../build/classes/kotlin/main" />
|
||||||
<option name="classpath" value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/net.aksingh/owm-japis/2.5.3.0/c3aca5d34ba937e0c8e9776cec906003b0703044/owm-japis-2.5.3.0.jar:/media/erik/Projects/maven/repository/net/thauvin/erik/pinboard-poster/1.0.1/pinboard-poster-1.0.1.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.4.20/756521338269950c2a276f1abe6fef8e1a5e5528/kotlin-stdlib-jdk8-1.4.20.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.4.2/4b9c6b2de7cabfb2c9ad7a5c709b1ddb7bbfd2ad/kotlinx-coroutines-core-jvm-1.4.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.4.20/9de2c79e95d4b4699a455e88ba285a95352e0bea/kotlin-stdlib-jdk7-1.4.20.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.20/9be77b243a362b745e365f286627b8724337009c/kotlin-stdlib-1.4.20.jar:/media/erik/Projects/maven/repository/net/thauvin/erik/semver/1.2.0/semver-1.2.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/pircbot/pircbot/1.5.0/cc27715d1c9c8246beb6a33ea099a9ca5d4e5da1/pircbot-1.5.0-sources.jar:/home/erik/.gradle/caches/modules-2/files-2.1/pircbot/pircbot/1.5.0/7a9dd235e6e81db733212202cc4067b5625650cf/pircbot-1.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.github.spotbugs/spotbugs-annotations/4.2.0/39d2a464e63fd44bcdbc2332b12a80df274dac83/spotbugs-annotations-4.2.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.rometools/rome/1.15.0/d3614542b857eccc0555d1ee8dfc36d2043d9c1f/rome-1.15.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/commons-cli/commons-cli/1.4/c51c00206bb913cd8612b24abd9fa98ae89719b1/commons-cli-1.4.jar:/home/erik/.gradle/caches/modules-2/files-2.1/commons-net/commons-net/3.7.2/fc22868c06d0b59dc97f23dc93ca77efd9381ab2/commons-net-3.7.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/net.objecthunter/exp4j/0.4.8/cf1cfc0f958077d86ac7452c7e36d944689b2ec4/exp4j-0.4.8.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.11/68e9a6adf7cf8eb7e9d31bbc554c7c75eeaac568/commons-lang3-3.11.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.json/json/20201115/f8e7a9953822c90e0701c3cd50764b5e9063f85c/json-20201115.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jsoup/jsoup/1.13.1/f9577f3732bb7caa4fee8aba5053158f4010c118/jsoup-1.13.1.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.twitter4j/twitter4j-core/4.0.7/5fdb375ccfb3eda7354efb262cbe9b53abccff2/twitter4j-core-4.0.7.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.14.0/e257b0562453f73eabac1bc3181ba33e79d193ed/log4j-core-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-slf4j-impl/2.14.0/d6003a3b3f24fdb476848f4ecabdb2a43354e410/log4j-slf4j-impl-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.14.0/23cdb2c6babad9b2b0dcf47c6a2c29d504e4c7a8/log4j-api-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.20/c6761d7805b5312302f2bbd78cda68c976ce0c70/kotlin-stdlib-common-1.4.20.jar:/media/erik/Projects/maven/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.rometools/rome-utils/1.15.0/ab1cb95382bf9a8dec81165d328bcbbf1acfb3ae/rome-utils-1.15.0.jar:/media/erik/Projects/maven/repository/org/jdom/jdom2/2.0.6/jdom2-2.0.6.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.25/da76ca59f6a57ee3102f8f9bd9cee742973efa8a/slf4j-api-1.7.25.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/converter-gson/2.5.0/1c96fc5d0230f57d36cd09e2541d10829a3352a7/converter-gson-2.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.google.code.gson/gson/2.8.5/f645ed69d595b24d4cf8b3fbb64cc505bede8829/gson-2.8.5.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/retrofit/2.5.0/713ce36037bf24a76a3974c05cb85c3f754b1cc3/retrofit-2.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.14.2/eaed79ed6bc1e14fad462172b6a09524545b165c/okhttp-3.14.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.17.2/78c7820b205002da4d2d137f6f312bd64b3d6049/okio-1.17.2.jar" />
|
<option name="classpath" value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/net.aksingh/owm-japis/2.5.3.0/c3aca5d34ba937e0c8e9776cec906003b0703044/owm-japis-2.5.3.0.jar:/media/erik/Projects/maven/repository/net/thauvin/erik/pinboard-poster/1.0.1/pinboard-poster-1.0.1.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.4.20/756521338269950c2a276f1abe6fef8e1a5e5528/kotlin-stdlib-jdk8-1.4.20.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.4.2/4b9c6b2de7cabfb2c9ad7a5c709b1ddb7bbfd2ad/kotlinx-coroutines-core-jvm-1.4.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.4.20/9de2c79e95d4b4699a455e88ba285a95352e0bea/kotlin-stdlib-jdk7-1.4.20.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.20/9be77b243a362b745e365f286627b8724337009c/kotlin-stdlib-1.4.20.jar:/home/erik/.gradle/caches/modules-2/files-2.1/pircbot/pircbot/1.5.0/cc27715d1c9c8246beb6a33ea099a9ca5d4e5da1/pircbot-1.5.0-sources.jar:/home/erik/.gradle/caches/modules-2/files-2.1/pircbot/pircbot/1.5.0/7a9dd235e6e81db733212202cc4067b5625650cf/pircbot-1.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.github.spotbugs/spotbugs-annotations/4.2.0/39d2a464e63fd44bcdbc2332b12a80df274dac83/spotbugs-annotations-4.2.0.jar:/media/erik/Projects/maven/repository/net/thauvin/erik/semver/1.2.0/semver-1.2.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.rometools/rome/1.15.0/d3614542b857eccc0555d1ee8dfc36d2043d9c1f/rome-1.15.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/commons-cli/commons-cli/1.4/c51c00206bb913cd8612b24abd9fa98ae89719b1/commons-cli-1.4.jar:/home/erik/.gradle/caches/modules-2/files-2.1/commons-net/commons-net/3.7.2/fc22868c06d0b59dc97f23dc93ca77efd9381ab2/commons-net-3.7.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/net.objecthunter/exp4j/0.4.8/cf1cfc0f958077d86ac7452c7e36d944689b2ec4/exp4j-0.4.8.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.11/68e9a6adf7cf8eb7e9d31bbc554c7c75eeaac568/commons-lang3-3.11.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.json/json/20201115/f8e7a9953822c90e0701c3cd50764b5e9063f85c/json-20201115.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jsoup/jsoup/1.13.1/f9577f3732bb7caa4fee8aba5053158f4010c118/jsoup-1.13.1.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.twitter4j/twitter4j-core/4.0.7/5fdb375ccfb3eda7354efb262cbe9b53abccff2/twitter4j-core-4.0.7.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.14.0/e257b0562453f73eabac1bc3181ba33e79d193ed/log4j-core-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-slf4j-impl/2.14.0/d6003a3b3f24fdb476848f4ecabdb2a43354e410/log4j-slf4j-impl-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.14.0/23cdb2c6babad9b2b0dcf47c6a2c29d504e4c7a8/log4j-api-2.14.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.20/c6761d7805b5312302f2bbd78cda68c976ce0c70/kotlin-stdlib-common-1.4.20.jar:/media/erik/Projects/maven/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.rometools/rome-utils/1.15.0/ab1cb95382bf9a8dec81165d328bcbbf1acfb3ae/rome-utils-1.15.0.jar:/media/erik/Projects/maven/repository/org/jdom/jdom2/2.0.6/jdom2-2.0.6.jar:/home/erik/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.25/da76ca59f6a57ee3102f8f9bd9cee742973efa8a/slf4j-api-1.7.25.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/converter-gson/2.5.0/1c96fc5d0230f57d36cd09e2541d10829a3352a7/converter-gson-2.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.google.code.gson/gson/2.8.5/f645ed69d595b24d4cf8b3fbb64cc505bede8829/gson-2.8.5.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/retrofit/2.5.0/713ce36037bf24a76a3974c05cb85c3f754b1cc3/retrofit-2.5.0.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.14.2/eaed79ed6bc1e14fad462172b6a09524545b165c/okhttp-3.14.2.jar:/home/erik/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.17.2/78c7820b205002da4d2d137f6f312bd64b3d6049/okio-1.17.2.jar" />
|
||||||
<option name="noStdlib" value="true" />
|
<option name="noStdlib" value="true" />
|
||||||
<option name="noReflect" value="true" />
|
<option name="noReflect" value="true" />
|
||||||
<option name="moduleName" value="mobibot" />
|
<option name="moduleName" value="mobibot" />
|
||||||
|
@ -20,6 +20,9 @@
|
||||||
</option>
|
</option>
|
||||||
<option name="pluginClasspaths">
|
<option name="pluginClasspaths">
|
||||||
<array>
|
<array>
|
||||||
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.4.20/fc1d26586910b32d676480c75acd3e922e5e81fa/kotlin-compiler-embeddable-1.4.20.jar" />
|
||||||
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-daemon-embeddable/1.4.20/a051291fb01bf2397759625626fec670cd57b3f0/kotlin-daemon-embeddable-1.4.20.jar" />
|
||||||
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.4.20/411fc46e908bfa9c034f52b0d31b2e1f61f06127/kotlin-reflect-1.4.20.jar" />
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.20/9793d2f6b262847a2d8127951c5786cf907cc7b1/kotlin-script-runtime-1.4.20.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.20/9793d2f6b262847a2d8127951c5786cf907cc7b1/kotlin-script-runtime-1.4.20.jar" />
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.20/2e2bf29688a76cec111df56bc5e358c5bbc5057/kotlin-scripting-common-1.4.20.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.20/2e2bf29688a76cec111df56bc5e358c5bbc5057/kotlin-scripting-common-1.4.20.jar" />
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.20/83704fbbe39946cc2ac6d0f07f41947abeb8dc20/kotlin-scripting-jvm-1.4.20.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.20/83704fbbe39946cc2ac6d0f07f41947abeb8dc20/kotlin-scripting-jvm-1.4.20.jar" />
|
||||||
|
@ -27,6 +30,7 @@
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.20/9be77b243a362b745e365f286627b8724337009c/kotlin-stdlib-1.4.20.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.20/9be77b243a362b745e365f286627b8724337009c/kotlin-stdlib-1.4.20.jar" />
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.7/8e2eb78158638b33793d204ffef0b65c4a578e1c/kotlinx-coroutines-core-1.3.7.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.7/8e2eb78158638b33793d204ffef0b65c4a578e1c/kotlinx-coroutines-core-1.3.7.jar" />
|
||||||
<option value="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
<option value="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
||||||
|
<option value="$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.jar" />
|
||||||
</array>
|
</array>
|
||||||
</option>
|
</option>
|
||||||
<option name="errors">
|
<option name="errors">
|
||||||
|
@ -39,46 +43,59 @@
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<output url="file://$MODULE_DIR$/../../build/classes/java/main" />
|
<output url="file://$MODULE_DIR$/../../build/classes/java/main" />
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$/../../src/generated/java">
|
<content url="file://$MODULE_DIR$/../../build/generated/source/kapt/main">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/generated/java" isTestSource="false" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/../../build/generated/source/kapt/main" isTestSource="false" generated="true" />
|
||||||
|
</content>
|
||||||
|
<content url="file://$MODULE_DIR$/../../build/generated/source/kaptKotlin/main">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../../build/generated/source/kaptKotlin/main" isTestSource="false" generated="true" />
|
||||||
</content>
|
</content>
|
||||||
<content url="file://$MODULE_DIR$/../../src/main">
|
<content url="file://$MODULE_DIR$/../../src/main">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/main/java" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/../../src/main/java" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/main/resources" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/../../src/main/resources" type="java-resource" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="library" name="Gradle: commons-cli:commons-cli:1.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: pircbot:pircbot:1.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.17.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jsoup:jsoup:1.13.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: net.objecthunter:exp4j:0.4.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.rometools:rome-utils:1.15.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.14.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.rometools:rome:1.15.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-slf4j-impl:2.14.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.slf4j:slf4j-api:1.7.25" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.20" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.twitter4j:twitter4j-core:4.0.7" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Gradle: pircbot:pircbot:sources:1.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:retrofit:2.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.14.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.json:json:20201115" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.14.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.code.findbugs:jsr305:3.0.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.github.spotbugs:spotbugs-annotations:4.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jdom:jdom2:2.0.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: commons-net:commons-net:3.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.20" level="project" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module-library">
|
||||||
|
<library name="Gradle: kaptGeneratedClasses">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="file://$MODULE_DIR$/../../build/tmp/kapt3/classes/main" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</orderEntry>
|
||||||
<orderEntry type="library" name="Gradle: net.aksingh:owm-japis:2.5.3.0" level="project" />
|
<orderEntry type="library" name="Gradle: net.aksingh:owm-japis:2.5.3.0" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: net.thauvin.erik:pinboard-poster:1.0.1" level="project" />
|
<orderEntry type="library" name="Gradle: net.thauvin.erik:pinboard-poster:1.0.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.4.20" level="project" />
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.4.20" level="project" />
|
||||||
<orderEntry type="library" scope="PROVIDED" name="Gradle: net.thauvin.erik:semver:1.2.0" level="project" />
|
<orderEntry type="library" name="Gradle: net.thauvin.erik:semver:1.2.0" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: pircbot:pircbot:1.5.0" level="project" />
|
<orderEntry type="library" scope="RUNTIME" name="Gradle: com.github.spullara.mustache.java:compiler:0.9.6" level="project" />
|
||||||
<orderEntry type="library" scope="PROVIDED" name="Gradle: pircbot:pircbot:sources:1.5.0" level="project" />
|
|
||||||
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.github.spotbugs:spotbugs-annotations:4.2.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.rometools:rome:1.15.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: commons-cli:commons-cli:1.4" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: commons-net:commons-net:3.7.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: net.objecthunter:exp4j:0.4.8" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.11" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.json:json:20201115" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jsoup:jsoup:1.13.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.twitter4j:twitter4j-core:4.0.7" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.14.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-slf4j-impl:2.14.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.14.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.20" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.5.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.5" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:retrofit:2.5.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.14.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0" level="project" />
|
|
||||||
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.code.findbugs:jsr305:3.0.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.rometools:rome-utils:1.15.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jdom:jdom2:2.0.6" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.slf4j:slf4j-api:1.7.25" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.20" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.17.2" level="project" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
26
.idea/modules/mobibot.test.iml
generated
26
.idea/modules/mobibot.test.iml
generated
File diff suppressed because one or more lines are too long
32
ReleaseInfo.mustache
Normal file
32
ReleaseInfo.mustache
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* This file is automatically generated.
|
||||||
|
* Do not modify! -- ALL CHANGES WILL BE ERASED!
|
||||||
|
*/
|
||||||
|
package {{packageName}}
|
||||||
|
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides semantic version information.
|
||||||
|
*
|
||||||
|
* @author [Semantic Version Annotation Processor](https://github.com/ethauvin/semver)
|
||||||
|
*/
|
||||||
|
object ReleaseInfo{
|
||||||
|
const val PROJECT = "{{project}}"
|
||||||
|
const val VERSION = "{{version}}"
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val BUILDDATE = LocalDateTime.ofInstant(Instant.ofEpochMilli({{epoch}}L), ZoneId.systemDefault())
|
||||||
|
|
||||||
|
const val MAJOR = {{major}}
|
||||||
|
const val MINOR = {{minor}}
|
||||||
|
const val PATCH = {{patch}}
|
||||||
|
const val BUILDMETA = "{{buildMeta}}"
|
||||||
|
const val PRERELEASE = "{{preRelease}}"
|
||||||
|
|
||||||
|
const val WEBSITE = "https://www.mobitopia.org/mobibot/"
|
||||||
|
const val AUTHOR = "Erik C. Thauvin"
|
||||||
|
const val AUTHOR_URL = "https://erik.thauvin.net/"
|
||||||
|
}
|
13
build.gradle
13
build.gradle
|
@ -9,6 +9,7 @@ plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'net.thauvin.erik.gradle.semver' version '1.0.4'
|
id 'net.thauvin.erik.gradle.semver' version '1.0.4'
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.4.20'
|
id 'org.jetbrains.kotlin.jvm' version '1.4.20'
|
||||||
|
id 'org.jetbrains.kotlin.kapt' version '1.4.20'
|
||||||
id 'org.sonarqube' version '3.0'
|
id 'org.sonarqube' version '3.0'
|
||||||
id 'pmd'
|
id 'pmd'
|
||||||
}
|
}
|
||||||
|
@ -33,8 +34,8 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
annotationProcessor semverProcessor
|
kapt(semverProcessor)
|
||||||
compileOnly semverProcessor
|
implementation(semverProcessor)
|
||||||
|
|
||||||
implementation 'pircbot:pircbot:1.5.0'
|
implementation 'pircbot:pircbot:1.5.0'
|
||||||
compileOnly 'pircbot:pircbot:1.5.0:sources'
|
compileOnly 'pircbot:pircbot:1.5.0:sources'
|
||||||
|
@ -77,14 +78,18 @@ java {
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kapt {
|
||||||
|
arguments {
|
||||||
|
arg("semver.project.dir", projectDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClassName = packageName + '.Mobibot'
|
mainClassName = packageName + '.Mobibot'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
options.annotationProcessorGeneratedSourcesDirectory = file("${projectDir}/src/generated/java")
|
|
||||||
options.compilerArgs += ["-Asemver.project.dir=$projectDir"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||||
<CurrentIssues>
|
<CurrentIssues>
|
||||||
<ID>ComplexMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
<ID>ComplexMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
|
<ID>ComplexMethod:Mobibot.kt$Mobibot$override fun onPrivateMessage( sender: String, login: String, hostname: String, message: String )</ID>
|
||||||
<ID>ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>LongMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
<ID>LongMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
|
<ID>LongMethod:Mobibot.kt$Mobibot.Companion$ @JvmStatic fun main(args: Array<String>)</ID>
|
||||||
<ID>LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )</ID>
|
<ID>LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )</ID>
|
||||||
|
@ -22,6 +24,11 @@
|
||||||
<ID>MagicNumber:Cycle.kt$Cycle$10</ID>
|
<ID>MagicNumber:Cycle.kt$Cycle$10</ID>
|
||||||
<ID>MagicNumber:Dice.kt$Dice$7</ID>
|
<ID>MagicNumber:Dice.kt$Dice$7</ID>
|
||||||
<ID>MagicNumber:Ignore.kt$Ignore$8</ID>
|
<ID>MagicNumber:Ignore.kt$Ignore$8</ID>
|
||||||
|
<ID>MagicNumber:Mobibot.kt$Mobibot$10</ID>
|
||||||
|
<ID>MagicNumber:Mobibot.kt$Mobibot$1000L</ID>
|
||||||
|
<ID>MagicNumber:Mobibot.kt$Mobibot$3</ID>
|
||||||
|
<ID>MagicNumber:Mobibot.kt$Mobibot$5</ID>
|
||||||
|
<ID>MagicNumber:Mobibot.kt$Mobibot$8</ID>
|
||||||
<ID>MagicNumber:Modules.kt$Modules$7</ID>
|
<ID>MagicNumber:Modules.kt$Modules$7</ID>
|
||||||
<ID>MagicNumber:Recap.kt$Recap.Companion$10</ID>
|
<ID>MagicNumber:Recap.kt$Recap.Companion$10</ID>
|
||||||
<ID>MagicNumber:Tell.kt$Tell$50</ID>
|
<ID>MagicNumber:Tell.kt$Tell$50</ID>
|
||||||
|
@ -50,11 +57,14 @@
|
||||||
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message</ID>
|
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message</ID>
|
||||||
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ @Throws(IOException::class, FeedException::class) fun loadEntries(file: String, channel: String, entries: ArrayList<EntryLink>): String</ID>
|
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ @Throws(IOException::class, FeedException::class) fun loadEntries(file: String, channel: String, entries: ArrayList<EntryLink>): String</ID>
|
||||||
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
<ID>NestedBlockDepth:EntryLink.kt$EntryLink$ fun setTags(tags: List<String?>)</ID>
|
<ID>NestedBlockDepth:EntryLink.kt$EntryLink$ private fun setTags(tags: List<String?>)</ID>
|
||||||
<ID>NestedBlockDepth:FeedReader.kt$FeedReader$ override fun run()</ID>
|
<ID>NestedBlockDepth:FeedReader.kt$FeedReader$ override fun run()</ID>
|
||||||
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
||||||
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
||||||
<ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )</ID>
|
<ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )</ID>
|
||||||
|
<ID>NestedBlockDepth:Mobibot.kt$Mobibot$ fun connect()</ID>
|
||||||
|
<ID>NestedBlockDepth:Mobibot.kt$Mobibot$override fun onMessage( channel: String, sender: String, login: String, hostname: String, message: String )</ID>
|
||||||
|
<ID>NestedBlockDepth:Mobibot.kt$Mobibot$override fun onPrivateMessage( sender: String, login: String, hostname: String, message: String )</ID>
|
||||||
<ID>NestedBlockDepth:StockQuote.kt$StockQuote$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
<ID>NestedBlockDepth:StockQuote.kt$StockQuote$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
||||||
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>NestedBlockDepth:Tell.kt$Tell$ @JvmOverloads fun send(nickname: String, isMessage: Boolean = false)</ID>
|
<ID>NestedBlockDepth:Tell.kt$Tell$ @JvmOverloads fun send(nickname: String, isMessage: Boolean = false)</ID>
|
||||||
|
@ -63,14 +73,18 @@
|
||||||
<ID>NestedBlockDepth:Weather2.kt$Weather2$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
<ID>NestedBlockDepth:Weather2.kt$Weather2$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
||||||
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>NestedBlockDepth:WorldTime.kt$WorldTime$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )</ID>
|
<ID>NestedBlockDepth:WorldTime.kt$WorldTime$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )</ID>
|
||||||
|
<ID>ReturnCount:Mobibot.kt$Mobibot$override fun onMessage( channel: String, sender: String, login: String, hostname: String, message: String )</ID>
|
||||||
<ID>ReturnCount:Utils.kt$Utils.Companion$ @JvmStatic fun colorize(s: String?, color: String): String</ID>
|
<ID>ReturnCount:Utils.kt$Utils.Companion$ @JvmStatic fun colorize(s: String?, color: String): String</ID>
|
||||||
<ID>ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$ @JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message></ID>
|
<ID>ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$ @JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message></ID>
|
||||||
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID>
|
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID>
|
||||||
<ID>ThrowsCount:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>ThrowsCount:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>TooGenericExceptionCaught:FeedReader.kt$FeedReader$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:FeedReader.kt$FeedReader$e: Exception</ID>
|
||||||
|
<ID>TooGenericExceptionCaught:Mobibot.kt$Mobibot$e: Exception</ID>
|
||||||
|
<ID>TooGenericExceptionCaught:Mobibot.kt$Mobibot$ex: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException</ID>
|
<ID>TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException</ID>
|
||||||
<ID>TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException</ID>
|
<ID>TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException</ID>
|
||||||
|
<ID>TooManyFunctions:Mobibot.kt$Mobibot : PircBot</ID>
|
||||||
<ID>TooManyFunctions:Tell.kt$Tell : AbstractCommand</ID>
|
<ID>TooManyFunctions:Tell.kt$Tell : AbstractCommand</ID>
|
||||||
<ID>TooManyFunctions:Utils.kt$Utils$Companion</ID>
|
<ID>TooManyFunctions:Utils.kt$Utils$Companion</ID>
|
||||||
</CurrentIssues>
|
</CurrentIssues>
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is automatically generated.
|
|
||||||
* Do not modify! -- ALL CHANGES WILL BE ERASED!
|
|
||||||
*/
|
|
||||||
package {{packageName}};
|
|
||||||
|
|
||||||
import java.time.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides semantic version information.
|
|
||||||
*
|
|
||||||
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
|
|
||||||
*/
|
|
||||||
public final class {{className}} {
|
|
||||||
public static final String PROJECT = "{{project}}";
|
|
||||||
public static final String VERSION = "{{version}}";
|
|
||||||
public static final LocalDateTime BUILDDATE =
|
|
||||||
LocalDateTime.ofInstant(Instant.ofEpochMilli({{epoch}}L), ZoneId.systemDefault());
|
|
||||||
|
|
||||||
public static final int MAJOR = {{major}};
|
|
||||||
public static final int MINOR = {{minor}};
|
|
||||||
public static final int PATCH = {{patch}};
|
|
||||||
public static final String BUILDMETA = "{{buildMeta}}";
|
|
||||||
public static final String PRERELEASE = "{{preRelease}}";
|
|
||||||
|
|
||||||
public static final String WEBSITE = "https://www.mobitopia.org/mobibot/";
|
|
||||||
public static final String AUTHOR = "Erik C. Thauvin";
|
|
||||||
public static final String AUTHOR_URL = "https://erik.thauvin.net/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the default constructor.
|
|
||||||
*/
|
|
||||||
private {{className}}() {
|
|
||||||
throw new UnsupportedOperationException("Illegal constructor call.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is automatically generated.
|
|
||||||
* Do not modify! -- ALL CHANGES WILL BE ERASED!
|
|
||||||
*/
|
|
||||||
package net.thauvin.erik.mobibot;
|
|
||||||
|
|
||||||
import java.time.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides semantic version information.
|
|
||||||
*
|
|
||||||
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
|
|
||||||
*/
|
|
||||||
public final class ReleaseInfo {
|
|
||||||
public static final String PROJECT = "mobibot";
|
|
||||||
public static final String VERSION = "0.8.0-beta+305";
|
|
||||||
public static final LocalDateTime BUILDDATE =
|
|
||||||
LocalDateTime.ofInstant(Instant.ofEpochMilli(1607122730368L), ZoneId.systemDefault());
|
|
||||||
|
|
||||||
public static final int MAJOR = 0;
|
|
||||||
public static final int MINOR = 8;
|
|
||||||
public static final int PATCH = 0;
|
|
||||||
public static final String BUILDMETA = "305";
|
|
||||||
public static final String PRERELEASE = "beta";
|
|
||||||
|
|
||||||
public static final String WEBSITE = "https://www.mobitopia.org/mobibot/";
|
|
||||||
public static final String AUTHOR = "Erik C. Thauvin";
|
|
||||||
public static final String AUTHOR_URL = "https://erik.thauvin.net/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the default constructor.
|
|
||||||
*/
|
|
||||||
private ReleaseInfo() {
|
|
||||||
throw new UnsupportedOperationException("Illegal constructor call.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,956 +0,0 @@
|
||||||
/*
|
|
||||||
* Mobibot.java
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* 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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import net.thauvin.erik.mobibot.commands.AbstractCommand;
|
|
||||||
import net.thauvin.erik.mobibot.commands.AddLog;
|
|
||||||
import net.thauvin.erik.mobibot.commands.ChannelFeed;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Cycle;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Ignore;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Info;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Me;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Modules;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Msg;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Nick;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Recap;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Say;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Users;
|
|
||||||
import net.thauvin.erik.mobibot.commands.Versions;
|
|
||||||
import net.thauvin.erik.mobibot.commands.links.Comment;
|
|
||||||
import net.thauvin.erik.mobibot.commands.links.LinksMgr;
|
|
||||||
import net.thauvin.erik.mobibot.commands.links.Posting;
|
|
||||||
import net.thauvin.erik.mobibot.commands.links.Tags;
|
|
||||||
import net.thauvin.erik.mobibot.commands.links.View;
|
|
||||||
import net.thauvin.erik.mobibot.commands.tell.Tell;
|
|
||||||
import net.thauvin.erik.mobibot.entries.EntriesMgr;
|
|
||||||
import net.thauvin.erik.mobibot.entries.EntryLink;
|
|
||||||
import net.thauvin.erik.mobibot.modules.AbstractModule;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Calc;
|
|
||||||
import net.thauvin.erik.mobibot.modules.CurrencyConverter;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Dice;
|
|
||||||
import net.thauvin.erik.mobibot.modules.GoogleSearch;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Joke;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Lookup;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Ping;
|
|
||||||
import net.thauvin.erik.mobibot.modules.RockPaperScissors;
|
|
||||||
import net.thauvin.erik.mobibot.modules.StockQuote;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Twitter;
|
|
||||||
import net.thauvin.erik.mobibot.modules.War;
|
|
||||||
import net.thauvin.erik.mobibot.modules.Weather2;
|
|
||||||
import net.thauvin.erik.mobibot.modules.WorldTime;
|
|
||||||
import net.thauvin.erik.mobibot.msg.Message;
|
|
||||||
import net.thauvin.erik.pinboard.PinboardPoster;
|
|
||||||
import net.thauvin.erik.semver.Version;
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.DefaultParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.logging.log4j.Level;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
|
||||||
import org.jibble.pircbot.PircBot;
|
|
||||||
import org.jibble.pircbot.User;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.logging.ConsoleHandler;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
import static org.apache.commons.lang3.StringUtils.lowerCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the #mobitopia bot.
|
|
||||||
*
|
|
||||||
* @author <a href="https://erik.thauvin.net" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @created Jan 31, 2004
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
|
||||||
@Version(properties = "version.properties",
|
|
||||||
className = "ReleaseInfo")
|
|
||||||
public class Mobibot extends PircBot {
|
|
||||||
// Logger
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(Mobibot.class);
|
|
||||||
// Maximum number of times the bot will try to reconnect, if disconnected
|
|
||||||
private static final int MAX_RECONNECT = 10;
|
|
||||||
// Timer
|
|
||||||
private static final Timer TIMER = new Timer(true);
|
|
||||||
// Commands and Modules
|
|
||||||
private final Addons addons = new Addons();
|
|
||||||
// Main channel
|
|
||||||
private final String ircChannel;
|
|
||||||
// IRC port
|
|
||||||
private final int ircPort;
|
|
||||||
// IRC server
|
|
||||||
private final String ircServer;
|
|
||||||
// Logger default level
|
|
||||||
private final Level loggerLevel;
|
|
||||||
// Log directory
|
|
||||||
private final String logsDir;
|
|
||||||
// Tell command
|
|
||||||
private final Tell tell;
|
|
||||||
// Today's date
|
|
||||||
private final String today = Utils.today();
|
|
||||||
// Twitter module
|
|
||||||
private final Twitter twitter;
|
|
||||||
// Backlogs URL
|
|
||||||
private String backLogsUrl = "";
|
|
||||||
// Ident message
|
|
||||||
private String identMsg = "";
|
|
||||||
// Ident nick
|
|
||||||
private String identNick = "";
|
|
||||||
// NickServ ident password
|
|
||||||
private String identPwd = "";
|
|
||||||
// Pinboard posts handler
|
|
||||||
private PinboardPoster pinboard;
|
|
||||||
// Weblog URL
|
|
||||||
private String weblogUrl = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Mobibot} instance.
|
|
||||||
*
|
|
||||||
* @param channel The irc channel.
|
|
||||||
* @param nickname The bot's nickname.
|
|
||||||
* @param logsDirPath The path to the logs directory.
|
|
||||||
* @param p The bot's properties.
|
|
||||||
*/
|
|
||||||
public Mobibot(final String nickname, final String channel, final String logsDirPath, final Properties p) {
|
|
||||||
super();
|
|
||||||
System.getProperties().setProperty("sun.net.client.defaultConnectTimeout",
|
|
||||||
String.valueOf(Constants.CONNECT_TIMEOUT));
|
|
||||||
System.getProperties().setProperty("sun.net.client.defaultReadTimeout",
|
|
||||||
String.valueOf(Constants.CONNECT_TIMEOUT));
|
|
||||||
|
|
||||||
setName(nickname);
|
|
||||||
|
|
||||||
ircServer = p.getProperty("server", Constants.DEFAULT_SERVER);
|
|
||||||
ircPort = Utils.getIntProperty(p.getProperty("port"), Constants.DEFAULT_PORT);
|
|
||||||
ircChannel = channel;
|
|
||||||
logsDir = logsDirPath;
|
|
||||||
|
|
||||||
// Set the logger level
|
|
||||||
loggerLevel = LOGGER.getLevel();
|
|
||||||
|
|
||||||
// Load the current entries and backlogs, if any
|
|
||||||
try {
|
|
||||||
LinksMgr.startup(logsDir + EntriesMgr.CURRENT_XML, logsDir + EntriesMgr.NAV_XML, ircChannel);
|
|
||||||
LOGGER.debug("Last feed: {}", LinksMgr.getStartDate());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error("An error occurred while loading the logs.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the bot
|
|
||||||
setVerbose(true);
|
|
||||||
setAutoNickChange(true);
|
|
||||||
setLogin(p.getProperty("login", getName()));
|
|
||||||
setVersion(ReleaseInfo.PROJECT + ' ' + ReleaseInfo.VERSION);
|
|
||||||
// setMessageDelay(1000);
|
|
||||||
setIdentity(p.getProperty("ident", ""), p.getProperty("ident-nick", ""), p.getProperty("ident-msg", ""));
|
|
||||||
|
|
||||||
// Set the URLs
|
|
||||||
setWeblogUrl(p.getProperty("weblog", ""));
|
|
||||||
setBacklogsUrl(Utils.ensureDir(p.getProperty("backlogs", weblogUrl), true));
|
|
||||||
|
|
||||||
// Set the pinboard authentication
|
|
||||||
setPinboardAuth(p.getProperty("pinboard-api-token"));
|
|
||||||
|
|
||||||
// Load the commands
|
|
||||||
addons.add(new AddLog(this), p);
|
|
||||||
addons.add(new ChannelFeed(this, getChannelName()), p);
|
|
||||||
addons.add(new Cycle(this), p);
|
|
||||||
addons.add(new Ignore(this), p);
|
|
||||||
addons.add(new Info(this), p);
|
|
||||||
addons.add(new Me(this), p);
|
|
||||||
addons.add(new Modules(this), p);
|
|
||||||
addons.add(new Msg(this), p);
|
|
||||||
addons.add(new Nick(this), p);
|
|
||||||
addons.add(new Recap(this), p);
|
|
||||||
addons.add(new Say(this), p);
|
|
||||||
addons.add(new Users(this), p);
|
|
||||||
addons.add(new Versions(this), p);
|
|
||||||
|
|
||||||
// Tell command
|
|
||||||
tell = new Tell(this);
|
|
||||||
addons.add(tell, p);
|
|
||||||
|
|
||||||
// Load the links commands
|
|
||||||
addons.add(new Comment(this), p);
|
|
||||||
addons.add(new Posting(this), p);
|
|
||||||
addons.add(new Tags(this), p);
|
|
||||||
addons.add(new LinksMgr(this), p);
|
|
||||||
addons.add(new View(this), p);
|
|
||||||
|
|
||||||
// Load the modules
|
|
||||||
addons.add(new Calc(this), p);
|
|
||||||
addons.add(new CurrencyConverter(this), p);
|
|
||||||
addons.add(new Dice(this), p);
|
|
||||||
addons.add(new GoogleSearch(this), p);
|
|
||||||
addons.add(new Joke(this), p);
|
|
||||||
addons.add(new Lookup(this), p);
|
|
||||||
addons.add(new Ping(this), p);
|
|
||||||
addons.add(new RockPaperScissors(this), p);
|
|
||||||
addons.add(new StockQuote(this), p);
|
|
||||||
addons.add(new War(this), p);
|
|
||||||
addons.add(new Weather2(this), p);
|
|
||||||
addons.add(new WorldTime(this), p);
|
|
||||||
|
|
||||||
// Twitter module
|
|
||||||
twitter = new Twitter(this);
|
|
||||||
addons.add(twitter, p);
|
|
||||||
|
|
||||||
// Sort the addons
|
|
||||||
addons.sort();
|
|
||||||
|
|
||||||
// Save the entries
|
|
||||||
LinksMgr.saveEntries(this, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Truth Is Out There...
|
|
||||||
*
|
|
||||||
* @param args The command line arguments.
|
|
||||||
*/
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
{ "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE",
|
|
||||||
"DM_DEFAULT_ENCODING",
|
|
||||||
"IOI_USE_OF_FILE_STREAM_CONSTRUCTORS" })
|
|
||||||
@SuppressWarnings({ "PMD.SystemPrintln", "PMD.AvoidFileStream", "PMD.CloseResource" })
|
|
||||||
public static void main(final String[] args) {
|
|
||||||
// Setup the command line options
|
|
||||||
final Options options = new Options()
|
|
||||||
.addOption(Constants.HELP_ARG.substring(0, 1),
|
|
||||||
Constants.HELP_ARG,
|
|
||||||
false,
|
|
||||||
"print this help message")
|
|
||||||
.addOption(Constants.DEBUG_ARG.substring(0, 1), Constants.DEBUG_ARG, false,
|
|
||||||
"print debug & logging data directly to the console")
|
|
||||||
.addOption(Option.builder(Constants.PROPS_ARG.substring(0, 1)).hasArg()
|
|
||||||
.argName("file")
|
|
||||||
.desc("use " + "alternate properties file")
|
|
||||||
.longOpt(Constants.PROPS_ARG).build())
|
|
||||||
.addOption(Constants.VERSION_ARG.substring(0, 1),
|
|
||||||
Constants.VERSION_ARG,
|
|
||||||
false,
|
|
||||||
"print version info");
|
|
||||||
|
|
||||||
// Parse the command line
|
|
||||||
final CommandLineParser parser = new DefaultParser();
|
|
||||||
CommandLine commandLine = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
commandLine = parser.parse(options, args);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
System.err.println("CLI Parsing failed. Reason: " + e.getMessage());
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commandLine.hasOption(Constants.HELP_ARG.charAt(0))) {
|
|
||||||
// Output the usage
|
|
||||||
new HelpFormatter().printHelp(Mobibot.class.getName(), options);
|
|
||||||
} else if (commandLine.hasOption(Constants.VERSION_ARG.charAt(0))) {
|
|
||||||
System.out.println(ReleaseInfo.PROJECT + ' ' + ReleaseInfo.VERSION
|
|
||||||
+ " (" + Utils.isoLocalDate(ReleaseInfo.BUILDDATE) + ')');
|
|
||||||
System.out.println(ReleaseInfo.WEBSITE);
|
|
||||||
} else {
|
|
||||||
final Properties p = new Properties();
|
|
||||||
try (final InputStream fis = Files.newInputStream(
|
|
||||||
Paths.get(commandLine.getOptionValue(Constants.PROPS_ARG.charAt(0), "./mobibot.properties")))) {
|
|
||||||
// Load the properties files
|
|
||||||
p.load(fis);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
System.err.println("Unable to find properties file.");
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Unable to open properties file.");
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String nickname = p.getProperty("nick", lowerCase(Mobibot.class.getName()));
|
|
||||||
final String channel = p.getProperty("channel");
|
|
||||||
final String logsDir = Utils.ensureDir(p.getProperty("logs", "."), false);
|
|
||||||
|
|
||||||
// Redirect the stdout and stderr
|
|
||||||
if (!commandLine.hasOption(Constants.DEBUG_ARG.charAt(0))) {
|
|
||||||
try {
|
|
||||||
final PrintStream stdout = new PrintStream(new BufferedOutputStream(new FileOutputStream(
|
|
||||||
logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true)), true);
|
|
||||||
System.setOut(stdout);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Unable to open output (stdout) log file.");
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final PrintStream stderr =
|
|
||||||
new PrintStream(new BufferedOutputStream(
|
|
||||||
new FileOutputStream(logsDir + nickname + ".err", true)), true);
|
|
||||||
System.setErr(stderr);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Unable to open error (stderr) log file.");
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the bot
|
|
||||||
final Mobibot bot = new Mobibot(nickname, channel, logsDir, p);
|
|
||||||
|
|
||||||
// Connect
|
|
||||||
bot.connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an action to the current channel.
|
|
||||||
*
|
|
||||||
* @param action The action.
|
|
||||||
*/
|
|
||||||
public final void action(final String action) {
|
|
||||||
action(ircChannel, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an action to the channel.
|
|
||||||
*
|
|
||||||
* @param channel The channel.
|
|
||||||
* @param action The action.
|
|
||||||
*/
|
|
||||||
private void action(final String channel, final String action) {
|
|
||||||
if (isNotBlank(channel) && isNotBlank(action)) {
|
|
||||||
sendAction(channel, action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds pin on pinboard.
|
|
||||||
*
|
|
||||||
* @param entry The entry to add.
|
|
||||||
*/
|
|
||||||
public final void addPin(final EntryLink entry) {
|
|
||||||
if (pinboard != null) {
|
|
||||||
PinboardUtils.addPin(pinboard, ircServer, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connects to the server and joins the channel.
|
|
||||||
*/
|
|
||||||
@SuppressFBWarnings({ "DM_EXIT", "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE" })
|
|
||||||
public final void connect() {
|
|
||||||
try {
|
|
||||||
connect(ircServer, ircPort);
|
|
||||||
} catch (Exception e) {
|
|
||||||
int retries = 0;
|
|
||||||
|
|
||||||
while ((retries++ < MAX_RECONNECT) && !isConnected()) {
|
|
||||||
sleep(10);
|
|
||||||
|
|
||||||
try {
|
|
||||||
connect(ircServer, ircPort);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
if (retries == MAX_RECONNECT) {
|
|
||||||
LOGGER.debug("Unable to reconnect to {} after {} retries.", ircServer, MAX_RECONNECT, ex);
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
identify();
|
|
||||||
joinChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes pin on pinboard.
|
|
||||||
*
|
|
||||||
* @param entry The entry to delete.
|
|
||||||
*/
|
|
||||||
public final void deletePin(final int index, final EntryLink entry) {
|
|
||||||
if (pinboard != null) {
|
|
||||||
PinboardUtils.deletePin(pinboard, entry);
|
|
||||||
}
|
|
||||||
if (twitter.isAutoPost()) {
|
|
||||||
twitter.removeEntry(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the backlogs URL.
|
|
||||||
*
|
|
||||||
* @return The backlogs URL.
|
|
||||||
*/
|
|
||||||
public final String getBacklogsUrl() {
|
|
||||||
return backLogsUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current channel.
|
|
||||||
*
|
|
||||||
* @return The current channel.
|
|
||||||
*/
|
|
||||||
public final String getChannel() {
|
|
||||||
return ircChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current channel name.
|
|
||||||
*
|
|
||||||
* @return The current channel name.
|
|
||||||
*/
|
|
||||||
@SuppressFBWarnings("STT_STRING_PARSING_A_FIELD")
|
|
||||||
public final String getChannelName() {
|
|
||||||
return ircChannel.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the irc server.
|
|
||||||
*
|
|
||||||
* @return The irc server.
|
|
||||||
*/
|
|
||||||
public final String getIrcServer() {
|
|
||||||
return ircServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bot's logger.
|
|
||||||
*
|
|
||||||
* @return The bot's logger.
|
|
||||||
*/
|
|
||||||
public final Logger getLogger() {
|
|
||||||
return LOGGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the log directory.
|
|
||||||
*
|
|
||||||
* @return the log directory.
|
|
||||||
*/
|
|
||||||
public final String getLogsDir() {
|
|
||||||
return logsDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the enabled modules names.
|
|
||||||
*
|
|
||||||
* @return The modules names.
|
|
||||||
*/
|
|
||||||
public final List<String> getModulesNames() {
|
|
||||||
return addons.getModulesNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Tell command.
|
|
||||||
*
|
|
||||||
* @return The tell command.
|
|
||||||
*/
|
|
||||||
public final Tell getTell() {
|
|
||||||
return tell;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bot's timer.
|
|
||||||
*
|
|
||||||
* @return The timer.
|
|
||||||
*/
|
|
||||||
public final Timer getTimer() {
|
|
||||||
return TIMER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get today's date for the feed.
|
|
||||||
*
|
|
||||||
* @return Today's date.
|
|
||||||
*/
|
|
||||||
public String getToday() {
|
|
||||||
return today;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Twitter command.
|
|
||||||
*
|
|
||||||
* @return The Twitter command.
|
|
||||||
*/
|
|
||||||
public final Twitter getTwitter() {
|
|
||||||
return twitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the weblog URL.
|
|
||||||
*
|
|
||||||
* @return The weblog URL.
|
|
||||||
*/
|
|
||||||
public final String getWeblogUrl() {
|
|
||||||
return weblogUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds with the commands help, if any.
|
|
||||||
*
|
|
||||||
* @param sender The nick of the person requesting Constants.
|
|
||||||
* @param topic The help topic.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
* @return {@code true} if the topic was found, {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
private boolean helpCommands(final String sender, final String topic, final boolean isPrivate) {
|
|
||||||
for (final AbstractCommand command : addons.getCommands()) {
|
|
||||||
if (command.isVisible() && command.getName().startsWith(topic)) {
|
|
||||||
return command.helpResponse(topic, sender, isOp(sender), isPrivate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds with the default Constants.
|
|
||||||
*
|
|
||||||
* @param sender The nick of the person requesting Constants.
|
|
||||||
* @param isOp The channel operator flag.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
*/
|
|
||||||
public void helpDefault(final String sender, final boolean isOp, final boolean isPrivate) {
|
|
||||||
send(sender, "Type a URL on " + ircChannel + " to post it.", isPrivate);
|
|
||||||
send(sender, "For more information on a specific command, type:", isPrivate);
|
|
||||||
send(sender,
|
|
||||||
Utils.helpIndent(Utils.helpFormat("%c " + Constants.HELP_CMD + " <command>", getNick(), isPrivate)),
|
|
||||||
isPrivate);
|
|
||||||
send(sender, "The commands are:", isPrivate);
|
|
||||||
sendList(sender, addons.getNames(), 8, isPrivate, true);
|
|
||||||
if (isOp) {
|
|
||||||
send(sender, "The op commands are:", isPrivate);
|
|
||||||
sendList(sender, addons.getOps(), 8, isPrivate, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds with the modules help, if any.
|
|
||||||
*
|
|
||||||
* @param sender The nick of the person requesting Constants.
|
|
||||||
* @param topic The help topic.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
* @return {@code true} if the topic was found, {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
private boolean helpModules(final String sender, final String topic, final boolean isPrivate) {
|
|
||||||
for (final AbstractModule module : addons.getModules()) {
|
|
||||||
for (final String cmd : module.commands) {
|
|
||||||
if (topic.equals(cmd)) {
|
|
||||||
module.helpResponse(sender, isPrivate);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds with the bot's Constants.
|
|
||||||
*
|
|
||||||
* @param sender The nick of the person who sent the private message.
|
|
||||||
* @param topic The help topic, if any.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
*/
|
|
||||||
private void helpResponse(final String sender, final String topic, final boolean isPrivate) {
|
|
||||||
final boolean isOp = isOp(sender);
|
|
||||||
if (StringUtils.isBlank(topic)) {
|
|
||||||
helpDefault(sender, isOp, isPrivate);
|
|
||||||
} else {
|
|
||||||
// Command, Modules or Default
|
|
||||||
if (!helpCommands(sender, topic, isPrivate) && !helpModules(sender, lowerCase(topic).trim(), isPrivate)) {
|
|
||||||
helpDefault(sender, isOp, isPrivate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifies the bot.
|
|
||||||
*/
|
|
||||||
private void identify() {
|
|
||||||
// Identify with NickServ
|
|
||||||
if (isNotBlank(identPwd)) {
|
|
||||||
identify(identPwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identify with a specified nick
|
|
||||||
if (isNotBlank(identNick) && isNotBlank(identMsg)) {
|
|
||||||
sendMessage(identNick, identMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns <code>true</code> if the specified sender is an Op on the {@link #ircChannel channel}.
|
|
||||||
*
|
|
||||||
* @param sender The sender.
|
|
||||||
* @return true, if the sender is an Op.
|
|
||||||
*/
|
|
||||||
public boolean isOp(final String sender) {
|
|
||||||
final User[] users = getUsers(ircChannel);
|
|
||||||
|
|
||||||
for (final User user : users) {
|
|
||||||
if (user.getNick().equals(sender)) {
|
|
||||||
return user.isOp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Joins the bot's channel.
|
|
||||||
*/
|
|
||||||
public final void joinChannel() {
|
|
||||||
joinChannel(ircChannel);
|
|
||||||
twitter.notification(getName() + " " + ReleaseInfo.VERSION + " has joined " + getChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final void onDisconnect() {
|
|
||||||
if (isNotBlank(weblogUrl)) {
|
|
||||||
setVersion(weblogUrl);
|
|
||||||
}
|
|
||||||
sleep(5);
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@SuppressFBWarnings(value = "CC_CYCLOMATIC_COMPLEXITY",
|
|
||||||
justification = "Working on it.")
|
|
||||||
@Override
|
|
||||||
protected final void onMessage(final String channel, final String sender, final String login, final String hostname,
|
|
||||||
final String message) {
|
|
||||||
LOGGER.debug(">>> {} : {}", sender, message);
|
|
||||||
|
|
||||||
tell.send(sender, true);
|
|
||||||
|
|
||||||
if (message.matches("(?i)" + Pattern.quote(getNick()) + ":.*")) { // mobibot: <command>
|
|
||||||
final String[] cmds = message.substring(message.indexOf(':') + 1).trim().split(" ", 2);
|
|
||||||
final String cmd = lowerCase(cmds[0]);
|
|
||||||
|
|
||||||
String args = "";
|
|
||||||
|
|
||||||
if (cmds.length > 1) {
|
|
||||||
args = cmds[1].trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help
|
|
||||||
helpResponse(sender, args, false);
|
|
||||||
} else {
|
|
||||||
// Commands
|
|
||||||
for (final AbstractCommand command : addons.getCommands()) {
|
|
||||||
if (command.isPublic() && command.getName().startsWith(cmd)) {
|
|
||||||
command.commandResponse(sender, login, args, isOp(sender), false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Modules
|
|
||||||
for (final AbstractModule module : addons.getModules()) { // modules
|
|
||||||
for (final String c : module.commands) {
|
|
||||||
if (cmd.startsWith(c)) {
|
|
||||||
module.commandResponse(sender, cmd, args, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Commands, e.g.: https://www.example.com/
|
|
||||||
for (final AbstractCommand command : addons.getCommands()) {
|
|
||||||
if (command.matches(message)) {
|
|
||||||
command.commandResponse(sender, login, message, isOp(sender), false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Recap.storeRecap(sender, message, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@SuppressFBWarnings(value = { "DM_EXIT", "CC_CYCLOMATIC_COMPLEXITY" },
|
|
||||||
justification = "Yes, we want to bail out.")
|
|
||||||
@Override
|
|
||||||
protected final void onPrivateMessage(final String sender, final String login, final String hostname,
|
|
||||||
final String message) {
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug(">>> {} : {}", sender, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String[] cmds = message.split(" ", 2);
|
|
||||||
final String cmd = lowerCase(cmds[0]);
|
|
||||||
String args = "";
|
|
||||||
|
|
||||||
if (cmds.length > 1) {
|
|
||||||
args = cmds[1].trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean isOp = isOp(sender);
|
|
||||||
|
|
||||||
if (cmd.startsWith(Constants.HELP_CMD)) { // help
|
|
||||||
helpResponse(sender, args, true);
|
|
||||||
} else if (isOp && "kill".equals(cmd)) { // kill
|
|
||||||
twitter.notification(getName() + " killed by " + sender + " on " + getChannel());
|
|
||||||
sendRawLine("QUIT : Poof!");
|
|
||||||
System.exit(0);
|
|
||||||
} else if (isOp && Constants.DEBUG_CMD.equals(cmd)) { // debug
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
Configurator.setLevel(LOGGER.getName(), loggerLevel);
|
|
||||||
} else {
|
|
||||||
Configurator.setLevel(LOGGER.getName(), Level.DEBUG);
|
|
||||||
}
|
|
||||||
send(sender, "Debug logging is " + (LOGGER.isDebugEnabled() ? "enabled." : "disabled."), true);
|
|
||||||
} else if (isOp && Constants.DIE_CMD.equals(cmd)) { // die
|
|
||||||
send(sender + " has just signed my death sentence.");
|
|
||||||
TIMER.cancel();
|
|
||||||
twitter.shutdown();
|
|
||||||
twitter.notification(getName() + " stopped by " + sender + " on " + getChannel());
|
|
||||||
sleep(3);
|
|
||||||
quitServer("The Bot Is Out There!");
|
|
||||||
System.exit(0);
|
|
||||||
} else {
|
|
||||||
for (final AbstractCommand command : addons.getCommands()) {
|
|
||||||
if (command.getName().startsWith(cmd)) {
|
|
||||||
command.commandResponse(sender, login, args, isOp, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (final AbstractModule module : addons.getModules()) {
|
|
||||||
if (module.isPrivateMsgEnabled()) {
|
|
||||||
for (final String c : module.commands) {
|
|
||||||
if (cmd.equals(c)) {
|
|
||||||
module.commandResponse(sender, cmd, args, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
helpDefault(sender, isOp, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final void onAction(final String sender, final String login, final String hostname, final String target,
|
|
||||||
final String action) {
|
|
||||||
if (ircChannel.equals(target)) {
|
|
||||||
Recap.storeRecap(sender, action, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onJoin(final String channel, final String sender, final String login, final String hostname) {
|
|
||||||
tell.send(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onNickChange(final String oldNick, final String login, final String hostname, final String newNick) {
|
|
||||||
tell.send(newNick);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a private message or notice.
|
|
||||||
*
|
|
||||||
* @param sender The channel or nick of the person who sent the message.
|
|
||||||
* @param message The actual message.
|
|
||||||
* @param isPrivate Set to <code>true</code> if the response should be a private message, otherwise a notice is
|
|
||||||
* sent.
|
|
||||||
*/
|
|
||||||
public final void send(final String sender, final String message, final boolean isPrivate) {
|
|
||||||
if (isNotBlank(message) && isNotBlank(sender)) {
|
|
||||||
if (isPrivate) {
|
|
||||||
LOGGER.debug("Sending message to {} : {}", sender, message);
|
|
||||||
sendMessage(sender, message);
|
|
||||||
} else {
|
|
||||||
LOGGER.debug("Sending notice to {} : {}", sender, message);
|
|
||||||
sendNotice(sender, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a notice to the channel.
|
|
||||||
*
|
|
||||||
* @param notice The notice message.
|
|
||||||
*/
|
|
||||||
public final void send(final String notice) {
|
|
||||||
send(getChannel(), notice, false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message.
|
|
||||||
*
|
|
||||||
* @param who The channel or nick of the person who sent the command.
|
|
||||||
* @param message The message.
|
|
||||||
*/
|
|
||||||
public final void send(final String who, final Message message) {
|
|
||||||
send(message.isNotice() ? who : getChannel(), message.getMsg(), message.getColor(), message.isPrivate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message.
|
|
||||||
*
|
|
||||||
* @param who The channel or nick of the person who sent the command.
|
|
||||||
* @param message The actual message.
|
|
||||||
* @param color The message's color.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
*/
|
|
||||||
public final void send(final String who, final String message, final String color, final boolean isPrivate) {
|
|
||||||
send(who, Utils.colorize(message, color), isPrivate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a formatted commands/modules, etc. list.
|
|
||||||
*
|
|
||||||
* @param nick The nick to send the list to.
|
|
||||||
* @param list The list to format.
|
|
||||||
* @param size The number of items per line.
|
|
||||||
* @param isPrivate The private flag.
|
|
||||||
* @param isBold The bold flag
|
|
||||||
*/
|
|
||||||
public final void sendList(final String nick,
|
|
||||||
final List<String> list,
|
|
||||||
final int size,
|
|
||||||
final boolean isPrivate,
|
|
||||||
final boolean isBold) {
|
|
||||||
for (int i = 0; i < list.size(); i += size) {
|
|
||||||
send(nick, Utils.helpIndent(
|
|
||||||
String.join(" ", list.subList(i, Math.min(list.size(), i + size))), isBold), isPrivate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the backlogs URL.
|
|
||||||
*
|
|
||||||
* @param url The backlogs URL.
|
|
||||||
*/
|
|
||||||
final void setBacklogsUrl(final String url) {
|
|
||||||
backLogsUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the bot's identification.
|
|
||||||
*
|
|
||||||
* @param pwd The password for NickServ, if any.
|
|
||||||
* @param nick The ident nick name.
|
|
||||||
* @param msg The ident message.
|
|
||||||
*/
|
|
||||||
final void setIdentity(final String pwd, final String nick, final String msg) {
|
|
||||||
identPwd = pwd;
|
|
||||||
identNick = nick;
|
|
||||||
identMsg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the pinboard authentication.
|
|
||||||
*
|
|
||||||
* @param apiToken The API token
|
|
||||||
*/
|
|
||||||
final void setPinboardAuth(final String apiToken) {
|
|
||||||
if (isNotBlank(apiToken)) {
|
|
||||||
pinboard = new PinboardPoster(apiToken);
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
final ConsoleHandler consoleHandler = new ConsoleHandler();
|
|
||||||
consoleHandler.setLevel(java.util.logging.Level.FINE);
|
|
||||||
pinboard.getLogger().addHandler(consoleHandler);
|
|
||||||
pinboard.getLogger().setLevel(java.util.logging.Level.FINE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the weblog URL.
|
|
||||||
*
|
|
||||||
* @param url The weblog URL.
|
|
||||||
*/
|
|
||||||
final void setWeblogUrl(final String url) {
|
|
||||||
weblogUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sleeps for the specified number of seconds.
|
|
||||||
*
|
|
||||||
* @param secs The number of seconds to sleep for.
|
|
||||||
*/
|
|
||||||
public final void sleep(final int secs) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(secs * 1000L);
|
|
||||||
} catch (InterruptedException ignore) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates pin on pinboard.
|
|
||||||
*
|
|
||||||
* @param oldUrl The old pin url.
|
|
||||||
* @param entry The entry to update.
|
|
||||||
*/
|
|
||||||
public final void updatePin(final String oldUrl, final EntryLink entry) {
|
|
||||||
if (pinboard != null) {
|
|
||||||
PinboardUtils.updatePin(pinboard, ircServer, oldUrl, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
776
src/main/java/net/thauvin/erik/mobibot/Mobibot.kt
Normal file
776
src/main/java/net/thauvin/erik/mobibot/Mobibot.kt
Normal file
|
@ -0,0 +1,776 @@
|
||||||
|
/*
|
||||||
|
* Mobibot.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.PinboardUtils.addPin
|
||||||
|
import net.thauvin.erik.mobibot.PinboardUtils.deletePin
|
||||||
|
import net.thauvin.erik.mobibot.PinboardUtils.updatePin
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.colorize
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.ensureDir
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.getIntProperty
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.helpFormat
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.helpIndent
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.isoLocalDate
|
||||||
|
import net.thauvin.erik.mobibot.Utils.Companion.today
|
||||||
|
import net.thauvin.erik.mobibot.commands.AddLog
|
||||||
|
import net.thauvin.erik.mobibot.commands.ChannelFeed
|
||||||
|
import net.thauvin.erik.mobibot.commands.Cycle
|
||||||
|
import net.thauvin.erik.mobibot.commands.Ignore
|
||||||
|
import net.thauvin.erik.mobibot.commands.Info
|
||||||
|
import net.thauvin.erik.mobibot.commands.Me
|
||||||
|
import net.thauvin.erik.mobibot.commands.Modules
|
||||||
|
import net.thauvin.erik.mobibot.commands.Msg
|
||||||
|
import net.thauvin.erik.mobibot.commands.Nick
|
||||||
|
import net.thauvin.erik.mobibot.commands.Recap
|
||||||
|
import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap
|
||||||
|
import net.thauvin.erik.mobibot.commands.Say
|
||||||
|
import net.thauvin.erik.mobibot.commands.Users
|
||||||
|
import net.thauvin.erik.mobibot.commands.Versions
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.Comment
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.LinksMgr
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.saveEntries
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.startDate
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.startup
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.Posting
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.Tags
|
||||||
|
import net.thauvin.erik.mobibot.commands.links.View
|
||||||
|
import net.thauvin.erik.mobibot.commands.tell.Tell
|
||||||
|
import net.thauvin.erik.mobibot.entries.EntriesMgr
|
||||||
|
import net.thauvin.erik.mobibot.entries.EntryLink
|
||||||
|
import net.thauvin.erik.mobibot.modules.Calc
|
||||||
|
import net.thauvin.erik.mobibot.modules.CurrencyConverter
|
||||||
|
import net.thauvin.erik.mobibot.modules.Dice
|
||||||
|
import net.thauvin.erik.mobibot.modules.GoogleSearch
|
||||||
|
import net.thauvin.erik.mobibot.modules.Joke
|
||||||
|
import net.thauvin.erik.mobibot.modules.Lookup
|
||||||
|
import net.thauvin.erik.mobibot.modules.Ping
|
||||||
|
import net.thauvin.erik.mobibot.modules.RockPaperScissors
|
||||||
|
import net.thauvin.erik.mobibot.modules.StockQuote
|
||||||
|
import net.thauvin.erik.mobibot.modules.Twitter
|
||||||
|
import net.thauvin.erik.mobibot.modules.War
|
||||||
|
import net.thauvin.erik.mobibot.modules.Weather2
|
||||||
|
import net.thauvin.erik.mobibot.modules.WorldTime
|
||||||
|
import net.thauvin.erik.mobibot.msg.Message
|
||||||
|
import net.thauvin.erik.pinboard.PinboardPoster
|
||||||
|
import net.thauvin.erik.semver.Version
|
||||||
|
import org.apache.commons.cli.CommandLine
|
||||||
|
import org.apache.commons.cli.CommandLineParser
|
||||||
|
import org.apache.commons.cli.DefaultParser
|
||||||
|
import org.apache.commons.cli.HelpFormatter
|
||||||
|
import org.apache.commons.cli.Option
|
||||||
|
import org.apache.commons.cli.Options
|
||||||
|
import org.apache.commons.cli.ParseException
|
||||||
|
import org.apache.logging.log4j.Level
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.apache.logging.log4j.Logger
|
||||||
|
import org.apache.logging.log4j.core.config.Configurator
|
||||||
|
import org.jibble.pircbot.PircBot
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.lang.String.join
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.util.*
|
||||||
|
import java.util.logging.ConsoleHandler
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the #mobitopia bot.
|
||||||
|
*/
|
||||||
|
@Version(properties = "version.properties", className = "ReleaseInfo", template = "ReleaseInfo.mustache", type = "kt")
|
||||||
|
class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Properties) : PircBot() {
|
||||||
|
// Commands and Modules
|
||||||
|
private val addons = Addons()
|
||||||
|
|
||||||
|
/** Main channel. */
|
||||||
|
val channel: String
|
||||||
|
|
||||||
|
// IRC port
|
||||||
|
private val ircPort: Int
|
||||||
|
|
||||||
|
/** IRC server. */
|
||||||
|
val ircServer: String
|
||||||
|
|
||||||
|
/** Logger. */
|
||||||
|
val logger: Logger = LogManager.getLogger(Mobibot::class.java)
|
||||||
|
|
||||||
|
// Logger default level
|
||||||
|
private val loggerLevel: Level
|
||||||
|
|
||||||
|
/** Log directory. */
|
||||||
|
val logsDir: String
|
||||||
|
|
||||||
|
// Pinboard posts handler
|
||||||
|
private val pinboard: PinboardPoster = PinboardPoster()
|
||||||
|
|
||||||
|
/** Tell command. */
|
||||||
|
val tell: Tell
|
||||||
|
|
||||||
|
/** Today's date. */
|
||||||
|
val today = today()
|
||||||
|
|
||||||
|
/** Twitter module. */
|
||||||
|
val twitter: Twitter
|
||||||
|
|
||||||
|
/** The backlogs URL. */
|
||||||
|
var backlogsUrl = ""
|
||||||
|
|
||||||
|
// Ident message
|
||||||
|
private var identMsg = ""
|
||||||
|
|
||||||
|
// Ident nick
|
||||||
|
private var identNick = ""
|
||||||
|
|
||||||
|
// NickServ ident password
|
||||||
|
private var identPwd = ""
|
||||||
|
|
||||||
|
// Is pinboard enabled?
|
||||||
|
private var isPinboardEnabled = false
|
||||||
|
|
||||||
|
/** Timer. */
|
||||||
|
val timer = Timer(true)
|
||||||
|
|
||||||
|
/** Weblog URL */
|
||||||
|
var weblogUrl = ""
|
||||||
|
|
||||||
|
/** The current channel name. */
|
||||||
|
private val channelName: String
|
||||||
|
get() = channel.substring(1)
|
||||||
|
|
||||||
|
/** The enabled modules names. */
|
||||||
|
val modulesNames: List<String>
|
||||||
|
get() = addons.modulesNames
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an action to the current channel.
|
||||||
|
*/
|
||||||
|
fun action(action: String) {
|
||||||
|
action(channel, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an action to the channel.
|
||||||
|
*/
|
||||||
|
private fun action(channel: String, action: String) {
|
||||||
|
if (channel.isNotBlank() && action.isNotBlank()) {
|
||||||
|
sendAction(channel, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds pin on pinboard.
|
||||||
|
*/
|
||||||
|
fun addPin(entry: EntryLink) {
|
||||||
|
if (isPinboardEnabled) {
|
||||||
|
addPin(pinboard, ircServer, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the server and joins the channel.
|
||||||
|
*/
|
||||||
|
fun connect() {
|
||||||
|
try {
|
||||||
|
connect(ircServer, ircPort)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
var retries = 0
|
||||||
|
while (retries++ < MAX_RECONNECT && !isConnected) {
|
||||||
|
sleep(10)
|
||||||
|
try {
|
||||||
|
connect(ircServer, ircPort)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (retries == MAX_RECONNECT) {
|
||||||
|
logger.debug("Unable to reconnect to $ircServer, after $MAX_RECONNECT retries.", ex)
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
identify()
|
||||||
|
joinChannel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes pin on pinboard.
|
||||||
|
*/
|
||||||
|
fun deletePin(index: Int, entry: EntryLink) {
|
||||||
|
if (isPinboardEnabled) {
|
||||||
|
deletePin(pinboard, entry)
|
||||||
|
}
|
||||||
|
if (twitter.isAutoPost) {
|
||||||
|
twitter.removeEntry(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responds with the commands help, if any.
|
||||||
|
*/
|
||||||
|
private fun helpCommands(sender: String, topic: String, isPrivate: Boolean): Boolean {
|
||||||
|
for (command in addons.commands) {
|
||||||
|
if (command.isVisible && command.name.startsWith(topic)) {
|
||||||
|
return command.helpResponse(topic, sender, isOp(sender), isPrivate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responds with the default help.
|
||||||
|
*/
|
||||||
|
fun helpDefault(sender: String, isOp: Boolean, isPrivate: Boolean) {
|
||||||
|
send(sender, "Type a URL on $channel to post it.", isPrivate)
|
||||||
|
send(sender, "For more information on a specific command, type:", isPrivate)
|
||||||
|
send(
|
||||||
|
sender,
|
||||||
|
helpIndent(helpFormat("""%c ${Constants.HELP_CMD} <command>""", nick, isPrivate)),
|
||||||
|
isPrivate
|
||||||
|
)
|
||||||
|
send(sender, "The commands are:", isPrivate)
|
||||||
|
sendList(sender, addons.names, 8, isPrivate, true)
|
||||||
|
if (isOp) {
|
||||||
|
send(sender, "The op commands are:", isPrivate)
|
||||||
|
sendList(sender, addons.ops, 8, isPrivate, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responds with the modules help, if any.
|
||||||
|
*/
|
||||||
|
private fun helpModules(sender: String, topic: String, isPrivate: Boolean): Boolean {
|
||||||
|
for (module in addons.modules) {
|
||||||
|
for (cmd in module.commands) {
|
||||||
|
if (topic == cmd) {
|
||||||
|
module.helpResponse(sender, isPrivate)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responds with the default, commands or modules help.
|
||||||
|
*/
|
||||||
|
private fun helpResponse(sender: String, topic: String, isPrivate: Boolean) {
|
||||||
|
val isOp = isOp(sender)
|
||||||
|
if (topic.isBlank()) {
|
||||||
|
helpDefault(sender, isOp, isPrivate)
|
||||||
|
} else {
|
||||||
|
// Command, Modules or Default
|
||||||
|
if (!helpCommands(sender, topic, isPrivate) && !helpModules(
|
||||||
|
sender,
|
||||||
|
topic.toLowerCase().trim(),
|
||||||
|
isPrivate
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
helpDefault(sender, isOp, isPrivate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies the bot.
|
||||||
|
*/
|
||||||
|
private fun identify() {
|
||||||
|
// Identify with NickServ
|
||||||
|
if (identPwd.isNotBlank()) {
|
||||||
|
identify(identPwd)
|
||||||
|
}
|
||||||
|
// Identify with a specified nick
|
||||||
|
if (identNick.isNotBlank() && identMsg.isNotBlank()) {
|
||||||
|
sendMessage(identNick, identMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the specified sender is an Op on the [channel][.ircChannel].
|
||||||
|
*/
|
||||||
|
fun isOp(sender: String): Boolean {
|
||||||
|
for (user in getUsers(channel)) {
|
||||||
|
if (user.nick == sender) {
|
||||||
|
return user.isOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins the bot's channel.
|
||||||
|
*/
|
||||||
|
private fun joinChannel() {
|
||||||
|
joinChannel(channel)
|
||||||
|
twitter.notification("$name ${ReleaseInfo.VERSION} has joined $channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisconnect() {
|
||||||
|
if (weblogUrl.isNotBlank()) {
|
||||||
|
version = weblogUrl
|
||||||
|
}
|
||||||
|
sleep(5)
|
||||||
|
connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessage(
|
||||||
|
channel: String,
|
||||||
|
sender: String,
|
||||||
|
login: String,
|
||||||
|
hostname: String,
|
||||||
|
message: String
|
||||||
|
) {
|
||||||
|
logger.debug(">>> $sender: $message")
|
||||||
|
tell.send(sender, true)
|
||||||
|
if (message.matches("(?i)${Pattern.quote(nick)}:.*".toRegex())) { // mobibot: <command>
|
||||||
|
val cmds = message.substring(message.indexOf(':') + 1).trim().split(" ".toRegex(), 2).toTypedArray()
|
||||||
|
val cmd = cmds[0].toLowerCase()
|
||||||
|
val args = if (cmds.size > 1) {
|
||||||
|
cmds[1].trim()
|
||||||
|
} else ""
|
||||||
|
if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help
|
||||||
|
helpResponse(sender, args, false)
|
||||||
|
} else {
|
||||||
|
// Commands
|
||||||
|
for (command in addons.commands) {
|
||||||
|
if (command.isPublic && command.name.startsWith(cmd)) {
|
||||||
|
command.commandResponse(sender, login, args, isOp(sender), false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Modules
|
||||||
|
for (module in addons.modules) { // modules
|
||||||
|
for (c in module.commands) {
|
||||||
|
if (cmd.startsWith(c)) {
|
||||||
|
module.commandResponse(sender, cmd, args, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Commands, e.g.: https://www.example.com/
|
||||||
|
for (command in addons.commands) {
|
||||||
|
if (command.matches(message)) {
|
||||||
|
command.commandResponse(sender, login, message, isOp(sender), false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storeRecap(sender, message, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrivateMessage(
|
||||||
|
sender: String,
|
||||||
|
login: String,
|
||||||
|
hostname: String,
|
||||||
|
message: String
|
||||||
|
) {
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
logger.debug(">>> $sender : $message")
|
||||||
|
}
|
||||||
|
val cmds = message.split(" ".toRegex(), 2).toTypedArray()
|
||||||
|
val cmd = cmds[0].toLowerCase()
|
||||||
|
val args = if (cmds.size > 1) {
|
||||||
|
cmds[1].trim()
|
||||||
|
} else ""
|
||||||
|
val isOp = isOp(sender)
|
||||||
|
if (cmd.startsWith(Constants.HELP_CMD)) { // help
|
||||||
|
helpResponse(sender, args, true)
|
||||||
|
} else if (isOp && "kill" == cmd) { // kill
|
||||||
|
twitter.notification("$name killed by $sender on $channel")
|
||||||
|
sendRawLine("QUIT : Poof!")
|
||||||
|
exitProcess(0)
|
||||||
|
} else if (isOp && Constants.DEBUG_CMD == cmd) { // debug
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
Configurator.setLevel(logger.name, loggerLevel)
|
||||||
|
} else {
|
||||||
|
Configurator.setLevel(logger.name, Level.DEBUG)
|
||||||
|
}
|
||||||
|
send(sender, "Debug logging is " + if (logger.isDebugEnabled) "enabled." else "disabled.", true)
|
||||||
|
} else if (isOp && Constants.DIE_CMD == cmd) { // die
|
||||||
|
send("$sender has just signed my death sentence.")
|
||||||
|
timer.cancel()
|
||||||
|
twitter.shutdown()
|
||||||
|
twitter.notification("$name stopped by $sender on $channel")
|
||||||
|
sleep(3)
|
||||||
|
quitServer("The Bot Is Out There!")
|
||||||
|
exitProcess(0)
|
||||||
|
} else {
|
||||||
|
for (command in addons.commands) {
|
||||||
|
if (command.name.startsWith(cmd)) {
|
||||||
|
command.commandResponse(sender, login, args, isOp, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (module in addons.modules) {
|
||||||
|
if (module.isPrivateMsgEnabled) {
|
||||||
|
for (c in module.commands) {
|
||||||
|
if (cmd == c) {
|
||||||
|
module.commandResponse(sender, cmd, args, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helpDefault(sender, isOp, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAction(sender: String, login: String, hostname: String, target: String, action: String) {
|
||||||
|
if (channel == target) {
|
||||||
|
storeRecap(sender, action, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJoin(channel: String, sender: String, login: String, hostname: String) {
|
||||||
|
tell.send(sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNickChange(oldNick: String, login: String, hostname: String, newNick: String) {
|
||||||
|
tell.send(newNick)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a private message or notice.
|
||||||
|
*/
|
||||||
|
fun send(sender: String, message: String?, isPrivate: Boolean) {
|
||||||
|
if (message != null && sender.isNotBlank()) {
|
||||||
|
if (isPrivate) {
|
||||||
|
logger.debug("Sending message to $sender : $message")
|
||||||
|
sendMessage(sender, message)
|
||||||
|
} else {
|
||||||
|
logger.debug("Sending notice to $sender: $message")
|
||||||
|
sendNotice(sender, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a notice to the channel.
|
||||||
|
*/
|
||||||
|
fun send(notice: String?) {
|
||||||
|
if (notice != null) send(channel, notice, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message.
|
||||||
|
*/
|
||||||
|
fun send(who: String, message: Message) {
|
||||||
|
send(if (message.isNotice) who else channel, message.msg, message.color, message.isPrivate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message.
|
||||||
|
*/
|
||||||
|
fun send(who: String, message: String, color: String, isPrivate: Boolean) {
|
||||||
|
send(who, colorize(message, color), isPrivate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a formatted commands/modules, etc. list.
|
||||||
|
*/
|
||||||
|
fun sendList(
|
||||||
|
nick: String,
|
||||||
|
list: List<String>,
|
||||||
|
size: Int,
|
||||||
|
isPrivate: Boolean,
|
||||||
|
isBold: Boolean
|
||||||
|
) {
|
||||||
|
var i = 0
|
||||||
|
while (i < list.size) {
|
||||||
|
send(
|
||||||
|
nick,
|
||||||
|
helpIndent(join(" ", list.subList(i, list.size.coerceAtMost(i + size))), isBold),
|
||||||
|
isPrivate
|
||||||
|
)
|
||||||
|
i += size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the bot's identification.
|
||||||
|
*/
|
||||||
|
private fun setIdentity(pwd: String, nick: String, msg: String) {
|
||||||
|
identPwd = pwd
|
||||||
|
identNick = nick
|
||||||
|
identMsg = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pinboard authentication.
|
||||||
|
*/
|
||||||
|
private fun setPinboardAuth(apiToken: String) {
|
||||||
|
if (apiToken.isNotBlank()) {
|
||||||
|
pinboard.apiToken = apiToken
|
||||||
|
isPinboardEnabled = true
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
val consoleHandler = ConsoleHandler()
|
||||||
|
consoleHandler.level = java.util.logging.Level.FINE
|
||||||
|
pinboard.logger.addHandler(consoleHandler)
|
||||||
|
pinboard.logger.level = java.util.logging.Level.FINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleeps for the specified number of seconds.
|
||||||
|
*/
|
||||||
|
fun sleep(secs: Int) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(secs * 1000L)
|
||||||
|
} catch (ignore: InterruptedException) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates pin on pinboard.
|
||||||
|
*/
|
||||||
|
fun updatePin(oldUrl: String, entry: EntryLink) {
|
||||||
|
if (isPinboardEnabled) {
|
||||||
|
updatePin(pinboard, ircServer, oldUrl, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Maximum number of times the bot will try to reconnect, if disconnected
|
||||||
|
private const val MAX_RECONNECT = 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Truth is Out There!
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
// Setup the command line options
|
||||||
|
val options = Options()
|
||||||
|
.addOption(
|
||||||
|
Constants.HELP_ARG.substring(0, 1),
|
||||||
|
Constants.HELP_ARG,
|
||||||
|
false,
|
||||||
|
"print this help message"
|
||||||
|
)
|
||||||
|
.addOption(
|
||||||
|
Constants.DEBUG_ARG.substring(0, 1), Constants.DEBUG_ARG, false,
|
||||||
|
"print debug & logging data directly to the console"
|
||||||
|
)
|
||||||
|
.addOption(
|
||||||
|
Option.builder(Constants.PROPS_ARG.substring(0, 1)).hasArg()
|
||||||
|
.argName("file")
|
||||||
|
.desc("use " + "alternate properties file")
|
||||||
|
.longOpt(Constants.PROPS_ARG).build()
|
||||||
|
)
|
||||||
|
.addOption(
|
||||||
|
Constants.VERSION_ARG.substring(0, 1),
|
||||||
|
Constants.VERSION_ARG,
|
||||||
|
false,
|
||||||
|
"print version info"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse the command line
|
||||||
|
val parser: CommandLineParser = DefaultParser()
|
||||||
|
val commandLine: CommandLine
|
||||||
|
try {
|
||||||
|
commandLine = parser.parse(options, args)
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
System.err.println("CLI Parsing failed. Reason: ${e.message}")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
commandLine.hasOption(Constants.HELP_ARG[0]) -> {
|
||||||
|
// Output the usage
|
||||||
|
HelpFormatter().printHelp(Mobibot::class.java.name, options)
|
||||||
|
}
|
||||||
|
commandLine.hasOption(Constants.VERSION_ARG[0]) -> {
|
||||||
|
println("${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION} (${isoLocalDate(ReleaseInfo.BUILDDATE)})")
|
||||||
|
println(ReleaseInfo.WEBSITE)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val p = Properties()
|
||||||
|
try {
|
||||||
|
Files.newInputStream(
|
||||||
|
Paths.get(commandLine.getOptionValue(Constants.PROPS_ARG[0], "./mobibot.properties"))
|
||||||
|
).use { fis ->
|
||||||
|
// Load the properties files
|
||||||
|
p.load(fis)
|
||||||
|
}
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
System.err.println("Unable to find properties file.")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
System.err.println("Unable to open properties file.")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
val nickname = p.getProperty("nick", Mobibot::class.java.name.toLowerCase())
|
||||||
|
val channel = p.getProperty("channel")
|
||||||
|
val logsDir = ensureDir(p.getProperty("logs", "."), false)
|
||||||
|
|
||||||
|
// Redirect the stdout and stderr
|
||||||
|
if (!commandLine.hasOption(Constants.DEBUG_ARG[0])) {
|
||||||
|
try {
|
||||||
|
val stdout = PrintStream(
|
||||||
|
BufferedOutputStream(
|
||||||
|
FileOutputStream(
|
||||||
|
logsDir + channel.substring(1) + '.' + today() + ".log", true
|
||||||
|
)
|
||||||
|
), true
|
||||||
|
)
|
||||||
|
System.setOut(stdout)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
System.err.println("Unable to open output (stdout) log file.")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val stderr = PrintStream(
|
||||||
|
BufferedOutputStream(
|
||||||
|
FileOutputStream("$logsDir$nickname.err", true)
|
||||||
|
), true
|
||||||
|
)
|
||||||
|
System.setErr(stderr)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
System.err.println("Unable to open error (stderr) log file.")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the bot
|
||||||
|
val bot = Mobibot(nickname, channel, logsDir, p)
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
bot.connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the bot.
|
||||||
|
*/
|
||||||
|
init {
|
||||||
|
System.getProperties().setProperty(
|
||||||
|
"sun.net.client.defaultConnectTimeout",
|
||||||
|
java.lang.String.valueOf(Constants.CONNECT_TIMEOUT)
|
||||||
|
)
|
||||||
|
System.getProperties().setProperty(
|
||||||
|
"sun.net.client.defaultReadTimeout",
|
||||||
|
java.lang.String.valueOf(Constants.CONNECT_TIMEOUT)
|
||||||
|
)
|
||||||
|
name = nickname
|
||||||
|
ircServer = p.getProperty("server", Constants.DEFAULT_SERVER)
|
||||||
|
ircPort = getIntProperty(p.getProperty("port"), Constants.DEFAULT_PORT)
|
||||||
|
this.channel = channel
|
||||||
|
logsDir = logsDirPath
|
||||||
|
|
||||||
|
// Set the logger level
|
||||||
|
loggerLevel = logger.level
|
||||||
|
|
||||||
|
// Load the current entries and backlogs, if any
|
||||||
|
try {
|
||||||
|
startup(logsDir + EntriesMgr.CURRENT_XML, logsDir + EntriesMgr.NAV_XML, this.channel)
|
||||||
|
logger.debug("Last feed: $startDate")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("An error occurred while loading the logs.", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the bot
|
||||||
|
setVerbose(true)
|
||||||
|
setAutoNickChange(true)
|
||||||
|
login = p.getProperty("login", name)
|
||||||
|
version = ReleaseInfo.PROJECT + ' ' + ReleaseInfo.VERSION
|
||||||
|
// setMessageDelay(1000);
|
||||||
|
setIdentity(p.getProperty("ident", ""), p.getProperty("ident-nick", ""), p.getProperty("ident-msg", ""))
|
||||||
|
|
||||||
|
// Set the URLs
|
||||||
|
weblogUrl = p.getProperty("weblog", "")
|
||||||
|
backlogsUrl = ensureDir(p.getProperty("backlogs", weblogUrl), true)
|
||||||
|
|
||||||
|
// Set the pinboard authentication
|
||||||
|
setPinboardAuth(p.getProperty("pinboard-api-token"))
|
||||||
|
|
||||||
|
// Load the commands
|
||||||
|
addons.add(AddLog(this), p)
|
||||||
|
addons.add(ChannelFeed(this, channelName), p)
|
||||||
|
addons.add(Cycle(this), p)
|
||||||
|
addons.add(Ignore(this), p)
|
||||||
|
addons.add(Info(this), p)
|
||||||
|
addons.add(Me(this), p)
|
||||||
|
addons.add(Modules(this), p)
|
||||||
|
addons.add(Msg(this), p)
|
||||||
|
addons.add(Nick(this), p)
|
||||||
|
addons.add(Recap(this), p)
|
||||||
|
addons.add(Say(this), p)
|
||||||
|
addons.add(Users(this), p)
|
||||||
|
addons.add(Versions(this), p)
|
||||||
|
|
||||||
|
// Tell command
|
||||||
|
tell = Tell(this)
|
||||||
|
addons.add(tell, p)
|
||||||
|
|
||||||
|
// Load the links commands
|
||||||
|
addons.add(Comment(this), p)
|
||||||
|
addons.add(Posting(this), p)
|
||||||
|
addons.add(Tags(this), p)
|
||||||
|
addons.add(LinksMgr(this), p)
|
||||||
|
addons.add(View(this), p)
|
||||||
|
|
||||||
|
// Load the modules
|
||||||
|
addons.add(Calc(this), p)
|
||||||
|
addons.add(CurrencyConverter(this), p)
|
||||||
|
addons.add(Dice(this), p)
|
||||||
|
addons.add(GoogleSearch(this), p)
|
||||||
|
addons.add(Joke(this), p)
|
||||||
|
addons.add(Lookup(this), p)
|
||||||
|
addons.add(Ping(this), p)
|
||||||
|
addons.add(RockPaperScissors(this), p)
|
||||||
|
addons.add(StockQuote(this), p)
|
||||||
|
addons.add(War(this), p)
|
||||||
|
addons.add(Weather2(this), p)
|
||||||
|
addons.add(WorldTime(this), p)
|
||||||
|
|
||||||
|
// Twitter module
|
||||||
|
twitter = Twitter(this)
|
||||||
|
addons.add(twitter, p)
|
||||||
|
|
||||||
|
// Sort the addons
|
||||||
|
addons.sort()
|
||||||
|
|
||||||
|
// Save the entries
|
||||||
|
saveEntries(this, true)
|
||||||
|
}
|
||||||
|
}
|
|
@ -134,7 +134,7 @@ class Posting(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeEntry(sender: String, login: String, isOp: Boolean, index: Int) {
|
private fun removeEntry(sender: String, login: String, isOp: Boolean, index: Int) {
|
||||||
val entry: EntryLink = LinksMgr.entries[index]
|
val entry: EntryLink = entries[index]
|
||||||
if (entry.login == login || isOp) {
|
if (entry.login == login || isOp) {
|
||||||
bot.deletePin(index, entry)
|
bot.deletePin(index, entry)
|
||||||
entries.removeAt(index)
|
entries.removeAt(index)
|
||||||
|
|
|
@ -41,7 +41,6 @@ import net.thauvin.erik.mobibot.Utils.Companion.reverseColor
|
||||||
import net.thauvin.erik.mobibot.Utils.Companion.utcDateTime
|
import net.thauvin.erik.mobibot.Utils.Companion.utcDateTime
|
||||||
import net.thauvin.erik.mobibot.commands.AbstractCommand
|
import net.thauvin.erik.mobibot.commands.AbstractCommand
|
||||||
import net.thauvin.erik.mobibot.commands.links.View
|
import net.thauvin.erik.mobibot.commands.links.View
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,7 +142,7 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
isPrivate: Boolean
|
isPrivate: Boolean
|
||||||
) {
|
) {
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
if (StringUtils.isBlank(args)) {
|
if (args.isBlank()) {
|
||||||
helpResponse(args, sender, isOp, isPrivate)
|
helpResponse(args, sender, isOp, isPrivate)
|
||||||
} else if (args.startsWith(View.VIEW_CMD)) {
|
} else if (args.startsWith(View.VIEW_CMD)) {
|
||||||
if (bot.isOp(sender) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
|
if (bot.isOp(sender) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
|
||||||
|
@ -178,12 +177,13 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
// New message.
|
// New message.
|
||||||
private fun newMessage(sender: String, args: String, isOp: Boolean, isPrivate: Boolean) {
|
private fun newMessage(sender: String, args: String, isOp: Boolean, isPrivate: Boolean) {
|
||||||
val split = args.split(" ".toRegex(), 2).toTypedArray()
|
val split = args.split(" ".toRegex(), 2).toTypedArray()
|
||||||
if (split.size == 2 && StringUtils.isNotBlank(split[1]) && split[1].contains(" ")) {
|
if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) {
|
||||||
if (messages.size < maxSize) {
|
if (messages.size < maxSize) {
|
||||||
val message = TellMessage(sender, split[0], split[1].trim())
|
val message = TellMessage(sender, split[0], split[1].trim())
|
||||||
messages.add(message)
|
messages.add(message)
|
||||||
save()
|
save()
|
||||||
bot.send(sender, "Message [ID ${message.id}] was queued for ${bold(message.recipient)}", isPrivate
|
bot.send(
|
||||||
|
sender, "Message [ID ${message.id}] was queued for ${bold(message.recipient)}", isPrivate
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
bot.send(sender, "Sorry, the messages queue is currently full.", isPrivate)
|
bot.send(sender, "Sorry, the messages queue is currently full.", isPrivate)
|
||||||
|
|
|
@ -74,12 +74,12 @@ class TellMessage internal constructor(
|
||||||
* Returns {@code true) if the message was received.
|
* Returns {@code true) if the message was received.
|
||||||
*/
|
*/
|
||||||
var isReceived = false
|
var isReceived = false
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
receptionDate = LocalDateTime.now(Clock.systemUTC())
|
receptionDate = LocalDateTime.now(Clock.systemUTC())
|
||||||
}
|
}
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the message creating date.
|
* Return the message creating date.
|
||||||
|
|
|
@ -32,18 +32,17 @@
|
||||||
package net.thauvin.erik.mobibot.commands.tell
|
package net.thauvin.erik.mobibot.commands.tell
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger
|
import org.apache.logging.log4j.Logger
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.io.ObjectInputStream
|
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.ClassNotFoundException
|
import java.io.ObjectInputStream
|
||||||
import java.io.BufferedOutputStream
|
|
||||||
import java.io.ObjectOutputStream
|
import java.io.ObjectOutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
import java.util.ArrayList
|
import java.time.LocalDateTime
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Tell Messages Manager.
|
* The Tell Messages Manager.
|
||||||
|
|
|
@ -41,7 +41,6 @@ import com.rometools.rome.io.SyndFeedInput
|
||||||
import com.rometools.rome.io.SyndFeedOutput
|
import com.rometools.rome.io.SyndFeedOutput
|
||||||
import net.thauvin.erik.mobibot.Mobibot
|
import net.thauvin.erik.mobibot.Mobibot
|
||||||
import net.thauvin.erik.mobibot.Utils.Companion.isoLocalDate
|
import net.thauvin.erik.mobibot.Utils.Companion.isoLocalDate
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.io.OutputStreamWriter
|
import java.io.OutputStreamWriter
|
||||||
|
@ -143,7 +142,7 @@ class EntriesMgr private constructor() {
|
||||||
if (bot.logger.isDebugEnabled) {
|
if (bot.logger.isDebugEnabled) {
|
||||||
bot.logger.debug("Saving the feeds...")
|
bot.logger.debug("Saving the feeds...")
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(bot.logsDir) && StringUtils.isNotBlank(bot.weblogUrl)) {
|
if (bot.logsDir.isNotBlank() && bot.weblogUrl.isNotBlank()) {
|
||||||
try {
|
try {
|
||||||
val output = SyndFeedOutput()
|
val output = SyndFeedOutput()
|
||||||
var rss: SyndFeed = SyndFeedImpl()
|
var rss: SyndFeed = SyndFeedImpl()
|
||||||
|
@ -208,7 +207,7 @@ class EntriesMgr private constructor() {
|
||||||
), StandardCharsets.UTF_8
|
), StandardCharsets.UTF_8
|
||||||
).use { fw -> output.output(rss, fw) }
|
).use { fw -> output.output(rss, fw) }
|
||||||
if (isDayBackup) {
|
if (isDayBackup) {
|
||||||
if (StringUtils.isNotBlank(bot.backlogsUrl)) {
|
if (bot.backlogsUrl.isNotBlank()) {
|
||||||
if (!history.contains(bot.today)) {
|
if (!history.contains(bot.today)) {
|
||||||
history.add(bot.today)
|
history.add(bot.today)
|
||||||
while (history.size > MAX_BACKLOGS) {
|
while (history.size > MAX_BACKLOGS) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ class EntryLink : Serializable {
|
||||||
var channel: String
|
var channel: String
|
||||||
|
|
||||||
// Creation date
|
// Creation date
|
||||||
var date = Calendar.getInstance().time
|
var date: Date = Calendar.getInstance().time
|
||||||
|
|
||||||
// Link's URL
|
// Link's URL
|
||||||
var link: String
|
var link: String
|
||||||
|
@ -178,12 +178,12 @@ class EntryLink : Serializable {
|
||||||
/**
|
/**
|
||||||
* Sets the tags.
|
* Sets the tags.
|
||||||
*/
|
*/
|
||||||
fun setTags(tags: List<String?>) {
|
private fun setTags(tags: List<String?>) {
|
||||||
if (!tags.isEmpty()) {
|
if (tags.isNotEmpty()) {
|
||||||
var category: SyndCategoryImpl
|
var category: SyndCategoryImpl
|
||||||
for (tag in tags) {
|
for (tag in tags) {
|
||||||
if (StringUtils.isNoneBlank(tag)) {
|
if (!tag.isNullOrBlank()) {
|
||||||
val t = StringUtils.lowerCase(tag)
|
val t = tag.toLowerCase()
|
||||||
val mod = t[0]
|
val mod = t[0]
|
||||||
if (mod == '-') {
|
if (mod == '-') {
|
||||||
// Don't remove the channel tag
|
// Don't remove the channel tag
|
||||||
|
|
|
@ -33,7 +33,6 @@ package net.thauvin.erik.mobibot.modules
|
||||||
|
|
||||||
import net.thauvin.erik.mobibot.Mobibot
|
import net.thauvin.erik.mobibot.Mobibot
|
||||||
import net.thauvin.erik.mobibot.Utils
|
import net.thauvin.erik.mobibot.Utils
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
@ -113,7 +112,7 @@ abstract class AbstractModule(val bot: Mobibot) {
|
||||||
open val isValidProperties: Boolean
|
open val isValidProperties: Boolean
|
||||||
get() {
|
get() {
|
||||||
for (s in propertyKeys) {
|
for (s in propertyKeys) {
|
||||||
if (StringUtils.isBlank(properties[s])) {
|
if (properties[s].isNullOrBlank()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +123,7 @@ abstract class AbstractModule(val bot: Mobibot) {
|
||||||
* Sets a property key and value.
|
* Sets a property key and value.
|
||||||
*/
|
*/
|
||||||
fun setProperty(key: String, value: String) {
|
fun setProperty(key: String, value: String) {
|
||||||
if (StringUtils.isNotBlank(key)) {
|
if (key.isNotBlank()) {
|
||||||
properties[key] = value
|
properties[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ package net.thauvin.erik.mobibot.modules
|
||||||
import net.objecthunter.exp4j.ExpressionBuilder
|
import net.objecthunter.exp4j.ExpressionBuilder
|
||||||
import net.thauvin.erik.mobibot.Mobibot
|
import net.thauvin.erik.mobibot.Mobibot
|
||||||
import net.thauvin.erik.mobibot.Utils
|
import net.thauvin.erik.mobibot.Utils
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +46,7 @@ class Calc(bot: Mobibot) : AbstractModule(bot) {
|
||||||
args: String,
|
args: String,
|
||||||
isPrivate: Boolean
|
isPrivate: Boolean
|
||||||
) {
|
) {
|
||||||
if (StringUtils.isNotBlank(args)) {
|
if (args.isNotBlank()) {
|
||||||
bot.send(calc(args))
|
bot.send(calc(args))
|
||||||
} else {
|
} else {
|
||||||
helpResponse(sender, isPrivate)
|
helpResponse(sender, isPrivate)
|
||||||
|
|
|
@ -157,8 +157,8 @@ class CurrencyConverter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
if (cmds[3] == cmds[1] || "0" == cmds[0]) {
|
if (cmds[3] == cmds[1] || "0" == cmds[0]) {
|
||||||
PublicMessage("You're kidding, right?")
|
PublicMessage("You're kidding, right?")
|
||||||
} else {
|
} else {
|
||||||
val to = StringUtils.upperCase(cmds[1])
|
val to = cmds[1].toUpperCase()
|
||||||
val from = StringUtils.upperCase(cmds[3])
|
val from = cmds[3].toUpperCase()
|
||||||
if (EXCHANGE_RATES.containsKey(to) && EXCHANGE_RATES.containsKey(from)) {
|
if (EXCHANGE_RATES.containsKey(to) && EXCHANGE_RATES.containsKey(from)) {
|
||||||
try {
|
try {
|
||||||
val amt = cmds[0].replace(",", "").toDouble()
|
val amt = cmds[0].replace(",", "").toDouble()
|
||||||
|
@ -166,10 +166,10 @@ class CurrencyConverter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
val doubleTo = EXCHANGE_RATES[from]!!.toDouble()
|
val doubleTo = EXCHANGE_RATES[from]!!.toDouble()
|
||||||
PublicMessage(
|
PublicMessage(
|
||||||
NumberFormat.getCurrencyInstance(Constants.LOCALE).format(amt).substring(1)
|
NumberFormat.getCurrencyInstance(Constants.LOCALE).format(amt).substring(1)
|
||||||
+ " ${StringUtils.upperCase(cmds[1])} = "
|
+ " ${cmds[1].toUpperCase()} = "
|
||||||
+ NumberFormat.getCurrencyInstance(Constants.LOCALE)
|
+ NumberFormat.getCurrencyInstance(Constants.LOCALE)
|
||||||
.format(amt * doubleTo / doubleFrom).substring(1)
|
.format(amt * doubleTo / doubleFrom).substring(1)
|
||||||
+ " ${StringUtils.upperCase(cmds[3])}"
|
+ " ${cmds[3].toUpperCase()}"
|
||||||
)
|
)
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
ErrorMessage("Let's try with some real numbers next time, okay?")
|
ErrorMessage("Let's try with some real numbers next time, okay?")
|
||||||
|
|
|
@ -52,7 +52,7 @@ class GoogleSearch(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
*/
|
*/
|
||||||
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
||||||
with(bot) {
|
with(bot) {
|
||||||
if (StringUtils.isNotBlank(args)) {
|
if (args.isNotBlank()) {
|
||||||
try {
|
try {
|
||||||
val results = searchGoogle(
|
val results = searchGoogle(
|
||||||
args, properties[GOOGLE_API_KEY_PROP],
|
args, properties[GOOGLE_API_KEY_PROP],
|
||||||
|
|
|
@ -56,11 +56,13 @@ class Joke(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
/**
|
/**
|
||||||
* Returns a random joke from [The Internet Chuck Norris Database](http://www.icndb.com/).
|
* Returns a random joke from [The Internet Chuck Norris Database](http://www.icndb.com/).
|
||||||
*/
|
*/
|
||||||
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) = try {
|
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
||||||
bot.send(Utils.cyan(randomJoke().msg))
|
try {
|
||||||
} catch (e: ModuleException) {
|
bot.send(Utils.cyan(randomJoke().msg))
|
||||||
bot.logger.warn(e.debugMessage, e)
|
} catch (e: ModuleException) {
|
||||||
bot.send(sender, e.message, isPrivate)
|
bot.logger.warn(e.debugMessage, e)
|
||||||
|
bot.send(sender, e.message, isPrivate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -37,7 +37,6 @@ import net.thauvin.erik.mobibot.msg.ErrorMessage
|
||||||
import net.thauvin.erik.mobibot.msg.Message
|
import net.thauvin.erik.mobibot.msg.Message
|
||||||
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
||||||
import net.thauvin.erik.mobibot.msg.PublicMessage
|
import net.thauvin.erik.mobibot.msg.PublicMessage
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
@ -53,7 +52,7 @@ class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
*/
|
*/
|
||||||
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
||||||
with(bot) {
|
with(bot) {
|
||||||
if (StringUtils.isNotBlank(args)) {
|
if (args.isNotBlank()) {
|
||||||
try {
|
try {
|
||||||
val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP])
|
val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP])
|
||||||
for (msg in messages) {
|
for (msg in messages) {
|
||||||
|
@ -88,7 +87,7 @@ class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
|
|
||||||
@Throws(ModuleException::class)
|
@Throws(ModuleException::class)
|
||||||
private fun getJsonResponse(response: String, debugMessage: String): JSONObject {
|
private fun getJsonResponse(response: String, debugMessage: String): JSONObject {
|
||||||
return if (StringUtils.isNotBlank(response)) {
|
return if (response.isNotBlank()) {
|
||||||
val json = JSONObject(response)
|
val json = JSONObject(response)
|
||||||
try {
|
try {
|
||||||
val info = json.getString("Information")
|
val info = json.getString("Information")
|
||||||
|
|
|
@ -39,7 +39,6 @@ import net.thauvin.erik.mobibot.commands.links.LinksMgr
|
||||||
import net.thauvin.erik.mobibot.entries.EntriesUtils
|
import net.thauvin.erik.mobibot.entries.EntriesUtils
|
||||||
import net.thauvin.erik.mobibot.msg.Message
|
import net.thauvin.erik.mobibot.msg.Message
|
||||||
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import twitter4j.TwitterException
|
import twitter4j.TwitterException
|
||||||
import twitter4j.TwitterFactory
|
import twitter4j.TwitterFactory
|
||||||
import twitter4j.conf.ConfigurationBuilder
|
import twitter4j.conf.ConfigurationBuilder
|
||||||
|
@ -88,7 +87,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
*/
|
*/
|
||||||
fun notification(msg: String) {
|
fun notification(msg: String) {
|
||||||
with(bot) {
|
with(bot) {
|
||||||
if (isEnabled && StringUtils.isNotBlank(handle)) {
|
if (isEnabled && !handle.isNullOrBlank()) {
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
post(message = msg, isDm = true)
|
post(message = msg, isDm = true)
|
||||||
|
|
|
@ -41,7 +41,6 @@ import net.thauvin.erik.mobibot.msg.ErrorMessage
|
||||||
import net.thauvin.erik.mobibot.msg.Message
|
import net.thauvin.erik.mobibot.msg.Message
|
||||||
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
||||||
import net.thauvin.erik.mobibot.msg.PublicMessage
|
import net.thauvin.erik.mobibot.msg.PublicMessage
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import org.jibble.pircbot.Colors
|
import org.jibble.pircbot.Colors
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
@ -54,7 +53,7 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
* Fetches the weather data from a specific city.
|
* Fetches the weather data from a specific city.
|
||||||
*/
|
*/
|
||||||
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
|
||||||
if (StringUtils.isNotBlank(args)) {
|
if (args.isNotBlank()) {
|
||||||
try {
|
try {
|
||||||
val messages = getWeather(args, properties[OWM_API_KEY_PROP])
|
val messages = getWeather(args, properties[OWM_API_KEY_PROP])
|
||||||
if (messages[0].isError) {
|
if (messages[0].isError) {
|
||||||
|
|
|
@ -190,7 +190,7 @@ class WorldTime(bot: Mobibot) : AbstractModule(bot) {
|
||||||
with(bot) {
|
with(bot) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
send(sender, "The supported countries/zones are: ", isPrivate)
|
send(sender, "The supported countries/zones are: ", isPrivate)
|
||||||
sendList(sender, ArrayList(COUNTRIES_MAP.keys), 17, false, false)
|
sendList(sender, ArrayList(COUNTRIES_MAP.keys), 17, isPrivate = false, isBold = false)
|
||||||
} else {
|
} else {
|
||||||
val msg = worldTime(args)
|
val msg = worldTime(args)
|
||||||
if (isPrivate) {
|
if (isPrivate) {
|
||||||
|
|
|
@ -31,11 +31,11 @@
|
||||||
*/
|
*/
|
||||||
package net.thauvin.erik.mobibot.commands.tell
|
package net.thauvin.erik.mobibot.commands.tell
|
||||||
|
|
||||||
import java.time.temporal.Temporal
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import org.assertj.core.api.Assertions
|
import org.assertj.core.api.Assertions
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.temporal.Temporal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `TellMessageTest` class.
|
* The `TellMessageTest` class.
|
||||||
|
|
|
@ -62,7 +62,7 @@ class GoogleSearchTest : LocalProperties() {
|
||||||
.`as`("no query").isInstanceOf(ModuleException::class.java).hasNoCause()
|
.`as`("no query").isInstanceOf(ModuleException::class.java).hasNoCause()
|
||||||
} catch (e: ModuleException) {
|
} catch (e: ModuleException) {
|
||||||
// Avoid displaying api keys in CI logs
|
// Avoid displaying api keys in CI logs
|
||||||
if ("true" == System.getenv("CI") && !apiKey.isNullOrBlank() && !cseKey.isNullOrBlank()) {
|
if ("true" == System.getenv("CI") && !apiKey.isBlank() && !cseKey.isBlank()) {
|
||||||
throw ModuleException(e.debugMessage, e.getSanitizedMessage(apiKey, cseKey))
|
throw ModuleException(e.debugMessage, e.getSanitizedMessage(apiKey, cseKey))
|
||||||
} else {
|
} else {
|
||||||
throw e
|
throw e
|
||||||
|
|
|
@ -63,7 +63,7 @@ class StockQuoteTest : LocalProperties() {
|
||||||
.isInstanceOf(ModuleException::class.java).hasNoCause()
|
.isInstanceOf(ModuleException::class.java).hasNoCause()
|
||||||
} catch (e: ModuleException) {
|
} catch (e: ModuleException) {
|
||||||
// Avoid displaying api keys in CI logs
|
// Avoid displaying api keys in CI logs
|
||||||
if ("true" == System.getenv("CI") && !apiKey.isNullOrBlank()) {
|
if ("true" == System.getenv("CI") && !apiKey.isBlank()) {
|
||||||
throw ModuleException(e.debugMessage, e.getSanitizedMessage(apiKey))
|
throw ModuleException(e.debugMessage, e.getSanitizedMessage(apiKey))
|
||||||
} else {
|
} else {
|
||||||
throw e
|
throw e
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#Generated by the Semver Plugin for Gradle
|
#Generated by the Semver Plugin for Gradle
|
||||||
#Fri Dec 04 15:43:01 PST 2020
|
#Fri Dec 04 22:59:43 PST 2020
|
||||||
version.buildmeta=312
|
version.buildmeta=337
|
||||||
version.major=0
|
version.major=0
|
||||||
version.minor=8
|
version.minor=8
|
||||||
version.patch=0
|
version.patch=0
|
||||||
version.prerelease=beta
|
version.prerelease=beta
|
||||||
version.project=mobibot
|
version.project=mobibot
|
||||||
version.semver=0.8.0-beta+312
|
version.semver=0.8.0-beta+337
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue