You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LoggingManager.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /*
  2. * Copyright (c) 2006-2017 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  5. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to the following conditions:
  8. *
  9. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
  10. * Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  14. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  15. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. */
  17. package com.dmdirc.addons.logging;
  18. import com.dmdirc.Query;
  19. import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
  20. import com.dmdirc.config.GlobalConfig;
  21. import com.dmdirc.config.prefs.PluginPreferencesCategory;
  22. import com.dmdirc.config.prefs.PreferencesCategory;
  23. import com.dmdirc.config.prefs.PreferencesDialogModel;
  24. import com.dmdirc.config.prefs.PreferencesSetting;
  25. import com.dmdirc.config.prefs.PreferencesType;
  26. import com.dmdirc.events.BaseChannelActionEvent;
  27. import com.dmdirc.events.BaseChannelMessageEvent;
  28. import com.dmdirc.events.BaseQueryActionEvent;
  29. import com.dmdirc.events.BaseQueryMessageEvent;
  30. import com.dmdirc.events.ChannelClosedEvent;
  31. import com.dmdirc.events.ChannelGotTopicEvent;
  32. import com.dmdirc.events.ChannelJoinEvent;
  33. import com.dmdirc.events.ChannelKickEvent;
  34. import com.dmdirc.events.ChannelModeChangeEvent;
  35. import com.dmdirc.events.ChannelNickChangeEvent;
  36. import com.dmdirc.events.ChannelOpenedEvent;
  37. import com.dmdirc.events.ChannelPartEvent;
  38. import com.dmdirc.events.ChannelQuitEvent;
  39. import com.dmdirc.events.ChannelTopicChangeEvent;
  40. import com.dmdirc.events.ClientPrefsOpenedEvent;
  41. import com.dmdirc.events.QueryClosedEvent;
  42. import com.dmdirc.events.QueryOpenedEvent;
  43. import com.dmdirc.events.QuerySelfActionEvent;
  44. import com.dmdirc.events.QuerySelfMessageEvent;
  45. import com.dmdirc.events.eventbus.EventBus;
  46. import com.dmdirc.interfaces.GroupChat;
  47. import com.dmdirc.interfaces.GroupChatUser;
  48. import com.dmdirc.interfaces.PrivateChat;
  49. import com.dmdirc.interfaces.User;
  50. import com.dmdirc.interfaces.WindowModel;
  51. import com.dmdirc.config.provider.AggregateConfigProvider;
  52. import com.dmdirc.config.provider.ConfigChangeListener;
  53. import com.dmdirc.plugins.PluginDomain;
  54. import com.dmdirc.plugins.PluginInfo;
  55. import com.dmdirc.ui.WindowManager;
  56. import com.dmdirc.ui.messages.BackBufferFactory;
  57. import com.dmdirc.ui.messages.IRCControlCodes;
  58. import com.dmdirc.ui.messages.StyledMessageUtils;
  59. import com.dmdirc.util.io.ReverseFileReader;
  60. import com.dmdirc.util.io.StreamUtils;
  61. import java.awt.Color;
  62. import java.io.BufferedWriter;
  63. import java.io.File;
  64. import java.io.FileWriter;
  65. import java.io.IOException;
  66. import java.nio.file.Files;
  67. import java.nio.file.Path;
  68. import java.nio.file.Paths;
  69. import java.text.DateFormat;
  70. import java.text.SimpleDateFormat;
  71. import java.time.format.DateTimeFormatter;
  72. import java.util.ArrayList;
  73. import java.util.Collection;
  74. import java.util.Collections;
  75. import java.util.Date;
  76. import java.util.HashMap;
  77. import java.util.Map;
  78. import java.util.Stack;
  79. import java.util.Timer;
  80. import java.util.TimerTask;
  81. import javax.inject.Inject;
  82. import javax.inject.Provider;
  83. import javax.inject.Singleton;
  84. import net.engio.mbassy.listener.Handler;
  85. import org.slf4j.Logger;
  86. import org.slf4j.LoggerFactory;
  87. import static com.dmdirc.util.LogUtils.USER_ERROR;
  88. /**
  89. * Manages logging activities.
  90. */
  91. @Singleton
  92. public class LoggingManager implements ConfigChangeListener {
  93. private static final Logger LOG = LoggerFactory.getLogger(LoggingManager.class);
  94. /** Date format used for "File Opened At" log. */
  95. private static final DateFormat OPENED_AT_FORMAT = new SimpleDateFormat(
  96. "EEEE MMMM dd, yyyy - HH:mm:ss");
  97. /** Object for synchronising access to the date forma.t */
  98. private static final Object FORMAT_LOCK = new Object();
  99. private static final DateFormat LOG_FORMAT = new SimpleDateFormat("[dd/MM/yyyy HH:mm:ss]");
  100. /** This plugin's plugin info. */
  101. private final String domain;
  102. private final PluginInfo pluginInfo;
  103. /** Global config. */
  104. private final AggregateConfigProvider config;
  105. /** The manager to add history windows to. */
  106. private final WindowManager windowManager;
  107. /** Map of open files. */
  108. private final Map<String, OpenFile> openFiles = Collections.synchronizedMap(new HashMap<>());
  109. private final EventBus eventBus;
  110. private final Provider<String> directoryProvider;
  111. private final BackBufferFactory backBufferFactory;
  112. private final LogFileLocator locator;
  113. private final StyledMessageUtils styleUtils;
  114. /** Timer used to close idle files. */
  115. private Timer idleFileTimer;
  116. /** Cached boolean settings. */
  117. private boolean addtime;
  118. private boolean stripcodes;
  119. private boolean channelmodeprefix;
  120. private boolean autobackbuffer;
  121. private String colour;
  122. /** Cached int settings. */
  123. private int historyLines;
  124. private int backbufferLines;
  125. @Inject
  126. public LoggingManager(
  127. @PluginDomain(LoggingPlugin.class) final String domain,
  128. @PluginDomain(LoggingPlugin.class) final PluginInfo pluginInfo,
  129. @GlobalConfig final AggregateConfigProvider globalConfig,
  130. final WindowManager windowManager, final EventBus eventBus,
  131. @Directory(LoggingModule.LOGS_DIRECTORY) final Provider<String> directoryProvider,
  132. final BackBufferFactory backBufferFactory,
  133. final LogFileLocator locator,
  134. final StyledMessageUtils styleUtils) {
  135. this.domain = domain;
  136. this.pluginInfo = pluginInfo;
  137. this.config = globalConfig;
  138. this.windowManager = windowManager;
  139. this.eventBus = eventBus;
  140. this.directoryProvider = directoryProvider;
  141. this.backBufferFactory = backBufferFactory;
  142. this.locator = locator;
  143. this.styleUtils = styleUtils;
  144. }
  145. public void load() {
  146. setCachedSettings();
  147. final File dir = new File(directoryProvider.get());
  148. if (dir.exists()) {
  149. if (!dir.isDirectory()) {
  150. LOG.info(USER_ERROR, "Unable to create logging dir (file exists instead)");
  151. }
  152. } else {
  153. if (!dir.mkdirs()) {
  154. LOG.info(USER_ERROR, "Unable to create logging dir");
  155. }
  156. }
  157. config.addChangeListener(domain, this);
  158. // Close idle files every hour.
  159. idleFileTimer = new Timer("LoggingPlugin Timer");
  160. idleFileTimer.schedule(new TimerTask() {
  161. @Override
  162. public void run() {
  163. timerTask();
  164. }
  165. }, 3600000);
  166. eventBus.subscribe(this);
  167. }
  168. public void unload() {
  169. if (idleFileTimer != null) {
  170. idleFileTimer.cancel();
  171. idleFileTimer.purge();
  172. }
  173. synchronized (openFiles) {
  174. for (OpenFile file : openFiles.values()) {
  175. StreamUtils.close(file.writer);
  176. }
  177. openFiles.clear();
  178. }
  179. eventBus.unsubscribe(this);
  180. }
  181. /**
  182. * What to do every hour when the timer fires.
  183. */
  184. protected void timerTask() {
  185. // Oldest time to allow
  186. final long oldestTime = System.currentTimeMillis() - 3480000;
  187. synchronized (openFiles) {
  188. final Collection<String> old = new ArrayList<>(openFiles.size());
  189. openFiles.entrySet().stream()
  190. .filter(entry -> entry.getValue().lastUsedTime < oldestTime)
  191. .forEach(entry -> {
  192. StreamUtils.close(entry.getValue().writer);
  193. old.add(entry.getKey());
  194. });
  195. openFiles.keySet().removeAll(old);
  196. }
  197. }
  198. @Handler
  199. public void handleQueryOpened(final QueryOpenedEvent event) {
  200. final String filename = locator.getLogFile(event.getQuery().getUser());
  201. if (autobackbuffer) {
  202. showBackBuffer(event.getQuery().getWindowModel(), filename);
  203. }
  204. synchronized (FORMAT_LOCK) {
  205. appendLine(filename, "*** Query opened at: %s", OPENED_AT_FORMAT.format(new Date()));
  206. appendLine(filename, "*** Query with User: %s", event.getQuery().getUser().getNickname()
  207. + '!' + event.getQuery().getUser().getUsername().orElse("")
  208. + '@' + event.getQuery().getUser().getHostname().orElse(""));
  209. appendLine(filename, "");
  210. }
  211. }
  212. @Handler
  213. public void handleQueryClosed(final QueryClosedEvent event) {
  214. final String filename = locator.getLogFile(event.getQuery().getUser());
  215. synchronized (FORMAT_LOCK) {
  216. appendLine(filename, "*** Query closed at: %s", OPENED_AT_FORMAT.format(new Date()));
  217. }
  218. if (openFiles.containsKey(filename)) {
  219. StreamUtils.close(openFiles.get(filename).writer);
  220. openFiles.remove(filename);
  221. }
  222. }
  223. @Handler
  224. public void handleQueryActions(final BaseQueryActionEvent event) {
  225. if (event instanceof QuerySelfActionEvent) { return; }
  226. final User user = event.getQuery().getUser();
  227. final String filename = locator.getLogFile(user);
  228. appendLine(filename, "* %s %s", user.getNickname(), event.getMessage());
  229. }
  230. @Handler
  231. public void handleQuerySelActions(final QuerySelfActionEvent event) {
  232. final User user = event.getQuery().getUser();
  233. final String filename = locator.getLogFile(user);
  234. if (event.getSource().getConnection().isPresent() && event.getSource().getConnection().get().getLocalUser().isPresent()) {
  235. appendLine(filename, "* %s %s", event.getSource().getConnection().get().getLocalUser().get().getNickname(), event.getMessage());
  236. } else {
  237. appendLine(filename, "* >> %s", event.getMessage());
  238. }
  239. }
  240. @Handler
  241. public void handleQueryMessages(final BaseQueryMessageEvent event) {
  242. if (event instanceof QuerySelfMessageEvent) { return; }
  243. final User user = event.getQuery().getUser();
  244. final String filename = locator.getLogFile(user);
  245. appendLine(filename, "<%s> %s", user.getNickname(), event.getMessage());
  246. }
  247. @Handler
  248. public void handleQuerySelfMessages(final QuerySelfMessageEvent event) {
  249. final User user = event.getQuery().getUser();
  250. final String filename = locator.getLogFile(user);
  251. if (event.getSource().getConnection().isPresent() && event.getSource().getConnection().get().getLocalUser().isPresent()) {
  252. appendLine(filename, "<%s> %s", event.getSource().getConnection().get().getLocalUser().get().getNickname(), event.getMessage());
  253. } else {
  254. appendLine(filename, ">> %s", event.getMessage());
  255. }
  256. }
  257. @Handler
  258. public void handleChannelMessage(final BaseChannelMessageEvent event) {
  259. final String filename = locator.getLogFile(event.getChannel());
  260. appendLine(filename, "<%s> %s", getDisplayName(event.getClient()), event.getMessage());
  261. }
  262. @Handler
  263. public void handleChannelAction(final BaseChannelActionEvent event) {
  264. final String filename = locator.getLogFile(event.getChannel());
  265. appendLine(filename, "* %s %s", getDisplayName(event.getClient()), event.getMessage());
  266. }
  267. @Handler
  268. public void handleChannelGotTopic(final ChannelGotTopicEvent event) {
  269. final String filename = locator.getLogFile(event.getChannel());
  270. appendLine(filename, "*** Topic is: %s", event.getTopic().getTopic());
  271. appendLine(filename, "*** Set at: %s on %s by %s",
  272. event.getTopic().getDate().format(DateTimeFormatter.ofPattern("HH:mm:ss")),
  273. event.getTopic().getDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")),
  274. event.getTopic().getClient()
  275. .map(GroupChatUser::getNickname).orElse("Unknown"));
  276. }
  277. @Handler
  278. public void handleChannelTopicChange(final ChannelTopicChangeEvent event) {
  279. final String filename = locator.getLogFile(event.getChannel());
  280. appendLine(filename, "*** %s Changed the topic to: %s",
  281. event.getTopic().getClient().map(this::getDisplayName).orElse(""), event.getTopic());
  282. }
  283. @Handler
  284. public void handleChannelJoin(final ChannelJoinEvent event) {
  285. final String filename = locator.getLogFile(event.getChannel());
  286. final GroupChatUser channelClient = event.getClient();
  287. appendLine(filename, "*** %s (%s) joined the channel", getDisplayName(channelClient),
  288. channelClient.getNickname());
  289. }
  290. @Handler
  291. public void handleChannelPart(final ChannelPartEvent event) {
  292. final String filename = locator.getLogFile(event.getChannel());
  293. final String message = event.getMessage();
  294. final GroupChatUser channelClient = event.getClient();
  295. if (message.isEmpty()) {
  296. appendLine(filename, "*** %s (%s) left the channel", getDisplayName(channelClient),
  297. channelClient.getNickname());
  298. } else {
  299. appendLine(filename, "*** %s (%s) left the channel (%s)",
  300. getDisplayName(channelClient), channelClient.getNickname(), message);
  301. }
  302. }
  303. @Handler
  304. public void handleChannelQuit(final ChannelQuitEvent event) {
  305. final String filename = locator.getLogFile(event.getChannel());
  306. final String reason = event.getMessage();
  307. final GroupChatUser channelClient = event.getClient();
  308. if (reason.isEmpty()) {
  309. appendLine(filename, "*** %s (%s) Quit IRC",
  310. getDisplayName(channelClient), channelClient.getNickname());
  311. } else {
  312. appendLine(filename, "*** %s (%s) Quit IRC (%s)",
  313. getDisplayName(channelClient), channelClient.getNickname(), reason);
  314. }
  315. }
  316. @Handler
  317. public void handleChannelKick(final ChannelKickEvent event) {
  318. final GroupChatUser victim = event.getVictim();
  319. final GroupChatUser perpetrator = event.getClient();
  320. final String reason = event.getReason();
  321. final String filename = locator.getLogFile(event.getChannel());
  322. if (reason.isEmpty()) {
  323. appendLine(filename, "*** %s was kicked by %s",
  324. getDisplayName(victim), getDisplayName(perpetrator));
  325. } else {
  326. appendLine(filename, "*** %s was kicked by %s (%s)",
  327. getDisplayName(victim), getDisplayName(perpetrator), reason);
  328. }
  329. }
  330. @Handler
  331. public void handleNickChange(final ChannelNickChangeEvent event) {
  332. final String filename = locator.getLogFile(event.getChannel());
  333. appendLine(filename, "*** %s is now %s", getDisplayName(event.getClient(),
  334. event.getOldNick()), getDisplayName(event.getClient()));
  335. }
  336. @Handler
  337. public void handleModeChange(final ChannelModeChangeEvent event) {
  338. final String filename = locator.getLogFile(event.getChannel());
  339. if (event.getClient().getNickname().isEmpty()) {
  340. appendLine(filename, "*** Channel modes are: %s", event.getModes());
  341. } else {
  342. appendLine(filename, "*** %s set modes: %s",
  343. getDisplayName(event.getClient()), event.getModes());
  344. }
  345. }
  346. @Override
  347. public void configChanged(final String domain, final String key) {
  348. setCachedSettings();
  349. }
  350. @Handler
  351. public void handleChannelOpened(final ChannelOpenedEvent event) {
  352. final String filename = locator.getLogFile(event.getChannel());
  353. if (autobackbuffer) {
  354. showBackBuffer(event.getChannel().getWindowModel(), filename);
  355. }
  356. synchronized (FORMAT_LOCK) {
  357. appendLine(filename, "*** Channel opened at: %s", OPENED_AT_FORMAT.format(new Date()));
  358. appendLine(filename, "");
  359. }
  360. }
  361. @Handler
  362. public void handleChannelClosed(final ChannelClosedEvent event) {
  363. final String filename = locator.getLogFile(event.getChannel());
  364. synchronized (FORMAT_LOCK) {
  365. appendLine(filename, "*** Channel closed at: %s", OPENED_AT_FORMAT.format(new Date()));
  366. }
  367. if (openFiles.containsKey(filename)) {
  368. StreamUtils.close(openFiles.get(filename).writer);
  369. openFiles.remove(filename);
  370. }
  371. }
  372. /**
  373. * Add a backbuffer to a frame.
  374. *
  375. * @param frame The frame to add the backbuffer lines to
  376. * @param filename File to get backbuffer from
  377. */
  378. protected void showBackBuffer(final WindowModel frame, final String filename) {
  379. if (frame == null) {
  380. LOG.info(USER_ERROR, "Unable to show back buffer, frame was null");
  381. return;
  382. }
  383. final Path testFile = Paths.get(filename);
  384. if (Files.exists(testFile)) {
  385. try (final ReverseFileReader file = new ReverseFileReader(testFile)) {
  386. // Because the file includes a newline char at the end, an empty line
  387. // is returned by getLines. To counter this, we call getLines(1) and do
  388. // nothing with the output.
  389. file.getLines(1);
  390. final Stack<String> lines = file.getLines(backbufferLines);
  391. while (!lines.empty()) {
  392. frame.getEventBus().publishAsync(new HistoricalLineRestoredEvent(frame,
  393. getColouredString(colour, lines.pop())));
  394. }
  395. file.close();
  396. frame.getEventBus().publishAsync(new HistoricalLineRestoredEvent(frame,
  397. getColouredString(colour, "--- End of backbuffer\n")));
  398. } catch (IOException | SecurityException e) {
  399. LOG.info(USER_ERROR, "Unable to show backbuffer (Filename: {}): {}", filename,
  400. e.getMessage(), e);
  401. }
  402. }
  403. }
  404. /**
  405. * Get a coloured String. If colour is invalid, IRC Colour 14 will be used.
  406. *
  407. * @param colour The colour the string should be (IRC Colour or 6-digit hex colour)
  408. * @param line the line to colour
  409. *
  410. * @return The given line with the appropriate irc codes appended/prepended to colour it.
  411. */
  412. protected static String getColouredString(final String colour, final String line) {
  413. String res = null;
  414. if (colour.length() < 3) {
  415. int num;
  416. try {
  417. num = Integer.parseInt(colour);
  418. } catch (NumberFormatException ex) {
  419. num = -1;
  420. }
  421. if (num >= 0 && num <= 15) {
  422. res = String.format("%c%02d%s%1$c", IRCControlCodes.COLOUR, num, line);
  423. }
  424. } else if (colour.length() == 6) {
  425. try {
  426. Color.decode('#' + colour);
  427. res = String.format("%c%s%s%1$c", IRCControlCodes.COLOUR_HEX, colour, line);
  428. } catch (NumberFormatException ex) { /* Do Nothing */ }
  429. }
  430. if (res == null) {
  431. res = String.format("%c%02d%s%1$c", IRCControlCodes.COLOUR, 14, line);
  432. }
  433. return res;
  434. }
  435. /**
  436. * Add a line to a file.
  437. *
  438. * @param filename Name of file to write to
  439. * @param format Format of line to add. (NewLine will be added Automatically)
  440. * @param args Arguments for format
  441. *
  442. * @return true on success, else false.
  443. */
  444. protected boolean appendLine(final String filename, final String format, final Object... args) {
  445. return appendLine(filename, String.format(format, args));
  446. }
  447. /**
  448. * Add a line to a file.
  449. *
  450. * @param filename Name of file to write to
  451. * @param line Line to add. (NewLine will be added Automatically)
  452. *
  453. * @return true on success, else false.
  454. */
  455. protected boolean appendLine(final String filename, final String line) {
  456. final StringBuilder finalLine = new StringBuilder();
  457. if (addtime) {
  458. final String dateString = LOG_FORMAT.format(new Date()).trim();
  459. finalLine.append(dateString);
  460. finalLine.append(' ');
  461. }
  462. if (stripcodes) {
  463. finalLine.append(styleUtils.stripControlCodes(line));
  464. } else {
  465. finalLine.append(line);
  466. }
  467. try {
  468. final BufferedWriter out;
  469. if (openFiles.containsKey(filename)) {
  470. final OpenFile of = openFiles.get(filename);
  471. of.lastUsedTime = System.currentTimeMillis();
  472. out = of.writer;
  473. } else {
  474. out = new BufferedWriter(new FileWriter(filename, true));
  475. openFiles.put(filename, new OpenFile(out));
  476. }
  477. out.write(finalLine.toString());
  478. out.newLine();
  479. out.flush();
  480. return true;
  481. } catch (IOException e) {
  482. /*
  483. * Do Nothing
  484. *
  485. * Makes no sense to keep adding errors to the logger when we can't write to the file,
  486. * as chances are it will happen on every incoming line.
  487. */
  488. }
  489. return false;
  490. }
  491. /**
  492. * Get name to display for channelClient (Taking into account the channelmodeprefix setting).
  493. *
  494. * @param channelClient The client to get the display name for
  495. *
  496. * @return name to display
  497. */
  498. protected String getDisplayName(final GroupChatUser channelClient) {
  499. return getDisplayName(channelClient, "");
  500. }
  501. /**
  502. * Get name to display for channelClient (Taking into account the channelmodeprefix setting).
  503. *
  504. * @param channelClient The client to get the display name for
  505. * @param overrideNick Nickname to display instead of real nickname
  506. *
  507. * @return name to display
  508. */
  509. protected String getDisplayName(final GroupChatUser channelClient, final String overrideNick) {
  510. if (channelClient == null) {
  511. return overrideNick.isEmpty() ? "Unknown Client" : overrideNick;
  512. } else if (overrideNick.isEmpty()) {
  513. return channelmodeprefix ? channelClient.getModePrefixedNickname()
  514. : channelClient.getNickname();
  515. } else {
  516. return channelmodeprefix ? channelClient.getImportantMode() + overrideNick :
  517. overrideNick;
  518. }
  519. }
  520. /**
  521. * Shows the history window for the specified target, if available.
  522. *
  523. * @param target The window whose history we're trying to open
  524. *
  525. * @return True if the history is available, false otherwise
  526. */
  527. protected boolean showHistory(final WindowModel target) {
  528. final Path log;
  529. if (target instanceof GroupChat) {
  530. log = Paths.get(locator.getLogFile((GroupChat)target));
  531. } else if (target instanceof Query) {
  532. log = Paths.get(locator.getLogFile(((PrivateChat) target).getUser()));
  533. } else {
  534. // Unknown component
  535. return false;
  536. }
  537. if (!Files.exists(log)) {
  538. // File doesn't exist
  539. return false;
  540. }
  541. windowManager.addWindow(target, new HistoryWindow("History", log, target,
  542. eventBus, backBufferFactory, historyLines));
  543. return true;
  544. }
  545. /** Updates cached settings. */
  546. public void setCachedSettings() {
  547. addtime = config.getOptionBool(domain, "general.addtime");
  548. stripcodes = config.getOptionBool(domain, "general.stripcodes");
  549. channelmodeprefix = config.getOptionBool(domain, "general.channelmodeprefix");
  550. autobackbuffer = config.getOptionBool(domain, "backbuffer.autobackbuffer");
  551. historyLines = config.getOptionInt(domain, "history.lines");
  552. colour = config.getOption(domain, "backbuffer.colour");
  553. backbufferLines = config.getOptionInt(domain, "backbuffer.lines");
  554. }
  555. @Handler
  556. public void showConfig(final ClientPrefsOpenedEvent event) {
  557. final PreferencesDialogModel manager = event.getModel();
  558. final PreferencesCategory general = new PluginPreferencesCategory(
  559. pluginInfo, "Logging", "General configuration for Logging plugin.");
  560. final PreferencesCategory backbuffer = new PluginPreferencesCategory(
  561. pluginInfo, "Back Buffer", "Options related to the automatic backbuffer");
  562. final PreferencesCategory advanced = new PluginPreferencesCategory(
  563. pluginInfo, "Advanced",
  564. "Advanced configuration for Logging plugin. You shouldn't need to edit this unless you know what you are doing.");
  565. general.addSetting(new PreferencesSetting(PreferencesType.DIRECTORY,
  566. pluginInfo.getDomain(), "general.directory", "Directory",
  567. "Directory for log files", manager.getConfigManager(),
  568. manager.getIdentity()));
  569. general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  570. pluginInfo.getDomain(), "general.networkfolders",
  571. "Separate logs by network",
  572. "Should the files be stored in a sub-dir with the networks name?",
  573. manager.getConfigManager(), manager.getIdentity()));
  574. general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  575. pluginInfo.getDomain(), "general.addtime", "Timestamp logs",
  576. "Should a timestamp be added to the log files?",
  577. manager.getConfigManager(), manager.getIdentity()));
  578. general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  579. pluginInfo.getDomain(), "general.stripcodes", "Strip Control Codes",
  580. "Remove known irc control codes from lines before saving?",
  581. manager.getConfigManager(), manager.getIdentity()));
  582. general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  583. pluginInfo.getDomain(), "general.channelmodeprefix",
  584. "Show channel mode prefix", "Show the @,+ etc next to nicknames",
  585. manager.getConfigManager(), manager.getIdentity()));
  586. backbuffer.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  587. pluginInfo.getDomain(), "backbuffer.autobackbuffer", "Automatically display",
  588. "Automatically display the backbuffer when a channel is joined",
  589. manager.getConfigManager(), manager.getIdentity()));
  590. backbuffer.addSetting(new PreferencesSetting(PreferencesType.COLOUR,
  591. pluginInfo.getDomain(), "backbuffer.colour", "Colour to use for display",
  592. "Colour used when displaying the backbuffer",
  593. manager.getConfigManager(), manager.getIdentity()));
  594. backbuffer.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
  595. pluginInfo.getDomain(), "backbuffer.lines", "Number of lines to show",
  596. "Number of lines used when displaying backbuffer",
  597. manager.getConfigManager(), manager.getIdentity()));
  598. advanced.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  599. pluginInfo.getDomain(), "advanced.filenamehash", "Add Filename hash",
  600. "Add the MD5 hash of the channel/client name to the filename. "
  601. + "(This is used to allow channels with similar names "
  602. + "(ie a _ not a -) to be logged separately)",
  603. manager.getConfigManager(), manager.getIdentity()));
  604. advanced.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  605. pluginInfo.getDomain(), "advanced.usedate", "Use Date directories",
  606. "Should the log files be in separate directories based on the date?",
  607. manager.getConfigManager(), manager.getIdentity()));
  608. advanced.addSetting(new PreferencesSetting(PreferencesType.TEXT,
  609. pluginInfo.getDomain(), "advanced.usedateformat", "Archive format",
  610. "The String to pass to 'SimpleDateFormat' to format the "
  611. + "directory name(s) for archiving",
  612. manager.getConfigManager(), manager.getIdentity()));
  613. general.addSubCategory(backbuffer.setInline());
  614. general.addSubCategory(advanced.setInline());
  615. manager.getCategory("Plugins").addSubCategory(general.setInlineAfter());
  616. }
  617. /** Open File. */
  618. private static class OpenFile {
  619. /** Last used time. */
  620. public long lastUsedTime = System.currentTimeMillis();
  621. /** Open file's writer. */
  622. public final BufferedWriter writer;
  623. /**
  624. * Creates a new open file.
  625. *
  626. * @param writer Writer that has file open
  627. */
  628. protected OpenFile(final BufferedWriter writer) {
  629. this.writer = writer;
  630. }
  631. }
  632. }