From 015a368bd125a2c76726ebfa7a04907656177713 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 2 Jul 2016 02:27:18 -0700 Subject: [PATCH] Moved most commands to modules. --- .idea/modules/mobibot.iml | 33 +- .idea/modules/mobibot_annotationProcessor.iml | 15 - .idea/modules/mobibot_main.iml | 36 - .idea/modules/mobibot_test.iml | 34 - build.gradle | 1 + mobibot.ipr | 542 ++++++------ .../net/thauvin/erik/mobibot/ReleaseInfo.java | 6 +- .../net/thauvin/erik/mobibot/Commands.java | 70 -- .../net/thauvin/erik/mobibot/Mobibot.java | 780 ++++-------------- .../java/net/thauvin/erik/mobibot/Utils.java | 77 +- .../erik/mobibot/modules/AbstractModule.java | 138 ++++ .../thauvin/erik/mobibot/modules/Calc.java | 98 +++ .../{ => modules}/CurrencyConverter.java | 96 ++- .../erik/mobibot/{ => modules}/Dice.java | 43 +- .../mobibot/{ => modules}/GoogleSearch.java | 108 ++- .../erik/mobibot/{ => modules}/Joke.java | 47 +- .../erik/mobibot/{ => modules}/Lookup.java | 98 ++- .../thauvin/erik/mobibot/modules/Ping.java | 67 ++ .../mobibot/{ => modules}/StockQuote.java | 61 +- .../erik/mobibot/{ => modules}/Twitter.java | 116 +-- .../erik/mobibot/{ => modules}/War.java | 45 +- .../erik/mobibot/{ => modules}/Weather.java | 69 +- .../erik/mobibot/{ => modules}/WorldTime.java | 49 +- version.properties | 4 +- 24 files changed, 1197 insertions(+), 1436 deletions(-) delete mode 100644 .idea/modules/mobibot_annotationProcessor.iml delete mode 100644 .idea/modules/mobibot_main.iml delete mode 100644 .idea/modules/mobibot_test.iml create mode 100644 src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java create mode 100644 src/main/java/net/thauvin/erik/mobibot/modules/Calc.java rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/CurrencyConverter.java (78%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/Dice.java (73%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/GoogleSearch.java (62%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/Joke.java (80%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/Lookup.java (62%) create mode 100644 src/main/java/net/thauvin/erik/mobibot/modules/Ping.java rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/StockQuote.java (81%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/Twitter.java (54%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/War.java (74%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/Weather.java (77%) rename src/main/java/net/thauvin/erik/mobibot/{ => modules}/WorldTime.java (82%) diff --git a/.idea/modules/mobibot.iml b/.idea/modules/mobibot.iml index de72d7d..58ccfb9 100644 --- a/.idea/modules/mobibot.iml +++ b/.idea/modules/mobibot.iml @@ -1,12 +1,43 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/mobibot_annotationProcessor.iml b/.idea/modules/mobibot_annotationProcessor.iml deleted file mode 100644 index 9ac6b73..0000000 --- a/.idea/modules/mobibot_annotationProcessor.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules/mobibot_main.iml b/.idea/modules/mobibot_main.iml deleted file mode 100644 index 039e934..0000000 --- a/.idea/modules/mobibot_main.iml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules/mobibot_test.iml b/.idea/modules/mobibot_test.iml deleted file mode 100644 index 02aaa94..0000000 --- a/.idea/modules/mobibot_test.iml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index ee895e3..f2027cb 100644 --- a/build.gradle +++ b/build.gradle @@ -63,6 +63,7 @@ dependencies { 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' diff --git a/mobibot.ipr b/mobibot.ipr index cdc8c10..bd77a17 100644 --- a/mobibot.ipr +++ b/mobibot.ipr @@ -1,146 +1,117 @@ - - false - false - false - false - false - - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java index b9773c3..95241ad 100644 --- a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java +++ b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java @@ -13,11 +13,11 @@ import java.util.Date; * Annotation Processor */ public final class ReleaseInfo { - private final static String buildmeta = "008"; - private final static Date date = new Date(1467076393978L); + private final static String buildmeta = "001"; + private final static Date date = new Date(1467451308717L); private final static int major = 0; private final static int minor = 6; - private final static int patch = 1; + private final static int patch = 5; private final static String prerelease = "beta"; private final static String project = "mobibot"; diff --git a/src/main/java/net/thauvin/erik/mobibot/Commands.java b/src/main/java/net/thauvin/erik/mobibot/Commands.java index 81509c5..b849b5e 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Commands.java +++ b/src/main/java/net/thauvin/erik/mobibot/Commands.java @@ -45,21 +45,6 @@ final class Commands */ public static final String ADDLOG_CMD = "addlog"; - /** - * The math command. - */ - public static final String CALC_CMD = "calc"; - - /** - * The currency command. - */ - public static final String CURRENCY_CMD = "currency"; - - /** - * The rates keyword. - */ - public static final String CURRENCY_RATES_KEYWORD = "rates"; - /** * The cycle command. */ @@ -75,21 +60,11 @@ final class Commands */ public static final String DEBUG_CMD = "debug"; - /** - * The dices command. - */ - public static final String DICE_CMD = "dice"; - /** * The die command. */ public static final String DIE_CMD = "die"; - /** - * The Google command. - */ - public static final String GOOGLE_CMD = "google"; - /** * Help command line argument. */ @@ -125,21 +100,11 @@ final class Commands */ public static final String INFO_CMD = "info"; - /** - * The joke command. - */ - public static final String JOKE_CMD = "joke"; - /** * The link command. */ public static final String LINK_CMD = "L"; - /** - * The lookup command. - */ - public static final String LOOKUP_CMD = "lookup"; - /** * The me command. */ @@ -155,16 +120,6 @@ final class Commands */ public static final String NICK_CMD = "nick"; - /** - * The ping command. - */ - public static final String PING_CMD = "ping"; - - /** - * The pong command. - */ - public static final String PONG_CMD = "pong"; - /** * Properties command line argument. */ @@ -180,11 +135,6 @@ final class Commands */ public static final String SAY_CMD = "say"; - /** - * The stock command. - */ - public static final String STOCK_CMD = "stock"; - /** * The {@link #TELL_CMD} all command. */ @@ -200,16 +150,6 @@ final class Commands */ public static final String TELL_DEL_CMD = "del"; - /** - * The time command. - */ - public static final String TIME_CMD = "time"; - - /** - * The Twitter command. - */ - public static final String TWITTER_CMD = "twitter"; - /** * The users command. */ @@ -230,16 +170,6 @@ final class Commands */ public static final String VIEW_CMD = "view"; - /** - * The war command. - */ - public static final String WAR_CMD = "war"; - - /** - * The weather command. - */ - public static final String WEATHER_CMD = "weather"; - /** * Disables the default constructor. * diff --git a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java index 45afd5f..f1e97a4 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java +++ b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java @@ -32,8 +32,7 @@ package net.thauvin.erik.mobibot; import com.rometools.rome.io.FeedException; -import net.objecthunter.exp4j.Expression; -import net.objecthunter.exp4j.ExpressionBuilder; +import net.thauvin.erik.mobibot.modules.*; import net.thauvin.erik.semver.Version; import org.apache.commons.cli.*; import org.apache.commons.logging.impl.Log4JLogger; @@ -44,8 +43,6 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.*; -import java.net.UnknownHostException; -import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; @@ -67,7 +64,7 @@ public class Mobibot extends PircBot /** * The empty title string. */ - public static final String NO_TITLE = "No Title"; + static final String NO_TITLE = "No Title"; /** * The default port. @@ -118,16 +115,16 @@ public class Mobibot extends PircBot */ private static final long MESSAGE_DELAY = 1000L; + /** + * The modules. + */ + private static final List MODULES = new ArrayList<>(0); + /** * The serialized object file extension. */ private static final String SER_EXT = ".ser"; - /** - * Shall we play a game? - */ - private static final String SHALL_WE_PLAY_A_GAME = "Shall we play a game?"; - /** * The start time. */ @@ -161,11 +158,6 @@ public class Mobibot extends PircBot */ private final List commandsList = new ArrayList<>(); - /** - * The currency converter. - */ - private final CurrencyConverter currencyConverter; - /** * The entries array. */ @@ -221,11 +213,6 @@ public class Mobibot extends PircBot */ private final List tellMessages = new CopyOnWriteArrayList<>(); - /** - * Time command. - */ - private final WorldTime worldTime = new WorldTime(); - /** * The backlogs URL. */ @@ -246,16 +233,6 @@ public class Mobibot extends PircBot */ private String feedURL = ""; - /** - * The Google API Key. - */ - private String googleApiKey = ""; - - /** - * The Google Custom Search Engine ID. - */ - private String googleCseCx = ""; - /** * The NickServ ident password. */ @@ -271,11 +248,6 @@ public class Mobibot extends PircBot */ private String identNick = ""; - /** - * The last player. - */ - private String lastPlayer = ""; - /** * The number of days message are kept. */ @@ -291,26 +263,6 @@ public class Mobibot extends PircBot */ private String today = Utils.today(); - /** - * The Twitter consumer key. - */ - private String twitterConsumerKey = ""; - - /** - * The Twitter consumer secret. - */ - private String twitterConsumerSecret = ""; - - /** - * The Twitter token. - */ - private String twitterToken = ""; - - /** - * The Twitter token secret. - */ - private String twitterTokenSecret = ""; - /** * The weblog URL. */ @@ -345,7 +297,6 @@ public class Mobibot extends PircBot // Initialization Utils.UTC_SDF.setTimeZone(TimeZone.getTimeZone("UTC")); - currencyConverter = new CurrencyConverter(this); // Load the current entries, if any. try @@ -385,6 +336,20 @@ public class Mobibot extends PircBot { 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()); } /** @@ -528,16 +493,6 @@ public class Mobibot extends PircBot final String dname = p.getProperty("delicious-user"); final String dpwd = p.getProperty("delicious-pwd"); - // Get the Twitter properties - final String tconsumerKey = p.getProperty("twitter-consumerKey"); - final String tconsumerSecret = p.getProperty("twitter-consumerSecret"); - final String ttoken = p.getProperty("twitter-token", ""); - final String ttokenSecret = p.getProperty("twitter-tokenSecret", ""); - - // Get the Google properties - final String googleApiKey = p.getProperty("google-api-key"); - final String googleCseCx = p.getProperty("google-cse-cx"); - // Get the tell command settings final int tellMaxDays = Utils.getIntProperty(p.getProperty("tell-max-days"), DEFAULT_TELL_MAX_DAYS); final int tellMaxSize = Utils.getIntProperty(p.getProperty("tell-max-size"), DEFAULT_TELL_MAX_SIZE); @@ -570,20 +525,13 @@ public class Mobibot extends PircBot bot.setDeliciousAuth(dname, dpwd); } - if (Utils.isValidString(tconsumerKey) && Utils.isValidString(tconsumerSecret) && Utils.isValidString(ttoken) - && Utils.isValidString(ttokenSecret)) - { - // Set the Twitter authentication - bot.setTwitterAuth(tconsumerKey, tconsumerSecret, ttoken, ttokenSecret); - } - - if (Utils.isValidString(googleApiKey)) - { - if (Utils.isValidString(googleCseCx)) + // Load the modules properties + MODULES.stream().filter(AbstractModule::hasProperties).forEach(module -> { + for (final String s : module.getPropertyKeys()) { - bot.setGoogleAuth(googleApiKey, googleCseCx); + module.setProperty(s, p.getProperty(s, "")); } - } + }); // Set the tags bot.setTags(tags); @@ -703,32 +651,6 @@ public class Mobibot extends PircBot delicious = new DeliciousPoster(username, password, ircServer); } - /** - * Sets the Twitter consumerSecret and password.. - * - * @param consumerKey The Twitter consumer key. - * @param consumerSecret The Twitter consumer secret. - * @param token The Twitter token. - * @param tokenSecret The Twitter token secret. - */ - private void setTwitterAuth(final String consumerKey, final String consumerSecret, final String token, - final String tokenSecret) - { - twitterConsumerKey = consumerKey; - twitterConsumerSecret = consumerSecret; - twitterToken = token; - twitterTokenSecret = tokenSecret; - } - - /** - * Sets the Google authentication. - */ - private void setGoogleAuth(final String apiKey, final String cseCx) - { - this.googleApiKey = apiKey; - this.googleCseCx = cseCx; - } - /** * Sets the default tags/categories. * @@ -844,7 +766,7 @@ public class Mobibot extends PircBot * * @param action The action. */ - final void action(final String action) + final public void action(final String action) { action(channel, action); } @@ -863,40 +785,6 @@ public class Mobibot extends PircBot } } - /** - * Processes the {@link Commands#CALC_CMD} command. - * - * @param sender The nick of the person who sent the message - * @param args The command arguments. - * @param message The actual message. - */ - private void calcResponse(final String sender, final String args, final String message) - { - if (Utils.isValidString(args)) - { - final DecimalFormat decimalFormat = new DecimalFormat("#.##"); - - try - { - final Expression calc = new ExpressionBuilder(args).build(); - send(channel, args.replaceAll(" ", "") + " = " + decimalFormat.format(calc.evaluate())); - } - catch (Exception e) - { - if (logger.isDebugEnabled()) - { - logger.debug("Unable to calculate: " + message, e); - } - - send(channel, "No idea. This is the kind of math I don't get."); - } - } - else - { - helpResponse(sender, Commands.CALC_CMD); - } - } - /** * Responds with the title and links from the RSS feed. * @@ -971,16 +859,6 @@ public class Mobibot extends PircBot return channel; } - /** - * Returns the Google API Key, if any. - * - * @return The Google API key or empty. - */ - public String getGoogleApiKey() - { - return this.googleApiKey; - } - /** * Returns the irc server. * @@ -1060,31 +938,6 @@ public class Mobibot extends PircBot this.weblogUrl = weblogUrl; } - /** - * Responds with the Google search results for the specified query. - * - * @param sender The nick of the person who sent the private message. - * @param query The Google query to execute. - */ - private void googleResponse(final String sender, final String query) - { - if (isGseEnabled()) - { - if (query.length() > 0) - { - new Thread(new GoogleSearch(this, googleCseCx, sender, query)).start(); - } - else - { - helpResponse(sender, Commands.GOOGLE_CMD); - } - } - else - { - send(sender, "The Google searching facility is disabled."); - } - } - /** * Returns indented and bold help string. * @@ -1092,7 +945,7 @@ public class Mobibot extends PircBot * * @return The indented help string. */ - private String helpIndent(final String help) + final public String helpIndent(final String help) { return helpIndent(help, true); } @@ -1116,11 +969,11 @@ public class Mobibot extends PircBot * @param sender The nick of the person who sent the private message. * @param topic The help topic, if any. */ - public final void helpResponse(final String sender, final String topic) + private void helpResponse(final String sender, final String topic) { - final String lcTopic = topic.toLowerCase(); + final String lcTopic = topic.toLowerCase().trim(); - if (lcTopic.endsWith(Commands.HELP_POSTING_KEYWORD)) + 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> [...]]")); @@ -1136,145 +989,63 @@ public class Mobibot extends PircBot send(sender, helpIndent(Commands.LINK_CMD + "1.1:-")); send(sender, "You can also view a posting by saying its label."); } - else if (lcTopic.endsWith(Commands.HELP_TAGS_KEYWORD)) + 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.endsWith(Commands.VIEW_CMD)) + 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.endsWith(channel.substring(1).toLowerCase())) + 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.endsWith(Commands.GOOGLE_CMD) && isGseEnabled()) - { - send(sender, "To search Google:"); - send(sender, helpIndent(getNick() + ": " + Commands.GOOGLE_CMD + " <query>")); - } - else if (lcTopic.endsWith(Commands.TWITTER_CMD) && isTwitterEnabled()) - { - send(sender, "To post to Twitter:"); - send(sender, helpIndent(getNick() + ": " + Commands.TWITTER_CMD + " <message>")); - } - else if (lcTopic.endsWith(Commands.RECAP_CMD)) + 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.endsWith(Commands.CALC_CMD)) - { - send(sender, "To solve a mathematical calculation:"); - send(sender, helpIndent(getNick() + ": " + Commands.CALC_CMD + " <calculation>")); - } - else if (lcTopic.endsWith(Commands.LOOKUP_CMD)) - { - send(sender, "To perform a DNS lookup query:"); - send(sender, helpIndent(getNick() + ": " + Commands.LOOKUP_CMD + " <ip address or hostname>")); - } - else if (lcTopic.endsWith(Commands.TIME_CMD)) - { - send(sender, "To display a country's current date/time:"); - send(sender, helpIndent(getNick() + ": " + Commands.TIME_CMD) + " [<country code>]"); - - send(sender, "For a listing of the supported countries:"); - send(sender, helpIndent(getNick() + ": " + Commands.TIME_CMD)); - } - else if (lcTopic.endsWith(Commands.JOKE_CMD)) - { - send(sender, "To retrieve a random joke:"); - send(sender, helpIndent(getNick() + ": " + Commands.JOKE_CMD)); - } - else if (lcTopic.endsWith(Commands.STOCK_CMD)) - { - send(sender, "To retrieve a stock quote:"); - send(sender, helpIndent(getNick() + ": " + Commands.STOCK_CMD + " <symbol[.country code]>")); - } - else if (lcTopic.endsWith(Commands.DICE_CMD)) - { - send(sender, "To roll the dice:"); - send(sender, helpIndent(getNick() + ": " + Commands.DICE_CMD)); - } - else if (lcTopic.endsWith(Commands.WAR_CMD)) - { - send(sender, "To play war:"); - send(sender, helpIndent(getNick() + ": " + Commands.WAR_CMD)); - } - else if (lcTopic.endsWith(Commands.WEATHER_CMD)) - { - send(sender, "To display weather information:"); - send(sender, helpIndent(getNick() + ": " + Commands.WEATHER_CMD + " <station id>")); - send(sender, "For a listing of the ICAO station IDs, please visit: " + Weather.STATIONS_URL); - } - else if (lcTopic.endsWith(Commands.USERS_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.endsWith(Commands.INFO_CMD)) + else if (lcTopic.equals(Commands.INFO_CMD) && isOp(sender)) { send(sender, "To view information about the bot:"); send(sender, helpIndent(getNick() + ": " + Commands.INFO_CMD)); } - else if (lcTopic.endsWith(Commands.CYCLE_CMD)) + else if (lcTopic.equals(Commands.CYCLE_CMD) && isOp(sender)) { - if (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.endsWith(Commands.ME_CMD)) - { - if (isOp(sender)) - { - send(sender, "To have the bot perform an action:"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.ME_CMD + " <action>")); - } - } - else if (lcTopic.endsWith(Commands.SAY_CMD)) - { - if (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.endsWith(Commands.VERSION_CMD)) - { - if (isOp(sender)) - { - send(sender, "To view the version data (bot, java, etc.):"); - send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.VERSION_CMD)); - } - } - else if (lcTopic.endsWith(Commands.MSG_CMD)) - { - if (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.startsWith(Commands.CURRENCY_CMD)) - { - send(sender, "To convert from one currency to another:"); - send(sender, helpIndent(getNick() + ": " + Commands.CURRENCY_CMD + " [100 USD to EUR]")); + send(sender, "To have the bot leave the channel and come back:"); + send(sender, helpIndent("/msg " + getNick() + ' ' + Commands.CYCLE_CMD)); - if (lcTopic.endsWith(Commands.CURRENCY_CMD)) - { - send(sender, "For a listing of currency rates:"); - send(sender, - helpIndent(getNick() + ": " + Commands.CURRENCY_CMD) + ' ' + Commands.CURRENCY_RATES_KEYWORD); - send(sender, "For a listing of supported currencies:"); - send(sender, helpIndent(getNick() + ": " + Commands.CURRENCY_CMD)); - } } - else if (lcTopic.startsWith(Commands.IGNORE_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)); @@ -1283,7 +1054,7 @@ public class Mobibot extends PircBot send(sender, helpIndent(getNick() + ": " + Commands.IGNORE_CMD + ' ' + Commands.IGNORE_ME_KEYWORD)); } - else if (lcTopic.startsWith(Commands.TELL_CMD)) + else if (lcTopic.equals(Commands.TELL_CMD)) { send(sender, "To send a message to someone when they join the channel:"); send(sender, helpIndent(getNick() + ": " + Commands.TELL_CMD + " <nick> <message>")); @@ -1295,6 +1066,19 @@ public class Mobibot extends PircBot } 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>")); @@ -1302,39 +1086,23 @@ public class Mobibot extends PircBot if (commandsList.isEmpty()) { - commandsList.add(Commands.CALC_CMD); - commandsList.add(Commands.CURRENCY_CMD); - commandsList.add(Commands.DICE_CMD); commandsList.add(Commands.IGNORE_CMD); commandsList.add(Commands.INFO_CMD); - commandsList.add(Commands.JOKE_CMD); - commandsList.add(Commands.LOOKUP_CMD); commandsList.add(channel.substring(1)); commandsList.add(Commands.HELP_POSTING_KEYWORD); - commandsList.add(Commands.RECAP_CMD); - commandsList.add(Commands.STOCK_CMD); commandsList.add(Commands.HELP_TAGS_KEYWORD); - commandsList.add(Commands.TIME_CMD); + commandsList.add(Commands.RECAP_CMD); commandsList.add(Commands.USERS_CMD); commandsList.add(Commands.VIEW_CMD); - commandsList.add(Commands.WAR_CMD); - commandsList.add(Commands.WEATHER_CMD); + + MODULES.stream().filter(AbstractModule::isEnabled) + .forEach(module -> commandsList.addAll(module.getCommands())); if (isTellEnabled()) { commandsList.add(Commands.TELL_CMD); } - if (isTwitterEnabled()) - { - commandsList.add(Commands.TWITTER_CMD); - } - - if (isGseEnabled()) - { - commandsList.add(Commands.GOOGLE_CMD); - } - Collections.sort(commandsList); } @@ -1350,7 +1118,7 @@ public class Mobibot extends PircBot sb.append(commandsList.get(i)); // 5 commands per line or last command - if (sb.length() > 0 && (cmdCount == 5 || i == (commandsList.size() - 1))) + if (sb.length() > 0 && (cmdCount == 6 || i == (commandsList.size() - 1))) { send(sender, helpIndent(sb.toString())); @@ -1466,16 +1234,6 @@ public class Mobibot extends PircBot isPrivate); } - /** - * Returns <code>true</code> if Google search is enabled. - * - * @return <code>true</code> or <code>false</code> - */ - private boolean isGseEnabled() - { - return Utils.isValidString(googleApiKey) && Utils.isValidString(googleCseCx); - } - /** * Determines whether the specified nick should be ignored. * @@ -1511,81 +1269,6 @@ public class Mobibot extends PircBot return false; } - /** - * Returns <code>true</code> if twitter posting is enabled. - * - * @return <code>true</code> or <code>false</code> - */ - private boolean isTwitterEnabled() - { - return Utils.isValidString(twitterConsumerKey) && Utils.isValidString(twitterConsumerSecret) && Utils - .isValidString(twitterToken) && Utils.isValidString(twitterTokenSecret); - } - - /** - * Responds with the results of a DNS query. - * - * @param sender The nick of the person who sent the message - * @param query The hostname or IP address. - */ - private void lookupResponse(final String sender, final String query) - { - if (query.matches("(\\S.)+(\\S)+")) - { - try - { - send(channel, Lookup.lookup(query)); - } - catch (UnknownHostException ignore) - { - if (query.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(query); - - if ((lines != null) && (lines.length > 0)) - { - String line; - - for (final String rawLine : lines) - { - line = rawLine.trim(); - - if ((line.length() > 0) && (line.charAt(0) != '#')) - { - send(channel, line); - } - } - } - else - { - send(channel, "Unknown host."); - } - } - catch (IOException ioe) - { - if (logger.isDebugEnabled()) - { - logger.debug("Unable to perform whois IP lookup: " + query, ioe); - } - - send(channel, "Unable to perform whois IP lookup: " + ioe.getMessage()); - } - } - else - { - send(channel, "Unknown host."); - } - } - } - else - { - helpResponse(sender, Commands.LOOKUP_CMD); - } - } - @Override protected final void onDisconnect() { @@ -1768,33 +1451,6 @@ public class Mobibot extends PircBot { helpResponse(sender, args); } - // mobibot: ping - else if (cmd.equals(Commands.PING_CMD)) - { - final String[] pings = { - "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!" - }; - - final Random r = new Random(); - - action(channel, pings[r.nextInt(pings.length)]); - } - // mobibot: pong - else if (cmd.equals(Commands.PONG_CMD)) - { - send(channel, Commands.PING_CMD, true); - } // mobibot: recap else if (cmd.equals(Commands.RECAP_CMD)) { @@ -1815,94 +1471,40 @@ public class Mobibot extends PircBot { versionResponse(sender, false); } - // mobibot: dice - else if (cmd.equals(Commands.DICE_CMD)) - { - if (!lastPlayer.equalsIgnoreCase(sender)) - { - send(channel, SHALL_WE_PLAY_A_GAME); - lastPlayer = sender; - } - - Dice.roll(this, sender); - } - // mobibot: war - else if (cmd.equals(Commands.WAR_CMD)) - { - if (!lastPlayer.equalsIgnoreCase(sender)) - { - send(channel, SHALL_WE_PLAY_A_GAME); - lastPlayer = sender; - } - - War.play(this, sender); - } // mobibot: <channel> else if (cmd.equalsIgnoreCase(channel.substring(1))) { feedResponse(sender); } - // mobibot: currency - else if (cmd.startsWith(Commands.CURRENCY_CMD)) - { - currencyConverter.setQuery(sender, args); - new Thread(currencyConverter).start(); - } - // mobibot: lookup - else if (cmd.startsWith(Commands.LOOKUP_CMD)) - { - lookupResponse(sender, args); - } // mobibot: view else if (cmd.startsWith(Commands.VIEW_CMD)) { viewResponse(sender, args, false); } - // mobibot: google - else if (cmd.startsWith(Commands.GOOGLE_CMD) && isGseEnabled()) - { - googleResponse(sender, args); - } - // mobibot: twitter - else if (cmd.startsWith(Commands.TWITTER_CMD) && isTwitterEnabled()) - { - twitterResponse(sender, args); - } - // mobibot: stock - else if (cmd.startsWith(Commands.STOCK_CMD)) - { - stockResponse(sender, args); - } - // mobibot: joke - else if (cmd.startsWith(Commands.JOKE_CMD)) - { - new Thread(new Joke(this, sender)).start(); - } - // mobibot: calc - else if (cmd.startsWith(Commands.CALC_CMD)) - { - calcResponse(sender, args, message); - } - // mobibot: time - else if (cmd.startsWith(Commands.TIME_CMD)) - { - worldTime.timeResponse(this, sender, args, false); - } // mobibot: tell else if (cmd.startsWith(Commands.TELL_CMD) && isTellEnabled()) { tellResponse(sender, args); } - // mobibot: weather - else if (cmd.startsWith(Commands.WEATHER_CMD)) - { - weatherResponse(sender, args, false); - } // 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]+:.*")) @@ -2172,24 +1774,18 @@ public class Mobibot extends PircBot { helpResponse(sender, args); } - else if ("kill".equals(cmd)) + else if ("kill".equals(cmd) && isOp(sender)) { - if (isOp(sender)) - { - sendRawLine("QUIT : Poof!"); - System.exit(0); - } + sendRawLine("QUIT : Poof!"); + System.exit(0); } - else if (cmd.equals(Commands.DIE_CMD)) + else if (cmd.equals(Commands.DIE_CMD) && isOp(sender)) { - if (isOp(sender)) - { - send(channel, sender + " has just signed my death sentence."); - saveEntries(true); - sleep(3); - quitServer("The Bot Is Out There!"); - System.exit(0); - } + 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)) { @@ -2207,97 +1803,77 @@ public class Mobibot extends PircBot { usersResponse(sender, true); } - else if (cmd.startsWith(Commands.ADDLOG_CMD) && (cmds.length > 1)) + else if (cmd.equals(Commands.ADDLOG_CMD) && (cmds.length > 1) && isOp(sender)) { - if (isOp(sender)) + // e.g. 2014-04-01 + final File backlog = new File(logsDir + args + EntriesMgr.XML_EXT); + if (backlog.exists()) { - // 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."); - } + history.add(0, args); + send(sender, history.toString(), true); + } + else + { + send(sender, "The specified log could not be found."); } } - else if (cmd.startsWith(Commands.ME_CMD)) + else if (cmd.equals(Commands.ME_CMD) && isOp(sender)) { - if (isOp(sender)) + if (args.length() > 1) { - if (args.length() > 1) - { - action(args); - } - else - { - helpResponse(sender, Commands.ME_CMD); - } + action(args); + } + else + { + helpResponse(sender, Commands.ME_CMD); } } - else if (cmd.startsWith(Commands.NICK_CMD) && (cmds.length > 1)) + else if (cmd.equals(Commands.NICK_CMD) && (cmds.length > 1)) { if (isOp(sender)) { changeNick(args); } } - else if (cmd.startsWith(Commands.SAY_CMD)) + else if (cmd.equals(Commands.SAY_CMD) && isOp(sender)) { - if (isOp(sender)) + if (cmds.length > 1) { - if (cmds.length > 1) - { - send(channel, args, true); - } - else - { - helpResponse(sender, Commands.SAY_CMD); - } + send(channel, args, true); + } + else + { + helpResponse(sender, Commands.SAY_CMD); } } - else if (cmd.startsWith(Commands.MSG_CMD)) + else if (cmd.equals(Commands.MSG_CMD) && isOp(sender)) { - if (isOp(sender)) + if (cmds.length > 1) { - if (cmds.length > 1) - { - final String[] msg = args.split(" ", 2); + final String[] msg = args.split(" ", 2); - if (args.length() > 2) - { - send(msg[0], msg[1], true); - } - else - { - helpResponse(sender, Commands.MSG_CMD); - } + 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.startsWith(Commands.VIEW_CMD)) + else if (cmd.equals(Commands.VIEW_CMD)) { viewResponse(sender, args, true); } - else if (cmd.startsWith(Commands.TIME_CMD)) - { - worldTime.timeResponse(this, sender, args, true); - } - else if (cmd.startsWith(Commands.TELL_CMD) && isTellEnabled()) + else if (cmd.equals(Commands.TELL_CMD) && isTellEnabled()) { tellResponse(sender, args); } - else if (cmd.startsWith(Commands.WEATHER_CMD)) - { - weatherResponse(sender, args, true); - } else if (cmd.equals(Commands.INFO_CMD)) { infoResponse(sender, true); @@ -2324,6 +1900,21 @@ public class Mobibot extends PircBot } 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, ""); } } @@ -2501,24 +2092,6 @@ public class Mobibot extends PircBot send(sender, message, false); } - /** - * Responds with the specified stock quote. - * - * @param sender The nick of the person who sent the message. - * @param symbol The stock symbol to lookup. - */ - private void stockResponse(final String sender, final String symbol) - { - if (symbol.length() > 0) - { - new Thread(new StockQuote(this, sender, symbol)).start(); - } - else - { - helpResponse(sender, Commands.STOCK_CMD); - } - } - /** * Processes the {@link Commands#TELL_CMD} commands. * @@ -2702,37 +2275,6 @@ public class Mobibot extends PircBot } } - /** - * Posts a message to Twitter. - * - * @param sender The sender's nick. - * @param message The message. - */ - private void twitterResponse(final String sender, final String message) - { - if (isTwitterEnabled()) - { - if (message.length() > 0) - { - new Thread(new Twitter(this, - sender, - twitterConsumerKey, - twitterConsumerSecret, - twitterToken, - twitterTokenSecret, - message)).start(); - } - else - { - helpResponse(sender, Commands.TWITTER_CMD); - } - } - else - { - send(sender, "The Twitter posting facility is disabled."); - } - } - /** * Responds with the users on a channel. * @@ -2885,16 +2427,4 @@ public class Mobibot extends PircBot send(sender, "There is currently nothing to view. Why don't you post something?", isPrivate); } } - - /** - * Responds with weather from the specified station ID. - * - * @param sender The nick of the person who sent the message. - * @param id The station's ID. - * @param isPrivate Set to true is the response should be send as a private message. - */ - private void weatherResponse(final String sender, final String id, final boolean isPrivate) - { - new Thread(new Weather(this, sender, id, isPrivate)).start(); - } } diff --git a/src/main/java/net/thauvin/erik/mobibot/Utils.java b/src/main/java/net/thauvin/erik/mobibot/Utils.java index 69267e9..424fb80 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Utils.java +++ b/src/main/java/net/thauvin/erik/mobibot/Utils.java @@ -34,10 +34,6 @@ package net.thauvin.erik.mobibot; import org.jibble.pircbot.Colors; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -48,7 +44,7 @@ import java.util.Calendar; * @created 2014-04-26 * @since 1.0 */ -final class Utils +final public class Utils { /** * The timestamp simple date format. @@ -58,12 +54,12 @@ final class Utils /** * The ISO (YYYY-MM-DD) simple date format. */ - static final SimpleDateFormat ISO_SDF = new SimpleDateFormat("yyyy-MM-dd"); + public static final SimpleDateFormat ISO_SDF = new SimpleDateFormat("yyyy-MM-dd"); /** * The UTC (yyyy-MM-dd HH:mm) simple date format. */ - static final SimpleDateFormat UTC_SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + public static final SimpleDateFormat UTC_SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm"); /** * Disables the default constructor. @@ -191,71 +187,6 @@ final class Utils return (Commands.LINK_CMD + (entryIndex + 1) + "T: " + entry.getDeliciousTags().replaceAll(",", ", ")); } - /** - * Copies a file. - * - * @param in The source file. - * @param out The destination file. - * - * @throws java.io.IOException If the file could not be copied. - */ - @SuppressWarnings("UnusedDeclaration") - public static void copyFile(final File in, final File out) - throws IOException - { - FileChannel inChannel = null; - FileChannel outChannel = null; - FileInputStream input = null; - FileOutputStream output = null; - - try - { - input = new FileInputStream(in); - output = new FileOutputStream(out); - - inChannel = input.getChannel(); - outChannel = output.getChannel(); - - inChannel.transferTo(0L, inChannel.size(), outChannel); - } - finally - { - try - { - if (inChannel != null) - { - inChannel.close(); - } - - if (input != null) - { - input.close(); - } - } - catch (Exception ignore) - { - ; // Do nothing - } - - try - { - if (outChannel != null) - { - outChannel.close(); - } - - if (output != null) - { - output.close(); - } - } - catch (Exception ignore) - { - ; // Do nothing - } - } - } - /** * Ensures that the given location (File/URL) has a trailing slash (<code>/</code>) to indicate a directory. * @@ -264,7 +195,7 @@ final class Utils * * @return The location ending with a slash. */ - public static String ensureDir(final String location, final boolean isUrl) + static String ensureDir(final String location, final boolean isUrl) { if (isUrl) { diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java new file mode 100644 index 0000000..7c4d90d --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java @@ -0,0 +1,138 @@ +/* + * Module.java + * + * Copyright (c) 2004-2016, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules; + +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; + +import java.util.*; + +/** + * The <code>Module</code> class. + * + * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> + * @created 2016-07-01 + * @since 1.0 + */ +public abstract class AbstractModule +{ + + final List<String> commands = new ArrayList<>(); + + final Map<String, String> properties = new HashMap<>(); + + /** + * 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 commands, if any. + * + * @return The commands. + */ + public List<String> getCommands() + { + return commands; + } + + /** + * Returns the module's property keys. + * + * @return The keys. + */ + public Set<String> getPropertyKeys() + { + return properties.keySet(); + } + + /** + * Returns <code>true</code> if the module has properties. + * + * @return <code>true</code> or <code>false</code> . + */ + public boolean hasProperties() + { + return !properties.isEmpty(); + } + + /** + * 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 is enabled. + * + * @return <code>true</code> or <code>false</code> + */ + public boolean isEnabled() + { + return true; + } + + /** + * Returns <codde>true</codde> if the module responds to private messages. + * + * @return <code>true</code> or <code>false</code> + */ + public boolean isPrivateMsgEnabled() + { + return false; + } + + /** + * 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 new file mode 100644 index 0000000..e5dbe92 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java @@ -0,0 +1,98 @@ +/* + * Calc.java + * + * Copyright (c) 2004-2016, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules; + +import net.objecthunter.exp4j.Expression; +import net.objecthunter.exp4j.ExpressionBuilder; +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; + +import java.text.DecimalFormat; + +/** + * The Calc module. + * + * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> + * @created 2016-07-01 + * @since 1.0 + */ +public class Calc extends AbstractModule +{ + /** + * The Calc command. + */ + private static final String CALC_CMD = "calc"; + + /** + * 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("#.##"); + + 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); + } + + } + + @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/CurrencyConverter.java b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java similarity index 78% rename from src/main/java/net/thauvin/erik/mobibot/CurrencyConverter.java rename to src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java index 121d452..b0616b6 100644 --- a/src/main/java/net/thauvin/erik/mobibot/CurrencyConverter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java @@ -29,8 +29,10 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; @@ -46,14 +48,24 @@ import java.util.Map; import java.util.TreeMap; /** - * Processes the {@link Commands#CURRENCY_CMD} command. + * The CurrentConverter module. * * @author Erik C. Thauvin * @created Feb 11, 2004 * @since 1.0 */ -class CurrencyConverter implements Runnable +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 exchange rates. */ @@ -64,40 +76,54 @@ class CurrencyConverter implements Runnable */ private static final String EXCHANGE_TABLE_URL = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml"; - /** - * The bot. - */ - private final Mobibot bot; - /** * The last exchange rates table publication date. */ private String pubDate = ""; - /** - * The actual currency query. - */ - private String query; - - /** - * The nick of the person who sent the message. - */ - private String sender; - /** * Creates a new {@link CurrencyConverter} instance. - * - * @param bot The bot's instance. */ - public CurrencyConverter(final Mobibot bot) + public CurrencyConverter() { - this.bot = bot; + 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(); + } + } + + 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]")); + + 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. */ - public final void run() + private void run(final Mobibot bot, final String sender, final String query) { if (Utils.isValidString(sender)) { @@ -183,7 +209,7 @@ class CurrencyConverter implements Runnable } } } - else if (query.equals(Commands.CURRENCY_RATES_KEYWORD)) + else if (query.equals(CURRENCY_RATES_KEYWORD)) { bot.send(sender, "Last Update: " + pubDate); @@ -204,27 +230,9 @@ class CurrencyConverter implements Runnable } else { - bot.helpResponse(sender, Commands.CURRENCY_CMD + ' ' + query); + helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); bot.send(sender, "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); } } } - - /** - * Sets the query. - * - * @param sender The nick of the person who sent the message. - * @param query The currency query. - */ - - public synchronized void setQuery(final String sender, final String query) - { - this.query = query; - this.sender = sender; - - if (!pubDate.equals(Utils.today())) - { - EXCHANGE_RATES.clear(); - } - } -} +} \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/Dice.java b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java similarity index 73% rename from src/main/java/net/thauvin/erik/mobibot/Dice.java rename to src/main/java/net/thauvin/erik/mobibot/modules/Dice.java index eeb9f8b..e9d251f 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Dice.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java @@ -29,37 +29,45 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; + +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import java.util.Random; /** - * Processes the {@link Commands#DICE_CMD} command. + * The Dice module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created 2014-04-28 * @since 1.0 */ -final class Dice +final public class Dice extends AbstractModule { /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. + * The dice command. */ - private Dice() - throws UnsupportedOperationException + private final String DICE_CMD = "dice"; + + /** + * The default constructor. + */ + public Dice() { - throw new UnsupportedOperationException("Illegal constructor call."); + commands.add(DICE_CMD); } /** * Rolls the dice. * * @param bot The bot's instance. - * @param sender The sender's nickname. + * @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 static void roll(final Mobibot bot, final String sender) + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { final Random r = new Random(); @@ -91,4 +99,17 @@ final class Dice 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 boolean isEnabled() + { + return true; + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/GoogleSearch.java b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java similarity index 62% rename from src/main/java/net/thauvin/erik/mobibot/GoogleSearch.java rename to src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java index f2bb11e..9becd44 100644 --- a/src/main/java/net/thauvin/erik/mobibot/GoogleSearch.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java @@ -29,8 +29,10 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import org.json.JSONArray; import org.json.JSONObject; @@ -41,67 +43,78 @@ import java.net.URLConnection; import java.net.URLEncoder; /** - * Processes the {@link Commands#GOOGLE_CMD} command. + * The GoogleSearch module. * * @author Erik C. Thauvin * @created Feb 7, 2004 * @since 1.0 */ -class GoogleSearch implements Runnable +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 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 bot. - */ - private final Mobibot bot; - - /** - * The Google Custom Search Engine ID. - */ - private final String cseCx; - - /** - * The search query. - */ - private final String query; - - /** - * The nick of the person who sent the message. - */ - private final String sender; - /** * Creates a new {@link GoogleSearch} instance. - * - * @param bot The bot's instance. - * @param cseCx The Google Custom Search Engine ID. - * @param sender The nick of the person who sent the message. - * @param query The Google query */ - public GoogleSearch(final Mobibot bot, final String cseCx, final String sender, final String query) + public GoogleSearch() { - this.bot = bot; - this.cseCx = cseCx; - this.sender = sender; - this.query = query; + 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); + } } /** * Searches Google. */ - public final void run() + private void run(final Mobibot bot, final String sender, final String query) { try { - final String query = URLEncoder.encode(this.query, "UTF-8"); + final String q = URLEncoder.encode(query, "UTF-8"); final URL url = - new URL("https://www.googleapis.com/customsearch/v1?key=" + bot.getGoogleApiKey() + "&cx=" + cseCx - + "&q=" + query + "&filter=1&num=5&alt=json"); + 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(); final StringBuilder sb = new StringBuilder(); @@ -131,4 +144,25 @@ class GoogleSearch implements Runnable bot.send(sender, "An error has occurred: " + e.getMessage()); } } + + @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."); + } + } + + @Override + public boolean isEnabled() + { + return Utils.isValidString(properties.get(GOOGLE_API_KEY_PROP)) && Utils + .isValidString(properties.get(GOOGLE_CSE_KEY_PROP)); + } } diff --git a/src/main/java/net/thauvin/erik/mobibot/Joke.java b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java similarity index 80% rename from src/main/java/net/thauvin/erik/mobibot/Joke.java rename to src/main/java/net/thauvin/erik/mobibot/modules/Joke.java index 69a6475..8d3f19a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Joke.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java @@ -29,8 +29,9 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; +import net.thauvin.erik.mobibot.Mobibot; import org.jibble.pircbot.Colors; import org.json.JSONObject; @@ -40,47 +41,53 @@ import java.net.URL; import java.net.URLConnection; /** - * Processes the {@link Commands#JOKE_CMD} command. + * The Joke module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created 2014-04-20 * @since 1.0 */ -class Joke implements Runnable +final public class Joke extends AbstractModule { + /** + * 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 bot's instance. - */ - private final Mobibot bot; - - /** - * The nick of the person who sent the message. - */ - private final String sender; - /** * Creates a new {@link Joke} instance. - * - * @param bot The bot's instance. - * @param sender The nick of the person who sent the message. */ - public Joke(final Mobibot bot, final String sender) + public Joke() { - this.bot = bot; - this.sender = sender; + 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 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> */ - public final void run() + private void run(final Mobibot bot, final String sender) { try { diff --git a/src/main/java/net/thauvin/erik/mobibot/Lookup.java b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java similarity index 62% rename from src/main/java/net/thauvin/erik/mobibot/Lookup.java rename to src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java index 632184e..b42c686 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Lookup.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java @@ -29,8 +29,9 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; +import net.thauvin.erik.mobibot.Mobibot; import org.apache.commons.net.whois.WhoisClient; import java.io.IOException; @@ -38,14 +39,18 @@ import java.net.InetAddress; import java.net.UnknownHostException; /** - * Processes the {@link Commands#LOOKUP_CMD} command. + * The Lookup module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created 2014-04-26 * @since 1.0 */ -final class Lookup +final public class Lookup extends AbstractModule { + /** + * THe lookup command. + */ + private static final String LOOKUP_CMD = "lookup"; /** * The whois host. @@ -53,14 +58,78 @@ final class Lookup private static final String WHOIS_HOST = "whois.arin.net"; /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. + * The default constructor */ - private Lookup() - throws UnsupportedOperationException + public Lookup() { - throw new UnsupportedOperationException("Illegal constructor call."); + 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); + + if ((lines != null) && (lines.length > 0)) + { + String line; + + for (final String rawLine : lines) + { + line = rawLine.trim(); + + 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); + } + + 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); + } } /** @@ -72,7 +141,7 @@ final class Lookup * * @throws java.net.UnknownHostException If the host is unknown. */ - public static String lookup(final String query) + private static String lookup(final String query) throws UnknownHostException { final StringBuilder buffer = new StringBuilder(""); @@ -116,7 +185,7 @@ final class Lookup * * @throws java.io.IOException If a connection error occurs. */ - public static String[] whois(final String query) + private static String[] whois(final String query) throws IOException { return whois(query, WHOIS_HOST); @@ -155,4 +224,11 @@ final class Lookup return lines; } + + @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 new file mode 100644 index 0000000..efed060 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java @@ -0,0 +1,67 @@ +/* + * Ping.java + * + * Copyright (c) 2016 Erik C. Thauvin (http://erik.thauvin.net/) + * All rights reserved. + */ +package net.thauvin.erik.mobibot.modules; + +import net.thauvin.erik.mobibot.Mobibot; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * The <code>Ping</code> class. + * + * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> + * @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!"); + + /** + * The ping command. + */ + private static final String PING_CMD = "ping"; + + /** + * 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(); + + 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)); + } +} \ No newline at end of file diff --git a/src/main/java/net/thauvin/erik/mobibot/StockQuote.java b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java similarity index 81% rename from src/main/java/net/thauvin/erik/mobibot/StockQuote.java rename to src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java index e026841..1ec40bf 100644 --- a/src/main/java/net/thauvin/erik/mobibot/StockQuote.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java @@ -29,61 +29,68 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; import com.Ostermiller.util.CSVParser; +import net.thauvin.erik.mobibot.Mobibot; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import java.io.IOException; /** - * Processes the {@link Commands#STOCK_CMD} command. + * The StockQuote module. * * @author Erik C. Thauvin * @created Feb 7, 2004 * @since 1.0 */ -class StockQuote implements Runnable +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 bot. - */ - private final Mobibot bot; - - /** - * The nick of the person who sent the message. - */ - private final String sender; - - /** - * The stock symbol. - */ - private final String symbol; - /** * Creates a new {@link StockQuote} instance. - * - * @param bot The bot's instance. - * @param sender The nick of the person who sent the message. - * @param symbol The stock symbol. */ - public StockQuote(final Mobibot bot, final String sender, final String symbol) + public StockQuote() { - this.bot = bot; - this.sender = sender; - this.symbol = symbol; + 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 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! */ - public final void run() + private void run(final Mobibot bot, final String sender, final String symbol) { try { diff --git a/src/main/java/net/thauvin/erik/mobibot/Twitter.java b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java similarity index 54% rename from src/main/java/net/thauvin/erik/mobibot/Twitter.java rename to src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java index 9096603..e518442 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Twitter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java @@ -29,89 +29,97 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import twitter4j.Status; import twitter4j.TwitterFactory; import twitter4j.conf.ConfigurationBuilder; /** - * Processes the {@link Commands#TWITTER_CMD} command. + * The Twitter module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created Sept 10, 2008 * @since 1.0 */ -class Twitter implements Runnable +final public class Twitter extends AbstractModule { - /** - * The Twitter access token. - */ - private final String accessToken; + 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"; /** - * The Twitter access token secret. + * The twitter command. */ - private final String accessTokenSecret; - - /** - * The bot. - */ - private final Mobibot bot; - - /** - * The Twitter consumer key. - */ - private final String consumerKey; - - /** - * The Twitter consumer secret. - */ - private final String consumerSecret; - - /** - * The Twitter message. - */ - private final String message; - - /** - * The nick of the person who sent the message. - */ - private final String sender; + private final static String TWITTER_CMD = "twitter"; /** * Creates a new {@link Twitter} instance. - * - * @param bot The bot's instance. - * @param sender The nick of the person who sent the message. - * @param consumerKey The Twitter consumer key. - * @param consumerSecret The Twitter consumer secret. - * @param accessToken The Twitter access token. - * @param accessTokenSecret The Twitter access token secret. - * @param message The Twitter message. */ - public Twitter(final Mobibot bot, final String sender, final String consumerKey, final String consumerSecret, - final String accessToken, final String accessTokenSecret, final String message) + public Twitter() { - this.bot = bot; - this.consumerKey = consumerKey; - this.consumerSecret = consumerSecret; - this.accessToken = accessToken; - this.accessTokenSecret = accessTokenSecret; - this.message = message; - this.sender = sender; + 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 Utils.isValidString(properties.get(CONSUMER_KEY_PROP)) && Utils + .isValidString(properties.get(CONSUMER_SECRET_PROP)) && Utils.isValidString(properties.get(TOKEN_PROP)) + && Utils.isValidString(properties.get(TOKEN_SECRET_PROP)); + } + + @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); + } + } + + @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."); + } } /** * Posts to twitter. */ - public final void run() + private void run(final Mobibot bot, final String sender, final String message) { try { final ConfigurationBuilder cb = new ConfigurationBuilder(); - cb.setDebugEnabled(true).setOAuthConsumerKey(consumerKey).setOAuthConsumerSecret(consumerSecret) - .setOAuthAccessToken(accessToken).setOAuthAccessTokenSecret(accessTokenSecret); + 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(); diff --git a/src/main/java/net/thauvin/erik/mobibot/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java similarity index 74% rename from src/main/java/net/thauvin/erik/mobibot/War.java rename to src/main/java/net/thauvin/erik/mobibot/modules/War.java index 4798a3b..182d5ee 100644 --- a/src/main/java/net/thauvin/erik/mobibot/War.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java @@ -29,48 +29,56 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; + +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import java.util.Random; /** - * Processes the {@link Commands#WAR_CMD} command. + * The War module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created 2014-04-28 * @since 1.0 */ -final class War +final public class War extends AbstractModule { /** - * The deck of card for the {@link net.thauvin.erik.mobibot.Commands#WAR_CMD war} command. + * 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 suits for the deck of card for the {@link Commands#WAR_CMD war} command. + * The suits for the deck of card. */ private static final String[] WAR_SUITS = new String[]{"Hearts", "Spades", "Diamonds", "Clubs"}; /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. + * The default constructor. */ - private War() - throws UnsupportedOperationException + public War() { - throw new UnsupportedOperationException("Illegal constructor call."); + commands.add(WAR_CMD); } /** * Plays war. * * @param bot The bot's instance. - * @param sender The sender's nickname. + * @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 static void play(final Mobibot bot, final String sender) + @Override + public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { final Random r = new Random(); @@ -102,9 +110,12 @@ final class War { bot.action("wins."); } - else - { - bot.action("tied."); - } + } + + @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/Weather.java b/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java similarity index 77% rename from src/main/java/net/thauvin/erik/mobibot/Weather.java rename to src/main/java/net/thauvin/erik/mobibot/modules/Weather.java index e0b457d..832678b 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Weather.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Weather.java @@ -29,74 +29,75 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; import net.sf.jweather.metar.Metar; import net.sf.jweather.metar.SkyCondition; import net.sf.jweather.metar.WeatherCondition; +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import java.text.DecimalFormat; import java.util.Date; /** - * Processes the {@link Commands#LOOKUP_CMD} command. + * The Weather module * * @author Erik C. Thauvin * @created Feb 7, 2004 * @since 1.0 */ -class Weather implements Runnable +final public class Weather extends AbstractModule { - /** - * The URL where the stations are listed. - */ - public static final String STATIONS_URL = "http://www.rap.ucar.edu/weather/surface/stations.txt"; - /** * The decimal number format. */ private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("0.##"); /** - * The bot. + * The URL where the stations are listed. */ - private final Mobibot bot; + private static final String STATIONS_URL = "http://www.rap.ucar.edu/weather/surface/stations.txt"; /** - * The private message flag. + * THe weather command. */ - private final boolean isPrivate; - - /** - * The nick of the person who sent the message. - */ - private final String sender; - - /** - * The station ID. - */ - private final String station; + private static final String WEATHER_CMD = "weather"; /** * Creates a new {@link Weather} instance. - * - * @param bot The bot's instance. - * @param sender The nick of the person who sent the message. - * @param station The station ID. - * @param isPrivate Set to true is the response should be send as a private message. */ - public Weather(final Mobibot bot, final String sender, final String station, final boolean isPrivate) + public Weather() { - this.bot = bot; - this.sender = sender; - this.station = station.toUpperCase(); - this.isPrivate = isPrivate; + 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 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; } /** * Fetches the weather data from a specific station ID. */ - public final void run() + private void run(final Mobibot bot, final String sender, final String station, final boolean isPrivate) { if (station.length() == 4) { @@ -177,6 +178,6 @@ class Weather implements Runnable } } - bot.helpResponse(sender, Commands.WEATHER_CMD); + helpResponse(bot, sender, station, isPrivate); } } diff --git a/src/main/java/net/thauvin/erik/mobibot/WorldTime.java b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java similarity index 82% rename from src/main/java/net/thauvin/erik/mobibot/WorldTime.java rename to src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java index 50a10f7..19fbcd0 100644 --- a/src/main/java/net/thauvin/erik/mobibot/WorldTime.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java @@ -29,7 +29,10 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.thauvin.erik.mobibot; +package net.thauvin.erik.mobibot.modules; + +import net.thauvin.erik.mobibot.Mobibot; +import net.thauvin.erik.mobibot.Utils; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -38,13 +41,13 @@ import java.util.TimeZone; import java.util.TreeMap; /** - * The {@link Commands#TIME_CMD} command. + * The WorldTime module. * * @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a> * @created 2014-04-27 * @since 1.0 */ -class WorldTime +final public class WorldTime extends AbstractModule { /** * The beats (Internet Time) keyword. @@ -52,12 +55,17 @@ class WorldTime private static final String BEATS_KEYWORD = ".beats"; /** - * The countries supported by the {@link net.thauvin.erik.mobibot.Commands#TIME_CMD time} command. + * The supported countries. */ private static final Map<String, String> COUNTRIES_MAP = new TreeMap<>(); /** - * The date/time format for the {@link net.thauvin.erik.mobibot.Commands#TIME_CMD time} command. + * 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 '"); @@ -67,6 +75,8 @@ class WorldTime */ public WorldTime() { + commands.add(TIME_CMD); + // Initialize the countries map COUNTRIES_MAP.put("AU", "Australia/Sydney"); COUNTRIES_MAP.put("BE", "Europe/Brussels"); @@ -140,12 +150,13 @@ class WorldTime /** * Responds with the current time in the specified timezone/country. * - * @param bot The bot instance. - * @param sender The nick of the person who sent the message. - * @param args The time command arguments. - * @param isPrivate Set to true is the response should be send as a private message. + * @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 final void timeResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) + @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()))); @@ -167,7 +178,7 @@ class WorldTime else { isInvalidTz = true; - response = "The supported time zones/countries are: " + COUNTRIES_MAP.keySet().toString(); + response = "The supported time zones are: " + COUNTRIES_MAP.keySet().toString(); } if (isPrivate) @@ -186,4 +197,20 @@ class WorldTime } } } + + @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)); + } + + @Override + public boolean isPrivateMsgEnabled() + { + return true; + } } \ No newline at end of file diff --git a/version.properties b/version.properties index c4f5d54..5d34ed4 100644 --- a/version.properties +++ b/version.properties @@ -3,6 +3,6 @@ version.project=mobibot version.major=0 version.minor=6 -version.patch=1 +version.patch=5 version.prerelease=beta -version.buildmeta=008 +version.buildmeta=001