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 23KB

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