1   // joi/10/juno/RemoteConsole.java                         
2   //                                                            
3   //                                                            
4   // Copyright 2003 Bill Campbell and Ethan Bolker                         
5                                                               
6   import java.io.*;
7   import java.net.*;
8   import java.util.*;
9   import java.text.*;
10  
11  /**
12   * A remote console listens on a port for a remote login to
13   * a running Juno system server. 
14   *
15   * @version 10
16   */
17  
18  public class RemoteConsole extends Thread 
19      implements OutputInterface, InputInterface 
20  {
21      // default just logs connection start and end
22      // change to true to log all i/o
23      private static boolean logall = false;
24  
25      private Juno system;
26      private boolean echo;
27      private InterpreterInterface interpreter;
28  
29      private Socket clientSocket;  
30      private BufferedReader in;
31      private PrintWriter out;
32      private int sessionCount = 0;
33  
34      private PrintWriter junoLog;
35  
36      /**
37       * Construct a remote console to listen for users trying
38       * to connect to Juno. 
39       *
40       * Called from Juno main.
41       *
42       * @param system the Juno system setting up this console.
43       * @param echo whether or not input should be echoed.
44       * @param port the port on which to listen for requests.
45       */
46  
47      public RemoteConsole( Juno system, boolean echo, int port ) 
48      {
49          this.echo = echo;
50          Date now  = new Date(); 
51          junoLog   = openlog(now);
52          log("*** Juno server started " + now + "\n");
53          try {
54              ServerSocket ss = new ServerSocket(port);
55              while (true) {
56                  clientSocket = ss.accept(); 
57                  new RemoteConsole( system, echo, clientSocket,
58                                     junoLog, ++sessionCount).start();
59              }
60          }
61          catch (IOException e) {
62              System.out.println("Remote login not supported");
63              System.exit(0);
64          }
65          finally {
66              system.shutDown();
67          }
68      }
69  
70      /** 
71       * Construct a remote console for a single remote user.
72       *
73       * @param system the Juno system to which the user is connecting.
74       * @param echo whether or not input should be echoed.
75       * @param clientSocket the socket for the user's connection
76       * @param junoLog track all user i/o
77       * @param sessionCount this session's number 
78       */
79  
80      public RemoteConsole( Juno system, boolean echo, Socket clientSocket, 
81                            PrintWriter junoLog, int sessionCount ) 
82      {
83          this.system = system;
84          this.echo = echo;
85          this.clientSocket = clientSocket;
86          this.junoLog = junoLog;
87          this.sessionCount = sessionCount;
88      }
89  
90      /**
91       * Action when the thread for this session starts.
92       */
93  
94      public void run() 
95      {
96          log("*** " + sessionCount + ", " +
97              clientSocket.getInetAddress()  + ", "  +
98              new Date());
99          try {
100             setUpConnection();
101             String s = this.readLine
102                 ("Please sign the guest book (name, email): ");
103             this.println("Thanks, " + s);       
104             if (!logall) {
105                 log("guest book: " + s);
106             }
107             new LoginInterpreter( system, this ).CLILogin();
108             clientSocket.close();
109         }
110         catch (IOException e) {
111             log("*** Error " + e);
112         }
113         log("*** end session " + sessionCount); 
114     }
115 
116     /**
117      * Create the readers and writers for the socket 
118      * for this session.
119      */
120 
121     private void setUpConnection() 
122          throws IOException 
123     {
124         in = new BufferedReader(
125                 new InputStreamReader(clientSocket.getInputStream()));
126         out = new PrintWriter(
127                 new OutputStreamWriter(clientSocket.getOutputStream()));
128     }
129     
130     // implement the InputInterface
131 
132    /**
133     * Read a line (terminated by a newline) from console socket.
134     *
135     * Log the input line before returning it if required.  
136     *
137     * @param promptString output string to prompt for input
138     * @return the string (without the newline character)
139     */
140     
141     public String readLine( String promptString ) 
142     {
143         String s = "";
144         this.print(promptString);
145         out.flush();
146         try {
147             s = in.readLine();
148             if (logall) { 
149                 log("> " + s);
150             }
151             if (echo) {
152                 out.println(s);
153             }
154         }
155         catch (IOException e) {
156             String msg = "IO error reading from remote console";
157             System.out.println(msg);
158             out.println(msg);
159         }
160         return s;
161     }
162 
163     /**
164      * Write a String to console socket.
165      *
166      * Log the output if required.  
167      *
168      * @param str - the string to write
169      */
170 
171     public void print( String str ) 
172     {
173         out.print( str );
174         out.flush();
175         if (logall) {
176             log("< " + str + "\\");
177         }
178     }
179 
180     // implement the OutputInterface
181 
182     /**
183      * Write a String followed by a newline
184      * to console socket.
185      *
186      * Log the output if required.  
187      *
188      * @param str - the string to write
189      */
190 
191     public void println( String str ) 
192     {
193         out.println( str + '\r' );
194         out.flush();
195         if (logall) {
196             log("< " + str);
197         }
198     }
199 
200     /**
201      * Write a String followed by a newline
202      * to console error output location. That's
203      * just the socket.
204      *
205      * @param str - the String to write
206      */
207 
208     public void errPrintln(String str ) 
209     {
210         println( str );
211     }
212 
213     /**
214      * Query what kind of console this is.
215      *
216      * @return false since it's not a GUI.
217      */
218 
219     public boolean isGUI() 
220     {
221         return false;
222     }
223 
224     /**
225      * Query what kind of console this is.
226      *
227      * @return true since it is remote.
228      */
229 
230     public boolean isRemote() 
231     {
232         return true;
233     }
234 
235     /**
236      * Query what kind of console this is.
237      *
238      * @return true if and only if echoing input.
239      */
240 
241     public boolean isEchoInput() 
242     {
243         return echo;
244     }
245 
246     /**
247      * Log a String.
248      *
249      * @param str the String to log.
250      */
251 
252     private void log(String str) 
253     {
254         junoLog.println(sessionCount + ": " + str);
255         junoLog.flush();
256     }
257 
258     /**
259      * Open a log for this console.
260      *
261      * @param now the current Date.
262      */
263 
264     private PrintWriter openlog(Date now) 
265     {
266         PrintWriter out = null;
267         SimpleDateFormat formatter
268             = new SimpleDateFormat ("MMM.dd:hh:mm:ss");
269         String dateString = formatter.format(now);
270         String filename = "log-" + dateString;
271         try { out = new PrintWriter(
272                     new BufferedWriter(
273                     new FileWriter(filename)));
274         }
275         catch (Exception e) {
276             out = new PrintWriter(new FileWriter(FileDescriptor.out));
277         }
278         return out;
279     }
280 }             
281