package games.strategy.triplea.ui.menubar; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import games.strategy.debug.ClientLogger; import games.strategy.engine.framework.system.SystemProperties; import games.strategy.engine.lobby.client.login.CreateUpdateAccountPanel; import games.strategy.engine.lobby.client.ui.LobbyFrame; import games.strategy.engine.lobby.client.ui.MacLobbyWrapper; import games.strategy.engine.lobby.server.IModeratorController; import games.strategy.engine.lobby.server.IUserManager; import games.strategy.engine.lobby.server.ModeratorController; import games.strategy.engine.lobby.server.userDB.DBUser; import games.strategy.engine.lobby.server.userDB.DBUserController; import games.strategy.net.INode; import games.strategy.net.Node; import games.strategy.sound.SoundOptions; import games.strategy.triplea.UrlConstants; import games.strategy.ui.SwingAction; import games.strategy.ui.SwingComponents; import games.strategy.util.MD5Crypt; public class LobbyMenu extends JMenuBar { private static final long serialVersionUID = 4980621864542042057L; private final LobbyFrame m_frame; public LobbyMenu(final LobbyFrame frame) { m_frame = frame; // file only has one value // and on mac it is in the apple menu if (!SystemProperties.isMac()) { createFileMenu(this); } else { MacLobbyWrapper.registerMacShutdownHandler(m_frame); } createAccountMenu(this); if (m_frame.getLobbyClient().isAdmin()) { createAdminMenu(this); } createSettingsMenu(this); createHelpMenu(this); } private void createAccountMenu(final LobbyMenu menuBar) { final JMenu account = new JMenu("Account"); menuBar.add(account); addUpdateAccountMenu(account); } private void createAdminMenu(final LobbyMenu menuBar) { final JMenu powerUser = new JMenu("Admin"); menuBar.add(powerUser); createDiagnosticsMenu(powerUser); createToolboxMenu(powerUser); } private void createDiagnosticsMenu(final JMenu menuBar) { final JMenu diagnostics = new JMenu("Diagnostics"); menuBar.add(diagnostics); addDisplayPlayersInformationMenu(diagnostics); } private void createToolboxMenu(final JMenu menuBar) { final JMenu toolbox = new JMenu("Toolbox"); menuBar.add(toolbox); addBanUsernameMenu(toolbox); addBanMacAddressMenu(toolbox); addUnbanUsernameMenu(toolbox); addUnbanMacAddressMenu(toolbox); } private void addDisplayPlayersInformationMenu(final JMenu parentMenu) { final JMenuItem revive = new JMenuItem("Display Players Information"); revive.setEnabled(true); revive.addActionListener(event -> { final Runnable runner = () -> { final IModeratorController controller = (IModeratorController) m_frame.getLobbyClient().getMessengers() .getRemoteMessenger().getRemote(ModeratorController.getModeratorControllerName()); final StringBuilder builder = new StringBuilder(); builder.append("Online Players:\r\n\r\n"); for (final INode player : m_frame.getChatMessagePanel().getChat().getOnlinePlayers()) { builder.append(controller.getInformationOn(player)).append("\r\n\r\n"); } builder.append("Players That Have Left (Last 10):\r\n\r\n"); for (final INode player : m_frame.getChatMessagePanel().getChat().getPlayersThatLeft_Last10()) { builder.append(controller.getInformationOn(player)).append("\r\n\r\n"); } final Runnable componentCreation = () -> { final JDialog dialog = new JDialog(m_frame, "Players Information"); final JTextArea label = new JTextArea(builder.toString()); label.setFont(new Font("Segoe UI", Font.PLAIN, 12)); label.setEditable(false); label.setAutoscrolls(true); label.setLineWrap(false); label.setFocusable(true); label.setWrapStyleWord(true); label.setLocation(0, 0); dialog.setBackground(label.getBackground()); dialog.setLayout(new BorderLayout()); final JScrollPane pane = new JScrollPane(); pane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); pane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); pane.setViewportView(label); dialog.add(pane, BorderLayout.CENTER); final JButton button = new JButton(SwingAction.of(e -> dialog.dispose())); button.setText("Close"); button.setMinimumSize(new Dimension(100, 30)); dialog.add(button, BorderLayout.SOUTH); dialog.setMinimumSize(new Dimension(500, 300)); dialog.setSize(new Dimension(800, 600)); dialog.setResizable(true); dialog.setLocationRelativeTo(m_frame); dialog.setDefaultCloseOperation(2); dialog.setVisible(true); }; SwingUtilities.invokeLater(componentCreation); }; final Thread thread = new Thread(runner); thread.start(); }); parentMenu.add(revive); } private void addBanUsernameMenu(final JMenu parentMenu) { final JMenuItem item = new JMenuItem("Ban Username"); item.addActionListener(e -> { final String name1 = JOptionPane.showInputDialog(null, "Enter the username that you want to ban from the lobby.\r\n\r\n" + "Note that this ban is effective on any username, registered or anonymous, online or offline.", ""); if (name1 == null || name1.length() < 1) { return; } if (DBUserController.validateUserName(name1) != null) { if (JOptionPane.showConfirmDialog(m_frame, "The username you entered is invalid. Do you want to ban it anyhow?", "Invalid Username", JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) { return; } } final long ticks = requestTimespanSupplication(); final long expire = System.currentTimeMillis() + ticks; final IModeratorController controller = (IModeratorController) m_frame.getLobbyClient().getMessengers() .getRemoteMessenger().getRemote(ModeratorController.getModeratorControllerName()); try { controller.banUsername(new Node(name1, InetAddress.getByName("0.0.0.0"), 0), new Date(expire)); } catch (final UnknownHostException ex) { ClientLogger.logQuietly(ex); } }); item.setEnabled(true); parentMenu.add(item); } private void addBanMacAddressMenu(final JMenu parentMenu) { final JMenuItem item = new JMenuItem("Ban Hashed Mac Address"); item.addActionListener(e -> { final String mac = JOptionPane.showInputDialog(null, "Enter the hashed Mac Address that you want to ban from the lobby.\r\n\r\n" + "Hashed Mac Addresses should be entered in this format: $1$MH$345ntXD4G3AKpAeHZdaGe3", ""); if (mac == null || mac.length() < 1) { return; } final String prefix = MD5Crypt.MAGIC + "MH$"; final String error; if (mac.length() != 28) { error = "Must be 28 characters long"; } else if (!mac.startsWith(prefix)) { error = "Must start with: " + prefix; } else if (!mac.matches("[0-9a-zA-Z$./]+")) { error = "Must use only these characters: 0-9a-zA-Z$./"; } else { error = null; } if (error != null) { if (JOptionPane.showConfirmDialog(m_frame, "The hashed Mac Address you entered is invalid (" + error + "). Do you want to ban it anyhow?", "Invalid Hashed Mac", JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) { return; } } final long ticks = requestTimespanSupplication(); final long expire = System.currentTimeMillis() + ticks; final IModeratorController controller = (IModeratorController) m_frame.getLobbyClient().getMessengers() .getRemoteMessenger().getRemote(ModeratorController.getModeratorControllerName()); try { controller.banMac(new Node("None (Admin menu originated ban)", InetAddress.getByName("0.0.0.0"), 0), mac, new Date(expire)); } catch (final UnknownHostException ex) { ClientLogger.logQuietly(ex); } }); item.setEnabled(true); parentMenu.add(item); } private void addUnbanUsernameMenu(final JMenu parentMenu) { final JMenuItem item = new JMenuItem("Unban Username"); item.addActionListener(e -> { final String name1 = JOptionPane.showInputDialog(null, "Enter the username that you want to unban from the lobby.", ""); if (name1 == null || name1.length() < 1) { return; } if (DBUserController.validateUserName(name1) != null) { if (JOptionPane.showConfirmDialog(m_frame, "The username you entered is invalid. Do you want to ban it anyhow?", "Invalid Username", JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) { return; } } final IModeratorController controller = (IModeratorController) m_frame.getLobbyClient().getMessengers() .getRemoteMessenger().getRemote(ModeratorController.getModeratorControllerName()); try { controller.banUsername(new Node(name1, InetAddress.getByName("0.0.0.0"), 0), new Date(0)); } catch (final UnknownHostException ex) { ClientLogger.logQuietly(ex); } }); item.setEnabled(true); parentMenu.add(item); } private void addUnbanMacAddressMenu(final JMenu parentMenu) { final JMenuItem item = new JMenuItem("Unban Hashed Mac Address"); item.addActionListener(e -> { final String mac = JOptionPane.showInputDialog(null, "Enter the hashed Mac Address that you want to unban from the lobby.\r\n\r\n" + "Hashed Mac Addresses should be entered in this format: $1$MH$345ntXD4G3AKpAeHZdaGe3", ""); if (mac == null || mac.length() < 1) { return; } final String prefix = MD5Crypt.MAGIC + "MH$"; final String error; if (mac.length() != 28) { error = "Must be 28 characters long"; } else if (!mac.startsWith(prefix)) { error = "Must start with: " + prefix; } else if (!mac.matches("[0-9a-zA-Z$./]+")) { error = "Must use only these characters: 0-9a-zA-Z$./"; } else { error = null; } if (error != null) { if (JOptionPane.showConfirmDialog(m_frame, "The hashed Mac Address you entered is invalid (" + error + "). Do you want to ban it anyhow?", "Invalid Hashed Mac", JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) { return; } } final IModeratorController controller = (IModeratorController) m_frame.getLobbyClient().getMessengers() .getRemoteMessenger().getRemote(ModeratorController.getModeratorControllerName()); try { controller.banMac(new Node("None (Admin menu originated unban)", InetAddress.getByName("0.0.0.0"), 0), mac, new Date(0)); } catch (final UnknownHostException ex) { ClientLogger.logQuietly(ex); } }); item.setEnabled(true); parentMenu.add(item); } private long requestTimespanSupplication() { final List<String> timeUnits = new ArrayList<>(); timeUnits.add("Minute"); timeUnits.add("Hour"); timeUnits.add("Day"); timeUnits.add("Week"); timeUnits.add("Month"); timeUnits.add("Year"); timeUnits.add("Forever"); final int result = JOptionPane.showOptionDialog(m_frame, "Select the unit of measurement: ", "Select Timespan Unit", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, timeUnits.toArray(), timeUnits.toArray()[3]); if (result < 0) { return -1; } final String selectedTimeUnit = (String) timeUnits.toArray()[result]; if (selectedTimeUnit.equals("Forever")) { return Long.MAX_VALUE; } final String stringr = JOptionPane.showInputDialog(m_frame, "Now please enter the length of time: (In " + selectedTimeUnit + "s) ", 1); if (stringr == null) { return -1; } final long result2 = Long.parseLong(stringr); if (result2 < 0) { return -1; } long ticks = 0; if (selectedTimeUnit.equals("Minute")) { ticks = result2 * 1000 * 60; } else if (selectedTimeUnit.equals("Hour")) { ticks = result2 * 1000 * 60 * 60; } else if (selectedTimeUnit.equals("Day")) { ticks = result2 * 1000 * 60 * 60 * 24; } else if (selectedTimeUnit.equals("Week")) { ticks = result2 * 1000 * 60 * 60 * 24 * 7; } else if (selectedTimeUnit.equals("Month")) { ticks = result2 * 1000 * 60 * 60 * 24 * 30; } else if (selectedTimeUnit.equals("Year")) { ticks = result2 * 1000 * 60 * 60 * 24 * 365; } return ticks; } private void createSettingsMenu(final LobbyMenu menuBar) { final JMenu settings = new JMenu("Settings"); menuBar.add(settings); SoundOptions.addGlobalSoundSwitchMenu(settings); SoundOptions.addToMenu(settings); addChatTimeMenu(settings); } private static void createHelpMenu(final LobbyMenu menuBar) { final JMenu help = new JMenu("Help"); menuBar.add(help); addHelpMenu(help); } private static void addHelpMenu(final JMenu parentMenu) { final JMenuItem hostingLink = new JMenuItem("How to host"); hostingLink.addActionListener(e -> SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.GITHUB_HOSTING)); parentMenu.add(hostingLink); final JMenuItem helpPageLink = new JMenuItem("Help Page"); helpPageLink.addActionListener(e -> SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.GITHUB_HELP)); parentMenu.add(helpPageLink); final JMenuItem lobbyRules = new JMenuItem("Lobby Rules"); lobbyRules.addActionListener( e -> SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.TRIPLEA_LOBBY_RULES)); parentMenu.add(lobbyRules); final JMenuItem warClub = new JMenuItem("TripleA Forum"); warClub.addActionListener(e -> SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.TRIPLEA_FORUM)); parentMenu.add(warClub); } private void addChatTimeMenu(final JMenu parentMenu) { final JCheckBoxMenuItem chatTimeBox = new JCheckBoxMenuItem("Show Chat Times"); chatTimeBox.addActionListener(e -> m_frame.setShowChatTime(chatTimeBox.isSelected())); chatTimeBox.setSelected(true); parentMenu.add(chatTimeBox); } private void addUpdateAccountMenu(final JMenu account) { final JMenuItem update = new JMenuItem("Update Account..."); // only if we are not anonymous login update.setEnabled(!m_frame.getLobbyClient().isAnonymousLogin()); update.addActionListener(e -> updateAccountDetails()); account.add(update); } private void updateAccountDetails() { final IUserManager manager = (IUserManager) m_frame.getLobbyClient().getRemoteMessenger().getRemote(IUserManager.USER_MANAGER); final DBUser user = manager.getUserInfo(m_frame.getLobbyClient().getMessenger().getLocalNode().getName()); if (user == null) { JOptionPane.showMessageDialog(this, "No user info found", "Error", JOptionPane.ERROR_MESSAGE); return; } final CreateUpdateAccountPanel panel = CreateUpdateAccountPanel.newUpdatePanel(user); final CreateUpdateAccountPanel.ReturnValue rVal = panel.show(m_frame); if (rVal == CreateUpdateAccountPanel.ReturnValue.CANCEL) { return; } final String error = manager.updateUser(panel.getUserName(), panel.getEmail(), MD5Crypt.crypt(panel.getPassword())); if (error != null) { JOptionPane.showMessageDialog(this, error, "Error", JOptionPane.ERROR_MESSAGE); } } private void createFileMenu(final JMenuBar menuBar) { final JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); addExitMenu(fileMenu); } private void addExitMenu(final JMenu parentMenu) { final boolean isMac = SystemProperties.isMac(); // Mac OS X automatically creates a Quit menu item under the TripleA menu, // so all we need to do is register that menu item with triplea's shutdown mechanism if (!isMac) { // On non-Mac operating systems, we need to manually create an Exit menu item final JMenuItem menuFileExit = new JMenuItem(SwingAction.of("Exit", e -> m_frame.shutdown())); parentMenu.add(menuFileExit); } } }