From c7da892cb23d50d4d85746c9a0b6b14bf570989d Mon Sep 17 00:00:00 2001 From: Adrian Dudau Date: Thu, 26 Jun 2014 13:23:09 +0200 Subject: initial commit for Enea Linux 4.0 Migrated from the internal git server on the daisy-enea branch Signed-off-by: Adrian Dudau --- tcf/lke_rse_tcf.patch | 2097 ++++++++++++++++++++++++++++++++++++++++++++ tcf/readme | 175 ++++ tcf/terminals_agent.patch | 1042 ++++++++++++++++++++++ tcf/terminals_plugin.patch | 618 +++++++++++++ 4 files changed, 3932 insertions(+) create mode 100644 tcf/lke_rse_tcf.patch create mode 100644 tcf/readme create mode 100644 tcf/terminals_agent.patch create mode 100644 tcf/terminals_plugin.patch (limited to 'tcf') diff --git a/tcf/lke_rse_tcf.patch b/tcf/lke_rse_tcf.patch new file mode 100644 index 0000000..6054b93 --- /dev/null +++ b/tcf/lke_rse_tcf.patch @@ -0,0 +1,2097 @@ +Index: plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF (working copy) +@@ -13,8 +13,16 @@ + org.eclipse.ui.views, + org.eclipse.rse.subsystems.files.core, + org.eclipse.rse.subsystems.processes.core, +- org.eclipse.rse.processes.ui ++ org.eclipse.rse.processes.ui, ++ org.eclipse.rse.subsystems.terminals.core, ++ org.eclipse.tm.tcf;bundle-version="0.3.0", ++ org.eclipse.rse.subsystems.shells.core;bundle-version="3.1.100", ++ org.eclipse.core.resources;bundle-version="3.6.0", ++ org.eclipse.tm.tcf.core;version="0.3.0" + Import-Package: org.eclipse.tm.tcf.core;version="0.3.0", ++ org.eclipse.rse.core.filters, ++ org.eclipse.tm.internal.tcf.terminals, ++ org.eclipse.rse.core.model, + org.eclipse.tm.tcf.protocol;version="0.3.0", + org.eclipse.tm.tcf.services;version="0.3.0", + org.eclipse.tm.tcf.util;version="0.3.0" +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java (working copy) +@@ -39,6 +39,11 @@ + + private final TCFFileAdapter file_adapter = new TCFFileAdapter(); + ++ public TCFFileSubSystemConfiguration() { ++ super(); ++ setIsUnixStyle(true); ++ } ++ + @Override + public ISubSystem createSubSystemInternal(IHost host) { + TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host); +@@ -78,13 +83,12 @@ + @Override + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance() +- .getConnectorService(host, ITCFSubSystem.class); ++ .getConnectorService(host, getServiceImplType()); + } + + @Override +- @SuppressWarnings("unchecked") +- public Class getServiceImplType() { +- return TCFFileService.class; ++ public Class getServiceImplType() { ++ return ITCFSubSystem.class; + } + + @Override +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java (working copy) +@@ -11,6 +11,7 @@ + * Uwe Stieber (Wind River) - [271224] NPE in TCFFileService#download + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Uwe Stieber (Wind River) - [274277] The TCF file service subsystem implementation is not updating the progress monitor ++ * Intel Corporation - Make recursive copy/delete available (delete/copy a folder contains files) + *******************************************************************************/ + package org.eclipse.tm.internal.tcf.rse.files; + +@@ -18,6 +19,7 @@ + import java.io.BufferedOutputStream; + import java.io.File; + import java.io.FileInputStream; ++import java.io.FileNotFoundException; + import java.io.FileOutputStream; + import java.io.IOException; + import java.io.InputStream; +@@ -131,22 +133,125 @@ + return s; + } + ++ /* Delete from UI action will call deleteBatch interface, yet ++ * for copy from UI action, it will call copy! It's totally ++ * inconsistency! For solving the problem, we have to modify ++ * the copy itself and made it recursive. We can't modify it ++ * in the same way as delete does! ++ * ++ */ ++ ++ public void internalCopy(String srcParent, ++ String srcName, String tgtParent, String tgtName, IProgressMonitor monitor) ++ throws SystemMessageException, InterruptedException { ++ //Note the dest directory or file exist surely since UI operations have ++ //done something, rename it to copy of XXX ++ if (monitor != null) ++ { ++ if (monitor.isCanceled()) ++ { ++ throw new InterruptedException("User cancelled the copy operation!"); ++ } ++ } ++ ++ try ++ { ++ //firstly create the target directory! ++ this.createFolder(tgtParent, tgtName, monitor); ++ //then copy the next level directory! ++ final String new_srcpath = toRemotePath(srcParent, srcName); ++ final String new_tgtpath = toRemotePath(tgtParent, tgtName); ++ IHostFile[] arrFiles = internalFetch(new_srcpath, null, ++ FILE_TYPE_FILES_AND_FOLDERS, monitor); ++ if (arrFiles == null || arrFiles.length <=0 ) ++ return; ++ else ++ { ++ for (int i = 0; i < arrFiles.length; i++) ++ { ++ String srcFile = toRemotePath(new_srcpath, arrFiles[i].getName()); ++ String tgtFile = toRemotePath(new_tgtpath, arrFiles[i].getName()); ++ if (arrFiles[i].isFile()) ++ { ++ copy(srcFile, tgtFile, monitor); ++ } ++ else ++ { ++ //do recursive directory copy! ++ internalCopy(new_srcpath, arrFiles[i].getName(), new_tgtpath, ++ arrFiles[i].getName(), monitor); ++ } ++ } ++ } ++ } ++ catch (SystemMessageException e) ++ { ++ e.printStackTrace(); ++ throw new SystemMessageException(e.getSystemMessage()); ++ } ++ catch (InterruptedException e) ++ { ++ throw new InterruptedException("User cancelled the copy operation!"); ++ } ++ } ++ + public void copy(String srcParent, + String srcName, String tgtParent, String tgtName, IProgressMonitor monitor) + throws SystemMessageException { +- final String src = toRemotePath(srcParent, srcName); +- final String tgt = toRemotePath(tgtParent, tgtName); ++ ++ if (monitor != null) ++ monitor.beginTask("Copying remote files!", 1); ++ ++ try { ++ ++ IHostFile curFile = getFile(srcParent, srcName, monitor); ++ final String srcFile = toRemotePath(srcParent, srcName); ++ final String tgtFile = toRemotePath(tgtParent, tgtName); ++ ++ if (curFile.isFile()) ++ copy(srcFile, tgtFile, monitor); ++ else if (curFile.isDirectory()) ++ { ++ internalCopy(srcParent, srcName, tgtParent, tgtName, monitor); ++ } ++ else ++ { ++ FileNotFoundException e = ++ new FileNotFoundException("Failed to find the to be " + ++ "copied file or directory!"); ++ throw new SystemMessageException(getMessage(e)); ++ } ++ } ++ catch (Exception e) { ++ // TODO Auto-generated catch block ++ if (e instanceof SystemMessageException) ++ throw (SystemMessageException)e; ++ else if (e instanceof InterruptedException) ++ { ++ System.out.println("User cancelled the copy operation!"); ++ } ++ throw new SystemOperationFailedException(Activator.PLUGIN_ID, e); ++ ++ } ++ finally { ++ if (monitor != null) ++ monitor.done(); ++ } ++ } ++ ++ public void copy(final String srcFile, final String tgtFile, IProgressMonitor monitor) ++ throws SystemMessageException { + new TCFRSETask() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); +- fs.copy(src, tgt, false, false, new IFileSystem.DoneCopy() { ++ fs.copy(srcFile, tgtFile, false, false, new IFileSystem.DoneCopy() { + public void doneCopy(IToken token, FileSystemException error) { + if (error != null) error(error); + else done(Boolean.TRUE); + } + }); + } +- }.getS(monitor, "Copy: " + srcName); //$NON-NLS-1$ ++ }.getS(monitor, "Copy: " + srcFile); //$NON-NLS-1$ + } + + public void copyBatch(String[] srcParents, +@@ -226,13 +331,81 @@ + }.getS(monitor, "Delete"); //$NON-NLS-1$ + } + ++ private void internalDelete(String parent, String name, ++ IProgressMonitor monitor) ++ throws SystemMessageException, InterruptedException ++ { ++ if (monitor != null) ++ { ++ if (monitor.isCanceled()) ++ { ++ throw new InterruptedException("User cancelled the delete operation!"); ++ } ++ } ++ ++ try ++ { ++ final String new_path = toRemotePath(parent, name); ++ IHostFile[] arrFiles = internalFetch(new_path, null, ++ FILE_TYPE_FILES_AND_FOLDERS, monitor); ++ if (arrFiles == null || arrFiles.length <= 0) ++ { ++ //This is an empty directory, directly delete! ++ delete(parent, name, monitor); ++ } ++ else ++ { ++ for (int i = 0; i < arrFiles.length; i++) ++ { ++ ++ if (arrFiles[i].isFile()) ++ { ++ delete(new_path, arrFiles[i].getName(), monitor); ++ } ++ else ++ internalDelete(new_path, arrFiles[i].getName(), monitor); ++ } ++ //now the folder becomes empty, let us delete it! ++ delete(parent, name, monitor); ++ } ++ } ++ catch (SystemMessageException e) { ++ // TODO Auto-generated catch block ++ e.printStackTrace(); ++ throw new SystemMessageException(e.getSystemMessage()); ++ } ++ catch (InterruptedException e) { ++ throw new InterruptedException("User cancelled the delete operation!"); ++ } ++ } ++ + @Override + public void deleteBatch(String[] remoteParents, String[] fileNames, + IProgressMonitor monitor) +- throws SystemMessageException { +- for (int i = 0; i < remoteParents.length; i++) { +- delete(remoteParents[i], fileNames[i], monitor); ++ throws SystemMessageException { ++ if (monitor != null) ++ monitor.beginTask("Deleting selected folders or files!", remoteParents.length); ++ try ++ { ++ for (int i = 0; i < remoteParents.length; i++) { ++ IHostFile curFile = getFile(remoteParents[i], fileNames[i], monitor); ++ if (curFile.isFile()) ++ delete(remoteParents[i], fileNames[i], monitor); ++ else if (curFile.isDirectory()) ++ internalDelete(remoteParents[i], fileNames[i], monitor); ++ } + } ++ catch (Exception x) { ++ if (x instanceof SystemMessageException) throw (SystemMessageException)x; ++ else if (x instanceof InterruptedException) { ++ System.out.println("user cancelled the delete operation!"); ++ } ++ throw new SystemOperationFailedException(Activator.PLUGIN_ID, x); ++ } ++ finally { ++ if (monitor != null) ++ monitor.done(); ++ } + } + + public void download(final String parent, +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java (revision 0) +@@ -0,0 +1,28 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse; ++ ++import org.eclipse.osgi.util.NLS; ++ ++public class TCFConnectorResources extends NLS { ++ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.TCFConnectorResources"; ++ static { ++ NLS.initializeMessages(BUNDLE_NAME, TCFConnectorResources.class); ++ } ++ private TCFConnectorResources() { ++ ++ } ++ ++ public static String TCFConnectorService_Name; ++ public static String TCFConnectorService_Description; ++ public static String PropertySet_Description; ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java (revision 0) +@@ -0,0 +1,29 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++ ++package org.eclipse.tm.internal.tcf.rse; ++ ++import org.eclipse.rse.services.files.RemoteFileException; ++import org.eclipse.tm.tcf.protocol.IChannel; ++ ++public interface ITCFSessionProvider { ++ public static final int ERROR_CODE = 100; // filed error code ++ public static final int SUCCESS_CODE = 150; // login pass code ++ public static final int CONNECT_CLOSED = 200; // code for end of login attempts ++ public static final int TCP_CONNECT_TIMEOUT = 10; //seconds - TODO: Make configurable ++ ++ public IChannel getChannel(); ++ public String getSessionUserId(); ++ public String getSessionPassword(); ++ public String getSessionHostName(); ++ public boolean isSubscribed(); ++ public void Subscribe() throws RemoteFileException; ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java (working copy) +@@ -26,10 +26,8 @@ + + private final TCFProcessAdapter process_adapter = new TCFProcessAdapter(); + +- @Override +- @SuppressWarnings("unchecked") +- public Class getServiceImplType() { +- return TCFProcessService.class; ++ public Class getServiceImplType() { ++ return ITCFSubSystem.class; + } + + @Override +@@ -50,7 +48,7 @@ + @Override + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance() +- .getConnectorService(host, ITCFSubSystem.class); ++ .getConnectorService(host, getServiceImplType()); + } + + @Override +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java (working copy) +@@ -10,29 +10,49 @@ + * Martin Oberhuber (Wind River) - [269682] Get port from RSE Property + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Anna Dushistova (MontaVista) - [285373] TCFConnectorService should send CommunicationsEvent.BEFORE_CONNECT and CommunicationsEvent.BEFORE_DISCONNECT +- *******************************************************************************/ ++ * Intel Corporation - Make TCF being authenticated connection and attached streaming subscription/unsubscription method ++ ******************************************************************************/ + package org.eclipse.tm.internal.tcf.rse; + ++import java.io.IOException; + import java.util.ArrayList; + import java.util.HashMap; + import java.util.List; + import java.util.Map; ++import java.util.concurrent.ExecutionException; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.TimeoutException; + + import org.eclipse.core.runtime.IProgressMonitor; + import org.eclipse.rse.core.model.IHost; +-import org.eclipse.rse.core.subsystems.BasicConnectorService; ++import org.eclipse.rse.core.model.IPropertySet; ++import org.eclipse.rse.core.model.PropertyType; ++import org.eclipse.rse.core.model.SystemSignonInformation; + import org.eclipse.rse.core.subsystems.CommunicationsEvent; ++import org.eclipse.rse.services.files.RemoteFileException; ++import org.eclipse.rse.ui.subsystems.StandardConnectorService; ++import org.eclipse.tm.internal.tcf.terminals.ITerminalsService; + import org.eclipse.tm.tcf.core.AbstractPeer; + import org.eclipse.tm.tcf.protocol.IChannel; + import org.eclipse.tm.tcf.protocol.IPeer; + import org.eclipse.tm.tcf.protocol.IService; ++import org.eclipse.tm.tcf.protocol.IToken; + import org.eclipse.tm.tcf.protocol.Protocol; + import org.eclipse.tm.tcf.services.IFileSystem; + import org.eclipse.tm.tcf.services.ILocator; ++import org.eclipse.tm.tcf.services.IStreams; + import org.eclipse.tm.tcf.services.ISysMonitor; ++import org.eclipse.tm.tcf.util.TCFTask; + ++public class TCFConnectorService extends StandardConnectorService implements ++ ITCFSessionProvider { + +-public class TCFConnectorService extends BasicConnectorService { ++ public static final String PROPERTY_SET_NAME = "TCF Connection Settings"; ++ public static final String PROPERTY_LOGIN_REQUIRED = "Login.Required"; //$NON-NLS-1$ ++ public static final String PROPERTY_PWD_REQUIRED="Pwd.Required"; ++ public static final String PROPERTY_LOGIN_PROMPT = "Login.Prompt"; //$NON-NLS-1$ ++ public static final String PROPERTY_PASSWORD_PROMPT = "Password.Prompt"; //$NON-NLS-1$ ++ public static final String PROPERTY_COMMAND_PROMPT = "Command.Prompt"; //$NON-NLS-1$ + + private IChannel channel; + private Throwable channel_error; +@@ -40,12 +60,62 @@ + + private boolean poll_timer_started; + ++ private boolean bSubscribed = false; ++ ++ /* subscribe the stream service on this TCP connection */ ++ private IStreams.StreamsListener streamListener = new IStreams.StreamsListener() { ++ public void created(String stream_type, String stream_id, ++ String context_id) { ++ System.out.printf("new stream id: %s , type: %s is created\n", ++ stream_id, stream_type); ++ } ++ ++ /** ++ * Called when a stream is disposed. ++ * ++ * @param stream_type ++ * - source type of the stream. ++ * @param stream_id ++ * - ID of the stream. ++ */ ++ public void disposed(String stream_type, String stream_id) { ++ System.out.printf("stream id: %s type: %s is disposed\n", ++ stream_id, stream_type); ++ } ++ }; ++ + public TCFConnectorService(IHost host, int port) { +- super("TCF", "Target Communication Framework", host, port); //$NON-NLS-1$ //$NON-NLS-2$ ++ super(TCFConnectorResources.TCFConnectorService_Name, ++ TCFConnectorResources.TCFConnectorService_Description, host, ++ port); //$NON-NLS-1$ //$NON-NLS-2$ ++ getTCFPropertySet(); + } ++ ++ public IPropertySet getTCFPropertySet() { ++ IPropertySet tcfSet = getPropertySet(PROPERTY_SET_NAME); ++ if (tcfSet == null) { ++ tcfSet = createPropertySet(PROPERTY_SET_NAME, TCFConnectorResources.PropertySet_Description); ++ //add default values if not set ++ tcfSet.addProperty(PROPERTY_LOGIN_REQUIRED, "true", PropertyType.getEnumPropertyType(new String[] {"true", "false"})); ++ tcfSet.addProperty(PROPERTY_PWD_REQUIRED, "false", PropertyType.getEnumPropertyType(new String[] {"true", "false"})); ++ tcfSet.addProperty(PROPERTY_LOGIN_PROMPT, "ogin: ", PropertyType.getStringPropertyType()); ++ tcfSet.addProperty(PROPERTY_PASSWORD_PROMPT, "assword: ", PropertyType.getStringPropertyType()); ++ tcfSet.addProperty(PROPERTY_COMMAND_PROMPT, "#", PropertyType.getStringPropertyType()); ++ } ++ return tcfSet; ++ } + ++ /** ++ * @return true if the associated connector service requires a password. ++ */ + @Override +- protected void internalConnect(final IProgressMonitor monitor) throws Exception { ++ public final boolean requiresPassword() { ++ return false; ++ } ++ ++ @Override ++ protected void internalConnect(final IProgressMonitor monitor) ++ throws Exception { + assert !Protocol.isDispatchThread(); + final Exception[] res = new Exception[1]; + // Fire comm event to signal state about to change +@@ -54,39 +124,55 @@ + synchronized (res) { + Protocol.invokeLater(new Runnable() { + public void run() { +- if (!connectTCFChannel(res, monitor)) add_to_wait_list(this); ++ if (!connectTCFChannel(res, monitor)) ++ add_to_wait_list(this); + } + }); + res.wait(); + } ++ if (res[0] != null) throw res[0]; + monitor.done(); +- if (res[0] != null) throw res[0]; + } + + @Override +- protected void internalDisconnect(final IProgressMonitor monitor) throws Exception { ++ protected void internalDisconnect(final IProgressMonitor monitor) ++ throws Exception { + assert !Protocol.isDispatchThread(); + final Exception[] res = new Exception[1]; + // Fire comm event to signal state about to change + fireCommunicationsEvent(CommunicationsEvent.BEFORE_DISCONNECT); + monitor.beginTask("Disconnecting " + getHostName(), 1); //$NON-NLS-1$ +- synchronized (res) { +- Protocol.invokeLater(new Runnable() { +- public void run() { +- if (!disconnectTCFChannel(res, monitor)) add_to_wait_list(this); +- } +- }); +- res.wait(); ++ try { ++ /* First UnSubscribe TCP channel */ ++ Unsubscribe(); ++ /* Disconnecting TCP channel */ ++ synchronized (res) { ++ Protocol.invokeLater(new Runnable() { ++ public void run() { ++ if (!disconnectTCFChannel(res, monitor)) ++ add_to_wait_list(this); ++ } ++ }); ++ res.wait(); ++ } ++ if (res[0] != null) throw res[0]; ++ + } +- monitor.done(); +- if (res[0] != null) throw res[0]; ++ catch (Exception e) { ++ e.printStackTrace(); ++ throw new RemoteFileException("Error creating Terminal", e); //$NON-NLS-1$ ++ } ++ finally { ++ monitor.done(); ++ } + } + + public boolean isConnected() { + final boolean res[] = new boolean[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { +- res[0] = channel != null && channel.getState() == IChannel.STATE_OPEN; ++ res[0] = channel != null ++ && channel.getState() == IChannel.STATE_OPEN; + } + }); + return res[0]; +@@ -108,7 +194,8 @@ + if (wait_list.isEmpty()) return; + Runnable[] r = wait_list.toArray(new Runnable[wait_list.size()]); + wait_list.clear(); +- for (int i = 0; i < r.length; i++) r[i].run(); ++ for (int i = 0; i < r.length; i++) ++ r[i].run(); + } + + private boolean connectTCFChannel(Exception[] res, IProgressMonitor monitor) { +@@ -117,9 +204,12 @@ + case IChannel.STATE_OPEN: + case IChannel.STATE_CLOSED: + synchronized (res) { +- if (channel_error instanceof Exception) res[0] = (Exception)channel_error; +- else if (channel_error != null) res[0] = new Exception(channel_error); +- else res[0] = null; ++ if (channel_error instanceof Exception) ++ res[0] = (Exception) channel_error; ++ else if (channel_error != null) ++ res[0] = new Exception(channel_error); ++ else ++ res[0] = null; + res.notify(); + return true; + } +@@ -137,7 +227,7 @@ + String host = getHostName().toLowerCase(); + int port = getConnectPort(); + if (port <= 0) { +- //Default fallback ++ // Default fallback + port = TCFConnectorServiceManager.TCF_PORT; + } + IPeer peer = null; +@@ -146,8 +236,8 @@ + for (IPeer p : locator.getPeers().values()) { + Map attrs = p.getAttributes(); + if ("TCP".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)) && //$NON-NLS-1$ +- host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) && +- port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) { ++ host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) ++ && port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) { + peer = p; + break; + } +@@ -171,17 +261,18 @@ + + public void congestionLevel(int level) { + } +- + public void onChannelClosed(Throwable error) { + assert channel != null; + channel.removeChannelListener(this); + channel_error = error; ++ + if (wait_list.isEmpty()) { + fireCommunicationsEvent(CommunicationsEvent.CONNECTION_ERROR); + } + else { + run_wait_list(); + } ++ bSubscribed = false; + channel = null; + channel_error = null; + } +@@ -192,7 +283,8 @@ + return false; + } + +- private boolean disconnectTCFChannel(Exception[] res, IProgressMonitor monitor) { ++ private boolean disconnectTCFChannel(Exception[] res, ++ IProgressMonitor monitor) { + if (channel == null || channel.getState() == IChannel.STATE_CLOSED) { + synchronized (res) { + res[0] = null; +@@ -212,9 +304,12 @@ + } + + public V getService(Class service_interface) { +- if (channel == null || channel.getState() != IChannel.STATE_OPEN) throw new Error("Not connected"); //$NON-NLS-1$ ++ if (channel == null || channel.getState() != IChannel.STATE_OPEN) ++ throw new Error("Not connected"); //$NON-NLS-1$ + V m = channel.getRemoteService(service_interface); +- if (m == null) throw new Error("Remote peer does not support " + service_interface.getName() + " service"); //$NON-NLS-1$ //$NON-NLS-2$ ++ if (m == null) ++ throw new Error( ++ "Remote peer does not support " + service_interface.getName() + " service"); //$NON-NLS-1$ //$NON-NLS-2$ + return m; + } + +@@ -225,4 +320,111 @@ + public IFileSystem getFileSystemService() { + return getService(IFileSystem.class); + } ++ ++ public IChannel getChannel() { ++ // TODO Auto-generated method stub ++ return channel; ++ } ++ ++ public String getSessionHostName() { ++ // TODO Auto-generated method stub ++ String hostName = ""; ++ IHost host = getHost(); ++ if (host != null) hostName = host.getHostName(); ++ return hostName; ++ } ++ ++ public String getSessionUserId() { ++ // TODO Auto-generated method stub ++ return getUserId(); ++ } ++ ++ public String getSessionPassword() { ++ // TODO Auto-generated method stub ++ String password = ""; ++ SystemSignonInformation ssi = getSignonInformation(); ++ if (ssi != null) { ++ password = ssi.getPassword(); ++ } ++ return password; ++ } ++ ++ public boolean isSubscribed() { ++ // TODO Auto-generated method stub ++ return bSubscribed; ++ } ++ ++ public void Unsubscribe() throws IOException { ++ if (bSubscribed) { ++ System.out ++ .println("Unsubscribe streams before disconnecting TCP channel."); ++ try { ++ new TCFTask() { ++ public void run() { ++ IStreams streams = getService(IStreams.class); ++ streams.unsubscribe(ITerminalsService.NAME, streamListener, ++ new IStreams.DoneUnsubscribe() { ++ public void doneUnsubscribe(IToken token, ++ Exception error) { ++ // TODO Auto-generated method stub ++ System.out.printf( ++ "stream type %s unsubscribed\n", ++ ITerminalsService.NAME); ++ done(this); ++ } ++ }); ++ } ++ }.get(1, TimeUnit.SECONDS); ++ } ++ catch (InterruptedException e) { ++ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams"); ++ } ++ catch (ExecutionException e) { ++ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams"); ++ } ++ catch (TimeoutException e) { ++ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams"); ++ } ++ bSubscribed = false; ++ } ++ ++ } ++ ++ public void Subscribe() throws RemoteFileException { ++ try { ++ new TCFTask() { ++ public void run() { ++ if (bSubscribed) { ++ done(this); ++ } ++ else { ++ bSubscribed = true; ++ IStreams streams = getService(IStreams.class); ++ streams.subscribe(ITerminalsService.NAME, streamListener, ++ new IStreams.DoneSubscribe() { ++ public void doneSubscribe(IToken token, ++ Exception error) { ++ // TODO Auto-generated method stub ++ System.out.println("Stream subscribed"); ++ if (error != null) { ++ System.out.println("subscribe error"); ++ bSubscribed = false; ++ error(error); ++ } ++ else ++ done(this); ++ } ++ ++ }); ++ }} ++ }.getIO(); ++ ++ } ++ catch (Exception e) { ++ e.printStackTrace(); ++ throw new RemoteFileException( ++ "Error When Subscribe Terminal streams!", e); //$NON-NLS-1$ ++ } ++ ++ } + } +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java (revision 0) +@@ -0,0 +1,35 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import org.eclipse.osgi.util.NLS; ++ ++public class TCFShellServiceResources extends NLS { ++ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.shells.TCFShellServiceResources"; //$NON-NLS-1$ ++ ++ public static String TCFPlugin_Unexpected_Exception; ++ ++ public static String TCFShellService_Description; ++ ++ public static String TCFShellService_Name; ++ ++ static { ++ // initialize resource bundle ++ NLS.initializeMessages(BUNDLE_NAME, TCFShellServiceResources.class); ++ } ++ ++ private TCFShellServiceResources(){ ++ } ++ ++} ++ ++ ++ +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java (revision 0) +@@ -0,0 +1,444 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import java.io.BufferedWriter; ++import java.io.IOException; ++import java.io.InputStream; ++import java.io.OutputStream; ++import java.io.OutputStreamWriter; ++import java.io.Writer; ++import java.util.Map; ++ ++import org.eclipse.core.runtime.IStatus; ++import org.eclipse.rse.core.model.IPropertySet; ++import org.eclipse.rse.services.clientserver.PathUtility; ++import org.eclipse.rse.services.clientserver.messages.CommonMessages; ++import org.eclipse.rse.services.clientserver.messages.ICommonMessageIds; ++import org.eclipse.rse.services.clientserver.messages.SimpleSystemMessage; ++import org.eclipse.rse.services.clientserver.messages.SystemMessage; ++import org.eclipse.rse.services.clientserver.messages.SystemMessageException; ++import org.eclipse.rse.services.terminals.AbstractTerminalShell; ++import org.eclipse.rse.services.terminals.ITerminalService; ++import org.eclipse.rse.ui.SystemBasePlugin; ++import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider; ++import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; ++import org.eclipse.tm.internal.tcf.rse.TCFRSETask; ++import org.eclipse.tm.internal.tcf.terminals.ITerminalsService; ++import org.eclipse.tm.tcf.protocol.IChannel; ++import org.eclipse.tm.tcf.protocol.IToken; ++import org.eclipse.tm.tcf.services.IStreams; ++ ++ ++public class TCFTerminalShell extends AbstractTerminalShell { ++ private ITCFSessionProvider fSessionProvider; ++ private IChannel fChannel; ++ private String fPtyType; ++ private ITerminalsService.TerminalContext terminalContext; ++ private String fEncoding; ++ private InputStream fInputStream; ++ private OutputStream fOutputStream; ++ private Writer fOutputStreamWriter; ++ private int fWidth = 0; ++ private int fHeight = 0; ++ private String fContextID; ++ private String in_id; ++ private String out_id; ++ private boolean connected = false; ++ private ITerminalsService terminal; ++ private int status; ++ ++ private IPropertySet tcfPropertySet = null; ++ ++ private static String defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding(); ++ private ITerminalsService.TerminalsListener listeners = new ITerminalsService.TerminalsListener(){ ++ ++ public void exited(String terminalId, int exitCode) { ++ // TODO Auto-generated method stub ++ System.out.printf("Console terminal shell %s exited, current shell ID %s\n", terminalId, terminalContext.getID()); ++ if(!terminalContext.getID().equals(terminalId)) ++ return; ++ terminal.removeListener(listeners); ++ TCFTerminalShell.this.connected = false; ++ } ++ ++ ++ public void winSizeChanged(String terminalId, int newWidth, ++ int newHeight) { ++ // TODO Auto-generated method stub ++ System.out.printf("Console terminal shell %s new width %d, height %d\n", terminalId, newWidth, newHeight); ++ } ++ }; ++ ++ private class LoginThread extends Thread { ++ ++ private String username; ++ private String password; ++ private int status = ITCFSessionProvider.SUCCESS_CODE; ++ public LoginThread(String username, String password) { ++ this.username = username; ++ this.password = password; ++ } ++ ++ public void run() { ++ tcfPropertySet = ((TCFConnectorService)fSessionProvider).getTCFPropertySet(); ++ String login_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_REQUIRED); ++ String login_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_PROMPT); ++ String password_prompt =tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PASSWORD_PROMPT); ++ String command_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_COMMAND_PROMPT); ++ String pwd_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PWD_REQUIRED); ++ ++ if (Boolean.valueOf(login_required).booleanValue()) { ++ status = ITCFSessionProvider.SUCCESS_CODE; ++ if (login_prompt != null && login_prompt.length() > 0) { ++ status = readUntil(login_prompt,fInputStream); ++ write(username + "\n"); ++ } ++ if (Boolean.valueOf(pwd_required).booleanValue()) { ++ if (status == ITCFSessionProvider.SUCCESS_CODE && password_prompt != null && password_prompt.length() > 0) { ++ status = readUntil(password_prompt,fInputStream); ++ write(password + "\n"); ++ } ++ } ++ if (status == ITCFSessionProvider.SUCCESS_CODE && command_prompt != null && command_prompt.length() > 0) { ++ status = readUntil(command_prompt,fInputStream); ++ write("\n"); ++ } ++ } else { ++ if (command_prompt != null && command_prompt.length() > 0) { ++ status = readUntil(command_prompt,fInputStream); ++ write("\n"); ++ } ++ } ++ } ++ ++ public int readUntil(String pattern,InputStream in) { ++ try { ++ char lastChar = pattern.charAt(pattern.length() - 1); ++ StringBuffer sb = new StringBuffer(); ++ int ch = in.read(); ++ while (ch >= 0) { ++ char tch = (char) ch; ++ sb.append(tch); ++ if (tch=='t' && sb.indexOf("incorrect") >= 0) { //$NON-NLS-1$ ++ return ITCFSessionProvider.ERROR_CODE; ++ } ++ if (tch=='d' && sb.indexOf("closed") >= 0) { //$NON-NLS-1$ ++ return ITCFSessionProvider.CONNECT_CLOSED; ++ } ++ if (tch == lastChar) { ++ if (sb.toString().endsWith(pattern)) { ++ return ITCFSessionProvider.SUCCESS_CODE; ++ } ++ } ++ ch = in.read(); ++ } ++ } ++ catch (Exception e) { ++ e.printStackTrace(); ++ SystemBasePlugin.logError(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), e); ++ } ++ return ITCFSessionProvider.CONNECT_CLOSED; ++ } ++ ++ public int getLoginStatus() { ++ return this.status; ++ } ++ ++ } ++ ++ public void write(String value) { ++ try { ++ int len = value.length() + 6; ++ fOutputStream.write(value.getBytes()); ++ System.out.printf("value is %s\n", value); ++ System.out.printf("write: ******************".substring(0, len <= 24 ? len : 24)); //$NON-NLS-1$ ++ } catch (Exception e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ private int login(String username, String password) throws InterruptedException ++ { ++ long millisToEnd = System.currentTimeMillis() + ITCFSessionProvider.TCP_CONNECT_TIMEOUT*1000; ++ LoginThread checkLogin = new LoginThread(username, password); ++ status = ITCFSessionProvider.ERROR_CODE; ++ checkLogin.start(); ++ while (checkLogin.isAlive() && System.currentTimeMillis()null if not ++ * relevant ++ * @param encoding The default encoding to use for initial command. ++ * @param environment Environment array to set, or null if ++ * not relevant. ++ * @param initialWorkingDirectory initial directory to open the Terminal in. ++ * Use null or empty String ("") to start in a ++ * default directory. Empty String will typically start in the ++ * home directory. ++ * @param commandToRun initial command to send. ++ * @throws SystemMessageException in case anything goes wrong. Channels and ++ * Streams are all cleaned up again in this case. ++ * @see ITerminalService ++ */ ++ public TCFTerminalShell(final ITCFSessionProvider sessionProvider, final String ptyType, ++ final String encoding, final String[] environment, ++ String initialWorkingDirectory, String commandToRun) ++ throws SystemMessageException { ++ Map map_ids; ++ Exception nestedException = null; ++ try { ++ fSessionProvider = sessionProvider; ++ fEncoding = encoding; ++ fPtyType = ptyType; ++ fChannel = fSessionProvider.getChannel(); ++ ++ if (fChannel == null || fChannel.getState() != IChannel.STATE_OPEN) ++ throw new Exception("TCP channel is not connected!"); ++ if (((TCFConnectorService)sessionProvider).isSubscribed() == false) ++ ((TCFConnectorService)sessionProvider).Subscribe(); ++ assert (((TCFConnectorService)sessionProvider).isSubscribed()); ++ ++ new TCFRSETask() { ++ public void run() { ++ terminal = ((TCFConnectorService)sessionProvider).getService(ITerminalsService.class); ++ terminal.addListener(listeners); ++ terminal.launch(ptyType, encoding, environment, new ITerminalsService.DoneLaunch() { ++ public void doneLaunch(IToken token, Exception error, ++ ITerminalsService.TerminalContext terminal) { ++ // TODO Auto-generated method stub ++ ++ terminalContext = terminal; ++ if (error != null) ++ error(error); ++ else done(terminal); ++ } ++ }); ++ } ++ ++ }.getS(null, TCFShellServiceResources.TCFShellService_Name); //$NON-NLS-1$ ++ ++ fPtyType = terminalContext.getPtyType(); ++ fEncoding = terminalContext.getEncoding(); ++ fContextID = terminalContext.getID(); ++ fWidth = terminalContext.getWidth(); ++ fHeight = terminalContext.getHeight(); ++ map_ids = terminalContext.getProperties(); ++ in_id = (String)map_ids.get(ITerminalsService.PROP_STDOUT_ID); ++ out_id = (String)map_ids.get(ITerminalsService.PROP_STDIN_ID); ++ ++ String user = fSessionProvider.getSessionUserId(); ++ String password = fSessionProvider.getSessionPassword(); //$NON-NLS-1$ ++ status = ITCFSessionProvider.ERROR_CODE; ++ ++ IStreams streams = ((TCFConnectorService)sessionProvider).getService(IStreams.class); ++ fOutputStream = new TCFTerminalOutputStream(streams, out_id); ++ fInputStream = new TCFTerminalInputStream(streams, in_id); ++ if (fEncoding != null) { ++ fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream, encoding)); ++ } else { ++ // default encoding == System.getProperty("file.encoding") ++ // TODO should try to determine remote encoding if possible ++ fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream)); ++ } ++ ++ try { ++ status = login(user, password); ++ } ++ finally ++ { ++ if ((status == ITCFSessionProvider.CONNECT_CLOSED)) ++ System.out.print("First time login fails, retry!"); ++ } ++ ++ //give another chance of retrying ++ if ((status == ITCFSessionProvider.CONNECT_CLOSED)) ++ { ++ ((TCFConnectorService)sessionProvider).Unsubscribe(); ++ ((TCFConnectorService)sessionProvider).Subscribe(); ++ assert (((TCFConnectorService)sessionProvider).isSubscribed()); ++ status = login(user, password); ++ } ++ ++ connected = true; ++ if (initialWorkingDirectory!=null && initialWorkingDirectory.length()>0 ++ && !initialWorkingDirectory.equals(".") //$NON-NLS-1$ ++ && !initialWorkingDirectory.equals("Command Shell") //$NON-NLS-1$ //FIXME workaround for bug 153047 ++ ) { ++ writeToShell("cd " + PathUtility.enQuoteUnix(initialWorkingDirectory)); //$NON-NLS-1$ ++ } ++ ++ if (commandToRun != null && commandToRun.length() > 0) { ++ writeToShell(commandToRun); ++ } ++ ++ } ++ catch (Exception e) ++ { ++ e.printStackTrace(); ++ nestedException = e; ++ } ++ finally { ++ if (status == ITCFSessionProvider.SUCCESS_CODE) { ++ System.out.println("TCF shell Service: Connected"); //$NON-NLS-1$ ++ } ++ else { ++ System.out.println("TCF shell Service: Connect failed"); //$NON-NLS-1$ ++ SystemMessage msg; ++ ++ if (nestedException!=null) { ++ msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID, ++ ICommonMessageIds.MSG_EXCEPTION_OCCURRED, ++ IStatus.ERROR, ++ CommonMessages.MSG_EXCEPTION_OCCURRED, nestedException); ++ } else { ++ String strErr; ++ if (status == ITCFSessionProvider.CONNECT_CLOSED) ++ strErr = "Connection closed!"; ++ else if (status == ITCFSessionProvider.ERROR_CODE) ++ strErr = "Login Incorrect or meet other unknown error!"; ++ else ++ strErr = "Not identified Errors"; ++ ++ msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID, ++ ICommonMessageIds.MSG_COMM_AUTH_FAILED, ++ IStatus.ERROR, ++ strErr, ++ "Meet error when trying to login in!"); ++ msg.makeSubstitution(((TCFConnectorService)fSessionProvider).getHost().getAliasName()); ++ } ++ throw new SystemMessageException(msg); ++ } ++ } ++ ++ } ++ ++ public void writeToShell(String command) throws IOException { ++ if (isActive()) { ++ if ("#break".equals(command)) { //$NON-NLS-1$ ++ command = "\u0003"; // Unicode 3 == Ctrl+C //$NON-NLS-1$ ++ } else { ++ command += "\r\n"; //$NON-NLS-1$ ++ } ++ fOutputStreamWriter.write(command); ++ } ++ } ++ ++ public void exit() { ++ ++ // TODO Auto-generated method stub ++ if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) { ++ System.out.println("This terminal shell exits already!"); ++ return; ++ } ++ try { ++ getOutputStream().close(); ++ getInputStream().close(); ++ ++ } ++ catch (IOException ioe) { ++ // TODO Auto-generated catch block ++ ioe.printStackTrace(); ++ } //$NON-NLS-1$ ++ ++ try { ++ new TCFRSETask() { ++ public void run() { ++ terminalContext.exit(new ITerminalsService.DoneCommand(){ ++ public void doneCommand(IToken token, ++ Exception error) { ++ // TODO Auto-generated method stub ++ if (error != null) ++ error(error); ++ else { ++ System.out.println("terminal exit command sent"); ++ done(this); ++ } ++ } ++ }); ++ }}.getS(null, TCFShellServiceResources.TCFShellService_Name); //seems no need block here. need further modification. ++ } ++ catch (SystemMessageException e) { ++ // TODO Auto-generated catch block ++ e.printStackTrace(); ++ } //$NON-NLS-1$; ++ } ++ ++ public InputStream getInputStream() { ++ // TODO Auto-generated method stub ++ return fInputStream; ++ } ++ ++ public OutputStream getOutputStream() { ++ // TODO Auto-generated method stub ++ return fOutputStream; ++ } ++ ++ public boolean isActive() { ++ // TODO Auto-generated method stub ++ if (fChannel != null && !(fChannel.getState() == IChannel.STATE_CLOSED) && connected) { ++ return true; ++ } ++ exit(); ++ // shell is not active: check for session lost ++ return false; ++ } ++ ++ public String getPtyType() { ++ return fPtyType; ++ } ++ ++ public void setTerminalSize(int newWidth, int newHeight) { ++ // do nothing ++ if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) { ++ System.out.println("This terminal shell exits already, can't set size!"); ++ return; ++ } ++ ++ try { ++ new TCFRSETask() { ++ public void run() { ++ if (fChannel != null && connected) { ++ terminal.setWinSize(fContextID, fWidth, fHeight, new ITerminalsService.DoneCommand(){ ++ ++ public void doneCommand(IToken token, Exception error) { ++ // TODO Auto-generated method stub ++ if (error != null) ++ error(error); ++ else ++ done(this); ++ ++ }}); ++ ++ } ++ }}.getS(null, TCFShellServiceResources.TCFShellService_Name); ++ } ++ catch (SystemMessageException e) { ++ // TODO Auto-generated catch block ++ e.printStackTrace(); ++ } //$NON-NLS-1$; ++ } ++ ++ public String getDefaultEncoding() { ++ if (fEncoding != null) return fEncoding; ++ return defaultEncoding; ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java (revision 0) +@@ -0,0 +1,33 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import org.eclipse.osgi.util.NLS; ++ ++ ++public class TCFLoginProperties extends NLS { ++ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.shells.TCFLoginProperties"; //$NON-NLS-1$ ++ public static final String PropertySet_Description = "TCF Shell login word settings"; ++ public static String TCFLOGIN_REQUIRED; ++ public static String TCFPWD_REQUIRED; ++ public static String TCFLOGIN_PROMPT; ++ public static String TCFPASSWORD_PROMPT; ++ public static String TCFCOMMAND_PROMPT; ++ ++ static { ++ NLS.initializeMessages(BUNDLE_NAME, TCFLoginProperties.class); ++ } ++ ++ private TCFLoginProperties() { ++ } ++ ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java (revision 0) +@@ -0,0 +1,198 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++import java.util.ArrayList; ++import java.util.StringTokenizer; ++ ++import org.eclipse.core.runtime.IPath; ++import org.eclipse.core.runtime.NullProgressMonitor; ++import org.eclipse.core.runtime.Path; ++import org.eclipse.rse.core.subsystems.ISubSystem; ++import org.eclipse.rse.internal.services.shells.TerminalServiceHostShell; ++import org.eclipse.rse.services.shells.IHostOutput; ++import org.eclipse.rse.services.shells.IHostShell; ++import org.eclipse.rse.services.shells.IHostShellChangeEvent; ++import org.eclipse.rse.services.shells.ParsedOutput; ++import org.eclipse.rse.services.shells.Patterns; ++import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; ++import org.eclipse.rse.subsystems.shells.core.model.ISystemOutputRemoteTypes; ++import org.eclipse.rse.subsystems.shells.core.model.RemoteError; ++import org.eclipse.rse.subsystems.shells.core.model.RemoteOutput; ++import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem; ++import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteOutput; ++import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ServiceCommandShell; ++ ++@SuppressWarnings("restriction") ++public class TCFServiceCommandShell extends ServiceCommandShell { ++ private Patterns _patterns; ++ private String _workingDir; ++ private String _curCommand; ++ private IRemoteFileSubSystem _fs; ++ ++ public TCFServiceCommandShell(IRemoteCmdSubSystem cmdSS, ++ IHostShell hostShell) { ++ super(cmdSS, hostShell); ++ // TODO Auto-generated constructor stub ++ _patterns = new Patterns(); ++ _patterns.update("cmd"); //$NON-NLS-1$ ++ ISubSystem[] sses = cmdSS.getHost().getSubSystems(); ++ for (int i = 0; i < sses.length; i++) ++ { ++ if (sses[i] instanceof IRemoteFileSubSystem) ++ { ++ _fs = (IRemoteFileSubSystem)sses[i]; ++ break; ++ } ++ } ++ } ++ ++ public Object getContext() ++ { ++ String workingDir = _workingDir; ++ if (workingDir != null && workingDir.length() > 0) ++ { ++ try { ++ return _fs.getRemoteFileObject(workingDir, new NullProgressMonitor()); ++ } ++ catch (Exception e) ++ { ++ e.printStackTrace(); ++ } ++ } ++ return null; ++ ++ } ++ ++ public String getContextString() ++ { ++ return _workingDir; ++ } ++ ++ public void shellOutputChanged(IHostShellChangeEvent event) ++ { ++ IHostOutput[] lines = event.getLines(); ++ boolean gotCommand = false; ++ ArrayList outputs = new ArrayList(lines.length); ++ for (int i = 0; i < lines.length; i++) ++ { ++ String line = lines[i].getString(); ++ System.out.println("shellOutput:"+line); ++ System.out.printf("cur command %s\n", _curCommand); ++ if (line.endsWith(getPromptCommand())) { ++ continue; //ignore our synthetic prompt command ++ } ++ ParsedOutput parsedMsg = null; ++ if (!gotCommand && line.equals(_curCommand)) { ++ gotCommand = true; ++ continue; //ignore remote command echo ++ } else ++ { ++ try ++ { ++ // Bug 160202: Remote shell dies. ++ if ((_curCommand == null) || (!_curCommand.trim().equals("ls"))) { //$NON-NLS-1$ ++ parsedMsg = _patterns.matchLine(line); ++ ++ // Bug 160202: Remote shell dies. ++ if (_curCommand != null) { ++ String temp = _curCommand.trim(); ++ StringTokenizer tokenizer = new StringTokenizer(temp); ++ ++ if (tokenizer.countTokens() == 2) { ++ String token1 = tokenizer.nextToken(); ++ String token2 = tokenizer.nextToken(); ++ ++ if ((token1.equals("ls")) && (token2.indexOf('-') == 0) && (token2.indexOf('l') > 0)) { //$NON-NLS-1$ ++ if (line.startsWith("total")) { //$NON-NLS-1$ ++ parsedMsg = null; ++ } ++ } ++ } ++ } ++ } ++ } ++ catch (Throwable e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ RemoteOutput output = null; ++ ++ String type = "stdout"; //$NON-NLS-1$ ++ ++ if (parsedMsg != null) { ++ type = parsedMsg.type; ++ } ++ ++ if (event.isError()) { ++ output = new RemoteError(this, type); ++ } ++ else { ++ output = new RemoteOutput(this, type); ++ } ++ ++ output.setText(line); ++ if (parsedMsg != null) ++ { ++ String file = parsedMsg.file; ++ if (type.equals(ISystemOutputRemoteTypes.TYPE_PROMPT)) ++ { ++ _workingDir = file; ++ output.setAbsolutePath(_workingDir); ++ } ++ else if(_workingDir!=null) ++ { ++ IPath p = new Path(_workingDir).append(file); ++ output.setAbsolutePath(p.toString()); ++ } ++ else ++ { ++ output.setAbsolutePath(file); ++ } ++ if (parsedMsg.line > 0){ ++ output.setLine(parsedMsg.line); ++ } ++ } ++ ++ addOutput(output); ++ outputs.add(output); ++ } ++ ++ IRemoteOutput[] remoteOutputs = outputs.toArray(new IRemoteOutput[outputs.size()]); ++ notifyOutputChanged(remoteOutputs, false); ++ } ++ ++ /** ++ * Return the prompt command, such that lines ending with the ++ * prompt command can be removed from output. ++ * Should be overridden in case the IHostShell used for this ++ * service is not an SshHostShell. ++ * @return String promptCommand ++ */ ++ protected String getPromptCommand() { ++ IHostShell shell = getHostShell(); ++ if (shell instanceof TerminalServiceHostShell) { ++ return ((TerminalServiceHostShell)shell).getPromptCommand(); ++ } ++ //return something impossible such that nothing is ever matched ++ return "\uffff"; //$NON-NLS-1$ ++ } ++ ++ public void writeToShell(String cmd) ++ { ++ _curCommand = cmd; ++ _patterns.update(cmd); ++ System.out.println("execute: cmd " + cmd); ++ super.writeToShell(cmd); ++ ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java (revision 0) +@@ -0,0 +1,148 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import java.io.IOException; ++import java.io.InputStream; ++ ++import org.eclipse.tm.tcf.protocol.IToken; ++import org.eclipse.tm.tcf.services.IStreams; ++import org.eclipse.tm.tcf.util.TCFTask; ++ ++public class TCFTerminalInputStream extends InputStream { ++ private IStreams streams; ++ private boolean connected = true;;/* The stream is connected or not */ ++ String is_id; ++ private int value; ++ private boolean bEof = false;; ++ ++ public TCFTerminalInputStream(final IStreams streams, final String is_id) throws IOException{ ++ if (streams == null) ++ throw new IOException("TCP streams is null"); ++ this.streams = streams; ++ this.is_id = is_id; ++ } ++ ++ /* read must be synchronized */ ++ @Override ++ public synchronized int read() throws IOException { ++ // TODO Auto-generated method stub ++ if (!connected) ++ throw new IOException("istream is not connected"); ++ if (bEof) ++ return -1; ++ try { ++ new TCFTask() { ++ public void run() { ++ streams.read(is_id, 1, new IStreams.DoneRead() { ++ public void doneRead(IToken token, Exception error, int lostSize, ++ byte[] data, boolean eos) { ++ // TODO Auto-generated method stub ++ if (error != null) { ++ error(error); ++ return; ++ } ++ bEof = eos; ++ if (data != null) { ++ value = (int)data[0]; ++ if (data.length != 1) { ++ System.out.println("TCF inputstream read one byte, yet return more than one byte!"); ++ } ++ } ++ else ++ value = -1; ++ done(this); ++ } ++ }); ++ } ++ }.getIO(); ++ } ++ catch (Exception e) { ++ e.printStackTrace(); ++ throw new IOException(e); ++ } ++ return value; ++ } ++ ++ private static class Buffer { ++ byte[] buf; ++ Buffer() { ++ } ++ } ++ private Buffer buffer; ++ ++ public synchronized int read(byte b[], final int off, final int len) throws IOException { ++ ++ ++ if (!connected) ++ throw new IOException("istream is not connected"); ++ if (bEof) return -1; ++ if (b == null) { ++ throw new NullPointerException(); ++ } else if (off < 0 || len < 0 || len > b.length - off) { ++ throw new IndexOutOfBoundsException(); ++ } else if (len == 0) { ++ return 0; ++ } ++ try { ++ new TCFTask() { ++ public void run() { ++ streams.read(is_id, len, new IStreams.DoneRead() { ++ public void doneRead(IToken token, Exception error, int lostSize, ++ byte[] data, boolean eos) { ++ // TODO Auto-generated method stub ++ if (error != null) { ++ error(error); ++ return; ++ } ++ bEof = eos; ++ if (data != null) { ++ buffer = new Buffer(); ++ buffer.buf = data; ++ ++ } ++ done(buffer); ++ } ++ }); ++ } ++ }.getIO(); ++ ++ if (buffer.buf != null) { ++ int length = buffer.buf.length; ++ System.arraycopy(buffer.buf, 0, b, off, length); ++ System.out.println("read a line:"+ new String(b, off,length)); ++ return length; ++ } ++ else if (bEof) ++ return -1; ++ else return 0; ++ } catch (Exception ee) { ++ ee.printStackTrace(); ++ throw new IOException(ee); ++ } ++ } ++ ++ public void close() throws IOException { ++ if (!connected) return; ++ new TCFTask() { ++ public void run() { ++ streams.disconnect(is_id, new IStreams.DoneDisconnect() { ++ public void doneDisconnect(IToken token, Exception error) { ++ connected = false; ++ done(this); ++ } ++ }); ++ } ++ }.getIO(); ++ connected = false; ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java (revision 0) +@@ -0,0 +1,110 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import java.io.IOException; ++ ++import java.io.OutputStream; ++ ++import org.eclipse.tm.tcf.protocol.IToken; ++import org.eclipse.tm.tcf.services.IStreams; ++import org.eclipse.tm.tcf.util.TCFTask; ++ ++public class TCFTerminalOutputStream extends OutputStream { ++ ++ private final IStreams streams; ++ private boolean connected = true; ++ private boolean write_eof; ++ String os_id; ++ ++ public TCFTerminalOutputStream(final IStreams streams, final String os_id) throws IOException{ ++ if (streams == null) throw new IOException("istream is null"); ++ this.streams = streams; ++ this.os_id = os_id; ++ write_eof = false; ++ } ++ ++ @Override ++ public synchronized void write(final byte b[], final int off, final int len) throws IOException { ++ /* If eof is written, we can't write anything into the stream */ ++ if (!connected || write_eof) ++ throw new IOException("stream is not connected or write_eof already!"); ++ System.out.println("write line: " + new String(b, off, len) ); ++ try { ++ new TCFTask() { ++ public void run() { ++ streams.write(os_id, b, off, len, new IStreams.DoneWrite() { ++ public void doneWrite(IToken token, Exception error) { ++ // TODO: stream write error handling ++ if (error != null) error(error); ++ done(this); ++ } ++ }); ++ ++ } ++ }.getIO(); ++ } ++ catch (Exception e) ++ { ++ throw new IOException(e); ++ } ++ } ++ ++ @Override ++ public synchronized void write(int b) throws IOException { ++ ++ // TODO Auto-generated method stub ++ try { ++ final byte[] buf = new byte[1]; ++ buf[0] = (byte)b; ++ this.write(buf, 0, 1); ++ } ++ catch(IOException ioe) { ++ ioe.printStackTrace(); ++ throw new IOException(ioe); ++ } ++ ++ } ++ ++ /* close must be called --Need to reconsider it in the future*/ ++ public void close() throws IOException { ++ if (!connected) ++ return; ++ try { ++ new TCFTask() { ++ public void run() { ++ streams.eos(os_id, new IStreams.DoneEOS() { ++ public void doneEOS(IToken token, Exception error) { ++ // TODO Auto-generated method stub ++ write_eof = true; ++ done(this); ++ } ++ }); ++ } ++ }.getIO(); ++ new TCFTask() { ++ public void run() { ++ streams.disconnect(os_id, new IStreams.DoneDisconnect() { ++ public void doneDisconnect(IToken token, Exception error) { ++ connected = false; ++ done(this); ++ } ++ }); ++ ++ } ++ }.getIO(); ++ } ++ catch(Exception e) { ++ throw new IOException(e); ++ } ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties (revision 0) +@@ -0,0 +1,3 @@ ++TCFPlugin_Unexpected_Exception=Unexpected {0}: {1} ++TCFShellService_Name=TCF Shell Service ++TCFShellService_Description=TCF Shell Service Description +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java (revision 0) +@@ -0,0 +1,70 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.shells; ++ ++import org.eclipse.rse.core.model.IHost; ++import org.eclipse.rse.core.subsystems.IConnectorService; ++import org.eclipse.rse.core.subsystems.ISubSystem; ++import org.eclipse.rse.services.shells.IHostShell; ++import org.eclipse.rse.services.shells.IShellService; ++import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem; ++import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.IServiceCommandShell; ++import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystem; ++import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystemConfiguration; ++import org.eclipse.tm.internal.tcf.rse.*; ++import org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalService; ++ ++ ++public class TCFShellSubSystemConfiguration extends ++ ShellServiceSubSystemConfiguration { ++ ++ public TCFShellSubSystemConfiguration() { ++ super(); ++ } ++ ++ /** ++ * Instantiate and return an instance of OUR subsystem. ++ * Do not populate it yet though! ++ * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost) ++ */ ++ public ISubSystem createSubSystemInternal(IHost host) ++ { ++ TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host); ++ ISubSystem subsys = new ShellServiceSubSystem(host, connectorService, createShellService(host)); ++ return subsys; ++ } ++ ++ public IConnectorService getConnectorService(IHost host) { ++ return TCFConnectorServiceManager.getInstance().getConnectorService(host, getServiceImplType()); ++} ++ ++ public void setConnectorService(IHost host, ++ IConnectorService connectorService) { ++ TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService); ++ } ++ ++ public Class getServiceImplType() ++ { ++ return ITCFSubSystem.class; ++ } ++ ++ public IServiceCommandShell createRemoteCommandShell(IRemoteCmdSubSystem cmdSS, IHostShell hostShell) { ++ return new TCFServiceCommandShell(cmdSS, hostShell); ++ } ++ ++ public IShellService createShellService(IHost host) { ++ TCFConnectorService cserv = (TCFConnectorService)getConnectorService(host); ++ ++ return (IShellService) (new TCFTerminalService(cserv)).getAdapter(IShellService.class); ++ } ++ ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties (revision 0) +@@ -0,0 +1,3 @@ ++TCFConnectorService_Name=TCF Connector Service ++TCFConnectorService_Description=Target Communication Framework ++PropertySet_Description=TCF login properties. Set these according to your remote system's login prompts. +\ No newline at end of file +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties (revision 0) +@@ -0,0 +1,3 @@ ++TCFPlugin_Unexpected_Exception=Unexpected {0}: {1} ++TCFTerminalService_Name=TCF Terminal Service ++TCFTerminalService_Description=TCF Terminal Service Description +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java (revision 0) +@@ -0,0 +1,64 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.terminals; ++ ++import org.eclipse.rse.core.model.IHost; ++import org.eclipse.rse.core.subsystems.IConnectorService; ++import org.eclipse.rse.core.subsystems.ISubSystem; ++import org.eclipse.rse.services.terminals.ITerminalService; ++import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystem; ++import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystemConfiguration; ++import org.eclipse.tm.internal.tcf.rse.ITCFSubSystem; ++import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; ++import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; ++ ++public class TCFTerminalServiceSubSystemConfiguration extends ++ TerminalServiceSubSystemConfiguration { ++ ++ ++ /** ++ * Instantiate and return an instance of OUR subsystem. Do not populate it ++ * yet though! ++ * ++ * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost) ++ */ ++ public ISubSystem createSubSystemInternal(IHost host) { ++ TCFConnectorService connectorService = (TCFConnectorService) getConnectorService(host); ++ ISubSystem subsys = new TerminalServiceSubSystem(host, ++ connectorService, createTerminalService(host)); ++ return subsys; ++ } ++ ++ /** ++ * @inheritDoc ++ * @since 1.0 ++ */ ++ public ITerminalService createTerminalService(IHost host) { ++ TCFConnectorService cserv = (TCFConnectorService) getConnectorService(host); ++ return new TCFTerminalService(cserv); ++ } ++ ++ public IConnectorService getConnectorService(IHost host) { ++ return TCFConnectorServiceManager.getInstance().getConnectorService( ++ host, getServiceImplType()); ++ } ++ ++ public void setConnectorService(IHost host, ++ IConnectorService connectorService) { ++ TCFConnectorServiceManager.getInstance().setConnectorService(host, ++ getServiceImplType(), connectorService); ++ } ++ ++ public Class getServiceImplType() { ++ return ITCFSubSystem.class; ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java (revision 0) +@@ -0,0 +1,36 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.terminals; ++ ++import org.eclipse.osgi.util.NLS; ++ ++public class TCFTerminalServiceResources extends NLS { ++ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalServiceResources"; //$NON-NLS-1$ ++ ++ public static String TCFPlugin_Unexpected_Exception; ++ ++ public static String TCFTerminalService_Description; ++ ++ public static String TCFTerminalService_Name; ++ ++ static { ++ // initialize resource bundle ++ NLS.initializeMessages(BUNDLE_NAME, TCFTerminalServiceResources.class); ++ } ++ ++ private TCFTerminalServiceResources(){ ++ ++ } ++ ++} ++ ++ ++ +Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java (revision 0) +@@ -0,0 +1,57 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel Corporation - initial API and implementation ++ ******************************************************************************/ ++package org.eclipse.tm.internal.tcf.rse.terminals; ++ ++import org.eclipse.core.runtime.IProgressMonitor; ++ ++import org.eclipse.rse.services.clientserver.messages.SystemMessageException; ++import org.eclipse.rse.services.terminals.AbstractTerminalService; ++import org.eclipse.rse.services.terminals.ITerminalShell; ++import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider; ++import org.eclipse.tm.internal.tcf.rse.shells.TCFTerminalShell; ++ ++public class TCFTerminalService extends AbstractTerminalService{ ++ private final ITCFSessionProvider fSessionProvider; ++ ++ /** ++ * Return the TCF property set, and fill it with default values if it has ++ * not been created yet. Extender may override in order to set different ++ * default values. ++ * ++ * @return a property set holding properties understood by the TCF ++ * connector service. ++ */ ++ public ITerminalShell launchTerminal(String ptyType, String encoding, ++ String[] environment, String initialWorkingDirectory, ++ String commandToRun, IProgressMonitor monitor) ++ throws SystemMessageException { ++ // TODO Auto-generated method stub ++ TCFTerminalShell hostShell = new TCFTerminalShell(fSessionProvider, ptyType, encoding, environment, initialWorkingDirectory, commandToRun); ++ return hostShell; ++ } ++ ++ ++ public TCFTerminalService(ITCFSessionProvider sessionProvider) { ++ fSessionProvider = sessionProvider; ++ } ++ ++ public ITCFSessionProvider getSessionProvider() { ++ return fSessionProvider; ++ } ++ @Override ++ public String getName() { ++ return TCFTerminalServiceResources.TCFTerminalService_Name; ++ } ++ @Override ++ public String getDescription() { ++ return TCFTerminalServiceResources.TCFTerminalService_Description; ++ } ++} +Index: plugins/org.eclipse.tm.tcf.rse/plugin.xml +=================================================================== +--- plugins/org.eclipse.tm.tcf.rse/plugin.xml (revision 1190) ++++ plugins/org.eclipse.tm.tcf.rse/plugin.xml (working copy) +@@ -37,6 +37,22 @@ + vendor="Wind River"> + + ++ ++ ++ ++ + + + + ++ ++ ++ ++ + + Import->General->"Existing projects into workspace", + browse to the "tcf_local/plugins" direcotry, and click "OK". + 2) Check the following plugins: + org.eclipse.tm.tcf + org.eclipse.tm.tcf.core + org.eclipse.tm.tcf.rse + org.eclipse.tm.tcf.terminals + 3) Click "Finish" to import the eclipse plugins. + 4) Select Project->"Build All" to build the plugins. If the + build process complains about missing dependent plugin, + please see Note 2 below. + + +II. Usage +================================ +On remote target side +1. Build & run tcf agent on target. +(This step can be skipped if the agent is already included in +the poky generated iamge) + + - cd to direcotry "org.eclipse.tm.tcf.terminals.agent". + - type "make" to build the tcf agent. + - run the tcf agent with root privilege on target. + e.g. sudo obj/GNU/Linux/x86_64/Debug/agent -Llog.txt + +On Host side +2. Launch the RSE plugin for TCF(org.eclipse.tm.tcf.rse). +Make sure the org.eclipse.tm.tcf.terminals plugin is launched along +with that plugin. + +3. CDT remote debug. + 1) Choose from menu Run->"Debug Configurations..."-> + "C/C++ Remote Application", and click the "New launch configuration" + button. + 2) In the "Main" tab, click "New..." button and it will launch a + "New Connection" wizard. + 3) In the "New Connection" dialogue, choose "TCF" as system type and + click "Next". + 4) Input the ip address of the remote target machine in "Host name:", + choose an arbitary unique name for "Connection name:", and click + "Next". + 5) Make sure "org.eclipse.tm.tcf.rse.Terminals" is checked, make sure + you have input the correct TCF session properties in the TCF + Connector Service and click "Next". (See Note 3 below) + 6) Make sure "org.eclipse.tm.tcf.rse.Files" is checked and click "Next". + 7) Make sure "org.eclipse.tm.tcf.rse.Processes" is checked and click + "Next". + 8) Make sure "org.eclipse.tm.tcf.rse.Shells" is checked, make sure you + have input the correct TCF session properties in the TCF Connector + Service. (See Note 3 below) + 9) Click "Finish" to close the "New Connection" dialogue. + 10) In the "Main" tab, choose the connection just created from the + "Connection" drop-list. + 11) In the "Main" tab, enter the "Remote Absolute File Path for + C/C++ Application". This is where the debugged application to be + downloaded to the remote target side. e.g. "/tmp/helloworld". + 12) In the "Debugger" tab, please choose the correct "GDB debugger". + Usually you should choose the cross-gdb which matches the host + and target machine. (see Known limitations 2.) + 13) Click "Debug". + 14) In the popped up "Enter Password" dialogue, enter the correct + "User ID" and "Password" and click "OK". It will be used to + login to the remote target machine. + +III. Note +================================ +1. Sometimes the eclispe would report a exception of + "Java.lang.OutOfMemoryError: PermGen space" and the application hangs. + This is because the JVM garbage collection doesn't clean the permenant + generation space, which is used to store meta-data descriptions of + classes. To fix this problem, please add "-XX:MaxPermSize=256M" to the + "VM arguements" when launching the plug-ins. + +2. The following eclipse plugins should be installed before building + TCF related plugins. + + CDT v6.0.2: http://download.eclipse.org/tools/cdt/releases/galileo + RSE v3.1.2: http://download.eclipse.org/dsdp/tm/updates/3.1/ + +3. TCF Connector Service Properties. +The TCF connector service properties are used for the TCF based RSE +terminals and shells subsystems. + +To change these properties, click the "TCF Connection Settings" under +the "Available Services" in the wizard, in the right, a list of +properties is shown and ready for change. + +Here is a list of the properties: + + - Command.Prompt + This is a string of which the shell/terminal prompt string on the remote + target system will end with. The default value is + "# "(Pay attention there is a space after the '#'). + + - Login.Prompt + This is a string of which the login prompt string on the remote target + system will end with. The default value is "ogin: "(Pay attention + there is a space after the ':'). + + - Login.Required + Set to "true" if the remote target system requires the user to input + login user name for terminal/shell services. Otherwise set to "false". + The default value is "true". + + - Password.Prompt + This is a string of which the password prompt string on the remote target + system will end with. The default value is "assword: ".(Pay attention + there is a space after the ':') + + - Pwd.Required + Setting to "true" if the remote target system requires the user to input + password for terminal/shell services. Otherwise set to "false". The + default value is "false". + +IV. Known limitations +================================ +1. Authentication retry is not implemented. The user only has one chance to + input the correct password. If it fails, the user needs to re-launch + shell/terminal. If the user has checked the "Save password" in the prompt + dialogue, it needs to be disconnected and re-connected. + +2. Users have to set the correct cross-gdb debugger manually in the + "Debugger" tab in the remote debug configuration. diff --git a/tcf/terminals_agent.patch b/tcf/terminals_agent.patch new file mode 100644 index 0000000..d9ca505 --- /dev/null +++ b/tcf/terminals_agent.patch @@ -0,0 +1,1042 @@ +Index: org.eclipse.tm.tcf.terminals.agent/terminals.c +=================================================================== +--- org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0) ++++ org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0) +@@ -0,0 +1,860 @@ ++/******************************************************************************* ++ * Copyright (c) 2008 Wind River Systems, Inc. and others. ++ * All rights reserved. This program and the accompanying materials ++ * are made available under the terms of the Eclipse Public License v1.0 ++ * and Eclipse Distribution License v1.0 which accompany this distribution. ++ * The Eclipse Public License is available at ++ * http://www.eclipse.org/legal/epl-v10.html ++ * and the Eclipse Distribution License is available at ++ * http://www.eclipse.org/org/documents/edl-v10.php. ++ * ++ * Contributors: ++ * Wind River Systems - initial API and implementation ++ * Intel - implemented terminals service ++ *******************************************************************************/ ++ ++/* ++ * Sample TCF service implementation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef TIOCGWINSZ ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TERMINALS_DEBUG 1 ++ ++#define TERMINALS_NO_LOGIN 0 ++ ++static const char * TERMINALS = "Terminals"; ++ ++#if defined(WIN32) ++# include ++# ifdef _MSC_VER ++# pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */ ++# include ++# else ++# include ++# endif ++# ifndef STATUS_INFO_LENGTH_MISMATCH ++# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) ++# endif ++# ifndef SystemHandleInformation ++# define SystemHandleInformation 16 ++# endif ++# error("unsupported WIN32!") ++#elif defined(_WRS_KERNEL) ++# include ++# include ++# include ++# include ++# include ++# error("unsupported WRS!") ++#else ++# include ++# include ++# include ++# if TERMINALS_NO_LOGIN ++# define TERM_LAUNCH_EXEC "/bin/bash" ++# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, NULL} ++# else ++# define TERM_LAUNCH_EXEC "/bin/login" ++# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, "-p", NULL} ++# endif ++#endif ++ ++#define PIPE_SIZE 0x1000 ++#define TERM_PROP_DEF_SIZE 256 ++ ++typedef struct Terminal ++{ ++ LINK link; ++ int pid; /*pid of the login process of the terminal*/ ++ TCFBroadcastGroup * bcg; ++ int inp; ++ int out; ++ int err; ++ struct TerminalInput * inp_struct; ++ struct TerminalOutput * out_struct; ++ struct TerminalOutput * err_struct; ++ char inp_id[256]; ++ char out_id[256]; ++ char err_id[256]; ++ ++ char pty_type[TERM_PROP_DEF_SIZE]; ++ char encoding[TERM_PROP_DEF_SIZE]; ++ unsigned long width; ++ unsigned long height; ++ long exit_code; ++ ++ Channel *channel; ++} Terminal; ++ ++typedef struct TerminalOutput ++{ ++ Terminal * prs; ++ AsyncReqInfo req; ++ int req_posted; ++ char buf[PIPE_SIZE]; ++ size_t buf_pos; ++ int eos; ++ VirtualStream * vstream; ++} TerminalOutput; ++ ++typedef struct TerminalInput ++{ ++ Terminal * prs; ++ AsyncReqInfo req; ++ int req_posted; ++ char buf[PIPE_SIZE]; ++ size_t buf_pos; ++ size_t buf_len; ++ int eos; ++ VirtualStream * vstream; ++} TerminalInput; ++ ++#define link2term(A) ((Terminal *)((char *)(A) - offsetof(Terminal, link))) ++ ++static LINK terms_list; ++#if defined(_WRS_KERNEL) ++static SEM_ID prs_list_lock = NULL; ++#endif ++ ++static Terminal * find_terminal(int pid) ++{ ++ LINK * qhp = &terms_list; ++ LINK * qp = qhp->next; ++ ++ while (qp != qhp) { ++ Terminal * prs = link2term(qp); ++ if (prs->pid == pid) ++ return prs; ++ qp = qp->next; ++ } ++ return NULL; ++} ++ ++static char * tid2id(int tid) ++{ ++ static char s[64]; ++ char * p = s + sizeof(s); ++ unsigned long n = (long) tid; ++ *(--p) = 0; ++ do { ++ *(--p) = (char) (n % 10 + '0'); ++ n = n / 10; ++ } while (n != 0); ++ ++ *(--p) = 'T'; ++ return p; ++} ++ ++static int id2tid(const char * id) ++{ ++ int tid = 0; ++ if (id == NULL) ++ return 0; ++ if (id[0] != 'T') ++ return 0; ++ if (id[1] == 0) ++ return 0; ++ tid = (unsigned) strtol(id + 1, (char **) &id, 10); ++ if (id[0] != 0) ++ return 0; ++ return tid; ++} ++ ++static void write_context(OutputStream * out, int tid) ++{ ++ Terminal * prs = find_terminal(tid); ++ ++ write_stream(out, '{'); ++ ++ if (prs != NULL) { ++ if (*prs->pty_type) { ++ json_write_string(out, "PtyType"); ++ write_stream(out, ':'); ++ json_write_string(out, prs->pty_type); ++ write_stream(out, ','); ++ } ++ ++ if (*prs->encoding) { ++ json_write_string(out, "Encoding"); ++ write_stream(out, ':'); ++ json_write_string(out, prs->encoding); ++ write_stream(out, ','); ++ } ++ ++ json_write_string(out, "Width"); ++ write_stream(out, ':'); ++ json_write_ulong(out, prs->width); ++ write_stream(out, ','); ++ ++ json_write_string(out, "Height"); ++ write_stream(out, ':'); ++ json_write_ulong(out, prs->height); ++ write_stream(out, ','); ++ ++ if (*prs->inp_id) { ++ json_write_string(out, "StdInID"); ++ write_stream(out, ':'); ++ json_write_string(out, prs->inp_id); ++ write_stream(out, ','); ++ } ++ if (*prs->out_id) { ++ json_write_string(out, "StdOutID"); ++ write_stream(out, ':'); ++ json_write_string(out, prs->out_id); ++ write_stream(out, ','); ++ } ++ if (*prs->err_id) { ++ json_write_string(out, "StdErrID"); ++ write_stream(out, ':'); ++ json_write_string(out, prs->err_id); ++ write_stream(out, ','); ++ } ++ } ++ ++ json_write_string(out, "ID"); ++ write_stream(out, ':'); ++ json_write_string(out, tid2id(tid)); ++ ++ write_stream(out, '}'); ++} ++ ++static void send_event_terminal_exited(OutputStream * out, Terminal * prs) ++{ ++ write_stringz(out, "E"); ++ write_stringz(out, TERMINALS); ++ write_stringz(out, "exited"); ++ ++ json_write_string(out, tid2id(prs->pid)); ++ write_stream(out, 0); ++ ++ json_write_ulong(out, prs->exit_code); ++ write_stream(out, 0); ++ ++ write_stream(out, MARKER_EOM); ++} ++ ++static void send_event_terminal_win_size_changed(OutputStream * out, ++ Terminal * prs) ++{ ++ write_stringz(out, "E"); ++ write_stringz(out, TERMINALS); ++ write_stringz(out, "winSizeChanged"); ++ ++ json_write_string(out, tid2id(prs->pid)); ++ write_stream(out, 0); ++ ++ json_write_long(out, prs->width); ++ write_stream(out, 0); ++ ++ json_write_long(out, prs->height); ++ write_stream(out, 0); ++ ++ write_stream(out, MARKER_EOM); ++} ++ ++static int kill_term(Terminal *term) ++{ ++ int err = 0; ++ ++#if defined(WIN32) ++ HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, term->pid); ++ if (h == NULL) ++ { ++ err = set_win32_errno(GetLastError()); ++ } ++ else ++ { ++ if (!TerminateProcess(h, 1)) err = set_win32_errno(GetLastError()); ++ if (!CloseHandle(h) && !err) err = set_win32_errno(GetLastError()); ++ } ++#else ++ if (kill(term->pid, SIGTERM) < 0) ++ err = errno; ++#endif ++ return err; ++} ++ ++static void command_exit(char * token, Channel * c) ++{ ++ int err = 0; ++ char id[256]; ++ unsigned tid; ++ Terminal *term = NULL; ++ ++ json_read_string(&c->inp, id, sizeof(id)); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ if (read_stream(&c->inp) != MARKER_EOM) ++ exception(ERR_JSON_SYNTAX); ++ ++ tid = id2tid(id); ++ write_stringz(&c->out, "R"); ++ write_stringz(&c->out, token); ++ ++ if (tid == 0) { ++ err = ERR_INV_CONTEXT; ++ } else { ++ term = find_terminal(tid); ++ if (term == NULL) { ++ err = ERR_INV_CONTEXT; ++ } else { ++ err = kill_term(term); ++ } ++ } ++ ++ write_errno(&c->out, err); ++ write_stream(&c->out, MARKER_EOM); ++} ++ ++static void terminal_exited(Terminal * prs) ++{ ++ Trap trap; ++ ++ if (set_trap(&trap)) { ++ send_event_terminal_exited(&prs->bcg->out, prs); ++ clear_trap(&trap); ++ } else { ++ trace(LOG_ALWAYS, "Exception sending terminal exited event: %d %s", ++ trap.error, errno_to_str(trap.error)); ++ } ++ ++#if defined(_WRS_KERNEL) ++ semTake(prs_list_lock, WAIT_FOREVER); ++#endif ++ list_remove(&prs->link); ++ close(prs->inp); ++ close(prs->out); ++ if (prs->out != prs->err) ++ close(prs->err); ++ if (prs->inp_struct) { ++ TerminalInput * inp = prs->inp_struct; ++ if (!inp->req_posted) { ++ virtual_stream_delete(inp->vstream); ++ loc_free(inp); ++ } else { ++ inp->prs = NULL; ++ } ++ } ++ if (prs->out_struct) ++ prs->out_struct->prs = NULL; ++ if (prs->err_struct) ++ prs->err_struct->prs = NULL; ++ loc_free(prs); ++#if defined(_WRS_KERNEL) ++ semGive(prs_list_lock); ++#endif ++} ++ ++static void terminal_input_streams_callback(VirtualStream * stream, ++ int event_code, void * args) ++{ ++ TerminalInput * inp = (TerminalInput *) args; ++ ++ assert(inp->vstream == stream); ++ if (!inp->req_posted) { ++ if (inp->buf_pos >= inp->buf_len && !inp->eos) { ++ inp->buf_pos = inp->buf_len = 0; ++ virtual_stream_get_data(stream, inp->buf, sizeof(inp->buf), ++ &inp->buf_len, &inp->eos); ++ } ++ if (inp->buf_pos < inp->buf_len) { ++ inp->req.u.fio.bufp = inp->buf + inp->buf_pos; ++ inp->req.u.fio.bufsz = inp->buf_len - inp->buf_pos; ++ inp->req_posted = 1; ++ async_req_post(&inp->req); ++ } ++ } ++} ++ ++static void write_terminal_input_done(void * x) ++{ ++ AsyncReqInfo * req = (AsyncReqInfo *) x; ++ TerminalInput * inp = (TerminalInput *) req->client_data; ++ ++ inp->req_posted = 0; ++ if (inp->prs == NULL) { ++ /* Process has exited */ ++ virtual_stream_delete(inp->vstream); ++ loc_free(inp); ++ } else { ++ int wr = inp->req.u.fio.rval; ++ ++ if (wr < 0) { ++ int err = inp->req.error; ++ trace(LOG_ALWAYS, "Can't write terminal input stream: %d %s", err, ++ errno_to_str(err)); ++ inp->buf_pos = inp->buf_len = 0; ++ } else { ++ inp->buf_pos += wr; ++ } ++ ++ terminal_input_streams_callback(inp->vstream, 0, inp); ++ } ++} ++ ++static void write_terminal_input(Terminal * prs) ++{ ++ TerminalInput * inp = prs->inp_struct = (TerminalInput *) loc_alloc_zero( ++ sizeof(TerminalInput)); ++ inp->prs = prs; ++ inp->req.client_data = inp; ++ inp->req.done = write_terminal_input_done; ++ inp->req.type = AsyncReqWrite; ++ inp->req.u.fio.fd = prs->inp; ++ virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE, ++ VS_ENABLE_REMOTE_WRITE, terminal_input_streams_callback, inp, ++ &inp->vstream); ++ virtual_stream_get_id(inp->vstream, prs->inp_id, sizeof(prs->inp_id)); ++} ++ ++static void terminal_output_streams_callback(VirtualStream * stream, ++ int event_code, void * args) ++{ ++ TerminalOutput * out = (TerminalOutput *) args; ++ ++ assert(out->vstream == stream); ++ if (!out->req_posted) { ++ int buf_len = out->req.u.fio.rval; ++ int err = 0; ++ int eos = 0; ++ ++ if (buf_len < 0) { ++ buf_len = 0; ++ err = out->req.error; ++ } ++ if (buf_len == 0) ++ eos = 1; ++ if (out->prs == NULL) { ++ eos = 1; ++ err = 0; ++ } ++ ++ assert(buf_len <= (int)sizeof(out->buf)); ++ assert(out->buf_pos <= (size_t)buf_len); ++ assert(out->req.u.fio.bufp == out->buf); ++#ifdef __linux__ ++ if (err == EIO) ++ err = 0; ++#endif ++ if (err) ++ trace(LOG_ALWAYS, "Can't read terminal output stream: %d %s", err, ++ errno_to_str(err)); ++ ++ if (out->buf_pos < (size_t) buf_len || out->eos != eos) { ++ size_t done = 0; ++ virtual_stream_add_data(stream, out->buf + out->buf_pos, buf_len ++ - out->buf_pos, &done, eos); ++ out->buf_pos += done; ++ if (eos) ++ out->eos = 1; ++ } ++ ++ if (out->buf_pos >= (size_t) buf_len) { ++ if (!eos) { ++ out->req_posted = 1; ++ async_req_post(&out->req); ++ } else if (virtual_stream_is_empty(stream)) { ++ if (out->prs != NULL) { ++ if (out == out->prs->out_struct) ++ out->prs->out_struct = NULL; ++ if (out == out->prs->err_struct) ++ out->prs->err_struct = NULL; ++ } ++ virtual_stream_delete(stream); ++ loc_free(out); ++ } ++ } ++ } // end if(!out->req_posted) ++} ++ ++static void read_terminal_output_done(void * x) ++{ ++ AsyncReqInfo * req = (AsyncReqInfo *) x; ++ TerminalOutput * out = (TerminalOutput *) req->client_data; ++ ++ out->buf_pos = 0; ++ out->req_posted = 0; ++ terminal_output_streams_callback(out->vstream, 0, out); ++} ++ ++static TerminalOutput * read_terminal_output(Terminal * prs, int fd, char * id, ++ size_t id_size) ++{ ++ TerminalOutput * out = (TerminalOutput *) loc_alloc_zero( ++ sizeof(TerminalOutput)); ++ out->prs = prs; ++ out->req.client_data = out; ++ out->req.done = read_terminal_output_done; ++ out->req.type = AsyncReqRead; ++ out->req.u.fio.bufp = out->buf; ++ out->req.u.fio.bufsz = sizeof(out->buf); ++ out->req.u.fio.fd = fd; ++ virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE, ++ VS_ENABLE_REMOTE_READ, terminal_output_streams_callback, out, ++ &out->vstream); ++ virtual_stream_get_id(out->vstream, id, id_size); ++ out->req_posted = 1; ++ async_req_post(&out->req); ++ return out; ++} ++ ++static char **envp_add(char **old_envp, int old_envp_len, char *env) ++{ ++ char **new_envp = NULL; ++ int i; ++ int env_size; ++ int old_envp_size; ++ ++ assert(old_envp || (old_envp==NULL && old_envp_len==0)); ++ assert(env); ++ assert(*env); ++ ++ for (i = 0, old_envp_size = 0; i < old_envp_len; i++) { ++ old_envp_size += sizeof(char *); //size of env pointer ++ old_envp_size += strlen(old_envp[i]) + 1; //size of env string, including trailing '\0' ++ } ++ assert((old_envp && old_envp[i]==NULL) || (old_envp==NULL)); ++ old_envp_size += sizeof(char *);//last null pointer ++ ++ env_size = strlen(env); //new env string size ++ ++ new_envp = loc_alloc(old_envp_size + sizeof(char *) + env_size + 1); ++ if (new_envp != NULL) { ++ new_envp[0] = (char *) new_envp + old_envp_size + sizeof(char *); //setting new env ptr ++ strcpy(new_envp[0], env); //copy new env string ++ if (old_envp) { ++ memcpy(&new_envp[1], old_envp, old_envp_size); //copy old envp ++ } else { ++ new_envp[1] = NULL; ++ } ++ } ++ return new_envp; ++} ++ ++static int start_terminal(Channel * c, char *pty_type, char *encoding, ++ char ** envp, int envp_len, char * exe, char ** args, int *pid, ++ Terminal ** prs) ++{ ++ int err = 0; ++ int fd_tty_master = -1; ++ char * tty_slave_name = NULL; ++ struct winsize size; ++ char **newenvp = envp; ++ ++ memset(&size, 0, sizeof(struct winsize)); ++ fd_tty_master = posix_openpt(O_RDWR | O_NOCTTY); ++ if (fd_tty_master < 0 || grantpt(fd_tty_master) < 0 || unlockpt( ++ fd_tty_master) < 0) ++ err = errno; ++ if (!err) { ++ tty_slave_name = ptsname(fd_tty_master); ++ if (tty_slave_name == NULL) ++ err = EINVAL; ++ } ++ ++ if (ioctl(fd_tty_master, TIOCGWINSZ, (char *) &size) < 0) ++ err = errno; ++ ++ if (!err && fd_tty_master < 3) { ++ int fd0 = fd_tty_master; ++ if ((fd_tty_master = dup(fd_tty_master)) < 0 || close(fd0)) ++ err = errno; ++ } ++ ++ if (!err) { ++ *pid = fork(); ++ if (*pid < 0) ++ err = errno; ++ if (*pid == 0) { ++ int fd = -1; ++ int fd_tty_slave = -1; ++ char env_term[TERM_PROP_DEF_SIZE]; ++ ++ if (*pty_type) { ++ snprintf(env_term, sizeof(env_term), "TERM=%s", pty_type); ++ newenvp = envp_add(envp, envp_len, env_term); ++ if (newenvp == NULL) { ++ err = ENOMEM; ++ } else if (envp) { ++ loc_free(envp); ++ envp = NULL; ++ } ++ } ++ ++ if (!err && *encoding) { ++ envp = newenvp; ++ envp_len += 1; ++ snprintf(env_term, sizeof(env_term), "LANG=%s", encoding); ++ newenvp = envp_add(envp, envp_len, env_term); ++ if (newenvp == NULL) { ++ err = ENOMEM; ++ } else if (envp) { ++ loc_free(envp); ++ envp = NULL; ++ } ++ } ++ ++ setsid(); ++ ++ if (!err && (fd = sysconf(_SC_OPEN_MAX)) < 0) ++ err = errno; ++ if (!err && (fd_tty_slave = open(tty_slave_name, O_RDWR)) < 0) ++ err = errno; ++#if defined(TIOCSCTTY) ++ if (!err && (ioctl(fd_tty_slave, TIOCSCTTY, (char *) 0)) < 0) ++ err = errno; ++#endif ++ if (!err && dup2(fd_tty_slave, 0) < 0) ++ err = errno; ++ if (!err && dup2(fd_tty_slave, 1) < 0) ++ err = errno; ++ if (!err && dup2(fd_tty_slave, 2) < 0) ++ err = errno; ++ while (!err && fd > 3) ++ close(--fd); ++ if (!err) { ++ execve(exe, args, newenvp); ++ err = errno; ++ } ++ if (newenvp) ++ loc_free(newenvp); ++ err = 1; ++ if (err < 1) ++ err = EINVAL; ++ else if (err > 0xff) ++ err = EINVAL; ++ exit(err); ++ } ++ } ++ ++ if (!err) { ++ *prs = (Terminal *) loc_alloc_zero(sizeof(Terminal)); ++ (*prs)->inp = fd_tty_master; ++ (*prs)->out = fd_tty_master; ++ (*prs)->err = fd_tty_master; ++ (*prs)->pid = *pid; ++ (*prs)->bcg = c->bcg; ++ (*prs)->channel = c; ++ if (*pty_type) ++ snprintf((*prs)->pty_type, sizeof((*prs)->pty_type), "%s", pty_type); ++ if (*encoding) ++ snprintf((*prs)->encoding, sizeof((*prs)->encoding), "%s", encoding); ++ (*prs)->width = size.ws_row; ++ (*prs)->height = size.ws_col; ++ list_add_first(&(*prs)->link, &terms_list); ++ } ++ ++ if (!err) ++ return 0; ++ errno = err; ++ return -1; ++} ++ ++static void command_get_context(char * token, Channel * c) ++{ ++ int err = 0; ++ char id[256]; ++ int tid; ++ Terminal *term; ++ ++ json_read_string(&c->inp, id, sizeof(id)); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ if (read_stream(&c->inp) != MARKER_EOM) ++ exception(ERR_JSON_SYNTAX); ++ ++ tid = id2tid(id); ++ write_stringz(&c->out, "R"); ++ write_stringz(&c->out, token); ++ ++ if (tid == 0) { ++ err = ERR_INV_CONTEXT; ++ } else { ++ term = find_terminal(tid); ++ if (term == NULL) { ++ err = ERR_INV_CONTEXT; ++ } else { ++ write_context(&c->out, tid); ++ write_stream(&c->out, 0); ++ } ++ } ++ ++ write_errno(&c->out, err); ++ write_stream(&c->out, MARKER_EOM); ++} ++ ++static void command_launch(char * token, Channel * c) ++{ ++ int pid = 0; ++ int err = 0; ++ char encoding[TERM_PROP_DEF_SIZE]; ++ char pty_type[TERM_PROP_DEF_SIZE]; ++ char *args[] = TERM_LAUNCH_ARGS; ++ ++ char ** envp = NULL; ++ int envp_len = 0; ++ ++ Terminal * prs = NULL; ++ Trap trap; ++ ++ if (set_trap(&trap)) { ++ json_read_string(&c->inp, pty_type, sizeof(pty_type)); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ json_read_string(&c->inp, encoding, sizeof(encoding)); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ envp = json_read_alloc_string_array(&c->inp, &envp_len); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ if (read_stream(&c->inp) != MARKER_EOM) ++ exception(ERR_JSON_SYNTAX); ++ ++ if (err == 0 && start_terminal(c, pty_type, encoding, envp, envp_len, ++ TERM_LAUNCH_EXEC, args, &pid, &prs) < 0) ++ err = errno; ++ if (prs != NULL) { ++ write_terminal_input(prs); ++ prs->out_struct = read_terminal_output(prs, prs->out, prs->out_id, ++ sizeof(prs->out_id)); ++ if (prs->out != prs->err) ++ prs->err_struct = read_terminal_output(prs, prs->err, ++ prs->err_id, sizeof(prs->err_id)); ++ } ++ if (!err) { ++ add_waitpid_process(pid); ++ } ++ //write result back ++ { ++ write_stringz(&c->out, "R"); ++ write_stringz(&c->out, token); ++ write_errno(&c->out, err); ++ if (err || pid == 0) { ++ write_stringz(&c->out, "null"); ++ } else { ++ write_context(&c->out, pid); ++ write_stream(&c->out, 0); ++ } ++ write_stream(&c->out, MARKER_EOM); ++ } ++ clear_trap(&trap); ++ } ++ ++ loc_free(envp); ++ ++ if (trap.error) ++ exception(trap.error); ++} ++ ++static void command_set_win_size(char * token, Channel * c) ++{ ++ int err = 0; ++ struct winsize size; ++ char id[256]; ++ unsigned tid; ++ Terminal *term = NULL; ++ ++ json_read_string(&c->inp, id, sizeof(id)); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ size.ws_col=json_read_ulong(&c->inp); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ size.ws_row=json_read_ulong(&c->inp); ++ if (read_stream(&c->inp) != 0) ++ exception(ERR_JSON_SYNTAX); ++ if (read_stream(&c->inp) != MARKER_EOM) ++ exception(ERR_JSON_SYNTAX); ++ ++ tid = id2tid(id); ++ ++ if(tid==0 || (term=find_terminal(tid))==NULL) { ++ err=ERR_INV_CONTEXT; ++ }else if (term->width != size.ws_col || term->height != size.ws_row) { ++ if(ioctl(term->inp,TIOCSWINSZ,&size)<0) { ++ err=errno; ++ } ++ if(!err) { ++ term->width=size.ws_col; ++ term->height=size.ws_row; ++ send_event_terminal_win_size_changed(&term->channel->out,term); ++ } ++ } ++ ++ write_stringz(&c->out, "R"); ++ write_stringz(&c->out, token); ++ write_errno(&c->out, err); ++ write_stream(&c->out, MARKER_EOM); ++ ++} ++ ++static void waitpid_listener(int pid, int exited, int exit_code, int signal, ++ int event_code, int syscall, void * args) ++{ ++ if (exited) { ++ Terminal * prs = find_terminal(pid); ++ if (prs) { ++ if (signal != 0) ++ prs->exit_code = -signal; ++ else ++ prs->exit_code = exit_code; ++ terminal_exited(prs); ++ } ++ } ++} ++ ++static void channel_close_listener(Channel * c) ++{ ++ LINK * l = NULL; ++ ++ for (l = terms_list.next; l != &terms_list;) { ++ Terminal * term = link2term(l); ++ l = l->next; ++ if (term->channel == c) { ++ trace(LOG_ALWAYS, "Terminal is left launched: T%d", term->pid); ++ kill_term(term); ++ } ++ } ++} ++ ++void ini_terminals_service(Protocol * proto) ++{ ++#if defined(_WRS_KERNEL) ++ prs_list_lock = semMCreate(SEM_Q_PRIORITY); ++ if (prs_list_lock == NULL) check_error(errno); ++ if (taskCreateHookAdd((FUNCPTR)task_create_hook) != OK) check_error(errno); ++ if (taskDeleteHookAdd((FUNCPTR)task_delete_hook) != OK) check_error(errno); ++#endif ++ list_init(&terms_list); ++ ++ add_waitpid_listener(waitpid_listener, NULL); ++ add_channel_close_listener(channel_close_listener); ++ ++ add_command_handler(proto, TERMINALS, "getContext", command_get_context); ++ add_command_handler(proto, TERMINALS, "launch", command_launch); ++ add_command_handler(proto, TERMINALS, "exit", command_exit); ++ add_command_handler(proto, TERMINALS, "setWinSize", command_set_win_size); ++} +Index: org.eclipse.tm.tcf.terminals.agent/main/services-ext.h +=================================================================== +--- org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0) ++++ org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0) +@@ -0,0 +1,26 @@ ++/******************************************************************************* ++ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. ++ * All rights reserved. This program and the accompanying materials ++ * are made available under the terms of the Eclipse Public License v1.0 ++ * and Eclipse Distribution License v1.0 which accompany this distribution. ++ * The Eclipse Public License is available at ++ * http://www.eclipse.org/legal/epl-v10.html ++ * and the Eclipse Distribution License is available at ++ * http://www.eclipse.org/org/documents/edl-v10.php. ++ * ++ * Contributors: ++ * Wind River Systems - initial API and implementation ++ * Intel - implemented terminals service ++ *******************************************************************************/ ++ ++/* ++ * Services initialization code extension point. ++ * If the agent is built with additional user-defined services, ++ * a customized version of services-ext.h file can be added to compiler headers search paths. ++ */ ++ ++#include "terminals.h" ++ ++static void ini_ext_services(Protocol * proto, TCFBroadcastGroup * bcg) { ++ ini_terminals_service(proto); ++} +Index: org.eclipse.tm.tcf.terminals.agent/terminals.h +=================================================================== +--- org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0) ++++ org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0) +@@ -0,0 +1,28 @@ ++/******************************************************************************* ++ * Copyright (c) 2008 Wind River Systems, Inc. and others. ++ * All rights reserved. This program and the accompanying materials ++ * are made available under the terms of the Eclipse Public License v1.0 ++ * and Eclipse Distribution License v1.0 which accompany this distribution. ++ * The Eclipse Public License is available at ++ * http://www.eclipse.org/legal/epl-v10.html ++ * and the Eclipse Distribution License is available at ++ * http://www.eclipse.org/org/documents/edl-v10.php. ++ * ++ * Contributors: ++ * Wind River Systems - initial API and implementation ++ * Intel - implemented terminals service ++ *******************************************************************************/ ++ ++/* ++ * TCF terminals service header file. ++ */ ++ ++#ifndef TERMINALS_H_ ++#define TERMINALS_H_ ++ ++#include ++#include ++ ++extern void ini_terminals_service(Protocol * proto); ++ ++#endif /*TERMINALS_H_*/ +Index: org.eclipse.tm.tcf.terminals.agent/config.h +=================================================================== +--- org.eclipse.tm.tcf.terminals.agent/config.h (revision 0) ++++ org.eclipse.tm.tcf.terminals.agent/config.h (revision 0) +@@ -0,0 +1,64 @@ ++/******************************************************************************* ++ * Copyright (c) 2008 Wind River Systems, Inc. and others. ++ * All rights reserved. This program and the accompanying materials ++ * are made available under the terms of the Eclipse Public License v1.0 ++ * and Eclipse Distribution License v1.0 which accompany this distribution. ++ * The Eclipse Public License is available at ++ * http://www.eclipse.org/legal/epl-v10.html ++ * and the Eclipse Distribution License is available at ++ * http://www.eclipse.org/org/documents/edl-v10.php. ++ * ++ * Contributors: ++ * Wind River Systems - initial API and implementation ++ * Intel - implemented terminals service ++ *******************************************************************************/ ++ ++/* ++ * This file contains "define" statements that control agent configuration. ++ * SERVICE_* definitions control which service implementations are included into the agent. ++ * ++ * This is example agent configuration. It includes only few standard services, ++ * and one example service: Day Time. ++ */ ++ ++#ifndef D_config ++#define D_config ++ ++#include ++ ++#if defined(WIN32) || defined(__CYGWIN__) ++# define TARGET_UNIX 0 ++#elif defined(_WRS_KERNEL) ++# define TARGET_UNIX 0 ++#else ++# define TARGET_UNIX 1 ++#endif ++ ++#define SERVICE_Locator 1 ++#define SERVICE_Processes 1 ++#define SERVICE_Streams 1 ++#define SERVICE_FileSystem 1 ++#define SERVICE_SysMonitor TARGET_UNIX ++ ++#define ENABLE_ZeroCopy 1 ++ ++#if !defined(ENABLE_Splice) ++# if ENABLE_ZeroCopy ++# include ++# if defined(SPLICE_F_MOVE) ++# define ENABLE_Splice 1 ++# else ++# define ENABLE_Splice 0 ++# endif ++# else ++# define ENABLE_Splice 0 ++# endif ++#endif ++ ++#define ENABLE_SSL 0 ++ ++#define ENABLE_Trace 1 ++#define ENABLE_Discovery 1 ++ ++ ++#endif /* D_config */ +Index: org.eclipse.tm.tcf.terminals.agent/Makefile +=================================================================== +--- org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0) ++++ org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0) +@@ -0,0 +1,39 @@ ++TCF_AGENT_DIR=../agent ++ ++include $(TCF_AGENT_DIR)/Makefile.inc ++ ++override CFLAGS += $(foreach dir,$(INCDIRS),-I$(dir)) $(OPTS) ++ ++HFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.h)) $(HFILES) ++CFILES := $(sort $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)) $(CFILES)) ++ ++#no using SSL ++LIBS = -lpthread -lrt ++ ++EXECS = $(BINDIR)/agent$(EXTEXE) ++ ++all: $(EXECS) ++ ++$(BINDIR)/libtcf$(EXTLIB) : $(OFILES) ++ $(AR) rcs $@ $^ ++ ++$(BINDIR)/agent$(EXTEXE): $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB) ++ $(CC) $(CFLAGS) -o $@ $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB) $(LIBS) ++ ++$(BINDIR)/%$(EXTOBJ): %.c $(HFILES) Makefile ++ @mkdir -p $(dir $@) ++ $(CC) $(CFLAGS) -c -o $@ $< ++ ++$(BINDIR)/%$(EXTOBJ): $(TCF_AGENT_DIR)/%.c $(HFILES) Makefile ++ @mkdir -p $(dir $@) ++ $(CC) $(CFLAGS) -c -o $@ $< ++ ++install: all ++ install -d -m 755 $(INSTALLROOT)$(SBIN) ++ install -d -m 755 $(INSTALLROOT)$(INIT) ++ install -c $(BINDIR)/agent -m 755 $(INSTALLROOT)$(SBIN)/tcf-agent ++ install -c $(TCF_AGENT_DIR)/main/tcf-agent.init -m 755 $(INSTALLROOT)$(INIT)/tcf-agent ++ ++clean: ++ rm -rf $(BINDIR) ++ diff --git a/tcf/terminals_plugin.patch b/tcf/terminals_plugin.patch new file mode 100644 index 0000000..352e151 --- /dev/null +++ b/tcf/terminals_plugin.patch @@ -0,0 +1,618 @@ +Index: plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF (revision 0) +@@ -0,0 +1,14 @@ ++Manifest-Version: 1.0 ++Bundle-ManifestVersion: 2 ++Bundle-Name: %pluginName ++Bundle-SymbolicName: org.eclipse.tm.tcf.terminals;singleton:=true ++Bundle-Version: 0.3.0.qualifier ++Bundle-Activator: org.eclipse.tm.internal.tcf.terminals.Activator ++Bundle-Vendor: %providerName ++Require-Bundle: org.eclipse.core.runtime, ++ org.eclipse.tm.tcf ++Bundle-ActivationPolicy: lazy ++Bundle-RequiredExecutionEnvironment: JavaSE-1.6 ++Import-Package: org.eclipse.tm.tcf.core;version="0.3.0", ++ org.eclipse.tm.tcf.protocol;version="0.3.0" ++Export-Package: org.eclipse.tm.internal.tcf.terminals +Index: plugins/org.eclipse.tm.tcf.terminals/.classpath +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/.classpath (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/.classpath (revision 0) +@@ -0,0 +1,7 @@ ++ ++ ++ ++ ++ ++ ++ +Index: plugins/org.eclipse.tm.tcf.terminals/.project +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/.project (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/.project (revision 0) +@@ -0,0 +1,28 @@ ++ ++ ++ org.eclipse.tm.tcf.terminals ++ ++ ++ ++ ++ ++ org.eclipse.jdt.core.javabuilder ++ ++ ++ ++ ++ org.eclipse.pde.ManifestBuilder ++ ++ ++ ++ ++ org.eclipse.pde.SchemaBuilder ++ ++ ++ ++ ++ ++ org.eclipse.pde.PluginNature ++ org.eclipse.jdt.core.javanature ++ ++ +Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java (revision 0) +@@ -0,0 +1,191 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel - initial API and implementation ++ *******************************************************************************/ ++ ++package org.eclipse.tm.internal.tcf.terminals; ++ ++import java.io.IOException; ++import java.util.HashMap; ++import java.util.Map; ++ ++import org.eclipse.tm.internal.tcf.terminals.ITerminalsService; ++import org.eclipse.tm.tcf.core.Command; ++import org.eclipse.tm.tcf.protocol.IChannel; ++import org.eclipse.tm.tcf.protocol.IToken; ++import org.eclipse.tm.tcf.protocol.JSON; ++import org.eclipse.tm.tcf.protocol.Protocol; ++ ++public class TerminalsServiceProxy implements ITerminalsService { ++ ++ private final IChannel channel; ++ private final Map listeners = ++ new HashMap(); ++ ++ private class TerminalContext implements ITerminalsService.TerminalContext { ++ ++ private final Map props; ++ ++ TerminalContext(Map props) { ++ this.props = props; ++ } ++ ++ public String getID() { ++ return (String)props.get(PROP_ID); ++ } ++ ++ public String getPtyType() { ++ return (String)props.get(PROP_PTY_TYPE); ++ } ++ ++ public String getEncoding() { ++ return (String)props.get(PROP_ENCODING); ++ } ++ ++ public int getWidth() { ++ return ((Integer)props.get(PROP_WIDTH)).intValue(); ++ } ++ ++ public int getHeight() { ++ return ((Integer)props.get(PROP_HEIGHT)).intValue(); ++ } ++ ++ public IToken exit(final DoneCommand done) { ++ return new Command(channel, TerminalsServiceProxy.this, ++ "exit", new Object[]{ getID() }) { ++ @Override ++ public void done(Exception error, Object[] args) { ++ if (error == null) { ++ assert args.length == 1; ++ error = toError(args[0]); ++ } ++ done.doneCommand(token, error); ++ } ++ }.token; ++ } ++ ++ public Map getProperties() { ++ return props; ++ } ++ ++ public String toString() { ++ return "[Terminals Context " + props.toString() + "]"; ++ } ++ } ++ ++ TerminalsServiceProxy(IChannel channel) { ++ this.channel = channel; ++ } ++ ++ /** ++ * Return service name, as it appears on the wire - a TCF name of the service. ++ */ ++ public String getName() { ++ return NAME; ++ } ++ ++ public IToken getContext(String id, final DoneGetContext done) ++ { ++ return new Command(channel, this, ++ "getContext", new Object[]{ id }) { ++ @SuppressWarnings("unchecked") ++ @Override ++ public void done(Exception error, Object[] args) { ++ TerminalContext ctx = null; ++ if (error == null) { ++ assert args.length == 2; ++ error = toError(args[0]); ++ if (args[1] != null) ctx = new TerminalContext((Map)args[1]); ++ } ++ done.doneGetContext(token, error, ctx); ++ } ++ }.token; ++ } ++ ++ public IToken launch(String type, String encoding, String[] environment, final DoneLaunch done) ++ { ++ return new Command(channel, this, "launch", ++ new Object[]{ type, encoding, environment}) { ++ @SuppressWarnings("unchecked") ++ @Override ++ public void done(Exception error, Object[] args) { ++ TerminalContext ctx=null; ++ if (error == null) { ++ assert args.length == 2; ++ error = toError(args[0]); ++ if (args[1] != null) ctx = new TerminalContext((Map)args[1]); ++ } ++ done.doneLaunch(token, error, ctx); ++ } ++ }.token; ++ } ++ ++ public IToken setWinSize(String context_id, int newWidth, int newHeight, final DoneCommand done) ++ { ++ return new Command(channel, this, "setWinSize", ++ new Object[]{ context_id, newWidth, newHeight}) { ++ @Override ++ public void done(Exception error, Object[] args) { ++ if (error == null) { ++ assert args.length == 1; ++ error = toError(args[0]); ++ } ++ done.doneCommand(token, error); ++ } ++ }.token; ++ } ++ ++ public void addListener(final TerminalsListener listener) ++ { ++ IChannel.IEventListener l = new IChannel.IEventListener() { ++ public void event(String name, byte[] data) { ++ try { ++ Object[] args = JSON.parseSequence(data); ++ if (name.equals("exited")) { ++ assert args.length == 2; ++ listener.exited((String)args[0], ((Number)args[1]).intValue()); ++ }else if(name.equals("winSizeChanged")) { ++ assert args.length == 3; ++ listener.winSizeChanged((String)args[0], ((Number)args[1]).intValue(), ((Number)args[2]).intValue()); ++ }else { ++ throw new IOException("Terminals service: unknown event: " + name); ++ } ++ }catch (Throwable x) { ++ channel.terminate(x); ++ } ++ } ++ }; ++ channel.addEventListener(this, l); ++ listeners.put(listener, l); ++ } ++ ++ public void removeListener(TerminalsListener listener) { ++ IChannel.IEventListener l = listeners.remove(listener); ++ if (l != null) channel.removeEventListener(this, l); ++ } ++ ++ static { ++ /* ++ * Make Terminal Service proxy available to all potential clients by creating ++ * the proxy object every time a TCF communication channel is opened. ++ * Note: extension point "org.eclipse.tm.tcf.startup" is used to load this class ++ * at TCF startup time, so proxy factory is properly activated even if nobody ++ * import directly from this plugin. ++ */ ++ Protocol.addChannelOpenListener(new Protocol.ChannelOpenListener() { ++ ++ public void onChannelOpen(IChannel channel) { ++ // Check if remote server provides Daytime service ++ if (channel.getRemoteService(ITerminalsService.NAME) == null) return; ++ // Create service proxy ++ channel.setServiceProxy(ITerminalsService.class, new TerminalsServiceProxy(channel)); ++ } ++ }); ++ } ++} +Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java (revision 0) +@@ -0,0 +1,193 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel - initial API and implementation ++ *******************************************************************************/ ++ ++package org.eclipse.tm.internal.tcf.terminals; ++ ++import java.util.Map; ++ ++import org.eclipse.tm.tcf.protocol.IService; ++import org.eclipse.tm.tcf.protocol.IToken; ++ ++/** ++ * ITerminalsService allows to launch a new terminal on the remote target system. ++ */ ++public interface ITerminalsService extends IService { ++ ++ /** ++ * This service name, as it appears on the wire - a TCF name of the service. ++ */ ++ static final String NAME = "Terminals"; ++ /** ++ * Retrieve context info for given context ID. ++ * A context corresponds to an terminal. ++ * Context IDs are valid across TCF services, so it is allowed to issue ++ * 'ITerminals.getContext' command with a context that was obtained, ++ * for example, from Memory service. ++ * However, 'ITerminals.getContext' is supposed to return only terminal specific data, ++ * If the ID is not a terminal ID, 'ITerminals.getContext' may not return any ++ * useful information ++ * ++ * @param id – context ID. ++ * @param done - call back interface called when operation is completed. ++ */ ++ IToken getContext(String id, DoneGetContext done); ++ ++ /** ++ * Client call back interface for getContext(). ++ */ ++ interface DoneGetContext { ++ /** ++ * Called when contexts data retrieval is done. ++ * @param error – error description if operation failed, null if succeeded. ++ * @param context – context data. ++ */ ++ void doneGetContext(IToken token, Exception error, TerminalContext context); ++ } ++ /** ++ * Context property names. ++ */ ++ static final String ++ /** The TCF context ID */ ++ PROP_ID = "ID", ++ ++ /** The pty type */ ++ PROP_PTY_TYPE = "PtyType", ++ ++ /** terminal encoding */ ++ PROP_ENCODING = "Encoding", ++ ++ /** window width size */ ++ PROP_WIDTH = "Width", ++ ++ /** window height size */ ++ PROP_HEIGHT = "Height", ++ ++ /** Process standard input stream ID */ ++ PROP_STDIN_ID = "StdInID", ++ ++ /** Process standard output stream ID */ ++ PROP_STDOUT_ID = "StdOutID", ++ ++ /** Process standard error stream ID */ ++ PROP_STDERR_ID = "StdErrID"; ++ ++ interface TerminalContext { ++ ++ /** ++ * Get context ID. ++ * Same as getProperties().get(“ID”) ++ */ ++ String getID(); ++ ++ /** ++ * Get terminal type. ++ * Same as getProperties().get(“PtyType”) ++ */ ++ String getPtyType(); ++ ++ /** ++ * Get encoding. ++ * Same as getProperties().get(“Encoding”) ++ */ ++ String getEncoding(); ++ ++ /** ++ * Get width. ++ * Same as getProperties().get(“Width”) ++ */ ++ int getWidth(); ++ ++ /** ++ * Get height. ++ * Same as getProperties().get(“Height”) ++ */ ++ int getHeight(); ++ ++ /** ++ * Get all available context properties. ++ * @return Map 'property name' -> 'property value' ++ */ ++ Map getProperties(); ++ ++ /** ++ * Exit the terminal. ++ * @param done - call back interface called when operation is completed. ++ * @return pending command handle, can be used to cancel the command. ++ */ ++ IToken exit(DoneCommand done); ++ } ++ ++ interface DoneCommand { ++ void doneCommand(IToken token, Exception error); ++ } ++ /** ++ * Launch a new terminal toremote machine. ++ * @param type - requested terminal type for the new terminal. ++ * @param encoding - requested encoding for the new terminal. ++ * @param environment - Array of environment variable strings. ++ * if null then default set of environment variables will be used. ++ * @param done - call back interface called when operation is completed. ++ * @return pending command handle, can be used to cancel the command. ++ */ ++ IToken launch(String type, String encoding, String[] environment, ++ DoneLaunch done); ++ ++ /** ++ * Call-back interface to be called when "start" command is complete. ++ */ ++ interface DoneLaunch { ++ void doneLaunch(IToken token, Exception error, TerminalContext terminal); ++ } ++ ++ ++ /** ++ * Set the terminal widows size ++ * @param context_id - context ID. ++ * @param signal - signal code. ++ * @param done - call back interface called when operation is completed. ++ * @return pending command handle, can be used to cancel the command. ++ */ ++ IToken setWinSize(String context_id, int newWidth, int newHeight, DoneCommand done); ++ ++ /** ++ * Add terminals service event listener. ++ * @param listener - event listener implementation. ++ */ ++ void addListener(TerminalsListener listener); ++ ++ /** ++ * Remove terminals service event listener. ++ * @param listener - event listener implementation. ++ */ ++ void removeListener(TerminalsListener listener); ++ ++ /** ++ * Process event listener is notified when a terminal exits. ++ * Event are reported only for terminals that were started by 'launch' command. ++ */ ++ interface TerminalsListener { ++ ++ /** ++ * Called when a terminal exits. ++ * @param terminal_id - terminal context ID ++ * @param exit_code - terminal exit code ++ */ ++ void exited(String terminal_id, int exit_code); ++ ++ /** ++ * Called when a terminal exits. ++ * @param terminal_id - terminal context ID ++ * @param newWidth – new terminal width ++ * @param newHeight – new terminal height ++ */ ++ void winSizeChanged (String terminal_id, int newWidth, int newHeight); ++ } ++} +Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java (revision 0) +@@ -0,0 +1,61 @@ ++/******************************************************************************* ++ * Copyright (c) 2010 Intel 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: ++ * Intel - initial API and implementation ++ *******************************************************************************/ ++ ++package org.eclipse.tm.internal.tcf.terminals; ++ ++import org.eclipse.core.runtime.Plugin; ++import org.osgi.framework.BundleContext; ++ ++/** ++ * The activator class controls the plug-in life cycle ++ */ ++public class Activator extends Plugin { ++ ++ // The plug-in ID ++ public static final String PLUGIN_ID = "org.eclipse.tm.tcf.terminals"; ++ ++ // The shared instance ++ private static Activator plugin; ++ ++ /** ++ * The constructor ++ */ ++ public Activator() { ++ } ++ ++ /* ++ * (non-Javadoc) ++ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) ++ */ ++ public void start(BundleContext context) throws Exception { ++ super.start(context); ++ plugin = this; ++ } ++ ++ /* ++ * (non-Javadoc) ++ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) ++ */ ++ public void stop(BundleContext context) throws Exception { ++ plugin = null; ++ super.stop(context); ++ } ++ ++ /** ++ * Returns the shared instance ++ * ++ * @return the shared instance ++ */ ++ public static Activator getDefault() { ++ return plugin; ++ } ++ ++} +Index: plugins/org.eclipse.tm.tcf.terminals/plugin.properties +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/plugin.properties (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/plugin.properties (revision 0) +@@ -0,0 +1,13 @@ ++############################################################################### ++# Copyright (c) 2010 Intel, Inc. 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: ++# Intel - initial implementation ++############################################################################### ++pluginName = TCF Terminals service (Incubation) ++providerName = Eclipse.org ++ +Index: plugins/org.eclipse.tm.tcf.terminals/build.properties +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/build.properties (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/build.properties (revision 0) +@@ -0,0 +1,8 @@ ++source.. = src/ ++output.. = bin/ ++bin.includes = META-INF/,\ ++ .,\ ++ plugin.xml,\ ++ about.html,\ ++ plugin.properties ++src.includes = about.html +Index: plugins/org.eclipse.tm.tcf.terminals/plugin.xml +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/plugin.xml (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/plugin.xml (revision 0) +@@ -0,0 +1,11 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: plugins/org.eclipse.tm.tcf.terminals/about.html +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/about.html (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/about.html (revision 0) +@@ -0,0 +1,28 @@ ++ ++ ++ ++ ++About ++ ++ ++

About This Content

++ ++

January 10, 2008

++

License

++ ++

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise ++indicated below, the Content is provided to you under the terms and conditions of the ++Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available ++at http://www.eclipse.org/legal/epl-v10.html. ++For purposes of the EPL, "Program" will mean the Content.

++ ++

If you did not receive this Content directly from the Eclipse Foundation, the Content is ++being redistributed by another party ("Redistributor") and different terms and conditions may ++apply to your use of any object code in the Content. Check the Redistributor's license that was ++provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise ++indicated below, the terms and conditions of the EPL still apply to any source code in the Content ++and such source code may be obtained at http://www.eclipse.org.

++ ++ ++ +\ No newline at end of file +Index: plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs +=================================================================== +--- plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs (revision 0) ++++ plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs (revision 0) +@@ -0,0 +1,8 @@ ++#Mon Jun 07 11:42:38 CST 2010 ++eclipse.preferences.version=1 ++org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled ++org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 ++org.eclipse.jdt.core.compiler.compliance=1.6 ++org.eclipse.jdt.core.compiler.problem.assertIdentifier=error ++org.eclipse.jdt.core.compiler.problem.enumIdentifier=error ++org.eclipse.jdt.core.compiler.source=1.6 -- cgit v1.2.3-54-g00ecf