/* * * Panbox - encryption for cloud storage * Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Additonally, third party code may be provided with notices and open source * licenses from communities and third parties that govern the use of those * portions, and any licenses granted hereunder do not alter any rights and * obligations you may have under such open source licenses, however, the * disclaimer of warranty and limitation of liability provisions of the GPLv3 * will apply to all the product. * */ package org.panbox.desktop.windows.client; import java.awt.AWTException; import java.awt.Image; import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.BindException; import java.text.MessageFormat; import java.util.Collections; import java.util.List; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.PatternLayout; import org.apache.log4j.RollingFileAppender; import org.panbox.PanboxConstants; import org.panbox.Settings; import org.panbox.core.keymgmt.VolumeParams.VolumeParamsFactory; import org.panbox.desktop.common.clipboard.ClipboardHandler; import org.panbox.desktop.common.clipboard.ClipboardObserver; import org.panbox.desktop.common.devicemgmt.DeviceManagerException; import org.panbox.desktop.common.gui.AboutWindow; import org.panbox.desktop.common.gui.OperationAbortedException; import org.panbox.desktop.common.gui.PanboxClientGUI; import org.panbox.desktop.common.gui.shares.PanboxShare; import org.panbox.desktop.common.sharemgmt.IPanboxService; import org.panbox.desktop.common.sharemgmt.ShareManagerException; import org.panbox.desktop.common.urihandler.PanboxHTTPServer; import org.panbox.desktop.common.utils.DesktopApi; public class PanboxClient extends org.panbox.desktop.common.PanboxClient { static { try { File programDataFolder = new File(System.getenv("APPDATA") + "\\Panbox.org\\Panbox\\"); if (!programDataFolder.exists()) { if (!programDataFolder.mkdirs()) { System.err .println("Failed to create subdir in ProgramData: " + programDataFolder.getAbsolutePath()); } else { System.out.println("Created subdir in ProgramData"); } } File logFile = new File(programDataFolder, "PanboxWindowsClient.log"); PatternLayout layout = new PatternLayout("%d %-5p [%t]: %m%n"); logger.setLevel(Level.ALL); logger.addAppender(new ConsoleAppender(new PatternLayout())); logger.addAppender(new RollingFileAppender(layout, logFile .getAbsolutePath(), true)); } catch (IOException ex) { System.err .println("Failed to add appender for logging files! Logging might not be available!"); logger.error( "PanboxClient : Failed to add appender for logging files!", ex); } logger.debug("PanboxClient : Class constructed"); } private static PanboxWindowsService service; public static void main(String[] args) { setGuiLookAndFeel(); // check and update MountPath for user from Version 1.0.0 (which was set to some Linux used value) if(Settings.getInstance().getMountDir().length() != 3) { Settings.getInstance().setMountDir("P:\\"); logger.warn("PanboxClient : Detected old mount point configuration. Reset mount point to drive letter P. If you want to reconfigure this please change the mount directory to a proper drive letter in PanBox settings."); JOptionPane.showMessageDialog(null, bundle.getString("PanboxClient.windows.resetDriveLetter")); } try { // Connect to the Panbox service service = new PanboxWindowsService(); service.startService(); PanboxClient client = new PanboxClient(service); // if initialization succeeds, we can create and set the gui PanboxClientGUI gui = new PanboxClientGUI(client); gui.setIconImage(getPanboxIcon(false)); client.registerMainwindow(gui); boolean autoStartGui = true; for (String arg : args) { if (arg.equals("minimized")) { autoStartGui = false; } } if (autoStartGui) { gui.setVisible(true); } client.executeVersionCheck(); } catch (OperationAbortedException e) { logger.error("PanboxClient : Wizard has been aborted."); System.exit(DesktopApi.EXIT_ERR_WIZARD_ABORTED); } catch (ShareManagerException | DeviceManagerException e) { logger.error( "PanboxClient : ShareManager or DeviceManager may be broken.", e); JOptionPane.showMessageDialog(null, bundle .getString("client.startup.failedCorruptManager.message"), bundle.getString("client.startup.error.title"), JOptionPane.ERROR_MESSAGE); System.exit(DesktopApi.EXIT_ERR_SERVICE_NOT_AVAILBLE); } catch (UnsatisfiedLinkError e) { logger.error("PanboxClient : Could not find a specified library.", e); JOptionPane.showMessageDialog(null, bundle.getString("client.startup.failedToLoadLib.message"), bundle.getString("client.startup.error.title"), JOptionPane.ERROR_MESSAGE); System.exit(DesktopApi.EXIT_ERR_UNKNOWN); } catch (Exception e) { logger.error( "PanboxClient : An unknown error occurred while Panbox startup.", e); JOptionPane.showMessageDialog(null, bundle.getString("client.startup.failedUnknown.message"), bundle.getString("client.startup.error.title"), JOptionPane.ERROR_MESSAGE); System.exit(DesktopApi.EXIT_ERR_UNKNOWN); } } private static void setGuiLookAndFeel() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { logger.debug("Could not load system specific look and feel. Will use default one."); } } private final IPanboxService session; private TrayIcon trayApp; private ClipboardHandler ch; public PanboxClient(IPanboxService session) throws Exception { super(session); this.session = session; logger.debug("WIN:PanboxClient : PanboxClient"); if (splash != null) { // Splashscreen is shown! try { splash.close(); } catch( Exception e ) { // This should be ignored as this means that the splashScreen has been closed already! logger.debug("WIN:PanboxClient : Tried to close splashscreen but there was none available."); } } } private void mountShares() throws Exception { logger.debug("WIN:PanboxClient : mountShares"); } private void unmountShares() throws Exception { logger.debug("WIN:PanboxClient : unmountShares"); for (PanboxShare share : Collections.list(shareList.elements())) { VolumeParamsFactory paramsFactory = shareManager.getParamsFactory(); session.removeShare(paramsFactory.createVolumeParams() .setShareName(share.getName()).setPath(share.getPath()) .setType(share.getType())); } } private static Image getPanboxIcon(boolean trayIcon) { Image image = new ImageIcon().getImage(); try { InputStream stream = null; if (trayIcon) { stream = ClassLoader.class .getResourceAsStream("/img/panbox-trayicon.png"); } else { stream = ClassLoader.class .getResourceAsStream("/img/panbox-icon.png"); } Image loadedImage = ImageIO.read(stream); if (loadedImage != null) { image = loadedImage; } } catch (IOException e) { logger.debug("Could not obtain icon resource. Will use empty picture instead."); } return image; } private void initTray() { logger.debug("WIN:PanboxClient : initTray"); Image image = getPanboxIcon(true); trayApp = new TrayIcon(image); trayApp.setToolTip(bundle.getString("tray.toolTip")); PopupMenu popupMenu = new PopupMenu(); MenuItem showClientItem = new MenuItem( bundle.getString("tray.showPanboxClient")); MenuItem openFolderItem = new MenuItem( bundle.getString("tray.openPanboxFolder")); MenuItem aboutItem = new MenuItem(bundle.getString("tray.about")); MenuItem exitClientItem = new MenuItem(bundle.getString("tray.exit")); ActionListener showPanboxActionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logger.debug("WIN:PanboxClient : showClientItem action called"); mainWindow.setVisible(true); } }; showClientItem.addActionListener(showPanboxActionListener); openFolderItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logger.debug("WIN:PanboxClient : openFolderItem action called"); try { String mountPoint = Settings.getInstance().getMountDir(); // try to open panbox folder DesktopApi.open(new File(mountPoint)); } catch (IllegalArgumentException e1) { JOptionPane.showMessageDialog(null, bundle.getString("tray.CouldNotFindPanboxDrive"), bundle.getString("tray.PanboxError"), JOptionPane.ERROR_MESSAGE); logger.error( getClass().getName() + " : Error while determining Panbox drive on system. ", e1); } } }); aboutItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logger.debug("WIN:PanboxClient : aboutItem action called"); AboutWindow.getInstance().showWindow(5); } }); exitClientItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logger.debug("WIN:PanboxClient : exitClientItem action called"); System.exit(0); } }); popupMenu.add(showClientItem); popupMenu.addSeparator(); popupMenu.add(openFolderItem); popupMenu.addSeparator(); popupMenu.add(aboutItem); popupMenu.add(exitClientItem); trayApp.setPopupMenu(popupMenu); trayApp.addActionListener(showPanboxActionListener); SystemTray systemTray = SystemTray.getSystemTray(); try { systemTray.add(trayApp); } catch (AWTException e) { logger.debug("Could not add the PanboxClient tray app to the system tray."); System.exit(0); } trayApp.displayMessage(bundle.getString("tray.panboxStarted"), bundle.getString("tray.nowReayMessage"), MessageType.INFO); } @Override public void informAddShare(PanboxShare share) throws Exception { if (trayApp != null) { MessageFormat formatter = new MessageFormat("", Settings .getInstance().getLocale()); formatter.applyPattern(bundle.getString("tray.addedShareMessage")); trayApp.displayMessage(bundle.getString("tray.addedShare"), formatter.format(new Object[] { share.getName() }), MessageType.INFO); } } @Override public void informRemoveShare(PanboxShare share) throws Exception { if (trayApp != null) { MessageFormat formatter = new MessageFormat("", Settings .getInstance().getLocale()); formatter .applyPattern(bundle.getString("tray.removedShareMessage")); trayApp.displayMessage(bundle.getString("tray.removedShare"), formatter.format(new Object[] { share.getName() }), MessageType.INFO); } } @Override public void panboxFolderChanged(String path) { // This feature does not exist in Windows version! } @Override protected void shutdown() throws Exception { logger.debug("WIN:PanboxClient : shutdown"); unmountShares(); stopClipboardHandler(); service.shutdownService(); } @Override protected void setup() throws Exception { logger.debug("WIN:PanboxClient : setup"); initTray(); mountShares(); if (Settings.getInstance().isUriHandlerSupported()) { startURIServer(); if (Settings.getInstance().isClipboardHandlerSupported()) { startClipboardHandler(); } } } private void startClipboardHandler() { // register clipboard handler to get access to panbox urls in // clipboard ClipboardObserver co = new ClipboardObserver(); ch = new ClipboardHandler(); ch.addObserver(co); ch.start(); } private void stopClipboardHandler() { if (ch != null) ch.stop(); } private void startURIServer() { logger.debug("WIN:PanboxClient : startURIServer"); try { PanboxHTTPServer.getInstance(this).start(); } catch (BindException e) { logger.error("Error binding Panbox URI Handler to default port", e); int ret = JOptionPane.showConfirmDialog(null, MessageFormat.format( bundle.getString("PanboxClient.BindException.message"), String.valueOf(PanboxConstants.PANBOX_DEFAULT_PORT)), bundle.getString("error"), JOptionPane.YES_NO_OPTION); if (ret == JOptionPane.YES_OPTION) { Settings.getInstance().setUriHandlerSupported(false); } } catch (Exception e) { logger.error("Error starting the Panbox URI Handler", e); } } @Override public void restartTrayIcon() { logger.debug("WIN:PanboxClient : restartTrayIcon"); // This makes no sense at all because language won't change after an // update. Bundle is static and will only be reloaded in case client // will be restarted! // remove before adding the new one! // SystemTray.getSystemTray().remove(trayApp); // initTray(); } @Override protected boolean checkPanboxProcessesRunning() { return true; } @Override protected boolean mountPointHandler() { return true; } @Override protected boolean panboxMounted() { return true; } public void showTrayMessage(String title, String message, MessageType type) { trayApp.displayMessage(title, message, type); } /** * Sun property pointing the main class and its arguments. Might not be * defined on non Hotspot VM implementations. */ public static final String SUN_JAVA_COMMAND = "sun.java.command"; /** * Restart the current Java application * * @param runBeforeRestart * some custom code to be run before restarting * @throws IOException */ public void restartApplication() throws IOException { try { // java binary String java = System.getProperty("java.home") + "/bin/java"; // vm arguments List<String> vmArguments = ManagementFactory.getRuntimeMXBean() .getInputArguments(); StringBuffer vmArgsOneLine = new StringBuffer(); for (String arg : vmArguments) { // if it's the agent argument : we ignore it otherwise the // address of the old application and the new one will be in // conflict if (!arg.contains("-agentlib")) { vmArgsOneLine.append(arg); vmArgsOneLine.append(" "); } } // init the command to execute, add the vm args final StringBuffer cmd = new StringBuffer(java + " " + vmArgsOneLine); // program main and program arguments String[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split( " "); // program main is a jar if (mainCommand[0].endsWith(".jar")) { // if it's a jar, add -jar mainJar cmd.append("-jar " + new File(mainCommand[0]).getPath()); } else { // else it's a .class, add the classpath and mainClass cmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]); } // finally add program arguments for (int i = 1; i < mainCommand.length; i++) { cmd.append(" "); cmd.append(mainCommand[i]); } // execute the command in a shutdown hook, to be sure that all the // resources have been disposed before restarting the application Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { Runtime.getRuntime().exec(cmd.toString()); } catch (IOException e) { e.printStackTrace(); } } }); // // execute some custom code before restarting // if (runBeforeRestart != null) { // runBeforeRestart.run(); // } shutdown(); // exit System.exit(0); } catch (Exception e) { // something went wrong throw new IOException( "Error while trying to restart the application", e); } } @Override public void openShareFolder(String name) { logger.debug("WIN:PanboxClient : openFolderItem action called"); try { String mountPoint = Settings.getInstance().getMountDir(); // try to open panbox folder if (!DesktopApi.open(new File(mountPoint + ":\\" + System.getProperty("user.name") + File.separator + name))) { // if the folder does not exist, user does not have any // shares! open panbox drive then so user will see that // no folder exists DesktopApi.open(new File(mountPoint + File.separator + name)); } } catch (IllegalArgumentException e1) { JOptionPane.showMessageDialog(null, bundle.getString("tray.CouldNotFindPanboxDrive"), bundle.getString("tray.PanboxError"), JOptionPane.ERROR_MESSAGE); logger.error(getClass().getName() + " : Error while determining Panbox drive on system. ", e1); } } }