PageRenderTime 28ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/EditServer.java

#
Java | 297 lines | 168 code | 38 blank | 91 comment | 27 complexity | 42acf7c73c7bfa429903f40482ffcd3a MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * EditServer.java - jEdit server
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000, 2001, 2002 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import javax.swing.SwingUtilities;
  25. import java.io.*;
  26. import java.net.*;
  27. import java.util.Random;
  28. import org.gjt.sp.jedit.io.FileVFS;
  29. import org.gjt.sp.util.Log;
  30. //}}}
  31. /**
  32. * The edit server protocol is very simple. <code>$HOME/.jedit/server</code>
  33. * is an ASCII file containing two lines, the first being the port number,
  34. * the second being the authorization key.<p>
  35. *
  36. * You connect to that port on the local machine, sending the authorization
  37. * key as four bytes in network byte order, followed by the length of the
  38. * BeanShell script as two bytes in network byte order, followed by the
  39. * script in UTF8 encoding. After the socked is closed, the BeanShell script
  40. * will be executed by jEdit.<p>
  41. *
  42. * The snippet is executed in the AWT thread. None of the usual BeanShell
  43. * variables (view, buffer, textArea, editPane) are set so the script has to
  44. * figure things out by itself.<p>
  45. *
  46. * In most cases, the script will call the static
  47. * <code>EditServer.handleClient()</code> method, but of course more
  48. * complicated stuff can be done too.
  49. *
  50. * @author Slava Pestov
  51. * @version $Id: EditServer.java 4169 2002-05-19 03:34:01Z spestov $
  52. */
  53. public class EditServer extends Thread
  54. {
  55. //{{{ EditServer constructor
  56. EditServer(String portFile)
  57. {
  58. super("jEdit server daemon [" + portFile + "]");
  59. setDaemon(true);
  60. this.portFile = portFile;
  61. try
  62. {
  63. // On Unix, set permissions of port file to rw-------,
  64. // so that on broken Unices which give everyone read
  65. // access to user home dirs, people can't see your
  66. // port file (and hence send arbitriary BeanShell code
  67. // your way. Nasty.)
  68. if(OperatingSystem.isUnix())
  69. {
  70. new File(portFile).createNewFile();
  71. FileVFS.setPermissions(portFile,0600);
  72. }
  73. // Bind to any port on localhost; accept 2 simultaneous
  74. // connection attempts before rejecting connections
  75. socket = new ServerSocket(0, 2,
  76. InetAddress.getByName("127.0.0.1"));
  77. authKey = Math.abs(new Random().nextInt());
  78. int port = socket.getLocalPort();
  79. FileWriter out = new FileWriter(portFile);
  80. out.write("b\n");
  81. out.write(String.valueOf(port));
  82. out.write("\n");
  83. out.write(String.valueOf(authKey));
  84. out.write("\n");
  85. out.close();
  86. Log.log(Log.DEBUG,this,"jEdit server started on port "
  87. + socket.getLocalPort());
  88. Log.log(Log.DEBUG,this,"Authorization key is "
  89. + authKey);
  90. ok = true;
  91. }
  92. catch(IOException io)
  93. {
  94. /* on some Windows versions, connections to localhost
  95. * fail if the network is not running. To avoid
  96. * confusing newbies with weird error messages, log
  97. * errors that occur while starting the server
  98. * as NOTICE, not ERROR */
  99. Log.log(Log.NOTICE,this,io);
  100. }
  101. } //}}}
  102. //{{{ isOK() method
  103. public boolean isOK()
  104. {
  105. return ok;
  106. } //}}}
  107. //{{{ run() method
  108. public void run()
  109. {
  110. boolean abort = false;
  111. for(;;)
  112. {
  113. if(abort)
  114. return;
  115. Socket client = null;
  116. try
  117. {
  118. client = socket.accept();
  119. // Stop script kiddies from opening the edit
  120. // server port and just leaving it open, as a
  121. // DoS
  122. client.setSoTimeout(1000);
  123. Log.log(Log.MESSAGE,this,client + ": connected");
  124. DataInputStream in = new DataInputStream(
  125. client.getInputStream());
  126. if(!handleClient(client,in))
  127. abort = true;
  128. }
  129. catch(Exception e)
  130. {
  131. Log.log(Log.ERROR,this,e);
  132. abort = true;
  133. }
  134. finally
  135. {
  136. if(client != null)
  137. {
  138. try
  139. {
  140. client.close();
  141. }
  142. catch(Exception e)
  143. {
  144. Log.log(Log.ERROR,this,e);
  145. }
  146. client = null;
  147. }
  148. }
  149. }
  150. } //}}}
  151. //{{{ handleClient() method
  152. /**
  153. * @param restore Ignored unless no views are open
  154. * @param parent The client's parent directory
  155. * @param args A list of files. Null entries are ignored, for convinience
  156. * @since jEdit 3.2pre7
  157. */
  158. public static void handleClient(boolean restore, String parent,
  159. String[] args)
  160. {
  161. String splitConfig = null;
  162. boolean newView = jEdit.getBooleanProperty("client.newView");
  163. // we have to deal with a huge range of possible border cases here.
  164. if(jEdit.getFirstView() == null || newView)
  165. {
  166. // coming out of background mode.
  167. // no views open.
  168. // no buffers open if args empty.
  169. Buffer buffer = jEdit.openFiles(null,parent,args);
  170. if(restore)
  171. {
  172. if(jEdit.getFirstBuffer() == null
  173. || (jEdit.getFirstBuffer().isUntitled()
  174. && jEdit.getBufferCount() == 1))
  175. splitConfig = jEdit.restoreOpenFiles();
  176. else if(jEdit.getBooleanProperty("restore.cli"))
  177. {
  178. // no initial split config
  179. jEdit.restoreOpenFiles();
  180. }
  181. }
  182. // if session file is empty or -norestore specified,
  183. // we need an initial buffer
  184. if(jEdit.getFirstBuffer() == null
  185. || (jEdit.getFirstBuffer().isUntitled()
  186. && jEdit.getBufferCount() == 1))
  187. buffer = jEdit.newFile(null);
  188. if(splitConfig != null)
  189. jEdit.newView(null,splitConfig);
  190. else
  191. jEdit.newView(null,buffer);
  192. }
  193. else
  194. {
  195. // no background mode, and reusing existing view
  196. View view = jEdit.getFirstView();
  197. jEdit.openFiles(view,parent,args);
  198. // Hack done to fix bringing the window to the front.
  199. // At least on windows, Frame.toFront() doesn't cut it.
  200. // Remove the isWindows check if it's broken under other
  201. // OSes too.
  202. if (OperatingSystem.isWindows())
  203. view.setState(java.awt.Frame.ICONIFIED);
  204. // un-iconify using JDK 1.3 API
  205. view.setState(java.awt.Frame.NORMAL);
  206. view.requestFocus();
  207. view.toFront();
  208. // do not create a new view
  209. return;
  210. }
  211. } //}}}
  212. // stopServer() method
  213. void stopServer()
  214. {
  215. stop();
  216. new File(portFile).delete();
  217. } //}}}
  218. //{{{ Private members
  219. //{{{ Instance variables
  220. private String portFile;
  221. private ServerSocket socket;
  222. private int authKey;
  223. private boolean ok;
  224. //}}}
  225. //{{{ handleClient() method
  226. private boolean handleClient(Socket client, DataInputStream in)
  227. throws Exception
  228. {
  229. int key = in.readInt();
  230. if(key != authKey)
  231. {
  232. Log.log(Log.ERROR,this,client + ": wrong"
  233. + " authorization key (got " + key
  234. + ", expected " + authKey + ")");
  235. in.close();
  236. client.close();
  237. return false;
  238. }
  239. else
  240. {
  241. // Reset the timeout
  242. client.setSoTimeout(0);
  243. Log.log(Log.DEBUG,this,client + ": authenticated"
  244. + " successfully");
  245. final String script = in.readUTF();
  246. Log.log(Log.DEBUG,this,script);
  247. SwingUtilities.invokeLater(new Runnable()
  248. {
  249. public void run()
  250. {
  251. BeanShell.eval(null,BeanShell.getNameSpace(),
  252. script);
  253. }
  254. });
  255. return true;
  256. }
  257. } //}}}
  258. //}}}
  259. }