diff --git a/README.txt b/README.txt index 1d111a1..0ece869 100644 --- a/README.txt +++ b/README.txt @@ -1,23 +1,23 @@ Some very basic instructions: - { clone with git or download the ZIP } - git clone git://github.com/ethauvin/mobibot.git - - cd mobibot - - { build with gradle } - ./gradlew + { clone with git or download the ZIP } + git clone git://github.com/ethauvin/mobibot.git + + cd mobibot + + { build with gradle } + ./gradlew - cd deploy + cd deploy - { configure the properties } - vi *.properties - - { help } - java -jar mobibot.jar -h + { configure the properties } + vi *.properties + + { help } + java -jar mobibot.jar -h - { twitter oauth token request } - java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth + { twitter oauth token request } + java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth - { launch } - /usr/bin/nohup java -jar mobibot.jar & + { launch } + /usr/bin/nohup java -jar mobibot.jar & diff --git a/build.gradle b/build.gradle index e43615c..b58a31c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id "com.ewerk.gradle.plugins.annotation-processor" version "1.0.2" - id "com.github.ben-manes.versions" version "0.12.0" + id "com.ewerk.gradle.plugins.annotation-processor" version "1.0.2" + id "com.github.ben-manes.versions" version "0.12.0" } apply plugin: 'java' @@ -13,29 +13,27 @@ def packageName = 'net.thauvin.erik.mobibot' def deployDir = 'deploy' def isRelease = 'release' in gradle.startParameter.taskNames -def getVersion(isIncrement = false) -{ - def propsFile = 'version.properties' - def majorKey = 'version.major' - def minorKey = 'version.minor' - def patchKey = 'version.patch' - def metaKey = 'version.buildmeta' - def preKey = 'version.prerelease' - if (isIncrement) - { - ant.propertyfile(file: propsFile) { - entry(key: patchKey, - type: 'int', - default: '-1', - operation: '+') - } - } - def p = new Properties() - file(propsFile).withInputStream { stream -> p.load(stream) } - def metadata = p.getProperty(metaKey, '') - def prerelease = p.getProperty(preKey, '') - return (p.getProperty(majorKey, '1') + '.' + p.getProperty(minorKey, '0') + '.' + p.getProperty(patchKey, '0') + - (prerelease.length() > 0 ? '-' + prerelease : '') + (metadata.length() > 0 ? '+' + metadata : '')) +def getVersion(isIncrement = false) { + def propsFile = 'version.properties' + def majorKey = 'version.major' + def minorKey = 'version.minor' + def patchKey = 'version.patch' + def metaKey = 'version.buildmeta' + def preKey = 'version.prerelease' + if (isIncrement) { + ant.propertyfile(file: propsFile) { + entry(key: patchKey, + type: 'int', + default: '-1', + operation: '+') + } + } + def p = new Properties() + file(propsFile).withInputStream { stream -> p.load(stream) } + def metadata = p.getProperty(metaKey, '') + def prerelease = p.getProperty(preKey, '') + return (p.getProperty(majorKey, '1') + '.' + p.getProperty(minorKey, '0') + '.' + p.getProperty(patchKey, '0') + + (prerelease.length() > 0 ? '-' + prerelease : '') + (metadata.length() > 0 ? '+' + metadata : '')) } version = getVersion() @@ -44,100 +42,100 @@ mainClassName = packageName + '.Mobibot' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' repositories { - mavenLocal() - mavenCentral() - jcenter() + mavenLocal() + mavenCentral() + jcenter() } dependencies { - compile 'log4j:log4j:1.2.17@jar' + compile 'log4j:log4j:1.2.17@jar' - compile 'pircbot:pircbot:1.5.0' + compile 'pircbot:pircbot:1.5.0' - compile 'commons-codec:commons-codec:1.10' - compile 'commons-logging:commons-logging:1.2' - compile 'commons-net:commons-net:3.5' - compile 'commons-cli:commons-cli:1.3.1' - compile 'commons-httpclient:commons-httpclient:3.1' + compile 'commons-codec:commons-codec:1.10' + compile 'commons-logging:commons-logging:1.2' + compile 'commons-net:commons-net:3.5' + compile 'commons-cli:commons-cli:1.3.1' + compile 'commons-httpclient:commons-httpclient:3.1' - compile 'oro:oro:2.0.8' + compile 'oro:oro:2.0.8' - compile 'org.jsoup:jsoup:1.9.2' - compile 'com.rometools:rome:1.6.1' - compile 'org.slf4j:slf4j-log4j12:1.7.21' - compile 'org.json:json:20160212' - compile 'org.ostermiller:utils:1.07.00' + compile 'org.jsoup:jsoup:1.9.2' + compile 'com.rometools:rome:1.6.1' + compile 'org.slf4j:slf4j-log4j12:1.7.21' + compile 'org.json:json:20160212' + compile 'org.ostermiller:utils:1.07.00' - compile 'net.sourceforge.jweather:jweather:0.3.0@jar' - compile 'net.objecthunter:exp4j:0.4.7' + compile 'net.sourceforge.jweather:jweather:0.3.0@jar' + compile 'net.objecthunter:exp4j:0.4.7' - compile 'org.twitter4j:twitter4j-core:4.0.4' - compile 'net.sf.delicious-java:delicious:1.14' + compile 'org.twitter4j:twitter4j-core:4.0.4' + compile 'net.sf.delicious-java:delicious:1.14' - compileOnly 'net.thauvin.erik:semver:0.9.6-beta' + compileOnly 'net.thauvin.erik:semver:0.9.6-beta' } annotationProcessor { - project.version = getVersion(isRelease) - library 'net.thauvin.erik:semver:0.9.6-beta' - processor 'net.thauvin.erik.semver.VersionProcessor' + project.version = getVersion(isRelease) + library 'net.thauvin.erik:semver:0.9.6-beta' + processor 'net.thauvin.erik.semver.VersionProcessor' } compileJava { - options.compilerArgs << '-proc:none' << '-Xlint:unchecked' << '-Xlint:deprecation' + options.compilerArgs << '-proc:none' << '-Xlint:unchecked' << '-Xlint:deprecation' } javadoc { - options.tags = ['created'] + options.tags = ['created'] } jar { - manifest.attributes('Main-Class': mainClassName, - 'Class-Path': '. ./lib/' + configurations.compile.collect { it.getName() }.join(' ./lib/')) + manifest.attributes('Main-Class': mainClassName, + 'Class-Path': '. ./lib/' + configurations.compile.collect { it.getName() }.join(' ./lib/')) - version = null + version = null } clean { - delete deployDir + delete deployDir } run { - args '--v' + args '--v' } task wrapper(type: Wrapper) { - gradleVersion = gradle.gradleVersion + gradleVersion = gradle.gradleVersion } task copyToDeploy(type: Copy) { - from('properties') { - include '*.properties' - } - from jar - into deployDir + from('properties') { + include '*.properties' + } + from jar + into deployDir } task copyToDeployLib(type: Copy) { - from configurations.runtime - into deployDir + '/lib' + from configurations.runtime + into deployDir + '/lib' } task deploy(dependsOn: ['build']) { - description = 'Copies all needed files to the ${deployDir} directory.' - group = 'Publishing' - outputs.dir deployDir - inputs.files copyToDeploy - inputs.files copyToDeployLib - doLast { - file(deployDir + '/logs').mkdir() - } - mustRunAfter clean + description = 'Copies all needed files to the ${deployDir} directory.' + group = 'Publishing' + outputs.dir deployDir + inputs.files copyToDeploy + inputs.files copyToDeployLib + doLast { + file(deployDir + '/logs').mkdir() + } + mustRunAfter clean } task release(dependsOn: ['wrapper', 'clean', 'deploy']) << { - group = 'Publishing' - description = 'Releases new version.' - isRelease = true + group = 'Publishing' + description = 'Releases new version.' + isRelease = true } diff --git a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java index 1ea174d..65a0955 100644 --- a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java +++ b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java @@ -13,8 +13,8 @@ import java.util.Date; * Annotation Processor */ public final class ReleaseInfo { - private final static String buildmeta = "006"; - private final static Date date = new Date(1468655027549L); + private final static String buildmeta = "008"; + private final static Date date = new Date(1468718052505L); private final static int major = 0; private final static int minor = 7; private final static int patch = 0; diff --git a/src/main/java/net/thauvin/erik/mobibot/Commands.java b/src/main/java/net/thauvin/erik/mobibot/Commands.java index e9dc7f3..4ec43ba 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Commands.java +++ b/src/main/java/net/thauvin/erik/mobibot/Commands.java @@ -38,131 +38,129 @@ package net.thauvin.erik.mobibot; * @created 2014-04-26 * @since 1.0 */ -final class Commands -{ - /** - * The add (back)log command. - */ - public static final String ADDLOG_CMD = "addlog"; +final class Commands { + /** + * The add (back)log command. + */ + public static final String ADDLOG_CMD = "addlog"; - /** - * The cycle command. - */ - public static final String CYCLE_CMD = "cycle"; + /** + * The cycle command. + */ + public static final String CYCLE_CMD = "cycle"; - /** - * Debug command line argument. - */ - public static final String DEBUG_ARG = "debug"; + /** + * Debug command line argument. + */ + public static final String DEBUG_ARG = "debug"; - /** - * The debug command. - */ - public static final String DEBUG_CMD = "debug"; + /** + * The debug command. + */ + public static final String DEBUG_CMD = "debug"; - /** - * The die command. - */ - public static final String DIE_CMD = "die"; + /** + * The die command. + */ + public static final String DIE_CMD = "die"; - /** - * Help command line argument. - */ - public static final String HELP_ARG = "help"; + /** + * Help command line argument. + */ + public static final String HELP_ARG = "help"; - /** - * The help command. - */ - public static final String HELP_CMD = "help"; + /** + * The help command. + */ + public static final String HELP_CMD = "help"; - /** - * The help on posting keyword. - */ - public static final String HELP_POSTING_KEYWORD = "posting"; + /** + * The help on posting keyword. + */ + public static final String HELP_POSTING_KEYWORD = "posting"; - /** - * The help on tags keyword. - */ - public static final String HELP_TAGS_KEYWORD = "tags"; + /** + * The help on tags keyword. + */ + public static final String HELP_TAGS_KEYWORD = "tags"; - /** - * The ignore command. - */ - public static final String IGNORE_CMD = "ignore"; + /** + * The ignore command. + */ + public static final String IGNORE_CMD = "ignore"; - /** - * The ignore me keyword. - */ - public static final String IGNORE_ME_KEYWORD = "me"; + /** + * The ignore me keyword. + */ + public static final String IGNORE_ME_KEYWORD = "me"; - /** - * The info command. - */ - public static final String INFO_CMD = "info"; + /** + * The info command. + */ + public static final String INFO_CMD = "info"; - /** - * The link command. - */ - public static final String LINK_CMD = "L"; + /** + * The link command. + */ + public static final String LINK_CMD = "L"; - /** - * The me command. - */ - public static final String ME_CMD = "me"; + /** + * The me command. + */ + public static final String ME_CMD = "me"; - /** - * The msg command. - */ - public static final String MSG_CMD = "msg"; + /** + * The msg command. + */ + public static final String MSG_CMD = "msg"; - /** - * The nick command. - */ - public static final String NICK_CMD = "nick"; + /** + * The nick command. + */ + public static final String NICK_CMD = "nick"; - /** - * Properties command line argument. - */ - public static final String PROPS_ARG = "properties"; + /** + * Properties command line argument. + */ + public static final String PROPS_ARG = "properties"; - /** - * The recap command. - */ - public static final String RECAP_CMD = "recap"; + /** + * The recap command. + */ + public static final String RECAP_CMD = "recap"; - /** - * The say command. - */ - public static final String SAY_CMD = "say"; + /** + * The say command. + */ + public static final String SAY_CMD = "say"; - /** - * The users command. - */ - public static final String USERS_CMD = "users"; + /** + * The users command. + */ + public static final String USERS_CMD = "users"; - /** - * Properties version line argument. - */ - public static final String VERSION_ARG = "version"; + /** + * Properties version line argument. + */ + public static final String VERSION_ARG = "version"; - /** - * The version command. - */ - public static final String VERSION_CMD = "version"; + /** + * The version command. + */ + public static final String VERSION_CMD = "version"; - /** - * The view command. - */ - public static final String VIEW_CMD = "view"; + /** + * The view command. + */ + public static final String VIEW_CMD = "view"; - /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. - */ - private Commands() - throws UnsupportedOperationException - { - throw new UnsupportedOperationException("Illegal constructor call."); - } + /** + * Disables the default constructor. + * + * @throws UnsupportedOperationException If the constructor is called. + */ + private Commands() + throws UnsupportedOperationException { + throw new UnsupportedOperationException("Illegal constructor call."); + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/DeliciousPoster.java b/src/main/java/net/thauvin/erik/mobibot/DeliciousPoster.java index 44b2bef..181a2f4 100644 --- a/src/main/java/net/thauvin/erik/mobibot/DeliciousPoster.java +++ b/src/main/java/net/thauvin/erik/mobibot/DeliciousPoster.java @@ -42,120 +42,103 @@ import javax.swing.*; * @created Mar 5, 2005 * @since 1.0 */ -class DeliciousPoster -{ - private final Delicious delicious; +class DeliciousPoster { + private final Delicious delicious; + private final String ircServer; - private final String ircServer; + /** + * Creates a new {@link DeliciousPoster} instance. + * + * @param username The del.icio.us user name. + * @param password The del.icio.us password. + * @param ircServer The IRC server. + */ + public DeliciousPoster(final String username, final String password, final String ircServer) { + delicious = new Delicious(username, password); + this.ircServer = ircServer; + } - /** - * Creates a new {@link DeliciousPoster} instance. - * - * @param username The del.icio.us user name. - * @param password The del.icio.us password. - * @param ircServer The IRC server. - */ - public DeliciousPoster(final String username, final String password, final String ircServer) - { - delicious = new Delicious(username, password); - this.ircServer = ircServer; - } + /** + * Adds a post to del.icio.us. + * + * @param entry The entry to add. + */ + public final void addPost(final EntryLink entry) { + final SwingWorker worker = new SwingWorker() { + @Override + protected Boolean doInBackground() + throws Exception { + return delicious.addPost(entry.getLink(), + entry.getTitle(), + postedBy(entry), + entry.getDeliciousTags(), + entry.getDate()); + } + }; - /** - * Adds a post to del.icio.us. - * - * @param entry The entry to add. - */ - public final void addPost(final EntryLink entry) - { - final SwingWorker worker = new SwingWorker() - { - @Override - protected Boolean doInBackground() - throws Exception - { - return delicious.addPost(entry.getLink(), - entry.getTitle(), - postedBy(entry), - entry.getDeliciousTags(), - entry.getDate()); - } - }; + worker.execute(); + } - worker.execute(); - } + /** + * Deletes a post to del.icio.us. + * + * @param entry The entry to delete. + */ + public final void deletePost(final EntryLink entry) { + final String link = entry.getLink(); - /** - * Returns he del.icio.us extended attribution line. - * - * @param entry The entry. - * - * @return The extended attribution line. - */ - private String postedBy(final EntryLink entry) - { - return "Posted by " + entry.getNick() + " on " + entry.getChannel() + " (" + ircServer + ')'; - } + final SwingWorker worker = new SwingWorker() { + @Override + protected Boolean doInBackground() + throws Exception { + return delicious.deletePost(link); + } + }; - /** - * Deletes a post to del.icio.us. - * - * @param entry The entry to delete. - */ - public final void deletePost(final EntryLink entry) - { - final String link = entry.getLink(); + worker.execute(); + } - final SwingWorker worker = new SwingWorker() - { - @Override - protected Boolean doInBackground() - throws Exception - { - return delicious.deletePost(link); - } - }; + /** + * Returns he del.icio.us extended attribution line. + * + * @param entry The entry. + * @return The extended attribution line. + */ + private String postedBy(final EntryLink entry) { + return "Posted by " + entry.getNick() + " on " + entry.getChannel() + " (" + ircServer + ')'; + } - worker.execute(); - } + /** + * Updates a post to del.icio.us. + * + * @param oldUrl The old post URL. + * @param entry The entry to add. + */ + public final void updatePost(final String oldUrl, final EntryLink entry) { + final SwingWorker worker = new SwingWorker() { + @Override + protected Boolean doInBackground() + throws Exception { + if (!oldUrl.equals(entry.getLink())) { + delicious.deletePost(oldUrl); - /** - * Updates a post to del.icio.us. - * - * @param oldUrl The old post URL. - * @param entry The entry to add. - */ - public final void updatePost(final String oldUrl, final EntryLink entry) - { - final SwingWorker worker = new SwingWorker() - { - @Override - protected Boolean doInBackground() - throws Exception - { - if (!oldUrl.equals(entry.getLink())) - { - delicious.deletePost(oldUrl); + return delicious.addPost(entry.getLink(), + entry.getTitle(), + postedBy(entry), + entry.getDeliciousTags(), + entry.getDate()); + } else { + return delicious.addPost(entry.getLink(), + entry.getTitle(), + postedBy(entry), + entry.getDeliciousTags(), + entry.getDate(), + true, + true); + } + } + }; - return delicious.addPost(entry.getLink(), - entry.getTitle(), - postedBy(entry), - entry.getDeliciousTags(), - entry.getDate()); - } - else - { - return delicious.addPost(entry.getLink(), - entry.getTitle(), - postedBy(entry), - entry.getDeliciousTags(), - entry.getDate(), - true, - true); - } - } - }; - - worker.execute(); - } + worker.execute(); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/EntriesMgr.java b/src/main/java/net/thauvin/erik/mobibot/EntriesMgr.java index c16baa2..daa8890 100644 --- a/src/main/java/net/thauvin/erik/mobibot/EntriesMgr.java +++ b/src/main/java/net/thauvin/erik/mobibot/EntriesMgr.java @@ -48,310 +48,270 @@ import java.util.List; * @created 2014-04-28 * @since 1.0 */ -final class EntriesMgr -{ - /** - * The name of the file containing the current entries. - */ - public static final String CURRENT_XML = "current.xml"; +final class EntriesMgr { + /** + * The name of the file containing the current entries. + */ + public static final String CURRENT_XML = "current.xml"; - /** - * The name of the file containing the backlog entries. - */ - public static final String NAV_XML = "nav.xml"; + /** + * The name of the file containing the backlog entries. + */ + public static final String NAV_XML = "nav.xml"; - /** - * The .xml extension - */ - public static final String XML_EXT = ".xml"; + /** + * The .xml extension + */ + public static final String XML_EXT = ".xml"; - /** - * The maximum number of backlogs to keep. - */ - private static final int MAX_BACKLOGS = 10; + /** + * The maximum number of backlogs to keep. + */ + private static final int MAX_BACKLOGS = 10; - /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. - */ - private EntriesMgr() - throws UnsupportedOperationException - { - throw new UnsupportedOperationException("Illegal constructor call."); - } + /** + * Disables the default constructor. + * + * @throws UnsupportedOperationException If the constructor is called. + */ + private EntriesMgr() + throws UnsupportedOperationException { + throw new UnsupportedOperationException("Illegal constructor call."); + } - /** - * Loads the backlogs. - * - * @param file The file containing the backlogs. - * @param history The history list. - * - * @throws IOException If the file was not found or could not be read. - * @throws FeedException If an error occurred while reading the feed. - */ - public static void loadBacklogs(final String file, final List history) - throws IOException, FeedException - { - history.clear(); + /** + * Loads the backlogs. + * + * @param file The file containing the backlogs. + * @param history The history list. + * @throws IOException If the file was not found or could not be read. + * @throws FeedException If an error occurred while reading the feed. + */ + public static void loadBacklogs(final String file, final List history) + throws IOException, FeedException { + history.clear(); - final SyndFeedInput input = new SyndFeedInput(); + final SyndFeedInput input = new SyndFeedInput(); - try (final InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(file)))) - { + try (final InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(file)))) { - final SyndFeed feed = input.build(reader); + final SyndFeed feed = input.build(reader); - final List items = feed.getEntries(); - SyndEntry item; + final List items = feed.getEntries(); + SyndEntry item; - for (int i = items.size() - 1; i >= 0; i--) - { - item = (SyndEntryImpl) items.get(i); - history.add(item.getTitle()); - } - } - } + for (int i = items.size() - 1; i >= 0; i--) { + item = (SyndEntryImpl) items.get(i); + history.add(item.getTitle()); + } + } + } - /** - * Loads the current entries. - * - * @param file The file containing the current entries. - * @param channel The channel - * @param entries The entries. - * - * @return The feed's last published date. - * - * @throws IOException If the file was not found or could not be read. - * @throws FeedException If an error occurred while reading the feed. - */ - @SuppressWarnings("unchecked") - public static String loadEntries(final String file, final String channel, final List entries) - throws IOException, FeedException - { - entries.clear(); + /** + * Loads the current entries. + * + * @param file The file containing the current entries. + * @param channel The channel + * @param entries The entries. + * @return The feed's last published date. + * @throws IOException If the file was not found or could not be read. + * @throws FeedException If an error occurred while reading the feed. + */ + @SuppressWarnings("unchecked") + public static String loadEntries(final String file, final String channel, final List entries) + throws IOException, FeedException { + entries.clear(); - final SyndFeedInput input = new SyndFeedInput(); + final SyndFeedInput input = new SyndFeedInput(); - final String today; + final String today; - try (InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(file)))) - { - final SyndFeed feed = input.build(reader); + try (InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(file)))) { + final SyndFeed feed = input.build(reader); - today = Utils.ISO_SDF.format(feed.getPublishedDate()); + today = Utils.ISO_SDF.format(feed.getPublishedDate()); - final List items = feed.getEntries(); - SyndEntry item; - SyndContent description; - String[] comments; - String author; - EntryLink entry; + final List items = feed.getEntries(); + SyndEntry item; + SyndContent description; + String[] comments; + String author; + EntryLink entry; - for (int i = items.size() - 1; i >= 0; i--) - { - item = (SyndEntryImpl) items.get(i); - author = item.getAuthor() - .substring(item.getAuthor().lastIndexOf('(') + 1, item.getAuthor().length() - 1); - entry = new EntryLink(item.getLink(), - item.getTitle(), - author, - channel, - item.getPublishedDate(), - item.getCategories()); - description = item.getDescription(); - comments = description.getValue().split("
"); + for (int i = items.size() - 1; i >= 0; i--) { + item = (SyndEntryImpl) items.get(i); + author = item.getAuthor() + .substring(item.getAuthor().lastIndexOf('(') + 1, item.getAuthor().length() - 1); + entry = new EntryLink(item.getLink(), + item.getTitle(), + author, + channel, + item.getPublishedDate(), + item.getCategories()); + description = item.getDescription(); + comments = description.getValue().split("
"); - int split; - for (final String comment : comments) - { - split = comment.indexOf(": "); + int split; + for (final String comment : comments) { + split = comment.indexOf(": "); - if (split != -1) - { - entry.addComment(comment.substring(split + 2).trim(), comment.substring(0, split).trim()); - } - } + if (split != -1) { + entry.addComment(comment.substring(split + 2).trim(), comment.substring(0, split).trim()); + } + } - entries.add(entry); - } - } + entries.add(entry); + } + } - return today; - } + return today; + } - /** - * Saves the entries. - * - * @param bot The bot object. - * @param entries The entries array. - * @param history The history array. - * @param isDayBackup Set the true if the daily backup file should also be created. - */ - public static void saveEntries(final Mobibot bot, final List entries, final List history, - final boolean isDayBackup) - { - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Saving the feeds..."); - } + /** + * Saves the entries. + * + * @param bot The bot object. + * @param entries The entries array. + * @param history The history array. + * @param isDayBackup Set the true if the daily backup file should also be created. + */ + public static void saveEntries(final Mobibot bot, final List entries, final List history, + final boolean isDayBackup) { + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Saving the feeds..."); + } - if (Utils.isValidString(bot.getLogsDir()) && Utils.isValidString(bot.getWeblogUrl())) - { - FileWriter fw = null; + if (Utils.isValidString(bot.getLogsDir()) && Utils.isValidString(bot.getWeblogUrl())) { + FileWriter fw = null; - try - { - fw = new FileWriter(new File(bot.getLogsDir() + CURRENT_XML)); + try { + fw = new FileWriter(new File(bot.getLogsDir() + CURRENT_XML)); - SyndFeed rss = new SyndFeedImpl(); - rss.setFeedType("rss_2.0"); - rss.setTitle(bot.getChannel() + " IRC Links"); - rss.setDescription("Links from " + bot.getIrcServer() + " on " + bot.getChannel()); - rss.setLink(bot.getWeblogUrl()); - rss.setPublishedDate(Calendar.getInstance().getTime()); - rss.setLanguage("en"); + SyndFeed rss = new SyndFeedImpl(); + rss.setFeedType("rss_2.0"); + rss.setTitle(bot.getChannel() + " IRC Links"); + rss.setDescription("Links from " + bot.getIrcServer() + " on " + bot.getChannel()); + rss.setLink(bot.getWeblogUrl()); + rss.setPublishedDate(Calendar.getInstance().getTime()); + rss.setLanguage("en"); - EntryLink entry; - StringBuffer buff; - EntryComment comment; - final List items = new ArrayList<>(0); - SyndEntry item; - SyndContent description; + EntryLink entry; + StringBuffer buff; + EntryComment comment; + final List items = new ArrayList<>(0); + SyndEntry item; + SyndContent description; - for (int i = (entries.size() - 1); i >= 0; --i) - { - entry = entries.get(i); + for (int i = (entries.size() - 1); i >= 0; --i) { + entry = entries.get(i); - buff = new StringBuffer( - "Posted by " + entry.getNick() + " on " + entry.getChannel() + ""); + buff = new StringBuffer( + "Posted by " + entry.getNick() + " on " + entry.getChannel() + ""); - if (entry.getCommentsCount() > 0) - { - buff.append("

"); + if (entry.getCommentsCount() > 0) { + buff.append("

"); - final EntryComment[] comments = entry.getComments(); + final EntryComment[] comments = entry.getComments(); - for (int j = 0; j < comments.length; j++) - { - comment = comments[j]; + for (int j = 0; j < comments.length; j++) { + comment = comments[j]; - if (j > 0) - { - buff.append("
"); - } + if (j > 0) { + buff.append("
"); + } - buff.append(comment.getNick()).append(": ").append(comment.getComment()); - } - } + buff.append(comment.getNick()).append(": ").append(comment.getComment()); + } + } - item = new SyndEntryImpl(); - item.setLink(entry.getLink()); - description = new SyndContentImpl(); - description.setValue(buff.toString()); - item.setDescription(description); - item.setTitle(entry.getTitle()); - item.setPublishedDate(entry.getDate()); - item.setAuthor( - bot.getChannel().substring(1) + '@' + bot.getIrcServer() + " (" + entry.getNick() + ')'); - item.setCategories(entry.getTags()); + item = new SyndEntryImpl(); + item.setLink(entry.getLink()); + description = new SyndContentImpl(); + description.setValue(buff.toString()); + item.setDescription(description); + item.setTitle(entry.getTitle()); + item.setPublishedDate(entry.getDate()); + item.setAuthor( + bot.getChannel().substring(1) + '@' + bot.getIrcServer() + " (" + entry.getNick() + ')'); + item.setCategories(entry.getTags()); - items.add(item); - } + items.add(item); + } - rss.setEntries(items); + rss.setEntries(items); - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Writing the entries feed."); - } + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Writing the entries feed."); + } - final SyndFeedOutput output = new SyndFeedOutput(); - output.output(rss, fw); - fw.close(); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(rss, fw); + fw.close(); - fw = new FileWriter(new File(bot.getLogsDir() + bot.getToday() + XML_EXT)); - output.output(rss, fw); + fw = new FileWriter(new File(bot.getLogsDir() + bot.getToday() + XML_EXT)); + output.output(rss, fw); - if (isDayBackup) - { - if (Utils.isValidString(bot.getBacklogsUrl())) - { - if (history.indexOf(bot.getToday()) == -1) - { - history.add(bot.getToday()); + if (isDayBackup) { + if (Utils.isValidString(bot.getBacklogsUrl())) { + if (history.indexOf(bot.getToday()) == -1) { + history.add(bot.getToday()); - while (history.size() > MAX_BACKLOGS) - { - history.remove(0); - } - } + while (history.size() > MAX_BACKLOGS) { + history.remove(0); + } + } - fw.close(); - fw = new FileWriter(new File(bot.getLogsDir() + NAV_XML)); - rss = new SyndFeedImpl(); - rss.setFeedType("rss_2.0"); - rss.setTitle(bot.getChannel() + " IRC Links Backlogs"); - rss.setDescription("Backlogs of Links from " + bot.getIrcServer() + " on " + bot.getChannel()); - rss.setLink(bot.getBacklogsUrl()); - rss.setPublishedDate(Calendar.getInstance().getTime()); + fw.close(); + fw = new FileWriter(new File(bot.getLogsDir() + NAV_XML)); + rss = new SyndFeedImpl(); + rss.setFeedType("rss_2.0"); + rss.setTitle(bot.getChannel() + " IRC Links Backlogs"); + rss.setDescription("Backlogs of Links from " + bot.getIrcServer() + " on " + bot.getChannel()); + rss.setLink(bot.getBacklogsUrl()); + rss.setPublishedDate(Calendar.getInstance().getTime()); - String date; - items.clear(); + String date; + items.clear(); - for (int i = (history.size() - 1); i >= 0; --i) - { - date = history.get(i); + for (int i = (history.size() - 1); i >= 0; --i) { + date = history.get(i); - item = new SyndEntryImpl(); - item.setLink(bot.getBacklogsUrl() + date + ".xml"); - item.setTitle(date); - description = new SyndContentImpl(); - description.setValue("Links for " + date); - item.setDescription(description); + item = new SyndEntryImpl(); + item.setLink(bot.getBacklogsUrl() + date + ".xml"); + item.setTitle(date); + description = new SyndContentImpl(); + description.setValue("Links for " + date); + item.setDescription(description); - items.add(item); - } + items.add(item); + } - rss.setEntries(items); + rss.setEntries(items); - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Writing the backlog feed."); - } + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Writing the backlog feed."); + } - output.output(rss, fw); - } - else - { - bot.getLogger().warn("Unable to generate the backlogs feed. No property configured."); - } - } - } - catch (Exception e) - { - bot.getLogger().warn("Unable to generate the entries feed.", e); - } - finally - { - try - { - if (fw != null) - { - fw.close(); - } - } - catch (Exception ignore) - { - ; // Do nothing - } - } - } - else - { - bot.getLogger() - .warn("Unable to generate the entries feed. At least one of the required property is missing."); - } - } + output.output(rss, fw); + } else { + bot.getLogger().warn("Unable to generate the backlogs feed. No property configured."); + } + } + } catch (Exception e) { + bot.getLogger().warn("Unable to generate the entries feed.", e); + } finally { + try { + if (fw != null) { + fw.close(); + } + } catch (Exception ignore) { + ; // Do nothing + } + } + } else { + bot.getLogger() + .warn("Unable to generate the entries feed. At least one of the required property is missing."); + } + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/EntryComment.java b/src/main/java/net/thauvin/erik/mobibot/EntryComment.java index e8e09b2..826deac 100644 --- a/src/main/java/net/thauvin/erik/mobibot/EntryComment.java +++ b/src/main/java/net/thauvin/erik/mobibot/EntryComment.java @@ -42,92 +42,83 @@ import java.util.Date; * @created Jan 31, 2004 * @since 1.0 */ -public class EntryComment implements Serializable -{ - /** - * The serial version UID. - */ - static final long serialVersionUID = 6957415292233553224L; +public class EntryComment implements Serializable { + /** + * The serial version UID. + */ + static final long serialVersionUID = 6957415292233553224L; - /** - * The creation date. - */ - private final Date date = Calendar.getInstance().getTime(); + /** + * The creation date. + */ + private final Date date = Calendar.getInstance().getTime(); - private String comment = ""; + private String comment = ""; + private String nick = ""; - private String nick = ""; + /** + * Creates a new comment. + * + * @param comment The new comment. + * @param nick The nickname of the comment's author. + */ + public EntryComment(final String comment, final String nick) { + this.comment = comment; + this.nick = nick; + } - /** - * Creates a new comment. - * - * @param comment The new comment. - * @param nick The nickname of the comment's author. - */ - public EntryComment(final String comment, final String nick) - { - this.comment = comment; - this.nick = nick; - } + /** + * Creates a new comment. + */ + @SuppressWarnings("UnusedDeclaration") + protected EntryComment() { + ; // Required for serialization. + } - /** - * Creates a new comment. - */ - @SuppressWarnings("UnusedDeclaration") - protected EntryComment() - { - ; // Required for serialization. - } + /** + * Returns the comment. + * + * @return The comment. + */ + public final String getComment() { + return comment; + } - /** - * Returns the comment. - * - * @return The comment. - */ - public final String getComment() - { - return comment; - } + /** + * Sets the comment. + * + * @param comment The actual comment. + */ + @SuppressWarnings("UnusedDeclaration") + public final void setComment(final String comment) { + this.comment = comment; + } - /** - * Sets the comment. - * - * @param comment The actual comment. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setComment(final String comment) - { - this.comment = comment; - } + /** + * Returns the comment's creation date. + * + * @return The date. + */ + @SuppressWarnings("UnusedDeclaration") + public final Date getDate() { + return date; + } - /** - * Returns the comment's creation date. - * - * @return The date. - */ - @SuppressWarnings("UnusedDeclaration") - public final Date getDate() - { - return date; - } + /** + * Returns the nickname of the author of the comment. + * + * @return The nickname. + */ + public final String getNick() { + return nick; + } - /** - * Returns the nickname of the author of the comment. - * - * @return The nickname. - */ - public final String getNick() - { - return nick; - } - - /** - * Sets the nickname of the author of the comment. - * - * @param nick The new nickname. - */ - public final void setNick(final String nick) - { - this.nick = nick; - } + /** + * Sets the nickname of the author of the comment. + * + * @param nick The new nickname. + */ + public final void setNick(final String nick) { + this.nick = nick; + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/EntryLink.java b/src/main/java/net/thauvin/erik/mobibot/EntryLink.java index e1fe035..2be2d11 100644 --- a/src/main/java/net/thauvin/erik/mobibot/EntryLink.java +++ b/src/main/java/net/thauvin/erik/mobibot/EntryLink.java @@ -47,391 +47,348 @@ import java.util.concurrent.CopyOnWriteArrayList; * @created Jan 31, 2004 * @since 1.0 */ -public class EntryLink implements Serializable -{ - /** - * The serial version UID. - */ - static final long serialVersionUID = 3676245542270899086L; +public class EntryLink implements Serializable { + /** + * The serial version UID. + */ + static final long serialVersionUID = 3676245542270899086L; - // The link's comments - private final List comments = new CopyOnWriteArrayList<>(); + // The link's comments + private final List comments = new CopyOnWriteArrayList<>(); - // The tags/categories - private final List tags = new CopyOnWriteArrayList<>(); + // The tags/categories + private final List tags = new CopyOnWriteArrayList<>(); - // The channel - private String channel = ""; + // The channel + private String channel = ""; - // The creation date - private Date date = Calendar.getInstance().getTime(); + // The creation date + private Date date = Calendar.getInstance().getTime(); - // The link's URL - private String link = ""; + // The link's URL + private String link = ""; - // The author's login - private String login = ""; + // The author's login + private String login = ""; - // The author's nickname - private String nick = ""; + // The author's nickname + private String nick = ""; - // The link's title - private String title = ""; + // The link's title + private String title = ""; - /** - * Creates a new entry. - * - * @param link The new entry's link. - * @param title The new entry's title. - * @param nick The nickname of the author of the link. - * @param login The login of the author of the link. - * @param channel The channel. - * @param tags The entry's tags/categories. - */ - public EntryLink(final String link, final String title, final String nick, final String login, final String channel, - final String tags) - { - this.link = link; - this.title = title; - this.nick = nick; - this.login = login; - this.channel = channel; + /** + * Creates a new entry. + * + * @param link The new entry's link. + * @param title The new entry's title. + * @param nick The nickname of the author of the link. + * @param login The login of the author of the link. + * @param channel The channel. + * @param tags The entry's tags/categories. + */ + public EntryLink(final String link, final String title, final String nick, final String login, final String channel, + final String tags) { + this.link = link; + this.title = title; + this.nick = nick; + this.login = login; + this.channel = channel; - setTags(tags); - } + setTags(tags); + } - /** - * Sets the tags. - * - * @param tags The space-delimited tags. - */ - public final void setTags(final String tags) - { - if (tags != null) - { - final String[] parts = tags.replaceAll(", ", " ").replaceAll(",", " ").split(" "); + /** + * Creates a new entry. + * + * @param link The new entry's link. + * @param title The new entry's title. + * @param nick The nickname of the author of the link. + * @param channel The channel. + * @param date The entry date. + * @param tags The entry's tags/categories. + */ + public EntryLink(final String link, final String title, final String nick, final String channel, final Date date, + final List tags) { + this.link = link; + this.title = title; + this.nick = nick; + this.channel = channel; + this.date = date; - SyndCategoryImpl tag; - String part; - char mod; + setTags(tags); + } - for (final String rawPart : parts) - { - part = rawPart.trim(); + /** + * Adds a new comment. + * + * @param comment The actual comment. + * @param nick The nickname of the author of the comment. + * @return The total number of comments for this entry. + */ + public final int addComment(final String comment, final String nick) { + comments.add(new EntryComment(comment, nick)); - if (part.length() >= 2) - { - tag = new SyndCategoryImpl(); - tag.setName(part.substring(1).toLowerCase()); + return (comments.size() - 1); + } - mod = part.charAt(0); + /** + * Deletes a specific comment. + * + * @param index The index of the comment to delete. + */ + public final void deleteComment(final int index) { + if (index < comments.size()) { + comments.remove(index); + } + } - if (mod == '-') - { - // Don't remove the channel tag, if any. - if (!tag.getName().equals(channel.substring(1))) - { - this.tags.remove(tag); - } - } - else if (mod == '+') - { - if (!this.tags.contains(tag)) - { - this.tags.add(tag); - } - } - else - { - tag.setName(part.trim().toLowerCase()); + /** + * Returns the channel the link was posted on. + * + * @return The channel + */ + public final String getChannel() { + return channel; + } - if (!this.tags.contains(tag)) - { - this.tags.add(tag); - } - } - } - } - } - } + /** + * Sets the channel. + * + * @param channel The channel. + */ + @SuppressWarnings("UnusedDeclaration") + public final void setChannel(final String channel) { + this.channel = channel; + } - /** - * Creates a new entry. - * - * @param link The new entry's link. - * @param title The new entry's title. - * @param nick The nickname of the author of the link. - * @param channel The channel. - * @param date The entry date. - * @param tags The entry's tags/categories. - */ - public EntryLink(final String link, final String title, final String nick, final String channel, final Date date, - final List tags) - { - this.link = link; - this.title = title; - this.nick = nick; - this.channel = channel; - this.date = date; + /** + * Returns a comment. + * + * @param index The comment's index. + * @return The specific comment. + */ + public final EntryComment getComment(final int index) { + return (comments.get(index)); + } - setTags(tags); - } + /** + * Returns all the comments. + * + * @return The comments. + */ + public final EntryComment[] getComments() { + return (comments.toArray(new EntryComment[comments.size()])); + } - /** - * Adds a new comment. - * - * @param comment The actual comment. - * @param nick The nickname of the author of the comment. - * - * @return The total number of comments for this entry. - */ - public final int addComment(final String comment, final String nick) - { - comments.add(new EntryComment(comment, nick)); + /** + * Returns the total number of comments. + * + * @return The count of comments. + */ + public final int getCommentsCount() { + return comments.size(); + } - return (comments.size() - 1); - } + /** + * Returns the comment's creation date. + * + * @return The date. + */ + public final Date getDate() { + return date; + } - /** - * Deletes a specific comment. - * - * @param index The index of the comment to delete. - */ - public final void deleteComment(final int index) - { - if (index < comments.size()) - { - comments.remove(index); - } - } + /** + * Returns the tags formatted for del.icio.us. + * + * @return The tags as a comma-delimited string. + */ + public final String getDeliciousTags() { + final StringBuilder tags = new StringBuilder(nick); - /** - * Returns the channel the link was posted on. - * - * @return The channel - */ - public final String getChannel() - { - return channel; - } + for (final Object tag : this.tags) { + tags.append(','); + tags.append(((SyndCategoryImpl) tag).getName()); + } - /** - * Sets the channel. - * - * @param channel The channel. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setChannel(final String channel) - { - this.channel = channel; - } + return tags.toString(); + } - /** - * Returns a comment. - * - * @param index The comment's index. - * - * @return The specific comment. - */ - public final EntryComment getComment(final int index) - { - return (comments.get(index)); - } + /** + * Returns the comment's link. + * + * @return The link. + */ + public final String getLink() { + return link; + } - /** - * Returns all the comments. - * - * @return The comments. - */ - public final EntryComment[] getComments() - { - return (comments.toArray(new EntryComment[comments.size()])); - } + /** + * Sets the comment's link. + * + * @param link The new link. + */ + public final void setLink(final String link) { + this.link = link; + } - /** - * Returns the total number of comments. - * - * @return The count of comments. - */ - public final int getCommentsCount() - { - return comments.size(); - } + /** + * Returns the comment's author login. + * + * @return The login; + */ + public final String getLogin() { + return login; + } - /** - * Returns the comment's creation date. - * - * @return The date. - */ - public final Date getDate() - { - return date; - } + /** + * Sets the comment's author login. + * + * @param login The new login. + */ + @SuppressWarnings("UnusedDeclaration") + public final void setLogin(final String login) { + this.login = login; + } - /** - * Returns the tags formatted for del.icio.us. - * - * @return The tags as a comma-delimited string. - */ - public final String getDeliciousTags() - { - final StringBuilder tags = new StringBuilder(nick); + /** + * Returns the comment's author nickname. + * + * @return The nickname. + */ + public final String getNick() { + return nick; + } - for (final Object tag : this.tags) - { - tags.append(','); - tags.append(((SyndCategoryImpl) tag).getName()); - } + /** + * Sets the comment's author nickname. + * + * @param nick The new nickname. + */ + public final void setNick(final String nick) { + this.nick = nick; + } - return tags.toString(); - } + /** + * Returns the tags. + * + * @return The tags. + */ + public final List getTags() { + return tags; + } - /** - * Returns the comment's link. - * - * @return The link. - */ - public final String getLink() - { - return link; - } + /** + * Sets the tags. + * + * @param tags The tags. + */ + private void setTags(final List tags) { + this.tags.addAll(tags); + } - /** - * Sets the comment's link. - * - * @param link The new link. - */ - public final void setLink(final String link) - { - this.link = link; - } + /** + * Returns the comment's title. + * + * @return The title. + */ + public final String getTitle() { + return title; + } - /** - * Returns the comment's author login. - * - * @return The login; - */ - public final String getLogin() - { - return login; - } + /** + * Sets the comment's title. + * + * @param title The new title. + */ + public final void setTitle(final String title) { + this.title = title; + } - /** - * Sets the comment's author login. - * - * @param login The new login. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setLogin(final String login) - { - this.login = login; - } + /** + * Returns true if the entry has comments. + * + * @return true if there are comments, false otherwise. + */ + public final boolean hasComments() { + return (!comments.isEmpty()); + } - /** - * Returns the comment's author nickname. - * - * @return The nickname. - */ - public final String getNick() - { - return nick; - } + /** + * Returns true if the entry has tags. + * + * @return true if there are tags, false otherwise. + */ + public final boolean hasTags() { + return (!tags.isEmpty()); + } - /** - * Sets the comment's author nickname. - * - * @param nick The new nickname. - */ - public final void setNick(final String nick) - { - this.nick = nick; - } + /** + * /** Sets a comment. + * + * @param index The comment's index. + * @param comment The actual comment. + * @param nick The nickname of the author of the comment. + */ + public final void setComment(final int index, final String comment, final String nick) { + if (index < comments.size()) { + comments.set(index, new EntryComment(comment, nick)); + } + } - /** - * Returns the tags. - * - * @return The tags. - */ - public final List getTags() - { - return tags; - } + /** + * Sets the tags. + * + * @param tags The space-delimited tags. + */ + public final void setTags(final String tags) { + if (tags != null) { + final String[] parts = tags.replaceAll(", ", " ").replaceAll(",", " ").split(" "); - /** - * Sets the tags. - * - * @param tags The tags. - */ - private void setTags(final List tags) - { - this.tags.addAll(tags); - } + SyndCategoryImpl tag; + String part; + char mod; - /** - * Returns the comment's title. - * - * @return The title. - */ - public final String getTitle() - { - return title; - } + for (final String rawPart : parts) { + part = rawPart.trim(); - /** - * Sets the comment's title. - * - * @param title The new title. - */ - public final void setTitle(final String title) - { - this.title = title; - } + if (part.length() >= 2) { + tag = new SyndCategoryImpl(); + tag.setName(part.substring(1).toLowerCase()); - /** - * Returns true if the entry has comments. - * - * @return true if there are comments, false otherwise. - */ - public final boolean hasComments() - { - return (!comments.isEmpty()); - } + mod = part.charAt(0); - /** - * Returns true if the entry has tags. - * - * @return true if there are tags, false otherwise. - */ - public final boolean hasTags() - { - return (!tags.isEmpty()); - } + if (mod == '-') { + // Don't remove the channel tag, if any. + if (!tag.getName().equals(channel.substring(1))) { + this.tags.remove(tag); + } + } else if (mod == '+') { + if (!this.tags.contains(tag)) { + this.tags.add(tag); + } + } else { + tag.setName(part.trim().toLowerCase()); - /** - * /** Sets a comment. - * - * @param index The comment's index. - * @param comment The actual comment. - * @param nick The nickname of the author of the comment. - */ - public final void setComment(final int index, final String comment, final String nick) - { - if (index < comments.size()) - { - comments.set(index, new EntryComment(comment, nick)); - } - } + if (!this.tags.contains(tag)) { + this.tags.add(tag); + } + } + } + } + } + } - /** - * Returns a string representation of the object. - * - * @return A string representation of the object. - */ - public final String toString() - { + /** + * Returns a string representation of the object. + * + * @return A string representation of the object. + */ + public final String toString() { - return super.toString() + "[ channel -> '" + channel + '\'' + ", comments -> " + comments + ", date -> " + date - + ", link -> '" + link + '\'' + ", login -> '" + login + '\'' + ", nick -> '" + nick + '\'' - + ", tags -> " + tags + ", title -> '" + title + '\'' + " ]"; - } + return super.toString() + "[ channel -> '" + channel + '\'' + ", comments -> " + comments + ", date -> " + date + + ", link -> '" + link + '\'' + ", login -> '" + login + '\'' + ", nick -> '" + nick + '\'' + + ", tags -> " + tags + ", title -> '" + title + '\'' + " ]"; + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/FeedReader.java b/src/main/java/net/thauvin/erik/mobibot/FeedReader.java index 8a7058d..ee8b4a5 100644 --- a/src/main/java/net/thauvin/erik/mobibot/FeedReader.java +++ b/src/main/java/net/thauvin/erik/mobibot/FeedReader.java @@ -48,76 +48,67 @@ import java.util.List; * @created Feb 1, 2004 * @since 1.0 */ -class FeedReader implements Runnable -{ - /** - * The maximum number of feed items to display. - */ - private static final int MAX_ITEMS = 5; +class FeedReader implements Runnable { + /** + * The maximum number of feed items to display. + */ + private static final int MAX_ITEMS = 5; - /** - * The tab indent (4 spaces). - */ - private static final String TAB_INDENT = " "; + /** + * The tab indent (4 spaces). + */ + private static final String TAB_INDENT = " "; - /** - * The bot. - */ - private final Mobibot bot; + /** + * The bot. + */ + private final Mobibot bot; - /** - * The nick of the person who sent the message. - */ - private final String sender; + /** + * The nick of the person who sent the message. + */ + private final String sender; - /** - * The URL to fetch. - */ - private final String url; + /** + * The URL to fetch. + */ + private final String url; - /** - * Creates a new {@link FeedReader} instance. - * - * @param bot The bot's instance. - * @param sender The nick of the person who sent the message. - * @param url The URL to fetch. - */ - public FeedReader(final Mobibot bot, final String sender, final String url) - { - this.bot = bot; - this.sender = sender; - this.url = url; - } + /** + * Creates a new {@link FeedReader} instance. + * + * @param bot The bot's instance. + * @param sender The nick of the person who sent the message. + * @param url The URL to fetch. + */ + public FeedReader(final Mobibot bot, final String sender, final String url) { + this.bot = bot; + this.sender = sender; + this.url = url; + } - /** - * Fetches the Feed's items. - */ - public final void run() - { - try - { - final SyndFeedInput input = new SyndFeedInput(); - final SyndFeed feed = input.build(new XmlReader(new URL(url))); + /** + * Fetches the Feed's items. + */ + public final void run() { + try { + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new XmlReader(new URL(url))); - SyndEntry item; - final List items = feed.getEntries(); + SyndEntry item; + final List items = feed.getEntries(); - for (int i = 0; (i < items.size()) && (i < MAX_ITEMS); i++) - { - item = (SyndEntryImpl) items.get(i); - bot.send(sender, item.getTitle()); - bot.send(sender, TAB_INDENT + Utils.green(item.getLink())); - } - } - catch (MalformedURLException e) - { - bot.getLogger().debug("Invalid feed URL.", e); - bot.send(sender, "The feed URL is invalid."); - } - catch (Exception e) - { - bot.getLogger().debug("Unable to fetch the feed.", e); - bot.send(sender, "An error has occurred while fetching the feed: " + e.getMessage()); - } - } + for (int i = 0; (i < items.size()) && (i < MAX_ITEMS); i++) { + item = (SyndEntryImpl) items.get(i); + bot.send(sender, item.getTitle()); + bot.send(sender, TAB_INDENT + Utils.green(item.getLink())); + } + } catch (MalformedURLException e) { + bot.getLogger().debug("Invalid feed URL.", e); + bot.send(sender, "The feed URL is invalid."); + } catch (Exception e) { + bot.getLogger().debug("Unable to fetch the feed.", e); + bot.send(sender, "An error has occurred while fetching the feed: " + e.getMessage()); + } + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java index 5cf86ef..4eb851d 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java +++ b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java @@ -53,2055 +53,1684 @@ import java.util.*; * @since 1.0 */ @Version(properties = "version.properties", className = "ReleaseInfo") -public class Mobibot extends PircBot -{ - /** - * The connect/read timeout in ms. - */ - public static final int CONNECT_TIMEOUT = 5000; - - /** - * The empty title string. - */ - static final String NO_TITLE = "No Title"; - - /** - * The default port. - */ - private static final int DEFAULT_PORT = 6667; - - /** - * The info strings. - */ - private static final String[] INFO_STRS = { - ReleaseInfo.getProject() + " v" + ReleaseInfo.getVersion() + " by Erik C. Thauvin (erik@thauvin.net)", - "http://www.mobitopia.org/mobibot/" - }; - - /** - * The link match string. - */ - private static final String LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*"; - - /** - * The default maximum number of entries to display. - */ - private static final int MAX_ENTRIES = 8; - - /** - * The default maximum recap entries. - */ - private static final int MAX_RECAP = 10; - - /** - * The maximum number of times the bot will try to reconnect, if disconnected. - */ - private static final int MAX_RECONNECT = 10; - - /** - * The number of milliseconds to delay between consecutive messages. - */ - private static final long MESSAGE_DELAY = 1000L; - - /** - * The modules. - */ - private static final List MODULES = new ArrayList<>(0); - - /** - * The start time. - */ - private static final long START_TIME = System.currentTimeMillis(); - - /** - * The tags/categories marker. - */ - private static final String TAGS_MARKER = "tags:"; - - /** - * The version strings. - */ - private static final String[] VERSION_STRS = { - "Version: " - + ReleaseInfo.getVersion() - + " (" - + Utils.ISO_SDF.format(ReleaseInfo.getBuildDate()) + ')', - "Platform: " - + System.getProperty("os.name") - + " (" - + System.getProperty("os.version") - + ", " - + System.getProperty("os.arch") - + ", " - + System.getProperty("user.country") + ')', - "Runtime: " - + System.getProperty("java.runtime.name") - + " (build " - + System.getProperty("java.runtime.version") - + ')', - "VM: " - + System.getProperty("java.vm.name") - + " (build " - + System.getProperty("java.vm.version") - + ", " - + System.getProperty("java.vm.info") - + ')' - }; - - /** - * The tell object. - */ - private static Tell tell; - - /** - * The main channel. - */ - private final String channel; - - /** - * The commands list. - */ - private final List commandsList = new ArrayList<>(); - - /** - * The entries array. - */ - private final List entries = new ArrayList<>(0); - - /** - * The history/backlogs array. - */ - private final List history = new ArrayList<>(0); - - /** - * The ignored nicks array. - */ - private final List ignoredNicks = new ArrayList<>(0); - - /** - * The IRC port. - */ - private final int ircPort; - - /** - * The IRC server. - */ - private final String ircServer; - - /** - * The logger. - */ - private final Log4JLogger logger = new Log4JLogger(Mobibot.class.getPackage().getName()); - - /** - * The logger default level. - */ - private final Level loggerLevel; - - /** - * The log directory. - */ - private final String logsDir; - - /** - * The recap array. - */ - private final List recap = new ArrayList<>(0); - - /** - * The backlogs URL. - */ - private String backLogsUrl = ""; - - /** - * The default tags/categories. - */ - private String defaultTags = ""; - - /** - * The del.icio.us posts handler. - */ - private DeliciousPoster delicious = null; - - /** - * The feed URL. - */ - private String feedURL = ""; - - /** - * The ident message. - */ - private String identMsg = ""; - - /** - * The ident nick. - */ - private String identNick = ""; - - /** - * The NickServ ident password. - */ - private String identPwd = ""; - - /** - * Today's date. - */ - private String today = Utils.today(); - - /** - * The weblog URL. - */ - private String weblogUrl = ""; - - /** - * Creates a new {@link Mobibot} instance. - * - * @param server The server. - * @param port The port. - * @param nickname The nickname. - * @param channel The channel. - * @param logsDir The logs directory. - */ - @SuppressWarnings("WeakerAccess") - public Mobibot(final String server, - final int port, - final String nickname, - final String channel, - final String logsDir) - { - System.getProperties().setProperty("sun.net.client.defaultConnectTimeout", String.valueOf(CONNECT_TIMEOUT)); - System.getProperties().setProperty("sun.net.client.defaultReadTimeout", String.valueOf(CONNECT_TIMEOUT)); - - setName(nickname); - - ircServer = server; - ircPort = port; - this.channel = channel; - this.logsDir = logsDir; - - // Set the logger level - loggerLevel = logger.getLogger().getLevel(); - - // Initialization - Utils.UTC_SDF.setTimeZone(TimeZone.getTimeZone("UTC")); - - // Load the current entries, if any. - try - { - today = EntriesMgr.loadEntries(this.logsDir + EntriesMgr.CURRENT_XML, this.channel, entries); - - if (logger.isDebugEnabled()) - { - logger.debug("Last feed: " + today); - } - - if (!Utils.today().equals(today)) - { - entries.clear(); - today = Utils.today(); - } - } - catch (IOException ignore) - { - ; // Do nothing. - } - catch (FeedException e) - { - logger.error("An error occurred while parsing the '" + EntriesMgr.CURRENT_XML + "' file.", e); - } - - // Load the backlogs, if any. - try - { - EntriesMgr.loadBacklogs(this.logsDir + EntriesMgr.NAV_XML, history); - } - catch (IOException ignore) - { - ; // Do nothing. - } - catch (FeedException e) - { - logger.error("An error occurred while parsing the '" + EntriesMgr.NAV_XML + "' file.", e); - } - - // Load the modules - MODULES.add(new Calc()); - MODULES.add(new CurrencyConverter()); - MODULES.add(new Dice()); - MODULES.add(new GoogleSearch()); - MODULES.add(new Joke()); - MODULES.add(new Lookup()); - MODULES.add(new Ping()); - MODULES.add(new StockQuote()); - MODULES.add(new Twitter()); - MODULES.add(new War()); - MODULES.add(new Weather()); - MODULES.add(new WorldTime()); - } - - /** - * The Truth Is Out There... - * - * @param args The command line arguments. - */ - public static void main(final String[] args) - { - // Setup the command line options - final Options options = new Options(); - options.addOption(Commands.HELP_ARG.substring(0, 1), Commands.HELP_ARG, false, "print this help message"); - options.addOption(Commands.DEBUG_ARG.substring(0, 1), Commands.DEBUG_ARG, false, - "print debug & logging data directly to the console"); - options.addOption(Option.builder( - Commands.PROPS_ARG.substring(0, 1)).hasArg().argName("file").desc("use " + "alternate properties file") - .longOpt(Commands.PROPS_ARG).build()); - options.addOption(Commands.VERSION_ARG.substring(0, 1), Commands.VERSION_ARG, false, "print version info"); - - // Parse the command line - final CommandLineParser parser = new DefaultParser(); - CommandLine line = null; - - try - { - line = parser.parse(options, args); - } - catch (ParseException e) - { - System.err.println("CLI Parsing failed. Reason: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - - if (line.hasOption(Commands.HELP_ARG.charAt(0))) - { - // Output the usage - new HelpFormatter().printHelp(Mobibot.class.getName(), options); - } - else if (line.hasOption(Commands.VERSION_ARG.charAt(0))) - { - for (final String s : INFO_STRS) - { - System.out.println(s); - } - } - else - { - final Properties p = new Properties(); - - try (final FileInputStream fis = new FileInputStream( - new File(line.getOptionValue(Commands.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); - } - - // Get the main properties - final String channel = p.getProperty("channel"); - final String server = p.getProperty("server"); - final int port = Utils.getIntProperty(p.getProperty("port"), DEFAULT_PORT); - final String nickname = p.getProperty("nick", Mobibot.class.getName().toLowerCase()); - final String logsDir = Utils.ensureDir(p.getProperty("logs", "."), false); - - if (!line.hasOption(Commands.DEBUG_ARG.charAt(0))) - { - // Redirect the stdout and stderr - PrintStream stdout = null; - - try - { - stdout = new PrintStream(new FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true)); - } - catch (IOException e) - { - System.err.println("Unable to open output (stdout) log file."); - e.printStackTrace(System.err); - System.exit(1); - } - - PrintStream stderr = null; - - try - { - stderr = new PrintStream(new FileOutputStream(logsDir + nickname + ".err", true)); - } - catch (IOException e) - { - System.err.println("Unable to open error (stderr) log file."); - e.printStackTrace(System.err); - System.exit(1); - } - - System.setOut(stdout); - System.setErr(stderr); - } - - // Get the bot's properties - final String login = p.getProperty("login", nickname); - final String weblogURL = p.getProperty("weblog", ""); - final String feedURL = p.getProperty("feed", ""); - final String backlogsURL = Utils.ensureDir(p.getProperty("backlogs", weblogURL), true); - final String ignoredNicks = p.getProperty("ignore", ""); - final String identNick = p.getProperty("ident-nick", ""); - final String identMsg = p.getProperty("ident-msg", ""); - final String identPwd = p.getProperty("ident", ""); - final String tags = p.getProperty("tags", ""); - - // Get the del.icio.us properties - final String dname = p.getProperty("delicious-user"); - final String dpwd = p.getProperty("delicious-pwd"); - - // Create the bot - final Mobibot bot = new Mobibot(server, port, nickname, channel, logsDir); - - // Get the tell command settings - tell = new Tell(bot, p.getProperty("tell-max-days"), p.getProperty("tell-max-size")); - - // Initialize the bot - bot.setVerbose(true); - bot.setAutoNickChange(true); - bot.setLogin(login); - bot.setVersion(weblogURL); - bot.setMessageDelay(MESSAGE_DELAY); - bot.setIdentity(identPwd, identNick, identMsg); - - // Set the URLs - bot.setWeblogUrl(weblogURL); - bot.setFeedURL(feedURL); - bot.setBacklogsUrl(backlogsURL); - - // Set the del.icio.us authentication - bot.setDeliciousAuth(dname, dpwd); - - // Load the modules properties - MODULES.stream().filter(AbstractModule::hasProperties).forEach( - module -> - { - for (final String s : module.getPropertyKeys()) - { - module.setProperty(s, p.getProperty(s, "")); - } - }); - - // Set the tags - bot.setTags(tags); - - // Set the ignored nicks - bot.setIgnoredNicks(ignoredNicks); - - // Save the entries - bot.saveEntries(true); - - // Connect - try - { - bot.connect(server, port); - } - catch (Exception e) - { - int retries = 0; - - while ((retries++ < MAX_RECONNECT) && !bot.isConnected()) - { - sleep(10); - - try - { - bot.connect(server, port); - } - catch (Exception ignore) - { - if (retries == MAX_RECONNECT) - { - System.err.println( - "Unable to connect to " + server + " after " + MAX_RECONNECT + " retries."); - e.printStackTrace(System.err); - System.exit(1); - } - } - } - } - - bot.setVersion(INFO_STRS[0]); - - bot.identify(); - - bot.joinChannel(channel); - } - } - - /** - * Sleeps for the specified number of seconds. - * - * @param secs The number of seconds to sleep for. - */ - private static void sleep(final int secs) - { - try - { - Thread.sleep((long) (secs * 1000)); - } - catch (InterruptedException ignore) - { - ; // Do nothing - } - } - - /** - * Sends an action to the current channel. - * - * @param action The action. - */ - final public void action(final String action) - { - action(channel, 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 (Utils.isValidString(channel) && Utils.isValidString(action)) - { - sendAction(channel, action); - } - } - - /** - * Responds with the title and links from the RSS feed. - * - * @param sender The nick of the person who sent the private message. - */ - private void feedResponse(final String sender) - { - if (Utils.isValidString(feedURL)) - { - new Thread(new FeedReader(this, sender, feedURL)).start(); - } - else - { - send(sender, "There is no weblog setup for this channel."); - } - } - - /** - * Returns the index of the specified duplicate entry, if any. - * - * @param link The link. - * - * @return The index or -1 if none. - */ - private int findDupEntry(final String link) - { - synchronized (entries) - { - for (int i = 0; i < entries.size(); i++) - { - if (link.equals(entries.get(i).getLink())) - { - return i; - } - } - } - - return -1; - } - - /** - * Returns the backlogs URL. - * - * @return The backlogs URL. - */ - public final String getBacklogsUrl() - { - return this.backLogsUrl; - } - - /** - * Sets the backlogs URL. - * - * @param backLogsUrl The backlogs URL. - */ - private void setBacklogsUrl(final String backLogsUrl) - { - this.backLogsUrl = backLogsUrl; - } - - /** - * Returns the current channel. - * - * @return The current channel. - */ - public final String getChannel() - { - return channel; - } - - /** - * Returns the irc server. - * - * @return The irc server. - */ - public final String getIrcServer() - { - return this.ircServer; - } - - /** - * Returns the bot's logger. - * - * @return The bot's logger. - */ - public final Log4JLogger getLogger() - { - return logger; - } - - /** - * Returns the log directory. - * - * @return the log directory. - */ - public final String getLogsDir() - { - return this.logsDir; - } - - /** - * Returns the bot's nickname regexp pattern. - * - * @return The nickname regexp pattern. - */ - private String getNickPattern() - { - final StringBuilder buff = new StringBuilder(0); - - for (final char c : getNick().toCharArray()) - { - if (Character.isLetter(c)) - { - buff.append('[') - .append(String.valueOf(c).toLowerCase()) - .append(String.valueOf(c).toUpperCase()) - .append(']'); - } - else - { - buff.append(c); - } - } - - return buff.toString(); - } - - /** - * Get today's date for the feed. - * - * @return Today's date. - */ - public String getToday() - { - return this.today; - } - - /** - * Returns the weblog URL. - * - * @return The weblog URL. - */ - public final String getWeblogUrl() - { - return this.weblogUrl; - } - - /** - * Sets the weblog URL. - * - * @param weblogUrl The weblog URL. - */ - private void setWeblogUrl(final String weblogUrl) - { - this.weblogUrl = weblogUrl; - } - - /** - * Returns indented and bold help string. - * - * @param help The help string. - * - * @return The indented help string. - */ - final public String helpIndent(final String help) - { - return helpIndent(help, true); - } - - /** - * Returns indented help string. - * - * @param help The help string. - * @param isBold The bold flag. - * - * @return The indented help string. - */ - public String helpIndent(final String help, final boolean isBold) - { - return " " + (isBold ? Utils.bold(help) : help); - } - - /** - * Responds with the bot's help. - * - * @param sender The nick of the person who sent the private message. - * @param topic The help topic, if any. - */ - private void helpResponse(final String sender, final String topic) - { - final String lcTopic = topic.toLowerCase().trim(); - - if (lcTopic.equals(Commands.HELP_POSTING_KEYWORD)) - { - send(sender, Utils.bold("Post a URL, by saying it on a line on its own:")); - send(sender, helpIndent(" [] [" + TAGS_MARKER + "<+tag> [...]]")); - send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + '1')); - send(sender, "To add a title, use a its label and a pipe:"); - send(sender, helpIndent(Commands.LINK_CMD + "1:|This is the title")); - send(sender, "To add a comment: "); - send(sender, helpIndent(Commands.LINK_CMD + "1:This is a comment")); - send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + "1.1")); - send(sender, "To edit a comment, use its label: "); - send(sender, helpIndent(Commands.LINK_CMD + "1.1:This is an edited comment")); - send(sender, "To delete a comment, use its label and a minus sign: "); - send(sender, helpIndent(Commands.LINK_CMD + "1.1:-")); - send(sender, "You can also view a posting by saying its label."); - } - else if (lcTopic.equals(Commands.HELP_TAGS_KEYWORD)) - { - send(sender, Utils.bold("To categorize or tag a URL, use its label and a T:")); - send(sender, helpIndent(Commands.LINK_CMD + "1T:<+tag|-tag> [...]")); - } - else if (lcTopic.equals(Commands.VIEW_CMD)) - { - send(sender, "To list or search the current URL posts:"); - send(sender, helpIndent(getNick() + ": " + Commands.VIEW_CMD) + " [<start>] [<query>]"); - } - else if (lcTopic.equals(channel.substring(1).toLowerCase())) - { - send(sender, "To list the last 5 posts from the channel's weblog:"); - send(sender, helpIndent(getNick() + ": " + channel.substring(1))); - } - else if (lcTopic.equals(Commands.RECAP_CMD)) - { - send(sender, "To list the last 10 public channel messages:"); - send(sender, helpIndent(getNick() + ": " + Commands.RECAP_CMD)); - } - else if (lcTopic.equals(Commands.USERS_CMD)) - { - send(sender, "To list the users present on the channel:"); - send(sender, helpIndent(getNick() + ": " + Commands.USERS_CMD)); - } - else if (lcTopic.equals(Commands.INFO_CMD)) - { - send(sender, "To view information about the bot:"); - send(sender, helpIndent(getNick() + ": " + Commands.INFO_CMD)); - } - else if (lcTopic.equals(Commands.CYCLE_CMD) && isOp(sender)) - { - send(sender, "To have the bot leave the channel and come back:"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.CYCLE_CMD)); - } - else if (lcTopic.equals(Commands.ME_CMD) && isOp(sender)) - { - send(sender, "To have the bot perform an action:"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.ME_CMD + " <action>")); - } - else if (lcTopic.equals(Commands.SAY_CMD) && isOp(sender)) - { - send(sender, "To have the bot say something on the channel:"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.SAY_CMD + " <text>")); - } - else if (lcTopic.equals(Commands.VERSION_CMD) && isOp(sender)) - { - send(sender, "To view the version data (bot, java, etc.):"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.VERSION_CMD)); - } - else if (lcTopic.equals(Commands.MSG_CMD) && isOp(sender)) - { - send(sender, "To have the bot send a private message to someone:"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.MSG_CMD + " <nick> <text>")); - } - else if (lcTopic.equals(Commands.IGNORE_CMD)) - { - send(sender, "To check your ignore status:"); - send(sender, helpIndent(getNick() + ": " + Commands.IGNORE_CMD)); - - send(sender, "To toggle your ignore status:"); - send(sender, helpIndent(getNick() + ": " + Commands.IGNORE_CMD + ' ' + Commands.IGNORE_ME_KEYWORD)); - } - else if (lcTopic.equals(Tell.TELL_CMD) && tell.isEnabled()) - { - tell.helpResponse(sender); - } - else - { - for (final AbstractModule module : MODULES) - { - for (final String cmd : module.getCommands()) - { - if (lcTopic.equals(cmd)) - { - module.helpResponse(this, sender, topic, true); - return; - } - } - } - - send(sender, Utils.bold("Type a URL on " + channel + " to post it.")); - send(sender, "For more information on a specific command, type:"); - send(sender, helpIndent(getNick() + ": " + Commands.HELP_CMD + " <command>")); - send(sender, "The commands are:"); - - if (commandsList.isEmpty()) - { - commandsList.add(Commands.IGNORE_CMD); - commandsList.add(Commands.INFO_CMD); - commandsList.add(channel.substring(1)); - commandsList.add(Commands.HELP_POSTING_KEYWORD); - commandsList.add(Commands.HELP_TAGS_KEYWORD); - commandsList.add(Commands.RECAP_CMD); - commandsList.add(Commands.USERS_CMD); - commandsList.add(Commands.VIEW_CMD); - - MODULES.stream().filter(AbstractModule::isEnabled).forEach( - module -> commandsList.addAll(module.getCommands())); - - if (tell.isEnabled()) - { - commandsList.add(Tell.TELL_CMD); - } - - Collections.sort(commandsList); - } - - final StringBuilder sb = new StringBuilder(0); - - for (int i = 0, cmdCount = 1; i < commandsList.size(); i++, cmdCount++) - { - if (sb.length() > 0) - { - sb.append(" "); - } - - sb.append(commandsList.get(i)); - - // 6 commands per line or last command - if (sb.length() > 0 && (cmdCount == 6 || i == (commandsList.size() - 1))) - { - send(sender, helpIndent(sb.toString())); - - sb.setLength(0); - cmdCount = 0; - } - } - - if (isOp(sender)) - { - send(sender, "The op commands are:"); - send(sender, helpIndent( - Commands.CYCLE_CMD + " " - + Commands.ME_CMD + " " - + Commands.MSG_CMD + " " - + Commands.SAY_CMD + " " - + Commands.VERSION_CMD)); - } - } - } - - /** - * Identifies the bot. - */ - private void identify() - { - // Identify with NickServ - if (Utils.isValidString(identPwd)) - { - identify(identPwd); - } - - // Identify with a specified nick - if (Utils.isValidString(identNick) && Utils.isValidString(identMsg)) - { - sendMessage(identNick, identMsg); - } - } - - /** - * Processes the {@link net.thauvin.erik.mobibot.Commands#IGNORE_CMD} command. - * - * @param sender The sender. - * @param args The command arguments. - */ - private void ignoreResponse(final String sender, final String args) - { - if (!isOp(sender)) - { - final String nick = sender.toLowerCase(); - final boolean isMe = args.toLowerCase().startsWith(Commands.IGNORE_ME_KEYWORD); - - if (ignoredNicks.contains(nick)) - { - if (isMe) - { - ignoredNicks.remove(nick); - - send(sender, "You are no longer ignored."); - } - else - { - send(sender, "You are currently ignored."); - } - } - else - { - if (isMe) - { - ignoredNicks.add(nick); - - send(sender, "You are now ignored."); - } - else - { - send(sender, "You are not currently ignored."); - } - } - } - else - { - if (args.length() > 0) - { - final String[] nicks = args.toLowerCase().split(" "); - - for (final String nick : nicks) - { - final String ignore; - - if (Commands.IGNORE_ME_KEYWORD.equals(nick)) - { - ignore = sender.toLowerCase(); - } - else - { - ignore = nick; - } - - if (ignoredNicks.contains(ignore)) - { - ignoredNicks.remove(ignore); - } - else - { - ignoredNicks.add(ignore); - } - } - } - - send(sender, "The following nicks are ignored: " + ignoredNicks.toString()); - } - } - - /** - * Responds with the bot's information. - * - * @param sender The nick of the person who sent the message. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - private void infoResponse(final String sender, final boolean isPrivate) - { - for (final String info : INFO_STRS) - { - if (info.startsWith("http://")) - { - send(sender, Utils.green(info), isPrivate); - } - else - { - send(sender, info, isPrivate); - } - } - - final StringBuilder info = new StringBuilder("Uptime: "); - - long timeInSeconds = (System.currentTimeMillis() - START_TIME) / 1000L; - - final long years = timeInSeconds / 31540000L; - - if (years > 0) - { - info.append(years).append(Utils.plural(years, " year ", " years ")); - timeInSeconds -= (years * 31540000L); - } - - final long weeks = timeInSeconds / 604800L; - - if (weeks > 0) - { - info.append(weeks).append(Utils.plural(weeks, " week ", " weeks ")); - timeInSeconds -= (weeks * 604800L); - } - - final long days = timeInSeconds / 86400L; - - if (days > 0) - { - info.append(days).append(Utils.plural(days, " day ", " days ")); - timeInSeconds -= (days * 86400L); - } - - final long hours = timeInSeconds / 3600L; - - if (hours > 0) - { - info.append(hours).append(Utils.plural(hours, " hour ", " hours ")); - timeInSeconds -= (hours * 3600L); - } - - final long minutes = timeInSeconds / 60L; - - info.append(minutes).append(Utils.plural(minutes, " minute ", " minutes ")); - - info.append("[Entries: ").append(entries.size()); - - if (tell.isEnabled() && isOp(sender)) - { - info.append(", Messages: ").append(tell.size()); - } - - info.append(']'); - - send(sender, info.toString(), isPrivate); - } - - /** - * Determines whether the specified nick should be ignored. - * - * @param nick The nick. - * - * @return <code>true</code> if the nick should be ignored, <code>false</code> otherwise. - */ - private boolean isIgnoredNick(final String nick) - { - return Utils.isValidString(nick) && ignoredNicks.contains(nick.toLowerCase()); - } - - /** - * Returns <code>true</code> if the specified sender is an Op on the {@link #channel channel}. - * - * @param sender The sender. - * - * @return true, if the sender is an Op. - */ - public boolean isOp(final String sender) - { - final User[] users = getUsers(channel); - - for (final User user : users) - { - if (user.getNick().equals(sender)) - { - return user.isOp(); - } - } - - return false; - } - - @Override - protected final void onAction(final String sender, - final String login, - final String hostname, - final String target, - final String action) - { - if (target.equals(channel)) - { - storeRecap(sender, action, true); - } - } - - @Override - protected final void onDisconnect() - { - if (Utils.isValidString(weblogUrl)) - { - setVersion(weblogUrl); - } - - sleep(5); - - // 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) - { - if (logger.isDebugEnabled()) - { - logger.debug( - "Unable to reconnect to " + ircServer + " after " + MAX_RECONNECT + " retries.", - ex); - } - - e.printStackTrace(System.err); - System.exit(1); - } - } - } - } - - setVersion(INFO_STRS[0]); - - identify(); - - joinChannel(channel); - } - - @Override - protected void onJoin(final String channel, final String sender, final String login, final String hostname) - { - tell.send(sender); - } - - @Override - protected final void onMessage(final String channel, - final String sender, - final String login, - final String hostname, - final String message) - { - if (logger.isDebugEnabled()) - { - logger.debug(">>> " + sender + ": " + message); - } - - boolean isCommand = false; - - // Capture URLs posted on the channel - if (message.matches(LINK_MATCH) && !isIgnoredNick(sender)) - { - isCommand = true; - - final String[] cmds = message.split(" ", 2); - - if (cmds.length == 1 || (!cmds[1].contains(getNick()))) - { - final String link = cmds[0].trim(); - boolean isBackup = false; - - final int dupIndex = findDupEntry(link); - - if (dupIndex == -1) - { - if (!Utils.today().equals(today)) - { - isBackup = true; - saveEntries(true); - - entries.clear(); - today = Utils.today(); - } - - final StringBuilder tags = new StringBuilder(defaultTags); - String title = NO_TITLE; - - if (cmds.length == 2) - { - final String[] data = cmds[1].trim().split(TAGS_MARKER, 2); - - if (data.length == 1) - { - title = data[0].trim(); - } - else - { - if (Utils.isValidString(data[0])) - { - title = data[0].trim(); - } - - tags.append(' ').append(data[1].trim()); - } - } - - if (NO_TITLE.equals(title)) - { - try - { - final Document html = Jsoup.connect(link).userAgent("Mozilla").get(); - final String htmlTitle = html.title(); - - if (Utils.isValidString(htmlTitle)) - { - title = htmlTitle; - } - } - catch (IOException ignore) - { - // Do nothing - } - } - - entries.add(new EntryLink(link, title, sender, login, channel, tags.toString())); - - final int index = entries.size() - 1; - final EntryLink entry = entries.get(index); - send(channel, Utils.buildLink(index, entry)); - - if (delicious != null) - { - delicious.addPost(entry); - } - - saveEntries(isBackup); - - if (NO_TITLE.equals(entry.getTitle())) - { - send(sender, "Please specify a title, by typing:", true); - send(sender, helpIndent(Commands.LINK_CMD + (index + 1) + ":|This is the title"), true); - } - } - else - { - final EntryLink entry = entries.get(dupIndex); - send(sender, "Duplicate >> " + Utils.buildLink(dupIndex, entry)); - } - } - } - // mobibot: <command> - else if (message.matches(getNickPattern() + ":.*")) - { - isCommand = true; - - final String[] cmds = message.substring(message.indexOf(':') + 1).trim().split(" ", 2); - final String cmd = cmds[0].toLowerCase(); - - String args = ""; - - if (cmds.length > 1) - { - args = cmds[1].trim(); - } - - // mobibot: help - if (cmd.startsWith(Commands.HELP_CMD)) - { - helpResponse(sender, args); - } - // mobibot: recap - else if (cmd.equals(Commands.RECAP_CMD)) - { - recapResponse(sender, false); - } - // mobibot: users - else if (cmd.equals(Commands.USERS_CMD)) - { - usersResponse(sender, false); - } - // mobibot: info - else if (cmd.equals(Commands.INFO_CMD)) - { - infoResponse(sender, false); - } - // mobbiot: version - else if (cmd.equals(Commands.VERSION_CMD)) - { - versionResponse(sender, false); - } - // mobibot: <channel> - else if (cmd.equalsIgnoreCase(channel.substring(1))) - { - feedResponse(sender); - } - // mobibot: view - else if (cmd.startsWith(Commands.VIEW_CMD)) - { - viewResponse(sender, args, false); - } - // mobibot: tell - else if (cmd.startsWith(Tell.TELL_CMD) && tell.isEnabled()) - { - tell.response(sender, args); - } - // mobibot: ignore - else if (cmd.startsWith(Commands.IGNORE_CMD)) - { - ignoreResponse(sender, args); - } - // modules - else - { - for (final AbstractModule module : MODULES) - { - for (final String c : module.getCommands()) - { - if (cmd.startsWith(c)) - { - module.commandResponse(this, sender, args, false); - } - } - } - } - } - // L1:<comment>, L1:-, L1:|<title>, etc. - else if (message.matches(Commands.LINK_CMD + "[0-9]+:.*")) - { - isCommand = true; - - final String[] cmds = message.substring(1).split(":", 2); - final int index = Integer.parseInt(cmds[0]) - 1; - - // L1:<comment> - if (index < entries.size()) - { - final String cmd = cmds[1].trim(); - - if (cmd.length() == 0) - { - final EntryLink entry = entries.get(index); - send(channel, Utils.buildLink(index, entry)); - - if (entry.hasTags()) - { - send(channel, Utils.buildTags(index, entry)); - } - - if (entry.hasComments()) - { - final EntryComment[] comments = entry.getComments(); - - for (int i = 0; i < comments.length; i++) - { - send(channel, Utils.buildComment(index, i, comments[i])); - } - } - } - else - { - // L1:- - if ("-".equals(cmd)) - { - final EntryLink entry = entries.get(index); - - if (entry.getLogin().equals(login) || isOp(sender)) - { - if (delicious != null) - { - delicious.deletePost(entry); - } - - entries.remove(index); - send(channel, "Entry " + Commands.LINK_CMD + (index + 1) + " removed."); - saveEntries(false); - } - else - { - send(sender, "Please ask a channel op to remove this entry for you."); - } - } - // L1:|<title> - else if (cmd.charAt(0) == '|') - { - if (cmd.length() > 1) - { - final EntryLink entry = entries.get(index); - entry.setTitle(cmd.substring(1).trim()); - - if (delicious != null) - { - delicious.updatePost(entry.getLink(), entry); - } - - send(channel, Utils.buildLink(index, entry)); - saveEntries(false); - } - } - // L1:=<url> - else if (cmd.charAt(0) == '=') - { - final EntryLink entry = entries.get(index); - - if (entry.getLogin().equals(login) || isOp(sender)) - { - final String link = cmd.substring(1); - - if (link.matches(LINK_MATCH)) - { - final String oldLink = entry.getLink(); - - entry.setLink(link); - - if (delicious != null) - { - delicious.updatePost(oldLink, entry); - } - - send(channel, Utils.buildLink(index, entry)); - saveEntries(false); - } - } - else - { - send(sender, "Please ask a channel op to change this link for you."); - } - } - // L1:?<author> - else if (cmd.charAt(0) == '?') - { - if (isOp(sender)) - { - if (cmd.length() > 1) - { - final EntryLink entry = entries.get(index); - entry.setNick(cmd.substring(1)); - send(channel, Utils.buildLink(index, entry)); - saveEntries(false); - } - } - else - { - send(sender, "Please ask a channel op to change the author of this link for you."); - } - } - else - { - final EntryLink entry = entries.get(index); - final int cindex = entry.addComment(cmd, sender); - - final EntryComment comment = entry.getComment(cindex); - send(sender, Utils.buildComment(index, cindex, comment)); - saveEntries(false); - } - } - } - } - // L1T:<+-tag> - else if (message.matches(Commands.LINK_CMD + "[0-9]+T:.*")) - { - isCommand = true; - - final String[] cmds = message.substring(1).split("T:", 2); - final int index = Integer.parseInt(cmds[0]) - 1; - - if (index < entries.size()) - { - final String cmd = cmds[1].trim(); - - final EntryLink entry = entries.get(index); - - if (cmd.length() != 0) - { - if (entry.getLogin().equals(login) || isOp(sender)) - { - entry.setTags(cmd); - - if (delicious != null) - { - delicious.updatePost(entry.getLink(), entry); - } - - send(channel, Utils.buildTags(index, entry)); - saveEntries(false); - } - else - { - send(sender, "Please ask a channel op to change the tags for you."); - } - } - else - { - if (entry.hasTags()) - { - send(channel, Utils.buildTags(index, entry)); - } - else - { - send(sender, "The entry has no tags. Why don't add some?"); - } - } - } - } - // L1.1:<command> - else if (message.matches(Commands.LINK_CMD + "[0-9]+\\.[0-9]+:.*")) - { - isCommand = true; - - final String[] cmds = message.substring(1).split("[.:]", 3); - final int index = Integer.parseInt(cmds[0]) - 1; - - if (index < entries.size()) - { - final EntryLink entry = entries.get(index); - final int cindex = Integer.parseInt(cmds[1]) - 1; - - if (cindex < entry.getCommentsCount()) - { - final String cmd = cmds[2].trim(); - - // L1.1: - if (cmd.length() == 0) - { - final EntryComment comment = entry.getComment(cindex); - send(channel, Utils.buildComment(index, cindex, comment)); - } - // L1.1:- - else if ("-".equals(cmd)) - { - entry.deleteComment(cindex); - send(channel, "Comment " + Commands.LINK_CMD + (index + 1) + '.' + (cindex + 1) + " removed."); - saveEntries(false); - } - // L1.1:?<author> - else if (cmd.charAt(0) == '?') - { - if (isOp(sender)) - { - if (cmd.length() > 1) - { - final EntryComment comment = entry.getComment(cindex); - comment.setNick(cmd.substring(1)); - send(channel, Utils.buildComment(index, cindex, comment)); - saveEntries(false); - } - } - else - { - send(sender, "Please ask a channel op to change the author of this comment for you."); - } - } - else - { - entry.setComment(cindex, cmd, sender); - - final EntryComment comment = entry.getComment(cindex); - send(sender, Utils.buildComment(index, cindex, comment)); - saveEntries(false); - } - } - } - } - - if (!isCommand) - { - storeRecap(sender, message, false); - } - - tell.send(sender, true); - } - - @Override - protected void onNickChange(final String oldNick, final String login, final String hostname, final String newNick) - { - tell.send(newNick); - } - - @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 = cmds[0].toLowerCase(); - String args = ""; - - if (cmds.length > 1) - { - args = cmds[1].trim(); - } - - if (cmd.startsWith(Commands.HELP_CMD)) - { - helpResponse(sender, args); - } - else if ("kill".equals(cmd) && isOp(sender)) - { - sendRawLine("QUIT : Poof!"); - System.exit(0); - } - else if (cmd.equals(Commands.DIE_CMD) && isOp(sender)) - { - send(channel, sender + " has just signed my death sentence."); - saveEntries(true); - sleep(3); - quitServer("The Bot Is Out There!"); - System.exit(0); - } - else if (cmd.equals(Commands.CYCLE_CMD)) - { - send(channel, sender + " has just asked me to leave. I'll be back!"); - sleep(0); - partChannel(channel); - sleep(10); - joinChannel(channel); - } - else if (cmd.equals(Commands.RECAP_CMD)) - { - recapResponse(sender, true); - } - else if (cmd.equals(Commands.USERS_CMD)) - { - usersResponse(sender, true); - } - else if (cmd.equals(Commands.ADDLOG_CMD) && (cmds.length > 1) && isOp(sender)) - { - // e.g. 2014-04-01 - final File backlog = new File(logsDir + args + EntriesMgr.XML_EXT); - if (backlog.exists()) - { - history.add(0, args); - send(sender, history.toString(), true); - } - else - { - send(sender, "The specified log could not be found."); - } - } - else if (cmd.equals(Commands.ME_CMD) && isOp(sender)) - { - if (args.length() > 1) - { - action(args); - } - else - { - helpResponse(sender, Commands.ME_CMD); - } - } - else if (cmd.equals(Commands.NICK_CMD) && (cmds.length > 1)) - { - if (isOp(sender)) - { - changeNick(args); - } - } - else if (cmd.equals(Commands.SAY_CMD) && isOp(sender)) - { - if (cmds.length > 1) - { - send(channel, args, true); - } - else - { - helpResponse(sender, Commands.SAY_CMD); - } - } - else if (cmd.equals(Commands.MSG_CMD) && isOp(sender)) - { - if (cmds.length > 1) - { - final String[] msg = args.split(" ", 2); - - if (args.length() > 2) - { - send(msg[0], msg[1], true); - } - else - { - helpResponse(sender, Commands.MSG_CMD); - } - } - else - { - helpResponse(sender, Commands.MSG_CMD); - } - } - else if (cmd.equals(Commands.VIEW_CMD)) - { - viewResponse(sender, args, true); - } - else if (cmd.equals(Tell.TELL_CMD) && tell.isEnabled()) - { - tell.response(sender, args); - } - else if (cmd.equals(Commands.INFO_CMD)) - { - infoResponse(sender, true); - } - else if (cmd.equals(Commands.VERSION_CMD)) - { - versionResponse(sender, true); - } - else if (cmd.equals(Commands.DEBUG_CMD) && isOp(sender)) - { - if (logger.isDebugEnabled()) - { - logger.getLogger().setLevel(loggerLevel); - } - else - { - logger.getLogger().setLevel(Level.DEBUG); - } - - send(sender, "Debug logging is " + (logger.isDebugEnabled() ? "enabled." : "disabled."), true); - } - else - { - for (final AbstractModule module : MODULES) - { - if (module.isPrivateMsgEnabled()) - { - for (final String c : module.getCommands()) - { - if (cmd.equals(c)) - { - module.commandResponse(this, sender, args, true); - return; - } - } - } - } - - helpResponse(sender, ""); - } - } - - /** - * Responds with the last 10 public messages. - * - * @param sender The nick of the person who sent the private message. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - private void recapResponse(final String sender, final boolean isPrivate) - { - for (final String recap : this.recap) - { - send(sender, recap, isPrivate); - } - } - - /** - * Saves the entries. - * - * @param isDayBackup Set the <code>true</code> if the daily backup file should also be created. - */ - private void saveEntries(final boolean isDayBackup) - { - EntriesMgr.saveEntries(this, entries, history, isDayBackup); - } - - /** - * Sends a private message or notice. - * - * @param sender The 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 (Utils.isValidString(message) && Utils.isValidString(sender)) - { - if (isPrivate) - { - if (logger.isDebugEnabled()) - { - logger.debug("Sending message to " + sender + ": " + message); - } - - sendMessage(sender, message); - } - else - { - if (logger.isDebugEnabled()) - { - logger.debug("Sending notice to " + sender + ": " + message); - } - - sendNotice(sender, message); - } - } - } - - /** - * Sends a private notice. - * - * @param sender The nick of the person who sent the message. - * @param message The actual message. - */ - public final void send(final String sender, final String message) - { - send(sender, message, false); - } - - /** - * Sets the del.icio.us authentication. - * - * @param username The del.icio.us user name. - * @param password The del.icio.us password. - */ - private void setDeliciousAuth(final String username, final String password) - { - if (Utils.isValidString(username) && Utils.isValidString(password)) - { - delicious = new DeliciousPoster(username, password, ircServer); - } - } - - /** - * Sets the feed URL. - * - * @param feedURL The feed URL. - */ - private void setFeedURL(final String feedURL) - { - this.feedURL = feedURL; - } - - /** - * Sets the bot's identification. - * - * @param identPwd The password for NickServ, if any. - * @param identNick The ident nick name. - * @param identMsg The ident message. - */ - private void setIdentity(final String identPwd, final String identNick, final String identMsg) - { - this.identPwd = identPwd; - this.identNick = identNick; - this.identMsg = identMsg; - } - - /** - * Sets the Ignored nicks. - * - * @param nicks The nicks to ignore - */ - private void setIgnoredNicks(final String nicks) - { - if (Utils.isValidString(nicks)) - { - final StringTokenizer st = new StringTokenizer(nicks, ","); - - while (st.hasMoreTokens()) - { - ignoredNicks.add(st.nextToken().trim().toLowerCase()); - } - } - } - - /** - * Sets the default tags/categories. - * - * @param tags The tags. - */ - private void setTags(final String tags) - { - defaultTags = tags; - } - - /** - * Stores the last 10 public messages and actions. - * - * @param sender The nick of the person who sent the private message. - * @param message The actual message sent. - * @param isAction Set to <code>true</code> if the message is an action. - */ - private void storeRecap(final String sender, final String message, final boolean isAction) - { - recap.add(Utils.UTC_SDF.format(Calendar.getInstance().getTime()) + " -> " + sender + (isAction ? " " : ": ") - + message); - - if (recap.size() > MAX_RECAP) - { - recap.remove(0); - } - } - - /** - * Responds with the users on a channel. - * - * @param sender The nick of the person who sent the message. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - private void usersResponse(final String sender, final boolean isPrivate) - { - final User[] users = getUsers(channel); - final String[] nicks = new String[users.length]; - - for (int i = 0; i < users.length; i++) - { - nicks[i] = users[i].getNick(); - } - - Arrays.sort(nicks, String.CASE_INSENSITIVE_ORDER); - - final StringBuilder buff = new StringBuilder(0); - - for (final String nick : nicks) - { - if (isOp(nick)) - { - buff.append('@'); - } - - buff.append(nick).append(' '); - } - - send(sender, buff.toString(), isPrivate); - } - - /** - * Responds with the bot's version info. - * - * @param sender The nick of the person who sent the message. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - private void versionResponse(final String sender, final boolean isPrivate) - { - if (isOp(sender)) - { - for (final String version : VERSION_STRS) - { - send(sender, version, isPrivate); - } - } - } - - /** - * Responds with the stored links. - * - * @param sender The nick of the person who sent the message. - * @param args The view command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - private void viewResponse(final String sender, final String args, final boolean isPrivate) - { - String lcArgs = args.toLowerCase(); - - if (!entries.isEmpty()) - { - final int max = entries.size(); - int i = 0; - - if (!(lcArgs.length() > 0) && (max > MAX_ENTRIES)) - { - i = max - MAX_ENTRIES; - } - - if (lcArgs.matches("^\\d+(| .*)")) - { - final String[] split = lcArgs.split(" ", 2); - - try - { - i = Integer.parseInt(split[0]); - - if (i > 0) - { - i--; - } - - if (split.length == 2) - { - lcArgs = split[1].trim(); - } - else - { - lcArgs = ""; - } - - if (i > max) - { - i = 0; - } - } - catch (NumberFormatException ignore) - { - ; // Do nothing - } - } - - EntryLink entry; - int sent = 0; - - for (; i < max; i++) - { - entry = entries.get(i); - - if (lcArgs.length() > 0) - { - if ((entry.getLink().toLowerCase().contains(lcArgs)) || - (entry.getTitle().toLowerCase().contains(lcArgs)) || - (entry.getNick().toLowerCase().contains(lcArgs))) - { - if (sent > MAX_ENTRIES) - { - send(sender, - "To view more, try: " + Utils - .bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1) + ' ' + lcArgs), - isPrivate); - - break; - } - - send(sender, Utils.buildLink(i, entry, true), isPrivate); - sent++; - } - } - else - { - if (sent > MAX_ENTRIES) - { - send(sender, - "To view more, try: " + Utils - .bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1)), - isPrivate); - - break; - } - - send(sender, Utils.buildLink(i, entry, true), isPrivate); - sent++; - } - } - } - else - { - send(sender, "There is currently nothing to view. Why don't you post something?", isPrivate); - } - } +public class Mobibot extends PircBot { + /** + * The connect/read timeout in ms. + */ + public static final int CONNECT_TIMEOUT = 5000; + + /** + * The empty title string. + */ + static final String NO_TITLE = "No Title"; + + /** + * The default port. + */ + private static final int DEFAULT_PORT = 6667; + + /** + * The info strings. + */ + private static final String[] INFO_STRS = { + ReleaseInfo.getProject() + " v" + ReleaseInfo.getVersion() + " by Erik C. Thauvin (erik@thauvin.net)", + "http://www.mobitopia.org/mobibot/" + }; + + /** + * The link match string. + */ + private static final String LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*"; + + /** + * The default maximum number of entries to display. + */ + private static final int MAX_ENTRIES = 8; + + /** + * The default maximum recap entries. + */ + private static final int MAX_RECAP = 10; + + /** + * The maximum number of times the bot will try to reconnect, if disconnected. + */ + private static final int MAX_RECONNECT = 10; + + /** + * The number of milliseconds to delay between consecutive messages. + */ + private static final long MESSAGE_DELAY = 1000L; + + /** + * The modules. + */ + private static final List<AbstractModule> MODULES = new ArrayList<>(0); + + /** + * The start time. + */ + private static final long START_TIME = System.currentTimeMillis(); + + /** + * The tags/categories marker. + */ + private static final String TAGS_MARKER = "tags:"; + + /** + * The version strings. + */ + private static final String[] VERSION_STRS = { + "Version: " + + ReleaseInfo.getVersion() + + " (" + + Utils.ISO_SDF.format(ReleaseInfo.getBuildDate()) + ')', + "Platform: " + + System.getProperty("os.name") + + " (" + + System.getProperty("os.version") + + ", " + + System.getProperty("os.arch") + + ", " + + System.getProperty("user.country") + ')', + "Runtime: " + + System.getProperty("java.runtime.name") + + " (build " + + System.getProperty("java.runtime.version") + + ')', + "VM: " + + System.getProperty("java.vm.name") + + " (build " + + System.getProperty("java.vm.version") + + ", " + + System.getProperty("java.vm.info") + + ')' + }; + + /** + * The tell object. + */ + private static Tell tell; + + /** + * The main channel. + */ + private final String channel; + + /** + * The commands list. + */ + private final List<String> commandsList = new ArrayList<>(); + + /** + * The entries array. + */ + private final List<EntryLink> entries = new ArrayList<>(0); + + /** + * The history/backlogs array. + */ + private final List<String> history = new ArrayList<>(0); + + /** + * The ignored nicks array. + */ + private final List<String> ignoredNicks = new ArrayList<>(0); + + /** + * The IRC port. + */ + private final int ircPort; + + /** + * The IRC server. + */ + private final String ircServer; + + /** + * The logger. + */ + private final Log4JLogger logger = new Log4JLogger(Mobibot.class.getPackage().getName()); + + /** + * The logger default level. + */ + private final Level loggerLevel; + + /** + * The log directory. + */ + private final String logsDir; + + /** + * The recap array. + */ + private final List<String> recap = new ArrayList<>(0); + + /** + * The backlogs URL. + */ + private String backLogsUrl = ""; + + /** + * The default tags/categories. + */ + private String defaultTags = ""; + + /** + * The del.icio.us posts handler. + */ + private DeliciousPoster delicious = null; + + /** + * The feed URL. + */ + private String feedURL = ""; + + /** + * The ident message. + */ + private String identMsg = ""; + + /** + * The ident nick. + */ + private String identNick = ""; + + /** + * The NickServ ident password. + */ + private String identPwd = ""; + + /** + * Today's date. + */ + private String today = Utils.today(); + + /** + * The weblog URL. + */ + private String weblogUrl = ""; + + /** + * Creates a new {@link Mobibot} instance. + * + * @param server The server. + * @param port The port. + * @param nickname The nickname. + * @param channel The channel. + * @param logsDir The logs directory. + */ + @SuppressWarnings("WeakerAccess") + public Mobibot(final String server, + final int port, + final String nickname, + final String channel, + final String logsDir) { + System.getProperties().setProperty("sun.net.client.defaultConnectTimeout", String.valueOf(CONNECT_TIMEOUT)); + System.getProperties().setProperty("sun.net.client.defaultReadTimeout", String.valueOf(CONNECT_TIMEOUT)); + + setName(nickname); + + ircServer = server; + ircPort = port; + this.channel = channel; + this.logsDir = logsDir; + + // Set the logger level + loggerLevel = logger.getLogger().getLevel(); + + // Initialization + Utils.UTC_SDF.setTimeZone(TimeZone.getTimeZone("UTC")); + + // Load the current entries, if any. + try { + today = EntriesMgr.loadEntries(this.logsDir + EntriesMgr.CURRENT_XML, this.channel, entries); + + if (logger.isDebugEnabled()) { + logger.debug("Last feed: " + today); + } + + if (!Utils.today().equals(today)) { + entries.clear(); + today = Utils.today(); + } + } catch (IOException ignore) { + ; // Do nothing. + } catch (FeedException e) { + logger.error("An error occurred while parsing the '" + EntriesMgr.CURRENT_XML + "' file.", e); + } + + // Load the backlogs, if any. + try { + EntriesMgr.loadBacklogs(this.logsDir + EntriesMgr.NAV_XML, history); + } catch (IOException ignore) { + ; // Do nothing. + } catch (FeedException e) { + logger.error("An error occurred while parsing the '" + EntriesMgr.NAV_XML + "' file.", e); + } + + // Load the modules + MODULES.add(new Calc()); + MODULES.add(new CurrencyConverter()); + MODULES.add(new Dice()); + MODULES.add(new GoogleSearch()); + MODULES.add(new Joke()); + MODULES.add(new Lookup()); + MODULES.add(new Ping()); + MODULES.add(new StockQuote()); + MODULES.add(new Twitter()); + MODULES.add(new War()); + MODULES.add(new Weather()); + MODULES.add(new WorldTime()); + } + + /** + * The Truth Is Out There... + * + * @param args The command line arguments. + */ + public static void main(final String[] args) { + // Setup the command line options + final Options options = new Options(); + options.addOption(Commands.HELP_ARG.substring(0, 1), Commands.HELP_ARG, false, "print this help message"); + options.addOption(Commands.DEBUG_ARG.substring(0, 1), Commands.DEBUG_ARG, false, + "print debug & logging data directly to the console"); + options.addOption(Option.builder( + Commands.PROPS_ARG.substring(0, 1)).hasArg().argName("file").desc("use " + "alternate properties file") + .longOpt(Commands.PROPS_ARG).build()); + options.addOption(Commands.VERSION_ARG.substring(0, 1), Commands.VERSION_ARG, false, "print version info"); + + // Parse the command line + final CommandLineParser parser = new DefaultParser(); + CommandLine line = null; + + try { + line = parser.parse(options, args); + } catch (ParseException e) { + System.err.println("CLI Parsing failed. Reason: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + + if (line.hasOption(Commands.HELP_ARG.charAt(0))) { + // Output the usage + new HelpFormatter().printHelp(Mobibot.class.getName(), options); + } else if (line.hasOption(Commands.VERSION_ARG.charAt(0))) { + for (final String s : INFO_STRS) { + System.out.println(s); + } + } else { + final Properties p = new Properties(); + + try (final FileInputStream fis = new FileInputStream( + new File(line.getOptionValue(Commands.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); + } + + // Get the main properties + final String channel = p.getProperty("channel"); + final String server = p.getProperty("server"); + final int port = Utils.getIntProperty(p.getProperty("port"), DEFAULT_PORT); + final String nickname = p.getProperty("nick", Mobibot.class.getName().toLowerCase()); + final String logsDir = Utils.ensureDir(p.getProperty("logs", "."), false); + + if (!line.hasOption(Commands.DEBUG_ARG.charAt(0))) { + // Redirect the stdout and stderr + PrintStream stdout = null; + + try { + stdout = new PrintStream(new FileOutputStream( + logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true)); + } catch (IOException e) { + System.err.println("Unable to open output (stdout) log file."); + e.printStackTrace(System.err); + System.exit(1); + } + + PrintStream stderr = null; + + try { + stderr = new PrintStream(new FileOutputStream(logsDir + nickname + ".err", true)); + } catch (IOException e) { + System.err.println("Unable to open error (stderr) log file."); + e.printStackTrace(System.err); + System.exit(1); + } + + System.setOut(stdout); + System.setErr(stderr); + } + + // Get the bot's properties + final String login = p.getProperty("login", nickname); + final String weblogURL = p.getProperty("weblog", ""); + final String feedURL = p.getProperty("feed", ""); + final String backlogsURL = Utils.ensureDir(p.getProperty("backlogs", weblogURL), true); + final String ignoredNicks = p.getProperty("ignore", ""); + final String identNick = p.getProperty("ident-nick", ""); + final String identMsg = p.getProperty("ident-msg", ""); + final String identPwd = p.getProperty("ident", ""); + final String tags = p.getProperty("tags", ""); + + // Get the del.icio.us properties + final String dname = p.getProperty("delicious-user"); + final String dpwd = p.getProperty("delicious-pwd"); + + // Create the bot + final Mobibot bot = new Mobibot(server, port, nickname, channel, logsDir); + + // Get the tell command settings + tell = new Tell(bot, p.getProperty("tell-max-days"), p.getProperty("tell-max-size")); + + // Initialize the bot + bot.setVerbose(true); + bot.setAutoNickChange(true); + bot.setLogin(login); + bot.setVersion(weblogURL); + bot.setMessageDelay(MESSAGE_DELAY); + bot.setIdentity(identPwd, identNick, identMsg); + + // Set the URLs + bot.setWeblogUrl(weblogURL); + bot.setFeedURL(feedURL); + bot.setBacklogsUrl(backlogsURL); + + // Set the del.icio.us authentication + bot.setDeliciousAuth(dname, dpwd); + + // Load the modules properties + MODULES.stream().filter(AbstractModule::hasProperties).forEach( + module -> { + for (final String s : module.getPropertyKeys()) { + module.setProperty(s, p.getProperty(s, "")); + } + }); + + // Set the tags + bot.setTags(tags); + + // Set the ignored nicks + bot.setIgnoredNicks(ignoredNicks); + + // Save the entries + bot.saveEntries(true); + + // Connect + try { + bot.connect(server, port); + } catch (Exception e) { + int retries = 0; + + while ((retries++ < MAX_RECONNECT) && !bot.isConnected()) { + sleep(10); + + try { + bot.connect(server, port); + } catch (Exception ignore) { + if (retries == MAX_RECONNECT) { + System.err.println( + "Unable to connect to " + server + " after " + MAX_RECONNECT + " retries."); + e.printStackTrace(System.err); + System.exit(1); + } + } + } + } + + bot.setVersion(INFO_STRS[0]); + + bot.identify(); + + bot.joinChannel(channel); + } + } + + /** + * Sleeps for the specified number of seconds. + * + * @param secs The number of seconds to sleep for. + */ + private static void sleep(final int secs) { + try { + Thread.sleep((long) (secs * 1000)); + } catch (InterruptedException ignore) { + ; // Do nothing + } + } + + /** + * Sends an action to the current channel. + * + * @param action The action. + */ + final public void action(final String action) { + action(channel, 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 (Utils.isValidString(channel) && Utils.isValidString(action)) { + sendAction(channel, action); + } + } + + /** + * Responds with the title and links from the RSS feed. + * + * @param sender The nick of the person who sent the private message. + */ + private void feedResponse(final String sender) { + if (Utils.isValidString(feedURL)) { + new Thread(new FeedReader(this, sender, feedURL)).start(); + } else { + send(sender, "There is no weblog setup for this channel."); + } + } + + /** + * Returns the index of the specified duplicate entry, if any. + * + * @param link The link. + * @return The index or -1 if none. + */ + private int findDupEntry(final String link) { + synchronized (entries) { + for (int i = 0; i < entries.size(); i++) { + if (link.equals(entries.get(i).getLink())) { + return i; + } + } + } + + return -1; + } + + /** + * Returns the backlogs URL. + * + * @return The backlogs URL. + */ + public final String getBacklogsUrl() { + return this.backLogsUrl; + } + + /** + * Sets the backlogs URL. + * + * @param backLogsUrl The backlogs URL. + */ + private void setBacklogsUrl(final String backLogsUrl) { + this.backLogsUrl = backLogsUrl; + } + + /** + * Returns the current channel. + * + * @return The current channel. + */ + public final String getChannel() { + return channel; + } + + /** + * Returns the irc server. + * + * @return The irc server. + */ + public final String getIrcServer() { + return this.ircServer; + } + + /** + * Returns the bot's logger. + * + * @return The bot's logger. + */ + public final Log4JLogger getLogger() { + return logger; + } + + /** + * Returns the log directory. + * + * @return the log directory. + */ + public final String getLogsDir() { + return this.logsDir; + } + + /** + * Returns the bot's nickname regexp pattern. + * + * @return The nickname regexp pattern. + */ + private String getNickPattern() { + final StringBuilder buff = new StringBuilder(0); + + for (final char c : getNick().toCharArray()) { + if (Character.isLetter(c)) { + buff.append('[') + .append(String.valueOf(c).toLowerCase()) + .append(String.valueOf(c).toUpperCase()) + .append(']'); + } else { + buff.append(c); + } + } + + return buff.toString(); + } + + /** + * Get today's date for the feed. + * + * @return Today's date. + */ + public String getToday() { + return this.today; + } + + /** + * Returns the weblog URL. + * + * @return The weblog URL. + */ + public final String getWeblogUrl() { + return this.weblogUrl; + } + + /** + * Sets the weblog URL. + * + * @param weblogUrl The weblog URL. + */ + private void setWeblogUrl(final String weblogUrl) { + this.weblogUrl = weblogUrl; + } + + /** + * Returns indented and bold help string. + * + * @param help The help string. + * @return The indented help string. + */ + final public String helpIndent(final String help) { + return helpIndent(help, true); + } + + /** + * Returns indented help string. + * + * @param help The help string. + * @param isBold The bold flag. + * @return The indented help string. + */ + public String helpIndent(final String help, final boolean isBold) { + return " " + (isBold ? Utils.bold(help) : help); + } + + /** + * Responds with the bot's help. + * + * @param sender The nick of the person who sent the private message. + * @param topic The help topic, if any. + */ + private void helpResponse(final String sender, final String topic) { + final String lcTopic = topic.toLowerCase().trim(); + + if (lcTopic.equals(Commands.HELP_POSTING_KEYWORD)) { + send(sender, Utils.bold("Post a URL, by saying it on a line on its own:")); + send(sender, helpIndent("<url> [<title>] [" + TAGS_MARKER + "<+tag> [...]]")); + send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + '1')); + send(sender, "To add a title, use a its label and a pipe:"); + send(sender, helpIndent(Commands.LINK_CMD + "1:|This is the title")); + send(sender, "To add a comment: "); + send(sender, helpIndent(Commands.LINK_CMD + "1:This is a comment")); + send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + "1.1")); + send(sender, "To edit a comment, use its label: "); + send(sender, helpIndent(Commands.LINK_CMD + "1.1:This is an edited comment")); + send(sender, "To delete a comment, use its label and a minus sign: "); + send(sender, helpIndent(Commands.LINK_CMD + "1.1:-")); + send(sender, "You can also view a posting by saying its label."); + } else if (lcTopic.equals(Commands.HELP_TAGS_KEYWORD)) { + send(sender, Utils.bold("To categorize or tag a URL, use its label and a T:")); + send(sender, helpIndent(Commands.LINK_CMD + "1T:<+tag|-tag> [...]")); + } else if (lcTopic.equals(Commands.VIEW_CMD)) { + send(sender, "To list or search the current URL posts:"); + send(sender, helpIndent(getNick() + ": " + Commands.VIEW_CMD) + " [<start>] [<query>]"); + } else if (lcTopic.equals(channel.substring(1).toLowerCase())) { + send(sender, "To list the last 5 posts from the channel's weblog:"); + send(sender, helpIndent(getNick() + ": " + channel.substring(1))); + } else if (lcTopic.equals(Commands.RECAP_CMD)) { + send(sender, "To list the last 10 public channel messages:"); + send(sender, helpIndent(getNick() + ": " + Commands.RECAP_CMD)); + } else if (lcTopic.equals(Commands.USERS_CMD)) { + send(sender, "To list the users present on the channel:"); + send(sender, helpIndent(getNick() + ": " + Commands.USERS_CMD)); + } else if (lcTopic.equals(Commands.INFO_CMD)) { + send(sender, "To view information about the bot:"); + send(sender, helpIndent(getNick() + ": " + Commands.INFO_CMD)); + } else if (lcTopic.equals(Commands.CYCLE_CMD) && isOp(sender)) { + send(sender, "To have the bot leave the channel and come back:"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.CYCLE_CMD)); + } else if (lcTopic.equals(Commands.ME_CMD) && isOp(sender)) { + send(sender, "To have the bot perform an action:"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.ME_CMD + " <action>")); + } else if (lcTopic.equals(Commands.SAY_CMD) && isOp(sender)) { + send(sender, "To have the bot say something on the channel:"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.SAY_CMD + " <text>")); + } else if (lcTopic.equals(Commands.VERSION_CMD) && isOp(sender)) { + send(sender, "To view the version data (bot, java, etc.):"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.VERSION_CMD)); + } else if (lcTopic.equals(Commands.MSG_CMD) && isOp(sender)) { + send(sender, "To have the bot send a private message to someone:"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.MSG_CMD + " <nick> <text>")); + } else if (lcTopic.equals(Commands.IGNORE_CMD)) { + send(sender, "To check your ignore status:"); + send(sender, helpIndent(getNick() + ": " + Commands.IGNORE_CMD)); + + send(sender, "To toggle your ignore status:"); + send(sender, helpIndent(getNick() + ": " + Commands.IGNORE_CMD + ' ' + Commands.IGNORE_ME_KEYWORD)); + } else if (lcTopic.equals(Tell.TELL_CMD) && tell.isEnabled()) { + tell.helpResponse(sender); + } else { + for (final AbstractModule module : MODULES) { + for (final String cmd : module.getCommands()) { + if (lcTopic.equals(cmd)) { + module.helpResponse(this, sender, topic, true); + return; + } + } + } + + send(sender, Utils.bold("Type a URL on " + channel + " to post it.")); + send(sender, "For more information on a specific command, type:"); + send(sender, helpIndent(getNick() + ": " + Commands.HELP_CMD + " <command>")); + send(sender, "The commands are:"); + + if (commandsList.isEmpty()) { + commandsList.add(Commands.IGNORE_CMD); + commandsList.add(Commands.INFO_CMD); + commandsList.add(channel.substring(1)); + commandsList.add(Commands.HELP_POSTING_KEYWORD); + commandsList.add(Commands.HELP_TAGS_KEYWORD); + commandsList.add(Commands.RECAP_CMD); + commandsList.add(Commands.USERS_CMD); + commandsList.add(Commands.VIEW_CMD); + + MODULES.stream().filter(AbstractModule::isEnabled).forEach( + module -> commandsList.addAll(module.getCommands())); + + if (tell.isEnabled()) { + commandsList.add(Tell.TELL_CMD); + } + + Collections.sort(commandsList); + } + + final StringBuilder sb = new StringBuilder(0); + + for (int i = 0, cmdCount = 1; i < commandsList.size(); i++, cmdCount++) { + if (sb.length() > 0) { + sb.append(" "); + } + + sb.append(commandsList.get(i)); + + // 6 commands per line or last command + if (sb.length() > 0 && (cmdCount == 6 || i == (commandsList.size() - 1))) { + send(sender, helpIndent(sb.toString())); + + sb.setLength(0); + cmdCount = 0; + } + } + + if (isOp(sender)) { + send(sender, "The op commands are:"); + send(sender, helpIndent( + Commands.CYCLE_CMD + " " + + Commands.ME_CMD + " " + + Commands.MSG_CMD + " " + + Commands.SAY_CMD + " " + + Commands.VERSION_CMD)); + } + } + } + + /** + * Identifies the bot. + */ + private void identify() { + // Identify with NickServ + if (Utils.isValidString(identPwd)) { + identify(identPwd); + } + + // Identify with a specified nick + if (Utils.isValidString(identNick) && Utils.isValidString(identMsg)) { + sendMessage(identNick, identMsg); + } + } + + /** + * Processes the {@link net.thauvin.erik.mobibot.Commands#IGNORE_CMD} command. + * + * @param sender The sender. + * @param args The command arguments. + */ + private void ignoreResponse(final String sender, final String args) { + if (!isOp(sender)) { + final String nick = sender.toLowerCase(); + final boolean isMe = args.toLowerCase().startsWith(Commands.IGNORE_ME_KEYWORD); + + if (ignoredNicks.contains(nick)) { + if (isMe) { + ignoredNicks.remove(nick); + + send(sender, "You are no longer ignored."); + } else { + send(sender, "You are currently ignored."); + } + } else { + if (isMe) { + ignoredNicks.add(nick); + + send(sender, "You are now ignored."); + } else { + send(sender, "You are not currently ignored."); + } + } + } else { + if (args.length() > 0) { + final String[] nicks = args.toLowerCase().split(" "); + + for (final String nick : nicks) { + final String ignore; + + if (Commands.IGNORE_ME_KEYWORD.equals(nick)) { + ignore = sender.toLowerCase(); + } else { + ignore = nick; + } + + if (ignoredNicks.contains(ignore)) { + ignoredNicks.remove(ignore); + } else { + ignoredNicks.add(ignore); + } + } + } + + send(sender, "The following nicks are ignored: " + ignoredNicks.toString()); + } + } + + /** + * Responds with the bot's information. + * + * @param sender The nick of the person who sent the message. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + private void infoResponse(final String sender, final boolean isPrivate) { + for (final String info : INFO_STRS) { + if (info.startsWith("http://")) { + send(sender, Utils.green(info), isPrivate); + } else { + send(sender, info, isPrivate); + } + } + + final StringBuilder info = new StringBuilder("Uptime: "); + + long timeInSeconds = (System.currentTimeMillis() - START_TIME) / 1000L; + + final long years = timeInSeconds / 31540000L; + + if (years > 0) { + info.append(years).append(Utils.plural(years, " year ", " years ")); + timeInSeconds -= (years * 31540000L); + } + + final long weeks = timeInSeconds / 604800L; + + if (weeks > 0) { + info.append(weeks).append(Utils.plural(weeks, " week ", " weeks ")); + timeInSeconds -= (weeks * 604800L); + } + + final long days = timeInSeconds / 86400L; + + if (days > 0) { + info.append(days).append(Utils.plural(days, " day ", " days ")); + timeInSeconds -= (days * 86400L); + } + + final long hours = timeInSeconds / 3600L; + + if (hours > 0) { + info.append(hours).append(Utils.plural(hours, " hour ", " hours ")); + timeInSeconds -= (hours * 3600L); + } + + final long minutes = timeInSeconds / 60L; + + info.append(minutes).append(Utils.plural(minutes, " minute ", " minutes ")); + + info.append("[Entries: ").append(entries.size()); + + if (tell.isEnabled() && isOp(sender)) { + info.append(", Messages: ").append(tell.size()); + } + + info.append(']'); + + send(sender, info.toString(), isPrivate); + } + + /** + * Determines whether the specified nick should be ignored. + * + * @param nick The nick. + * @return <code>true</code> if the nick should be ignored, <code>false</code> otherwise. + */ + private boolean isIgnoredNick(final String nick) { + return Utils.isValidString(nick) && ignoredNicks.contains(nick.toLowerCase()); + } + + /** + * Returns <code>true</code> if the specified sender is an Op on the {@link #channel channel}. + * + * @param sender The sender. + * @return true, if the sender is an Op. + */ + public boolean isOp(final String sender) { + final User[] users = getUsers(channel); + + for (final User user : users) { + if (user.getNick().equals(sender)) { + return user.isOp(); + } + } + + return false; + } + + @Override + protected final void onAction(final String sender, + final String login, + final String hostname, + final String target, + final String action) { + if (target.equals(channel)) { + storeRecap(sender, action, true); + } + } + + @Override + protected final void onDisconnect() { + if (Utils.isValidString(weblogUrl)) { + setVersion(weblogUrl); + } + + sleep(5); + + // 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) { + if (logger.isDebugEnabled()) { + logger.debug( + "Unable to reconnect to " + ircServer + " after " + MAX_RECONNECT + " retries.", + ex); + } + + e.printStackTrace(System.err); + System.exit(1); + } + } + } + } + + setVersion(INFO_STRS[0]); + + identify(); + + joinChannel(channel); + } + + @Override + protected void onJoin(final String channel, final String sender, final String login, final String hostname) { + tell.send(sender); + } + + @Override + protected final void onMessage(final String channel, + final String sender, + final String login, + final String hostname, + final String message) { + if (logger.isDebugEnabled()) { + logger.debug(">>> " + sender + ": " + message); + } + + boolean isCommand = false; + + // Capture URLs posted on the channel + if (message.matches(LINK_MATCH) && !isIgnoredNick(sender)) { + isCommand = true; + + final String[] cmds = message.split(" ", 2); + + if (cmds.length == 1 || (!cmds[1].contains(getNick()))) { + final String link = cmds[0].trim(); + boolean isBackup = false; + + final int dupIndex = findDupEntry(link); + + if (dupIndex == -1) { + if (!Utils.today().equals(today)) { + isBackup = true; + saveEntries(true); + + entries.clear(); + today = Utils.today(); + } + + final StringBuilder tags = new StringBuilder(defaultTags); + String title = NO_TITLE; + + if (cmds.length == 2) { + final String[] data = cmds[1].trim().split(TAGS_MARKER, 2); + + if (data.length == 1) { + title = data[0].trim(); + } else { + if (Utils.isValidString(data[0])) { + title = data[0].trim(); + } + + tags.append(' ').append(data[1].trim()); + } + } + + if (NO_TITLE.equals(title)) { + try { + final Document html = Jsoup.connect(link).userAgent("Mozilla").get(); + final String htmlTitle = html.title(); + + if (Utils.isValidString(htmlTitle)) { + title = htmlTitle; + } + } catch (IOException ignore) { + // Do nothing + } + } + + entries.add(new EntryLink(link, title, sender, login, channel, tags.toString())); + + final int index = entries.size() - 1; + final EntryLink entry = entries.get(index); + send(channel, Utils.buildLink(index, entry)); + + if (delicious != null) { + delicious.addPost(entry); + } + + saveEntries(isBackup); + + if (NO_TITLE.equals(entry.getTitle())) { + send(sender, "Please specify a title, by typing:", true); + send(sender, helpIndent(Commands.LINK_CMD + (index + 1) + ":|This is the title"), true); + } + } else { + final EntryLink entry = entries.get(dupIndex); + send(sender, "Duplicate >> " + Utils.buildLink(dupIndex, entry)); + } + } + } + // mobibot: <command> + else if (message.matches(getNickPattern() + ":.*")) { + isCommand = true; + + final String[] cmds = message.substring(message.indexOf(':') + 1).trim().split(" ", 2); + final String cmd = cmds[0].toLowerCase(); + + String args = ""; + + if (cmds.length > 1) { + args = cmds[1].trim(); + } + + // mobibot: help + if (cmd.startsWith(Commands.HELP_CMD)) { + helpResponse(sender, args); + } + // mobibot: recap + else if (cmd.equals(Commands.RECAP_CMD)) { + recapResponse(sender, false); + } + // mobibot: users + else if (cmd.equals(Commands.USERS_CMD)) { + usersResponse(sender, false); + } + // mobibot: info + else if (cmd.equals(Commands.INFO_CMD)) { + infoResponse(sender, false); + } + // mobbiot: version + else if (cmd.equals(Commands.VERSION_CMD)) { + versionResponse(sender, false); + } + // mobibot: <channel> + else if (cmd.equalsIgnoreCase(channel.substring(1))) { + feedResponse(sender); + } + // mobibot: view + else if (cmd.startsWith(Commands.VIEW_CMD)) { + viewResponse(sender, args, false); + } + // mobibot: tell + else if (cmd.startsWith(Tell.TELL_CMD) && tell.isEnabled()) { + tell.response(sender, args); + } + // mobibot: ignore + else if (cmd.startsWith(Commands.IGNORE_CMD)) { + ignoreResponse(sender, args); + } + // modules + else { + for (final AbstractModule module : MODULES) { + for (final String c : module.getCommands()) { + if (cmd.startsWith(c)) { + module.commandResponse(this, sender, args, false); + } + } + } + } + } + // L1:<comment>, L1:-, L1:|<title>, etc. + else if (message.matches(Commands.LINK_CMD + "[0-9]+:.*")) { + isCommand = true; + + final String[] cmds = message.substring(1).split(":", 2); + final int index = Integer.parseInt(cmds[0]) - 1; + + // L1:<comment> + if (index < entries.size()) { + final String cmd = cmds[1].trim(); + + if (cmd.length() == 0) { + final EntryLink entry = entries.get(index); + send(channel, Utils.buildLink(index, entry)); + + if (entry.hasTags()) { + send(channel, Utils.buildTags(index, entry)); + } + + if (entry.hasComments()) { + final EntryComment[] comments = entry.getComments(); + + for (int i = 0; i < comments.length; i++) { + send(channel, Utils.buildComment(index, i, comments[i])); + } + } + } else { + // L1:- + if ("-".equals(cmd)) { + final EntryLink entry = entries.get(index); + + if (entry.getLogin().equals(login) || isOp(sender)) { + if (delicious != null) { + delicious.deletePost(entry); + } + + entries.remove(index); + send(channel, "Entry " + Commands.LINK_CMD + (index + 1) + " removed."); + saveEntries(false); + } else { + send(sender, "Please ask a channel op to remove this entry for you."); + } + } + // L1:|<title> + else if (cmd.charAt(0) == '|') { + if (cmd.length() > 1) { + final EntryLink entry = entries.get(index); + entry.setTitle(cmd.substring(1).trim()); + + if (delicious != null) { + delicious.updatePost(entry.getLink(), entry); + } + + send(channel, Utils.buildLink(index, entry)); + saveEntries(false); + } + } + // L1:=<url> + else if (cmd.charAt(0) == '=') { + final EntryLink entry = entries.get(index); + + if (entry.getLogin().equals(login) || isOp(sender)) { + final String link = cmd.substring(1); + + if (link.matches(LINK_MATCH)) { + final String oldLink = entry.getLink(); + + entry.setLink(link); + + if (delicious != null) { + delicious.updatePost(oldLink, entry); + } + + send(channel, Utils.buildLink(index, entry)); + saveEntries(false); + } + } else { + send(sender, "Please ask a channel op to change this link for you."); + } + } + // L1:?<author> + else if (cmd.charAt(0) == '?') { + if (isOp(sender)) { + if (cmd.length() > 1) { + final EntryLink entry = entries.get(index); + entry.setNick(cmd.substring(1)); + send(channel, Utils.buildLink(index, entry)); + saveEntries(false); + } + } else { + send(sender, "Please ask a channel op to change the author of this link for you."); + } + } else { + final EntryLink entry = entries.get(index); + final int cindex = entry.addComment(cmd, sender); + + final EntryComment comment = entry.getComment(cindex); + send(sender, Utils.buildComment(index, cindex, comment)); + saveEntries(false); + } + } + } + } + // L1T:<+-tag> + else if (message.matches(Commands.LINK_CMD + "[0-9]+T:.*")) { + isCommand = true; + + final String[] cmds = message.substring(1).split("T:", 2); + final int index = Integer.parseInt(cmds[0]) - 1; + + if (index < entries.size()) { + final String cmd = cmds[1].trim(); + + final EntryLink entry = entries.get(index); + + if (cmd.length() != 0) { + if (entry.getLogin().equals(login) || isOp(sender)) { + entry.setTags(cmd); + + if (delicious != null) { + delicious.updatePost(entry.getLink(), entry); + } + + send(channel, Utils.buildTags(index, entry)); + saveEntries(false); + } else { + send(sender, "Please ask a channel op to change the tags for you."); + } + } else { + if (entry.hasTags()) { + send(channel, Utils.buildTags(index, entry)); + } else { + send(sender, "The entry has no tags. Why don't add some?"); + } + } + } + } + // L1.1:<command> + else if (message.matches(Commands.LINK_CMD + "[0-9]+\\.[0-9]+:.*")) { + isCommand = true; + + final String[] cmds = message.substring(1).split("[.:]", 3); + final int index = Integer.parseInt(cmds[0]) - 1; + + if (index < entries.size()) { + final EntryLink entry = entries.get(index); + final int cindex = Integer.parseInt(cmds[1]) - 1; + + if (cindex < entry.getCommentsCount()) { + final String cmd = cmds[2].trim(); + + // L1.1: + if (cmd.length() == 0) { + final EntryComment comment = entry.getComment(cindex); + send(channel, Utils.buildComment(index, cindex, comment)); + } + // L1.1:- + else if ("-".equals(cmd)) { + entry.deleteComment(cindex); + send(channel, "Comment " + Commands.LINK_CMD + (index + 1) + '.' + (cindex + 1) + " removed."); + saveEntries(false); + } + // L1.1:?<author> + else if (cmd.charAt(0) == '?') { + if (isOp(sender)) { + if (cmd.length() > 1) { + final EntryComment comment = entry.getComment(cindex); + comment.setNick(cmd.substring(1)); + send(channel, Utils.buildComment(index, cindex, comment)); + saveEntries(false); + } + } else { + send(sender, "Please ask a channel op to change the author of this comment for you."); + } + } else { + entry.setComment(cindex, cmd, sender); + + final EntryComment comment = entry.getComment(cindex); + send(sender, Utils.buildComment(index, cindex, comment)); + saveEntries(false); + } + } + } + } + + if (!isCommand) { + storeRecap(sender, message, false); + } + + tell.send(sender, true); + } + + @Override + protected void onNickChange(final String oldNick, final String login, final String hostname, final String newNick) { + tell.send(newNick); + } + + @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 = cmds[0].toLowerCase(); + String args = ""; + + if (cmds.length > 1) { + args = cmds[1].trim(); + } + + if (cmd.startsWith(Commands.HELP_CMD)) { + helpResponse(sender, args); + } else if ("kill".equals(cmd) && isOp(sender)) { + sendRawLine("QUIT : Poof!"); + System.exit(0); + } else if (cmd.equals(Commands.DIE_CMD) && isOp(sender)) { + send(channel, sender + " has just signed my death sentence."); + saveEntries(true); + sleep(3); + quitServer("The Bot Is Out There!"); + System.exit(0); + } else if (cmd.equals(Commands.CYCLE_CMD)) { + send(channel, sender + " has just asked me to leave. I'll be back!"); + sleep(0); + partChannel(channel); + sleep(10); + joinChannel(channel); + } else if (cmd.equals(Commands.RECAP_CMD)) { + recapResponse(sender, true); + } else if (cmd.equals(Commands.USERS_CMD)) { + usersResponse(sender, true); + } else if (cmd.equals(Commands.ADDLOG_CMD) && (cmds.length > 1) && isOp(sender)) { + // e.g. 2014-04-01 + final File backlog = new File(logsDir + args + EntriesMgr.XML_EXT); + if (backlog.exists()) { + history.add(0, args); + send(sender, history.toString(), true); + } else { + send(sender, "The specified log could not be found."); + } + } else if (cmd.equals(Commands.ME_CMD) && isOp(sender)) { + if (args.length() > 1) { + action(args); + } else { + helpResponse(sender, Commands.ME_CMD); + } + } else if (cmd.equals(Commands.NICK_CMD) && (cmds.length > 1)) { + if (isOp(sender)) { + changeNick(args); + } + } else if (cmd.equals(Commands.SAY_CMD) && isOp(sender)) { + if (cmds.length > 1) { + send(channel, args, true); + } else { + helpResponse(sender, Commands.SAY_CMD); + } + } else if (cmd.equals(Commands.MSG_CMD) && isOp(sender)) { + if (cmds.length > 1) { + final String[] msg = args.split(" ", 2); + + if (args.length() > 2) { + send(msg[0], msg[1], true); + } else { + helpResponse(sender, Commands.MSG_CMD); + } + } else { + helpResponse(sender, Commands.MSG_CMD); + } + } else if (cmd.equals(Commands.VIEW_CMD)) { + viewResponse(sender, args, true); + } else if (cmd.equals(Tell.TELL_CMD) && tell.isEnabled()) { + tell.response(sender, args); + } else if (cmd.equals(Commands.INFO_CMD)) { + infoResponse(sender, true); + } else if (cmd.equals(Commands.VERSION_CMD)) { + versionResponse(sender, true); + } else if (cmd.equals(Commands.DEBUG_CMD) && isOp(sender)) { + if (logger.isDebugEnabled()) { + logger.getLogger().setLevel(loggerLevel); + } else { + logger.getLogger().setLevel(Level.DEBUG); + } + + send(sender, "Debug logging is " + (logger.isDebugEnabled() ? "enabled." : "disabled."), true); + } else { + for (final AbstractModule module : MODULES) { + if (module.isPrivateMsgEnabled()) { + for (final String c : module.getCommands()) { + if (cmd.equals(c)) { + module.commandResponse(this, sender, args, true); + return; + } + } + } + } + + helpResponse(sender, ""); + } + } + + /** + * Responds with the last 10 public messages. + * + * @param sender The nick of the person who sent the private message. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + private void recapResponse(final String sender, final boolean isPrivate) { + for (final String recap : this.recap) { + send(sender, recap, isPrivate); + } + } + + /** + * Saves the entries. + * + * @param isDayBackup Set the <code>true</code> if the daily backup file should also be created. + */ + private void saveEntries(final boolean isDayBackup) { + EntriesMgr.saveEntries(this, entries, history, isDayBackup); + } + + /** + * Sends a private message or notice. + * + * @param sender The 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 (Utils.isValidString(message) && Utils.isValidString(sender)) { + if (isPrivate) { + if (logger.isDebugEnabled()) { + logger.debug("Sending message to " + sender + ": " + message); + } + + sendMessage(sender, message); + } else { + if (logger.isDebugEnabled()) { + logger.debug("Sending notice to " + sender + ": " + message); + } + + sendNotice(sender, message); + } + } + } + + /** + * Sends a private notice. + * + * @param sender The nick of the person who sent the message. + * @param message The actual message. + */ + public final void send(final String sender, final String message) { + send(sender, message, false); + } + + /** + * Sets the del.icio.us authentication. + * + * @param username The del.icio.us user name. + * @param password The del.icio.us password. + */ + private void setDeliciousAuth(final String username, final String password) { + if (Utils.isValidString(username) && Utils.isValidString(password)) { + delicious = new DeliciousPoster(username, password, ircServer); + } + } + + /** + * Sets the feed URL. + * + * @param feedURL The feed URL. + */ + private void setFeedURL(final String feedURL) { + this.feedURL = feedURL; + } + + /** + * Sets the bot's identification. + * + * @param identPwd The password for NickServ, if any. + * @param identNick The ident nick name. + * @param identMsg The ident message. + */ + private void setIdentity(final String identPwd, final String identNick, final String identMsg) { + this.identPwd = identPwd; + this.identNick = identNick; + this.identMsg = identMsg; + } + + /** + * Sets the Ignored nicks. + * + * @param nicks The nicks to ignore + */ + private void setIgnoredNicks(final String nicks) { + if (Utils.isValidString(nicks)) { + final StringTokenizer st = new StringTokenizer(nicks, ","); + + while (st.hasMoreTokens()) { + ignoredNicks.add(st.nextToken().trim().toLowerCase()); + } + } + } + + /** + * Sets the default tags/categories. + * + * @param tags The tags. + */ + private void setTags(final String tags) { + defaultTags = tags; + } + + /** + * Stores the last 10 public messages and actions. + * + * @param sender The nick of the person who sent the private message. + * @param message The actual message sent. + * @param isAction Set to <code>true</code> if the message is an action. + */ + private void storeRecap(final String sender, final String message, final boolean isAction) { + recap.add(Utils.UTC_SDF.format(Calendar.getInstance().getTime()) + " -> " + sender + (isAction ? " " : ": ") + + message); + + if (recap.size() > MAX_RECAP) { + recap.remove(0); + } + } + + /** + * Responds with the users on a channel. + * + * @param sender The nick of the person who sent the message. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + private void usersResponse(final String sender, final boolean isPrivate) { + final User[] users = getUsers(channel); + final String[] nicks = new String[users.length]; + + for (int i = 0; i < users.length; i++) { + nicks[i] = users[i].getNick(); + } + + Arrays.sort(nicks, String.CASE_INSENSITIVE_ORDER); + + final StringBuilder buff = new StringBuilder(0); + + for (final String nick : nicks) { + if (isOp(nick)) { + buff.append('@'); + } + + buff.append(nick).append(' '); + } + + send(sender, buff.toString(), isPrivate); + } + + /** + * Responds with the bot's version info. + * + * @param sender The nick of the person who sent the message. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + private void versionResponse(final String sender, final boolean isPrivate) { + if (isOp(sender)) { + for (final String version : VERSION_STRS) { + send(sender, version, isPrivate); + } + } + } + + /** + * Responds with the stored links. + * + * @param sender The nick of the person who sent the message. + * @param args The view command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + private void viewResponse(final String sender, final String args, final boolean isPrivate) { + String lcArgs = args.toLowerCase(); + + if (!entries.isEmpty()) { + final int max = entries.size(); + int i = 0; + + if (!(lcArgs.length() > 0) && (max > MAX_ENTRIES)) { + i = max - MAX_ENTRIES; + } + + if (lcArgs.matches("^\\d+(| .*)")) { + final String[] split = lcArgs.split(" ", 2); + + try { + i = Integer.parseInt(split[0]); + + if (i > 0) { + i--; + } + + if (split.length == 2) { + lcArgs = split[1].trim(); + } else { + lcArgs = ""; + } + + if (i > max) { + i = 0; + } + } catch (NumberFormatException ignore) { + ; // Do nothing + } + } + + EntryLink entry; + int sent = 0; + + for (; i < max; i++) { + entry = entries.get(i); + + if (lcArgs.length() > 0) { + if ((entry.getLink().toLowerCase().contains(lcArgs)) || + (entry.getTitle().toLowerCase().contains(lcArgs)) || + (entry.getNick().toLowerCase().contains(lcArgs))) { + if (sent > MAX_ENTRIES) { + send(sender, + "To view more, try: " + Utils + .bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1) + ' ' + lcArgs), + isPrivate); + + break; + } + + send(sender, Utils.buildLink(i, entry, true), isPrivate); + sent++; + } + } else { + if (sent > MAX_ENTRIES) { + send(sender, + "To view more, try: " + Utils + .bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1)), + isPrivate); + + break; + } + + send(sender, Utils.buildLink(i, entry, true), isPrivate); + sent++; + } + } + } else { + send(sender, "There is currently nothing to view. Why don't you post something?", isPrivate); + } + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/Tell.java b/src/main/java/net/thauvin/erik/mobibot/Tell.java index dff6317..fd8858c 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Tell.java +++ b/src/main/java/net/thauvin/erik/mobibot/Tell.java @@ -41,389 +41,317 @@ import java.util.concurrent.CopyOnWriteArrayList; * @created 2016-07-02 * @since 1.0 */ -public class Tell -{ - /** - * The all keyword. - */ - public static final String TELL_ALL_KEYWORD = "all"; +public class Tell { + /** + * The all keyword. + */ + public static final String TELL_ALL_KEYWORD = "all"; - /** - * The tell command. - */ - public static final String TELL_CMD = "tell"; + /** + * The tell command. + */ + public static final String TELL_CMD = "tell"; - /** - * The delete command. - */ - public static final String TELL_DEL_KEYWORD = "del"; + /** + * The delete command. + */ + public static final String TELL_DEL_KEYWORD = "del"; - /** - * The default maximum number of days to keep messages. - */ + /** + * The default maximum number of days to keep messages. + */ + private static final int DEFAULT_TELL_MAX_DAYS = 7; - private static final int DEFAULT_TELL_MAX_DAYS = 7; + /** + * The default message max queue size. + */ + private static final int DEFAULT_TELL_MAX_SIZE = 50; - /** - * The default message max queue size. - */ - private static final int DEFAULT_TELL_MAX_SIZE = 50; + /** + * The serialized object file extension. + */ + private static final String SER_EXT = ".ser"; - /** - * The serialized object file extension. - */ - private static final String SER_EXT = ".ser"; + /** + * The bot instance. + */ + final private Mobibot bot; - /** - * The bot instance. - */ - final private Mobibot bot; + /** + * The maximum number of days to keep messages. + */ + final private int maxDays; - /** - * The maximum number of days to keep messages. - */ - final private int maxDays; + /** + * The message maximum queue size. + */ + final private int maxSize; - /** - * The message maximum queue size. - */ - final private int maxSize; + /** + * The messages queue. + */ + private final List<TellMessage> messages = new CopyOnWriteArrayList<>(); - /** - * The messages queue. - */ - private final List<TellMessage> messages = new CopyOnWriteArrayList<>(); + /** + * The serialized object file. + */ + private final String serializedObject; - /** - * The serialized object file. - */ - private final String serializedObject; + public Tell(final Mobibot bot, final String maxDays, final String maxSize) { + this.bot = bot; + this.maxDays = Utils.getIntProperty(maxDays, DEFAULT_TELL_MAX_DAYS); + this.maxSize = Utils.getIntProperty(maxSize, DEFAULT_TELL_MAX_SIZE); - public Tell(final Mobibot bot, final String maxDays, final String maxSize) - { - this.bot = bot; - this.maxDays = Utils.getIntProperty(maxDays, DEFAULT_TELL_MAX_DAYS); - this.maxSize = Utils.getIntProperty(maxSize, DEFAULT_TELL_MAX_SIZE); + // Load the message queue. + serializedObject = bot.getLogsDir() + bot.getName() + SER_EXT; + messages.addAll(TellMessagesMgr.load(serializedObject, bot.getLogger())); - // Load the message queue. - serializedObject = bot.getLogsDir() + bot.getName() + SER_EXT; - messages.addAll(TellMessagesMgr.load(serializedObject, bot.getLogger())); + if (clean()) { + save(); + } + } - if (clean()) - { - save(); - } - } + /** + * Cleans the messages queue. + * + * @return <code>True</code> if the queue was cleaned. + */ + private boolean clean() { + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Cleaning the messages."); + } - /** - * Cleans the messages queue. - * - * @return <code>True</code> if the queue was cleaned. - */ - private boolean clean() - { - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Cleaning the messages."); - } + return TellMessagesMgr.clean(messages, maxDays); + } - return TellMessagesMgr.clean(messages, maxDays); - } + /** + * Responds with help. + * + * @param sender The sender. + */ + public void helpResponse(final String sender) { + bot.send(sender, "To send a message to someone when they join the channel:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TELL_CMD + " <nick> <message>")); - /** - * Saves the messages queue. - */ - private void save() - { - TellMessagesMgr.save(serializedObject, messages, bot.getLogger()); - } + bot.send(sender, "To view queued and sent messages:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TELL_CMD + ' ' + Commands.VIEW_CMD)); - /** - * Processes the commands. - * - * @param sender The sender's nick. - * @param cmds The commands string. - */ - public void response(final String sender, final String cmds) - { - if (!Utils.isValidString(cmds)) - { - helpResponse(sender); - } - else if (cmds.startsWith(Commands.VIEW_CMD)) - { - if (bot.isOp(sender) && cmds.equals(Commands.VIEW_CMD + ' ' + TELL_ALL_KEYWORD)) - { - if (messages.size() > 0) - { - for (final TellMessage message : messages) - { - bot.send(sender, - Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) - + " [ID: " + message.getId() + ", " + (message.isReceived() ? "DELIVERED" : "QUEUED") - + ']', - true); - } - } - else - { - bot.send(sender, "There are no messages in the queue.", true); - } - } - else - { - boolean hasMessage = false; + bot.send(sender, "Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days.")); + } - for (final TellMessage message : messages) - { - if (message.isMatch(sender)) - { - if (!hasMessage) - { - hasMessage = true; - bot.send(sender, "Here are your messages: ", true); - } + /** + * Returns <code>true</code> if enabled. + * + * @return <code>true</code> or <code>false</code> + */ + public boolean isEnabled() { + return maxSize > 0 && maxDays > 0; + } - if (message.isReceived()) - { - bot.send(sender, - Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) - + " [" + Utils.UTC_SDF.format(message.getReceived()) + ", ID: " + message.getId() - + ", DELIVERED]", - true); + /** + * Processes the commands. + * + * @param sender The sender's nick. + * @param cmds The commands string. + */ + public void response(final String sender, final String cmds) { + if (!Utils.isValidString(cmds)) { + helpResponse(sender); + } else if (cmds.startsWith(Commands.VIEW_CMD)) { + if (bot.isOp(sender) && cmds.equals(Commands.VIEW_CMD + ' ' + TELL_ALL_KEYWORD)) { + if (messages.size() > 0) { + for (final TellMessage message : messages) { + bot.send(sender, Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) + + " [ID: " + message.getId() + ", " + + (message.isReceived() ? "DELIVERED" : "QUEUED") + ']', + true); + } + } else { + bot.send(sender, "There are no messages in the queue.", true); + } + } else { + boolean hasMessage = false; - } - else - { - bot.send(sender, - Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) - + " [" + Utils.UTC_SDF.format(message.getQueued()) + ", ID: " + message.getId() - + ", QUEUED]", - true); - } + for (final TellMessage message : messages) { + if (message.isMatch(sender)) { + if (!hasMessage) { + hasMessage = true; + bot.send(sender, "Here are your messages: ", true); + } - bot.send(sender, bot.helpIndent(message.getMessage(), false), true); - } - } + if (message.isReceived()) { + bot.send(sender, + Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) + + " [" + Utils.UTC_SDF.format(message.getReceived()) + ", ID: " + + message.getId() + ", DELIVERED]", + true); - if (!hasMessage) - { - bot.send(sender, "You have no messages in the queue.", true); - } - else - { - bot.send(sender, "To delete one or all delivered messages:"); - bot.send(sender, - bot.helpIndent(bot.getNick() + ": " + TELL_CMD + ' ' + TELL_DEL_KEYWORD + " <id|" - + TELL_ALL_KEYWORD + '>')); - bot.send(sender, - "Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days.")); - } - } - } - else if (cmds.startsWith(TELL_DEL_KEYWORD + ' ')) - { - final String[] split = cmds.split(" "); + } else { + bot.send(sender, + Utils.bold(message.getSender()) + " --> " + Utils.bold(message.getRecipient()) + + " [" + Utils.UTC_SDF.format(message.getQueued()) + ", ID: " + + message.getId() + ", QUEUED]", + true); + } - if (split.length == 2) - { - final String id = split[1]; - boolean deleted = false; + bot.send(sender, bot.helpIndent(message.getMessage(), false), true); + } + } - if (id.equalsIgnoreCase(TELL_ALL_KEYWORD)) - { - for (final TellMessage message : messages) - { - if (message.getSender().equalsIgnoreCase(sender) && message.isReceived()) - { - messages.remove(message); - deleted = true; - } - } + if (!hasMessage) { + bot.send(sender, "You have no messages in the queue.", true); + } else { + bot.send(sender, "To delete one or all delivered messages:"); + bot.send(sender, + bot.helpIndent(bot.getNick() + ": " + TELL_CMD + ' ' + TELL_DEL_KEYWORD + " <id|" + + TELL_ALL_KEYWORD + '>')); + bot.send(sender, "Messages are kept for " + Utils.bold(maxDays) + + Utils.plural(maxDays, " day.", " days.")); + } + } + } else if (cmds.startsWith(TELL_DEL_KEYWORD + ' ')) { + final String[] split = cmds.split(" "); - if (deleted) - { - save(); - bot.send(sender, "Delivered messages have been deleted.", true); - } - else - { - bot.send(sender, "No delivered messages were found.", true); - } + if (split.length == 2) { + final String id = split[1]; + boolean deleted = false; - } - else - { - boolean found = false; + if (id.equalsIgnoreCase(TELL_ALL_KEYWORD)) { + for (final TellMessage message : messages) { + if (message.getSender().equalsIgnoreCase(sender) && message.isReceived()) { + messages.remove(message); + deleted = true; + } + } - for (final TellMessage message : messages) - { - found = message.isMatchId(id); + if (deleted) { + save(); + bot.send(sender, "Delivered messages have been deleted.", true); + } else { + bot.send(sender, "No delivered messages were found.", true); + } - if (found && (message.getSender().equalsIgnoreCase(sender) || bot.isOp(sender))) - { - messages.remove(message); + } else { + boolean found = false; - save(); - bot.send(sender, "Your message was deleted from the queue.", true); - deleted = true; - break; - } - } + for (final TellMessage message : messages) { + found = message.isMatchId(id); - if (!deleted) - { - if (found) - { - bot.send(sender, "Only messages that you sent can be deleted.", true); - } - else - { - bot.send(sender, "The specified message [ID " + id + "] could not be found.", true); - } - } - } - } - else - { - helpResponse(sender); - } - } - else - { - final String[] split = cmds.split(" ", 2); + if (found && (message.getSender().equalsIgnoreCase(sender) || bot.isOp(sender))) { + messages.remove(message); - if (split.length == 2 && (Utils.isValidString(split[1]) && split[1].contains(" "))) - { - if (messages.size() < maxSize) - { - final TellMessage message = new TellMessage(sender, split[0], split[1].trim()); + save(); + bot.send(sender, "Your message was deleted from the queue.", true); + deleted = true; + break; + } + } - messages.add(message); + if (!deleted) { + if (found) { + bot.send(sender, "Only messages that you sent can be deleted.", true); + } else { + bot.send(sender, "The specified message [ID " + id + "] could not be found.", true); + } + } + } + } else { + helpResponse(sender); + } + } else { + final String[] split = cmds.split(" ", 2); - save(); + if (split.length == 2 && (Utils.isValidString(split[1]) && split[1].contains(" "))) { + if (messages.size() < maxSize) { + final TellMessage message = new TellMessage(sender, split[0], split[1].trim()); - bot.send(sender, - "Message [ID " + message.getId() + "] was queued for " + Utils - .bold(message.getRecipient()), true); - } - else - { - bot.send(sender, "Sorry, the messages queue is currently full.", true); - } - } - else - { - helpResponse(sender); - } - } + messages.add(message); - if (clean()) - { - save(); - } - } + save(); - /** - * Responds with help. - * - * @param sender The sender. - */ - public void helpResponse(final String sender) - { - bot.send(sender, "To send a message to someone when they join the channel:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TELL_CMD + " <nick> <message>")); + bot.send(sender, "Message [ID " + message.getId() + "] was queued for " + + Utils.bold(message.getRecipient()), true); + } else { + bot.send(sender, "Sorry, the messages queue is currently full.", true); + } + } else { + helpResponse(sender); + } + } - bot.send(sender, "To view queued and sent messages:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TELL_CMD + ' ' + Commands.VIEW_CMD)); + if (clean()) save(); + } - bot.send(sender, "Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days.")); - } + /** + * Saves the messages queue. + */ + private void save() { + TellMessagesMgr.save(serializedObject, messages, bot.getLogger()); + } - /** - * Checks and sends messages. - * - * @param nickname The user's nickname. - */ - public void send(final String nickname) - { - send(nickname, false); - } + /** + * Checks and sends messages. + * + * @param nickname The user's nickname. + * @param isMessage The message flag. + */ + public void send(final String nickname, final boolean isMessage) { + if (!nickname.equals(bot.getNick()) && isEnabled()) { + messages.stream().filter(message -> message.isMatch(nickname)).forEach( + message -> { + if (message.getRecipient().equalsIgnoreCase(nickname) && !message.isReceived()) { + if (message.getSender().equals(nickname)) { + if (!isMessage) { + bot.send(nickname, Utils.bold("You") + " wanted me to remind you: " + + Utils.reverseColor(message.getMessage()), + true); - /** - * Checks and sends messages. - * - * @param nickname The user's nickname. - * @param isMessage The message flag. - */ - public void send(final String nickname, final boolean isMessage) - { - if (!nickname.equals(bot.getNick()) && isEnabled()) - { - messages.stream().filter(message -> message.isMatch(nickname)).forEach(message -> { - if (message.getRecipient().equalsIgnoreCase(nickname) && !message.isReceived()) - { - if (message.getSender().equals(nickname)) - { - if (!isMessage) - { - bot.send(nickname, - Utils.bold("You") + " wanted me to remind you: " + Utils - .reverseColor(message.getMessage()), - true); + message.setIsReceived(); + message.setIsNotified(); - message.setIsReceived(); - message.setIsNotified(); + save(); + } + } else { + bot.send(nickname, message.getSender() + " wanted me to tell you: " + + Utils.reverseColor(message.getMessage()), + true); - save(); - } - } - else - { - bot.send(nickname, - message.getSender() + " wanted me to tell you: " + Utils - .reverseColor(message.getMessage()), - true); + message.setIsReceived(); - message.setIsReceived(); + save(); + } + } else if (message.getSender().equalsIgnoreCase(nickname) && message.isReceived() + && !message.isNotified()) { + bot.send(nickname, + "Your message " + + Utils.reverseColor("[ID " + message.getId() + ']') + " was sent to " + + Utils.bold(message.getRecipient()) + " on " + + Utils.UTC_SDF.format(message.getReceived()), + true); - save(); - } - } - else if (message.getSender().equalsIgnoreCase(nickname) && message.isReceived() && !message - .isNotified()) - { - bot.send(nickname, - "Your message " + Utils.reverseColor("[ID " + message.getId() + ']') + " was sent to " - + Utils.bold(message.getRecipient()) + " on " + Utils.UTC_SDF - .format(message.getReceived()), - true); + message.setIsNotified(); - message.setIsNotified(); + save(); + } + }); + } + } - save(); - } - }); - } - } + /** + * Checks and sends messages. + * + * @param nickname The user's nickname. + */ + public void send(final String nickname) { + send(nickname, false); + } - /** - * Returns <code>true</code> if enabled. - * - * @return <code>true</code> or <code>false</code> - */ - public boolean isEnabled() - { - return maxSize > 0 && maxDays > 0; - } - - /** - * Returns the messages queue size. - * - * @return The size. - */ - public int size() - { - return messages.size(); - } + /** + * Returns the messages queue size. + * + * @return The size. + */ + public int size() { + return messages.size(); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/TellMessage.java b/src/main/java/net/thauvin/erik/mobibot/TellMessage.java index 1d20b77..dc64bc0 100644 --- a/src/main/java/net/thauvin/erik/mobibot/TellMessage.java +++ b/src/main/java/net/thauvin/erik/mobibot/TellMessage.java @@ -42,162 +42,138 @@ import java.util.Date; * @created 2014-04-24 * @since 1.0 */ -public class TellMessage implements Serializable -{ - private static final long serialVersionUID = 1L; +public class TellMessage implements Serializable { + private static final long serialVersionUID = 1L; + private final String id; + private final String message; + final private Date queued; + private final String recipient; + private final String sender; + private boolean isNotified; + private boolean isReceived; + private Date received; - private final String id; + /** + * Create a new message. + * + * @param sender The sender's nick. + * @param recipient The recipient's nick. + * @param message The message. + */ + public TellMessage(final String sender, final String recipient, final String message) { + this.sender = sender; + this.recipient = recipient; + this.message = message; - private final String message; + this.queued = Calendar.getInstance().getTime(); + this.id = Utils.TIMESTAMP_SDF.format(this.queued); - final private Date queued; + } - private final String recipient; + /** + * Returns the message id. + * + * @return The message id. + */ + public String getId() { + return id; + } - private final String sender; + /** + * Returns the message text. + * + * @return The text of the message. + */ + public String getMessage() { + return message; + } - private boolean isNotified; + /** + * Returns the state of the queue flag. + * + * @return <code>true</code> if the message is queued. + */ + public Date getQueued() { + return queued; + } - private boolean isReceived; + /** + * Returns the state of the received flag. + * + * @return <code>true</code> if the message has been received. + */ + public Date getReceived() { + return received; + } - private Date received; + /** + * Returns the message's recipient. + * + * @return The recipient of the message. + */ + public String getRecipient() { + return recipient; + } - /** - * Create a new message. - * - * @param sender The sender's nick. - * @param recipient The recipient's nick. - * @param message The message. - */ - public TellMessage(final String sender, final String recipient, final String message) - { - this.sender = sender; - this.recipient = recipient; - this.message = message; + /** + * Returns the message's sender. + * + * @return The sender of the message. + */ + public String getSender() { + return sender; + } - this.queued = Calendar.getInstance().getTime(); - this.id = Utils.TIMESTAMP_SDF.format(this.queued); + /** + * Matches the message sender or recipient. + * + * @param nick The nickname to match with. + * @return <code>true</code> if the nickname matches. + */ + public boolean isMatch(final String nick) { + return (sender.equalsIgnoreCase(nick) || recipient.equalsIgnoreCase(nick)); + } - } + /** + * Match the message ID. + * + * @param id The ID to match with. + * @return <code>true</code> if the id matches. + */ + public boolean isMatchId(final String id) { + return this.id.equals(id); + } - /** - * Returns the message id. - * - * @return The message id. - */ - public String getId() - { - return id; - } + /** + * Returns the notification flag state. + * + * @return <code>true</code> if the sender has been notified. + */ + public boolean isNotified() { + return isNotified; + } - /** - * Returns the message text. - * - * @return The text of the message. - */ - public String getMessage() - { - return message; - } + /** + * Returns the received flag state. + * + * @return <code>true</code> if the message was received. + */ + public boolean isReceived() { + return isReceived; + } - /** - * Returns the state of the queue flag. - * - * @return <code>true</code> if the message is queued. - */ - public Date getQueued() - { - return queued; - } + /** + * Sets the notified flag. + */ + public void setIsNotified() { + isNotified = true; + } - /** - * Returns the state of the received flag. - * - * @return <code>true</code> if the message has been received. - */ - public Date getReceived() - { - return received; - } - - /** - * Returns the message's recipient. - * - * @return The recipient of the message. - */ - public String getRecipient() - { - return recipient; - } - - /** - * Returns the message's sender. - * - * @return The sender of the message. - */ - public String getSender() - { - return sender; - } - - /** - * Matches the message sender or recipient. - * - * @param nick The nickname to match with. - * - * @return <code>true</code> if the nickname matches. - */ - public boolean isMatch(final String nick) - { - return (sender.equalsIgnoreCase(nick) || recipient.equalsIgnoreCase(nick)); - } - - /** - * Match the message ID. - * - * @param id The ID to match with. - * - * @return <code>true</code> if the id matches. - */ - public boolean isMatchId(final String id) - { - return this.id.equals(id); - } - - /** - * Returns the notification flag state. - * - * @return <code>true</code> if the sender has been notified. - */ - public boolean isNotified() - { - return isNotified; - } - - /** - * Returns the received flag state. - * - * @return <code>true</code> if the message was received. - */ - public boolean isReceived() - { - return isReceived; - } - - /** - * Sets the notified flag. - */ - public void setIsNotified() - { - isNotified = true; - } - - /** - * Sets the received flag. - */ - public void setIsReceived() - { - received = Calendar.getInstance().getTime(); - isReceived = true; - } + /** + * Sets the received flag. + */ + public void setIsReceived() { + received = Calendar.getInstance().getTime(); + isReceived = true; + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/TellMessagesMgr.java b/src/main/java/net/thauvin/erik/mobibot/TellMessagesMgr.java index 1137f0b..37e0346 100644 --- a/src/main/java/net/thauvin/erik/mobibot/TellMessagesMgr.java +++ b/src/main/java/net/thauvin/erik/mobibot/TellMessagesMgr.java @@ -46,113 +46,90 @@ import java.util.List; * @created 2014-04-26 * @since 1.0 */ -final class TellMessagesMgr -{ - /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. - */ - private TellMessagesMgr() - throws UnsupportedOperationException - { - throw new UnsupportedOperationException("Illegal constructor call."); - } +final class TellMessagesMgr { + /** + * Disables the default constructor. + * + * @throws UnsupportedOperationException If the constructor is called. + */ + private TellMessagesMgr() + throws UnsupportedOperationException { + throw new UnsupportedOperationException("Illegal constructor call."); + } - /** - * Cleans the messages queue - * - * @param tellMessages The messages list. - * @param tellMaxDays The maximum number of days to keep messages for. - * - * @return <code>True</code> if the queue was cleaned. - */ - public static boolean clean(final List<TellMessage> tellMessages, final int tellMaxDays) - { - final Calendar maxDate = Calendar.getInstance(); - final Date today = new Date(); - boolean cleaned = false; + /** + * Cleans the messages queue + * + * @param tellMessages The messages list. + * @param tellMaxDays The maximum number of days to keep messages for. + * @return <code>True</code> if the queue was cleaned. + */ + public static boolean clean(final List<TellMessage> tellMessages, final int tellMaxDays) { + final Calendar maxDate = Calendar.getInstance(); + final Date today = new Date(); + boolean cleaned = false; - for (final TellMessage message : tellMessages) - { - maxDate.setTime(message.getQueued()); - maxDate.add(Calendar.DATE, tellMaxDays); + for (final TellMessage message : tellMessages) { + maxDate.setTime(message.getQueued()); + maxDate.add(Calendar.DATE, tellMaxDays); - if (maxDate.getTime().before(today)) - { - tellMessages.remove(message); - cleaned = true; - } - } + if (maxDate.getTime().before(today)) { + tellMessages.remove(message); + cleaned = true; + } + } - return cleaned; - } + return cleaned; + } - /** - * Loads the messages. - * - * @param file The serialized objects file. - * @param logger The logger. - * - * @return The {@link net.thauvin.erik.mobibot.TellMessage} array. - */ - @SuppressWarnings("unchecked") - public static List<TellMessage> load(final String file, final Log4JLogger logger) - { - try - { + /** + * Loads the messages. + * + * @param file The serialized objects file. + * @param logger The logger. + * @return The {@link net.thauvin.erik.mobibot.TellMessage} array. + */ + @SuppressWarnings("unchecked") + public static List<TellMessage> load(final String file, final Log4JLogger logger) { + try { - try (ObjectInput input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) - { - if (logger.isDebugEnabled()) - { - logger.debug("Loading the messages."); - } + try (ObjectInput input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { + if (logger.isDebugEnabled()) { + logger.debug("Loading the messages."); + } - return ((List<TellMessage>) input.readObject()); - } - } - catch (FileNotFoundException ignore) - { - ; // Do nothing. - } - catch (IOException e) - { - logger.error("An IO error occurred loading the messages queue.", e); - } - catch (Exception e) - { - logger.getLogger().error("An error occurred loading the messages queue.", e); - } + return ((List<TellMessage>) input.readObject()); + } + } catch (FileNotFoundException ignore) { + ; // Do nothing. + } catch (IOException e) { + logger.error("An IO error occurred loading the messages queue.", e); + } catch (Exception e) { + logger.getLogger().error("An error occurred loading the messages queue.", e); + } - return new ArrayList<>(); - } + return new ArrayList<>(); + } - /** - * Saves the messages. - * - * @param file The serialized objects file. - * @param messages The {@link net.thauvin.erik.mobibot.TellMessage} array. - * @param logger The logger. - */ - public static void save(final String file, final List<TellMessage> messages, final Log4JLogger logger) - { - try - { + /** + * Saves the messages. + * + * @param file The serialized objects file. + * @param messages The {@link net.thauvin.erik.mobibot.TellMessage} array. + * @param logger The logger. + */ + public static void save(final String file, final List<TellMessage> messages, final Log4JLogger logger) { + try { - try (ObjectOutput output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) - { - if (logger.isDebugEnabled()) - { - logger.debug("Saving the messages."); - } + try (ObjectOutput output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { + if (logger.isDebugEnabled()) { + logger.debug("Saving the messages."); + } - output.writeObject(messages); - } - } - catch (IOException e) - { - logger.error("Unable to save messages queue.", e); - } - } + output.writeObject(messages); + } + } catch (IOException e) { + logger.error("Unable to save messages queue.", e); + } + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java b/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java index 45efe3b..5f3b492 100644 --- a/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java +++ b/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java @@ -9,68 +9,61 @@ import java.io.BufferedReader; import java.io.InputStreamReader; /** - * The <code>TwitterOAuth</code> class. <p> Go to <a href="http://twitter.com/oauth_clients/new">http://twitter.com/oauth_clients/new</a> - * to register your bot. </p> Then execute: <p> <code>java -cp "mobibot.jar:lib/*" - * net.thauvin.erik.mobibot.TwitterOAuth - * <consumerKey> <consumerSecret></code> </p> and follow the prompts/instructions. + * The <code>TwitterOAuth</code> class. + * <p> + * Go to <a href="http://twitter.com/oauth_clients/new">http://twitter.com/oauth_clients/new</a> to register your bot. + * </p> + * Then execute: + * <p> + * <code> + * java -cp "mobibot.jar:lib/*"net.thauvin.erik.mobibot.TwitterOAuth <consumerKey> <consumerSecret> + * </code> + * </p> + * and follow the prompts/instructions. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @author <a href="http://twitter4j.org/en/code-examples.html#oauth">http://twitter4j.org/en/code-examples.html#oauth</a> * @created Sep 13, 2010 * @since 1.0 */ -public final class TwitterOAuth -{ - public static void main(final String[] args) - throws Exception - { - if (args.length == 2) - { - final twitter4j.Twitter twitter = new TwitterFactory().getInstance(); - twitter.setOAuthConsumer(args[0], args[1]); - final RequestToken requestToken = twitter.getOAuthRequestToken(); - AccessToken accessToken = null; - final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - while (null == accessToken) - { - System.out.println("Open the following URL and grant access to your account:"); - System.out.println(requestToken.getAuthorizationURL()); - System.out.print("Enter the PIN (if available) or just hit enter.[PIN]:"); - final String pin = br.readLine(); - try - { - if (pin.length() > 0) - { - accessToken = twitter.getOAuthAccessToken(requestToken, pin); - } - else - { - accessToken = twitter.getOAuthAccessToken(); - } +public final class TwitterOAuth { + public static void main(final String[] args) + throws Exception { + if (args.length == 2) { + final twitter4j.Twitter twitter = new TwitterFactory().getInstance(); + twitter.setOAuthConsumer(args[0], args[1]); + final RequestToken requestToken = twitter.getOAuthRequestToken(); + AccessToken accessToken = null; + final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + while (null == accessToken) { + System.out.println("Open the following URL and grant access to your account:"); + System.out.println(requestToken.getAuthorizationURL()); + System.out.print("Enter the PIN (if available) or just hit enter.[PIN]:"); + final String pin = br.readLine(); + try { + if (pin.length() > 0) { + accessToken = twitter.getOAuthAccessToken(requestToken, pin); + } else { + accessToken = twitter.getOAuthAccessToken(); + } - System.out.println( - "Please add the following to the bot's property file:" + "\n\n" + "twitter-consumerKey=" - + args[0] + '\n' + "twitter-consumerSecret=" + args[1] + '\n' + "twitter-token=" - + accessToken.getToken() + '\n' + "twitter-tokenSecret=" + accessToken.getTokenSecret()); - } - catch (TwitterException te) - { - if (401 == te.getStatusCode()) - { - System.out.println("Unable to get the access token."); - } - else - { - te.printStackTrace(); - } - } - } - } - else - { - System.out.println("Usage: " + TwitterOAuth.class.getName() + " <consumerKey> <consumerSecret>"); - } + System.out.println( + "Please add the following to the bot's property file:" + "\n\n" + "twitter-consumerKey=" + + args[0] + '\n' + "twitter-consumerSecret=" + args[1] + '\n' + "twitter-token=" + + accessToken.getToken() + '\n' + "twitter-tokenSecret=" + accessToken + .getTokenSecret()); + } catch (TwitterException te) { + if (401 == te.getStatusCode()) { + System.out.println("Unable to get the access token."); + } else { + te.printStackTrace(); + } + } + } + } else { + System.out.println("Usage: " + TwitterOAuth.class.getName() + " <consumerKey> <consumerSecret>"); + } - System.exit(0); - } + System.exit(0); + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/Utils.java b/src/main/java/net/thauvin/erik/mobibot/Utils.java index 174d373..99586fc 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Utils.java +++ b/src/main/java/net/thauvin/erik/mobibot/Utils.java @@ -44,288 +44,235 @@ import java.util.Calendar; * @created 2014-04-26 * @since 1.0 */ -final public class Utils -{ - /** - * The ISO (YYYY-MM-DD) simple date format. - */ - public static final SimpleDateFormat ISO_SDF = new SimpleDateFormat("yyyy-MM-dd"); +final public class Utils { + /** + * The ISO (YYYY-MM-DD) simple date format. + */ + public static final SimpleDateFormat ISO_SDF = new SimpleDateFormat("yyyy-MM-dd"); + /** + * The timestamp simple date format. + */ + public static final SimpleDateFormat TIMESTAMP_SDF = new SimpleDateFormat("yyyyMMddHHmmss"); + /** + * The UTC (yyyy-MM-dd HH:mm) simple date format. + */ + public static final SimpleDateFormat UTC_SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - /** - * The timestamp simple date format. - */ - public static final SimpleDateFormat TIMESTAMP_SDF = new SimpleDateFormat("yyyyMMddHHmmss"); + /** + * Disables the default constructor. + * + * @throws UnsupportedOperationException If the constructor is called. + */ + private Utils() + throws UnsupportedOperationException { + throw new UnsupportedOperationException("Illegal constructor call."); + } - /** - * The UTC (yyyy-MM-dd HH:mm) simple date format. - */ - public static final SimpleDateFormat UTC_SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + /** + * Makes the given int bold. + * + * @param i The int. + * @return The bold string. + */ + public static String bold(final int i) { + return bold(Integer.toString(i)); + } - /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. - */ - private Utils() - throws UnsupportedOperationException - { - throw new UnsupportedOperationException("Illegal constructor call."); - } + /** + * Makes the given string bold. + * + * @param s The string. + * @return The bold string. + */ + public static String bold(final String s) { + return Colors.BOLD + s + Colors.BOLD; + } - /** - * Makes the given int bold. - * - * @param i The int. - * - * @return The bold string. - */ - public static String bold(final int i) - { - return bold(Integer.toString(i)); - } + /** + * Builds an entry's comment for display on the channel. + * + * @param entryIndex The entry's index. + * @param commentIndex The comment's index. + * @param comment The {@link net.thauvin.erik.mobibot.EntryComment comment} object. + * @return The entry's comment. + */ + static String buildComment(final int entryIndex, final int commentIndex, final EntryComment comment) { + return (Commands.LINK_CMD + (entryIndex + 1) + '.' + (commentIndex + 1) + ": [" + comment.getNick() + "] " + + comment.getComment()); + } - /** - * Makes the given string bold. - * - * @param s The string. - * - * @return The bold string. - */ - public static String bold(final String s) - { - return Colors.BOLD + s + Colors.BOLD; - } + /** + * Builds an entry's link for display on the channel. + * + * @param index The entry's index. + * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. + * @return The entry's link. + * @see #buildLink(int, net.thauvin.erik.mobibot.EntryLink, boolean) + */ + static String buildLink(final int index, final EntryLink entry) { + return buildLink(index, entry, false); + } - /** - * Builds an entry's comment for display on the channel. - * - * @param entryIndex The entry's index. - * @param commentIndex The comment's index. - * @param comment The {@link net.thauvin.erik.mobibot.EntryComment comment} object. - * - * @return The entry's comment. - */ - static String buildComment(final int entryIndex, final int commentIndex, final EntryComment comment) - { - return (Commands.LINK_CMD + (entryIndex + 1) + '.' + (commentIndex + 1) + ": [" + comment.getNick() + "] " - + comment.getComment()); - } + /** + * Builds an entry's link for display on the channel. + * + * @param index The entry's index. + * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. + * @param isView Set to true to display the number of comments. + * @return The entry's link. + */ + static String buildLink(final int index, final EntryLink entry, final boolean isView) { + final StringBuilder buff = new StringBuilder(Commands.LINK_CMD + (index + 1) + ": "); - /** - * Builds an entry's link for display on the channel. - * - * @param index The entry's index. - * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. - * - * @return The entry's link. - * - * @see #buildLink(int, net.thauvin.erik.mobibot.EntryLink, boolean) - */ - static String buildLink(final int index, final EntryLink entry) - { - return buildLink(index, entry, false); - } + buff.append('[').append(entry.getNick()).append(']'); - /** - * Builds an entry's link for display on the channel. - * - * @param index The entry's index. - * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. - * @param isView Set to true to display the number of comments. - * - * @return The entry's link. - */ - static String buildLink(final int index, final EntryLink entry, final boolean isView) - { - final StringBuilder buff = new StringBuilder(Commands.LINK_CMD + (index + 1) + ": "); + if (isView && entry.hasComments()) { + buff.append("[+").append(entry.getCommentsCount()).append(']'); + } - buff.append('[').append(entry.getNick()).append(']'); + buff.append(' '); - if (isView && entry.hasComments()) - { - buff.append("[+").append(entry.getCommentsCount()).append(']'); - } + if (Mobibot.NO_TITLE.equals(entry.getTitle())) { + buff.append(entry.getTitle()); + } else { + buff.append(bold(entry.getTitle())); + } - buff.append(' '); + buff.append(" ( ").append(Utils.green(entry.getLink())).append(" )"); - if (Mobibot.NO_TITLE.equals(entry.getTitle())) - { - buff.append(entry.getTitle()); - } - else - { - buff.append(bold(entry.getTitle())); - } + return buff.toString(); + } - buff.append(" ( ").append(Utils.green(entry.getLink())).append(" )"); + /** + * Build an entry's tags/categories for display on the channel. + * + * @param entryIndex The entry's index. + * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. + * @return The entry's tags. + */ + static String buildTags(final int entryIndex, final EntryLink entry) { + return (Commands.LINK_CMD + (entryIndex + 1) + "T: " + entry.getDeliciousTags().replaceAll(",", ", ")); + } - return buff.toString(); - } + /** + * Ensures that the given location (File/URL) has a trailing slash (<code>/</code>) to indicate a directory. + * + * @param location The File or URL location. + * @param isUrl Set to true if the location is a URL + * @return The location ending with a slash. + */ + static String ensureDir(final String location, final boolean isUrl) { + if (isUrl) { + if (location.charAt(location.length() - 1) == '/') { + return location; + } else { + return location + '/'; + } + } else { + if (location.charAt(location.length() - 1) == File.separatorChar) { + return location; + } else { + return location + File.separatorChar; + } + } + } - /** - * Makes the given string green. - * - * @param s The string. - * - * @return The bold string. - */ - public static String green(final String s) - { - return Colors.DARK_GREEN + s + Colors.NORMAL; - } + /** + * Returns a property as an int. + * + * @param property The port property value. + * @param def The default property value. + * @return The port or default value if invalid. + */ + public static int getIntProperty(final String property, final int def) { + int prop; - /** - * Build an entry's tags/categories for display on the channel. - * - * @param entryIndex The entry's index. - * @param entry The {@link net.thauvin.erik.mobibot.EntryLink entry} object. - * - * @return The entry's tags. - */ - static String buildTags(final int entryIndex, final EntryLink entry) - { - return (Commands.LINK_CMD + (entryIndex + 1) + "T: " + entry.getDeliciousTags().replaceAll(",", ", ")); - } + try { + prop = Integer.parseInt(property); + } catch (NumberFormatException ignore) { + prop = def; + } - /** - * Ensures that the given location (File/URL) has a trailing slash (<code>/</code>) to indicate a directory. - * - * @param location The File or URL location. - * @param isUrl Set to true if the location is a URL - * - * @return The location ending with a slash. - */ - static String ensureDir(final String location, final boolean isUrl) - { - if (isUrl) - { - if (location.charAt(location.length() - 1) == '/') - { - return location; - } - else - { - return location + '/'; - } - } - else - { - if (location.charAt(location.length() - 1) == File.separatorChar) - { - return location; - } - else - { - return location + File.separatorChar; - } - } - } + return prop; + } - /** - * Returns a property as an int. - * - * @param property The port property value. - * @param def The default property value. - * - * @return The port or default value if invalid. - */ - public static int getIntProperty(final String property, final int def) - { - int prop; + /** + * Makes the given string green. + * + * @param s The string. + * @return The bold string. + */ + public static String green(final String s) { + return Colors.DARK_GREEN + s + Colors.NORMAL; + } - try - { - prop = Integer.parseInt(property); - } - catch (NumberFormatException ignore) - { - prop = def; - } + /** + * Returns <code>true</code> if the given string is <em>not</em> blank or null. + * + * @param s The string to check. + * @return <code>true</code> if the string is valid, <code>false</code> otherwise. + */ + public static boolean isValidString(final CharSequence s) { + final int len; + if (s == null || (len = s.length()) == 0) { + return false; + } + for (int i = 0; i < len; i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return true; + } + } + return false; + } - return prop; - } + /** + * Returns the plural form of a word, if count > 1. + * + * @param count The count. + * @param word The word. + * @param plural The plural word. + */ + public static String plural(final long count, final String word, final String plural) { + if (count > 1) { + return plural; + } else { + return word; + } + } - /** - * Returns <code>true</code> if the given string is <em>not</em> blank or null. - * - * @param s The string to check. - * - * @return <code>true</code> if the string is valid, <code>false</code> otherwise. - */ - public static boolean isValidString(final CharSequence s) - { - final int len; - if (s == null || (len = s.length()) == 0) - { - return false; - } - for (int i = 0; i < len; i++) - { - if (!Character.isWhitespace(s.charAt(i))) - { - return true; - } - } - return false; - } + /** + * Makes the given string reverse color. + * + * @param s The string. + * @return The reverse color string. + */ + public static String reverseColor(final String s) { + return Colors.REVERSE + s + Colors.REVERSE; + } - /** - * Returns the plural form of a word, if count > 1. - * - * @param count The count. - * @param word The word. - * @param plural The plural word. - */ - public static String plural(final long count, final String word, final String plural) - { - if (count > 1) - { - return plural; - } - else - { - return word; - } - } + /** + * Returns today's date. + * + * @return Today's date in {@link #ISO_SDF ISO} format. + */ + public static String today() { + return ISO_SDF.format(Calendar.getInstance().getTime()); + } - /** - * Makes the given string reverse color. - * - * @param s The string. - * - * @return The reverse color string. - */ - public static String reverseColor(final String s) - { - return Colors.REVERSE + s + Colors.REVERSE; - } + /** + * Converts XML/XHTML entities to plain text. + * + * @param str The string to unescape. + * @return The unescaped string. + */ + public static String unescapeXml(final String str) { + String s = str.replaceAll("&", "&"); + s = s.replaceAll("<", "<"); + s = s.replaceAll(">", ">"); + s = s.replaceAll(""", "\""); + s = s.replaceAll("'", "'"); + s = s.replaceAll("'", "'"); - /** - * Returns today's date. - * - * @return Today's date in {@link #ISO_SDF ISO} format. - */ - public static String today() - { - return ISO_SDF.format(Calendar.getInstance().getTime()); - } - - /** - * Converts XML/XHTML entities to plain text. - * - * @param str The string to unescape. - * - * @return The unescaped string. - */ - public static String unescapeXml(final String str) - { - String s = str.replaceAll("&", "&"); - s = s.replaceAll("<", "<"); - s = s.replaceAll(">", ">"); - s = s.replaceAll(""", "\""); - s = s.replaceAll("'", "'"); - s = s.replaceAll("'", "'"); - - return s; - } + return s; + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java index f43b31a..678ac99 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java @@ -43,118 +43,105 @@ import java.util.*; * @created 2016-07-01 * @since 1.0 */ -public abstract class AbstractModule -{ +public abstract class AbstractModule { + final List<String> commands = new ArrayList<>(); + final Map<String, String> properties = new HashMap<>(); - final List<String> commands = new ArrayList<>(); + /** + * Responds to a command. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + public abstract void commandResponse(final Mobibot bot, + final String sender, + final String args, + final boolean isPrivate); - final Map<String, String> properties = new HashMap<>(); + /** + * Returns the module's commands, if any. + * + * @return The commands. + */ + public List<String> getCommands() { + return commands; + } - /** - * Responds to a command. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - public abstract void commandResponse(final Mobibot bot, - final String sender, - final String args, - final boolean isPrivate); + /** + * Returns the module's property keys. + * + * @return The keys. + */ + public Set<String> getPropertyKeys() { + return properties.keySet(); + } - /** - * Returns the module's commands, if any. - * - * @return The commands. - */ - public List<String> getCommands() - { - return commands; - } + /** + * Returns <code>true</code> if the module has properties. + * + * @return <code>true</code> or <code>false</code> . + */ + public boolean hasProperties() { + return !properties.isEmpty(); + } - /** - * Returns the module's property keys. - * - * @return The keys. - */ - public Set<String> getPropertyKeys() - { - return properties.keySet(); - } + /** + * Responds with the module's help. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The help arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + public abstract void helpResponse(final Mobibot bot, + final String sender, + final String args, + final boolean isPrivate); - /** - * Returns <code>true</code> if the module has properties. - * - * @return <code>true</code> or <code>false</code> . - */ - public boolean hasProperties() - { - return !properties.isEmpty(); - } + /** + * Returns <code>true</code> if the module is enabled. + * + * @return <code>true</code> or <code>false</code> + */ + public boolean isEnabled() { + return true; + } - /** - * Responds with the module's help. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The help arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - public abstract void helpResponse(final Mobibot bot, - final String sender, - final String args, - final boolean isPrivate); + /** + * Returns <codde>true</codde> if the module responds to private messages. + * + * @return <code>true</code> or <code>false</code> + */ + public boolean isPrivateMsgEnabled() { + return false; + } - /** - * Returns <code>true</code> if the module is enabled. - * - * @return <code>true</code> or <code>false</code> - */ - public boolean isEnabled() - { - return true; - } + /** + * Ensures that all properties have values. + * + * @return <code>true</code> if the properties are valid, <code>false</code> otherwise. + */ + public boolean isValidProperties() { + for (final String s : getPropertyKeys()) { + if (!Utils.isValidString(properties.get(s))) { + return false; + } + } - /** - * Returns <codde>true</codde> if the module responds to private messages. - * - * @return <code>true</code> or <code>false</code> - */ - public boolean isPrivateMsgEnabled() - { - return false; - } + return true; + } - /** - * Ensures that all properties have values. - * - * @return <code>true</code> if the properties are valid, <code>false</code> otherwise. - */ - public boolean isValidProperties() - { - for (final String s : getPropertyKeys()) - { - if (!Utils.isValidString(properties.get(s))) - { - return false; - } - } - - return true; - } - - /** - * Sets a property key and value. - * - * @param key The key. - * @param value The value. - */ - public void setProperty(final String key, final String value) - { - if (Utils.isValidString(key)) - { - properties.put(key, value); - } - } + /** + * Sets a property key and value. + * + * @param key The key. + * @param value The value. + */ + public void setProperty(final String key, final String value) { + if (Utils.isValidString(key)) { + properties.put(key, value); + } + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java b/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java index e5dbe92..233ae79 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java @@ -45,54 +45,43 @@ import java.text.DecimalFormat; * @created 2016-07-01 * @since 1.0 */ -public class Calc extends AbstractModule -{ - /** - * The Calc command. - */ - private static final String CALC_CMD = "calc"; +public class Calc extends AbstractModule { + /** + * The Calc command. + */ + private static final String CALC_CMD = "calc"; - /** - * The default constructor. - */ - public Calc() - { - commands.add(CALC_CMD); - } + /** + * The default constructor. + */ + public Calc() { + commands.add(CALC_CMD); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (Utils.isValidString(args)) - { - final DecimalFormat decimalFormat = new DecimalFormat("#.##"); + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (Utils.isValidString(args)) { + final DecimalFormat decimalFormat = new DecimalFormat("#.##"); - try - { - final Expression calc = new ExpressionBuilder(args).build(); - bot.send(bot.getChannel(), args.replaceAll(" ", "") + " = " + decimalFormat.format(calc.evaluate())); - } - catch (Exception e) - { - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Unable to calculate: " + args, e); - } + try { + final Expression calc = new ExpressionBuilder(args).build(); + bot.send(bot.getChannel(), args.replaceAll(" ", "") + " = " + decimalFormat.format(calc.evaluate())); + } catch (Exception e) { + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Unable to calculate: " + args, e); + } - bot.send(bot.getChannel(), "No idea. This is the kind of math I don't get."); - } - } - else - { - helpResponse(bot, sender, args, isPrivate); - } + bot.send(bot.getChannel(), "No idea. This is the kind of math I don't get."); + } + } else { + helpResponse(bot, sender, args, isPrivate); + } - } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To solve a mathematical calculation:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CALC_CMD + " <calculation>")); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To solve a mathematical calculation:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CALC_CMD + " <calculation>")); + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java index 5f41439..e66b343 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java @@ -54,188 +54,154 @@ import java.util.TreeMap; * @created Feb 11, 2004 * @since 1.0 */ -final public class CurrencyConverter extends AbstractModule -{ - /** - * The currency command. - */ - private static final String CURRENCY_CMD = "currency"; +final public class CurrencyConverter extends AbstractModule { + /** + * The currency command. + */ + private static final String CURRENCY_CMD = "currency"; - /** - * The rates keyword. - */ - private static final String CURRENCY_RATES_KEYWORD = "rates"; + /** + * The rates keyword. + */ + private static final String CURRENCY_RATES_KEYWORD = "rates"; - /** - * The exchange rates. - */ - private static final Map<String, String> EXCHANGE_RATES = new TreeMap<>(); + /** + * The exchange rates. + */ + private static final Map<String, String> EXCHANGE_RATES = new TreeMap<>(); - /** - * The exchange rates table URL. - */ - private static final String EXCHANGE_TABLE_URL = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml"; + /** + * The exchange rates table URL. + */ + private static final String EXCHANGE_TABLE_URL = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml"; - /** - * The last exchange rates table publication date. - */ - private String pubDate = ""; + /** + * The last exchange rates table publication date. + */ + private static String pubDate = ""; - /** - * Creates a new {@link CurrencyConverter} instance. - */ - public CurrencyConverter() - { - commands.add(CURRENCY_CMD); - } + /** + * Creates a new {@link CurrencyConverter} instance. + */ + public CurrencyConverter() { + commands.add(CURRENCY_CMD); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - synchronized (this) - { - if (!pubDate.equals(Utils.today())) - { - EXCHANGE_RATES.clear(); - } - } + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + synchronized (this) { + if (!pubDate.equals(Utils.today())) { + EXCHANGE_RATES.clear(); + } + } - new Thread(() -> run(bot, sender, args)).start(); - } + new Thread(() -> run(bot, sender, args)).start(); + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To convert from one currency to another:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD + " [100 USD to EUR]")); + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To convert from one currency to another:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD + " [100 USD to EUR]")); - if (args.endsWith(CURRENCY_CMD)) - { - bot.send(sender, "For a listing of currency rates:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD) + ' ' + CURRENCY_RATES_KEYWORD); - bot.send(sender, "For a listing of supported currencies:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD)); - } - } + if (args.endsWith(CURRENCY_CMD)) { + bot.send(sender, "For a listing of currency rates:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD) + ' ' + CURRENCY_RATES_KEYWORD); + bot.send(sender, "For a listing of supported currencies:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + CURRENCY_CMD)); + } + } - /** - * Converts the specified currencies. - */ - private void run(final Mobibot bot, final String sender, final String query) - { - if (Utils.isValidString(sender)) - { - if (EXCHANGE_RATES.isEmpty()) - { - try - { - final SAXBuilder builder = new SAXBuilder(); - builder.setIgnoringElementContentWhitespace(true); + /** + * Converts the specified currencies. + */ + private void run(final Mobibot bot, final String sender, final String query) { + if (Utils.isValidString(sender)) { + if (EXCHANGE_RATES.isEmpty()) { + try { + final SAXBuilder builder = new SAXBuilder(); + builder.setIgnoringElementContentWhitespace(true); - final Document doc = builder.build(new URL(EXCHANGE_TABLE_URL)); - final Element root = doc.getRootElement(); - final Namespace ns = root.getNamespace(""); - final Element cubeRoot = root.getChild("Cube", ns); - final Element cubeTime = cubeRoot.getChild("Cube", ns); + final Document doc = builder.build(new URL(EXCHANGE_TABLE_URL)); + final Element root = doc.getRootElement(); + final Namespace ns = root.getNamespace(""); + final Element cubeRoot = root.getChild("Cube", ns); + final Element cubeTime = cubeRoot.getChild("Cube", ns); - pubDate = cubeTime.getAttribute("time").getValue(); + pubDate = cubeTime.getAttribute("time").getValue(); - final List cubes = cubeTime.getChildren(); - Element cube; + final List cubes = cubeTime.getChildren(); + Element cube; - for (final Object rawCube : cubes) - { - cube = (Element) rawCube; - EXCHANGE_RATES.put( - cube.getAttribute("currency").getValue(), - cube.getAttribute("rate").getValue()); - } + for (final Object rawCube : cubes) { + cube = (Element) rawCube; + EXCHANGE_RATES.put( + cube.getAttribute("currency").getValue(), + cube.getAttribute("rate").getValue()); + } - EXCHANGE_RATES.put("EUR", "1"); - } - catch (JDOMException e) - { - bot.getLogger().debug("Unable to parse the exchange rates table.", e); - bot.send(sender, "An error has occurred while parsing the exchange rates table."); - } - catch (IOException e) - { - bot.getLogger().debug("Unable to fetch the exchange rates table.", e); - bot.send(sender, - "An error has occurred while fetching the exchange rates table: " + e.getMessage()); - } - } + EXCHANGE_RATES.put("EUR", "1"); + } catch (JDOMException e) { + bot.getLogger().debug("Unable to parse the exchange rates table.", e); + bot.send(sender, "An error has occurred while parsing the exchange rates table."); + } catch (IOException e) { + bot.getLogger().debug("Unable to fetch the exchange rates table.", e); + bot.send(sender, + "An error has occurred while fetching the exchange rates table: " + e.getMessage()); + } + } - if (EXCHANGE_RATES.isEmpty()) - { - bot.getLogger().debug("The exchange rate table is empty."); - bot.send(sender, "Sorry, but the exchange rate table is empty."); - } - else if (Utils.isValidString(query)) - { - if (!EXCHANGE_RATES.isEmpty()) - { - if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) - { - final String[] cmds = query.split(" "); + if (EXCHANGE_RATES.isEmpty()) { + bot.getLogger().debug("The exchange rate table is empty."); + bot.send(sender, "Sorry, but the exchange rate table is empty."); + } else if (Utils.isValidString(query)) { + if (!EXCHANGE_RATES.isEmpty()) { + if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) { + final String[] cmds = query.split(" "); - if (cmds.length == 4) - { - if (cmds[3].equals(cmds[1]) || cmds[0].equals("0")) - { - bot.send(sender, "You're kidding, right?"); - } - else - { - try - { - final double amt = Double.parseDouble(cmds[0].replaceAll(",", "")); - final double from = Double.parseDouble(EXCHANGE_RATES.get(cmds[1].toUpperCase())); - final double to = Double.parseDouble(EXCHANGE_RATES.get(cmds[3].toUpperCase())); + if (cmds.length == 4) { + if (cmds[3].equals(cmds[1]) || cmds[0].equals("0")) { + bot.send(sender, "You're kidding, right?"); + } else { + try { + final double amt = Double.parseDouble(cmds[0].replaceAll(",", "")); + final double from = Double.parseDouble(EXCHANGE_RATES.get(cmds[1].toUpperCase())); + final double to = Double.parseDouble(EXCHANGE_RATES.get(cmds[3].toUpperCase())); - bot.send(bot.getChannel(), - NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) - + ' ' - + cmds[1].toUpperCase() - + " = " - + NumberFormat.getCurrencyInstance(Locale.US) - .format((amt * to) / from) - .substring(1) - + ' ' - + cmds[3].toUpperCase()); - } - catch (NullPointerException ignored) - { - bot.send(sender, - "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); - } - } - } - } - else if (query.equals(CURRENCY_RATES_KEYWORD)) - { - bot.send(sender, "Last Update: " + pubDate); + bot.send(bot.getChannel(), + NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) + + ' ' + + cmds[1].toUpperCase() + + " = " + + NumberFormat.getCurrencyInstance(Locale.US) + .format((amt * to) / from) + .substring(1) + + ' ' + + cmds[3].toUpperCase()); + } catch (NullPointerException ignored) { + bot.send(sender, + "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); + } + } + } + } else if (query.equals(CURRENCY_RATES_KEYWORD)) { + bot.send(sender, "Last Update: " + pubDate); - final StringBuilder buff = new StringBuilder(0); + final StringBuilder buff = new StringBuilder(0); - for (final Map.Entry<String, String> rate : EXCHANGE_RATES.entrySet()) - { - if (buff.length() > 0) - { - buff.append(", "); - } - buff.append(rate.getKey()).append(": ").append(rate.getValue()); - } + for (final Map.Entry<String, String> rate : EXCHANGE_RATES.entrySet()) { + if (buff.length() > 0) { + buff.append(", "); + } + buff.append(rate.getKey()).append(": ").append(rate.getValue()); + } - bot.send(sender, buff.toString()); - } - } - } - else - { - helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); - bot.send(sender, "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); - } - } - } + bot.send(sender, buff.toString()); + } + } + } else { + helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); + bot.send(sender, "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); + } + } + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java index e9d251f..b13c989 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java @@ -43,73 +43,63 @@ import java.util.Random; * @created 2014-04-28 * @since 1.0 */ -final public class Dice extends AbstractModule -{ - /** - * The dice command. - */ - private final String DICE_CMD = "dice"; +final public class Dice extends AbstractModule { + /** + * The dice command. + */ + private final String DICE_CMD = "dice"; - /** - * The default constructor. - */ - public Dice() - { - commands.add(DICE_CMD); - } + /** + * The default constructor. + */ + public Dice() { + commands.add(DICE_CMD); + } - /** - * Rolls the dice. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - final Random r = new Random(); + /** + * Rolls the dice. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + final Random r = new Random(); - int i = r.nextInt(6) + 1; - int y = r.nextInt(6) + 1; - final int playerTotal = i + y; + int i = r.nextInt(6) + 1; + int y = r.nextInt(6) + 1; + final int playerTotal = i + y; - bot.send(bot.getChannel(), - sender + " rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils - .bold(playerTotal)); + bot.send(bot.getChannel(), + sender + " rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils + .bold(playerTotal)); - i = r.nextInt(6) + 1; - y = r.nextInt(6) + 1; - final int total = i + y; + i = r.nextInt(6) + 1; + y = r.nextInt(6) + 1; + final int total = i + y; - bot.action( - "rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils.bold(total)); + bot.action( + "rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils.bold(total)); - if (playerTotal < total) - { - bot.action("wins."); - } - else if (playerTotal > total) - { - bot.action("lost."); - } - else - { - bot.action("tied."); - } - } + if (playerTotal < total) { + bot.action("wins."); + } else if (playerTotal > total) { + bot.action("lost."); + } else { + bot.action("tied."); + } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To roll the dice:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + DICE_CMD)); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To roll the dice:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + DICE_CMD)); + } - @Override - public boolean isEnabled() - { - return true; - } + @Override + public boolean isEnabled() { + return true; + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java index 973117d..85f2bec 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java @@ -49,121 +49,100 @@ import java.net.URLEncoder; * @created Feb 7, 2004 * @since 1.0 */ -final public class GoogleSearch extends AbstractModule -{ - /** - * The Google API Key property. - */ - private static final String GOOGLE_API_KEY_PROP = "google-api-key"; +final public class GoogleSearch extends AbstractModule { + /** + * The Google API Key property. + */ + private static final String GOOGLE_API_KEY_PROP = "google-api-key"; - /** - * The google command. - */ - private static final String GOOGLE_CMD = "google"; + /** + * The google command. + */ + private static final String GOOGLE_CMD = "google"; - /** - * The Google Custom Search Engine ID property. - */ - private static final String GOOGLE_CSE_KEY_PROP = "google-cse-cx"; + /** + * The Google Custom Search Engine ID property. + */ + private static final String GOOGLE_CSE_KEY_PROP = "google-cse-cx"; - /** - * The tab indent (4 spaces). - */ - private static final String TAB_INDENT = " "; + /** + * The tab indent (4 spaces). + */ + private static final String TAB_INDENT = " "; - /** - * Creates a new {@link GoogleSearch} instance. - */ - public GoogleSearch() - { - commands.add(GOOGLE_CMD); - properties.put(GOOGLE_API_KEY_PROP, ""); - properties.put(GOOGLE_CSE_KEY_PROP, ""); - } + /** + * Creates a new {@link GoogleSearch} instance. + */ + public GoogleSearch() { + commands.add(GOOGLE_CMD); + properties.put(GOOGLE_API_KEY_PROP, ""); + properties.put(GOOGLE_CSE_KEY_PROP, ""); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (isEnabled() && args.length() > 0) - { - if (args.length() > 0) - { - new Thread(() -> run(bot, sender, args)).start(); - } - else - { - helpResponse(bot, sender, args, isPrivate); - } - } - else - { - helpResponse(bot, sender, args, isPrivate); - } - } + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (isEnabled() && args.length() > 0) { + if (args.length() > 0) { + new Thread(() -> run(bot, sender, args)).start(); + } else { + helpResponse(bot, sender, args, isPrivate); + } + } else { + helpResponse(bot, sender, args, isPrivate); + } + } - /** - * Searches Google. - */ - private void run(final Mobibot bot, final String sender, final String query) - { - try - { - final String q = URLEncoder.encode(query, "UTF-8"); + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (isEnabled()) { + bot.send(sender, "To search Google:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + GOOGLE_CMD + " <query>")); + } else { + bot.send(sender, "The Google searching facility is disabled."); + } + } - final URL url = - new URL("https://www.googleapis.com/customsearch/v1?key=" - + properties.get(GOOGLE_API_KEY_PROP) - + "&cx=" - + properties.get(GOOGLE_CSE_KEY_PROP) - + "&q=" - + q - + "&filter=1&num=5&alt=json"); - final URLConnection conn = url.openConnection(); + @Override + public boolean isEnabled() { + return isValidProperties(); + } - final StringBuilder sb = new StringBuilder(); - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) - { - String line; - while ((line = reader.readLine()) != null) - { - sb.append(line); - } + /** + * Searches Google. + */ + private void run(final Mobibot bot, final String sender, final String query) { + try { + final String q = URLEncoder.encode(query, "UTF-8"); - final JSONObject json = new JSONObject(sb.toString()); - final JSONArray ja = json.getJSONArray("items"); + final URL url = + new URL("https://www.googleapis.com/customsearch/v1?key=" + + properties.get(GOOGLE_API_KEY_PROP) + + "&cx=" + + properties.get(GOOGLE_CSE_KEY_PROP) + + "&q=" + + q + + "&filter=1&num=5&alt=json"); + final URLConnection conn = url.openConnection(); - for (int i = 0; i < ja.length(); i++) - { - final JSONObject j = ja.getJSONObject(i); - bot.send(sender, Utils.unescapeXml(j.getString("title"))); - bot.send(sender, TAB_INDENT + Utils.green(j.getString("link"))); - } - } - } - catch (Exception e) - { - bot.getLogger().warn("Unable to search in Google for: " + query, e); - bot.send(sender, "An error has occurred searching in Google: " + e.getMessage()); - } - } + final StringBuilder sb = new StringBuilder(); + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (isEnabled()) - { - bot.send(sender, "To search Google:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + GOOGLE_CMD + " <query>")); - } - else - { - bot.send(sender, "The Google searching facility is disabled."); - } - } + final JSONObject json = new JSONObject(sb.toString()); + final JSONArray ja = json.getJSONArray("items"); - @Override - public boolean isEnabled() - { - return isValidProperties(); - } + for (int i = 0; i < ja.length(); i++) { + final JSONObject j = ja.getJSONObject(i); + bot.send(sender, Utils.unescapeXml(j.getString("title"))); + bot.send(sender, TAB_INDENT + Utils.green(j.getString("link"))); + } + } + } catch (Exception e) { + bot.getLogger().warn("Unable to search in Google for: " + query, e); + bot.send(sender, "An error has occurred searching in Google: " + e.getMessage()); + } + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java index 8796dbc..d945f85 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java @@ -47,73 +47,62 @@ import java.net.URLConnection; * @created 2014-04-20 * @since 1.0 */ -final public class Joke extends AbstractModule -{ +final public class Joke extends AbstractModule { + /** + * The joke command. + */ + private static final String JOKE_CMD = "joke"; - /** - * The joke command. - */ - private static final String JOKE_CMD = "joke"; + /** + * The ICNDB URL. + */ + private static final String JOKE_URL = + "http://api.icndb.com/jokes/random?escape=javascript&exclude=[explicit]&limitTo=[nerdy]"; - /** - * The ICNDB URL. - */ - private static final String JOKE_URL = - "http://api.icndb.com/jokes/random?escape=javascript&exclude=[explicit]&limitTo=[nerdy]"; + /** + * Creates a new {@link Joke} instance. + */ + public Joke() { + commands.add(JOKE_CMD); + } - /** - * Creates a new {@link Joke} instance. - */ - public Joke() - { - commands.add(JOKE_CMD); - } + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + new Thread(() -> run(bot, sender)).start(); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - new Thread(() -> run(bot, sender)).start(); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To retrieve a random joke:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + JOKE_CMD)); + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To retrieve a random joke:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + JOKE_CMD)); - } + /** + * Returns a random joke from <a href="http://www.icndb.com/">The Internet Chuck Norris Database</a> + */ + private void run(final Mobibot bot, final String sender) { + try { + final URL url = new URL(JOKE_URL); + final URLConnection conn = url.openConnection(); - /** - * Returns a random joke from <a href="http://www.icndb.com/">The Internet Chuck Norris Database</a> - */ - private void run(final Mobibot bot, final String sender) - { - try - { - final URL url = new URL(JOKE_URL); - final URLConnection conn = url.openConnection(); + final StringBuilder sb = new StringBuilder(); + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } - final StringBuilder sb = new StringBuilder(); - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) - { - String line; - while ((line = reader.readLine()) != null) - { - sb.append(line); - } + final JSONObject json = new JSONObject(sb.toString()); - final JSONObject json = new JSONObject(sb.toString()); - - bot.send(bot.getChannel(), - Colors.CYAN - + json.getJSONObject("value").get("joke").toString().replaceAll("\\'", "'") - .replaceAll("\\\"", "\"") - + Colors.NORMAL); - } - } - catch (Exception e) - { - bot.getLogger().warn("Unable to retrieve random joke.", e); - bot.send(sender, "An error has occurred retrieving a random joke: " + e.getMessage()); - } - } + bot.send(bot.getChannel(), + Colors.CYAN + + json.getJSONObject("value").get("joke").toString().replaceAll("\\'", "'") + .replaceAll("\\\"", "\"") + + Colors.NORMAL); + } + } catch (Exception e) { + bot.getLogger().warn("Unable to retrieve random joke.", e); + bot.send(sender, "An error has occurred retrieving a random joke: " + e.getMessage()); + } + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java index b42c686..cf67caa 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java @@ -45,190 +45,151 @@ import java.net.UnknownHostException; * @created 2014-04-26 * @since 1.0 */ -final public class Lookup extends AbstractModule -{ - /** - * THe lookup command. - */ - private static final String LOOKUP_CMD = "lookup"; +final public class Lookup extends AbstractModule { + /** + * THe lookup command. + */ + private static final String LOOKUP_CMD = "lookup"; - /** - * The whois host. - */ - private static final String WHOIS_HOST = "whois.arin.net"; + /** + * The whois host. + */ + private static final String WHOIS_HOST = "whois.arin.net"; - /** - * The default constructor - */ - public Lookup() - { - commands.add(LOOKUP_CMD); - } + /** + * The default constructor + */ + public Lookup() { + commands.add(LOOKUP_CMD); + } - /** - * Process a command. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (args.matches("(\\S.)+(\\S)+")) - { - try - { - bot.send(bot.getChannel(), Lookup.lookup(args)); - } - catch (UnknownHostException ignore) - { - if (args.matches( - "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")) - { - try - { - final String[] lines = Lookup.whois(args); + /** + * Performs a DNS lookup on the specified query. + * + * @param query The IP address or hostname. + * @return The lookup query result string. + * @throws java.net.UnknownHostException If the host is unknown. + */ + private static String lookup(final String query) + throws UnknownHostException { + final StringBuilder buffer = new StringBuilder(""); - if ((lines != null) && (lines.length > 0)) - { - String line; + final InetAddress[] results = InetAddress.getAllByName(query); + String hostInfo; - for (final String rawLine : lines) - { - line = rawLine.trim(); + for (final InetAddress result : results) { + if (result.getHostAddress().equals(query)) { + hostInfo = result.getHostName(); - if ((line.length() > 0) && (line.charAt(0) != '#')) - { - bot.send(bot.getChannel(), line); - } - } - } - else - { - bot.send(bot.getChannel(), "Unknown host."); - } - } - catch (IOException ioe) - { - if (bot.getLogger().isDebugEnabled()) - { - bot.getLogger().debug("Unable to perform whois IP lookup: " + args, ioe); - } + if (hostInfo.equals(query)) { + throw new UnknownHostException(); + } + } else { + hostInfo = result.getHostAddress(); + } - bot.send(bot.getChannel(), "Unable to perform whois IP lookup: " + ioe.getMessage()); - } - } - else - { - bot.send(bot.getChannel(), "Unknown host."); - } - } - } - else - { - helpResponse(bot, sender, args, true); - } - } + if (buffer.length() > 0) { + buffer.append(", "); + } - /** - * Performs a DNS lookup on the specified query. - * - * @param query The IP address or hostname. - * - * @return The lookup query result string. - * - * @throws java.net.UnknownHostException If the host is unknown. - */ - private static String lookup(final String query) - throws UnknownHostException - { - final StringBuilder buffer = new StringBuilder(""); + buffer.append(hostInfo); + } - final InetAddress[] results = InetAddress.getAllByName(query); - String hostInfo; + return buffer.toString(); + } - for (final InetAddress result : results) - { - if (result.getHostAddress().equals(query)) - { - hostInfo = result.getHostName(); + /** + * Performs a whois IP query. + * + * @param query The IP address. + * @return The IP whois data, if any. + * @throws java.io.IOException If a connection error occurs. + */ + private static String[] whois(final String query) + throws IOException { + return whois(query, WHOIS_HOST); + } - if (hostInfo.equals(query)) - { - throw new UnknownHostException(); - } - } - else - { - hostInfo = result.getHostAddress(); - } + /** + * Performs a whois IP query. + * + * @param query The IP address. + * @param host The whois host. + * @return The IP whois data, if any. + * @throws java.io.IOException If a connection error occurs. + */ + @SuppressWarnings("WeakerAccess, SameParameterValue") + public static String[] whois(final String query, final String host) + throws IOException { + final WhoisClient whois = new WhoisClient(); + String[] lines; - if (buffer.length() > 0) - { - buffer.append(", "); - } + try { + whois.setDefaultTimeout(Mobibot.CONNECT_TIMEOUT); + whois.connect(host); + whois.setSoTimeout(Mobibot.CONNECT_TIMEOUT); + whois.setSoLinger(false, 0); - buffer.append(hostInfo); - } + lines = whois.query('-' + query).split("\n"); + } finally { + whois.disconnect(); + } - return buffer.toString(); - } + return lines; + } - /** - * Performs a whois IP query. - * - * @param query The IP address. - * - * @return The IP whois data, if any. - * - * @throws java.io.IOException If a connection error occurs. - */ - private static String[] whois(final String query) - throws IOException - { - return whois(query, WHOIS_HOST); - } + /** + * Process a command. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (args.matches("(\\S.)+(\\S)+")) { + try { + bot.send(bot.getChannel(), Lookup.lookup(args)); + } catch (UnknownHostException ignore) { + if (args.matches( + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." + + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")) { + try { + final String[] lines = Lookup.whois(args); - /** - * Performs a whois IP query. - * - * @param query The IP address. - * @param host The whois host. - * - * @return The IP whois data, if any. - * - * @throws java.io.IOException If a connection error occurs. - */ - @SuppressWarnings("WeakerAccess, SameParameterValue") - public static String[] whois(final String query, final String host) - throws IOException - { - final WhoisClient whois = new WhoisClient(); - String[] lines; + if ((lines != null) && (lines.length > 0)) { + String line; - try - { - whois.setDefaultTimeout(Mobibot.CONNECT_TIMEOUT); - whois.connect(host); - whois.setSoTimeout(Mobibot.CONNECT_TIMEOUT); - whois.setSoLinger(false, 0); + for (final String rawLine : lines) { + line = rawLine.trim(); - lines = whois.query('-' + query).split("\n"); - } - finally - { - whois.disconnect(); - } + if ((line.length() > 0) && (line.charAt(0) != '#')) { + bot.send(bot.getChannel(), line); + } + } + } else { + bot.send(bot.getChannel(), "Unknown host."); + } + } catch (IOException ioe) { + if (bot.getLogger().isDebugEnabled()) { + bot.getLogger().debug("Unable to perform whois IP lookup: " + args, ioe); + } - return lines; - } + bot.send(bot.getChannel(), "Unable to perform whois IP lookup: " + ioe.getMessage()); + } + } else { + bot.send(bot.getChannel(), "Unknown host."); + } + } + } else { + helpResponse(bot, sender, args, true); + } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To perform a DNS lookup query:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + LOOKUP_CMD + " <ip address or hostname>")); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To perform a DNS lookup query:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + LOOKUP_CMD + " <ip address or hostname>")); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java b/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java index 19feda8..dad186e 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java @@ -44,49 +44,47 @@ import java.util.Random; * @created 2016-07-02 * @since 1.0 */ -public class Ping extends AbstractModule -{ - /** - * The ping responses. - */ - private static final List<String> PINGS = Arrays.asList("is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!"); +public class Ping extends AbstractModule { + /** + * The ping responses. + */ + private static final List<String> PINGS = + Arrays.asList( + "is barely alive.", + "is trying to stay awake.", + "has gone fishing.", + "is somewhere over the rainbow.", + "has fallen and can't get up.", + "is running. You better go chase it.", + "has just spontaneously combusted.", + "is talking to itself... don't interrupt. That's rude.", + "is bartending at an AA meeting.", + "is hibernating.", + "is saving energy: apathetic mode activated.", + "is busy. Go away!"); - /** - * The ping command. - */ - private static final String PING_CMD = "ping"; + /** + * The ping command. + */ + private static final String PING_CMD = "ping"; - /** - * The default constructor. - */ - public Ping() - { - commands.add(PING_CMD); - } + /** + * The default constructor. + */ + public Ping() { + commands.add(PING_CMD); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - final Random r = new Random(); + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + final Random r = new Random(); - bot.action(PINGS.get(r.nextInt(PINGS.size()))); - } + bot.action(PINGS.get(r.nextInt(PINGS.size()))); + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To ping the bot:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + PING_CMD)); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To ping the bot:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + PING_CMD)); + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java index b2dbbc0..6d4096a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java @@ -45,120 +45,93 @@ import java.io.IOException; * @created Feb 7, 2004 * @since 1.0 */ -final public class StockQuote extends AbstractModule -{ - /** - * The quote command. - */ - private static final String STOCK_CMD = "stock"; +final public class StockQuote extends AbstractModule { + /** + * The quote command. + */ + private static final String STOCK_CMD = "stock"; - /** - * The Yahoo! stock quote URL. - */ - private static final String YAHOO_URL = "http://finance.yahoo.com/d/quotes.csv?&f=snl1d1t1c1oghv&e=.csv&s="; + /** + * The Yahoo! stock quote URL. + */ + private static final String YAHOO_URL = "http://finance.yahoo.com/d/quotes.csv?&f=snl1d1t1c1oghv&e=.csv&s="; - /** - * Creates a new {@link StockQuote} instance. - */ - public StockQuote() - { - commands.add(STOCK_CMD); - } + /** + * Creates a new {@link StockQuote} instance. + */ + public StockQuote() { + commands.add(STOCK_CMD); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (args.length() > 0) - { - new Thread(() -> run(bot, sender, args)).start(); - } - else - { - helpResponse(bot, sender, args, isPrivate); - } - } + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (args.length() > 0) { + new Thread(() -> run(bot, sender, args)).start(); + } else { + helpResponse(bot, sender, args, isPrivate); + } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To retrieve a stock quote:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + STOCK_CMD + " <symbol[.country code]>")); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To retrieve a stock quote:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + STOCK_CMD + " <symbol[.country code]>")); + } - /** - * Returns the specified stock quote from Yahoo! - */ - private void run(final Mobibot bot, final String sender, final String symbol) - { - try - { - final HttpClient client = new HttpClient(); - client.getHttpConnectionManager().getParams().setConnectionTimeout(Mobibot.CONNECT_TIMEOUT); - client.getHttpConnectionManager().getParams().setSoTimeout(Mobibot.CONNECT_TIMEOUT); + /** + * Returns the specified stock quote from Yahoo! + */ + private void run(final Mobibot bot, final String sender, final String symbol) { + try { + final HttpClient client = new HttpClient(); + client.getHttpConnectionManager().getParams().setConnectionTimeout(Mobibot.CONNECT_TIMEOUT); + client.getHttpConnectionManager().getParams().setSoTimeout(Mobibot.CONNECT_TIMEOUT); - final GetMethod getMethod = new GetMethod(YAHOO_URL + symbol.toUpperCase()); - client.executeMethod(getMethod); + final GetMethod getMethod = new GetMethod(YAHOO_URL + symbol.toUpperCase()); + client.executeMethod(getMethod); - final String[][] lines = CSVParser.parse(getMethod.getResponseBodyAsString()); + final String[][] lines = CSVParser.parse(getMethod.getResponseBodyAsString()); - if (lines.length > 0) - { - final String[] quote = lines[0]; + if (lines.length > 0) { + final String[] quote = lines[0]; - if (quote.length > 0) - { - if ((quote.length > 3) && (!"N/A".equalsIgnoreCase(quote[3]))) - { - bot.send(bot.getChannel(), "Symbol: " + quote[0] + " [" + quote[1] + ']'); + if (quote.length > 0) { + if ((quote.length > 3) && (!"N/A".equalsIgnoreCase(quote[3]))) { + bot.send(bot.getChannel(), "Symbol: " + quote[0] + " [" + quote[1] + ']'); - if (quote.length > 5) - { - bot.send(bot.getChannel(), "Last Trade: " + quote[2] + " (" + quote[5] + ')'); - } - else - { - bot.send(bot.getChannel(), "Last Trade: " + quote[2]); - } + if (quote.length > 5) { + bot.send(bot.getChannel(), "Last Trade: " + quote[2] + " (" + quote[5] + ')'); + } else { + bot.send(bot.getChannel(), "Last Trade: " + quote[2]); + } - if (quote.length > 4) - { - bot.send(sender, "Time: " + quote[3] + ' ' + quote[4]); - } + if (quote.length > 4) { + bot.send(sender, "Time: " + quote[3] + ' ' + quote[4]); + } - if (quote.length > 6 && !"N/A".equalsIgnoreCase(quote[6])) - { - bot.send(sender, "Open: " + quote[6]); - } + if (quote.length > 6 && !"N/A".equalsIgnoreCase(quote[6])) { + bot.send(sender, "Open: " + quote[6]); + } - if (quote.length > 7 && !"N/A".equalsIgnoreCase(quote[7]) && !"N/A".equalsIgnoreCase(quote[8])) - { - bot.send(sender, "Day's Range: " + quote[7] + " - " + quote[8]); - } + if (quote.length > 7 && !"N/A".equalsIgnoreCase(quote[7]) && !"N/A".equalsIgnoreCase(quote[8])) { + bot.send(sender, "Day's Range: " + quote[7] + " - " + quote[8]); + } - if (quote.length > 9 && !"0".equalsIgnoreCase(quote[9])) - { - bot.send(sender, "Volume: " + quote[9]); - } - } - else - { - bot.send(sender, "Invalid ticker symbol."); - } - } - else - { - bot.send(sender, "No values returned."); - } - } - else - { - bot.send(sender, "No data returned."); - } - } - catch (IOException e) - { - bot.getLogger().debug("Unable to retrieve stock quote for: " + symbol, e); - bot.send(sender, "An error has occurred retrieving a stock quote: " + e.getMessage()); - } - } + if (quote.length > 9 && !"0".equalsIgnoreCase(quote[9])) { + bot.send(sender, "Volume: " + quote[9]); + } + } else { + bot.send(sender, "Invalid ticker symbol."); + } + } else { + bot.send(sender, "No values returned."); + } + } else { + bot.send(sender, "No data returned."); + } + } catch (IOException e) { + bot.getLogger().debug("Unable to retrieve stock quote for: " + symbol, e); + bot.send(sender, "An error has occurred retrieving a stock quote: " + e.getMessage()); + } + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java index b65a4b0..05e41d7 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java @@ -43,92 +43,74 @@ import twitter4j.conf.ConfigurationBuilder; * @created Sept 10, 2008 * @since 1.0 */ -final public class Twitter extends AbstractModule -{ - private final static String CONSUMER_KEY_PROP = "twitter-consumerKey"; +final public class Twitter extends AbstractModule { + private final static String CONSUMER_KEY_PROP = "twitter-consumerKey"; + private final static String CONSUMER_SECRET_PROP = "twitter-consumerSecret"; + private final static String TOKEN_PROP = "twitter-token"; + private final static String TOKEN_SECRET_PROP = "twitter-tokenSecret"; - private final static String CONSUMER_SECRET_PROP = "twitter-consumerSecret"; + /** + * The twitter command. + */ + private final static String TWITTER_CMD = "twitter"; - private final static String TOKEN_PROP = "twitter-token"; + /** + * Creates a new {@link Twitter} instance. + */ + public Twitter() { + commands.add(TWITTER_CMD); + properties.put(CONSUMER_SECRET_PROP, ""); + properties.put(CONSUMER_KEY_PROP, ""); + properties.put(TOKEN_PROP, ""); + properties.put(TOKEN_SECRET_PROP, ""); + } - private final static String TOKEN_SECRET_PROP = "twitter-tokenSecret"; + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (isEnabled() && args.length() > 0) { + new Thread(() -> run(bot, sender, args)).start(); + } else { + helpResponse(bot, sender, args, isPrivate); + } + } - /** - * The twitter command. - */ - private final static String TWITTER_CMD = "twitter"; + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + if (isEnabled()) { + bot.send(sender, "To post to Twitter:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TWITTER_CMD + " <message>")); + } else { + bot.send(sender, "The Twitter posting facility is disabled."); + } + } - /** - * Creates a new {@link Twitter} instance. - */ - public Twitter() - { - commands.add(TWITTER_CMD); - properties.put(CONSUMER_SECRET_PROP, ""); - properties.put(CONSUMER_KEY_PROP, ""); - properties.put(TOKEN_PROP, ""); - properties.put(TOKEN_SECRET_PROP, ""); - } + @Override + public boolean isEnabled() { + return isValidProperties(); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (isEnabled() && args.length() > 0) - { - new Thread(() -> run(bot, sender, args)).start(); - } - else - { - helpResponse(bot, sender, args, isPrivate); - } - } + /** + * Posts to twitter. + */ + private void run(final Mobibot bot, final String sender, final String message) { + try { + final ConfigurationBuilder cb = new ConfigurationBuilder(); + cb.setDebugEnabled(true) + .setOAuthConsumerKey(properties.get(CONSUMER_KEY_PROP)) + .setOAuthConsumerSecret(properties.get(CONSUMER_SECRET_PROP)) + .setOAuthAccessToken(properties.get(TOKEN_PROP)) + .setOAuthAccessTokenSecret(properties.get(TOKEN_SECRET_PROP)); + final TwitterFactory tf = new TwitterFactory(cb.build()); + final twitter4j.Twitter twitter = tf.getInstance(); - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - if (isEnabled()) - { - bot.send(sender, "To post to Twitter:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TWITTER_CMD + " <message>")); - } - else - { - bot.send(sender, "The Twitter posting facility is disabled."); - } - } + final Status status = twitter.updateStatus(message + " (" + sender + ')'); - @Override - public boolean isEnabled() - { - return isValidProperties(); - } - - /** - * Posts to twitter. - */ - private void run(final Mobibot bot, final String sender, final String message) - { - try - { - final ConfigurationBuilder cb = new ConfigurationBuilder(); - cb.setDebugEnabled(true) - .setOAuthConsumerKey(properties.get(CONSUMER_KEY_PROP)) - .setOAuthConsumerSecret(properties.get(CONSUMER_SECRET_PROP)) - .setOAuthAccessToken(properties.get(TOKEN_PROP)) - .setOAuthAccessTokenSecret(properties.get(TOKEN_SECRET_PROP)); - final TwitterFactory tf = new TwitterFactory(cb.build()); - final twitter4j.Twitter twitter = tf.getInstance(); - - final Status status = twitter.updateStatus(message + " (" + sender + ')'); - - bot.send(sender, - "You message was posted to http://twitter.com/" + twitter.getScreenName() + "/statuses/" + status - .getId()); - } - catch (Exception e) - { - bot.getLogger().warn("Unable to post to Twitter: " + message, e); - bot.send(sender, "An error has occurred: " + e.getMessage()); - } - } + bot.send(sender, + "You message was posted to http://twitter.com/" + twitter.getScreenName() + "/statuses/" + status + .getId()); + } catch (Exception e) { + bot.getLogger().warn("Unable to post to Twitter: " + message, e); + bot.send(sender, "An error has occurred: " + e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java index 182d5ee..ab07d74 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java @@ -43,79 +43,70 @@ import java.util.Random; * @created 2014-04-28 * @since 1.0 */ -final public class War extends AbstractModule -{ - /** - * The war command. - */ - private static final String WAR_CMD = "war"; +final public class War extends AbstractModule { + /** + * The war command. + */ + private static final String WAR_CMD = "war"; - /** - * The deck of card. - */ - private static final String[] WAR_DECK = - new String[]{"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"}; + /** + * The deck of card. + */ + private static final String[] WAR_DECK = + new String[]{"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"}; - /** - * The suits for the deck of card. - */ - private static final String[] WAR_SUITS = new String[]{"Hearts", "Spades", "Diamonds", "Clubs"}; + /** + * The suits for the deck of card. + */ + private static final String[] WAR_SUITS = new String[]{"Hearts", "Spades", "Diamonds", "Clubs"}; - /** - * The default constructor. - */ - public War() - { - commands.add(WAR_CMD); - } + /** + * The default constructor. + */ + public War() { + commands.add(WAR_CMD); + } - /** - * Plays war. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - final Random r = new Random(); + /** + * Plays war. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + final Random r = new Random(); - int i; - int y; + int i; + int y; - while (true) - { - i = r.nextInt(WAR_DECK.length); - y = r.nextInt(WAR_DECK.length); + while (true) { + i = r.nextInt(WAR_DECK.length); + y = r.nextInt(WAR_DECK.length); - bot.send(bot.getChannel(), - sender + " drew the " + Utils.bold(WAR_DECK[i]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); - bot.action("drew the " + Utils.bold(WAR_DECK[y]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); + bot.send(bot.getChannel(), + sender + " drew the " + Utils.bold(WAR_DECK[i]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); + bot.action("drew the " + Utils.bold(WAR_DECK[y]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); - if (i != y) - { - break; - } + if (i != y) { + break; + } - bot.send(bot.getChannel(), "This means " + Utils.bold("WAR") + '!'); - } + bot.send(bot.getChannel(), "This means " + Utils.bold("WAR") + '!'); + } - if (i < y) - { - bot.action("lost."); - } - else if (i > y) - { - bot.action("wins."); - } - } + if (i < y) { + bot.action("lost."); + } else if (i > y) { + bot.action("wins."); + } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To play war:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + WAR_CMD)); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To play war:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + WAR_CMD)); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java b/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java index ba0bb8d..2611d2f 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java @@ -47,145 +47,127 @@ import java.util.Date; * @created Feb 7, 2004 * @since 1.0 */ -final public class Weather extends AbstractModule -{ - /** - * The decimal number format. - */ - private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("0.##"); +final public class Weather extends AbstractModule { + /** + * The decimal number format. + */ + private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("0.##"); - /** - * The URL where the stations are listed. - */ - private static final String STATIONS_URL = "http://www.rap.ucar.edu/weather/surface/stations.txt"; + /** + * The URL where the stations are listed. + */ + private static final String STATIONS_URL = "http://www.rap.ucar.edu/weather/surface/stations.txt"; - /** - * THe weather command. - */ - private static final String WEATHER_CMD = "weather"; + /** + * THe weather command. + */ + private static final String WEATHER_CMD = "weather"; - /** - * Creates a new {@link Weather} instance. - */ - public Weather() - { - commands.add(WEATHER_CMD); - } + /** + * Creates a new {@link Weather} instance. + */ + public Weather() { + commands.add(WEATHER_CMD); + } - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - new Thread(() -> run(bot, sender, args.toUpperCase(), isPrivate)).start(); - } + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + new Thread(() -> run(bot, sender, args.toUpperCase(), isPrivate)).start(); + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To display weather information:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + WEATHER_CMD + " <station id>")); - bot.send(sender, "For a listing of the ICAO station IDs, please visit: " + STATIONS_URL); - } + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To display weather information:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + WEATHER_CMD + " <station id>")); + bot.send(sender, "For a listing of the ICAO station IDs, please visit: " + STATIONS_URL); + } - @Override - public boolean isPrivateMsgEnabled() - { - return true; - } + @Override + public boolean isPrivateMsgEnabled() { + return true; + } - /** - * Fetches the weather data from a specific station ID. - */ - private void run(final Mobibot bot, final String sender, final String station, final boolean isPrivate) - { - if (station.length() == 4) - { - final Metar metar = net.sf.jweather.Weather.getMetar(station); + /** + * Fetches the weather data from a specific station ID. + */ + private void run(final Mobibot bot, final String sender, final String station, final boolean isPrivate) { + if (station.length() == 4) { + final Metar metar = net.sf.jweather.Weather.getMetar(station); - if (metar != null) - { - Float result; + if (metar != null) { + Float result; - bot.send(sender, "Station ID: " + metar.getStationID(), isPrivate); + bot.send(sender, "Station ID: " + metar.getStationID(), isPrivate); - bot.send(sender, - "At: " - + Utils.UTC_SDF.format(metar.getDate()) - + " UTC (" - + (((new Date()).getTime() - metar.getDate().getTime()) / 1000L / 60L) - + " minutes ago)", - isPrivate); + bot.send(sender, + "At: " + + Utils.UTC_SDF.format(metar.getDate()) + + " UTC (" + + (((new Date()).getTime() - metar.getDate().getTime()) / 1000L / 60L) + + " minutes ago)", + isPrivate); - result = metar.getWindSpeedInMPH(); + result = metar.getWindSpeedInMPH(); - if (result != null) - { - bot.send(sender, - "Wind Speed: " - + result - + " mph, " - + metar.getWindSpeedInKnots() - + " knots, " - + metar.getWindSpeedInMPS() - + " m/s", - isPrivate); - } + if (result != null) { + bot.send(sender, + "Wind Speed: " + + result + + " mph, " + + metar.getWindSpeedInKnots() + + " knots, " + + metar.getWindSpeedInMPS() + + " m/s", + isPrivate); + } - result = metar.getVisibility(); + result = metar.getVisibility(); - if (result != null) - { - bot.send(sender, - "Visibility: " - + (metar.getVisibilityLessThan() ? "< " : "") - + NUMBER_FORMAT.format(result) - + " mi, " + metar.getVisibilityInKilometers() + " km", - isPrivate); - } + if (result != null) { + bot.send(sender, + "Visibility: " + + (metar.getVisibilityLessThan() ? "< " : "") + + NUMBER_FORMAT.format(result) + + " mi, " + metar.getVisibilityInKilometers() + " km", + isPrivate); + } - result = metar.getPressure(); + result = metar.getPressure(); - if (result != null) - { - bot.send(sender, - "Pressure: " + result + " Hg, " + metar.getPressureInHectoPascals() + " hPa", - isPrivate); - } + if (result != null) { + bot.send(sender, + "Pressure: " + result + " Hg, " + metar.getPressureInHectoPascals() + " hPa", + isPrivate); + } - result = metar.getTemperatureInCelsius(); + result = metar.getTemperatureInCelsius(); - if (result != null) - { - bot.send(sender, - "Temperature: " + result + " \u00B0C, " + metar.getTemperatureInFahrenheit() + " \u00B0F", - isPrivate); - } + if (result != null) { + bot.send(sender, + "Temperature: " + result + " \u00B0C, " + metar.getTemperatureInFahrenheit() + " \u00B0F", + isPrivate); + } - if (metar.getWeatherConditions() != null) - { - for (final Object weatherCondition : metar.getWeatherConditions()) - { - bot.send(sender, ((WeatherCondition) weatherCondition).getNaturalLanguageString(), isPrivate); - } - } + if (metar.getWeatherConditions() != null) { + for (final Object weatherCondition : metar.getWeatherConditions()) { + bot.send(sender, ((WeatherCondition) weatherCondition).getNaturalLanguageString(), isPrivate); + } + } - if (metar.getSkyConditions() != null) - { - for (final Object skyCondition : metar.getSkyConditions()) - { - bot.send(sender, ((SkyCondition) skyCondition).getNaturalLanguageString(), isPrivate); - } - } + if (metar.getSkyConditions() != null) { + for (final Object skyCondition : metar.getSkyConditions()) { + bot.send(sender, ((SkyCondition) skyCondition).getNaturalLanguageString(), isPrivate); + } + } - return; - } - else - { - bot.send(sender, "Invalid Station ID. Please try again.", isPrivate); + return; + } else { + bot.send(sender, "Invalid Station ID. Please try again.", isPrivate); - return; - } - } + return; + } + } - helpResponse(bot, sender, station, isPrivate); - } + helpResponse(bot, sender, station, isPrivate); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java index 9bc3c1a..87263d4 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java @@ -46,210 +46,184 @@ import java.util.TreeMap; * @created 2014-04-27 * @since 1.0 */ -final public class WorldTime extends AbstractModule -{ - /** - * The beats (Internet Time) keyword. - */ - private static final String BEATS_KEYWORD = ".beats"; +final public class WorldTime extends AbstractModule { + /** + * The beats (Internet Time) keyword. + */ + private static final String BEATS_KEYWORD = ".beats"; - /** - * The supported countries. - */ - private static final Map<String, String> COUNTRIES_MAP = new TreeMap<>(); + /** + * The supported countries. + */ + private static final Map<String, String> COUNTRIES_MAP = new TreeMap<>(); - /** - * The time command. - */ - private static final String TIME_CMD = "time"; + /** + * The time command. + */ + private static final String TIME_CMD = "time"; - /** - * The date/time format. - */ - private static final SimpleDateFormat TIME_SDF = - new SimpleDateFormat("'The time is 'HH:mm' on 'EEEE, d MMMM yyyy' in '"); + /** + * The date/time format. + */ + private static final SimpleDateFormat TIME_SDF = + new SimpleDateFormat("'The time is 'HH:mm' on 'EEEE, d MMMM yyyy' in '"); - /** - * Creates a new {@link WorldTime} instance. - */ - public WorldTime() - { - commands.add(TIME_CMD); + /** + * Creates a new {@link WorldTime} instance. + */ + public WorldTime() { + commands.add(TIME_CMD); - // Initialize the countries map - COUNTRIES_MAP.put("AU", "Australia/Sydney"); - COUNTRIES_MAP.put("BE", "Europe/Brussels"); - COUNTRIES_MAP.put("CA", "America/Montreal"); - COUNTRIES_MAP.put("CDT", "America/Chicago"); - COUNTRIES_MAP.put("CET", "CET"); - COUNTRIES_MAP.put("CH", "Europe/Zurich"); - COUNTRIES_MAP.put("CN", "Asia/Shanghai"); - COUNTRIES_MAP.put("CST", "America/Chicago"); - COUNTRIES_MAP.put("CU", "Cuba"); - COUNTRIES_MAP.put("DE", "Europe/Berlin"); - COUNTRIES_MAP.put("DK", "Europe/Copenhagen"); - COUNTRIES_MAP.put("EDT", "America/New_York"); - COUNTRIES_MAP.put("EG", "Africa/Cairo"); - COUNTRIES_MAP.put("ER", "Africa/Asmara"); - COUNTRIES_MAP.put("ES", "Europe/Madrid"); - COUNTRIES_MAP.put("EST", "America/New_York"); - COUNTRIES_MAP.put("FI", "Europe/Helsinki"); - COUNTRIES_MAP.put("FR", "Europe/Paris"); - COUNTRIES_MAP.put("GB", "Europe/London"); - COUNTRIES_MAP.put("GMT", "GMT"); - COUNTRIES_MAP.put("HK", "Asia/Hong_Kong"); - COUNTRIES_MAP.put("HST", "HST"); - COUNTRIES_MAP.put("IE", "Europe/Dublin"); - COUNTRIES_MAP.put("IL", "Asia/Tel_Aviv"); - COUNTRIES_MAP.put("IN", "Asia/Calcutta"); - COUNTRIES_MAP.put("IR", "Asia/Tehran"); - COUNTRIES_MAP.put("IS", "Atlantic/Reykjavik"); - COUNTRIES_MAP.put("IT", "Europe/Rome"); - COUNTRIES_MAP.put("JM", "Jamaica"); - COUNTRIES_MAP.put("JP", "Asia/Tokyo"); - COUNTRIES_MAP.put("LY", "Africa/Tripoli"); - COUNTRIES_MAP.put("MDT", "America/Denver"); - COUNTRIES_MAP.put("MH", "Kwajalein"); - COUNTRIES_MAP.put("MST", "America/Denver"); - COUNTRIES_MAP.put("MX", "America/Mexico_City"); - COUNTRIES_MAP.put("NL", "Europe/Amsterdam"); - COUNTRIES_MAP.put("NO", "Europe/Oslo"); - COUNTRIES_MAP.put("NP", "Asia/Katmandu"); - COUNTRIES_MAP.put("NZ", "Pacific/Auckland"); - COUNTRIES_MAP.put("PDT", "America/Los_Angeles"); - COUNTRIES_MAP.put("PK", "Asia/Karachi"); - COUNTRIES_MAP.put("PL", "Europe/Warsaw"); - COUNTRIES_MAP.put("PST", "America/Los_Angeles"); - COUNTRIES_MAP.put("PT", "Europe/Lisbon"); - COUNTRIES_MAP.put("RU", "Europe/Moscow"); - COUNTRIES_MAP.put("SE", "Europe/Stockholm"); - COUNTRIES_MAP.put("SG", "Asia/Singapore"); - COUNTRIES_MAP.put("SU", "Europe/Moscow"); - COUNTRIES_MAP.put("TH", "Asia/Bangkok"); - COUNTRIES_MAP.put("TM", "Asia/Ashgabat"); - COUNTRIES_MAP.put("TR", "Europe/Istanbul"); - COUNTRIES_MAP.put("TW", "Asia/Taipei"); - COUNTRIES_MAP.put("UK", "Europe/London"); - COUNTRIES_MAP.put("US", "America/New_York"); - COUNTRIES_MAP.put("UTC", "UTC"); - COUNTRIES_MAP.put("VA", "Europe/Vatican"); - COUNTRIES_MAP.put("VN", "Asia/Ho_Chi_Minh"); - COUNTRIES_MAP.put("INTERNET", BEATS_KEYWORD); - COUNTRIES_MAP.put("BEATS", BEATS_KEYWORD); + // Initialize the countries map + COUNTRIES_MAP.put("AU", "Australia/Sydney"); + COUNTRIES_MAP.put("BE", "Europe/Brussels"); + COUNTRIES_MAP.put("CA", "America/Montreal"); + COUNTRIES_MAP.put("CDT", "America/Chicago"); + COUNTRIES_MAP.put("CET", "CET"); + COUNTRIES_MAP.put("CH", "Europe/Zurich"); + COUNTRIES_MAP.put("CN", "Asia/Shanghai"); + COUNTRIES_MAP.put("CST", "America/Chicago"); + COUNTRIES_MAP.put("CU", "Cuba"); + COUNTRIES_MAP.put("DE", "Europe/Berlin"); + COUNTRIES_MAP.put("DK", "Europe/Copenhagen"); + COUNTRIES_MAP.put("EDT", "America/New_York"); + COUNTRIES_MAP.put("EG", "Africa/Cairo"); + COUNTRIES_MAP.put("ER", "Africa/Asmara"); + COUNTRIES_MAP.put("ES", "Europe/Madrid"); + COUNTRIES_MAP.put("EST", "America/New_York"); + COUNTRIES_MAP.put("FI", "Europe/Helsinki"); + COUNTRIES_MAP.put("FR", "Europe/Paris"); + COUNTRIES_MAP.put("GB", "Europe/London"); + COUNTRIES_MAP.put("GMT", "GMT"); + COUNTRIES_MAP.put("HK", "Asia/Hong_Kong"); + COUNTRIES_MAP.put("HST", "HST"); + COUNTRIES_MAP.put("IE", "Europe/Dublin"); + COUNTRIES_MAP.put("IL", "Asia/Tel_Aviv"); + COUNTRIES_MAP.put("IN", "Asia/Calcutta"); + COUNTRIES_MAP.put("IR", "Asia/Tehran"); + COUNTRIES_MAP.put("IS", "Atlantic/Reykjavik"); + COUNTRIES_MAP.put("IT", "Europe/Rome"); + COUNTRIES_MAP.put("JM", "Jamaica"); + COUNTRIES_MAP.put("JP", "Asia/Tokyo"); + COUNTRIES_MAP.put("LY", "Africa/Tripoli"); + COUNTRIES_MAP.put("MDT", "America/Denver"); + COUNTRIES_MAP.put("MH", "Kwajalein"); + COUNTRIES_MAP.put("MST", "America/Denver"); + COUNTRIES_MAP.put("MX", "America/Mexico_City"); + COUNTRIES_MAP.put("NL", "Europe/Amsterdam"); + COUNTRIES_MAP.put("NO", "Europe/Oslo"); + COUNTRIES_MAP.put("NP", "Asia/Katmandu"); + COUNTRIES_MAP.put("NZ", "Pacific/Auckland"); + COUNTRIES_MAP.put("PDT", "America/Los_Angeles"); + COUNTRIES_MAP.put("PK", "Asia/Karachi"); + COUNTRIES_MAP.put("PL", "Europe/Warsaw"); + COUNTRIES_MAP.put("PST", "America/Los_Angeles"); + COUNTRIES_MAP.put("PT", "Europe/Lisbon"); + COUNTRIES_MAP.put("RU", "Europe/Moscow"); + COUNTRIES_MAP.put("SE", "Europe/Stockholm"); + COUNTRIES_MAP.put("SG", "Asia/Singapore"); + COUNTRIES_MAP.put("SU", "Europe/Moscow"); + COUNTRIES_MAP.put("TH", "Asia/Bangkok"); + COUNTRIES_MAP.put("TM", "Asia/Ashgabat"); + COUNTRIES_MAP.put("TR", "Europe/Istanbul"); + COUNTRIES_MAP.put("TW", "Asia/Taipei"); + COUNTRIES_MAP.put("UK", "Europe/London"); + COUNTRIES_MAP.put("US", "America/New_York"); + COUNTRIES_MAP.put("UTC", "UTC"); + COUNTRIES_MAP.put("VA", "Europe/Vatican"); + COUNTRIES_MAP.put("VN", "Asia/Ho_Chi_Minh"); + COUNTRIES_MAP.put("INTERNET", BEATS_KEYWORD); + COUNTRIES_MAP.put("BEATS", BEATS_KEYWORD); - for (final String tz : TimeZone.getAvailableIDs()) - { - if (!tz.contains("/") && tz.length() == 3 & !COUNTRIES_MAP.containsKey(tz)) - { - COUNTRIES_MAP.put(tz, tz); - } - } - } + for (final String tz : TimeZone.getAvailableIDs()) { + if (!tz.contains("/") && tz.length() == 3 & !COUNTRIES_MAP.containsKey(tz)) { + COUNTRIES_MAP.put(tz, tz); + } + } + } - /** - * Responds with the current time in the specified timezone/country. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. - */ - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - boolean isInvalidTz = false; - final String tz = (COUNTRIES_MAP.get((args.substring(args.indexOf(' ') + 1).trim().toUpperCase()))); - final String response; + /** + * Responds with the current time in the specified timezone/country. + * + * @param bot The bot's instance. + * @param sender The sender. + * @param args The command arguments. + * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + */ + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + boolean isInvalidTz = false; + final String tz = (COUNTRIES_MAP.get((args.substring(args.indexOf(' ') + 1).trim().toUpperCase()))); + final String response; - if (tz != null) - { - if (tz.equals(BEATS_KEYWORD)) - { - response = ("The current Internet Time is: " + internetTime() + ' ' + BEATS_KEYWORD); - } - else - { - TIME_SDF.setTimeZone(TimeZone.getTimeZone(tz)); - response = TIME_SDF.format(Calendar.getInstance().getTime()) + tz.substring(tz.indexOf('/') + 1) - .replace('_', ' '); - } - } - else - { - isInvalidTz = true; - response = "The supported time zones are: " + COUNTRIES_MAP.keySet().toString(); - } + if (tz != null) { + if (tz.equals(BEATS_KEYWORD)) { + response = ("The current Internet Time is: " + internetTime() + ' ' + BEATS_KEYWORD); + } else { + TIME_SDF.setTimeZone(TimeZone.getTimeZone(tz)); + response = TIME_SDF.format(Calendar.getInstance().getTime()) + tz.substring(tz.indexOf('/') + 1) + .replace('_', ' '); + } + } else { + isInvalidTz = true; + response = "The supported time zones are: " + COUNTRIES_MAP.keySet().toString(); + } - if (isPrivate) - { - bot.send(sender, response, true); - } - else - { - if (isInvalidTz) - { - bot.send(sender, response); - } - else - { - bot.send(bot.getChannel(), response); - } - } - } + if (isPrivate) { + bot.send(sender, response, true); + } else { + if (isInvalidTz) { + bot.send(sender, response); + } else { + bot.send(bot.getChannel(), response); + } + } + } - @Override - public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) - { - bot.send(sender, "To display a country's current date/time:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TIME_CMD) + " [<country code>]"); + @Override + public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + bot.send(sender, "To display a country's current date/time:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TIME_CMD) + " [<country code>]"); - bot.send(sender, "For a listing of the supported countries:"); - bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TIME_CMD)); - } + bot.send(sender, "For a listing of the supported countries:"); + bot.send(sender, bot.helpIndent(bot.getNick() + ": " + TIME_CMD)); + } - /** - * Returns the current Internet (beat) Time. - * - * @return The Internet Time string. - */ - private String internetTime() - { - final Calendar gc = Calendar.getInstance(); + /** + * Returns the current Internet (beat) Time. + * + * @return The Internet Time string. + */ + private String internetTime() { + final Calendar gc = Calendar.getInstance(); - final int offset = (gc.get(Calendar.ZONE_OFFSET) / (60 * 60 * 1000)); - int hh = gc.get(Calendar.HOUR_OF_DAY); - final int mm = gc.get(Calendar.MINUTE); - final int ss = gc.get(Calendar.SECOND); + final int offset = (gc.get(Calendar.ZONE_OFFSET) / (60 * 60 * 1000)); + int hh = gc.get(Calendar.HOUR_OF_DAY); + final int mm = gc.get(Calendar.MINUTE); + final int ss = gc.get(Calendar.SECOND); - hh -= offset; // GMT - hh += 1; // BMT + hh -= offset; // GMT + hh += 1; // BMT - long beats = Math.round(Math.floor((double) ((((hh * 3600) + (mm * 60) + ss) * 1000) / 86400))); + long beats = Math.round(Math.floor((double) ((((hh * 3600) + (mm * 60) + ss) * 1000) / 86400))); - if (beats >= 1000) - { - beats -= (long) 1000; - } - else if (beats < 0) - { - beats += (long) 1000; - } + if (beats >= 1000) { + beats -= (long) 1000; + } else if (beats < 0) { + beats += (long) 1000; + } - if (beats < 10) - { - return ("@00" + beats); - } - else if (beats < 100) - { - return ("@0" + beats); - } + if (beats < 10) { + return ("@00" + beats); + } else if (beats < 100) { + return ("@0" + beats); + } - return ('@' + String.valueOf(beats)); - } + return ('@' + String.valueOf(beats)); + } - @Override - public boolean isPrivateMsgEnabled() - { - return true; - } + @Override + public boolean isPrivateMsgEnabled() { + return true; + } } \ No newline at end of file diff --git a/version.properties b/version.properties index 93eb253..e552373 100644 --- a/version.properties +++ b/version.properties @@ -5,4 +5,4 @@ version.major=0 version.minor=7 version.patch=0 version.prerelease=beta -version.buildmeta=007 +version.buildmeta=008