123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917 |
- /*
- * Copyright (c) 2006-2013 DMDirc Developers
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- package com.dmdirc.addons.logging;
-
- import com.dmdirc.util.io.ReverseFileReader;
- import com.dmdirc.Channel;
- import com.dmdirc.FrameContainer;
- import com.dmdirc.Query;
- import com.dmdirc.Server;
- import com.dmdirc.actions.CoreActionType;
- import com.dmdirc.interfaces.actions.ActionType;
- import com.dmdirc.config.ConfigManager;
- import com.dmdirc.config.Identity;
- import com.dmdirc.config.IdentityManager;
- import com.dmdirc.config.prefs.PluginPreferencesCategory;
- import com.dmdirc.config.prefs.PreferencesCategory;
- import com.dmdirc.config.prefs.PreferencesDialogModel;
- import com.dmdirc.config.prefs.PreferencesSetting;
- import com.dmdirc.config.prefs.PreferencesType;
- import com.dmdirc.interfaces.ActionController;
- import com.dmdirc.interfaces.ActionListener;
- import com.dmdirc.interfaces.ConfigChangeListener;
- import com.dmdirc.logger.ErrorLevel;
- import com.dmdirc.logger.Logger;
- import com.dmdirc.parser.interfaces.ChannelClientInfo;
- import com.dmdirc.parser.interfaces.ChannelInfo;
- import com.dmdirc.parser.interfaces.ClientInfo;
- import com.dmdirc.parser.interfaces.Parser;
- import com.dmdirc.plugins.BasePlugin;
- import com.dmdirc.plugins.PluginInfo;
- import com.dmdirc.ui.messages.Styliser;
- import com.dmdirc.util.io.StreamUtils;
-
- import java.awt.Color;
- import java.io.BufferedWriter;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.math.BigInteger;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Stack;
- import java.util.Timer;
- import java.util.TimerTask;
-
- /**
- * Adds logging facility to client.
- */
- public class LoggingPlugin extends BasePlugin implements ActionListener,
- ConfigChangeListener {
-
- /** Cached boolean settings. */
- private boolean networkfolders, filenamehash, addtime, stripcodes,
- channelmodeprefix, autobackbuffer, backbufferTimestamp, usedate;
- /** Cached string settings. */
- private String timestamp, usedateformat, logDirectory, colour;
- /** Cached int settings. */
- private int historyLines, backbufferLines;
- /** This plugin's plugin info. */
- private final PluginInfo pluginInfo;
- /** The action controller to use. */
- private final ActionController actionController;
- /** Global config. */
- private final ConfigManager config;
- /** Addon identity. */
- private final Identity identity;
- /** Parent Identity Manager. */
- private final IdentityManager identityManager;
-
- /** Timer used to close idle files. */
- protected Timer idleFileTimer;
-
- /** Map of open files. */
- protected final Map<String, OpenFile> openFiles
- = Collections.synchronizedMap(new HashMap<String, OpenFile>());
-
- /** Date format used for "File Opened At" log. */
- final DateFormat openedAtFormat = new SimpleDateFormat("EEEE MMMM dd, yyyy - HH:mm:ss");
-
- /**
- * Creates a new instance of this plugin.
- *
- * @param pluginInfo This plugin's plugin info
- * @param actionController The action controller to register listeners with
- * @param identityManager The Identity Manager that controls the current config
- */
- public LoggingPlugin(final PluginInfo pluginInfo,
- final ActionController actionController,
- final IdentityManager identityManager) {
- super();
- this.identityManager = identityManager;
-
- this.pluginInfo = pluginInfo;
- this.actionController = actionController;
- config = identityManager.getGlobalConfiguration();
- identity = identityManager.getGlobalAddonIdentity();
-
- registerCommand(new LoggingCommand(this), LoggingCommand.INFO);
- }
-
- /** {@inheritDoc} */
- @Override
- public void domainUpdated() {
- identity.setOption(getDomain(), "general.directory",
- identityManager.getConfigDir() + "logs" + System.getProperty("file.separator"));
- }
-
- /**
- * Called when the plugin is loaded.
- */
- @Override
- public void onLoad() {
- setCachedSettings();
-
- final File dir = new File(logDirectory);
- if (dir.exists()) {
- if (!dir.isDirectory()) {
- Logger.userError(ErrorLevel.LOW, "Unable to create logging dir (file exists instead)");
- }
- } else {
- if (!dir.mkdirs()) {
- Logger.userError(ErrorLevel.LOW, "Unable to create logging dir");
- }
- }
-
- config.addChangeListener(getDomain(), this);
-
- actionController.registerListener(this,
- CoreActionType.CHANNEL_OPENED,
- CoreActionType.CHANNEL_CLOSED,
- CoreActionType.CHANNEL_MESSAGE,
- CoreActionType.CHANNEL_SELF_MESSAGE,
- CoreActionType.CHANNEL_ACTION,
- CoreActionType.CHANNEL_SELF_ACTION,
- CoreActionType.CHANNEL_GOTTOPIC,
- CoreActionType.CHANNEL_TOPICCHANGE,
- CoreActionType.CHANNEL_JOIN,
- CoreActionType.CHANNEL_PART,
- CoreActionType.CHANNEL_QUIT,
- CoreActionType.CHANNEL_KICK,
- CoreActionType.CHANNEL_NICKCHANGE,
- CoreActionType.CHANNEL_MODECHANGE,
- CoreActionType.QUERY_OPENED,
- CoreActionType.QUERY_CLOSED,
- CoreActionType.QUERY_MESSAGE,
- CoreActionType.QUERY_SELF_MESSAGE,
- CoreActionType.QUERY_ACTION,
- CoreActionType.QUERY_SELF_ACTION);
-
- // Close idle files every hour.
- idleFileTimer = new Timer("LoggingPlugin Timer");
- idleFileTimer.schedule(new TimerTask() {
-
- /** {@inheritDoc} */
- @Override
- public void run() {
- timerTask();
- }
-
- }, 3600000);
- super.onLoad();
- }
-
- /**
- * What to do every hour when the timer fires.
- */
- protected void timerTask() {
- // Oldest time to allow
- final long oldestTime = System.currentTimeMillis() - 3480000;
-
- synchronized (openFiles) {
- final Collection<String> old = new ArrayList<String>(openFiles.size());
- for (Map.Entry<String, OpenFile> entry : openFiles.entrySet()) {
- if (entry.getValue().lastUsedTime < oldestTime) {
- StreamUtils.close(entry.getValue().writer);
- old.add(entry.getKey());
- }
- }
-
- openFiles.keySet().removeAll(old);
- }
- }
-
- /**
- * Called when this plugin is unloaded.
- */
- @Override
- public void onUnload() {
- if (idleFileTimer != null) {
- idleFileTimer.cancel();
- idleFileTimer.purge();
- }
-
- actionController.unregisterListener(this);
-
- synchronized (openFiles) {
- for (OpenFile file : openFiles.values()) {
- StreamUtils.close(file.writer);
- }
- openFiles.clear();
- }
-
- super.onUnload();
- }
-
- /** {@inheritDoc} */
- @Override
- public void showConfig(final PreferencesDialogModel manager) {
- final PreferencesCategory general = new PluginPreferencesCategory(
- pluginInfo, "Logging", "General configuration for Logging plugin.");
- final PreferencesCategory backbuffer = new PluginPreferencesCategory(
- pluginInfo, "Back Buffer", "Options related to the automatic backbuffer");
- final PreferencesCategory advanced = new PluginPreferencesCategory(
- pluginInfo, "Advanced", "Advanced configuration for Logging plugin. You shouldn't need to edit this unless you know what you are doing.");
-
- general.addSetting(new PreferencesSetting(PreferencesType.DIRECTORY,
- getDomain(), "general.directory", "Directory",
- "Directory for log files", manager.getConfigManager(),
- manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "general.networkfolders",
- "Separate logs by network",
- "Should the files be stored in a sub-dir with the networks name?",
- manager.getConfigManager(), manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "general.addtime", "Timestamp logs",
- "Should a timestamp be added to the log files?",
- manager.getConfigManager(), manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.TEXT,
- getDomain(), "general.timestamp", "Timestamp format",
- "The String to pass to 'SimpleDateFormat' to format the timestamp",
- manager.getConfigManager(), manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "general.stripcodes", "Strip Control Codes",
- "Remove known irc control codes from lines before saving?",
- manager.getConfigManager(), manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "general.channelmodeprefix",
- "Show channel mode prefix", "Show the @,+ etc next to nicknames",
- manager.getConfigManager(), manager.getIdentity()));
-
- backbuffer.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "backbuffer.autobackbuffer", "Automatically display",
- "Automatically display the backbuffer when a channel is joined",
- manager.getConfigManager(), manager.getIdentity()));
- backbuffer.addSetting(new PreferencesSetting(PreferencesType.COLOUR,
- getDomain(), "backbuffer.colour", "Colour to use for display",
- "Colour used when displaying the backbuffer",
- manager.getConfigManager(), manager.getIdentity()));
- backbuffer.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
- getDomain(), "backbuffer.lines", "Number of lines to show",
- "Number of lines used when displaying backbuffer",
- manager.getConfigManager(), manager.getIdentity()));
- backbuffer.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "backbuffer.timestamp", "Show Formatter-Timestamp",
- "Should the line be added to the frame with the timestamp from "
- + "the formatter aswell as the file contents",
- manager.getConfigManager(), manager.getIdentity()));
-
- advanced.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "advanced.filenamehash", "Add Filename hash",
- "Add the MD5 hash of the channel/client name to the filename. "
- + "(This is used to allow channels with similar names "
- + "(ie a _ not a -) to be logged separately)",
- manager.getConfigManager(), manager.getIdentity()));
-
- advanced.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- getDomain(), "advanced.usedate", "Use Date directories",
- "Should the log files be in separate directories based on the date?",
- manager.getConfigManager(), manager.getIdentity()));
- advanced.addSetting(new PreferencesSetting(PreferencesType.TEXT,
- getDomain(), "advanced.usedateformat", "Archive format",
- "The String to pass to 'SimpleDateFormat' to format the "
- + "directory name(s) for archiving",
- manager.getConfigManager(), manager.getIdentity()));
-
- general.addSubCategory(backbuffer.setInline());
- general.addSubCategory(advanced.setInline());
- manager.getCategory("Plugins").addSubCategory(general.setInlineAfter());
- }
-
- /**
- * Log a query-related event.
- *
- * @param type The type of the event to process
- * @param format Format of messages that are about to be sent. (May be null)
- * @param arguments The arguments for the event
- */
- protected void handleQueryEvent(final CoreActionType type, final StringBuffer format, final Object... arguments) {
- final Query query = (Query) arguments[0];
- if (query.getServer() == null) {
- Logger.appError(ErrorLevel.MEDIUM, "Query object has no server (" + type.toString() + ")", new Exception("Query object has no server (" + type.toString() + ")"));
- return;
- }
-
- final Parser parser = query.getServer().getParser();
- ClientInfo client;
-
- if (parser == null) {
- // Without a parser object, we might not be able to find the file to log this to.
- if (networkfolders) {
- // We *wont* be able to, so rather than logging to an incorrect file we just won't log.
- return;
- }
- client = null;
- } else {
- client = parser.getClient(query.getHost());
- }
-
- final String filename = getLogFile(client);
-
- switch (type) {
- case QUERY_OPENED:
- if (autobackbuffer) {
- showBackBuffer(query, filename);
- }
-
- appendLine(filename, "*** Query opened at: %s", openedAtFormat.format(new Date()));
- appendLine(filename, "*** Query with User: %s", query.getHost());
- appendLine(filename, "");
- break;
- case QUERY_CLOSED:
- appendLine(filename, "*** Query closed at: %s", openedAtFormat.format(new Date()));
- if (openFiles.containsKey(filename)) {
- StreamUtils.close(openFiles.get(filename).writer);
- openFiles.remove(filename);
- }
- break;
- case QUERY_MESSAGE:
- case QUERY_SELF_MESSAGE:
- case QUERY_ACTION:
- case QUERY_SELF_ACTION:
- final boolean isME = (type == CoreActionType.QUERY_SELF_MESSAGE || type == CoreActionType.QUERY_SELF_ACTION);
- final String overrideNick = isME ? getDisplayName(parser.getLocalClient()) : "";
-
- if (type == CoreActionType.QUERY_MESSAGE || type == CoreActionType.QUERY_SELF_MESSAGE) {
- appendLine(filename, "<%s> %s", getDisplayName(client, overrideNick), arguments[2]);
- } else {
- appendLine(filename, "* %s %s", getDisplayName(client, overrideNick), arguments[2]);
- }
- break;
- }
- }
-
- /**
- * Log a channel-related event.
- *
- * @param type The type of the event to process
- * @param format Format of messages that are about to be sent. (May be null)
- * @param arguments The arguments for the event
- */
- protected void handleChannelEvent(final CoreActionType type, final StringBuffer format, final Object... arguments) {
- final Channel chan = ((Channel) arguments[0]);
- final ChannelInfo channel = chan.getChannelInfo();
- final String filename = getLogFile(channel);
-
- final ChannelClientInfo channelClient = (arguments.length > 1 && arguments[1] instanceof ChannelClientInfo) ? (ChannelClientInfo) arguments[1] : null;
- final ClientInfo client = channelClient == null ? null : channelClient.getClient();
-
- final String message = (arguments.length > 2 && arguments[2] instanceof String) ? (String) arguments[2] : null;
-
- switch (type) {
- case CHANNEL_OPENED:
- if (autobackbuffer) {
- showBackBuffer(chan, filename);
- }
-
- appendLine(filename, "*** Channel opened at: %s", openedAtFormat.format(new Date()));
- appendLine(filename, "");
- break;
- case CHANNEL_CLOSED:
- appendLine(filename, "*** Channel closed at: %s", openedAtFormat.format(new Date()));
- if (openFiles.containsKey(filename)) {
- StreamUtils.close(openFiles.get(filename).writer);
- openFiles.remove(filename);
- }
- break;
- case CHANNEL_MESSAGE:
- case CHANNEL_SELF_MESSAGE:
- case CHANNEL_ACTION:
- case CHANNEL_SELF_ACTION:
- if (type == CoreActionType.CHANNEL_MESSAGE || type == CoreActionType.CHANNEL_SELF_MESSAGE) {
- appendLine(filename, "<%s> %s", getDisplayName(client), message);
- } else {
- appendLine(filename, "* %s %s", getDisplayName(client), message);
- }
- break;
- case CHANNEL_GOTTOPIC:
- // ActionManager.processEvent(CoreActionType.CHANNEL_GOTTOPIC, this);
- final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
- final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
-
- appendLine(filename, "*** Topic is: %s", channel.getTopic());
- appendLine(filename, "*** Set at: %s on %s by %s", timeFormat.format(1000 * channel.getTopicTime()), dateFormat.format(1000 * channel.getTopicTime()), channel.getTopicSetter());
- break;
- case CHANNEL_TOPICCHANGE:
- appendLine(filename, "*** %s Changed the topic to: %s", getDisplayName(channelClient), message);
- break;
- case CHANNEL_JOIN:
- appendLine(filename, "*** %s (%s) joined the channel", getDisplayName(channelClient), client.toString());
- break;
- case CHANNEL_PART:
- if (message.isEmpty()) {
- appendLine(filename, "*** %s (%s) left the channel", getDisplayName(channelClient), client.toString());
- } else {
- appendLine(filename, "*** %s (%s) left the channel (%s)", getDisplayName(channelClient), client.toString(), message);
- }
- break;
- case CHANNEL_QUIT:
- if (message.isEmpty()) {
- appendLine(filename, "*** %s (%s) Quit IRC", getDisplayName(channelClient), client.toString());
- } else {
- appendLine(filename, "*** %s (%s) Quit IRC (%s)", getDisplayName(channelClient), client.toString(), message);
- }
- break;
- case CHANNEL_KICK:
- final String kickReason = (String) arguments[3];
- final ChannelClientInfo kickedClient = (ChannelClientInfo) arguments[2];
-
- if (kickReason.isEmpty()) {
- appendLine(filename, "*** %s was kicked by %s", getDisplayName(kickedClient), getDisplayName(channelClient));
- } else {
- appendLine(filename, "*** %s was kicked by %s (%s)", getDisplayName(kickedClient), getDisplayName(channelClient), kickReason);
- }
- break;
- case CHANNEL_NICKCHANGE:
- appendLine(filename, "*** %s is now %s", getDisplayName(channelClient, message), getDisplayName(channelClient));
- break;
- case CHANNEL_MODECHANGE:
- if (channelClient.getClient().getNickname().isEmpty()) {
- appendLine(filename, "*** Channel modes are: %s", message);
- } else {
- appendLine(filename, "*** %s set modes: %s", getDisplayName(channelClient), message);
- }
- break;
- }
- }
-
- /**
- * Process an event of the specified type.
- *
- * @param type The type of the event to process
- * @param format Format of messages that are about to be sent. (May be null)
- * @param arguments The arguments for the event
- */
- @Override
- public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
- if (type instanceof CoreActionType) {
- final CoreActionType thisType = (CoreActionType) type;
-
- switch (thisType) {
- case CHANNEL_OPENED:
- case CHANNEL_CLOSED:
- case CHANNEL_MESSAGE:
- case CHANNEL_SELF_MESSAGE:
- case CHANNEL_ACTION:
- case CHANNEL_SELF_ACTION:
- case CHANNEL_GOTTOPIC:
- case CHANNEL_TOPICCHANGE:
- case CHANNEL_JOIN:
- case CHANNEL_PART:
- case CHANNEL_QUIT:
- case CHANNEL_KICK:
- case CHANNEL_NICKCHANGE:
- case CHANNEL_MODECHANGE:
- handleChannelEvent(thisType, format, arguments);
- break;
- case QUERY_OPENED:
- case QUERY_CLOSED:
- case QUERY_MESSAGE:
- case QUERY_SELF_MESSAGE:
- case QUERY_ACTION:
- case QUERY_SELF_ACTION:
- handleQueryEvent(thisType, format, arguments);
- break;
- default:
- break;
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void configChanged(final String domain, final String key) {
- setCachedSettings();
- }
-
- /**
- * Add a backbuffer to a frame.
- *
- * @param frame The frame to add the backbuffer lines to
- * @param filename File to get backbuffer from
- */
- protected void showBackBuffer(final FrameContainer frame, final String filename) {
- if (frame == null) {
- Logger.userError(ErrorLevel.LOW, "Given a null frame");
- return;
- }
-
- final File testFile = new File(filename);
- if (testFile.exists()) {
- try {
- final ReverseFileReader file = new ReverseFileReader(testFile);
- // Because the file includes a newline char at the end, an empty line
- // is returned by getLines. To counter this, we call getLines(1) and do
- // nothing with the output.
- file.getLines(1);
- final Stack<String> lines = file.getLines(backbufferLines);
- while (!lines.empty()) {
- frame.addLine(getColouredString(colour, lines.pop()), backbufferTimestamp);
- }
- file.close();
- frame.addLine(getColouredString(colour, "--- End of backbuffer\n"), backbufferTimestamp);
- } catch (FileNotFoundException e) {
- Logger.userError(ErrorLevel.LOW, "Unable to show backbuffer (Filename: " + filename + "): " + e.getMessage());
- } catch (IOException e) {
- Logger.userError(ErrorLevel.LOW, "Unable to show backbuffer (Filename: " + filename + "): " + e.getMessage());
- } catch (SecurityException e) {
- Logger.userError(ErrorLevel.LOW, "Unable to show backbuffer (Filename: " + filename + "): " + e.getMessage());
- }
- }
- }
-
- /**
- * Get a coloured String.
- * If colour is invalid, IRC Colour 14 will be used.
- *
- * @param colour The colour the string should be (IRC Colour or 6-digit hex colour)
- * @param line the line to colour
- * @return The given line with the appropriate irc codes appended/prepended to colour it.
- */
- protected static String getColouredString(final String colour, final String line) {
- String res = null;
- if (colour.length() < 3) {
- int num;
-
- try {
- num = Integer.parseInt(colour);
- } catch (NumberFormatException ex) {
- num = -1;
- }
-
- if (num >= 0 && num <= 15) {
- res = String.format("%c%02d%s%1$c", Styliser.CODE_COLOUR, num, line);
- }
- } else if (colour.length() == 6) {
- try {
- Color.decode("#" + colour);
- res = String.format("%c%s%s%1$c", Styliser.CODE_HEXCOLOUR, colour, line);
- } catch (NumberFormatException ex) { /* Do Nothing */ }
- }
-
- if (res == null) {
- res = String.format("%c%02d%s%1$c", Styliser.CODE_COLOUR, 14, line);
- }
- return res;
- }
-
- /**
- * Add a line to a file.
- *
- * @param filename Name of file to write to
- * @param format Format of line to add. (NewLine will be added Automatically)
- * @param args Arguments for format
- * @return true on success, else false.
- */
- protected boolean appendLine(final String filename, final String format, final Object... args) {
- return appendLine(filename, String.format(format, args));
- }
-
- /**
- * Add a line to a file.
- *
- * @param filename Name of file to write to
- * @param line Line to add. (NewLine will be added Automatically)
- * @return true on success, else false.
- */
- protected boolean appendLine(final String filename, final String line) {
- final StringBuffer finalLine = new StringBuffer();
-
- if (addtime) {
- String dateString;
- try {
- final DateFormat dateFormat = new SimpleDateFormat(timestamp);
- dateString = dateFormat.format(new Date()).trim();
- } catch (IllegalArgumentException iae) {
- // Default to known good format
- final DateFormat dateFormat = new SimpleDateFormat("[dd/MM/yyyy HH:mm:ss]");
- dateString = dateFormat.format(new Date()).trim();
-
- Logger.userError(ErrorLevel.LOW, "Dateformat String '" + timestamp + "' is invalid. For more information: http://java.sun.com/javase/6/docs/api/java/text/SimpleDateFormat.html");
- }
- finalLine.append(dateString);
- finalLine.append(' ');
- }
-
- if (stripcodes) {
- finalLine.append(Styliser.stipControlCodes(line));
- } else {
- finalLine.append(line);
- }
- //System.out.println("[Adding] "+filename+" => "+finalLine);
- BufferedWriter out = null;
- try {
- if (openFiles.containsKey(filename)) {
- final OpenFile of = openFiles.get(filename);
- of.lastUsedTime = System.currentTimeMillis();
- out = of.writer;
- } else {
- out = new BufferedWriter(new FileWriter(filename, true));
- openFiles.put(filename, new OpenFile(out));
- }
- out.write(finalLine.toString());
- out.newLine();
- out.flush();
- return true;
- } catch (IOException e) {
- /*
- * Do Nothing
- *
- * Makes no sense to keep adding errors to the logger when we can't
- * write to the file, as chances are it will happen on every incomming
- * line.
- */
- }
- return false;
- }
-
- /**
- * Get the name of the log file for a specific object.
- *
- * @param obj Object to get name for
- * @return the name of the log file to use for this object.
- */
- protected String getLogFile(final Object obj) {
- final StringBuffer directory = new StringBuffer();
- final StringBuffer file = new StringBuffer();
- String md5String = "";
-
- directory.append(logDirectory);
- if (directory.charAt(directory.length() - 1) != File.separatorChar) {
- directory.append(File.separatorChar);
- }
-
- if (obj == null) {
- file.append("null.log");
- } else if (obj instanceof ChannelInfo) {
- final ChannelInfo channel = (ChannelInfo) obj;
- if (channel.getParser() != null) {
- addNetworkDir(directory, file, channel.getParser().getNetworkName());
- }
- file.append(sanitise(channel.getName().toLowerCase()));
- md5String = channel.getName();
- } else if (obj instanceof ClientInfo) {
- final ClientInfo client = (ClientInfo) obj;
- if (client.getParser() != null) {
- addNetworkDir(directory, file, client.getParser().getNetworkName());
- }
- file.append(sanitise(client.getNickname().toLowerCase()));
- md5String = client.getNickname();
- } else {
- file.append(sanitise(obj.toString().toLowerCase()));
- md5String = obj.toString();
- }
-
- if (usedate) {
- final String dateFormat = usedateformat;
- final String dateDir = new SimpleDateFormat(dateFormat).format(new Date());
- directory.append(dateDir);
- if (directory.charAt(directory.length() - 1) != File.separatorChar) {
- directory.append(File.separatorChar);
- }
-
- if (!new File(directory.toString()).exists() && !(new File(directory.toString())).mkdirs()) {
- Logger.userError(ErrorLevel.LOW, "Unable to create date dirs");
- }
- }
-
- if (filenamehash) {
- file.append('.');
- file.append(md5(md5String));
- }
- file.append(".log");
-
- return directory.toString() + file.toString();
- }
-
- /**
- * This function adds the networkName to the log file.
- * It first tries to create a directory for each network, if that fails
- * it will prepend the networkName to the filename instead.
- *
- * @param directory Current directory name
- * @param file Current file name
- * @param networkName Name of network
- */
- protected void addNetworkDir(final StringBuffer directory, final StringBuffer file, final String networkName) {
- if (!networkfolders) {
- return;
- }
-
- final String network = sanitise(networkName.toLowerCase());
-
- boolean prependNetwork = false;
-
- // Check dir exists
- final File dir = new File(directory.toString() + network + System.getProperty("file.separator"));
- if (dir.exists() && !dir.isDirectory()) {
- Logger.userError(ErrorLevel.LOW, "Unable to create networkfolders dir (file exists instead)");
- // Prepend network name to file instead.
- prependNetwork = true;
- } else if (!dir.exists() && !dir.mkdirs()) {
- Logger.userError(ErrorLevel.LOW, "Unable to create networkfolders dir");
- prependNetwork = true;
- }
-
- if (prependNetwork) {
- file.insert(0, " -- ");
- file.insert(0, network);
- } else {
- directory.append(network);
- directory.append(System.getProperty("file.separator"));
- }
- }
-
- /**
- * Sanitise a string to be used as a filename.
- *
- * @param name String to sanitise
- * @return Sanitised version of name that can be used as a filename.
- */
- protected static String sanitise(final String name) {
- // Replace illegal chars with
- return name.replaceAll("[^\\w\\.\\s\\-\\#\\&\\_]", "_");
- }
-
- /**
- * Get the md5 hash of a string.
- *
- * @param string String to hash
- * @return md5 hash of given string
- */
- protected static String md5(final String string) {
- try {
- final MessageDigest m = MessageDigest.getInstance("MD5");
- m.update(string.getBytes(), 0, string.length());
- return new BigInteger(1, m.digest()).toString(16);
- } catch (NoSuchAlgorithmException e) {
- return "";
- }
- }
-
- /**
- * Get name to display for client.
- *
- * @param client The client to get the display name for
- * @return name to display
- */
- protected String getDisplayName(final ClientInfo client) {
- return getDisplayName(client, "");
- }
-
- /**
- * Get name to display for client.
- *
- * @param client The client to get the display name for
- * @param overrideNick Nickname to display instead of real nickname
- * @return name to display
- */
- protected String getDisplayName(final ClientInfo client, final String overrideNick) {
- if (overrideNick.isEmpty()) {
- return (client == null) ? "Unknown Client" : client.getNickname();
- } else {
- return overrideNick;
- }
- }
-
- /**
- * Get name to display for channelClient (Taking into account the channelmodeprefix setting).
- *
- * @param channelClient The client to get the display name for
- * @return name to display
- */
- protected String getDisplayName(final ChannelClientInfo channelClient) {
- return getDisplayName(channelClient, "");
- }
-
- /**
- * Get name to display for channelClient (Taking into account the channelmodeprefix setting).
- *
- * @param channelClient The client to get the display name for
- * @param overrideNick Nickname to display instead of real nickname
- * @return name to display
- */
- protected String getDisplayName(final ChannelClientInfo channelClient, final String overrideNick) {
- if (channelClient == null) {
- return (overrideNick.isEmpty()) ? "Unknown Client" : overrideNick;
- } else if (overrideNick.isEmpty()) {
- return channelmodeprefix ? channelClient.toString() : channelClient.getClient().getNickname();
- } else {
- return channelmodeprefix ? channelClient.getImportantModePrefix() + overrideNick : overrideNick;
- }
- }
-
- /**
- * Shows the history window for the specified target, if available.
- *
- * @param target The window whose history we're trying to open
- * @return True if the history is available, false otherwise
- */
- protected boolean showHistory(final FrameContainer target) {
- Object component;
-
- if (target instanceof Channel) {
- component = ((Channel) target).getChannelInfo();
- } else if (target instanceof Query) {
- final Parser parser = ((Query) target).getServer().getParser();
- component = parser.getClient(((Query) target).getHost());
- } else if (target instanceof Server) {
- component = ((Server) target).getParser();
- } else {
- // Unknown component
- return false;
- }
-
- final String log = getLogFile(component);
-
- if (!new File(log).exists()) {
- // File doesn't exist
- return false;
- }
-
- ReverseFileReader reader;
-
- try {
- reader = new ReverseFileReader(log);
- } catch (FileNotFoundException ex) {
- return false;
- } catch (IOException ex) {
- return false;
- } catch (SecurityException ex) {
- return false;
- }
-
- new HistoryWindow("History", reader, target, historyLines);
-
- return true;
- }
-
- /** Updates cached settings. */
- public void setCachedSettings() {
- networkfolders = config.getOptionBool(getDomain(), "general.networkfolders");
- filenamehash = config.getOptionBool(getDomain(), "advanced.filenamehash");
- addtime = config.getOptionBool(getDomain(), "general.addtime");
- stripcodes = config.getOptionBool(getDomain(), "general.stripcodes");
- channelmodeprefix = config.getOptionBool(getDomain(), "general.channelmodeprefix");
- autobackbuffer = config.getOptionBool(getDomain(), "backbuffer.autobackbuffer");
- backbufferTimestamp = config.getOptionBool(getDomain(), "backbuffer.timestamp");
- usedate = config.getOptionBool(getDomain(), "advanced.usedate");
- timestamp = config.getOption(getDomain(), "general.timestamp");
- usedateformat = config.getOption(getDomain(), "advanced.usedateformat");
- historyLines = config.getOptionInt(getDomain(), "history.lines");
- colour = config.getOption(getDomain(), "backbuffer.colour");
- backbufferLines = config.getOptionInt(getDomain(), "backbuffer.lines");
- logDirectory = config.getOption(getDomain(), "general.directory");
- }
-
- /** Open File. */
- protected static class OpenFile {
-
- /** Last used time. */
- public long lastUsedTime = System.currentTimeMillis();
-
- /** Open file's writer. */
- public BufferedWriter writer = null;
-
- /**
- * Creates a new open file.
- *
- * @param writer Writer that has file open
- */
- protected OpenFile(final BufferedWriter writer) {
- this.writer = writer;
- }
-
- }
-
- }
|