PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/EditServer.java

#
Java | 363 lines | 210 code | 39 blank | 114 comment | 29 complexity | 25f5e633b33f472d99ece9f20fe43298 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, 2003 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 bsh.NameSpace;
  25. import javax.swing.SwingUtilities;
  26. import java.io.*;
  27. import java.net.*;
  28. import java.util.Random;
  29. import org.gjt.sp.jedit.io.FileVFS;
  30. import org.gjt.sp.util.Log;
  31. //}}}
  32. /**
  33. * Inter-process communication.<p>
  34. *
  35. * The edit server protocol is very simple. <code>$HOME/.jedit/server</code>
  36. * is an ASCII file containing two lines, the first being the port number,
  37. * the second being the authorization key.<p>
  38. *
  39. * You connect to that port on the local machine, sending the authorization
  40. * key as four bytes in network byte order, followed by the length of the
  41. * BeanShell script as two bytes in network byte order, followed by the
  42. * script in UTF8 encoding. After the socked is closed, the BeanShell script
  43. * will be executed by jEdit.<p>
  44. *
  45. * The snippet is executed in the AWT thread. None of the usual BeanShell
  46. * variables (view, buffer, textArea, editPane) are set so the script has to
  47. * figure things out by itself.<p>
  48. *
  49. * In most cases, the script will call the static
  50. * {@link #handleClient(boolean,String,String[])} method, but of course more
  51. * complicated stuff can be done too.
  52. *
  53. * @author Slava Pestov
  54. * @version $Id: EditServer.java 5053 2004-05-29 01:55:26Z spestov $
  55. */
  56. public class EditServer extends Thread
  57. {
  58. //{{{ EditServer constructor
  59. EditServer(String portFile)
  60. {
  61. super("jEdit server daemon [" + portFile + "]");
  62. setDaemon(true);
  63. this.portFile = portFile;
  64. try
  65. {
  66. // On Unix, set permissions of port file to rw-------,
  67. // so that on broken Unices which give everyone read
  68. // access to user home dirs, people can't see your
  69. // port file (and hence send arbitriary BeanShell code
  70. // your way. Nasty.)
  71. if(OperatingSystem.isUnix())
  72. {
  73. new File(portFile).createNewFile();
  74. FileVFS.setPermissions(portFile,0600);
  75. }
  76. // Bind to any port on localhost; accept 2 simultaneous
  77. // connection attempts before rejecting connections
  78. socket = new ServerSocket(0, 2,
  79. InetAddress.getByName("127.0.0.1"));
  80. authKey = Math.abs(new Random().nextInt());
  81. int port = socket.getLocalPort();
  82. FileWriter out = new FileWriter(portFile);
  83. try
  84. {
  85. out.write("b\n");
  86. out.write(String.valueOf(port));
  87. out.write("\n");
  88. out.write(String.valueOf(authKey));
  89. out.write("\n");
  90. }
  91. finally
  92. {
  93. out.close();
  94. }
  95. ok = true;
  96. Log.log(Log.DEBUG,this,"jEdit server started on port "
  97. + socket.getLocalPort());
  98. Log.log(Log.DEBUG,this,"Authorization key is "
  99. + authKey);
  100. }
  101. catch(IOException io)
  102. {
  103. /* on some Windows versions, connections to localhost
  104. * fail if the network is not running. To avoid
  105. * confusing newbies with weird error messages, log
  106. * errors that occur while starting the server
  107. * as NOTICE, not ERROR */
  108. Log.log(Log.NOTICE,this,io);
  109. }
  110. } //}}}
  111. //{{{ run() method
  112. public void run()
  113. {
  114. for(;;)
  115. {
  116. if(abort)
  117. return;
  118. Socket client = null;
  119. try
  120. {
  121. client = socket.accept();
  122. // Stop script kiddies from opening the edit
  123. // server port and just leaving it open, as a
  124. // DoS
  125. client.setSoTimeout(1000);
  126. Log.log(Log.MESSAGE,this,client + ": connected");
  127. DataInputStream in = new DataInputStream(
  128. client.getInputStream());
  129. OutputStream out = client.getOutputStream();
  130. if(!handleClient(client,in))
  131. abort = true;
  132. }
  133. catch(Exception e)
  134. {
  135. if(!abort)
  136. Log.log(Log.ERROR,this,e);
  137. abort = true;
  138. }
  139. finally
  140. {
  141. /* if(client != null)
  142. {
  143. try
  144. {
  145. client.close();
  146. }
  147. catch(Exception e)
  148. {
  149. Log.log(Log.ERROR,this,e);
  150. }
  151. client = null;
  152. } */
  153. }
  154. }
  155. } //}}}
  156. //{{{ handleClient() method
  157. /**
  158. * @param restore Ignored unless no views are open
  159. * @param parent The client's parent directory
  160. * @param args A list of files. Null entries are ignored, for convinience
  161. * @since jEdit 3.2pre7
  162. */
  163. public static void handleClient(boolean restore, String parent,
  164. String[] args)
  165. {
  166. handleClient(restore,false,false,parent,args);
  167. } //}}}
  168. //{{{ handleClient() method
  169. /**
  170. * @param restore Ignored unless no views are open
  171. * @param newView Open a new view?
  172. * @param newPlainView Open a new plain view?
  173. * @param parent The client's parent directory
  174. * @param args A list of files. Null entries are ignored, for convinience
  175. * @since jEdit 4.2pre1
  176. */
  177. public static Buffer handleClient(boolean restore,
  178. boolean newView, boolean newPlainView, String parent,
  179. String[] args)
  180. {
  181. // we have to deal with a huge range of possible border cases here.
  182. if(jEdit.getFirstView() == null)
  183. {
  184. // coming out of background mode.
  185. // no views open.
  186. // no buffers open if args empty.
  187. Buffer buffer = jEdit.openFiles(null,parent,args);
  188. boolean restoreFiles = restore && jEdit.getBooleanProperty("restore")
  189. && (buffer == null || jEdit.getBooleanProperty("restore.cli"));
  190. View view = PerspectiveManager.loadPerspective(restoreFiles);
  191. if(view == null)
  192. {
  193. if(buffer == null)
  194. buffer = jEdit.getFirstBuffer();
  195. view = jEdit.newView(null,buffer);
  196. }
  197. else if(buffer != null)
  198. view.setBuffer(buffer);
  199. return buffer;
  200. }
  201. else if(newPlainView)
  202. {
  203. // no background mode, and opening a new view
  204. Buffer buffer = jEdit.openFiles(null,parent,args);
  205. if(buffer == null)
  206. buffer = jEdit.getFirstBuffer();
  207. jEdit.newView(null,buffer,true);
  208. return buffer;
  209. }
  210. else if(newView)
  211. {
  212. // no background mode, and opening a new view
  213. Buffer buffer = jEdit.openFiles(null,parent,args);
  214. if(buffer == null)
  215. buffer = jEdit.getFirstBuffer();
  216. jEdit.newView(jEdit.getActiveView(),buffer,false);
  217. return buffer;
  218. }
  219. else
  220. {
  221. // no background mode, and reusing existing view
  222. View view = jEdit.getActiveView();
  223. Buffer buffer = jEdit.openFiles(view,parent,args);
  224. // Hack done to fix bringing the window to the front.
  225. // At least on windows, Frame.toFront() doesn't cut it.
  226. // Remove the isWindows check if it's broken under other
  227. // OSes too.
  228. if (jEdit.getBooleanProperty("server.brokenToFront"))
  229. view.setState(java.awt.Frame.ICONIFIED);
  230. // un-iconify using JDK 1.3 API
  231. view.setState(java.awt.Frame.NORMAL);
  232. view.requestFocus();
  233. view.toFront();
  234. return buffer;
  235. }
  236. } //}}}
  237. //{{{ isOK() method
  238. boolean isOK()
  239. {
  240. return ok;
  241. } //}}}
  242. //{{{ getPort method
  243. public int getPort()
  244. {
  245. return socket.getLocalPort();
  246. } //}}}
  247. //{{{ stopServer() method
  248. void stopServer()
  249. {
  250. abort = true;
  251. try
  252. {
  253. socket.close();
  254. }
  255. catch(IOException io)
  256. {
  257. }
  258. new File(portFile).delete();
  259. } //}}}
  260. //{{{ Private members
  261. //{{{ Instance variables
  262. private String portFile;
  263. private ServerSocket socket;
  264. private int authKey;
  265. private boolean ok;
  266. private boolean abort;
  267. //}}}
  268. //{{{ handleClient() method
  269. private boolean handleClient(final Socket client, DataInputStream in)
  270. throws Exception
  271. {
  272. int key = in.readInt();
  273. if(key != authKey)
  274. {
  275. Log.log(Log.ERROR,this,client + ": wrong"
  276. + " authorization key (got " + key
  277. + ", expected " + authKey + ")");
  278. in.close();
  279. client.close();
  280. return false;
  281. }
  282. else
  283. {
  284. // Reset the timeout
  285. client.setSoTimeout(0);
  286. Log.log(Log.DEBUG,this,client + ": authenticated"
  287. + " successfully");
  288. final String script = in.readUTF();
  289. Log.log(Log.DEBUG,this,script);
  290. SwingUtilities.invokeLater(new Runnable()
  291. {
  292. public void run()
  293. {
  294. try
  295. {
  296. NameSpace ns = new NameSpace(
  297. BeanShell.getNameSpace(),
  298. "EditServer namespace");
  299. ns.setVariable("socket",client);
  300. BeanShell.eval(null,ns,script);
  301. }
  302. catch(bsh.UtilEvalError e)
  303. {
  304. Log.log(Log.ERROR,this,e);
  305. }
  306. finally
  307. {
  308. try
  309. {
  310. BeanShell.getNameSpace().setVariable("socket",null);
  311. }
  312. catch(bsh.UtilEvalError e)
  313. {
  314. Log.log(Log.ERROR,this,e);
  315. }
  316. }
  317. }
  318. });
  319. return true;
  320. }
  321. } //}}}
  322. //}}}
  323. }