/** * Copyright (C) 2017-2021 Christian Pierre MOMON * Copyright (C) 2011-2013,2017 Nicolas Vinot * * This file is part of (April) Hebdobot. * * Hebdobot is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Hebdobot is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Hebdobot. If not, see */ package org.april.hebdobot.bot; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.time.LocalDate; import java.time.LocalTime; import org.apache.commons.lang3.StringUtils; import org.april.hebdobot.HebdobotException; import org.april.hebdobot.bot.hooks.AnnivHook; import org.april.hebdobot.bot.hooks.BadCommandHook; import org.april.hebdobot.bot.hooks.CancelPreviousInputHook; import org.april.hebdobot.bot.hooks.ChronoHook; import org.april.hebdobot.bot.hooks.CollectiveSubjectHook; import org.april.hebdobot.bot.hooks.CommentHook; import org.april.hebdobot.bot.hooks.CurrentHook; import org.april.hebdobot.bot.hooks.DateHook; import org.april.hebdobot.bot.hooks.DefaultHook; import org.april.hebdobot.bot.hooks.FinishReviewHook; import org.april.hebdobot.bot.hooks.HelloHook; import org.april.hebdobot.bot.hooks.HelpHook; import org.april.hebdobot.bot.hooks.Hooker; import org.april.hebdobot.bot.hooks.IndividualSubjectHook; import org.april.hebdobot.bot.hooks.InputReviewHook; import org.april.hebdobot.bot.hooks.LicenseHook; import org.april.hebdobot.bot.hooks.ListenAlexandrieHook; import org.april.hebdobot.bot.hooks.MissingHook; import org.april.hebdobot.bot.hooks.RecordHook; import org.april.hebdobot.bot.hooks.StartReviewHook; import org.april.hebdobot.bot.hooks.StatsHook; import org.april.hebdobot.bot.hooks.StatusHook; import org.april.hebdobot.bot.hooks.StopReviewHook; import org.april.hebdobot.bot.hooks.ThanksHook; import org.april.hebdobot.bot.hooks.VersionHook; import org.april.hebdobot.bot.review.Message; import org.april.hebdobot.bot.review.Review; import org.april.hebdobot.cron.CronManager; import org.april.hebdobot.cron.CronSettings; import org.april.hebdobot.identica.IdenticaSettings; import org.april.hebdobot.privatebin.PrivatebinSettings; import org.april.hebdobot.twitter.TwitterClient; import org.april.hebdobot.twitter.TwitterSettings; import org.april.hebdobot.util.Chrono; import org.jibble.pircbot.IrcException; import org.jibble.pircbot.NickAlreadyInUseException; import org.jibble.pircbot.PircBot; import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.devinsy.strings.StringList; import twitter4j.TwitterException; /** * The Class Hebdobot. */ public class Hebdobot extends PircBot { private static final Logger logger = LoggerFactory.getLogger(Hebdobot.class); private File homeDirectory; private String host; private int port; private String channel; private String identifyNick; private String identifyPassword; private File reviewDirectory; private String reviewFileSuffix; private LocalTime reviewWaitTime; private Review review; private Chrono chrono; private IdenticaSettings identicaSettings; private PrivatebinSettings privatebinSettings; private TwitterSettings twitterSettings; private CronSettings cronSettings; private UserAliases aliases; private CronManager cronManager; private Hooker hooker; /** * Instantiates a new hebdobot. * * @param host * the host * @param port * the port * @param nickname * the nickname * @param channel * the channel * @param homeDirectory * the home directory * @param reviewDirectory * the review directory * @param identifyNick * the identify nick * @param identifyPassword * the identify password */ public Hebdobot(final String host, final int port, final String nickname, final String channel, final File homeDirectory, final File reviewDirectory, final String identifyNick, final String identifyPassword) { this.homeDirectory = homeDirectory; this.host = host; this.port = port; this.channel = channel; this.setName(nickname); this.identifyNick = identifyNick; this.identifyPassword = identifyPassword; this.reviewDirectory = reviewDirectory; this.reviewFileSuffix = null; this.reviewWaitTime = null; this.review = null; this.chrono = new Chrono(); this.identicaSettings = new IdenticaSettings(); this.privatebinSettings = new PrivatebinSettings(); this.twitterSettings = new TwitterSettings(); this.cronSettings = new CronSettings(); this.aliases = new UserAliases(); this.cronManager = null; // this.hooker = new Hooker(); this.hooker.add(new ListenAlexandrieHook()); this.hooker.add(new CancelPreviousInputHook()); this.hooker.add(new ChronoHook()); this.hooker.add(new CollectiveSubjectHook()); this.hooker.add(new CommentHook()); this.hooker.add(new CurrentHook()); this.hooker.add(new FinishReviewHook()); this.hooker.add(new HelpHook()); this.hooker.add(new IndividualSubjectHook()); this.hooker.add(new MissingHook()); this.hooker.add(new RecordHook()); this.hooker.add(new StartReviewHook()); this.hooker.add(new StopReviewHook()); this.hooker.add(new StatsHook()); this.hooker.add(new StatusHook()); this.hooker.add(new AnnivHook()); this.hooker.add(new DateHook()); this.hooker.add(new HelloHook()); this.hooker.add(new LicenseHook()); this.hooker.add(new ThanksHook()); this.hooker.add(new VersionHook()); this.hooker.add(new BadCommandHook()); this.hooker.add(new InputReviewHook()); this.hooker.add(new DefaultHook()); } /** * Check anniversary. */ public void checkReviewAnniversary() { LocalDate now = LocalDate.now(); LocalDate creation = LocalDate.of(2010, 04, 30); LocalDate anniv = LocalDate.of(now.getYear(), creation.getMonth(), creation.getDayOfMonth()); logger.debug("now ={}", now.toString()); logger.debug("creation={}", creation.toString()); logger.debug("anniv ={}", anniv.toString()); if ((!now.isBefore(anniv)) && (now.isBefore(anniv.plusDays(7)))) { logger.info("Review anniversary detected."); int year = anniv.getYear() - creation.getYear(); sendMessage("% \\o/ Joyeux " + year + "e anniversaire la revue hebdo \\o/"); } } /** * Close. */ public void close() { this.disconnect(); this.dispose(); } /** * End review. */ public void endReview() { this.review.endReview(); this.chrono.reset(); } /** * Gets the aliases. * * @return the aliases */ public UserAliases getAliases() { return this.aliases; } public Chrono getChrono() { return this.chrono; } public CronManager getCronManager() { return this.cronManager; } /** * Gets the cron settings. * * @return the cron settings */ public CronSettings getCronSettings() { return this.cronSettings; } /** * Gets the help. * * @param source * the source * @return the help * @throws HebdobotException * the hebdobot exception */ public StringList getHelp(final String source) throws HebdobotException { StringList result; if (source == null) { result = null; } else { result = this.hooker.attemptHelp(source); } // return result; } /** * Gets the home directory. * * @return the home directory */ public File getHomeDirectory() { return this.homeDirectory; } /** * Gets the identica settings. * * @return the identica settings */ public IdenticaSettings getIdenticaSettings() { return this.identicaSettings; } /** * Gets the privatebin settings. * * @return the privatebin settings */ public PrivatebinSettings getPrivatebinSettings() { return this.privatebinSettings; } public Review getReview() { return this.review; } public File getReviewDirectory() { return this.reviewDirectory; } public String getReviewFileSuffix() { return this.reviewFileSuffix; } public LocalTime getReviewWaitTime() { return this.reviewWaitTime; } /** * Gets the twitter settings. * * @return the twitter settings */ public TwitterSettings getTwitterSettings() { return this.twitterSettings; } /** * Notify irc. * * @param message * the message */ public void notifyIrc(final String message) { sendMessage(message); } /** * Notify twitter. * * @param message * the message */ public void notifyTwitter(final String message) { notifyTwitter(message, null); } /** * Notify twitter. * * @param message * the message * @param imageFile * the image file */ public void notifyTwitter(final String message, final File imageFile) { if ((this.twitterSettings.isValid()) && (StringUtils.isNotBlank(message))) { try { TwitterClient twitter = new TwitterClient(this.twitterSettings.getConsumerKey(), this.twitterSettings.getConsumerSecret(), this.twitterSettings.getAccessToken(), this.twitterSettings.getAccessTokenSecret()); twitter.tweet(message, imageFile); } catch (TwitterException exception) { logger.error("Error in tweet", exception); sendMessage("(pour information, la notification par Tweet a échoué : " + exception.getErrorMessage() + ")"); } } } /* (non-Javadoc) * @see org.jibble.pircbot.PircBot#onMessage(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ @Override protected void onMessage(final String channel, final String sender, final String login, final String hostname, final String message) { logger.debug("Message received - channel : {}, sender : {}, message : {}", channel, sender, message); if (channel.equalsIgnoreCase(this.channel)) { String text = message.trim(); if (this.review != null) { this.review.addRaw(new Message(sender, text)); } text = text.replaceAll("^" + getName().replace("[", "\\[").replaceAll("]", "\\]") + "[,:]\\s*", "!"); try { this.hooker.attemptProcess(this, channel, sender, login, hostname, text); } catch (Exception exception) { logger.error("Error managing post.", exception); sendMessage("/me a choppé un bug : ", exception.getMessage()); } } } /* (non-Javadoc) * @see org.jibble.pircbot.PircBot#onPrivateMessage(java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ @Override protected void onPrivateMessage(final String sender, final String login, final String hostname, final String message) { logger.debug("Private message received - sender : {}, message : {}", sender, message); String text = message.trim(); if (text.startsWith("!")) { logger.info("!??? caught."); // Command unknown. sendMessage(sender, "vos commandes dans le salon public"); } else { // Nothing to say. } } /** * Run. * * @throws HebdobotException * the hebdobot exception */ public void run() throws HebdobotException { // try { logger.info("Cron initializing."); { this.cronManager = new CronManager(this, this.cronSettings); this.cronManager.start(); } logger.info("Cron initialized."); } catch (SchedulerException | ParseException exception) { throw new HebdobotException("Error in cron settings.", exception); } // Manage "Caused by: java.net.UnknownHostException: irc.freenode.org". boolean ended = false; while (!ended) { try { logger.info("Bot connection."); this.connect(this.host, this.port); logger.info("Bot connected."); ended = true; } catch (NickAlreadyInUseException exception) { throw new HebdobotException(exception); } catch (IOException exception) { logger.error("IOException during connection ", exception); try { Thread.sleep(200000); } catch (InterruptedException subException) { logger.error("Exception during sleep ", subException); } } catch (IrcException exception) { throw new HebdobotException(exception); } } // if (this.identifyPassword == null) { logger.info("Skipped identify."); } else { logger.info("Apply identify."); sendMessage("NickServ", "identify " + this.identifyNick + " " + this.identifyPassword); logger.info("Applied identify."); } logger.info("Bot joining channel ({}).", this.channel); this.joinChannel(this.channel); logger.info("Bot ready."); } /** * Send chrono message. */ public void sendChronoMessage() { if (this.review == null) { sendMessage("% durée du point : pas de revue en cours."); } else if (this.review.isEmpty()) { sendMessage("% durée du point : pas de point en cours."); } else { String topicTitle = this.review.getCurrentTopic().getTitle(); String chronoValue = this.chrono.toString(); sendMessage(String.format("%% durée du point %s : %s", topicTitle, chronoValue)); } } /** * Send message. * * @param message * the message */ public void sendMessage(final String message) { logger.debug("Send message : {}", message); this.sendMessage(this.channel, message); if (this.review != null) { this.review.addRaw(new Message("Hebdobot", message)); } } /** * Sets the home directory. * * @param homeDirectory * the new home directory */ public void setHomeDirectory(final File homeDirectory) { this.homeDirectory = homeDirectory; } public void setReview(final Review review) { this.review = review; } public void setReviewDirectory(final File reviewDirectory) { this.reviewDirectory = reviewDirectory; } public void setReviewFileSuffix(final String reviewFileSuffix) { this.reviewFileSuffix = reviewFileSuffix; } public void setReviewWaitTime(final LocalTime reviewWaitTime) { this.reviewWaitTime = reviewWaitTime; } /** * Stop review. */ public void stopReview() { setReview(null); this.chrono.reset(); } }