001: /*
002: * RemoteShell.java
003: *
004: * Copyright (C) 2000-2004 Peter Graves
005: * $Id: RemoteShell.java,v 1.7 2004/04/13 14:05:33 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.io.OutputStreamWriter;
025: import javax.swing.SwingUtilities;
026:
027: public class RemoteShell extends Shell {
028: private String host;
029:
030: private RemoteShell(int type, String host) {
031: super ();
032: if (type != TYPE_TELNET && type != TYPE_SSH)
033: throw new NotSupportedException();
034: this .type = type;
035: this .host = host;
036: if (type == TYPE_TELNET) {
037: shellCommand = Editor.preferences().getStringProperty(
038: Property.TELNET);
039: if (shellCommand == null)
040: shellCommand = "telnet";
041: } else if (type == TYPE_SSH) {
042: shellCommand = Editor.preferences().getStringProperty(
043: Property.SSH);
044: if (shellCommand == null)
045: shellCommand = "ssh";
046: }
047: title = shellCommand + " " + host;
048: }
049:
050: // Called in Shell constructor, so we override it here.
051: protected void initializeHistory() {
052: history = new History("remoteShell.history");
053: }
054:
055: protected void startProcess() {
056: Process process = null;
057: try {
058: process = Runtime.getRuntime().exec(
059: "jpty " + shellCommand + " " + host);
060: setProcess(process);
061: } catch (Throwable t) {
062: setProcess(null);
063: return;
064: }
065: startWatcherThread();
066: // See if the process exits right away (meaning jpty couldn't launch
067: // the program).
068: try {
069: Thread.sleep(100);
070: } catch (InterruptedException e) {
071: Log.error(e);
072: }
073: // When the process exits, the watcher thread calls setProcess(null),
074: // so check the value of getProcess() here.
075: if (getProcess() == null)
076: return; // Process exited.
077: Property property;
078: switch (type) {
079: case TYPE_TELNET:
080: property = Property.TELNET_PROMPT_PATTERN;
081: break;
082: case TYPE_SSH:
083: property = Property.SSH_PROMPT_PATTERN;
084: break;
085: default:
086: property = null;
087: break;
088: }
089: if (property != null)
090: setPromptRE(Editor.preferences()
091: .getStringProperty(property));
092: try {
093: stdin = new OutputStreamWriter(process.getOutputStream());
094: stdoutThread = new StdoutThread(process.getInputStream());
095: stderrThread = new StderrThread(process.getErrorStream());
096: stdoutThread.start();
097: stderrThread.start();
098: readOnly = false;
099: } catch (Throwable t) {
100: Log.error(t);
101: }
102: }
103:
104: private static RemoteShell createRemoteShell(int type, String host) {
105: RemoteShell remoteShell = new RemoteShell(type, host);
106: remoteShell.startProcess();
107: if (remoteShell.getProcess() == null) {
108: Editor.getBufferList().remove(remoteShell);
109: String program = null;
110: switch (type) {
111: case TYPE_TELNET:
112: program = "telnet";
113: break;
114: case TYPE_SSH:
115: program = "ssh";
116: break;
117: default:
118: program = "client"; // A nice generic name.
119: }
120: String message;
121: if (Utilities.haveJpty())
122: message = "Unable to start " + program + " process";
123: else
124: message = "Unable to start " + program
125: + " process (jpty not found in PATH)";
126: MessageDialog.showMessageDialog(Editor.currentEditor(),
127: message, "Error");
128: remoteShell = null;
129: }
130: return remoteShell;
131: }
132:
133: private static RemoteShell findRemoteShell(int type, String host) {
134: if (host == null)
135: return null;
136: for (BufferIterator it = new BufferIterator(); it.hasNext();) {
137: Buffer buf = it.nextBuffer();
138: if (buf instanceof RemoteShell) {
139: RemoteShell remoteShell = (RemoteShell) buf;
140: if (type == remoteShell.getType())
141: if (host.equals(remoteShell.getHost()))
142: return remoteShell;
143: }
144: }
145: return null;
146: }
147:
148: private StringBuffer sbFilter;
149:
150: private String telnetStdOutFilter(String s) {
151: if (stripEcho && input != null) {
152: if (sbFilter == null)
153: sbFilter = new StringBuffer(s);
154: else {
155: sbFilter.append(s);
156: s = sbFilter.toString();
157: }
158: if (s.startsWith(input)) {
159: s = stripEcho(s);
160: stripEcho = false; // Strip echo only once per command line.
161: sbFilter = null;
162: } else
163: s = ""; // Save output until we have enough to strip echo.
164: }
165: return s;
166: }
167:
168: private String sshStdOutFilter(String s) {
169: if (stripEcho && input != null) {
170: if (s.startsWith(input)) {
171: s = stripEcho(s);
172: stripEcho = false; // Strip echo only once per command line.
173: }
174: }
175: return s;
176: }
177:
178: protected String stdOutFilter(String s) {
179: if (type == TYPE_TELNET)
180: return telnetStdOutFilter(s);
181: if (type == TYPE_SSH)
182: return sshStdOutFilter(s);
183: return s;
184: }
185:
186: private String stripEcho(String s) {
187: if (s.startsWith(input)) {
188: int begin = input.length();
189: if (s.length() > begin && s.charAt(begin) == '\r')
190: ++begin;
191: if (s.length() > begin && s.charAt(begin) == '\n')
192: ++begin;
193: s = s.substring(begin);
194: }
195: return s;
196: }
197:
198: protected void stdOutUpdate(final String s) {
199: // Filter to prevent two carriage returns in a row.
200: final FastStringBuffer sb = new FastStringBuffer(s.length());
201: boolean skipCR = false;
202: final int limit = s.length();
203: for (int i = 0; i < limit; i++) {
204: char c = s.charAt(i);
205: if (c == '\r') {
206: if (skipCR)
207: skipCR = false;
208: else {
209: sb.append(c);
210: skipCR = true;
211: }
212: } else {
213: sb.append(c);
214: skipCR = false;
215: }
216: }
217: Runnable r = new Runnable() {
218: public void run() {
219: appendString(sb.toString());
220: setEndOfOutput(new Position(getEnd()));
221: updateLineFlags();
222: updateDisplayInAllFrames();
223: resetUndo();
224: checkPasswordPrompt();
225: }
226: };
227: SwingUtilities.invokeLater(r);
228: }
229:
230: protected String stdErrFilter(String s) {
231: return s;
232: }
233:
234: private final String getHost() {
235: return host;
236: }
237:
238: public final File getCurrentDirectory() {
239: return Directories.getUserHomeDirectory();
240: }
241:
242: // For the buffer list.
243: public String toString() {
244: return title;
245: }
246:
247: public String getTitle() {
248: return title;
249: }
250:
251: public static void telnet() {
252: if (!Editor.checkExperimental())
253: return;
254: if (Platform.isPlatformWindows()) {
255: if (Editor.preferences().getStringProperty(Property.TELNET) == null)
256: return;
257: }
258: String host = InputDialog.showInputDialog(Editor
259: .currentEditor(), "Host:", "telnet");
260: if (host == null || host.length() == 0)
261: return;
262: telnet(host);
263: }
264:
265: public static void telnet(String host) {
266: if (!Editor.checkExperimental())
267: return;
268: if (Platform.isPlatformWindows()) {
269: if (Editor.preferences().getStringProperty(Property.TELNET) == null)
270: return;
271: }
272: RemoteShell remoteShell = findRemoteShell(TYPE_TELNET, host);
273: if (remoteShell != null) {
274: if (remoteShell.getProcess() == null)
275: remoteShell.startProcess();
276: } else
277: remoteShell = createRemoteShell(TYPE_TELNET, host);
278: if (remoteShell != null) {
279: final Editor editor = Editor.currentEditor();
280: editor.makeNext(remoteShell);
281: editor.switchToBuffer(remoteShell);
282: }
283: }
284:
285: public static void ssh() {
286: if (!Editor.checkExperimental())
287: return;
288: if (Platform.isPlatformWindows()) {
289: if (Editor.preferences().getStringProperty(Property.SSH) == null)
290: return;
291: }
292: String host = InputDialog.showInputDialog(Editor
293: .currentEditor(), "Host:", "ssh");
294: if (host == null || host.length() == 0)
295: return;
296: ssh(host);
297: }
298:
299: public static void ssh(String host) {
300: if (!Editor.checkExperimental())
301: return;
302: if (Platform.isPlatformWindows()) {
303: if (Editor.preferences().getStringProperty(Property.SSH) == null)
304: return;
305: }
306: RemoteShell remoteShell = RemoteShell.findRemoteShell(TYPE_SSH,
307: host);
308: if (remoteShell != null) {
309: if (remoteShell.getProcess() == null)
310: remoteShell.startProcess();
311: } else
312: remoteShell = RemoteShell.createRemoteShell(TYPE_SSH, host);
313: if (remoteShell != null) {
314: final Editor editor = Editor.currentEditor();
315: editor.makeNext(remoteShell);
316: editor.switchToBuffer(remoteShell);
317: }
318: }
319: }
|