Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 106356 Details for
Bug 4922
[EditorMgmt] Need ability to open a file in eclipse from the command line
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Simple socket solution
patch.txt (text/plain), 39.73 KB, created by
John Arthorne
on 2008-07-02 16:36:56 EDT
(
hide
)
Description:
Simple socket solution
Filename:
MIME Type:
Creator:
John Arthorne
Created:
2008-07-02 16:36:56 EDT
Size:
39.73 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.ui.ide >Index: src/org/eclipse/ui/internal/ide/ChooseWorkspaceData.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceData.java,v >retrieving revision 1.21 >diff -u -r1.21 ChooseWorkspaceData.java >--- src/org/eclipse/ui/internal/ide/ChooseWorkspaceData.java 24 Mar 2008 19:13:35 -0000 1.21 >+++ src/org/eclipse/ui/internal/ide/ChooseWorkspaceData.java 2 Jul 2008 20:29:53 -0000 >@@ -69,7 +69,7 @@ > /** > * This is the second version of the encode/decode protocol that uses the > * confi area preferences store for persistence. This version is the same as >- * the previous version except it uses a \n character to seperate the path >+ * the previous version except it uses a \n character to separate the path > * entries instead of commas. (see bug 98467) > * > * @since 3.3.1 >@@ -83,6 +83,18 @@ > private String selection; > > private String[] recentWorkspaces; >+ >+ /** >+ * The port on which an instance of this configuration is already listening for remote communication. >+ * This value is 0 if nobody is already listening. >+ */ >+ private int port = 0; >+ /** >+ * An authorization integer that a client must provide when communication with >+ * this application. This is a simple security measure to prevent a port scanner >+ * from executing commands in this application. >+ */ >+ private int ipcAuth = 0; > > // xml tags > private static interface XML { >@@ -101,7 +113,11 @@ > public static final String MAX_LENGTH = "maxLength"; //$NON-NLS-1$ > > public static final String PATH = "path"; //$NON-NLS-1$ >- } >+ >+ public static final String PORT= "port"; //$NON-NLS-1$ >+ >+ public static final String IPC_AUTH= "ipcAuth"; //$NON-NLS-1$ >+} > > /** > * Creates a new instance, loading persistent data if its found. >@@ -151,6 +167,23 @@ > } > initialDefault = dir; > } >+ >+ /** >+ * Sets the port on which an instance is listening for remote communication. >+ * @param port The port, or 0 to indicate not listening. >+ */ >+ public void setPort(int port) { >+ this.port = port; >+ } >+ >+ /** >+ * Sets an authorization integer that a client must provide to establish >+ * remote communication. This is used to prevent a port sniffer from >+ * executing commands. >+ */ >+ public void setIPCAuthorization(int auth) { >+ this.ipcAuth = auth; >+ } > > /** > * Return the currently selected workspace or null if nothing is selected. >@@ -173,6 +206,23 @@ > public String[] getRecentWorkspaces() { > return recentWorkspaces; > } >+ >+ /** >+ * Returns the port on which an instance of this same configuration is >+ * already listening for remote communication, or 0 if nobody is listening. >+ * @return The port number, or 0. >+ */ >+ public int getPort() { >+ return port; >+ } >+ >+ /** >+ * Returns the authorization integer for establishing interprocess communication. >+ * @return The authorization integer >+ */ >+ public int getIPCAuthorization() { >+ return ipcAuth; >+ } > > /** > * The argument workspace has been selected, update the receiver. Does not >@@ -230,8 +280,14 @@ > // 5. store the protocol version used to encode the list > node.putInt(IDE.Preferences.RECENT_WORKSPACES_PROTOCOL, > PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS); >+ >+ // 6. store the interprocess communication data, if any >+ if (port != 0) { >+ node.putInt(XML.PORT, port); >+ node.putInt(XML.IPC_AUTH, ipcAuth); >+ } > >- // 6. store the node >+ // 7. store the node > try { > node.flush(); > } catch (BackingStoreException e) { >@@ -405,6 +461,10 @@ > .getString(IDE.Preferences.RECENT_WORKSPACES); > recentWorkspaces = decodeStoredWorkspacePaths(protocol, max, workspacePathPref); > >+ // 5. load the interprocess communication data >+ port = store.getInt(XML.PORT); >+ ipcAuth = store.getInt(XML.IPC_AUTH); >+ > return true; > } > >#P org.eclipse.ui.ide.application >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF,v >retrieving revision 1.8 >diff -u -r1.8 MANIFEST.MF >--- META-INF/MANIFEST.MF 1 May 2008 14:01:17 -0000 1.8 >+++ META-INF/MANIFEST.MF 2 Jul 2008 20:29:53 -0000 >@@ -13,7 +13,8 @@ > org.eclipse.ui.navigator.resources;bundle-version="[3.2.100,4.0.0)", > org.eclipse.core.net;bundle-version="[1.0.0,2.0.0)", > org.eclipse.update.core;bundle-version="[3.1.100,4.0.0)", >- com.ibm.icu;bundle-version="3.8.1" >+ com.ibm.icu;bundle-version="3.8.1", >+ org.eclipse.core.filesystem;bundle-version="1.2.0" > Export-Package: org.eclipse.ui.internal.ide.application;x-internal:=true, > org.eclipse.ui.internal.ide.application.dialogs;x-internal:=true > Bundle-RequiredExecutionEnvironment: J2SE-1.4 >Index: src/org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java,v >retrieving revision 1.13 >diff -u -r1.13 IDEWorkbenchAdvisor.java >--- src/org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java 1 May 2008 14:01:17 -0000 1.13 >+++ src/org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java 2 Jul 2008 20:29:53 -0000 >@@ -10,34 +10,18 @@ > *******************************************************************************/ > package org.eclipse.ui.internal.ide.application; > >+import org.eclipse.ui.PartInitException; >+ >+import com.ibm.icu.text.Collator; > import java.lang.reflect.InvocationTargetException; > import java.net.URL; >-import java.util.ArrayList; >-import java.util.Iterator; >-import java.util.Map; >-import java.util.TreeMap; >- >+import java.util.*; >+import org.eclipse.core.filesystem.EFS; > import org.eclipse.core.net.proxy.IProxyService; >-import org.eclipse.core.resources.IContainer; >-import org.eclipse.core.resources.IResource; >-import org.eclipse.core.resources.ResourcesPlugin; >-import org.eclipse.core.resources.WorkspaceJob; >-import org.eclipse.core.runtime.CoreException; >-import org.eclipse.core.runtime.FileLocator; >-import org.eclipse.core.runtime.IAdaptable; >-import org.eclipse.core.runtime.IBundleGroup; >-import org.eclipse.core.runtime.IBundleGroupProvider; >-import org.eclipse.core.runtime.IProgressMonitor; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.MultiStatus; >-import org.eclipse.core.runtime.Path; >-import org.eclipse.core.runtime.Platform; >-import org.eclipse.core.runtime.Status; >+import org.eclipse.core.resources.*; >+import org.eclipse.core.runtime.*; > import org.eclipse.core.runtime.jobs.Job; >-import org.eclipse.jface.dialogs.ErrorDialog; >-import org.eclipse.jface.dialogs.IDialogSettings; >-import org.eclipse.jface.dialogs.MessageDialog; >-import org.eclipse.jface.dialogs.TrayDialog; >+import org.eclipse.jface.dialogs.*; > import org.eclipse.jface.operation.IRunnableWithProgress; > import org.eclipse.jface.preference.IPreferenceStore; > import org.eclipse.jface.resource.ImageDescriptor; >@@ -46,23 +30,11 @@ > import org.eclipse.swt.SWT; > import org.eclipse.swt.widgets.Display; > import org.eclipse.swt.widgets.Listener; >-import org.eclipse.ui.PlatformUI; >-import org.eclipse.ui.application.IWorkbenchConfigurer; >-import org.eclipse.ui.application.IWorkbenchWindowConfigurer; >-import org.eclipse.ui.application.WorkbenchAdvisor; >-import org.eclipse.ui.application.WorkbenchWindowAdvisor; >+import org.eclipse.ui.*; >+import org.eclipse.ui.application.*; > import org.eclipse.ui.ide.IDE; >-import org.eclipse.ui.internal.ISelectionConversionService; >-import org.eclipse.ui.internal.PluginActionBuilder; >-import org.eclipse.ui.internal.Workbench; >-import org.eclipse.ui.internal.ide.AboutInfo; >-import org.eclipse.ui.internal.ide.IDEInternalPreferences; >-import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages; >-import org.eclipse.ui.internal.ide.IDESelectionConversionService; >-import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper; >-import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler; >-import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; >-import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; >+import org.eclipse.ui.internal.*; >+import org.eclipse.ui.internal.ide.*; > import org.eclipse.ui.internal.ide.model.WorkbenchAdapterBuilder; > import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor; > import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog; >@@ -70,11 +42,7 @@ > import org.eclipse.ui.statushandlers.AbstractStatusHandler; > import org.eclipse.ui.statushandlers.StatusManager; > import org.eclipse.update.core.SiteManager; >-import org.osgi.framework.Bundle; >-import org.osgi.framework.ServiceReference; >-import org.osgi.framework.Version; >- >-import com.ibm.icu.text.Collator; >+import org.osgi.framework.*; > > /** > * IDE-specified workbench advisor which configures the workbench for use as an >@@ -128,7 +96,7 @@ > private IDEIdleHelper idleHelper; > > private Listener settingsChangeListener; >- >+ > /** > * Support class for monitoring workspace changes and periodically > * validating the undo history >@@ -140,6 +108,10 @@ > */ > private AbstractStatusHandler ideWorkbenchErrorHandler; > >+ static IDEWorkbenchAdvisor getInstance() { >+ return workbenchAdvisor; >+ } >+ > /** > * Creates a new workbench advisor instance. > */ >@@ -159,7 +131,7 @@ > public void initialize(IWorkbenchConfigurer configurer) { > > PluginActionBuilder.setAllowIdeLogging(true); >- >+ > // make sure we always save and restore workspace state > configurer.setSaveAndRestore(true); > >@@ -186,7 +158,6 @@ > } > } > >- // register shared images > declareWorkbenchImages(); > > // initialize the activity helper >@@ -194,7 +165,7 @@ > > // initialize idle handler > idleHelper = new IDEIdleHelper(configurer); >- >+ > // initialize the workspace undo monitor > workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance(); > >@@ -215,14 +186,10 @@ > Job.getJobManager().suspend(); > > // Register the build actions >- IProgressService service = PlatformUI.getWorkbench() >- .getProgressService(); >- ImageDescriptor newImage = IDEInternalWorkbenchImages >- .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); >- service.registerIconForFamily(newImage, >- ResourcesPlugin.FAMILY_MANUAL_BUILD); >- service.registerIconForFamily(newImage, >- ResourcesPlugin.FAMILY_AUTO_BUILD); >+ IProgressService service = PlatformUI.getWorkbench().getProgressService(); >+ ImageDescriptor newImage = IDEInternalWorkbenchImages.getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); >+ service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD); >+ service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD); > } > > /* >@@ -235,19 +202,50 @@ > refreshFromLocal(); > activateProxyService(); > checkUpdates(); >- ((Workbench) PlatformUI.getWorkbench()).registerService( >- ISelectionConversionService.class, >- new IDESelectionConversionService()); >+ ((Workbench) PlatformUI.getWorkbench()).registerService(ISelectionConversionService.class, new IDESelectionConversionService()); > > initializeSettingsChangeListener(); >- Display.getCurrent().addListener(SWT.Settings, >- settingsChangeListener); >+ Display.getCurrent().addListener(SWT.Settings, settingsChangeListener); >+ runStartupCommand(Platform.getCommandLineArgs()); > } finally {// Resume background jobs after we startup > Job.getJobManager().resume(); > } > } > > /** >+ * Runs a command specified on the command line, if any >+ */ >+ boolean runStartupCommand(String[] arguments) { >+ if (arguments.length == 0) >+ return false; >+ //if the last command line argument is a file, open that file in an editor >+ final IPath path = new Path(arguments[arguments.length - 1]); >+ if (!path.toFile().exists()) >+ return false; >+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); >+ if (window == null) { >+ IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); >+ if (windows.length > 0) >+ window = windows[0]; >+ } >+ if (window == null) >+ return false; >+ final IWorkbenchPage page = window.getActivePage(); >+ if (page == null) >+ return false; >+ window.getShell().getDisplay().syncExec(new Runnable() { >+ public void run() { >+ try { >+ IDE.openEditorOnFileStore(page, EFS.getLocalFileSystem().getStore(path)); >+ } catch (PartInitException e) { >+ IDEWorkbenchPlugin.log("Error opening editor on path: " + path, e); //$NON-NLS-1$ >+ } >+ } >+ }); >+ return true; >+ } >+ >+ /** > * Activate the proxy service by obtaining it. > */ > private void activateProxyService() { >@@ -260,7 +258,7 @@ > } > if (proxyService == null) { > IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$ >- } >+ } > } > > /** >@@ -269,8 +267,7 @@ > private void initializeSettingsChangeListener() { > settingsChangeListener = new Listener() { > >- boolean currentHighContrast = Display.getCurrent() >- .getHighContrast(); >+ boolean currentHighContrast = Display.getCurrent().getHighContrast(); > > public void handleEvent(org.eclipse.swt.widgets.Event event) { > if (Display.getCurrent().getHighContrast() == currentHighContrast) >@@ -279,13 +276,7 @@ > currentHighContrast = !currentHighContrast; > > // make sure they really want to do this >- if (new MessageDialog(null, >- IDEWorkbenchMessages.SystemSettingsChange_title, null, >- IDEWorkbenchMessages.SystemSettingsChange_message, >- MessageDialog.QUESTION, new String[] { >- IDEWorkbenchMessages.SystemSettingsChange_yes, >- IDEWorkbenchMessages.SystemSettingsChange_no }, >- 1).open() == Window.OK) { >+ if (new MessageDialog(null, IDEWorkbenchMessages.SystemSettingsChange_title, null, IDEWorkbenchMessages.SystemSettingsChange_message, MessageDialog.QUESTION, new String[] {IDEWorkbenchMessages.SystemSettingsChange_yes, IDEWorkbenchMessages.SystemSettingsChange_no}, 1).open() == Window.OK) { > PlatformUI.getWorkbench().restart(); > } > } >@@ -322,8 +313,7 @@ > * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown() > */ > public boolean preShutdown() { >- Display.getCurrent().removeListener(SWT.Settings, >- settingsChangeListener); >+ Display.getCurrent().removeListener(SWT.Settings, settingsChangeListener); > return super.preShutdown(); > } > >@@ -332,8 +322,7 @@ > * > * @see org.eclipse.ui.application.WorkbenchAdvisor#createWorkbenchWindowAdvisor(org.eclipse.ui.application.IWorkbenchWindowConfigurer) > */ >- public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( >- IWorkbenchWindowConfigurer configurer) { >+ public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { > return new IDEWorkbenchWindowAdvisor(this, configurer); > } > >@@ -343,16 +332,13 @@ > * @return boolean > */ > public boolean hasIntro() { >- return getWorkbenchConfigurer().getWorkbench().getIntroManager() >- .hasIntro(); >+ return getWorkbenchConfigurer().getWorkbench().getIntroManager().hasIntro(); > } > > private void refreshFromLocal() { > String[] commandLineArgs = Platform.getCommandLineArgs(); >- IPreferenceStore store = IDEWorkbenchPlugin.getDefault() >- .getPreferenceStore(); >- boolean refresh = store >- .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP); >+ IPreferenceStore store = IDEWorkbenchPlugin.getDefault().getPreferenceStore(); >+ boolean refresh = store.getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP); > if (!refresh) { > return; > } >@@ -366,8 +352,7 @@ > > final IContainer root = ResourcesPlugin.getWorkspace().getRoot(); > Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) { >- public IStatus runInWorkspace(IProgressMonitor monitor) >- throws CoreException { >+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { > root.refreshLocal(IResource.DEPTH_INFINITE, monitor); > return Status.OK_STATUS; > } >@@ -381,14 +366,11 @@ > */ > private void disconnectFromWorkspace() { > // save the workspace >- final MultiStatus status = new MultiStatus( >- IDEWorkbenchPlugin.IDE_WORKBENCH, 1, >- IDEWorkbenchMessages.ProblemSavingWorkbench, null); >+ final MultiStatus status = new MultiStatus(IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.ProblemSavingWorkbench, null); > IRunnableWithProgress runnable = new IRunnableWithProgress() { > public void run(IProgressMonitor monitor) { > try { >- status.merge(ResourcesPlugin.getWorkspace().save(true, >- monitor)); >+ status.merge(ResourcesPlugin.getWorkspace().save(true, monitor)); > } catch (CoreException e) { > status.merge(e.getStatus()); > } >@@ -397,22 +379,13 @@ > try { > new ProgressMonitorJobsDialog(null).run(true, false, runnable); > } catch (InvocationTargetException e) { >- status >- .merge(new Status(IStatus.ERROR, >- IDEWorkbenchPlugin.IDE_WORKBENCH, 1, >- IDEWorkbenchMessages.InternalError, e >- .getTargetException())); >+ status.merge(new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.InternalError, e.getTargetException())); > } catch (InterruptedException e) { >- status.merge(new Status(IStatus.ERROR, >- IDEWorkbenchPlugin.IDE_WORKBENCH, 1, >- IDEWorkbenchMessages.InternalError, e)); >- } >- ErrorDialog.openError(null, >- IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status, >- IStatus.ERROR | IStatus.WARNING); >+ status.merge(new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.InternalError, e)); >+ } >+ ErrorDialog.openError(null, IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status, IStatus.ERROR | IStatus.WARNING); > if (!status.isOK()) { >- IDEWorkbenchPlugin.log( >- IDEWorkbenchMessages.ProblemsSavingWorkspace, status); >+ IDEWorkbenchPlugin.log(IDEWorkbenchMessages.ProblemsSavingWorkspace, status); > } > } > >@@ -519,8 +492,7 @@ > */ > private Map createNewBundleGroupsMap() { > // retrieve list of installed bundle groups from last session >- IDialogSettings settings = IDEWorkbenchPlugin.getDefault() >- .getDialogSettings(); >+ IDialogSettings settings = IDEWorkbenchPlugin.getDefault().getDialogSettings(); > String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES); > > // get a map of currently installed bundle groups and store it for next >@@ -573,85 +545,41 @@ > > Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH); > >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL >- + "build_exec.gif", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER, >- PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED, >- PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL >- + "search_src.gif", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER, >- PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED, >- PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL >- + "next_nav.gif", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL >- + "prev_nav.gif", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN >- + "newprj_wiz.png", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ, >- PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN >- + "newfile_wiz.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ, >- PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ, >- PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ, >- PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ, >- PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ, >- PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN >- + "saveas_wiz.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN >- + "quick_fix.png", false); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT, >- PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT >- + "cprj_obj.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER, >- PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED, >- PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED, >- PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER, PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED, PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER, PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED, PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL + "next_nav.gif", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL + "prev_nav.gif", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN + "newprj_wiz.png", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ, PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN + "newfile_wiz.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ, PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ, PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ, PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ, PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ, PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN + "saveas_wiz.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN + "quick_fix.png", false); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT, PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT + "cprj_obj.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER, PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED, PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED, PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ > > // task objects > // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK, >@@ -661,43 +589,21 @@ > // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK, > // PATH_OBJECT+"lprio_tsk.gif"); > >- declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK, >- PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK, >- PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT >- + "complete_tsk.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT >- + "incomplete_tsk.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT >- + "welcome_item.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT >- + "welcome_banner.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT >- + "error_tsk.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT >- + "warn_tsk.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT >- + "info_tsk.gif", true); //$NON-NLS-1$ >- >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL >- + "flatLayout.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT, >- PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$ >- declareWorkbenchImage(ideBundle, >- IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY, >- PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$ >- >+ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK, PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK, PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT + "complete_tsk.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT + "incomplete_tsk.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT + "welcome_item.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT + "welcome_banner.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT + "error_tsk.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT + "warn_tsk.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT + "info_tsk.gif", true); //$NON-NLS-1$ >+ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL + "flatLayout.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT, PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$ >+ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY, PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$ >+ > // synchronization indicator objects > // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT, > // PATH_OVERLAY+"wbet_stat.gif"); >@@ -728,8 +634,7 @@ > * <code>false</code> if this is not a shared image > * @see IWorkbenchConfigurer#declareImage > */ >- private void declareWorkbenchImage(Bundle ideBundle, String symbolicName, >- String path, boolean shared) { >+ private void declareWorkbenchImage(Bundle ideBundle, String symbolicName, String path, boolean shared) { > URL url = FileLocator.find(ideBundle, new Path(path), null); > ImageDescriptor desc = ImageDescriptor.createFromURL(url); > getWorkbenchConfigurer().declareImage(symbolicName, desc, shared); >@@ -765,8 +670,7 @@ > ArrayList list = new ArrayList(m.size()); > for (Iterator i = m.values().iterator(); i.hasNext();) { > AboutInfo info = (AboutInfo) i.next(); >- if (info != null && info.getWelcomePerspectiveId() != null >- && info.getWelcomePageURL() != null) { >+ if (info != null && info.getWelcomePerspectiveId() != null && info.getWelcomePageURL() != null) { > list.add(info); > } > } >@@ -784,8 +688,7 @@ > */ > public AbstractStatusHandler getWorkbenchErrorHandler() { > if (ideWorkbenchErrorHandler == null) { >- ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler( >- getWorkbenchConfigurer()); >+ ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler(getWorkbenchConfigurer()); > } > return ideWorkbenchErrorHandler; > } >Index: src/org/eclipse/ui/internal/ide/application/IDEApplication.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java,v >retrieving revision 1.7 >diff -u -r1.7 IDEApplication.java >--- src/org/eclipse/ui/internal/ide/application/IDEApplication.java 3 Jun 2008 17:56:02 -0000 1.7 >+++ src/org/eclipse/ui/internal/ide/application/IDEApplication.java 2 Jul 2008 20:29:53 -0000 >@@ -105,7 +105,7 @@ > Platform.endSplash(); > return EXIT_OK; > } >- >+ > // create the workbench with this advisor and run it until it exits > // N.B. createWorkbench remembers the advisor, and also registers > // the workbench globally so that all UI plug-ins can find it using >@@ -217,6 +217,15 @@ > // -data @noDefault or -data not specified, prompt and set > ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc > .getDefault()); >+ >+ //check if someone is listening that we can pass our command line to >+ if (launchData.getPort() != 0) { >+ if (new IDECommunication().writeToPort(launchData.getPort(), launchData.getIPCAuthorization())) { >+ //we successfully punted this application's command line to another instance, >+ //so we can just shutdown this instance. >+ return false; >+ } >+ } > > boolean force = false; > while (true) { >@@ -233,6 +242,11 @@ > // the operation will fail if the url is not a valid > // instance data area, so other checking is unneeded > if (instanceLoc.setURL(workspaceUrl, true)) { >+ int[] ipcData = new IDECommunication().listen(); >+ if (ipcData != null) { >+ launchData.setPort(ipcData[0]); >+ launchData.setIPCAuthorization(ipcData[1]); >+ } > launchData.writePersistedData(); > writeWorkspaceVersion(); > return true; >Index: src/org/eclipse/ui/internal/ide/application/IDECommunication.java >=================================================================== >RCS file: src/org/eclipse/ui/internal/ide/application/IDECommunication.java >diff -N src/org/eclipse/ui/internal/ide/application/IDECommunication.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/ui/internal/ide/application/IDECommunication.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,208 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.ui.internal.ide.application; >+ >+import java.security.SecureRandom; >+ >+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; >+ >+import java.io.*; >+import java.net.*; >+import org.eclipse.core.runtime.*; >+import org.eclipse.core.runtime.jobs.Job; >+ >+/** >+ * A helper class that deals with interprocess communication between applications. >+ * <p> >+ * This class uses a socket connection on a random available port to establish >+ * communication between applications. The client must provide an authorization >+ * code to protect against communication from arbitrary port sniffing applications. >+ * >+ * @since 3.5 >+ */ >+class IDECommunication { >+ /** >+ * A job that listens on a socket for a command, and then invokes the >+ * workbench advisor to handle the command. >+ */ >+ class ListenJob extends Job { >+ private ServerSocket server; >+ private int auth; >+ >+ public ListenJob(ServerSocket server, int auth) { >+ super("Listen"); //$NON-NLS-1$ >+ this.server = server; >+ this.auth = auth; >+ setSystem(true); >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.core.runtime.jobs.Job#canceling() >+ */ >+ protected void canceling() { >+ try { >+ server.close(); >+ } catch (IOException e) { >+ //ignore >+ } >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) >+ */ >+ protected IStatus run(IProgressMonitor monitor) { >+ if (server.isClosed()) >+ return Status.OK_STATUS; >+ Socket client = null; >+ DataInputStream in = null; >+ DataOutputStream out = null; >+ try { >+ client = server.accept(); >+ in = new DataInputStream(client.getInputStream()); >+ out = new DataOutputStream(client.getOutputStream()); >+ //read the protocol version >+ int version = in.readInt(); >+ String[] args = null; >+ if (version == PROTOCOL_VERSION_ONE) { >+ //read the authorization checksum >+ int receivedAuth = in.readInt(); >+ //abort immediately if we failed to read the authorization integer >+ if (receivedAuth != auth) { >+ schedule(SCHEDULE_DELAY); >+ return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, "Connection from unauthorized client on port " + server.getLocalPort()); //$NON-NLS-1$ >+ } >+ args = new String[in.readInt()]; >+ for (int i = 0; i < args.length; i++) { >+ args[i] = in.readUTF(); >+ } >+ } >+ //pass the read arguments to the workbench advisor >+ IDEWorkbenchAdvisor advisor = IDEWorkbenchAdvisor.getInstance(); >+ if (advisor != null && args != null) { >+ if (advisor.runStartupCommand(args)) >+ out.writeUTF(OK); >+ else >+ out.writeUTF(FAIL); >+ } >+ } catch (IOException e) { >+ IDEWorkbenchPlugin.log("Error communicating with client", e); //$NON-NLS-1$ >+ } finally { >+ safeClose(in); >+ safeClose(out); >+ safeClose(client); >+ } >+ //reschedule >+ schedule(SCHEDULE_DELAY); >+ return Status.OK_STATUS; >+ } >+ } >+ >+ /** >+ * The first communication protocol version. This version contains an authorization >+ * integer followed by a list of command line arguments. The format is: int authorizationId, int N, String[N]. >+ */ >+ private static final int PROTOCOL_VERSION_ONE = 1; >+ >+ private static final long SCHEDULE_DELAY = 1000; >+ >+ static final String OK = "OK"; //$NON-NLS-1$ >+ static final String FAIL = "FAIL"; //$NON-NLS-1$ >+ >+ /** >+ * Start listening for commands. >+ * @return An integer array of size two. The first integer is the port >+ * number we are listening on, and the second integer is an authorization >+ * integer used to validate connections. Returns <code>null</code> if >+ * there was a failure to establish communication >+ */ >+ public int[] listen() { >+ try { >+ ServerSocket server = new ServerSocket(0); >+ int auth = new SecureRandom().nextInt(); >+ new ListenJob(server, auth).schedule(SCHEDULE_DELAY); >+ return new int[] {server.getLocalPort(), auth}; >+ } catch (IOException e) { >+ return null; >+ } >+ } >+ >+ /** >+ * Close the given stream and ignore secondary failures. >+ */ >+ void safeClose(DataInputStream in) { >+ try { >+ if (in != null) >+ in.close(); >+ } catch (IOException e) { >+ //ignore secondary failure while closing >+ } >+ } >+ >+ /** >+ * Close the given stream and ignore secondary failures. >+ */ >+ void safeClose(DataOutputStream out) { >+ try { >+ if (out != null) >+ out.close(); >+ } catch (IOException e) { >+ //ignore secondary failure while closing >+ } >+ } >+ >+ /** >+ * Close the given socket and ignore secondary failures. >+ */ >+ void safeClose(Socket socket) { >+ try { >+ if (socket != null) >+ socket.close(); >+ } catch (IOException e) { >+ //ignore secondary failure while closing >+ } >+ } >+ >+ /** >+ * Writes this application's command line arguments to the given port. >+ * >+ * @param port The port to write data to >+ * @param auth The authorization integer >+ * @return <code>true</code> if written successfully, and <code>false</code> otherwise. >+ */ >+ public boolean writeToPort(int port, int auth) { >+ Socket socket = null; >+ DataOutputStream out = null; >+ DataInputStream in = null; >+ try { >+ socket = new Socket("localhost", port);//$NON-NLS-1$ >+ out = new DataOutputStream(socket.getOutputStream()); >+ in = new DataInputStream(socket.getInputStream()); >+ out.writeInt(PROTOCOL_VERSION_ONE); >+ out.writeInt(auth); >+ String[] args = Platform.getCommandLineArgs(); >+ out.writeInt(args.length); >+ for (int i = 0; i < args.length; i++) >+ out.writeUTF(args[i]); >+ //server will return OK or FAIL >+ return in.readUTF().equals(OK); >+ } catch (UnknownHostException e) { >+ return false; >+ } catch (IOException e) { >+ return false; >+ } finally { >+ safeClose(socket); >+ safeClose(out); >+ safeClose(in); >+ } >+ } >+ >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 4922
:
83454
|
104405
|
104406
|
106356
|
106360
|
156681
|
156974
|
156991