Package org.exist.irc

Source Code of org.exist.irc.XBot$FunctionLookup

package org.exist.irc;

import org.exist.security.Permission;
import org.exist.security.PermissionFactory;
import org.exist.xmldb.UserManagementService;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.jibble.pircbot.PircBot;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.CollectionManagementService;
import org.xmldb.api.modules.XMLResource;
import org.xmldb.api.modules.XPathQueryService;
import org.xmldb.api.modules.XUpdateQueryService;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Implements a simple IRC drone, which logs IRC events to a collection in an eXist database.
* One log file is created every day. Messages are appended using XUpdate.
*
* @author wolf
*
*/
public class XBot extends PircBot {

  private final static String VERSION = "0.2";
 
  private final static String URI = "xmldb:exist://localhost:8080/exist/xmlrpc/db";
 
  private final static String COLLECTION = "ircbot";
   
    private final static Properties DEFAULTS = new Properties();
    static {
        DEFAULTS.setProperty("xmldb.user", "guest");
        DEFAULTS.setProperty("xmldb.password", "guest");
        DEFAULTS.setProperty("xmldb.uri", URI);
        DEFAULTS.setProperty("xmldb.collection", COLLECTION);
        DEFAULTS.setProperty("irc.server", "irc.freenode.net");
        DEFAULTS.setProperty("irc.channel", "#existdb");
        DEFAULTS.setProperty("irc.nickname", "XDrone");
        DEFAULTS.setProperty("irc.password", "");
    }
 
  private final static String XUPDATE_START =
    "<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">\n" +
    "  <xu:variable name=\"now\" select=\"current-time()\"/>\n";
 
  private final static String URL_REGEX =
    "((http|ftp)s{0,1}://[\\-\\.\\,/\\%\\~\\=\\@\\_\\&\\:\\?\\#a-zA-Z0-9]*[/\\=\\#a-zA-Z0-9])";

    private final static int MAX_CONNECT_ATTEMPTS = 50;
   
    // these commands may be passed in a private message to the bot
  private final Command[] commands = {
    new HelpCommand(),
    new QuitCommand(),
    new FunctionLookup()
  };

    private Properties properties = new Properties(DEFAULTS);
   
  // the base collection
  private Collection collection;

  private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
 
  private Pattern urlPattern;
  private Matcher matcher = null;

    private boolean disconnect = false;

    public XBot() throws IrcException {
    super();

        File f = new File("xbot.properties");
        if (f.canRead()) {
            System.out.println("Reading properties file: " + f.getAbsolutePath());
            try {
              FileInputStream stream = new FileInputStream(f);
              try {
                properties.load(stream);
              } finally {
                stream.close();
              }
            } catch (IOException e) {
                System.err.println("Failed to load properties: " + e.getMessage());
            }
        }
    this.setName(properties.getProperty("irc.nickname"));
    this.setVerbose(true);
    setupDb();
   
    urlPattern = Pattern.compile(URL_REGEX);
  }

  /**
   * Connect to the server.
   *
   * @throws IrcException
   * @throws IOException
   */
  public void connect() throws IrcException, IOException {
    log("Connecting to " + properties.getProperty("irc.server"));
    attemptConnect();
  }

    protected void onDisconnect() {
        if (disconnect)
            return;
        log("We were disconnected from the server. Trying to reconnect ...");
        try {
            attemptConnect();
        } catch (IrcException e) {
            log("Reconnect failed. Giving up.");
        }
    }

    protected void attemptConnect() throws IrcException {
        int attempts = 0;
        boolean connected = false;
    while (!connected) {
            ++attempts;
            try {
        connect(properties.getProperty("irc.server"));
        connected = true;
      } catch (NickAlreadyInUseException e) {
        this.setName(this.getName() + '_');
      } catch (IOException e) {
                log("Failed to connect. Reason: " + e.getMessage());
            }
            if (attempts == MAX_CONNECT_ATTEMPTS) {
                log("Reached max connection attempts. Giving up.");
                return;
            }
        }
    log("Join channel: " + properties.getProperty("irc.channel"));
    joinChannel(properties.getProperty("irc.channel"));
    sendMessage("NickServ", "IDENTIFY " + properties.getProperty("irc.password"));
    }

    /**
   * Callback method called after a user has joined the channel.
   */
  protected void onJoin(String channel, String sender, String login, String hostname) {
    try {
      String xupdate =
        "<join nick=\"" + sender + "\" login=\"" + login + "\" host=\"" + hostname + "\">" +
        "<xu:attribute name=\"time\"><xu:value-of select=\"$now\"/></xu:attribute>" +
        "</join>";
      doUpdate(xupdate);
    } catch (XMLDBException e) {
      log("An error occurred: " + e.getMessage());
    }
  }

   
    /**
   * Callback method: a user has parted.
   */
  protected void onPart(String channel, String sender, String login, String hostname) {
    try {
      String xupdate =
        "<part nick=\"" + sender + "\" login=\"" + login + "\" host=\"" + hostname + "\">" +
        "<xu:attribute name=\"time\"><xu:value-of select=\"$now\"/></xu:attribute>" +
        "</part>";
      doUpdate(xupdate);
    } catch (XMLDBException e) {
      log("An error occurred: " + e.getMessage());
    }
  }
 
  /**
   * Callback method: a user disconnected from the server.
   */
  protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
    try {
      String xupdate =
        "<part nick=\"" + sourceNick + "\" login=\"" + sourceLogin + "\" host=\"" + sourceHostname +
        "\" reason=\"" + reason + "\">" +
        "<xu:attribute name=\"time\"><xu:value-of select=\"$now\"/></xu:attribute>" +
        "</part>";
      doUpdate(xupdate);
    } catch (XMLDBException e) {
      log("An error occurred: " + e.getMessage());
    }
  }
 
  /**
   * Callback method: a message was sent.
   */
  protected void onMessage(String channel, String sender, String login, String hostname, String message) {
    try {
      String xupdate =
        "<message nick=\"" + sender + "\">" +
        "<xu:attribute name=\"time\"><xu:value-of select=\"$now\"/></xu:attribute>" +
        "<![CDATA[" + preprocessMessage(message) + "]]>" +
        "</message>\n";
      doUpdate(xupdate);
    } catch (XMLDBException e) {
      log("An error occurred: " + e.getMessage());
    }
  }
 
  /**
   * Callback method: a private message has been sent to the bot. Check if it contains a known
   * command and execute it.
   */
  protected void onPrivateMessage(String sender, String login, String hostname, String message) {
    String args[] = message.split("\\s+");
    log("Arguments: " + args.length + "; command: " + args[0]);
    boolean recognized = false;
    for (int i = 0; i < commands.length; i++) {
      if (args[0].equalsIgnoreCase(commands[i].name)) {
        // executing command
        try {
          commands[i].execute(sender, args);
        } catch (IrcException e) {
          log("An exception occurred while executing command '" + message + "': " + e.getMessage());
        }
        recognized = true;
      }
    }
    if (!recognized) {
      sendMessage(sender, "Don't know what to respond. Send me a message 'HELP' to see a list of " +
          "commands I understand.");
    }
  }
 
  /**
   * Helper method to xupdate the log file.
   *
   * @param content
   * @throws XMLDBException
   */
  private void doUpdate(String content) throws XMLDBException {
    String xupdate =
      XUPDATE_START +
      "  <xu:append select=\"doc('" + getLogPath() + "')/xlog\">\n" +
      content +
      "  </xu:append>\n" +
      "</xu:modifications>";
        log("XUpdate:\n" + xupdate);
    XUpdateQueryService service = (XUpdateQueryService)
    collection.getService("XUpdateQueryService", "1.0");
    service.update(xupdate);
  }
 
  /**
   * Parse a message. Tries to detect URLs in the message and transforms them
   * into an HTML link.
   *
   * @param message
   * @return
   */
  private String preprocessMessage(String message) {
    if (matcher == null)
      matcher = urlPattern.matcher(message);
    else
      matcher.reset(message);
    return matcher.replaceAll("]]><a href=\"$1\">$1</a><![CDATA[");
  }
 
  /**
   * Initialize the database.
   *
   * @throws IrcException
   */
  private void setupDb() throws IrcException {
    try {
      Class<?> cl = Class.forName("org.exist.xmldb.DatabaseImpl");
      Database database = (Database) cl.newInstance();
      database.setProperty("create-database", "true");
      DatabaseManager.registerDatabase(database);
           
      collection = DatabaseManager.getCollection(properties.getProperty("xmldb.uri") + '/' + properties.getProperty("xmldb.collection"),
                    properties.getProperty("xmldb.user"), properties.getProperty("xmldb.password"));
           
      if (collection == null) {
        Collection root = DatabaseManager.getCollection(properties.getProperty("xmldb.uri"),
                        properties.getProperty("xmldb.user"), properties.getProperty("xmldb.password"));
        CollectionManagementService mgr = (CollectionManagementService)
          root.getService("CollectionManagementService", "1.0");
                UserManagementService umgr = (UserManagementService)
                    root.getService("UserManagementService", "1.0");
        collection = mgr.createCollection(COLLECTION);
                Permission perms = umgr.getPermissions(collection);
                perms.setMode(0744);
                umgr.setPermissions(collection, perms);
      }
    } catch (Exception e) {
      throw new IrcException("Failed to initialize the database: " + e.getMessage());
    }
  }
 
  /**
   * Returns the full database path to the current log document.
   *
   * @return
   * @throws XMLDBException
   */
  private String getLogPath() throws XMLDBException {
    return "/db/" + COLLECTION + '/' + getCurrentLog();
  }
 
  /**
   * Returns the name of the current log document. If no document
   * has been created for today yet, create a new, empty one.
   *
   * @return
   * @throws XMLDBException
   */
  private String getCurrentLog() throws XMLDBException {
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    String date = dateFormat.format(cal.getTime());
    String resourceName = date + ".xlog";
    XMLResource res = (XMLResource) collection.getResource(resourceName);
    if (res == null) {
      // create a new log for today's date
      String xml =
        "<xlog server=\"" + properties.getProperty("irc.server") + "\" channel=\"" + properties.getProperty("irc.channel") + "\" date=\"" + date + "\"/>";
      res = (XMLResource) collection.createResource(resourceName, "XMLResource");
      res.setContent(xml);
      collection.storeResource(res);
            UserManagementService umgr = (UserManagementService)
                collection.getService("UserManagementService", "1.0");
            umgr.setPermissions(res,
                PermissionFactory.getPermission(
                    properties.getProperty("xmldb.user"),
                    properties.getProperty("xmldb.password"),
                    0744));
    }
    return resourceName;
  }
 
  /**
   * Base class for all commands that can be send in a private message.
   *
   * @author wolf
   *
   */
  private abstract class Command {
    String name;
    String description;
   
    public Command(String name, String description) {
      this.name = name;
      this.description = description;
    }
   
    public abstract void execute(String target, String[] args) throws IrcException;
  }
 
  private class HelpCommand extends Command {
   
    public HelpCommand() {
      super("help", "List available commands.");
    }
   
    public void execute(String target, String args[]) throws IrcException {
      sendMessage(target, "XBot " + VERSION + " - Available commands:");
      for (int i = 0; i < commands.length; i++) {
        sendMessage(target, commands[i].name + "\t\t" + commands[i].description);
      }
    }
  }
 
  private class QuitCommand extends Command {
   
    public QuitCommand() {
      super("quit", "Disconnect from the server.");
    }
   
    public void execute(String target, String[] args) throws IrcException {
      if (args.length < 2) {
        sendMessage(target, "Usage: QUIT password");
        return;
      }
      if (!args[1].equals(properties.getProperty("irc.password"))) {
        sendMessage(target, "Wrong password specified!");
        return;
      }
            disconnect = true;
            quitServer("Even a bot needs to rest sometimes...");
      System.exit(0);
    }
  }
 
  private class FunctionLookup extends Command {
   
    public FunctionLookup() {
      super("lookup", "Lookup a function definition");
    }
   
    public void execute(String target, String[] args) throws IrcException {
      try {
        XPathQueryService service = (XPathQueryService)
          collection.getService("XPathQueryService", "1.0");
        ResourceSet result = service.query("util:describe-function('" + args[1] + "')");
        if (result.getSize() == 0) {
          sendMessage(target, "Function " + args[1] + " is unknown!");
          return;
        }
        Node node = ((XMLResource) result.getResource(0)).getContentAsDOM();
        if (node.getNodeType() == Node.DOCUMENT_NODE)
          node = ((Document)node).getDocumentElement();
        NodeList children = ((Element)node).getElementsByTagName("prototype");
        for (int i = 0; i < children.getLength(); i++) {
          Element elem = (Element) children.item(i);
          NodeList nl = elem.getChildNodes();
          for (int j = 0; j < nl.getLength(); j++) {
            node = nl.item(j);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
              if ("signature".equals(node.getLocalName())) {
                sendMessage(target, "[signature] " + getNodeValue(node));
              } else if ("description".equals(node.getLocalName())) {
                sendMessage(target, "[description] " + getNodeValue(node));
              }
            }
          }
        }
      } catch (XMLDBException e) {
        sendMessage(target, "An exception occurred: " + e.getMessage());
      }
    }
   
    private String getNodeValue(Node node) {
      StringBuffer buf = new StringBuffer();
      node = node.getFirstChild();
      while (node != null) {
        buf.append(node.getNodeValue());
        node = node.getNextSibling();
      }
      return buf.toString();
    }
  }
 
  /**
   * @param args
   * @throws IrcException
   */
  public static void main(String[] args) throws Exception {
    XBot bot = new XBot();
    bot.connect();
  }
}
TOP

Related Classes of org.exist.irc.XBot$FunctionLookup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');