/*
* Copyright 2002-2005 Uwyn bvba/sprl <info[remove] at uwyn dot com>
* Distributed under the terms of the GNU Lesser General Public
* License, v2.1 or later
*
* $Id: Log.java 1702 2005-03-26 21:54:38Z gbevin $
*/
package com.uwyn.drone.modules;
import com.uwyn.drone.DroneConfig;
import com.uwyn.drone.core.AbstractModule;
import com.uwyn.drone.core.Bot;
import com.uwyn.drone.core.Channel;
import com.uwyn.drone.core.exceptions.CoreException;
import com.uwyn.drone.modules.exceptions.LogManagerException;
import com.uwyn.drone.modules.logmanagement.DatabaseLogs;
import com.uwyn.drone.modules.logmanagement.DatabaseLogsFactory;
import com.uwyn.drone.modules.logmanagement.LogResultProcessor;
import com.uwyn.drone.modules.logmanagement.exceptions.InvalidSearchSyntaxException;
import com.uwyn.drone.protocol.AttributeCode;
import com.uwyn.drone.protocol.ServerMessage;
import com.uwyn.drone.protocol.commands.Privmsg;
import com.uwyn.drone.tools.SearchTool;
import com.uwyn.rife.config.Config;
import com.uwyn.rife.tools.ExceptionUtils;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Log extends AbstractModule
{
private static final int MAX_RESULTS = Config.getRepInstance().getInt("MAX_SEARCH_RESULTS", 20);
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("EEE dd MMM yyyy HH:mm '"+DroneConfig.getTimezone()+"'");
private static final String[] MESSAGE_COMMANDS = new String[] {"logsearch"};
private static final Pattern SEARCH_PATTERN = Pattern.compile("^\\s*(#\\w+)\\s+(.+)\\s*$");
private static final String SEARCH_SYNTAX = "[query];[nick=name];[begin=[[yyyy/]mm/dd] [hh:mm]];[end=[[yyyy/]mm/dd] [hh:mm]];[#=count]";
private static final HashMap HELPMAP = new HashMap();
private static final String IRC_ACTION = "\u0001ACTION";
static
{
HELPMAP.put(null,
AttributeCode.BOLD+"Log"+AttributeCode.BOLD+" stores all the conversions on a channel."+AttributeCode.ENDLINE+
"It can be used to search in detail what was said by whom"+AttributeCode.ENDLINE+
"at which moment."+AttributeCode.ENDLINE+
"For more information on a specific command, type "+AttributeCode.ENDLINE+
AttributeCode.BOLD+"/msg $botnick help $modulename <command>"+AttributeCode.BOLD+"."+AttributeCode.ENDLINE+
" "+AttributeCode.ENDLINE+
AttributeCode.BOLD+"Privmsg commands"+AttributeCode.BOLD+""+AttributeCode.ENDLINE+
" LOGSEARCH searches the log of a channel"+AttributeCode.ENDLINE);
HELPMAP.put("logsearch",
"Syntax: "+AttributeCode.BOLD+"LOGSEARCH <#channel> <search>"+AttributeCode.BOLD+""+AttributeCode.ENDLINE+
" "+AttributeCode.ENDLINE+
"Queries the stored logs of the public conversations in a"+AttributeCode.ENDLINE+
"channel."+AttributeCode.ENDLINE+
" "+AttributeCode.ENDLINE+
"The format of the search parameter is as follows: "+AttributeCode.ENDLINE+
AttributeCode.BOLD+"[query];[nick=name];[begin=date];[end=date];[#=count]"+AttributeCode.BOLD+AttributeCode.ENDLINE+
"where at least one part should be present, below is"+AttributeCode.ENDLINE+
"a detailed explanation of each query part."+AttributeCode.ENDLINE+
" "+AttributeCode.BOLD+"query"+AttributeCode.BOLD+" is a string with '%' as wildcard"+AttributeCode.ENDLINE+
" "+AttributeCode.BOLD+"name"+AttributeCode.BOLD+" is the nick name of someone who spoke"+AttributeCode.ENDLINE+
" "+AttributeCode.BOLD+"date"+AttributeCode.BOLD+" with the format '[[yyyy/]mm/dd] [hh:mm]'"+AttributeCode.ENDLINE+
" "+AttributeCode.BOLD+"count"+AttributeCode.BOLD+" limits the results"+AttributeCode.ENDLINE+
"In any case, "+MAX_RESULTS+" results are returned maximum"+AttributeCode.ENDLINE);
}
public String getName()
{
return "LOG";
}
public String getDescription()
{
return "Logs all the conversations on a channel.";
}
public Map getHelpMap()
{
return HELPMAP;
}
public String[] getMessageCommands()
{
return MESSAGE_COMMANDS;
}
public boolean processesChannelMessages()
{
return true;
}
public void messageCommand(Bot bot, String nick, String command, String arguments, ServerMessage fullMessage)
throws CoreException
{
DatabaseLogs database_log = DatabaseLogsFactory.get();
try
{
if (command.equals("logsearch"))
{
if (null == arguments ||
0 == arguments.length())
{
bot.send(new Privmsg(nick, "You need to provide a search argument."));
return;
}
Matcher logsearch_matcher = SEARCH_PATTERN.matcher(arguments);
if (!logsearch_matcher.matches() ||
logsearch_matcher.groupCount() != 2)
{
bot.send(new Privmsg(nick, "Invalid syntax '"+command+" "+arguments+"'"));
return;
}
// obtain the requested channel
String channel_name = logsearch_matcher.group(1);
String search = logsearch_matcher.group(2);
Channel channel = bot.getServer().getChannel(channel_name);
if (null == channel)
{
bot.send(new Privmsg(nick, "Unknown channel '"+channel_name+"'"));
return;
}
SearchResults search_results = new SearchResults(bot, nick);
try
{
if (!database_log.searchLog(search_results, bot, channel, search))
{
bot.send(new Privmsg(nick, "No results for '"+search+"' could be found in channel '"+channel_name+"'."));
}
}
catch (InvalidSearchSyntaxException e)
{
bot.send(new Privmsg(nick, "The search syntax of '"+search+"' is not valid, it should be like this :"));
bot.send(new Privmsg(nick, SEARCH_SYNTAX));
}
}
}
catch (LogManagerException e)
{
Logger.getLogger("com.uwyn.drone.modules").severe(ExceptionUtils.getExceptionStackTrace(e));
}
}
public void channelMessage(Bot bot, Channel channel, String nick, ServerMessage fullMessage)
{
Date moment = new Date();
DatabaseLogs database_log = DatabaseLogsFactory.get();
try
{
database_log.addLog(moment, bot, channel, fullMessage);
}
catch (LogManagerException e)
{
Logger.getLogger("com.uwyn.drone.modules").severe(ExceptionUtils.getExceptionStackTrace(e));
}
SearchTool search_tool = new SearchTool();
search_tool.indexServerMessage(moment, bot, channel, ServerMessage.parse(fullMessage.getRaw()));
}
private class SearchResults extends LogResultProcessor
{
private Bot mBot = null;
private String mNick = null;
public SearchResults(Bot bot, String nick)
{
assert bot != null;
assert nick != null;
mBot = bot;
mNick = nick;
}
public boolean gotMessage(Timestamp moment, ServerMessage serverMessage)
{
try
{
if (getCount() <= MAX_RESULTS)
{
StringBuffer formatted_result = new StringBuffer();
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone(DroneConfig.getTimezone()));
formatted_result.append("[");
formatted_result.append(DATE_FORMAT.format(moment));
formatted_result.append("] (");
formatted_result.append(serverMessage.getPrefix().getNickName());
formatted_result.append(") ");
// translate the \u0001ACTION command which corresponds to
// /me so that the user's nickname is used instead
if (serverMessage.getPrefix() != null &&
serverMessage.getTrailing().startsWith(IRC_ACTION))
{
formatted_result.append(serverMessage.getPrefix().getNickName());
formatted_result.append(serverMessage.getTrailing().substring(IRC_ACTION.length()));
}
else
{
formatted_result.append(serverMessage.getTrailing());
}
mBot.send(new Privmsg(mNick, formatted_result.toString()));
return true;
}
else
{
mBot.send(new Privmsg(mNick, "!!! more than "+MAX_RESULTS+" matches, refine your search."));
}
}
catch (CoreException e)
{
Logger.getLogger("com.uwyn.drone.modules").severe(ExceptionUtils.getExceptionStackTrace(e));
}
return false;
}
}
}