summaryrefslogtreecommitdiffstats
path: root/tcf
diff options
context:
space:
mode:
Diffstat (limited to 'tcf')
-rw-r--r--tcf/lke_rse_tcf.patch2097
-rw-r--r--tcf/readme175
-rw-r--r--tcf/terminals_agent.patch1042
-rw-r--r--tcf/terminals_plugin.patch618
4 files changed, 3932 insertions, 0 deletions
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 @@
1Index: plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF
2===================================================================
3--- plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF (revision 1190)
4+++ plugins/org.eclipse.tm.tcf.rse/META-INF/MANIFEST.MF (working copy)
5@@ -13,8 +13,16 @@
6 org.eclipse.ui.views,
7 org.eclipse.rse.subsystems.files.core,
8 org.eclipse.rse.subsystems.processes.core,
9- org.eclipse.rse.processes.ui
10+ org.eclipse.rse.processes.ui,
11+ org.eclipse.rse.subsystems.terminals.core,
12+ org.eclipse.tm.tcf;bundle-version="0.3.0",
13+ org.eclipse.rse.subsystems.shells.core;bundle-version="3.1.100",
14+ org.eclipse.core.resources;bundle-version="3.6.0",
15+ org.eclipse.tm.tcf.core;version="0.3.0"
16 Import-Package: org.eclipse.tm.tcf.core;version="0.3.0",
17+ org.eclipse.rse.core.filters,
18+ org.eclipse.tm.internal.tcf.terminals,
19+ org.eclipse.rse.core.model,
20 org.eclipse.tm.tcf.protocol;version="0.3.0",
21 org.eclipse.tm.tcf.services;version="0.3.0",
22 org.eclipse.tm.tcf.util;version="0.3.0"
23Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java
24===================================================================
25--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java (revision 1190)
26+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileSubSystemConfiguration.java (working copy)
27@@ -39,6 +39,11 @@
28
29 private final TCFFileAdapter file_adapter = new TCFFileAdapter();
30
31+ public TCFFileSubSystemConfiguration() {
32+ super();
33+ setIsUnixStyle(true);
34+ }
35+
36 @Override
37 public ISubSystem createSubSystemInternal(IHost host) {
38 TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host);
39@@ -78,13 +83,12 @@
40 @Override
41 public IConnectorService getConnectorService(IHost host) {
42 return TCFConnectorServiceManager.getInstance()
43- .getConnectorService(host, ITCFSubSystem.class);
44+ .getConnectorService(host, getServiceImplType());
45 }
46
47 @Override
48- @SuppressWarnings("unchecked")
49- public Class getServiceImplType() {
50- return TCFFileService.class;
51+ public Class<ITCFSubSystem> getServiceImplType() {
52+ return ITCFSubSystem.class;
53 }
54
55 @Override
56Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java
57===================================================================
58--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java (revision 1190)
59+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/files/TCFFileService.java (working copy)
60@@ -11,6 +11,7 @@
61 * Uwe Stieber (Wind River) - [271224] NPE in TCFFileService#download
62 * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse
63 * Uwe Stieber (Wind River) - [274277] The TCF file service subsystem implementation is not updating the progress monitor
64+ * Intel Corporation - Make recursive copy/delete available (delete/copy a folder contains files)
65 *******************************************************************************/
66 package org.eclipse.tm.internal.tcf.rse.files;
67
68@@ -18,6 +19,7 @@
69 import java.io.BufferedOutputStream;
70 import java.io.File;
71 import java.io.FileInputStream;
72+import java.io.FileNotFoundException;
73 import java.io.FileOutputStream;
74 import java.io.IOException;
75 import java.io.InputStream;
76@@ -131,22 +133,125 @@
77 return s;
78 }
79
80+ /* Delete from UI action will call deleteBatch interface, yet
81+ * for copy from UI action, it will call copy! It's totally
82+ * inconsistency! For solving the problem, we have to modify
83+ * the copy itself and made it recursive. We can't modify it
84+ * in the same way as delete does!
85+ *
86+ */
87+
88+ public void internalCopy(String srcParent,
89+ String srcName, String tgtParent, String tgtName, IProgressMonitor monitor)
90+ throws SystemMessageException, InterruptedException {
91+ //Note the dest directory or file exist surely since UI operations have
92+ //done something, rename it to copy of XXX
93+ if (monitor != null)
94+ {
95+ if (monitor.isCanceled())
96+ {
97+ throw new InterruptedException("User cancelled the copy operation!");
98+ }
99+ }
100+
101+ try
102+ {
103+ //firstly create the target directory!
104+ this.createFolder(tgtParent, tgtName, monitor);
105+ //then copy the next level directory!
106+ final String new_srcpath = toRemotePath(srcParent, srcName);
107+ final String new_tgtpath = toRemotePath(tgtParent, tgtName);
108+ IHostFile[] arrFiles = internalFetch(new_srcpath, null,
109+ FILE_TYPE_FILES_AND_FOLDERS, monitor);
110+ if (arrFiles == null || arrFiles.length <=0 )
111+ return;
112+ else
113+ {
114+ for (int i = 0; i < arrFiles.length; i++)
115+ {
116+ String srcFile = toRemotePath(new_srcpath, arrFiles[i].getName());
117+ String tgtFile = toRemotePath(new_tgtpath, arrFiles[i].getName());
118+ if (arrFiles[i].isFile())
119+ {
120+ copy(srcFile, tgtFile, monitor);
121+ }
122+ else
123+ {
124+ //do recursive directory copy!
125+ internalCopy(new_srcpath, arrFiles[i].getName(), new_tgtpath,
126+ arrFiles[i].getName(), monitor);
127+ }
128+ }
129+ }
130+ }
131+ catch (SystemMessageException e)
132+ {
133+ e.printStackTrace();
134+ throw new SystemMessageException(e.getSystemMessage());
135+ }
136+ catch (InterruptedException e)
137+ {
138+ throw new InterruptedException("User cancelled the copy operation!");
139+ }
140+ }
141+
142 public void copy(String srcParent,
143 String srcName, String tgtParent, String tgtName, IProgressMonitor monitor)
144 throws SystemMessageException {
145- final String src = toRemotePath(srcParent, srcName);
146- final String tgt = toRemotePath(tgtParent, tgtName);
147+
148+ if (monitor != null)
149+ monitor.beginTask("Copying remote files!", 1);
150+
151+ try {
152+
153+ IHostFile curFile = getFile(srcParent, srcName, monitor);
154+ final String srcFile = toRemotePath(srcParent, srcName);
155+ final String tgtFile = toRemotePath(tgtParent, tgtName);
156+
157+ if (curFile.isFile())
158+ copy(srcFile, tgtFile, monitor);
159+ else if (curFile.isDirectory())
160+ {
161+ internalCopy(srcParent, srcName, tgtParent, tgtName, monitor);
162+ }
163+ else
164+ {
165+ FileNotFoundException e =
166+ new FileNotFoundException("Failed to find the to be " +
167+ "copied file or directory!");
168+ throw new SystemMessageException(getMessage(e));
169+ }
170+ }
171+ catch (Exception e) {
172+ // TODO Auto-generated catch block
173+ if (e instanceof SystemMessageException)
174+ throw (SystemMessageException)e;
175+ else if (e instanceof InterruptedException)
176+ {
177+ System.out.println("User cancelled the copy operation!");
178+ }
179+ throw new SystemOperationFailedException(Activator.PLUGIN_ID, e);
180+
181+ }
182+ finally {
183+ if (monitor != null)
184+ monitor.done();
185+ }
186+ }
187+
188+ public void copy(final String srcFile, final String tgtFile, IProgressMonitor monitor)
189+ throws SystemMessageException {
190 new TCFRSETask<Boolean>() {
191 public void run() {
192 IFileSystem fs = connector.getFileSystemService();
193- fs.copy(src, tgt, false, false, new IFileSystem.DoneCopy() {
194+ fs.copy(srcFile, tgtFile, false, false, new IFileSystem.DoneCopy() {
195 public void doneCopy(IToken token, FileSystemException error) {
196 if (error != null) error(error);
197 else done(Boolean.TRUE);
198 }
199 });
200 }
201- }.getS(monitor, "Copy: " + srcName); //$NON-NLS-1$
202+ }.getS(monitor, "Copy: " + srcFile); //$NON-NLS-1$
203 }
204
205 public void copyBatch(String[] srcParents,
206@@ -226,13 +331,81 @@
207 }.getS(monitor, "Delete"); //$NON-NLS-1$
208 }
209
210+ private void internalDelete(String parent, String name,
211+ IProgressMonitor monitor)
212+ throws SystemMessageException, InterruptedException
213+ {
214+ if (monitor != null)
215+ {
216+ if (monitor.isCanceled())
217+ {
218+ throw new InterruptedException("User cancelled the delete operation!");
219+ }
220+ }
221+
222+ try
223+ {
224+ final String new_path = toRemotePath(parent, name);
225+ IHostFile[] arrFiles = internalFetch(new_path, null,
226+ FILE_TYPE_FILES_AND_FOLDERS, monitor);
227+ if (arrFiles == null || arrFiles.length <= 0)
228+ {
229+ //This is an empty directory, directly delete!
230+ delete(parent, name, monitor);
231+ }
232+ else
233+ {
234+ for (int i = 0; i < arrFiles.length; i++)
235+ {
236+
237+ if (arrFiles[i].isFile())
238+ {
239+ delete(new_path, arrFiles[i].getName(), monitor);
240+ }
241+ else
242+ internalDelete(new_path, arrFiles[i].getName(), monitor);
243+ }
244+ //now the folder becomes empty, let us delete it!
245+ delete(parent, name, monitor);
246+ }
247+ }
248+ catch (SystemMessageException e) {
249+ // TODO Auto-generated catch block
250+ e.printStackTrace();
251+ throw new SystemMessageException(e.getSystemMessage());
252+ }
253+ catch (InterruptedException e) {
254+ throw new InterruptedException("User cancelled the delete operation!");
255+ }
256+ }
257+
258 @Override
259 public void deleteBatch(String[] remoteParents, String[] fileNames,
260 IProgressMonitor monitor)
261- throws SystemMessageException {
262- for (int i = 0; i < remoteParents.length; i++) {
263- delete(remoteParents[i], fileNames[i], monitor);
264+ throws SystemMessageException {
265+ if (monitor != null)
266+ monitor.beginTask("Deleting selected folders or files!", remoteParents.length);
267+ try
268+ {
269+ for (int i = 0; i < remoteParents.length; i++) {
270+ IHostFile curFile = getFile(remoteParents[i], fileNames[i], monitor);
271+ if (curFile.isFile())
272+ delete(remoteParents[i], fileNames[i], monitor);
273+ else if (curFile.isDirectory())
274+ internalDelete(remoteParents[i], fileNames[i], monitor);
275+ }
276 }
277+ catch (Exception x) {
278+ if (x instanceof SystemMessageException) throw (SystemMessageException)x;
279+ else if (x instanceof InterruptedException) {
280+ System.out.println("user cancelled the delete operation!");
281+ }
282+ throw new SystemOperationFailedException(Activator.PLUGIN_ID, x);
283+ }
284+ finally {
285+ if (monitor != null)
286+ monitor.done();
287+ }
288 }
289
290 public void download(final String parent,
291Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java
292===================================================================
293--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java (revision 0)
294+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.java (revision 0)
295@@ -0,0 +1,28 @@
296+/*******************************************************************************
297+ * Copyright (c) 2010 Intel Corporation. and others.
298+ * All rights reserved. This program and the accompanying materials
299+ * are made available under the terms of the Eclipse Public License v1.0
300+ * which accompanies this distribution, and is available at
301+ * http://www.eclipse.org/legal/epl-v10.html
302+ *
303+ * Contributors:
304+ * Intel Corporation - initial API and implementation
305+ ******************************************************************************/
306+package org.eclipse.tm.internal.tcf.rse;
307+
308+import org.eclipse.osgi.util.NLS;
309+
310+public class TCFConnectorResources extends NLS {
311+ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.TCFConnectorResources";
312+ static {
313+ NLS.initializeMessages(BUNDLE_NAME, TCFConnectorResources.class);
314+ }
315+ private TCFConnectorResources() {
316+
317+ }
318+
319+ public static String TCFConnectorService_Name;
320+ public static String TCFConnectorService_Description;
321+ public static String PropertySet_Description;
322+
323+}
324Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java
325===================================================================
326--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java (revision 0)
327+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/ITCFSessionProvider.java (revision 0)
328@@ -0,0 +1,29 @@
329+/*******************************************************************************
330+ * Copyright (c) 2010 Intel Corporation. and others.
331+ * All rights reserved. This program and the accompanying materials
332+ * are made available under the terms of the Eclipse Public License v1.0
333+ * which accompanies this distribution, and is available at
334+ * http://www.eclipse.org/legal/epl-v10.html
335+ *
336+ * Contributors:
337+ * Intel Corporation - initial API and implementation
338+ ******************************************************************************/
339+
340+package org.eclipse.tm.internal.tcf.rse;
341+
342+import org.eclipse.rse.services.files.RemoteFileException;
343+import org.eclipse.tm.tcf.protocol.IChannel;
344+
345+public interface ITCFSessionProvider {
346+ public static final int ERROR_CODE = 100; // filed error code
347+ public static final int SUCCESS_CODE = 150; // login pass code
348+ public static final int CONNECT_CLOSED = 200; // code for end of login attempts
349+ public static final int TCP_CONNECT_TIMEOUT = 10; //seconds - TODO: Make configurable
350+
351+ public IChannel getChannel();
352+ public String getSessionUserId();
353+ public String getSessionPassword();
354+ public String getSessionHostName();
355+ public boolean isSubscribed();
356+ public void Subscribe() throws RemoteFileException;
357+}
358Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java
359===================================================================
360--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java (revision 1190)
361+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/processes/TCFProcessSubSystemConfiguration.java (working copy)
362@@ -26,10 +26,8 @@
363
364 private final TCFProcessAdapter process_adapter = new TCFProcessAdapter();
365
366- @Override
367- @SuppressWarnings("unchecked")
368- public Class getServiceImplType() {
369- return TCFProcessService.class;
370+ public Class<ITCFSubSystem> getServiceImplType() {
371+ return ITCFSubSystem.class;
372 }
373
374 @Override
375@@ -50,7 +48,7 @@
376 @Override
377 public IConnectorService getConnectorService(IHost host) {
378 return TCFConnectorServiceManager.getInstance()
379- .getConnectorService(host, ITCFSubSystem.class);
380+ .getConnectorService(host, getServiceImplType());
381 }
382
383 @Override
384Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java
385===================================================================
386--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java (revision 1190)
387+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorService.java (working copy)
388@@ -10,29 +10,49 @@
389 * Martin Oberhuber (Wind River) - [269682] Get port from RSE Property
390 * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse
391 * Anna Dushistova (MontaVista) - [285373] TCFConnectorService should send CommunicationsEvent.BEFORE_CONNECT and CommunicationsEvent.BEFORE_DISCONNECT
392- *******************************************************************************/
393+ * Intel Corporation - Make TCF being authenticated connection and attached streaming subscription/unsubscription method
394+ ******************************************************************************/
395 package org.eclipse.tm.internal.tcf.rse;
396
397+import java.io.IOException;
398 import java.util.ArrayList;
399 import java.util.HashMap;
400 import java.util.List;
401 import java.util.Map;
402+import java.util.concurrent.ExecutionException;
403+import java.util.concurrent.TimeUnit;
404+import java.util.concurrent.TimeoutException;
405
406 import org.eclipse.core.runtime.IProgressMonitor;
407 import org.eclipse.rse.core.model.IHost;
408-import org.eclipse.rse.core.subsystems.BasicConnectorService;
409+import org.eclipse.rse.core.model.IPropertySet;
410+import org.eclipse.rse.core.model.PropertyType;
411+import org.eclipse.rse.core.model.SystemSignonInformation;
412 import org.eclipse.rse.core.subsystems.CommunicationsEvent;
413+import org.eclipse.rse.services.files.RemoteFileException;
414+import org.eclipse.rse.ui.subsystems.StandardConnectorService;
415+import org.eclipse.tm.internal.tcf.terminals.ITerminalsService;
416 import org.eclipse.tm.tcf.core.AbstractPeer;
417 import org.eclipse.tm.tcf.protocol.IChannel;
418 import org.eclipse.tm.tcf.protocol.IPeer;
419 import org.eclipse.tm.tcf.protocol.IService;
420+import org.eclipse.tm.tcf.protocol.IToken;
421 import org.eclipse.tm.tcf.protocol.Protocol;
422 import org.eclipse.tm.tcf.services.IFileSystem;
423 import org.eclipse.tm.tcf.services.ILocator;
424+import org.eclipse.tm.tcf.services.IStreams;
425 import org.eclipse.tm.tcf.services.ISysMonitor;
426+import org.eclipse.tm.tcf.util.TCFTask;
427
428+public class TCFConnectorService extends StandardConnectorService implements
429+ ITCFSessionProvider {
430
431-public class TCFConnectorService extends BasicConnectorService {
432+ public static final String PROPERTY_SET_NAME = "TCF Connection Settings";
433+ public static final String PROPERTY_LOGIN_REQUIRED = "Login.Required"; //$NON-NLS-1$
434+ public static final String PROPERTY_PWD_REQUIRED="Pwd.Required";
435+ public static final String PROPERTY_LOGIN_PROMPT = "Login.Prompt"; //$NON-NLS-1$
436+ public static final String PROPERTY_PASSWORD_PROMPT = "Password.Prompt"; //$NON-NLS-1$
437+ public static final String PROPERTY_COMMAND_PROMPT = "Command.Prompt"; //$NON-NLS-1$
438
439 private IChannel channel;
440 private Throwable channel_error;
441@@ -40,12 +60,62 @@
442
443 private boolean poll_timer_started;
444
445+ private boolean bSubscribed = false;
446+
447+ /* subscribe the stream service on this TCP connection */
448+ private IStreams.StreamsListener streamListener = new IStreams.StreamsListener() {
449+ public void created(String stream_type, String stream_id,
450+ String context_id) {
451+ System.out.printf("new stream id: %s , type: %s is created\n",
452+ stream_id, stream_type);
453+ }
454+
455+ /**
456+ * Called when a stream is disposed.
457+ *
458+ * @param stream_type
459+ * - source type of the stream.
460+ * @param stream_id
461+ * - ID of the stream.
462+ */
463+ public void disposed(String stream_type, String stream_id) {
464+ System.out.printf("stream id: %s type: %s is disposed\n",
465+ stream_id, stream_type);
466+ }
467+ };
468+
469 public TCFConnectorService(IHost host, int port) {
470- super("TCF", "Target Communication Framework", host, port); //$NON-NLS-1$ //$NON-NLS-2$
471+ super(TCFConnectorResources.TCFConnectorService_Name,
472+ TCFConnectorResources.TCFConnectorService_Description, host,
473+ port); //$NON-NLS-1$ //$NON-NLS-2$
474+ getTCFPropertySet();
475 }
476+
477+ public IPropertySet getTCFPropertySet() {
478+ IPropertySet tcfSet = getPropertySet(PROPERTY_SET_NAME);
479+ if (tcfSet == null) {
480+ tcfSet = createPropertySet(PROPERTY_SET_NAME, TCFConnectorResources.PropertySet_Description);
481+ //add default values if not set
482+ tcfSet.addProperty(PROPERTY_LOGIN_REQUIRED, "true", PropertyType.getEnumPropertyType(new String[] {"true", "false"}));
483+ tcfSet.addProperty(PROPERTY_PWD_REQUIRED, "false", PropertyType.getEnumPropertyType(new String[] {"true", "false"}));
484+ tcfSet.addProperty(PROPERTY_LOGIN_PROMPT, "ogin: ", PropertyType.getStringPropertyType());
485+ tcfSet.addProperty(PROPERTY_PASSWORD_PROMPT, "assword: ", PropertyType.getStringPropertyType());
486+ tcfSet.addProperty(PROPERTY_COMMAND_PROMPT, "#", PropertyType.getStringPropertyType());
487+ }
488+ return tcfSet;
489+ }
490
491+ /**
492+ * @return true if the associated connector service requires a password.
493+ */
494 @Override
495- protected void internalConnect(final IProgressMonitor monitor) throws Exception {
496+ public final boolean requiresPassword() {
497+ return false;
498+ }
499+
500+ @Override
501+ protected void internalConnect(final IProgressMonitor monitor)
502+ throws Exception {
503 assert !Protocol.isDispatchThread();
504 final Exception[] res = new Exception[1];
505 // Fire comm event to signal state about to change
506@@ -54,39 +124,55 @@
507 synchronized (res) {
508 Protocol.invokeLater(new Runnable() {
509 public void run() {
510- if (!connectTCFChannel(res, monitor)) add_to_wait_list(this);
511+ if (!connectTCFChannel(res, monitor))
512+ add_to_wait_list(this);
513 }
514 });
515 res.wait();
516 }
517+ if (res[0] != null) throw res[0];
518 monitor.done();
519- if (res[0] != null) throw res[0];
520 }
521
522 @Override
523- protected void internalDisconnect(final IProgressMonitor monitor) throws Exception {
524+ protected void internalDisconnect(final IProgressMonitor monitor)
525+ throws Exception {
526 assert !Protocol.isDispatchThread();
527 final Exception[] res = new Exception[1];
528 // Fire comm event to signal state about to change
529 fireCommunicationsEvent(CommunicationsEvent.BEFORE_DISCONNECT);
530 monitor.beginTask("Disconnecting " + getHostName(), 1); //$NON-NLS-1$
531- synchronized (res) {
532- Protocol.invokeLater(new Runnable() {
533- public void run() {
534- if (!disconnectTCFChannel(res, monitor)) add_to_wait_list(this);
535- }
536- });
537- res.wait();
538+ try {
539+ /* First UnSubscribe TCP channel */
540+ Unsubscribe();
541+ /* Disconnecting TCP channel */
542+ synchronized (res) {
543+ Protocol.invokeLater(new Runnable() {
544+ public void run() {
545+ if (!disconnectTCFChannel(res, monitor))
546+ add_to_wait_list(this);
547+ }
548+ });
549+ res.wait();
550+ }
551+ if (res[0] != null) throw res[0];
552+
553 }
554- monitor.done();
555- if (res[0] != null) throw res[0];
556+ catch (Exception e) {
557+ e.printStackTrace();
558+ throw new RemoteFileException("Error creating Terminal", e); //$NON-NLS-1$
559+ }
560+ finally {
561+ monitor.done();
562+ }
563 }
564
565 public boolean isConnected() {
566 final boolean res[] = new boolean[1];
567 Protocol.invokeAndWait(new Runnable() {
568 public void run() {
569- res[0] = channel != null && channel.getState() == IChannel.STATE_OPEN;
570+ res[0] = channel != null
571+ && channel.getState() == IChannel.STATE_OPEN;
572 }
573 });
574 return res[0];
575@@ -108,7 +194,8 @@
576 if (wait_list.isEmpty()) return;
577 Runnable[] r = wait_list.toArray(new Runnable[wait_list.size()]);
578 wait_list.clear();
579- for (int i = 0; i < r.length; i++) r[i].run();
580+ for (int i = 0; i < r.length; i++)
581+ r[i].run();
582 }
583
584 private boolean connectTCFChannel(Exception[] res, IProgressMonitor monitor) {
585@@ -117,9 +204,12 @@
586 case IChannel.STATE_OPEN:
587 case IChannel.STATE_CLOSED:
588 synchronized (res) {
589- if (channel_error instanceof Exception) res[0] = (Exception)channel_error;
590- else if (channel_error != null) res[0] = new Exception(channel_error);
591- else res[0] = null;
592+ if (channel_error instanceof Exception)
593+ res[0] = (Exception) channel_error;
594+ else if (channel_error != null)
595+ res[0] = new Exception(channel_error);
596+ else
597+ res[0] = null;
598 res.notify();
599 return true;
600 }
601@@ -137,7 +227,7 @@
602 String host = getHostName().toLowerCase();
603 int port = getConnectPort();
604 if (port <= 0) {
605- //Default fallback
606+ // Default fallback
607 port = TCFConnectorServiceManager.TCF_PORT;
608 }
609 IPeer peer = null;
610@@ -146,8 +236,8 @@
611 for (IPeer p : locator.getPeers().values()) {
612 Map<String, String> attrs = p.getAttributes();
613 if ("TCP".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)) && //$NON-NLS-1$
614- host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) &&
615- port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) {
616+ host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST))
617+ && port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) {
618 peer = p;
619 break;
620 }
621@@ -171,17 +261,18 @@
622
623 public void congestionLevel(int level) {
624 }
625-
626 public void onChannelClosed(Throwable error) {
627 assert channel != null;
628 channel.removeChannelListener(this);
629 channel_error = error;
630+
631 if (wait_list.isEmpty()) {
632 fireCommunicationsEvent(CommunicationsEvent.CONNECTION_ERROR);
633 }
634 else {
635 run_wait_list();
636 }
637+ bSubscribed = false;
638 channel = null;
639 channel_error = null;
640 }
641@@ -192,7 +283,8 @@
642 return false;
643 }
644
645- private boolean disconnectTCFChannel(Exception[] res, IProgressMonitor monitor) {
646+ private boolean disconnectTCFChannel(Exception[] res,
647+ IProgressMonitor monitor) {
648 if (channel == null || channel.getState() == IChannel.STATE_CLOSED) {
649 synchronized (res) {
650 res[0] = null;
651@@ -212,9 +304,12 @@
652 }
653
654 public <V extends IService> V getService(Class<V> service_interface) {
655- if (channel == null || channel.getState() != IChannel.STATE_OPEN) throw new Error("Not connected"); //$NON-NLS-1$
656+ if (channel == null || channel.getState() != IChannel.STATE_OPEN)
657+ throw new Error("Not connected"); //$NON-NLS-1$
658 V m = channel.getRemoteService(service_interface);
659- if (m == null) throw new Error("Remote peer does not support " + service_interface.getName() + " service"); //$NON-NLS-1$ //$NON-NLS-2$
660+ if (m == null)
661+ throw new Error(
662+ "Remote peer does not support " + service_interface.getName() + " service"); //$NON-NLS-1$ //$NON-NLS-2$
663 return m;
664 }
665
666@@ -225,4 +320,111 @@
667 public IFileSystem getFileSystemService() {
668 return getService(IFileSystem.class);
669 }
670+
671+ public IChannel getChannel() {
672+ // TODO Auto-generated method stub
673+ return channel;
674+ }
675+
676+ public String getSessionHostName() {
677+ // TODO Auto-generated method stub
678+ String hostName = "";
679+ IHost host = getHost();
680+ if (host != null) hostName = host.getHostName();
681+ return hostName;
682+ }
683+
684+ public String getSessionUserId() {
685+ // TODO Auto-generated method stub
686+ return getUserId();
687+ }
688+
689+ public String getSessionPassword() {
690+ // TODO Auto-generated method stub
691+ String password = "";
692+ SystemSignonInformation ssi = getSignonInformation();
693+ if (ssi != null) {
694+ password = ssi.getPassword();
695+ }
696+ return password;
697+ }
698+
699+ public boolean isSubscribed() {
700+ // TODO Auto-generated method stub
701+ return bSubscribed;
702+ }
703+
704+ public void Unsubscribe() throws IOException {
705+ if (bSubscribed) {
706+ System.out
707+ .println("Unsubscribe streams before disconnecting TCP channel.");
708+ try {
709+ new TCFTask<Object>() {
710+ public void run() {
711+ IStreams streams = getService(IStreams.class);
712+ streams.unsubscribe(ITerminalsService.NAME, streamListener,
713+ new IStreams.DoneUnsubscribe() {
714+ public void doneUnsubscribe(IToken token,
715+ Exception error) {
716+ // TODO Auto-generated method stub
717+ System.out.printf(
718+ "stream type %s unsubscribed\n",
719+ ITerminalsService.NAME);
720+ done(this);
721+ }
722+ });
723+ }
724+ }.get(1, TimeUnit.SECONDS);
725+ }
726+ catch (InterruptedException e) {
727+ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams");
728+ }
729+ catch (ExecutionException e) {
730+ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams");
731+ }
732+ catch (TimeoutException e) {
733+ new IOException("Meet " + e.getMessage() + " when Unsubsribe streams");
734+ }
735+ bSubscribed = false;
736+ }
737+
738+ }
739+
740+ public void Subscribe() throws RemoteFileException {
741+ try {
742+ new TCFTask<Object>() {
743+ public void run() {
744+ if (bSubscribed) {
745+ done(this);
746+ }
747+ else {
748+ bSubscribed = true;
749+ IStreams streams = getService(IStreams.class);
750+ streams.subscribe(ITerminalsService.NAME, streamListener,
751+ new IStreams.DoneSubscribe() {
752+ public void doneSubscribe(IToken token,
753+ Exception error) {
754+ // TODO Auto-generated method stub
755+ System.out.println("Stream subscribed");
756+ if (error != null) {
757+ System.out.println("subscribe error");
758+ bSubscribed = false;
759+ error(error);
760+ }
761+ else
762+ done(this);
763+ }
764+
765+ });
766+ }}
767+ }.getIO();
768+
769+ }
770+ catch (Exception e) {
771+ e.printStackTrace();
772+ throw new RemoteFileException(
773+ "Error When Subscribe Terminal streams!", e); //$NON-NLS-1$
774+ }
775+
776+ }
777 }
778Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java
779===================================================================
780--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java (revision 0)
781+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.java (revision 0)
782@@ -0,0 +1,35 @@
783+/*******************************************************************************
784+ * Copyright (c) 2010 Intel Corporation. and others.
785+ * All rights reserved. This program and the accompanying materials
786+ * are made available under the terms of the Eclipse Public License v1.0
787+ * which accompanies this distribution, and is available at
788+ * http://www.eclipse.org/legal/epl-v10.html
789+ *
790+ * Contributors:
791+ * Intel Corporation - initial API and implementation
792+ ******************************************************************************/
793+package org.eclipse.tm.internal.tcf.rse.shells;
794+
795+import org.eclipse.osgi.util.NLS;
796+
797+public class TCFShellServiceResources extends NLS {
798+ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.shells.TCFShellServiceResources"; //$NON-NLS-1$
799+
800+ public static String TCFPlugin_Unexpected_Exception;
801+
802+ public static String TCFShellService_Description;
803+
804+ public static String TCFShellService_Name;
805+
806+ static {
807+ // initialize resource bundle
808+ NLS.initializeMessages(BUNDLE_NAME, TCFShellServiceResources.class);
809+ }
810+
811+ private TCFShellServiceResources(){
812+ }
813+
814+}
815+
816+
817+
818Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java
819===================================================================
820--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java (revision 0)
821+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalShell.java (revision 0)
822@@ -0,0 +1,444 @@
823+/*******************************************************************************
824+ * Copyright (c) 2010 Intel Corporation. and others.
825+ * All rights reserved. This program and the accompanying materials
826+ * are made available under the terms of the Eclipse Public License v1.0
827+ * which accompanies this distribution, and is available at
828+ * http://www.eclipse.org/legal/epl-v10.html
829+ *
830+ * Contributors:
831+ * Intel Corporation - initial API and implementation
832+ ******************************************************************************/
833+package org.eclipse.tm.internal.tcf.rse.shells;
834+
835+import java.io.BufferedWriter;
836+import java.io.IOException;
837+import java.io.InputStream;
838+import java.io.OutputStream;
839+import java.io.OutputStreamWriter;
840+import java.io.Writer;
841+import java.util.Map;
842+
843+import org.eclipse.core.runtime.IStatus;
844+import org.eclipse.rse.core.model.IPropertySet;
845+import org.eclipse.rse.services.clientserver.PathUtility;
846+import org.eclipse.rse.services.clientserver.messages.CommonMessages;
847+import org.eclipse.rse.services.clientserver.messages.ICommonMessageIds;
848+import org.eclipse.rse.services.clientserver.messages.SimpleSystemMessage;
849+import org.eclipse.rse.services.clientserver.messages.SystemMessage;
850+import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
851+import org.eclipse.rse.services.terminals.AbstractTerminalShell;
852+import org.eclipse.rse.services.terminals.ITerminalService;
853+import org.eclipse.rse.ui.SystemBasePlugin;
854+import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider;
855+import org.eclipse.tm.internal.tcf.rse.TCFConnectorService;
856+import org.eclipse.tm.internal.tcf.rse.TCFRSETask;
857+import org.eclipse.tm.internal.tcf.terminals.ITerminalsService;
858+import org.eclipse.tm.tcf.protocol.IChannel;
859+import org.eclipse.tm.tcf.protocol.IToken;
860+import org.eclipse.tm.tcf.services.IStreams;
861+
862+
863+public class TCFTerminalShell extends AbstractTerminalShell {
864+ private ITCFSessionProvider fSessionProvider;
865+ private IChannel fChannel;
866+ private String fPtyType;
867+ private ITerminalsService.TerminalContext terminalContext;
868+ private String fEncoding;
869+ private InputStream fInputStream;
870+ private OutputStream fOutputStream;
871+ private Writer fOutputStreamWriter;
872+ private int fWidth = 0;
873+ private int fHeight = 0;
874+ private String fContextID;
875+ private String in_id;
876+ private String out_id;
877+ private boolean connected = false;
878+ private ITerminalsService terminal;
879+ private int status;
880+
881+ private IPropertySet tcfPropertySet = null;
882+
883+ private static String defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding();
884+ private ITerminalsService.TerminalsListener listeners = new ITerminalsService.TerminalsListener(){
885+
886+ public void exited(String terminalId, int exitCode) {
887+ // TODO Auto-generated method stub
888+ System.out.printf("Console terminal shell %s exited, current shell ID %s\n", terminalId, terminalContext.getID());
889+ if(!terminalContext.getID().equals(terminalId))
890+ return;
891+ terminal.removeListener(listeners);
892+ TCFTerminalShell.this.connected = false;
893+ }
894+
895+
896+ public void winSizeChanged(String terminalId, int newWidth,
897+ int newHeight) {
898+ // TODO Auto-generated method stub
899+ System.out.printf("Console terminal shell %s new width %d, height %d\n", terminalId, newWidth, newHeight);
900+ }
901+ };
902+
903+ private class LoginThread extends Thread {
904+
905+ private String username;
906+ private String password;
907+ private int status = ITCFSessionProvider.SUCCESS_CODE;
908+ public LoginThread(String username, String password) {
909+ this.username = username;
910+ this.password = password;
911+ }
912+
913+ public void run() {
914+ tcfPropertySet = ((TCFConnectorService)fSessionProvider).getTCFPropertySet();
915+ String login_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_REQUIRED);
916+ String login_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_PROMPT);
917+ String password_prompt =tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PASSWORD_PROMPT);
918+ String command_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_COMMAND_PROMPT);
919+ String pwd_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PWD_REQUIRED);
920+
921+ if (Boolean.valueOf(login_required).booleanValue()) {
922+ status = ITCFSessionProvider.SUCCESS_CODE;
923+ if (login_prompt != null && login_prompt.length() > 0) {
924+ status = readUntil(login_prompt,fInputStream);
925+ write(username + "\n");
926+ }
927+ if (Boolean.valueOf(pwd_required).booleanValue()) {
928+ if (status == ITCFSessionProvider.SUCCESS_CODE && password_prompt != null && password_prompt.length() > 0) {
929+ status = readUntil(password_prompt,fInputStream);
930+ write(password + "\n");
931+ }
932+ }
933+ if (status == ITCFSessionProvider.SUCCESS_CODE && command_prompt != null && command_prompt.length() > 0) {
934+ status = readUntil(command_prompt,fInputStream);
935+ write("\n");
936+ }
937+ } else {
938+ if (command_prompt != null && command_prompt.length() > 0) {
939+ status = readUntil(command_prompt,fInputStream);
940+ write("\n");
941+ }
942+ }
943+ }
944+
945+ public int readUntil(String pattern,InputStream in) {
946+ try {
947+ char lastChar = pattern.charAt(pattern.length() - 1);
948+ StringBuffer sb = new StringBuffer();
949+ int ch = in.read();
950+ while (ch >= 0) {
951+ char tch = (char) ch;
952+ sb.append(tch);
953+ if (tch=='t' && sb.indexOf("incorrect") >= 0) { //$NON-NLS-1$
954+ return ITCFSessionProvider.ERROR_CODE;
955+ }
956+ if (tch=='d' && sb.indexOf("closed") >= 0) { //$NON-NLS-1$
957+ return ITCFSessionProvider.CONNECT_CLOSED;
958+ }
959+ if (tch == lastChar) {
960+ if (sb.toString().endsWith(pattern)) {
961+ return ITCFSessionProvider.SUCCESS_CODE;
962+ }
963+ }
964+ ch = in.read();
965+ }
966+ }
967+ catch (Exception e) {
968+ e.printStackTrace();
969+ SystemBasePlugin.logError(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), e);
970+ }
971+ return ITCFSessionProvider.CONNECT_CLOSED;
972+ }
973+
974+ public int getLoginStatus() {
975+ return this.status;
976+ }
977+
978+ }
979+
980+ public void write(String value) {
981+ try {
982+ int len = value.length() + 6;
983+ fOutputStream.write(value.getBytes());
984+ System.out.printf("value is %s\n", value);
985+ System.out.printf("write: ******************".substring(0, len <= 24 ? len : 24)); //$NON-NLS-1$
986+ } catch (Exception e) {
987+ e.printStackTrace();
988+ }
989+ }
990+
991+ private int login(String username, String password) throws InterruptedException
992+ {
993+ long millisToEnd = System.currentTimeMillis() + ITCFSessionProvider.TCP_CONNECT_TIMEOUT*1000;
994+ LoginThread checkLogin = new LoginThread(username, password);
995+ status = ITCFSessionProvider.ERROR_CODE;
996+ checkLogin.start();
997+ while (checkLogin.isAlive() && System.currentTimeMillis()<millisToEnd)
998+ checkLogin.join(500);
999+ status = checkLogin.getLoginStatus();
1000+ checkLogin.join();
1001+ return status;
1002+ }
1003+ /**
1004+ * Construct a new TCF connection.
1005+ *
1006+ * The TCF channel is immediately connected in the Constructor.
1007+ *
1008+ * @param sessionProvider TCF session provider
1009+ * @param ptyType Terminal type to set, or <code>null</code> if not
1010+ * relevant
1011+ * @param encoding The default encoding to use for initial command.
1012+ * @param environment Environment array to set, or <code>null</code> if
1013+ * not relevant.
1014+ * @param initialWorkingDirectory initial directory to open the Terminal in.
1015+ * Use <code>null</code> or empty String ("") to start in a
1016+ * default directory. Empty String will typically start in the
1017+ * home directory.
1018+ * @param commandToRun initial command to send.
1019+ * @throws SystemMessageException in case anything goes wrong. Channels and
1020+ * Streams are all cleaned up again in this case.
1021+ * @see ITerminalService
1022+ */
1023+ public TCFTerminalShell(final ITCFSessionProvider sessionProvider, final String ptyType,
1024+ final String encoding, final String[] environment,
1025+ String initialWorkingDirectory, String commandToRun)
1026+ throws SystemMessageException {
1027+ Map<String, Object> map_ids;
1028+ Exception nestedException = null;
1029+ try {
1030+ fSessionProvider = sessionProvider;
1031+ fEncoding = encoding;
1032+ fPtyType = ptyType;
1033+ fChannel = fSessionProvider.getChannel();
1034+
1035+ if (fChannel == null || fChannel.getState() != IChannel.STATE_OPEN)
1036+ throw new Exception("TCP channel is not connected!");
1037+ if (((TCFConnectorService)sessionProvider).isSubscribed() == false)
1038+ ((TCFConnectorService)sessionProvider).Subscribe();
1039+ assert (((TCFConnectorService)sessionProvider).isSubscribed());
1040+
1041+ new TCFRSETask<ITerminalsService.TerminalContext>() {
1042+ public void run() {
1043+ terminal = ((TCFConnectorService)sessionProvider).getService(ITerminalsService.class);
1044+ terminal.addListener(listeners);
1045+ terminal.launch(ptyType, encoding, environment, new ITerminalsService.DoneLaunch() {
1046+ public void doneLaunch(IToken token, Exception error,
1047+ ITerminalsService.TerminalContext terminal) {
1048+ // TODO Auto-generated method stub
1049+
1050+ terminalContext = terminal;
1051+ if (error != null)
1052+ error(error);
1053+ else done(terminal);
1054+ }
1055+ });
1056+ }
1057+
1058+ }.getS(null, TCFShellServiceResources.TCFShellService_Name); //$NON-NLS-1$
1059+
1060+ fPtyType = terminalContext.getPtyType();
1061+ fEncoding = terminalContext.getEncoding();
1062+ fContextID = terminalContext.getID();
1063+ fWidth = terminalContext.getWidth();
1064+ fHeight = terminalContext.getHeight();
1065+ map_ids = terminalContext.getProperties();
1066+ in_id = (String)map_ids.get(ITerminalsService.PROP_STDOUT_ID);
1067+ out_id = (String)map_ids.get(ITerminalsService.PROP_STDIN_ID);
1068+
1069+ String user = fSessionProvider.getSessionUserId();
1070+ String password = fSessionProvider.getSessionPassword(); //$NON-NLS-1$
1071+ status = ITCFSessionProvider.ERROR_CODE;
1072+
1073+ IStreams streams = ((TCFConnectorService)sessionProvider).getService(IStreams.class);
1074+ fOutputStream = new TCFTerminalOutputStream(streams, out_id);
1075+ fInputStream = new TCFTerminalInputStream(streams, in_id);
1076+ if (fEncoding != null) {
1077+ fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream, encoding));
1078+ } else {
1079+ // default encoding == System.getProperty("file.encoding")
1080+ // TODO should try to determine remote encoding if possible
1081+ fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream));
1082+ }
1083+
1084+ try {
1085+ status = login(user, password);
1086+ }
1087+ finally
1088+ {
1089+ if ((status == ITCFSessionProvider.CONNECT_CLOSED))
1090+ System.out.print("First time login fails, retry!");
1091+ }
1092+
1093+ //give another chance of retrying
1094+ if ((status == ITCFSessionProvider.CONNECT_CLOSED))
1095+ {
1096+ ((TCFConnectorService)sessionProvider).Unsubscribe();
1097+ ((TCFConnectorService)sessionProvider).Subscribe();
1098+ assert (((TCFConnectorService)sessionProvider).isSubscribed());
1099+ status = login(user, password);
1100+ }
1101+
1102+ connected = true;
1103+ if (initialWorkingDirectory!=null && initialWorkingDirectory.length()>0
1104+ && !initialWorkingDirectory.equals(".") //$NON-NLS-1$
1105+ && !initialWorkingDirectory.equals("Command Shell") //$NON-NLS-1$ //FIXME workaround for bug 153047
1106+ ) {
1107+ writeToShell("cd " + PathUtility.enQuoteUnix(initialWorkingDirectory)); //$NON-NLS-1$
1108+ }
1109+
1110+ if (commandToRun != null && commandToRun.length() > 0) {
1111+ writeToShell(commandToRun);
1112+ }
1113+
1114+ }
1115+ catch (Exception e)
1116+ {
1117+ e.printStackTrace();
1118+ nestedException = e;
1119+ }
1120+ finally {
1121+ if (status == ITCFSessionProvider.SUCCESS_CODE) {
1122+ System.out.println("TCF shell Service: Connected"); //$NON-NLS-1$
1123+ }
1124+ else {
1125+ System.out.println("TCF shell Service: Connect failed"); //$NON-NLS-1$
1126+ SystemMessage msg;
1127+
1128+ if (nestedException!=null) {
1129+ msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID,
1130+ ICommonMessageIds.MSG_EXCEPTION_OCCURRED,
1131+ IStatus.ERROR,
1132+ CommonMessages.MSG_EXCEPTION_OCCURRED, nestedException);
1133+ } else {
1134+ String strErr;
1135+ if (status == ITCFSessionProvider.CONNECT_CLOSED)
1136+ strErr = "Connection closed!";
1137+ else if (status == ITCFSessionProvider.ERROR_CODE)
1138+ strErr = "Login Incorrect or meet other unknown error!";
1139+ else
1140+ strErr = "Not identified Errors";
1141+
1142+ msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID,
1143+ ICommonMessageIds.MSG_COMM_AUTH_FAILED,
1144+ IStatus.ERROR,
1145+ strErr,
1146+ "Meet error when trying to login in!");
1147+ msg.makeSubstitution(((TCFConnectorService)fSessionProvider).getHost().getAliasName());
1148+ }
1149+ throw new SystemMessageException(msg);
1150+ }
1151+ }
1152+
1153+ }
1154+
1155+ public void writeToShell(String command) throws IOException {
1156+ if (isActive()) {
1157+ if ("#break".equals(command)) { //$NON-NLS-1$
1158+ command = "\u0003"; // Unicode 3 == Ctrl+C //$NON-NLS-1$
1159+ } else {
1160+ command += "\r\n"; //$NON-NLS-1$
1161+ }
1162+ fOutputStreamWriter.write(command);
1163+ }
1164+ }
1165+
1166+ public void exit() {
1167+
1168+ // TODO Auto-generated method stub
1169+ if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) {
1170+ System.out.println("This terminal shell exits already!");
1171+ return;
1172+ }
1173+ try {
1174+ getOutputStream().close();
1175+ getInputStream().close();
1176+
1177+ }
1178+ catch (IOException ioe) {
1179+ // TODO Auto-generated catch block
1180+ ioe.printStackTrace();
1181+ } //$NON-NLS-1$
1182+
1183+ try {
1184+ new TCFRSETask<Object>() {
1185+ public void run() {
1186+ terminalContext.exit(new ITerminalsService.DoneCommand(){
1187+ public void doneCommand(IToken token,
1188+ Exception error) {
1189+ // TODO Auto-generated method stub
1190+ if (error != null)
1191+ error(error);
1192+ else {
1193+ System.out.println("terminal exit command sent");
1194+ done(this);
1195+ }
1196+ }
1197+ });
1198+ }}.getS(null, TCFShellServiceResources.TCFShellService_Name); //seems no need block here. need further modification.
1199+ }
1200+ catch (SystemMessageException e) {
1201+ // TODO Auto-generated catch block
1202+ e.printStackTrace();
1203+ } //$NON-NLS-1$;
1204+ }
1205+
1206+ public InputStream getInputStream() {
1207+ // TODO Auto-generated method stub
1208+ return fInputStream;
1209+ }
1210+
1211+ public OutputStream getOutputStream() {
1212+ // TODO Auto-generated method stub
1213+ return fOutputStream;
1214+ }
1215+
1216+ public boolean isActive() {
1217+ // TODO Auto-generated method stub
1218+ if (fChannel != null && !(fChannel.getState() == IChannel.STATE_CLOSED) && connected) {
1219+ return true;
1220+ }
1221+ exit();
1222+ // shell is not active: check for session lost
1223+ return false;
1224+ }
1225+
1226+ public String getPtyType() {
1227+ return fPtyType;
1228+ }
1229+
1230+ public void setTerminalSize(int newWidth, int newHeight) {
1231+ // do nothing
1232+ if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) {
1233+ System.out.println("This terminal shell exits already, can't set size!");
1234+ return;
1235+ }
1236+
1237+ try {
1238+ new TCFRSETask<Object>() {
1239+ public void run() {
1240+ if (fChannel != null && connected) {
1241+ terminal.setWinSize(fContextID, fWidth, fHeight, new ITerminalsService.DoneCommand(){
1242+
1243+ public void doneCommand(IToken token, Exception error) {
1244+ // TODO Auto-generated method stub
1245+ if (error != null)
1246+ error(error);
1247+ else
1248+ done(this);
1249+
1250+ }});
1251+
1252+ }
1253+ }}.getS(null, TCFShellServiceResources.TCFShellService_Name);
1254+ }
1255+ catch (SystemMessageException e) {
1256+ // TODO Auto-generated catch block
1257+ e.printStackTrace();
1258+ } //$NON-NLS-1$;
1259+ }
1260+
1261+ public String getDefaultEncoding() {
1262+ if (fEncoding != null) return fEncoding;
1263+ return defaultEncoding;
1264+ }
1265+
1266+}
1267Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java
1268===================================================================
1269--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java (revision 0)
1270+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFLoginProperties.java (revision 0)
1271@@ -0,0 +1,33 @@
1272+/*******************************************************************************
1273+ * Copyright (c) 2010 Intel Corporation. and others.
1274+ * All rights reserved. This program and the accompanying materials
1275+ * are made available under the terms of the Eclipse Public License v1.0
1276+ * which accompanies this distribution, and is available at
1277+ * http://www.eclipse.org/legal/epl-v10.html
1278+ *
1279+ * Contributors:
1280+ * Intel Corporation - initial API and implementation
1281+ ******************************************************************************/
1282+package org.eclipse.tm.internal.tcf.rse.shells;
1283+
1284+import org.eclipse.osgi.util.NLS;
1285+
1286+
1287+public class TCFLoginProperties extends NLS {
1288+ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.shells.TCFLoginProperties"; //$NON-NLS-1$
1289+ public static final String PropertySet_Description = "TCF Shell login word settings";
1290+ public static String TCFLOGIN_REQUIRED;
1291+ public static String TCFPWD_REQUIRED;
1292+ public static String TCFLOGIN_PROMPT;
1293+ public static String TCFPASSWORD_PROMPT;
1294+ public static String TCFCOMMAND_PROMPT;
1295+
1296+ static {
1297+ NLS.initializeMessages(BUNDLE_NAME, TCFLoginProperties.class);
1298+ }
1299+
1300+ private TCFLoginProperties() {
1301+ }
1302+
1303+
1304+}
1305Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java
1306===================================================================
1307--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java (revision 0)
1308+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFServiceCommandShell.java (revision 0)
1309@@ -0,0 +1,198 @@
1310+/*******************************************************************************
1311+ * Copyright (c) 2010 Intel Corporation. and others.
1312+ * All rights reserved. This program and the accompanying materials
1313+ * are made available under the terms of the Eclipse Public License v1.0
1314+ * which accompanies this distribution, and is available at
1315+ * http://www.eclipse.org/legal/epl-v10.html
1316+ *
1317+ * Contributors:
1318+ * Intel Corporation - initial API and implementation
1319+ ******************************************************************************/
1320+package org.eclipse.tm.internal.tcf.rse.shells;
1321+import java.util.ArrayList;
1322+import java.util.StringTokenizer;
1323+
1324+import org.eclipse.core.runtime.IPath;
1325+import org.eclipse.core.runtime.NullProgressMonitor;
1326+import org.eclipse.core.runtime.Path;
1327+import org.eclipse.rse.core.subsystems.ISubSystem;
1328+import org.eclipse.rse.internal.services.shells.TerminalServiceHostShell;
1329+import org.eclipse.rse.services.shells.IHostOutput;
1330+import org.eclipse.rse.services.shells.IHostShell;
1331+import org.eclipse.rse.services.shells.IHostShellChangeEvent;
1332+import org.eclipse.rse.services.shells.ParsedOutput;
1333+import org.eclipse.rse.services.shells.Patterns;
1334+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem;
1335+import org.eclipse.rse.subsystems.shells.core.model.ISystemOutputRemoteTypes;
1336+import org.eclipse.rse.subsystems.shells.core.model.RemoteError;
1337+import org.eclipse.rse.subsystems.shells.core.model.RemoteOutput;
1338+import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem;
1339+import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteOutput;
1340+import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ServiceCommandShell;
1341+
1342+@SuppressWarnings("restriction")
1343+public class TCFServiceCommandShell extends ServiceCommandShell {
1344+ private Patterns _patterns;
1345+ private String _workingDir;
1346+ private String _curCommand;
1347+ private IRemoteFileSubSystem _fs;
1348+
1349+ public TCFServiceCommandShell(IRemoteCmdSubSystem cmdSS,
1350+ IHostShell hostShell) {
1351+ super(cmdSS, hostShell);
1352+ // TODO Auto-generated constructor stub
1353+ _patterns = new Patterns();
1354+ _patterns.update("cmd"); //$NON-NLS-1$
1355+ ISubSystem[] sses = cmdSS.getHost().getSubSystems();
1356+ for (int i = 0; i < sses.length; i++)
1357+ {
1358+ if (sses[i] instanceof IRemoteFileSubSystem)
1359+ {
1360+ _fs = (IRemoteFileSubSystem)sses[i];
1361+ break;
1362+ }
1363+ }
1364+ }
1365+
1366+ public Object getContext()
1367+ {
1368+ String workingDir = _workingDir;
1369+ if (workingDir != null && workingDir.length() > 0)
1370+ {
1371+ try {
1372+ return _fs.getRemoteFileObject(workingDir, new NullProgressMonitor());
1373+ }
1374+ catch (Exception e)
1375+ {
1376+ e.printStackTrace();
1377+ }
1378+ }
1379+ return null;
1380+
1381+ }
1382+
1383+ public String getContextString()
1384+ {
1385+ return _workingDir;
1386+ }
1387+
1388+ public void shellOutputChanged(IHostShellChangeEvent event)
1389+ {
1390+ IHostOutput[] lines = event.getLines();
1391+ boolean gotCommand = false;
1392+ ArrayList<RemoteOutput> outputs = new ArrayList<RemoteOutput>(lines.length);
1393+ for (int i = 0; i < lines.length; i++)
1394+ {
1395+ String line = lines[i].getString();
1396+ System.out.println("shellOutput:"+line);
1397+ System.out.printf("cur command %s\n", _curCommand);
1398+ if (line.endsWith(getPromptCommand())) {
1399+ continue; //ignore our synthetic prompt command
1400+ }
1401+ ParsedOutput parsedMsg = null;
1402+ if (!gotCommand && line.equals(_curCommand)) {
1403+ gotCommand = true;
1404+ continue; //ignore remote command echo
1405+ } else
1406+ {
1407+ try
1408+ {
1409+ // Bug 160202: Remote shell dies.
1410+ if ((_curCommand == null) || (!_curCommand.trim().equals("ls"))) { //$NON-NLS-1$
1411+ parsedMsg = _patterns.matchLine(line);
1412+
1413+ // Bug 160202: Remote shell dies.
1414+ if (_curCommand != null) {
1415+ String temp = _curCommand.trim();
1416+ StringTokenizer tokenizer = new StringTokenizer(temp);
1417+
1418+ if (tokenizer.countTokens() == 2) {
1419+ String token1 = tokenizer.nextToken();
1420+ String token2 = tokenizer.nextToken();
1421+
1422+ if ((token1.equals("ls")) && (token2.indexOf('-') == 0) && (token2.indexOf('l') > 0)) { //$NON-NLS-1$
1423+ if (line.startsWith("total")) { //$NON-NLS-1$
1424+ parsedMsg = null;
1425+ }
1426+ }
1427+ }
1428+ }
1429+ }
1430+ }
1431+ catch (Throwable e) {
1432+ e.printStackTrace();
1433+ }
1434+ }
1435+
1436+ RemoteOutput output = null;
1437+
1438+ String type = "stdout"; //$NON-NLS-1$
1439+
1440+ if (parsedMsg != null) {
1441+ type = parsedMsg.type;
1442+ }
1443+
1444+ if (event.isError()) {
1445+ output = new RemoteError(this, type);
1446+ }
1447+ else {
1448+ output = new RemoteOutput(this, type);
1449+ }
1450+
1451+ output.setText(line);
1452+ if (parsedMsg != null)
1453+ {
1454+ String file = parsedMsg.file;
1455+ if (type.equals(ISystemOutputRemoteTypes.TYPE_PROMPT))
1456+ {
1457+ _workingDir = file;
1458+ output.setAbsolutePath(_workingDir);
1459+ }
1460+ else if(_workingDir!=null)
1461+ {
1462+ IPath p = new Path(_workingDir).append(file);
1463+ output.setAbsolutePath(p.toString());
1464+ }
1465+ else
1466+ {
1467+ output.setAbsolutePath(file);
1468+ }
1469+ if (parsedMsg.line > 0){
1470+ output.setLine(parsedMsg.line);
1471+ }
1472+ }
1473+
1474+ addOutput(output);
1475+ outputs.add(output);
1476+ }
1477+
1478+ IRemoteOutput[] remoteOutputs = outputs.toArray(new IRemoteOutput[outputs.size()]);
1479+ notifyOutputChanged(remoteOutputs, false);
1480+ }
1481+
1482+ /**
1483+ * Return the prompt command, such that lines ending with the
1484+ * prompt command can be removed from output.
1485+ * Should be overridden in case the IHostShell used for this
1486+ * service is not an SshHostShell.
1487+ * @return String promptCommand
1488+ */
1489+ protected String getPromptCommand() {
1490+ IHostShell shell = getHostShell();
1491+ if (shell instanceof TerminalServiceHostShell) {
1492+ return ((TerminalServiceHostShell)shell).getPromptCommand();
1493+ }
1494+ //return something impossible such that nothing is ever matched
1495+ return "\uffff"; //$NON-NLS-1$
1496+ }
1497+
1498+ public void writeToShell(String cmd)
1499+ {
1500+ _curCommand = cmd;
1501+ _patterns.update(cmd);
1502+ System.out.println("execute: cmd " + cmd);
1503+ super.writeToShell(cmd);
1504+
1505+ }
1506+
1507+}
1508Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java
1509===================================================================
1510--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java (revision 0)
1511+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalInputStream.java (revision 0)
1512@@ -0,0 +1,148 @@
1513+/*******************************************************************************
1514+ * Copyright (c) 2010 Intel Corporation. and others.
1515+ * All rights reserved. This program and the accompanying materials
1516+ * are made available under the terms of the Eclipse Public License v1.0
1517+ * which accompanies this distribution, and is available at
1518+ * http://www.eclipse.org/legal/epl-v10.html
1519+ *
1520+ * Contributors:
1521+ * Intel Corporation - initial API and implementation
1522+ ******************************************************************************/
1523+package org.eclipse.tm.internal.tcf.rse.shells;
1524+
1525+import java.io.IOException;
1526+import java.io.InputStream;
1527+
1528+import org.eclipse.tm.tcf.protocol.IToken;
1529+import org.eclipse.tm.tcf.services.IStreams;
1530+import org.eclipse.tm.tcf.util.TCFTask;
1531+
1532+public class TCFTerminalInputStream extends InputStream {
1533+ private IStreams streams;
1534+ private boolean connected = true;;/* The stream is connected or not */
1535+ String is_id;
1536+ private int value;
1537+ private boolean bEof = false;;
1538+
1539+ public TCFTerminalInputStream(final IStreams streams, final String is_id) throws IOException{
1540+ if (streams == null)
1541+ throw new IOException("TCP streams is null");
1542+ this.streams = streams;
1543+ this.is_id = is_id;
1544+ }
1545+
1546+ /* read must be synchronized */
1547+ @Override
1548+ public synchronized int read() throws IOException {
1549+ // TODO Auto-generated method stub
1550+ if (!connected)
1551+ throw new IOException("istream is not connected");
1552+ if (bEof)
1553+ return -1;
1554+ try {
1555+ new TCFTask<Object>() {
1556+ public void run() {
1557+ streams.read(is_id, 1, new IStreams.DoneRead() {
1558+ public void doneRead(IToken token, Exception error, int lostSize,
1559+ byte[] data, boolean eos) {
1560+ // TODO Auto-generated method stub
1561+ if (error != null) {
1562+ error(error);
1563+ return;
1564+ }
1565+ bEof = eos;
1566+ if (data != null) {
1567+ value = (int)data[0];
1568+ if (data.length != 1) {
1569+ System.out.println("TCF inputstream read one byte, yet return more than one byte!");
1570+ }
1571+ }
1572+ else
1573+ value = -1;
1574+ done(this);
1575+ }
1576+ });
1577+ }
1578+ }.getIO();
1579+ }
1580+ catch (Exception e) {
1581+ e.printStackTrace();
1582+ throw new IOException(e);
1583+ }
1584+ return value;
1585+ }
1586+
1587+ private static class Buffer {
1588+ byte[] buf;
1589+ Buffer() {
1590+ }
1591+ }
1592+ private Buffer buffer;
1593+
1594+ public synchronized int read(byte b[], final int off, final int len) throws IOException {
1595+
1596+
1597+ if (!connected)
1598+ throw new IOException("istream is not connected");
1599+ if (bEof) return -1;
1600+ if (b == null) {
1601+ throw new NullPointerException();
1602+ } else if (off < 0 || len < 0 || len > b.length - off) {
1603+ throw new IndexOutOfBoundsException();
1604+ } else if (len == 0) {
1605+ return 0;
1606+ }
1607+ try {
1608+ new TCFTask<Buffer>() {
1609+ public void run() {
1610+ streams.read(is_id, len, new IStreams.DoneRead() {
1611+ public void doneRead(IToken token, Exception error, int lostSize,
1612+ byte[] data, boolean eos) {
1613+ // TODO Auto-generated method stub
1614+ if (error != null) {
1615+ error(error);
1616+ return;
1617+ }
1618+ bEof = eos;
1619+ if (data != null) {
1620+ buffer = new Buffer();
1621+ buffer.buf = data;
1622+
1623+ }
1624+ done(buffer);
1625+ }
1626+ });
1627+ }
1628+ }.getIO();
1629+
1630+ if (buffer.buf != null) {
1631+ int length = buffer.buf.length;
1632+ System.arraycopy(buffer.buf, 0, b, off, length);
1633+ System.out.println("read a line:"+ new String(b, off,length));
1634+ return length;
1635+ }
1636+ else if (bEof)
1637+ return -1;
1638+ else return 0;
1639+ } catch (Exception ee) {
1640+ ee.printStackTrace();
1641+ throw new IOException(ee);
1642+ }
1643+ }
1644+
1645+ public void close() throws IOException {
1646+ if (!connected) return;
1647+ new TCFTask<Object>() {
1648+ public void run() {
1649+ streams.disconnect(is_id, new IStreams.DoneDisconnect() {
1650+ public void doneDisconnect(IToken token, Exception error) {
1651+ connected = false;
1652+ done(this);
1653+ }
1654+ });
1655+ }
1656+ }.getIO();
1657+ connected = false;
1658+ }
1659+
1660+}
1661Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java
1662===================================================================
1663--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java (revision 0)
1664+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFTerminalOutputStream.java (revision 0)
1665@@ -0,0 +1,110 @@
1666+/*******************************************************************************
1667+ * Copyright (c) 2010 Intel Corporation. and others.
1668+ * All rights reserved. This program and the accompanying materials
1669+ * are made available under the terms of the Eclipse Public License v1.0
1670+ * which accompanies this distribution, and is available at
1671+ * http://www.eclipse.org/legal/epl-v10.html
1672+ *
1673+ * Contributors:
1674+ * Intel Corporation - initial API and implementation
1675+ ******************************************************************************/
1676+package org.eclipse.tm.internal.tcf.rse.shells;
1677+
1678+import java.io.IOException;
1679+
1680+import java.io.OutputStream;
1681+
1682+import org.eclipse.tm.tcf.protocol.IToken;
1683+import org.eclipse.tm.tcf.services.IStreams;
1684+import org.eclipse.tm.tcf.util.TCFTask;
1685+
1686+public class TCFTerminalOutputStream extends OutputStream {
1687+
1688+ private final IStreams streams;
1689+ private boolean connected = true;
1690+ private boolean write_eof;
1691+ String os_id;
1692+
1693+ public TCFTerminalOutputStream(final IStreams streams, final String os_id) throws IOException{
1694+ if (streams == null) throw new IOException("istream is null");
1695+ this.streams = streams;
1696+ this.os_id = os_id;
1697+ write_eof = false;
1698+ }
1699+
1700+ @Override
1701+ public synchronized void write(final byte b[], final int off, final int len) throws IOException {
1702+ /* If eof is written, we can't write anything into the stream */
1703+ if (!connected || write_eof)
1704+ throw new IOException("stream is not connected or write_eof already!");
1705+ System.out.println("write line: " + new String(b, off, len) );
1706+ try {
1707+ new TCFTask<Object>() {
1708+ public void run() {
1709+ streams.write(os_id, b, off, len, new IStreams.DoneWrite() {
1710+ public void doneWrite(IToken token, Exception error) {
1711+ // TODO: stream write error handling
1712+ if (error != null) error(error);
1713+ done(this);
1714+ }
1715+ });
1716+
1717+ }
1718+ }.getIO();
1719+ }
1720+ catch (Exception e)
1721+ {
1722+ throw new IOException(e);
1723+ }
1724+ }
1725+
1726+ @Override
1727+ public synchronized void write(int b) throws IOException {
1728+
1729+ // TODO Auto-generated method stub
1730+ try {
1731+ final byte[] buf = new byte[1];
1732+ buf[0] = (byte)b;
1733+ this.write(buf, 0, 1);
1734+ }
1735+ catch(IOException ioe) {
1736+ ioe.printStackTrace();
1737+ throw new IOException(ioe);
1738+ }
1739+
1740+ }
1741+
1742+ /* close must be called --Need to reconsider it in the future*/
1743+ public void close() throws IOException {
1744+ if (!connected)
1745+ return;
1746+ try {
1747+ new TCFTask<Object>() {
1748+ public void run() {
1749+ streams.eos(os_id, new IStreams.DoneEOS() {
1750+ public void doneEOS(IToken token, Exception error) {
1751+ // TODO Auto-generated method stub
1752+ write_eof = true;
1753+ done(this);
1754+ }
1755+ });
1756+ }
1757+ }.getIO();
1758+ new TCFTask<Object>() {
1759+ public void run() {
1760+ streams.disconnect(os_id, new IStreams.DoneDisconnect() {
1761+ public void doneDisconnect(IToken token, Exception error) {
1762+ connected = false;
1763+ done(this);
1764+ }
1765+ });
1766+
1767+ }
1768+ }.getIO();
1769+ }
1770+ catch(Exception e) {
1771+ throw new IOException(e);
1772+ }
1773+ }
1774+
1775+}
1776Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties
1777===================================================================
1778--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties (revision 0)
1779+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellServiceResources.properties (revision 0)
1780@@ -0,0 +1,3 @@
1781+TCFPlugin_Unexpected_Exception=Unexpected {0}: {1}
1782+TCFShellService_Name=TCF Shell Service
1783+TCFShellService_Description=TCF Shell Service Description
1784Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java
1785===================================================================
1786--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java (revision 0)
1787+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/shells/TCFShellSubSystemConfiguration.java (revision 0)
1788@@ -0,0 +1,70 @@
1789+/*******************************************************************************
1790+ * Copyright (c) 2010 Intel Corporation. and others.
1791+ * All rights reserved. This program and the accompanying materials
1792+ * are made available under the terms of the Eclipse Public License v1.0
1793+ * which accompanies this distribution, and is available at
1794+ * http://www.eclipse.org/legal/epl-v10.html
1795+ *
1796+ * Contributors:
1797+ * Intel Corporation - initial API and implementation
1798+ ******************************************************************************/
1799+package org.eclipse.tm.internal.tcf.rse.shells;
1800+
1801+import org.eclipse.rse.core.model.IHost;
1802+import org.eclipse.rse.core.subsystems.IConnectorService;
1803+import org.eclipse.rse.core.subsystems.ISubSystem;
1804+import org.eclipse.rse.services.shells.IHostShell;
1805+import org.eclipse.rse.services.shells.IShellService;
1806+import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem;
1807+import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.IServiceCommandShell;
1808+import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystem;
1809+import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystemConfiguration;
1810+import org.eclipse.tm.internal.tcf.rse.*;
1811+import org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalService;
1812+
1813+
1814+public class TCFShellSubSystemConfiguration extends
1815+ ShellServiceSubSystemConfiguration {
1816+
1817+ public TCFShellSubSystemConfiguration() {
1818+ super();
1819+ }
1820+
1821+ /**
1822+ * Instantiate and return an instance of OUR subsystem.
1823+ * Do not populate it yet though!
1824+ * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost)
1825+ */
1826+ public ISubSystem createSubSystemInternal(IHost host)
1827+ {
1828+ TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host);
1829+ ISubSystem subsys = new ShellServiceSubSystem(host, connectorService, createShellService(host));
1830+ return subsys;
1831+ }
1832+
1833+ public IConnectorService getConnectorService(IHost host) {
1834+ return TCFConnectorServiceManager.getInstance().getConnectorService(host, getServiceImplType());
1835+}
1836+
1837+ public void setConnectorService(IHost host,
1838+ IConnectorService connectorService) {
1839+ TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService);
1840+ }
1841+
1842+ public Class<ITCFSubSystem> getServiceImplType()
1843+ {
1844+ return ITCFSubSystem.class;
1845+ }
1846+
1847+ public IServiceCommandShell createRemoteCommandShell(IRemoteCmdSubSystem cmdSS, IHostShell hostShell) {
1848+ return new TCFServiceCommandShell(cmdSS, hostShell);
1849+ }
1850+
1851+ public IShellService createShellService(IHost host) {
1852+ TCFConnectorService cserv = (TCFConnectorService)getConnectorService(host);
1853+
1854+ return (IShellService) (new TCFTerminalService(cserv)).getAdapter(IShellService.class);
1855+ }
1856+
1857+
1858+}
1859Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties
1860===================================================================
1861--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties (revision 0)
1862+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/TCFConnectorResources.properties (revision 0)
1863@@ -0,0 +1,3 @@
1864+TCFConnectorService_Name=TCF Connector Service
1865+TCFConnectorService_Description=Target Communication Framework
1866+PropertySet_Description=TCF login properties. Set these according to your remote system's login prompts.
1867\ No newline at end of file
1868Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties
1869===================================================================
1870--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties (revision 0)
1871+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.properties (revision 0)
1872@@ -0,0 +1,3 @@
1873+TCFPlugin_Unexpected_Exception=Unexpected {0}: {1}
1874+TCFTerminalService_Name=TCF Terminal Service
1875+TCFTerminalService_Description=TCF Terminal Service Description
1876Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java
1877===================================================================
1878--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java (revision 0)
1879+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java (revision 0)
1880@@ -0,0 +1,64 @@
1881+/*******************************************************************************
1882+ * Copyright (c) 2010 Intel Corporation. and others.
1883+ * All rights reserved. This program and the accompanying materials
1884+ * are made available under the terms of the Eclipse Public License v1.0
1885+ * which accompanies this distribution, and is available at
1886+ * http://www.eclipse.org/legal/epl-v10.html
1887+ *
1888+ * Contributors:
1889+ * Intel Corporation - initial API and implementation
1890+ ******************************************************************************/
1891+package org.eclipse.tm.internal.tcf.rse.terminals;
1892+
1893+import org.eclipse.rse.core.model.IHost;
1894+import org.eclipse.rse.core.subsystems.IConnectorService;
1895+import org.eclipse.rse.core.subsystems.ISubSystem;
1896+import org.eclipse.rse.services.terminals.ITerminalService;
1897+import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystem;
1898+import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystemConfiguration;
1899+import org.eclipse.tm.internal.tcf.rse.ITCFSubSystem;
1900+import org.eclipse.tm.internal.tcf.rse.TCFConnectorService;
1901+import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager;
1902+
1903+public class TCFTerminalServiceSubSystemConfiguration extends
1904+ TerminalServiceSubSystemConfiguration {
1905+
1906+
1907+ /**
1908+ * Instantiate and return an instance of OUR subsystem. Do not populate it
1909+ * yet though!
1910+ *
1911+ * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost)
1912+ */
1913+ public ISubSystem createSubSystemInternal(IHost host) {
1914+ TCFConnectorService connectorService = (TCFConnectorService) getConnectorService(host);
1915+ ISubSystem subsys = new TerminalServiceSubSystem(host,
1916+ connectorService, createTerminalService(host));
1917+ return subsys;
1918+ }
1919+
1920+ /**
1921+ * @inheritDoc
1922+ * @since 1.0
1923+ */
1924+ public ITerminalService createTerminalService(IHost host) {
1925+ TCFConnectorService cserv = (TCFConnectorService) getConnectorService(host);
1926+ return new TCFTerminalService(cserv);
1927+ }
1928+
1929+ public IConnectorService getConnectorService(IHost host) {
1930+ return TCFConnectorServiceManager.getInstance().getConnectorService(
1931+ host, getServiceImplType());
1932+ }
1933+
1934+ public void setConnectorService(IHost host,
1935+ IConnectorService connectorService) {
1936+ TCFConnectorServiceManager.getInstance().setConnectorService(host,
1937+ getServiceImplType(), connectorService);
1938+ }
1939+
1940+ public Class<ITCFSubSystem> getServiceImplType() {
1941+ return ITCFSubSystem.class;
1942+ }
1943+
1944+}
1945Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java
1946===================================================================
1947--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java (revision 0)
1948+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalServiceResources.java (revision 0)
1949@@ -0,0 +1,36 @@
1950+/*******************************************************************************
1951+ * Copyright (c) 2010 Intel Corporation. and others.
1952+ * All rights reserved. This program and the accompanying materials
1953+ * are made available under the terms of the Eclipse Public License v1.0
1954+ * which accompanies this distribution, and is available at
1955+ * http://www.eclipse.org/legal/epl-v10.html
1956+ *
1957+ * Contributors:
1958+ * Intel Corporation - initial API and implementation
1959+ ******************************************************************************/
1960+package org.eclipse.tm.internal.tcf.rse.terminals;
1961+
1962+import org.eclipse.osgi.util.NLS;
1963+
1964+public class TCFTerminalServiceResources extends NLS {
1965+ private static final String BUNDLE_NAME = "org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalServiceResources"; //$NON-NLS-1$
1966+
1967+ public static String TCFPlugin_Unexpected_Exception;
1968+
1969+ public static String TCFTerminalService_Description;
1970+
1971+ public static String TCFTerminalService_Name;
1972+
1973+ static {
1974+ // initialize resource bundle
1975+ NLS.initializeMessages(BUNDLE_NAME, TCFTerminalServiceResources.class);
1976+ }
1977+
1978+ private TCFTerminalServiceResources(){
1979+
1980+ }
1981+
1982+}
1983+
1984+
1985+
1986Index: plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java
1987===================================================================
1988--- plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java (revision 0)
1989+++ plugins/org.eclipse.tm.tcf.rse/src/org/eclipse/tm/internal/tcf/rse/terminals/TCFTerminalService.java (revision 0)
1990@@ -0,0 +1,57 @@
1991+/*******************************************************************************
1992+ * Copyright (c) 2010 Intel Corporation. and others.
1993+ * All rights reserved. This program and the accompanying materials
1994+ * are made available under the terms of the Eclipse Public License v1.0
1995+ * which accompanies this distribution, and is available at
1996+ * http://www.eclipse.org/legal/epl-v10.html
1997+ *
1998+ * Contributors:
1999+ * Intel Corporation - initial API and implementation
2000+ ******************************************************************************/
2001+package org.eclipse.tm.internal.tcf.rse.terminals;
2002+
2003+import org.eclipse.core.runtime.IProgressMonitor;
2004+
2005+import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
2006+import org.eclipse.rse.services.terminals.AbstractTerminalService;
2007+import org.eclipse.rse.services.terminals.ITerminalShell;
2008+import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider;
2009+import org.eclipse.tm.internal.tcf.rse.shells.TCFTerminalShell;
2010+
2011+public class TCFTerminalService extends AbstractTerminalService{
2012+ private final ITCFSessionProvider fSessionProvider;
2013+
2014+ /**
2015+ * Return the TCF property set, and fill it with default values if it has
2016+ * not been created yet. Extender may override in order to set different
2017+ * default values.
2018+ *
2019+ * @return a property set holding properties understood by the TCF
2020+ * connector service.
2021+ */
2022+ public ITerminalShell launchTerminal(String ptyType, String encoding,
2023+ String[] environment, String initialWorkingDirectory,
2024+ String commandToRun, IProgressMonitor monitor)
2025+ throws SystemMessageException {
2026+ // TODO Auto-generated method stub
2027+ TCFTerminalShell hostShell = new TCFTerminalShell(fSessionProvider, ptyType, encoding, environment, initialWorkingDirectory, commandToRun);
2028+ return hostShell;
2029+ }
2030+
2031+
2032+ public TCFTerminalService(ITCFSessionProvider sessionProvider) {
2033+ fSessionProvider = sessionProvider;
2034+ }
2035+
2036+ public ITCFSessionProvider getSessionProvider() {
2037+ return fSessionProvider;
2038+ }
2039+ @Override
2040+ public String getName() {
2041+ return TCFTerminalServiceResources.TCFTerminalService_Name;
2042+ }
2043+ @Override
2044+ public String getDescription() {
2045+ return TCFTerminalServiceResources.TCFTerminalService_Description;
2046+ }
2047+}
2048Index: plugins/org.eclipse.tm.tcf.rse/plugin.xml
2049===================================================================
2050--- plugins/org.eclipse.tm.tcf.rse/plugin.xml (revision 1190)
2051+++ plugins/org.eclipse.tm.tcf.rse/plugin.xml (working copy)
2052@@ -37,6 +37,22 @@
2053 vendor="Wind River">
2054 </configuration>
2055 </extension>
2056+ <extension
2057+ point="org.eclipse.rse.core.subsystemConfigurations">
2058+ <configuration
2059+ category="shells"
2060+ class="org.eclipse.tm.internal.tcf.rse.shells.TCFShellSubSystemConfiguration"
2061+ description="Shells"
2062+ icon="icons/system-processes.gif"
2063+ iconlive="icons/system-processes-live.gif"
2064+ id="org.eclipse.tm.tcf.rse.Shells"
2065+ name="Shells"
2066+ priority="200"
2067+ serviceType="_ssh._tcp;_sftp-ssh._tcp"
2068+ systemTypeIds="org.eclipse.tm.tcf.rse.systemType"
2069+ vendor="Intel">
2070+ </configuration>
2071+ </extension>
2072 <extension
2073 point="org.eclipse.rse.core.subsystemConfigurations">
2074 <configuration
2075@@ -52,6 +68,22 @@
2076 vendor="Wind River">
2077 </configuration>
2078 </extension>
2079+ <extension
2080+ point="org.eclipse.rse.core.subsystemConfigurations">
2081+ <configuration
2082+ category="terminals"
2083+ class="org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalServiceSubSystemConfiguration"
2084+ description="TCF Terminal Service Description"
2085+ icon="icons/system-processes.gif"
2086+ iconlive="icons/system-processes-live.gif"
2087+ id="org.eclipse.tm.tcf.rse.Terminals"
2088+ name="Terminals"
2089+ priority="200"
2090+ serviceType="_ssh._tcp;_sftp-ssh._tcp"
2091+ systemTypeIds="org.eclipse.tm.tcf.rse.systemType"
2092+ vendor="Intel">
2093+ </configuration>
2094+ </extension>
2095 <extension point="org.eclipse.core.runtime.adapters">
2096 <factory
2097 class="org.eclipse.tm.internal.tcf.rse.processes.TCFSystemViewProcessAdapterFactory"
diff --git a/tcf/readme b/tcf/readme
new file mode 100644
index 0000000..95529a1
--- /dev/null
+++ b/tcf/readme
@@ -0,0 +1,175 @@
1The current implmentaion is based on TCF contribution 0.3.0(SVN revision 998).
2(svn://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/tags/0.3.0)
3
4I. Build
5================================
61. Check out the TCF contribution code version 0.3.0 from TCF SVN
7repository.
8
9svn co svn://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/tags/0.3.0 tcf_local/
10
11To use SVN inside Intel firewall, please use tsocks.
12(http://opensource.intel.com/linux-wiki/LinuxDesktop?highlight=%28tsocks%29#head-7dfffbdc3bda005c74d26ed2af467643dc89844b)
13
142. Apply the patches.
15
16cd tcf_local
17patch -p0 < ../terminals_agent.patch
18patch -p0 < ../terminals_plugin.patch
19patch -p0 < ../lke_rse_tcf.patch
20
21After the successful patch, only the following components are useful
22for CDT remote debug. Other plugins are not required.
23
24plugins/org.eclipse.tm.tcf/
25 TCF plugin for Eclipse integration.
26
27plugins/org.eclipse.tm.tcf.core/
28 TCF Java framework and intefaces for standard services.
29
30plugins/org.eclipse.tm.tcf.rse/
31 RSE plugin using TCF.
32
33plugins/org.eclipse.tm.tcf.terminals/
34 TCF Java interfaces & eclipse integration for terminal service.
35
36agent/
37 TCF reference agent for standard services.
38
39org.eclipse.tm.tcf.terminals.agent/
40 TCF reference agent with addtional terminal service.
41
423. Build the agent on remote target side.
43(This step can be skipped if the agent is already included in
44the poky generated image)
45
46 1) copy the directories "agent/" or "org.eclipse.tm.tcf.terminals.agent/"
47 to the remote target machine.
48 2) cd "org.eclipse.tm.tcf.terminals.agent/"
49 3) make
50
514. Import the eclipse plugins on host side.
52 1) In eclipse, choose from menu
53 File->Import->General->"Existing projects into workspace",
54 browse to the "tcf_local/plugins" direcotry, and click "OK".
55 2) Check the following plugins:
56 org.eclipse.tm.tcf
57 org.eclipse.tm.tcf.core
58 org.eclipse.tm.tcf.rse
59 org.eclipse.tm.tcf.terminals
60 3) Click "Finish" to import the eclipse plugins.
61 4) Select Project->"Build All" to build the plugins. If the
62 build process complains about missing dependent plugin,
63 please see Note 2 below.
64
65
66II. Usage
67================================
68On remote target side
691. Build & run tcf agent on target.
70(This step can be skipped if the agent is already included in
71the poky generated iamge)
72
73 - cd to direcotry "org.eclipse.tm.tcf.terminals.agent".
74 - type "make" to build the tcf agent.
75 - run the tcf agent with root privilege on target.
76 e.g. sudo obj/GNU/Linux/x86_64/Debug/agent -Llog.txt
77
78On Host side
792. Launch the RSE plugin for TCF(org.eclipse.tm.tcf.rse).
80Make sure the org.eclipse.tm.tcf.terminals plugin is launched along
81with that plugin.
82
833. CDT remote debug.
84 1) Choose from menu Run->"Debug Configurations..."->
85 "C/C++ Remote Application", and click the "New launch configuration"
86 button.
87 2) In the "Main" tab, click "New..." button and it will launch a
88 "New Connection" wizard.
89 3) In the "New Connection" dialogue, choose "TCF" as system type and
90 click "Next".
91 4) Input the ip address of the remote target machine in "Host name:",
92 choose an arbitary unique name for "Connection name:", and click
93 "Next".
94 5) Make sure "org.eclipse.tm.tcf.rse.Terminals" is checked, make sure
95 you have input the correct TCF session properties in the TCF
96 Connector Service and click "Next". (See Note 3 below)
97 6) Make sure "org.eclipse.tm.tcf.rse.Files" is checked and click "Next".
98 7) Make sure "org.eclipse.tm.tcf.rse.Processes" is checked and click
99 "Next".
100 8) Make sure "org.eclipse.tm.tcf.rse.Shells" is checked, make sure you
101 have input the correct TCF session properties in the TCF Connector
102 Service. (See Note 3 below)
103 9) Click "Finish" to close the "New Connection" dialogue.
104 10) In the "Main" tab, choose the connection just created from the
105 "Connection" drop-list.
106 11) In the "Main" tab, enter the "Remote Absolute File Path for
107 C/C++ Application". This is where the debugged application to be
108 downloaded to the remote target side. e.g. "/tmp/helloworld".
109 12) In the "Debugger" tab, please choose the correct "GDB debugger".
110 Usually you should choose the cross-gdb which matches the host
111 and target machine. (see Known limitations 2.)
112 13) Click "Debug".
113 14) In the popped up "Enter Password" dialogue, enter the correct
114 "User ID" and "Password" and click "OK". It will be used to
115 login to the remote target machine.
116
117III. Note
118================================
1191. Sometimes the eclispe would report a exception of
120 "Java.lang.OutOfMemoryError: PermGen space" and the application hangs.
121 This is because the JVM garbage collection doesn't clean the permenant
122 generation space, which is used to store meta-data descriptions of
123 classes. To fix this problem, please add "-XX:MaxPermSize=256M" to the
124 "VM arguements" when launching the plug-ins.
125
1262. The following eclipse plugins should be installed before building
127 TCF related plugins.
128
129 CDT v6.0.2: http://download.eclipse.org/tools/cdt/releases/galileo
130 RSE v3.1.2: http://download.eclipse.org/dsdp/tm/updates/3.1/
131
1323. TCF Connector Service Properties.
133The TCF connector service properties are used for the TCF based RSE
134terminals and shells subsystems.
135
136To change these properties, click the "TCF Connection Settings" under
137the "Available Services" in the wizard, in the right, a list of
138properties is shown and ready for change.
139
140Here is a list of the properties:
141
142 - Command.Prompt
143 This is a string of which the shell/terminal prompt string on the remote
144 target system will end with. The default value is
145 "# "(Pay attention there is a space after the '#').
146
147 - Login.Prompt
148 This is a string of which the login prompt string on the remote target
149 system will end with. The default value is "ogin: "(Pay attention
150 there is a space after the ':').
151
152 - Login.Required
153 Set to "true" if the remote target system requires the user to input
154 login user name for terminal/shell services. Otherwise set to "false".
155 The default value is "true".
156
157 - Password.Prompt
158 This is a string of which the password prompt string on the remote target
159 system will end with. The default value is "assword: ".(Pay attention
160 there is a space after the ':')
161
162 - Pwd.Required
163 Setting to "true" if the remote target system requires the user to input
164 password for terminal/shell services. Otherwise set to "false". The
165 default value is "false".
166
167IV. Known limitations
168================================
1691. Authentication retry is not implemented. The user only has one chance to
170 input the correct password. If it fails, the user needs to re-launch
171 shell/terminal. If the user has checked the "Save password" in the prompt
172 dialogue, it needs to be disconnected and re-connected.
173
1742. Users have to set the correct cross-gdb debugger manually in the
175 "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 @@
1Index: org.eclipse.tm.tcf.terminals.agent/terminals.c
2===================================================================
3--- org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0)
4+++ org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0)
5@@ -0,0 +1,860 @@
6+/*******************************************************************************
7+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
8+ * All rights reserved. This program and the accompanying materials
9+ * are made available under the terms of the Eclipse Public License v1.0
10+ * and Eclipse Distribution License v1.0 which accompany this distribution.
11+ * The Eclipse Public License is available at
12+ * http://www.eclipse.org/legal/epl-v10.html
13+ * and the Eclipse Distribution License is available at
14+ * http://www.eclipse.org/org/documents/edl-v10.php.
15+ *
16+ * Contributors:
17+ * Wind River Systems - initial API and implementation
18+ * Intel - implemented terminals service
19+ *******************************************************************************/
20+
21+/*
22+ * Sample TCF service implementation.
23+ */
24+
25+#include <config.h>
26+#include <stdlib.h>
27+#include <stdio.h>
28+#include <string.h>
29+#include <errno.h>
30+#include <fcntl.h>
31+#include <signal.h>
32+#include <assert.h>
33+#include <termios.h>
34+#ifndef TIOCGWINSZ
35+#include <sys/ioctl.h>
36+#endif
37+#include <framework/myalloc.h>
38+#include <framework/protocol.h>
39+#include <framework/trace.h>
40+#include <framework/context.h>
41+#include <framework/json.h>
42+#include <framework/asyncreq.h>
43+#include <framework/exceptions.h>
44+#include <framework/waitpid.h>
45+#include <framework/signames.h>
46+#include <services/streamsservice.h>
47+#include <terminals.h>
48+
49+#define TERMINALS_DEBUG 1
50+
51+#define TERMINALS_NO_LOGIN 0
52+
53+static const char * TERMINALS = "Terminals";
54+
55+#if defined(WIN32)
56+# include <tlhelp32.h>
57+# ifdef _MSC_VER
58+# pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */
59+# include <winternl.h>
60+# else
61+# include <ntdef.h>
62+# endif
63+# ifndef STATUS_INFO_LENGTH_MISMATCH
64+# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
65+# endif
66+# ifndef SystemHandleInformation
67+# define SystemHandleInformation 16
68+# endif
69+# error("unsupported WIN32!")
70+#elif defined(_WRS_KERNEL)
71+# include <symLib.h>
72+# include <sysSymTbl.h>
73+# include <ioLib.h>
74+# include <ptyDrv.h>
75+# include <taskHookLib.h>
76+# error("unsupported WRS!")
77+#else
78+# include <sys/stat.h>
79+# include <unistd.h>
80+# include <dirent.h>
81+# if TERMINALS_NO_LOGIN
82+# define TERM_LAUNCH_EXEC "/bin/bash"
83+# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, NULL}
84+# else
85+# define TERM_LAUNCH_EXEC "/bin/login"
86+# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, "-p", NULL}
87+# endif
88+#endif
89+
90+#define PIPE_SIZE 0x1000
91+#define TERM_PROP_DEF_SIZE 256
92+
93+typedef struct Terminal
94+{
95+ LINK link;
96+ int pid; /*pid of the login process of the terminal*/
97+ TCFBroadcastGroup * bcg;
98+ int inp;
99+ int out;
100+ int err;
101+ struct TerminalInput * inp_struct;
102+ struct TerminalOutput * out_struct;
103+ struct TerminalOutput * err_struct;
104+ char inp_id[256];
105+ char out_id[256];
106+ char err_id[256];
107+
108+ char pty_type[TERM_PROP_DEF_SIZE];
109+ char encoding[TERM_PROP_DEF_SIZE];
110+ unsigned long width;
111+ unsigned long height;
112+ long exit_code;
113+
114+ Channel *channel;
115+} Terminal;
116+
117+typedef struct TerminalOutput
118+{
119+ Terminal * prs;
120+ AsyncReqInfo req;
121+ int req_posted;
122+ char buf[PIPE_SIZE];
123+ size_t buf_pos;
124+ int eos;
125+ VirtualStream * vstream;
126+} TerminalOutput;
127+
128+typedef struct TerminalInput
129+{
130+ Terminal * prs;
131+ AsyncReqInfo req;
132+ int req_posted;
133+ char buf[PIPE_SIZE];
134+ size_t buf_pos;
135+ size_t buf_len;
136+ int eos;
137+ VirtualStream * vstream;
138+} TerminalInput;
139+
140+#define link2term(A) ((Terminal *)((char *)(A) - offsetof(Terminal, link)))
141+
142+static LINK terms_list;
143+#if defined(_WRS_KERNEL)
144+static SEM_ID prs_list_lock = NULL;
145+#endif
146+
147+static Terminal * find_terminal(int pid)
148+{
149+ LINK * qhp = &terms_list;
150+ LINK * qp = qhp->next;
151+
152+ while (qp != qhp) {
153+ Terminal * prs = link2term(qp);
154+ if (prs->pid == pid)
155+ return prs;
156+ qp = qp->next;
157+ }
158+ return NULL;
159+}
160+
161+static char * tid2id(int tid)
162+{
163+ static char s[64];
164+ char * p = s + sizeof(s);
165+ unsigned long n = (long) tid;
166+ *(--p) = 0;
167+ do {
168+ *(--p) = (char) (n % 10 + '0');
169+ n = n / 10;
170+ } while (n != 0);
171+
172+ *(--p) = 'T';
173+ return p;
174+}
175+
176+static int id2tid(const char * id)
177+{
178+ int tid = 0;
179+ if (id == NULL)
180+ return 0;
181+ if (id[0] != 'T')
182+ return 0;
183+ if (id[1] == 0)
184+ return 0;
185+ tid = (unsigned) strtol(id + 1, (char **) &id, 10);
186+ if (id[0] != 0)
187+ return 0;
188+ return tid;
189+}
190+
191+static void write_context(OutputStream * out, int tid)
192+{
193+ Terminal * prs = find_terminal(tid);
194+
195+ write_stream(out, '{');
196+
197+ if (prs != NULL) {
198+ if (*prs->pty_type) {
199+ json_write_string(out, "PtyType");
200+ write_stream(out, ':');
201+ json_write_string(out, prs->pty_type);
202+ write_stream(out, ',');
203+ }
204+
205+ if (*prs->encoding) {
206+ json_write_string(out, "Encoding");
207+ write_stream(out, ':');
208+ json_write_string(out, prs->encoding);
209+ write_stream(out, ',');
210+ }
211+
212+ json_write_string(out, "Width");
213+ write_stream(out, ':');
214+ json_write_ulong(out, prs->width);
215+ write_stream(out, ',');
216+
217+ json_write_string(out, "Height");
218+ write_stream(out, ':');
219+ json_write_ulong(out, prs->height);
220+ write_stream(out, ',');
221+
222+ if (*prs->inp_id) {
223+ json_write_string(out, "StdInID");
224+ write_stream(out, ':');
225+ json_write_string(out, prs->inp_id);
226+ write_stream(out, ',');
227+ }
228+ if (*prs->out_id) {
229+ json_write_string(out, "StdOutID");
230+ write_stream(out, ':');
231+ json_write_string(out, prs->out_id);
232+ write_stream(out, ',');
233+ }
234+ if (*prs->err_id) {
235+ json_write_string(out, "StdErrID");
236+ write_stream(out, ':');
237+ json_write_string(out, prs->err_id);
238+ write_stream(out, ',');
239+ }
240+ }
241+
242+ json_write_string(out, "ID");
243+ write_stream(out, ':');
244+ json_write_string(out, tid2id(tid));
245+
246+ write_stream(out, '}');
247+}
248+
249+static void send_event_terminal_exited(OutputStream * out, Terminal * prs)
250+{
251+ write_stringz(out, "E");
252+ write_stringz(out, TERMINALS);
253+ write_stringz(out, "exited");
254+
255+ json_write_string(out, tid2id(prs->pid));
256+ write_stream(out, 0);
257+
258+ json_write_ulong(out, prs->exit_code);
259+ write_stream(out, 0);
260+
261+ write_stream(out, MARKER_EOM);
262+}
263+
264+static void send_event_terminal_win_size_changed(OutputStream * out,
265+ Terminal * prs)
266+{
267+ write_stringz(out, "E");
268+ write_stringz(out, TERMINALS);
269+ write_stringz(out, "winSizeChanged");
270+
271+ json_write_string(out, tid2id(prs->pid));
272+ write_stream(out, 0);
273+
274+ json_write_long(out, prs->width);
275+ write_stream(out, 0);
276+
277+ json_write_long(out, prs->height);
278+ write_stream(out, 0);
279+
280+ write_stream(out, MARKER_EOM);
281+}
282+
283+static int kill_term(Terminal *term)
284+{
285+ int err = 0;
286+
287+#if defined(WIN32)
288+ HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, term->pid);
289+ if (h == NULL)
290+ {
291+ err = set_win32_errno(GetLastError());
292+ }
293+ else
294+ {
295+ if (!TerminateProcess(h, 1)) err = set_win32_errno(GetLastError());
296+ if (!CloseHandle(h) && !err) err = set_win32_errno(GetLastError());
297+ }
298+#else
299+ if (kill(term->pid, SIGTERM) < 0)
300+ err = errno;
301+#endif
302+ return err;
303+}
304+
305+static void command_exit(char * token, Channel * c)
306+{
307+ int err = 0;
308+ char id[256];
309+ unsigned tid;
310+ Terminal *term = NULL;
311+
312+ json_read_string(&c->inp, id, sizeof(id));
313+ if (read_stream(&c->inp) != 0)
314+ exception(ERR_JSON_SYNTAX);
315+ if (read_stream(&c->inp) != MARKER_EOM)
316+ exception(ERR_JSON_SYNTAX);
317+
318+ tid = id2tid(id);
319+ write_stringz(&c->out, "R");
320+ write_stringz(&c->out, token);
321+
322+ if (tid == 0) {
323+ err = ERR_INV_CONTEXT;
324+ } else {
325+ term = find_terminal(tid);
326+ if (term == NULL) {
327+ err = ERR_INV_CONTEXT;
328+ } else {
329+ err = kill_term(term);
330+ }
331+ }
332+
333+ write_errno(&c->out, err);
334+ write_stream(&c->out, MARKER_EOM);
335+}
336+
337+static void terminal_exited(Terminal * prs)
338+{
339+ Trap trap;
340+
341+ if (set_trap(&trap)) {
342+ send_event_terminal_exited(&prs->bcg->out, prs);
343+ clear_trap(&trap);
344+ } else {
345+ trace(LOG_ALWAYS, "Exception sending terminal exited event: %d %s",
346+ trap.error, errno_to_str(trap.error));
347+ }
348+
349+#if defined(_WRS_KERNEL)
350+ semTake(prs_list_lock, WAIT_FOREVER);
351+#endif
352+ list_remove(&prs->link);
353+ close(prs->inp);
354+ close(prs->out);
355+ if (prs->out != prs->err)
356+ close(prs->err);
357+ if (prs->inp_struct) {
358+ TerminalInput * inp = prs->inp_struct;
359+ if (!inp->req_posted) {
360+ virtual_stream_delete(inp->vstream);
361+ loc_free(inp);
362+ } else {
363+ inp->prs = NULL;
364+ }
365+ }
366+ if (prs->out_struct)
367+ prs->out_struct->prs = NULL;
368+ if (prs->err_struct)
369+ prs->err_struct->prs = NULL;
370+ loc_free(prs);
371+#if defined(_WRS_KERNEL)
372+ semGive(prs_list_lock);
373+#endif
374+}
375+
376+static void terminal_input_streams_callback(VirtualStream * stream,
377+ int event_code, void * args)
378+{
379+ TerminalInput * inp = (TerminalInput *) args;
380+
381+ assert(inp->vstream == stream);
382+ if (!inp->req_posted) {
383+ if (inp->buf_pos >= inp->buf_len && !inp->eos) {
384+ inp->buf_pos = inp->buf_len = 0;
385+ virtual_stream_get_data(stream, inp->buf, sizeof(inp->buf),
386+ &inp->buf_len, &inp->eos);
387+ }
388+ if (inp->buf_pos < inp->buf_len) {
389+ inp->req.u.fio.bufp = inp->buf + inp->buf_pos;
390+ inp->req.u.fio.bufsz = inp->buf_len - inp->buf_pos;
391+ inp->req_posted = 1;
392+ async_req_post(&inp->req);
393+ }
394+ }
395+}
396+
397+static void write_terminal_input_done(void * x)
398+{
399+ AsyncReqInfo * req = (AsyncReqInfo *) x;
400+ TerminalInput * inp = (TerminalInput *) req->client_data;
401+
402+ inp->req_posted = 0;
403+ if (inp->prs == NULL) {
404+ /* Process has exited */
405+ virtual_stream_delete(inp->vstream);
406+ loc_free(inp);
407+ } else {
408+ int wr = inp->req.u.fio.rval;
409+
410+ if (wr < 0) {
411+ int err = inp->req.error;
412+ trace(LOG_ALWAYS, "Can't write terminal input stream: %d %s", err,
413+ errno_to_str(err));
414+ inp->buf_pos = inp->buf_len = 0;
415+ } else {
416+ inp->buf_pos += wr;
417+ }
418+
419+ terminal_input_streams_callback(inp->vstream, 0, inp);
420+ }
421+}
422+
423+static void write_terminal_input(Terminal * prs)
424+{
425+ TerminalInput * inp = prs->inp_struct = (TerminalInput *) loc_alloc_zero(
426+ sizeof(TerminalInput));
427+ inp->prs = prs;
428+ inp->req.client_data = inp;
429+ inp->req.done = write_terminal_input_done;
430+ inp->req.type = AsyncReqWrite;
431+ inp->req.u.fio.fd = prs->inp;
432+ virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE,
433+ VS_ENABLE_REMOTE_WRITE, terminal_input_streams_callback, inp,
434+ &inp->vstream);
435+ virtual_stream_get_id(inp->vstream, prs->inp_id, sizeof(prs->inp_id));
436+}
437+
438+static void terminal_output_streams_callback(VirtualStream * stream,
439+ int event_code, void * args)
440+{
441+ TerminalOutput * out = (TerminalOutput *) args;
442+
443+ assert(out->vstream == stream);
444+ if (!out->req_posted) {
445+ int buf_len = out->req.u.fio.rval;
446+ int err = 0;
447+ int eos = 0;
448+
449+ if (buf_len < 0) {
450+ buf_len = 0;
451+ err = out->req.error;
452+ }
453+ if (buf_len == 0)
454+ eos = 1;
455+ if (out->prs == NULL) {
456+ eos = 1;
457+ err = 0;
458+ }
459+
460+ assert(buf_len <= (int)sizeof(out->buf));
461+ assert(out->buf_pos <= (size_t)buf_len);
462+ assert(out->req.u.fio.bufp == out->buf);
463+#ifdef __linux__
464+ if (err == EIO)
465+ err = 0;
466+#endif
467+ if (err)
468+ trace(LOG_ALWAYS, "Can't read terminal output stream: %d %s", err,
469+ errno_to_str(err));
470+
471+ if (out->buf_pos < (size_t) buf_len || out->eos != eos) {
472+ size_t done = 0;
473+ virtual_stream_add_data(stream, out->buf + out->buf_pos, buf_len
474+ - out->buf_pos, &done, eos);
475+ out->buf_pos += done;
476+ if (eos)
477+ out->eos = 1;
478+ }
479+
480+ if (out->buf_pos >= (size_t) buf_len) {
481+ if (!eos) {
482+ out->req_posted = 1;
483+ async_req_post(&out->req);
484+ } else if (virtual_stream_is_empty(stream)) {
485+ if (out->prs != NULL) {
486+ if (out == out->prs->out_struct)
487+ out->prs->out_struct = NULL;
488+ if (out == out->prs->err_struct)
489+ out->prs->err_struct = NULL;
490+ }
491+ virtual_stream_delete(stream);
492+ loc_free(out);
493+ }
494+ }
495+ } // end if(!out->req_posted)
496+}
497+
498+static void read_terminal_output_done(void * x)
499+{
500+ AsyncReqInfo * req = (AsyncReqInfo *) x;
501+ TerminalOutput * out = (TerminalOutput *) req->client_data;
502+
503+ out->buf_pos = 0;
504+ out->req_posted = 0;
505+ terminal_output_streams_callback(out->vstream, 0, out);
506+}
507+
508+static TerminalOutput * read_terminal_output(Terminal * prs, int fd, char * id,
509+ size_t id_size)
510+{
511+ TerminalOutput * out = (TerminalOutput *) loc_alloc_zero(
512+ sizeof(TerminalOutput));
513+ out->prs = prs;
514+ out->req.client_data = out;
515+ out->req.done = read_terminal_output_done;
516+ out->req.type = AsyncReqRead;
517+ out->req.u.fio.bufp = out->buf;
518+ out->req.u.fio.bufsz = sizeof(out->buf);
519+ out->req.u.fio.fd = fd;
520+ virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE,
521+ VS_ENABLE_REMOTE_READ, terminal_output_streams_callback, out,
522+ &out->vstream);
523+ virtual_stream_get_id(out->vstream, id, id_size);
524+ out->req_posted = 1;
525+ async_req_post(&out->req);
526+ return out;
527+}
528+
529+static char **envp_add(char **old_envp, int old_envp_len, char *env)
530+{
531+ char **new_envp = NULL;
532+ int i;
533+ int env_size;
534+ int old_envp_size;
535+
536+ assert(old_envp || (old_envp==NULL && old_envp_len==0));
537+ assert(env);
538+ assert(*env);
539+
540+ for (i = 0, old_envp_size = 0; i < old_envp_len; i++) {
541+ old_envp_size += sizeof(char *); //size of env pointer
542+ old_envp_size += strlen(old_envp[i]) + 1; //size of env string, including trailing '\0'
543+ }
544+ assert((old_envp && old_envp[i]==NULL) || (old_envp==NULL));
545+ old_envp_size += sizeof(char *);//last null pointer
546+
547+ env_size = strlen(env); //new env string size
548+
549+ new_envp = loc_alloc(old_envp_size + sizeof(char *) + env_size + 1);
550+ if (new_envp != NULL) {
551+ new_envp[0] = (char *) new_envp + old_envp_size + sizeof(char *); //setting new env ptr
552+ strcpy(new_envp[0], env); //copy new env string
553+ if (old_envp) {
554+ memcpy(&new_envp[1], old_envp, old_envp_size); //copy old envp
555+ } else {
556+ new_envp[1] = NULL;
557+ }
558+ }
559+ return new_envp;
560+}
561+
562+static int start_terminal(Channel * c, char *pty_type, char *encoding,
563+ char ** envp, int envp_len, char * exe, char ** args, int *pid,
564+ Terminal ** prs)
565+{
566+ int err = 0;
567+ int fd_tty_master = -1;
568+ char * tty_slave_name = NULL;
569+ struct winsize size;
570+ char **newenvp = envp;
571+
572+ memset(&size, 0, sizeof(struct winsize));
573+ fd_tty_master = posix_openpt(O_RDWR | O_NOCTTY);
574+ if (fd_tty_master < 0 || grantpt(fd_tty_master) < 0 || unlockpt(
575+ fd_tty_master) < 0)
576+ err = errno;
577+ if (!err) {
578+ tty_slave_name = ptsname(fd_tty_master);
579+ if (tty_slave_name == NULL)
580+ err = EINVAL;
581+ }
582+
583+ if (ioctl(fd_tty_master, TIOCGWINSZ, (char *) &size) < 0)
584+ err = errno;
585+
586+ if (!err && fd_tty_master < 3) {
587+ int fd0 = fd_tty_master;
588+ if ((fd_tty_master = dup(fd_tty_master)) < 0 || close(fd0))
589+ err = errno;
590+ }
591+
592+ if (!err) {
593+ *pid = fork();
594+ if (*pid < 0)
595+ err = errno;
596+ if (*pid == 0) {
597+ int fd = -1;
598+ int fd_tty_slave = -1;
599+ char env_term[TERM_PROP_DEF_SIZE];
600+
601+ if (*pty_type) {
602+ snprintf(env_term, sizeof(env_term), "TERM=%s", pty_type);
603+ newenvp = envp_add(envp, envp_len, env_term);
604+ if (newenvp == NULL) {
605+ err = ENOMEM;
606+ } else if (envp) {
607+ loc_free(envp);
608+ envp = NULL;
609+ }
610+ }
611+
612+ if (!err && *encoding) {
613+ envp = newenvp;
614+ envp_len += 1;
615+ snprintf(env_term, sizeof(env_term), "LANG=%s", encoding);
616+ newenvp = envp_add(envp, envp_len, env_term);
617+ if (newenvp == NULL) {
618+ err = ENOMEM;
619+ } else if (envp) {
620+ loc_free(envp);
621+ envp = NULL;
622+ }
623+ }
624+
625+ setsid();
626+
627+ if (!err && (fd = sysconf(_SC_OPEN_MAX)) < 0)
628+ err = errno;
629+ if (!err && (fd_tty_slave = open(tty_slave_name, O_RDWR)) < 0)
630+ err = errno;
631+#if defined(TIOCSCTTY)
632+ if (!err && (ioctl(fd_tty_slave, TIOCSCTTY, (char *) 0)) < 0)
633+ err = errno;
634+#endif
635+ if (!err && dup2(fd_tty_slave, 0) < 0)
636+ err = errno;
637+ if (!err && dup2(fd_tty_slave, 1) < 0)
638+ err = errno;
639+ if (!err && dup2(fd_tty_slave, 2) < 0)
640+ err = errno;
641+ while (!err && fd > 3)
642+ close(--fd);
643+ if (!err) {
644+ execve(exe, args, newenvp);
645+ err = errno;
646+ }
647+ if (newenvp)
648+ loc_free(newenvp);
649+ err = 1;
650+ if (err < 1)
651+ err = EINVAL;
652+ else if (err > 0xff)
653+ err = EINVAL;
654+ exit(err);
655+ }
656+ }
657+
658+ if (!err) {
659+ *prs = (Terminal *) loc_alloc_zero(sizeof(Terminal));
660+ (*prs)->inp = fd_tty_master;
661+ (*prs)->out = fd_tty_master;
662+ (*prs)->err = fd_tty_master;
663+ (*prs)->pid = *pid;
664+ (*prs)->bcg = c->bcg;
665+ (*prs)->channel = c;
666+ if (*pty_type)
667+ snprintf((*prs)->pty_type, sizeof((*prs)->pty_type), "%s", pty_type);
668+ if (*encoding)
669+ snprintf((*prs)->encoding, sizeof((*prs)->encoding), "%s", encoding);
670+ (*prs)->width = size.ws_row;
671+ (*prs)->height = size.ws_col;
672+ list_add_first(&(*prs)->link, &terms_list);
673+ }
674+
675+ if (!err)
676+ return 0;
677+ errno = err;
678+ return -1;
679+}
680+
681+static void command_get_context(char * token, Channel * c)
682+{
683+ int err = 0;
684+ char id[256];
685+ int tid;
686+ Terminal *term;
687+
688+ json_read_string(&c->inp, id, sizeof(id));
689+ if (read_stream(&c->inp) != 0)
690+ exception(ERR_JSON_SYNTAX);
691+ if (read_stream(&c->inp) != MARKER_EOM)
692+ exception(ERR_JSON_SYNTAX);
693+
694+ tid = id2tid(id);
695+ write_stringz(&c->out, "R");
696+ write_stringz(&c->out, token);
697+
698+ if (tid == 0) {
699+ err = ERR_INV_CONTEXT;
700+ } else {
701+ term = find_terminal(tid);
702+ if (term == NULL) {
703+ err = ERR_INV_CONTEXT;
704+ } else {
705+ write_context(&c->out, tid);
706+ write_stream(&c->out, 0);
707+ }
708+ }
709+
710+ write_errno(&c->out, err);
711+ write_stream(&c->out, MARKER_EOM);
712+}
713+
714+static void command_launch(char * token, Channel * c)
715+{
716+ int pid = 0;
717+ int err = 0;
718+ char encoding[TERM_PROP_DEF_SIZE];
719+ char pty_type[TERM_PROP_DEF_SIZE];
720+ char *args[] = TERM_LAUNCH_ARGS;
721+
722+ char ** envp = NULL;
723+ int envp_len = 0;
724+
725+ Terminal * prs = NULL;
726+ Trap trap;
727+
728+ if (set_trap(&trap)) {
729+ json_read_string(&c->inp, pty_type, sizeof(pty_type));
730+ if (read_stream(&c->inp) != 0)
731+ exception(ERR_JSON_SYNTAX);
732+ json_read_string(&c->inp, encoding, sizeof(encoding));
733+ if (read_stream(&c->inp) != 0)
734+ exception(ERR_JSON_SYNTAX);
735+ envp = json_read_alloc_string_array(&c->inp, &envp_len);
736+ if (read_stream(&c->inp) != 0)
737+ exception(ERR_JSON_SYNTAX);
738+ if (read_stream(&c->inp) != MARKER_EOM)
739+ exception(ERR_JSON_SYNTAX);
740+
741+ if (err == 0 && start_terminal(c, pty_type, encoding, envp, envp_len,
742+ TERM_LAUNCH_EXEC, args, &pid, &prs) < 0)
743+ err = errno;
744+ if (prs != NULL) {
745+ write_terminal_input(prs);
746+ prs->out_struct = read_terminal_output(prs, prs->out, prs->out_id,
747+ sizeof(prs->out_id));
748+ if (prs->out != prs->err)
749+ prs->err_struct = read_terminal_output(prs, prs->err,
750+ prs->err_id, sizeof(prs->err_id));
751+ }
752+ if (!err) {
753+ add_waitpid_process(pid);
754+ }
755+ //write result back
756+ {
757+ write_stringz(&c->out, "R");
758+ write_stringz(&c->out, token);
759+ write_errno(&c->out, err);
760+ if (err || pid == 0) {
761+ write_stringz(&c->out, "null");
762+ } else {
763+ write_context(&c->out, pid);
764+ write_stream(&c->out, 0);
765+ }
766+ write_stream(&c->out, MARKER_EOM);
767+ }
768+ clear_trap(&trap);
769+ }
770+
771+ loc_free(envp);
772+
773+ if (trap.error)
774+ exception(trap.error);
775+}
776+
777+static void command_set_win_size(char * token, Channel * c)
778+{
779+ int err = 0;
780+ struct winsize size;
781+ char id[256];
782+ unsigned tid;
783+ Terminal *term = NULL;
784+
785+ json_read_string(&c->inp, id, sizeof(id));
786+ if (read_stream(&c->inp) != 0)
787+ exception(ERR_JSON_SYNTAX);
788+ size.ws_col=json_read_ulong(&c->inp);
789+ if (read_stream(&c->inp) != 0)
790+ exception(ERR_JSON_SYNTAX);
791+ size.ws_row=json_read_ulong(&c->inp);
792+ if (read_stream(&c->inp) != 0)
793+ exception(ERR_JSON_SYNTAX);
794+ if (read_stream(&c->inp) != MARKER_EOM)
795+ exception(ERR_JSON_SYNTAX);
796+
797+ tid = id2tid(id);
798+
799+ if(tid==0 || (term=find_terminal(tid))==NULL) {
800+ err=ERR_INV_CONTEXT;
801+ }else if (term->width != size.ws_col || term->height != size.ws_row) {
802+ if(ioctl(term->inp,TIOCSWINSZ,&size)<0) {
803+ err=errno;
804+ }
805+ if(!err) {
806+ term->width=size.ws_col;
807+ term->height=size.ws_row;
808+ send_event_terminal_win_size_changed(&term->channel->out,term);
809+ }
810+ }
811+
812+ write_stringz(&c->out, "R");
813+ write_stringz(&c->out, token);
814+ write_errno(&c->out, err);
815+ write_stream(&c->out, MARKER_EOM);
816+
817+}
818+
819+static void waitpid_listener(int pid, int exited, int exit_code, int signal,
820+ int event_code, int syscall, void * args)
821+{
822+ if (exited) {
823+ Terminal * prs = find_terminal(pid);
824+ if (prs) {
825+ if (signal != 0)
826+ prs->exit_code = -signal;
827+ else
828+ prs->exit_code = exit_code;
829+ terminal_exited(prs);
830+ }
831+ }
832+}
833+
834+static void channel_close_listener(Channel * c)
835+{
836+ LINK * l = NULL;
837+
838+ for (l = terms_list.next; l != &terms_list;) {
839+ Terminal * term = link2term(l);
840+ l = l->next;
841+ if (term->channel == c) {
842+ trace(LOG_ALWAYS, "Terminal is left launched: T%d", term->pid);
843+ kill_term(term);
844+ }
845+ }
846+}
847+
848+void ini_terminals_service(Protocol * proto)
849+{
850+#if defined(_WRS_KERNEL)
851+ prs_list_lock = semMCreate(SEM_Q_PRIORITY);
852+ if (prs_list_lock == NULL) check_error(errno);
853+ if (taskCreateHookAdd((FUNCPTR)task_create_hook) != OK) check_error(errno);
854+ if (taskDeleteHookAdd((FUNCPTR)task_delete_hook) != OK) check_error(errno);
855+#endif
856+ list_init(&terms_list);
857+
858+ add_waitpid_listener(waitpid_listener, NULL);
859+ add_channel_close_listener(channel_close_listener);
860+
861+ add_command_handler(proto, TERMINALS, "getContext", command_get_context);
862+ add_command_handler(proto, TERMINALS, "launch", command_launch);
863+ add_command_handler(proto, TERMINALS, "exit", command_exit);
864+ add_command_handler(proto, TERMINALS, "setWinSize", command_set_win_size);
865+}
866Index: org.eclipse.tm.tcf.terminals.agent/main/services-ext.h
867===================================================================
868--- org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0)
869+++ org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0)
870@@ -0,0 +1,26 @@
871+/*******************************************************************************
872+ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
873+ * All rights reserved. This program and the accompanying materials
874+ * are made available under the terms of the Eclipse Public License v1.0
875+ * and Eclipse Distribution License v1.0 which accompany this distribution.
876+ * The Eclipse Public License is available at
877+ * http://www.eclipse.org/legal/epl-v10.html
878+ * and the Eclipse Distribution License is available at
879+ * http://www.eclipse.org/org/documents/edl-v10.php.
880+ *
881+ * Contributors:
882+ * Wind River Systems - initial API and implementation
883+ * Intel - implemented terminals service
884+ *******************************************************************************/
885+
886+/*
887+ * Services initialization code extension point.
888+ * If the agent is built with additional user-defined services,
889+ * a customized version of services-ext.h file can be added to compiler headers search paths.
890+ */
891+
892+#include "terminals.h"
893+
894+static void ini_ext_services(Protocol * proto, TCFBroadcastGroup * bcg) {
895+ ini_terminals_service(proto);
896+}
897Index: org.eclipse.tm.tcf.terminals.agent/terminals.h
898===================================================================
899--- org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0)
900+++ org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0)
901@@ -0,0 +1,28 @@
902+/*******************************************************************************
903+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
904+ * All rights reserved. This program and the accompanying materials
905+ * are made available under the terms of the Eclipse Public License v1.0
906+ * and Eclipse Distribution License v1.0 which accompany this distribution.
907+ * The Eclipse Public License is available at
908+ * http://www.eclipse.org/legal/epl-v10.html
909+ * and the Eclipse Distribution License is available at
910+ * http://www.eclipse.org/org/documents/edl-v10.php.
911+ *
912+ * Contributors:
913+ * Wind River Systems - initial API and implementation
914+ * Intel - implemented terminals service
915+ *******************************************************************************/
916+
917+/*
918+ * TCF terminals service header file.
919+ */
920+
921+#ifndef TERMINALS_H_
922+#define TERMINALS_H_
923+
924+#include <config.h>
925+#include <framework/protocol.h>
926+
927+extern void ini_terminals_service(Protocol * proto);
928+
929+#endif /*TERMINALS_H_*/
930Index: org.eclipse.tm.tcf.terminals.agent/config.h
931===================================================================
932--- org.eclipse.tm.tcf.terminals.agent/config.h (revision 0)
933+++ org.eclipse.tm.tcf.terminals.agent/config.h (revision 0)
934@@ -0,0 +1,64 @@
935+/*******************************************************************************
936+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
937+ * All rights reserved. This program and the accompanying materials
938+ * are made available under the terms of the Eclipse Public License v1.0
939+ * and Eclipse Distribution License v1.0 which accompany this distribution.
940+ * The Eclipse Public License is available at
941+ * http://www.eclipse.org/legal/epl-v10.html
942+ * and the Eclipse Distribution License is available at
943+ * http://www.eclipse.org/org/documents/edl-v10.php.
944+ *
945+ * Contributors:
946+ * Wind River Systems - initial API and implementation
947+ * Intel - implemented terminals service
948+ *******************************************************************************/
949+
950+/*
951+ * This file contains "define" statements that control agent configuration.
952+ * SERVICE_* definitions control which service implementations are included into the agent.
953+ *
954+ * This is example agent configuration. It includes only few standard services,
955+ * and one example service: Day Time.
956+ */
957+
958+#ifndef D_config
959+#define D_config
960+
961+#include <framework/mdep.h>
962+
963+#if defined(WIN32) || defined(__CYGWIN__)
964+# define TARGET_UNIX 0
965+#elif defined(_WRS_KERNEL)
966+# define TARGET_UNIX 0
967+#else
968+# define TARGET_UNIX 1
969+#endif
970+
971+#define SERVICE_Locator 1
972+#define SERVICE_Processes 1
973+#define SERVICE_Streams 1
974+#define SERVICE_FileSystem 1
975+#define SERVICE_SysMonitor TARGET_UNIX
976+
977+#define ENABLE_ZeroCopy 1
978+
979+#if !defined(ENABLE_Splice)
980+# if ENABLE_ZeroCopy
981+# include <fcntl.h>
982+# if defined(SPLICE_F_MOVE)
983+# define ENABLE_Splice 1
984+# else
985+# define ENABLE_Splice 0
986+# endif
987+# else
988+# define ENABLE_Splice 0
989+# endif
990+#endif
991+
992+#define ENABLE_SSL 0
993+
994+#define ENABLE_Trace 1
995+#define ENABLE_Discovery 1
996+
997+
998+#endif /* D_config */
999Index: org.eclipse.tm.tcf.terminals.agent/Makefile
1000===================================================================
1001--- org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0)
1002+++ org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0)
1003@@ -0,0 +1,39 @@
1004+TCF_AGENT_DIR=../agent
1005+
1006+include $(TCF_AGENT_DIR)/Makefile.inc
1007+
1008+override CFLAGS += $(foreach dir,$(INCDIRS),-I$(dir)) $(OPTS)
1009+
1010+HFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.h)) $(HFILES)
1011+CFILES := $(sort $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)) $(CFILES))
1012+
1013+#no using SSL
1014+LIBS = -lpthread -lrt
1015+
1016+EXECS = $(BINDIR)/agent$(EXTEXE)
1017+
1018+all: $(EXECS)
1019+
1020+$(BINDIR)/libtcf$(EXTLIB) : $(OFILES)
1021+ $(AR) rcs $@ $^
1022+
1023+$(BINDIR)/agent$(EXTEXE): $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB)
1024+ $(CC) $(CFLAGS) -o $@ $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB) $(LIBS)
1025+
1026+$(BINDIR)/%$(EXTOBJ): %.c $(HFILES) Makefile
1027+ @mkdir -p $(dir $@)
1028+ $(CC) $(CFLAGS) -c -o $@ $<
1029+
1030+$(BINDIR)/%$(EXTOBJ): $(TCF_AGENT_DIR)/%.c $(HFILES) Makefile
1031+ @mkdir -p $(dir $@)
1032+ $(CC) $(CFLAGS) -c -o $@ $<
1033+
1034+install: all
1035+ install -d -m 755 $(INSTALLROOT)$(SBIN)
1036+ install -d -m 755 $(INSTALLROOT)$(INIT)
1037+ install -c $(BINDIR)/agent -m 755 $(INSTALLROOT)$(SBIN)/tcf-agent
1038+ install -c $(TCF_AGENT_DIR)/main/tcf-agent.init -m 755 $(INSTALLROOT)$(INIT)/tcf-agent
1039+
1040+clean:
1041+ rm -rf $(BINDIR)
1042+
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 @@
1Index: plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF
2===================================================================
3--- plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF (revision 0)
4+++ plugins/org.eclipse.tm.tcf.terminals/META-INF/MANIFEST.MF (revision 0)
5@@ -0,0 +1,14 @@
6+Manifest-Version: 1.0
7+Bundle-ManifestVersion: 2
8+Bundle-Name: %pluginName
9+Bundle-SymbolicName: org.eclipse.tm.tcf.terminals;singleton:=true
10+Bundle-Version: 0.3.0.qualifier
11+Bundle-Activator: org.eclipse.tm.internal.tcf.terminals.Activator
12+Bundle-Vendor: %providerName
13+Require-Bundle: org.eclipse.core.runtime,
14+ org.eclipse.tm.tcf
15+Bundle-ActivationPolicy: lazy
16+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
17+Import-Package: org.eclipse.tm.tcf.core;version="0.3.0",
18+ org.eclipse.tm.tcf.protocol;version="0.3.0"
19+Export-Package: org.eclipse.tm.internal.tcf.terminals
20Index: plugins/org.eclipse.tm.tcf.terminals/.classpath
21===================================================================
22--- plugins/org.eclipse.tm.tcf.terminals/.classpath (revision 0)
23+++ plugins/org.eclipse.tm.tcf.terminals/.classpath (revision 0)
24@@ -0,0 +1,7 @@
25+<?xml version="1.0" encoding="UTF-8"?>
26+<classpath>
27+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
28+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
29+ <classpathentry kind="src" path="src"/>
30+ <classpathentry kind="output" path="bin"/>
31+</classpath>
32Index: plugins/org.eclipse.tm.tcf.terminals/.project
33===================================================================
34--- plugins/org.eclipse.tm.tcf.terminals/.project (revision 0)
35+++ plugins/org.eclipse.tm.tcf.terminals/.project (revision 0)
36@@ -0,0 +1,28 @@
37+<?xml version="1.0" encoding="UTF-8"?>
38+<projectDescription>
39+ <name>org.eclipse.tm.tcf.terminals</name>
40+ <comment></comment>
41+ <projects>
42+ </projects>
43+ <buildSpec>
44+ <buildCommand>
45+ <name>org.eclipse.jdt.core.javabuilder</name>
46+ <arguments>
47+ </arguments>
48+ </buildCommand>
49+ <buildCommand>
50+ <name>org.eclipse.pde.ManifestBuilder</name>
51+ <arguments>
52+ </arguments>
53+ </buildCommand>
54+ <buildCommand>
55+ <name>org.eclipse.pde.SchemaBuilder</name>
56+ <arguments>
57+ </arguments>
58+ </buildCommand>
59+ </buildSpec>
60+ <natures>
61+ <nature>org.eclipse.pde.PluginNature</nature>
62+ <nature>org.eclipse.jdt.core.javanature</nature>
63+ </natures>
64+</projectDescription>
65Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java
66===================================================================
67--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java (revision 0)
68+++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/TerminalsServiceProxy.java (revision 0)
69@@ -0,0 +1,191 @@
70+/*******************************************************************************
71+ * Copyright (c) 2010 Intel Corporation. and others.
72+ * All rights reserved. This program and the accompanying materials
73+ * are made available under the terms of the Eclipse Public License v1.0
74+ * which accompanies this distribution, and is available at
75+ * http://www.eclipse.org/legal/epl-v10.html
76+ *
77+ * Contributors:
78+ * Intel - initial API and implementation
79+ *******************************************************************************/
80+
81+package org.eclipse.tm.internal.tcf.terminals;
82+
83+import java.io.IOException;
84+import java.util.HashMap;
85+import java.util.Map;
86+
87+import org.eclipse.tm.internal.tcf.terminals.ITerminalsService;
88+import org.eclipse.tm.tcf.core.Command;
89+import org.eclipse.tm.tcf.protocol.IChannel;
90+import org.eclipse.tm.tcf.protocol.IToken;
91+import org.eclipse.tm.tcf.protocol.JSON;
92+import org.eclipse.tm.tcf.protocol.Protocol;
93+
94+public class TerminalsServiceProxy implements ITerminalsService {
95+
96+ private final IChannel channel;
97+ private final Map<TerminalsListener,IChannel.IEventListener> listeners =
98+ new HashMap<TerminalsListener,IChannel.IEventListener>();
99+
100+ private class TerminalContext implements ITerminalsService.TerminalContext {
101+
102+ private final Map<String,Object> props;
103+
104+ TerminalContext(Map<String,Object> props) {
105+ this.props = props;
106+ }
107+
108+ public String getID() {
109+ return (String)props.get(PROP_ID);
110+ }
111+
112+ public String getPtyType() {
113+ return (String)props.get(PROP_PTY_TYPE);
114+ }
115+
116+ public String getEncoding() {
117+ return (String)props.get(PROP_ENCODING);
118+ }
119+
120+ public int getWidth() {
121+ return ((Integer)props.get(PROP_WIDTH)).intValue();
122+ }
123+
124+ public int getHeight() {
125+ return ((Integer)props.get(PROP_HEIGHT)).intValue();
126+ }
127+
128+ public IToken exit(final DoneCommand done) {
129+ return new Command(channel, TerminalsServiceProxy.this,
130+ "exit", new Object[]{ getID() }) {
131+ @Override
132+ public void done(Exception error, Object[] args) {
133+ if (error == null) {
134+ assert args.length == 1;
135+ error = toError(args[0]);
136+ }
137+ done.doneCommand(token, error);
138+ }
139+ }.token;
140+ }
141+
142+ public Map<String, Object> getProperties() {
143+ return props;
144+ }
145+
146+ public String toString() {
147+ return "[Terminals Context " + props.toString() + "]";
148+ }
149+ }
150+
151+ TerminalsServiceProxy(IChannel channel) {
152+ this.channel = channel;
153+ }
154+
155+ /**
156+ * Return service name, as it appears on the wire - a TCF name of the service.
157+ */
158+ public String getName() {
159+ return NAME;
160+ }
161+
162+ public IToken getContext(String id, final DoneGetContext done)
163+ {
164+ return new Command(channel, this,
165+ "getContext", new Object[]{ id }) {
166+ @SuppressWarnings("unchecked")
167+ @Override
168+ public void done(Exception error, Object[] args) {
169+ TerminalContext ctx = null;
170+ if (error == null) {
171+ assert args.length == 2;
172+ error = toError(args[0]);
173+ if (args[1] != null) ctx = new TerminalContext((Map<String, Object>)args[1]);
174+ }
175+ done.doneGetContext(token, error, ctx);
176+ }
177+ }.token;
178+ }
179+
180+ public IToken launch(String type, String encoding, String[] environment, final DoneLaunch done)
181+ {
182+ return new Command(channel, this, "launch",
183+ new Object[]{ type, encoding, environment}) {
184+ @SuppressWarnings("unchecked")
185+ @Override
186+ public void done(Exception error, Object[] args) {
187+ TerminalContext ctx=null;
188+ if (error == null) {
189+ assert args.length == 2;
190+ error = toError(args[0]);
191+ if (args[1] != null) ctx = new TerminalContext((Map<String, Object>)args[1]);
192+ }
193+ done.doneLaunch(token, error, ctx);
194+ }
195+ }.token;
196+ }
197+
198+ public IToken setWinSize(String context_id, int newWidth, int newHeight, final DoneCommand done)
199+ {
200+ return new Command(channel, this, "setWinSize",
201+ new Object[]{ context_id, newWidth, newHeight}) {
202+ @Override
203+ public void done(Exception error, Object[] args) {
204+ if (error == null) {
205+ assert args.length == 1;
206+ error = toError(args[0]);
207+ }
208+ done.doneCommand(token, error);
209+ }
210+ }.token;
211+ }
212+
213+ public void addListener(final TerminalsListener listener)
214+ {
215+ IChannel.IEventListener l = new IChannel.IEventListener() {
216+ public void event(String name, byte[] data) {
217+ try {
218+ Object[] args = JSON.parseSequence(data);
219+ if (name.equals("exited")) {
220+ assert args.length == 2;
221+ listener.exited((String)args[0], ((Number)args[1]).intValue());
222+ }else if(name.equals("winSizeChanged")) {
223+ assert args.length == 3;
224+ listener.winSizeChanged((String)args[0], ((Number)args[1]).intValue(), ((Number)args[2]).intValue());
225+ }else {
226+ throw new IOException("Terminals service: unknown event: " + name);
227+ }
228+ }catch (Throwable x) {
229+ channel.terminate(x);
230+ }
231+ }
232+ };
233+ channel.addEventListener(this, l);
234+ listeners.put(listener, l);
235+ }
236+
237+ public void removeListener(TerminalsListener listener) {
238+ IChannel.IEventListener l = listeners.remove(listener);
239+ if (l != null) channel.removeEventListener(this, l);
240+ }
241+
242+ static {
243+ /*
244+ * Make Terminal Service proxy available to all potential clients by creating
245+ * the proxy object every time a TCF communication channel is opened.
246+ * Note: extension point "org.eclipse.tm.tcf.startup" is used to load this class
247+ * at TCF startup time, so proxy factory is properly activated even if nobody
248+ * import directly from this plugin.
249+ */
250+ Protocol.addChannelOpenListener(new Protocol.ChannelOpenListener() {
251+
252+ public void onChannelOpen(IChannel channel) {
253+ // Check if remote server provides Daytime service
254+ if (channel.getRemoteService(ITerminalsService.NAME) == null) return;
255+ // Create service proxy
256+ channel.setServiceProxy(ITerminalsService.class, new TerminalsServiceProxy(channel));
257+ }
258+ });
259+ }
260+}
261Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java
262===================================================================
263--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java (revision 0)
264+++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/ITerminalsService.java (revision 0)
265@@ -0,0 +1,193 @@
266+/*******************************************************************************
267+ * Copyright (c) 2010 Intel Corporation. and others.
268+ * All rights reserved. This program and the accompanying materials
269+ * are made available under the terms of the Eclipse Public License v1.0
270+ * which accompanies this distribution, and is available at
271+ * http://www.eclipse.org/legal/epl-v10.html
272+ *
273+ * Contributors:
274+ * Intel - initial API and implementation
275+ *******************************************************************************/
276+
277+package org.eclipse.tm.internal.tcf.terminals;
278+
279+import java.util.Map;
280+
281+import org.eclipse.tm.tcf.protocol.IService;
282+import org.eclipse.tm.tcf.protocol.IToken;
283+
284+/**
285+ * ITerminalsService allows to launch a new terminal on the remote target system.
286+ */
287+public interface ITerminalsService extends IService {
288+
289+ /**
290+ * This service name, as it appears on the wire - a TCF name of the service.
291+ */
292+ static final String NAME = "Terminals";
293+ /**
294+ * Retrieve context info for given context ID.
295+ * A context corresponds to an terminal.
296+ * Context IDs are valid across TCF services, so it is allowed to issue
297+ * 'ITerminals.getContext' command with a context that was obtained,
298+ * for example, from Memory service.
299+ * However, 'ITerminals.getContext' is supposed to return only terminal specific data,
300+ * If the ID is not a terminal ID, 'ITerminals.getContext' may not return any
301+ * useful information
302+ *
303+ * @param id – context ID.
304+ * @param done - call back interface called when operation is completed.
305+ */
306+ IToken getContext(String id, DoneGetContext done);
307+
308+ /**
309+ * Client call back interface for getContext().
310+ */
311+ interface DoneGetContext {
312+ /**
313+ * Called when contexts data retrieval is done.
314+ * @param error – error description if operation failed, null if succeeded.
315+ * @param context – context data.
316+ */
317+ void doneGetContext(IToken token, Exception error, TerminalContext context);
318+ }
319+ /**
320+ * Context property names.
321+ */
322+ static final String
323+ /** The TCF context ID */
324+ PROP_ID = "ID",
325+
326+ /** The pty type */
327+ PROP_PTY_TYPE = "PtyType",
328+
329+ /** terminal encoding */
330+ PROP_ENCODING = "Encoding",
331+
332+ /** window width size */
333+ PROP_WIDTH = "Width",
334+
335+ /** window height size */
336+ PROP_HEIGHT = "Height",
337+
338+ /** Process standard input stream ID */
339+ PROP_STDIN_ID = "StdInID",
340+
341+ /** Process standard output stream ID */
342+ PROP_STDOUT_ID = "StdOutID",
343+
344+ /** Process standard error stream ID */
345+ PROP_STDERR_ID = "StdErrID";
346+
347+ interface TerminalContext {
348+
349+ /**
350+ * Get context ID.
351+ * Same as getProperties().get(“ID”)
352+ */
353+ String getID();
354+
355+ /**
356+ * Get terminal type.
357+ * Same as getProperties().get(“PtyType”)
358+ */
359+ String getPtyType();
360+
361+ /**
362+ * Get encoding.
363+ * Same as getProperties().get(“Encoding”)
364+ */
365+ String getEncoding();
366+
367+ /**
368+ * Get width.
369+ * Same as getProperties().get(“Width”)
370+ */
371+ int getWidth();
372+
373+ /**
374+ * Get height.
375+ * Same as getProperties().get(“Height”)
376+ */
377+ int getHeight();
378+
379+ /**
380+ * Get all available context properties.
381+ * @return Map 'property name' -> 'property value'
382+ */
383+ Map<String, Object> getProperties();
384+
385+ /**
386+ * Exit the terminal.
387+ * @param done - call back interface called when operation is completed.
388+ * @return pending command handle, can be used to cancel the command.
389+ */
390+ IToken exit(DoneCommand done);
391+ }
392+
393+ interface DoneCommand {
394+ void doneCommand(IToken token, Exception error);
395+ }
396+ /**
397+ * Launch a new terminal toremote machine.
398+ * @param type - requested terminal type for the new terminal.
399+ * @param encoding - requested encoding for the new terminal.
400+ * @param environment - Array of environment variable strings.
401+ * if null then default set of environment variables will be used.
402+ * @param done - call back interface called when operation is completed.
403+ * @return pending command handle, can be used to cancel the command.
404+ */
405+ IToken launch(String type, String encoding, String[] environment,
406+ DoneLaunch done);
407+
408+ /**
409+ * Call-back interface to be called when "start" command is complete.
410+ */
411+ interface DoneLaunch {
412+ void doneLaunch(IToken token, Exception error, TerminalContext terminal);
413+ }
414+
415+
416+ /**
417+ * Set the terminal widows size
418+ * @param context_id - context ID.
419+ * @param signal - signal code.
420+ * @param done - call back interface called when operation is completed.
421+ * @return pending command handle, can be used to cancel the command.
422+ */
423+ IToken setWinSize(String context_id, int newWidth, int newHeight, DoneCommand done);
424+
425+ /**
426+ * Add terminals service event listener.
427+ * @param listener - event listener implementation.
428+ */
429+ void addListener(TerminalsListener listener);
430+
431+ /**
432+ * Remove terminals service event listener.
433+ * @param listener - event listener implementation.
434+ */
435+ void removeListener(TerminalsListener listener);
436+
437+ /**
438+ * Process event listener is notified when a terminal exits.
439+ * Event are reported only for terminals that were started by 'launch' command.
440+ */
441+ interface TerminalsListener {
442+
443+ /**
444+ * Called when a terminal exits.
445+ * @param terminal_id - terminal context ID
446+ * @param exit_code - terminal exit code
447+ */
448+ void exited(String terminal_id, int exit_code);
449+
450+ /**
451+ * Called when a terminal exits.
452+ * @param terminal_id - terminal context ID
453+ * @param newWidth – new terminal width
454+ * @param newHeight – new terminal height
455+ */
456+ void winSizeChanged (String terminal_id, int newWidth, int newHeight);
457+ }
458+}
459Index: plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java
460===================================================================
461--- plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java (revision 0)
462+++ plugins/org.eclipse.tm.tcf.terminals/src/org/eclipse/tm/internal/tcf/terminals/Activator.java (revision 0)
463@@ -0,0 +1,61 @@
464+/*******************************************************************************
465+ * Copyright (c) 2010 Intel Corporation. and others.
466+ * All rights reserved. This program and the accompanying materials
467+ * are made available under the terms of the Eclipse Public License v1.0
468+ * which accompanies this distribution, and is available at
469+ * http://www.eclipse.org/legal/epl-v10.html
470+ *
471+ * Contributors:
472+ * Intel - initial API and implementation
473+ *******************************************************************************/
474+
475+package org.eclipse.tm.internal.tcf.terminals;
476+
477+import org.eclipse.core.runtime.Plugin;
478+import org.osgi.framework.BundleContext;
479+
480+/**
481+ * The activator class controls the plug-in life cycle
482+ */
483+public class Activator extends Plugin {
484+
485+ // The plug-in ID
486+ public static final String PLUGIN_ID = "org.eclipse.tm.tcf.terminals";
487+
488+ // The shared instance
489+ private static Activator plugin;
490+
491+ /**
492+ * The constructor
493+ */
494+ public Activator() {
495+ }
496+
497+ /*
498+ * (non-Javadoc)
499+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
500+ */
501+ public void start(BundleContext context) throws Exception {
502+ super.start(context);
503+ plugin = this;
504+ }
505+
506+ /*
507+ * (non-Javadoc)
508+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
509+ */
510+ public void stop(BundleContext context) throws Exception {
511+ plugin = null;
512+ super.stop(context);
513+ }
514+
515+ /**
516+ * Returns the shared instance
517+ *
518+ * @return the shared instance
519+ */
520+ public static Activator getDefault() {
521+ return plugin;
522+ }
523+
524+}
525Index: plugins/org.eclipse.tm.tcf.terminals/plugin.properties
526===================================================================
527--- plugins/org.eclipse.tm.tcf.terminals/plugin.properties (revision 0)
528+++ plugins/org.eclipse.tm.tcf.terminals/plugin.properties (revision 0)
529@@ -0,0 +1,13 @@
530+###############################################################################
531+# Copyright (c) 2010 Intel, Inc. and others.
532+# All rights reserved. This program and the accompanying materials
533+# are made available under the terms of the Eclipse Public License v1.0
534+# which accompanies this distribution, and is available at
535+# http://www.eclipse.org/legal/epl-v10.html
536+#
537+# Contributors:
538+# Intel - initial implementation
539+###############################################################################
540+pluginName = TCF Terminals service (Incubation)
541+providerName = Eclipse.org
542+
543Index: plugins/org.eclipse.tm.tcf.terminals/build.properties
544===================================================================
545--- plugins/org.eclipse.tm.tcf.terminals/build.properties (revision 0)
546+++ plugins/org.eclipse.tm.tcf.terminals/build.properties (revision 0)
547@@ -0,0 +1,8 @@
548+source.. = src/
549+output.. = bin/
550+bin.includes = META-INF/,\
551+ .,\
552+ plugin.xml,\
553+ about.html,\
554+ plugin.properties
555+src.includes = about.html
556Index: plugins/org.eclipse.tm.tcf.terminals/plugin.xml
557===================================================================
558--- plugins/org.eclipse.tm.tcf.terminals/plugin.xml (revision 0)
559+++ plugins/org.eclipse.tm.tcf.terminals/plugin.xml (revision 0)
560@@ -0,0 +1,11 @@
561+<?xml version="1.0" encoding="UTF-8"?>
562+<?eclipse version="3.4"?>
563+<plugin>
564+ <extension
565+ point="org.eclipse.tm.tcf.startup">
566+ <class
567+ name="org.eclipse.tm.internal.tcf.terminals.TerminalsServiceProxy">
568+ </class>
569+ </extension>
570+
571+</plugin>
572Index: plugins/org.eclipse.tm.tcf.terminals/about.html
573===================================================================
574--- plugins/org.eclipse.tm.tcf.terminals/about.html (revision 0)
575+++ plugins/org.eclipse.tm.tcf.terminals/about.html (revision 0)
576@@ -0,0 +1,28 @@
577+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
578+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
579+<html xmlns="http://www.w3.org/1999/xhtml">
580+<head>
581+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
582+<title>About</title>
583+</head>
584+<body lang="EN-US">
585+<h2>About This Content</h2>
586+
587+<p>January 10, 2008</p>
588+<h3>License</h3>
589+
590+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
591+indicated below, the Content is provided to you under the terms and conditions of the
592+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
593+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
594+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
595+
596+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
597+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
598+apply to your use of any object code in the Content. Check the Redistributor's license that was
599+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
600+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
601+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
602+
603+</body>
604+</html>
605\ No newline at end of file
606Index: plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs
607===================================================================
608--- plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs (revision 0)
609+++ plugins/org.eclipse.tm.tcf.terminals/.settings/org.eclipse.jdt.core.prefs (revision 0)
610@@ -0,0 +1,8 @@
611+#Mon Jun 07 11:42:38 CST 2010
612+eclipse.preferences.version=1
613+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
614+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
615+org.eclipse.jdt.core.compiler.compliance=1.6
616+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
617+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
618+org.eclipse.jdt.core.compiler.source=1.6