From: "Juanma Barranquero" <lekktu@gmail.com>
Subject: Re: Back to emacsclient/server
Date: Fri, 27 Oct 2006 02:27:09 +0200 [thread overview]
Message-ID: <f7ccd24b0610261727t1cf8a448v36eb641348fdad1c@mail.gmail.com> (raw)
In-Reply-To: <f7ccd24b0610240139x7a5a0807n4efe09b41e573f5b@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1982 bytes --]
OK, there's a rough first cut at the emacsclient patch (attached in
context and unified diffs, for easier reading). No doc patches nor
ChangeLogs, yet.
Notes:
- Should `server-ensure-safe-dir' be used also to create/check
safety of the `server-auth-dir' directory (by default at
~/.emacs.d/server)? If so, `server-ensure-safe-dir' must be changed to
create directories in the path (because `server-auth-dir', unlike
`server-socket-dir', can be customized by the user, and so it can be
at any depth). I've implemented this (by passing the PARENTS arg to
`make-directory'), but I'm not sure that's the right way,
security-wise.
- Also, I've patched `server-ensure-safe-dir' to ignore Unix-style
file permissions in Windows (checking ACLs would be useful, but I
don't know whether that's possible from Emacs).
- emasclient.c compiles and works fine with MinGW 3.4.5; I'll try to
test it with MSVC once the code/features settle.
- With an eye to porting it to MSVC, I've changed the code to use
send/recv instead of streams (it'll be easier to maintain
compatibility, I believe). The Unix sockets code should work OK, but I
don't really know, so please test it.
- I haven't tried compiling on GNU/Linux or Unix, so there could be
typos or oversights, which should be trivial to fix.
- There's a new argument --server-file. If --server-file (or
environment variable EMACS_SERVER_FILE) exist, emacsclient uses TCP
sockets, else it uses Unix sockets (either --socket-name, or "emacs"
by default).
- The only major thing missing is interpreting
--server-file=SERVERNAME as ~/.emacs.d/server/SERVERNAME (currently,
you've got to pass the full path). What would be the easier portable
way to find the user directory? The $HOME (or %HOME in Windows) env
var?
I'd be glad if people could try the patch, with stress on testing on
non-Windows environments and non-TCP sockets (I want to be sure I'm
not breaking anything).
Comments welcome.
/L/e/k/t/u
[-- Attachment #2: newserver-c.patch --]
[-- Type: application/octet-stream, Size: 30313 bytes --]
Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.113
diff -b -c -2 -r1.113 server.el
*** lisp/server.el 6 Jul 2006 22:48:16 -0000 1.113
--- lisp/server.el 26 Oct 2006 23:06:08 -0000
***************
*** 83,86 ****
--- 83,115 ----
:group 'external)
+ (defcustom server-use-tcp nil
+ "If non-nil, use TCP sockets instead of local sockets."
+ :set #'(lambda (sym val)
+ (if (featurep 'make-network-process '(:family local))
+ (set-default sym val)
+ (unless load-in-progress
+ (message "Local sockets unsupported, using TCP sockets"))
+ (set-default sym t)))
+ :group 'server
+ :type 'boolean
+ :version "22.1")
+
+ (defcustom server-host nil
+ "The name or IP address to use as host address of the server process.
+ If set, the server accepts remote connections; otherwise it is local."
+ :group 'server
+ :type '(choice
+ (string :tag "Name or IP address")
+ (const :tag "Local" nil))
+ :version "22.1")
+ (put 'server-host 'risky-local-variable t)
+
+ (defcustom server-auth-dir "~/.emacs.d/server/"
+ "Directory for server authentication files."
+ :group 'server
+ :type 'directory
+ :version "22.1")
+ (put 'server-auth-dir 'risky-local-variable t)
+
(defcustom server-visit-hook nil
"*Hook run when visiting a file for the Emacs server."
***************
*** 101,104 ****
--- 130,136 ----
"The current server process.")
+ (defvar server-auth-string nil
+ "The current server authentication string.")
+
(defvar server-clients nil
"List of current server clients.
***************
*** 232,242 ****
(let ((attrs (file-attributes dir)))
(unless attrs
! (letf (((default-file-modes) ?\700)) (make-directory dir))
(setq attrs (file-attributes dir)))
;; Check that it's safe for use.
(unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
! (zerop (logand ?\077 (file-modes dir))))
(error "The directory %s is unsafe" dir))))
;;;###autoload
(defun server-start (&optional leave-dead)
--- 264,285 ----
(let ((attrs (file-attributes dir)))
(unless attrs
! (letf (((default-file-modes) ?\700)) (make-directory dir t))
(setq attrs (file-attributes dir)))
;; Check that it's safe for use.
(unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
! (or (eq system-type 'windows-nt)
! (zerop (logand ?\077 (file-modes dir)))))
(error "The directory %s is unsafe" dir))))
+ (defun server-auth-string ()
+ (or server-auth-string
+ ;; If the authentication string does not exist, create it on the fly:
+ ;; it's a 64-byte string of random chars in the range `!'..`~'.
+ (setq server-auth-string
+ (loop
+ for i below 64
+ collect (+ 33 (random 94)) into auth
+ finally return (concat auth)))))
+
;;;###autoload
(defun server-start (&optional leave-dead)
***************
*** 249,259 ****
Prefix arg means just kill any existing server communications subprocess."
(interactive "P")
;; kill it dead!
! (if server-process
! (condition-case () (delete-process server-process) (error nil)))
! ;; Delete the socket files made by previous server invocations.
! (condition-case ()
(delete-file (expand-file-name server-name server-socket-dir))
! (error nil))
;; If this Emacs already had a server, clear out associated status.
(while server-clients
--- 292,304 ----
Prefix arg means just kill any existing server communications subprocess."
(interactive "P")
+ (when server-process
;; kill it dead!
! (ignore-errors (delete-process server-process))
! (ignore-errors
! ;; Delete the socket or authentication files made by previous server invocations.
! (if (eq (process-contact server-process :family) 'local)
(delete-file (expand-file-name server-name server-socket-dir))
! (setq server-auth-string nil)
! (delete-file (expand-file-name server-name server-auth-dir)))))
;; If this Emacs already had a server, clear out associated status.
(while server-clients
***************
*** 263,279 ****
(unless leave-dead
;; Make sure there is a safe directory in which to place the socket.
! (server-ensure-safe-dir server-socket-dir)
! (if server-process
(server-log (message "Restarting server")))
(letf (((default-file-modes) ?\700))
(setq server-process
! (make-network-process
! :name "server" :family 'local :server t :noquery t
! :service (expand-file-name server-name server-socket-dir)
! :sentinel 'server-sentinel :filter 'server-process-filter
;; We must receive file names without being decoded.
;; Those are decoded by server-process-filter according
;; to file-name-coding-system.
! :coding 'raw-text)))))
;;;###autoload
--- 308,342 ----
(unless leave-dead
;; Make sure there is a safe directory in which to place the socket.
! (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
! (when server-process
(server-log (message "Restarting server")))
(letf (((default-file-modes) ?\700))
(setq server-process
! (apply #'make-network-process
! :name server-name
! :server t
! :noquery t
! :sentinel 'server-sentinel
! :filter 'server-process-filter
;; We must receive file names without being decoded.
;; Those are decoded by server-process-filter according
;; to file-name-coding-system.
! :coding 'raw-text
! ;; The rest of the arguments depend on the kind of socket used
! (if server-use-tcp
! (list :family nil
! :service t
! :host (or server-host 'local)
! :plist '(:authenticated nil))
! (list :family 'local
! :service (expand-file-name server-name server-socket-dir)
! :plist '(:authenticated t))))))
! (unless server-process (error "Could not start server process"))
! (when server-use-tcp
! (with-temp-file (expand-file-name server-name server-auth-dir)
! (set-buffer-multibyte nil)
! (setq buffer-file-coding-system 'no-conversion)
! (insert (format-network-address (process-contact server-process :local))
! "\n" (server-auth-string))))))
;;;###autoload
***************
*** 290,301 ****
(server-start (not server-mode)))
\f
! (defun server-process-filter (proc string)
"Process a request from the server to edit some files.
PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
(server-log string proc)
! (let ((prev (process-get proc 'previous-string)))
(when prev
(setq string (concat prev string))
! (process-put proc 'previous-string nil)))
;; If the input is multiple lines,
;; process each line individually.
--- 353,375 ----
(server-start (not server-mode)))
\f
! (defun* server-process-filter (proc string)
"Process a request from the server to edit some files.
PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
+ ;; First things first: let's check the authentication
+ (unless (process-get proc :authenticated)
+ (if (and (string-match "-auth \\(.*?\\)\n" string)
+ (string= (match-string 1 string) server-auth-string))
+ (progn
+ (setq string (substring string (match-end 0)))
+ (process-put proc :authenticated t)
+ (server-log "Authentication successful" proc))
+ (server-log "Authentication failed" proc)
+ (delete-process proc)
+ (return-from server-process-filter)))
(server-log string proc)
! (let ((prev (process-get proc :previous-string)))
(when prev
(setq string (concat prev string))
! (process-put proc :previous-string nil)))
;; If the input is multiple lines,
;; process each line individually.
***************
*** 390,394 ****
;; Save for later any partial line that remains.
(when (> (length string) 0)
! (process-put proc 'previous-string string)))
(defun server-goto-line-column (file-line-col)
--- 464,468 ----
;; Save for later any partial line that remains.
(when (> (length string) 0)
! (process-put proc :previous-string string)))
(defun server-goto-line-column (file-line-col)
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.77
diff -b -c -2 -r1.77 emacsclient.c
*** lib-src/emacsclient.c 18 Jul 2006 16:33:45 -0000 1.77
--- lib-src/emacsclient.c 27 Oct 2006 00:06:01 -0000
***************
*** 27,35 ****
#endif
#undef signal
#include <ctype.h>
#include <stdio.h>
! #include <getopt.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
--- 27,40 ----
#endif
+ #ifdef WINDOWSNT
+ #define HAVE_SOCKETS
+ #define NO_SOCKETS_IN_FILE_SYSTEM
+ #endif
+
#undef signal
#include <ctype.h>
#include <stdio.h>
! #include "getopt.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
***************
*** 38,43 ****
#ifdef VMS
# include "vms-pwd.h"
! #else
# include <pwd.h>
#endif /* not VMS */
--- 43,52 ----
#ifdef VMS
# include "vms-pwd.h"
! #else /* not VMS */
! #ifdef WINDOWSNT
! # include <io.h>
! #else /* not WINDOWSNT */
# include <pwd.h>
+ #endif /* not WINDOWSNT */
#endif /* not VMS */
***************
*** 49,52 ****
--- 58,76 ----
#endif
+ #define SEND_STRING(data) (send_to_emacs (s, (data)))
+ #define SEND_QUOTED(data) (quote_file_name (s, (data)))
+
+ #ifndef EXIT_SUCCESS
+ #define EXIT_SUCCESS 0
+ #endif
+
+ #ifndef EXIT_FAILURE
+ #define EXIT_FAILURE 1
+ #endif
+
+ #ifndef NO_RETURN
+ #define NO_RETURN
+ #endif
+ \f
/* Name used to invoke this program. */
char *progname;
***************
*** 68,71 ****
--- 92,98 ----
char *socket_name = NULL;
+ /* If non-NULL, the filename of the authentication file. */
+ char *server_file = NULL;
+
void print_help_and_exit () NO_RETURN;
***************
*** 78,81 ****
--- 105,109 ----
{ "alternate-editor", required_argument, NULL, 'a' },
{ "socket-name", required_argument, NULL, 's' },
+ { "server-file", required_argument, NULL, 'f' },
{ "display", required_argument, NULL, 'd' },
{ 0, 0, 0, 0 }
***************
*** 91,99 ****
{
alternate_editor = getenv ("ALTERNATE_EDITOR");
while (1)
{
int opt = getopt_long (argc, argv,
! "VHnea:s:d:", longopts, 0);
if (opt == EOF)
--- 119,128 ----
{
alternate_editor = getenv ("ALTERNATE_EDITOR");
+ server_file = getenv ("EMACS_SERVER_FILE");
while (1)
{
int opt = getopt_long (argc, argv,
! "VHnea:s:f:d:", longopts, 0);
if (opt == EOF)
***************
*** 115,118 ****
--- 144,151 ----
break;
+ case 'f':
+ server_file = optarg;
+ break;
+
case 'd':
display = optarg;
***************
*** 158,163 ****
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY Visit the file in the given display\n\
! -s, --socket-name=FILENAME\n\
Set the filename of the UNIX socket for communication\n\
-a, --alternate-editor=EDITOR\n\
Editor to fallback to if the server is not running\n\
--- 191,202 ----
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY Visit the file in the given display\n\
! "
! #ifndef NO_SOCKETS_IN_FILE_SYSTEM
! "-s, --socket-name=FILENAME\n\
Set the filename of the UNIX socket for communication\n\
+ "
+ #endif
+ "-f, --server-file=FILENAME\n\
+ Set the filename of the TCP configuration file\n\
-a, --alternate-editor=EDITOR\n\
Editor to fallback to if the server is not running\n\
***************
*** 167,178 ****
}
/* In NAME, insert a & before each &, each space, each newline, and
any initial -. Change spaces to underscores, too, so that the
return value never contains a space. */
-
void
! quote_file_name (name, stream)
char *name;
- FILE *stream;
{
char *copy = (char *) malloc (strlen (name) * 2 + 1);
--- 206,313 ----
}
+ \f
+ /*
+ Try to run a different command, or --if no alternate editor is
+ defined-- exit with an errorcode.
+ */
+ void
+ fail (argc, argv)
+ int argc;
+ char **argv;
+ {
+ if (alternate_editor)
+ {
+ int i = optind - 1;
+ execvp (alternate_editor, argv + i);
+ return;
+ }
+ else
+ {
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ \f
+ #if !defined (HAVE_SOCKETS)
+
+ int
+ main (argc, argv)
+ int argc;
+ char **argv;
+ {
+ fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
+ argv[0]);
+ fprintf (stderr, "on systems with Berkeley sockets.\n");
+
+ fail (argc, argv);
+ }
+
+ #else /* HAVE_SOCKETS */
+
+ #define AUTH_STRING_LENGTH 64
+ #define SEND_BUFFER_SIZE 4096
+
+ #ifdef WINDOWSNT
+ # include <winsock2.h>
+ #else
+ # include <sys/types.h>
+ # include <sys/socket.h>
+ # include <sys/un.h>
+ # include <sys/stat.h>
+ # include <errno.h>
+ #endif
+
+ extern char *strerror ();
+ extern int errno;
+
+ /* Buffer to accumulate data to send in TCP connections. */
+ char send_buffer[SEND_BUFFER_SIZE + 1];
+ int sblen = 0; /* Fill pointer for the send buffer. */
+
+ /* Let's send the data to Emacs when either
+ - the data ends in "\n", or
+ - the buffer is full (but this shouldn't happen)
+ Otherwise, we just accumulate it. */
+ void send_to_emacs (s, data)
+ SOCKET s;
+ char *data;
+ {
+ while (data)
+ {
+ int dlen = strlen (data);
+ if (dlen + sblen >= SEND_BUFFER_SIZE)
+ {
+ int part = SEND_BUFFER_SIZE - sblen;
+ strncpy (&send_buffer[sblen], data, part);
+ data += part;
+ sblen = SEND_BUFFER_SIZE;
+ }
+ else if (dlen)
+ {
+ strcpy (&send_buffer[sblen], data);
+ data = NULL;
+ sblen += dlen;
+ }
+ else
+ break;
+
+ if (sblen == SEND_BUFFER_SIZE
+ || (sblen > 0 && send_buffer[sblen-1] == '\n'))
+ {
+ int sent = send (s, send_buffer, sblen, 0);
+ if (sent != sblen)
+ strcpy (send_buffer, &send_buffer[sent]);
+ sblen -= sent;
+ }
+ }
+ }
+
/* In NAME, insert a & before each &, each space, each newline, and
any initial -. Change spaces to underscores, too, so that the
return value never contains a space. */
void
! quote_file_name (s, name)
! SOCKET s;
char *name;
{
char *copy = (char *) malloc (strlen (name) * 2 + 1);
***************
*** 204,274 ****
*q++ = 0;
! fprintf (stream, "%s", copy);
free (copy);
}
! /* Like malloc but get fatal error if memory is exhausted. */
! long *
! xmalloc (size)
! unsigned int size;
{
! long *result = (long *) malloc (size);
! if (result == NULL)
{
! perror ("malloc");
exit (EXIT_FAILURE);
}
! return result;
}
\f
/*
! Try to run a different command, or --if no alternate editor is
! defined-- exit with an errorcode.
*/
! void
! fail (argc, argv)
! int argc;
! char **argv;
{
! if (alternate_editor)
{
! int i = optind - 1;
! execvp (alternate_editor, argv + i);
! return;
}
else
{
exit (EXIT_FAILURE);
}
- }
\f
! #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
! int
! main (argc, argv)
! int argc;
! char **argv;
{
! fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
! argv[0]);
! fprintf (stderr, "on systems with Berkeley sockets.\n");
! fail (argc, argv);
! }
! #else /* HAVE_SOCKETS */
! #include <sys/types.h>
! #include <sys/socket.h>
! #include <sys/un.h>
! #include <sys/stat.h>
! #include <errno.h>
! extern char *strerror ();
! extern int errno;
/* Three possibilities:
--- 339,463 ----
*q++ = 0;
! SEND_STRING (copy);
free (copy);
}
! #ifdef WINDOWSNT
! /* Wrapper to make WSACleanup a cdecl, as required by atexit(). */
! void close_winsock ()
! {
! WSACleanup ();
! }
! #endif /* WINDOWSNT */
! void initialize_sockets ()
{
! #ifdef WINDOWSNT
! WSADATA wsaData;
!
! /* Initialize the WinSock2 library. */
! if (WSAStartup (MAKEWORD (2, 0), &wsaData))
{
! fprintf (stderr, "%s: error initializing WinSock2", progname);
exit (EXIT_FAILURE);
}
!
! atexit (close_winsock);
! #endif /* WINDOWSNT */
}
/*
! * Read the information needed to set up a TCP comm channel with
! * the Emacs server: host, port and authentication string.
*/
! void get_server_config (server, authentication)
! struct sockaddr_in *server;
! char *authentication;
{
! FILE *config;
! char dotted[32];
! char *port;
!
! if (! (config = fopen (server_file, "rb")))
{
! fprintf (stderr, "%s: cannot read configuration file %s",
! progname, server_file);
! exit (EXIT_FAILURE);
! }
!
! if (fgets (dotted, sizeof dotted, config)
! && (port = strchr (dotted, ':')))
! {
! *port++ = '\0';
}
else
{
+ fprintf (stderr, "%s: invalid configuration info", progname);
exit (EXIT_FAILURE);
}
+ server->sin_family = AF_INET;
+ server->sin_addr.s_addr = inet_addr (dotted);
+ server->sin_port = htons (atoi (port));
+ if (! fread (authentication, AUTH_STRING_LENGTH, 1, config))
+ {
+ fprintf (stderr, "%s: cannot read authentication info", progname);
+ exit (EXIT_FAILURE);
+ }
! fclose (config);
! }
! SOCKET
! set_tcp_socket ()
{
! SOCKET s;
! struct sockaddr_in server;
! unsigned long c_arg = 0;
! struct linger l_arg = {1, 1};
! char auth_string[AUTH_STRING_LENGTH + 1];
! initialize_sockets ();
! get_server_config (&server, auth_string);
! /*
! * Open up an AF_INET socket
! */
! if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
! {
! fprintf (stderr, "%s: ", progname);
! perror ("socket");
! return INVALID_SOCKET;
! }
! /*
! * Set up the socket
! */
! if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
! {
! fprintf (stderr, "%s: ", progname);
! perror ("connect");
! return INVALID_SOCKET;
! }
!
! ioctlsocket (s, FIONBIO, &c_arg);
! setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
!
! /*
! * Send the authentication
! */
! auth_string[AUTH_STRING_LENGTH] = '\0';
!
! SEND_STRING ("-auth ");
! SEND_STRING (auth_string);
! SEND_STRING ("\n");
!
! return s;
! }
!
! #if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
/* Three possibilities:
***************
*** 292,317 ****
}
! int
! main (argc, argv)
! int argc;
! char **argv;
{
! int s, i, needlf = 0;
! FILE *out, *in;
struct sockaddr_un server;
- char *cwd, *str;
- char string[BUFSIZ];
-
- progname = argv[0];
-
- /* Process options. */
- decode_options (argc, argv);
-
- if ((argc - optind < 1) && !eval)
- {
- fprintf (stderr, "%s: file name or argument required\n", progname);
- fprintf (stderr, "Try `%s --help' for more information\n", progname);
- exit (EXIT_FAILURE);
- }
/*
--- 481,489 ----
}
! SOCKET
! set_local_socket ()
{
! SOCKET s;
struct sockaddr_un server;
/*
***************
*** 321,327 ****
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
! fprintf (stderr, "%s: ", argv[0]);
perror ("socket");
! fail (argc, argv);
}
--- 493,499 ----
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
! fprintf (stderr, "%s: ", progname);
perror ("socket");
! return INVALID_SOCKET;
}
***************
*** 353,357 ****
{
fprintf (stderr, "%s: socket-name %s too long",
! argv[0], socket_name);
exit (EXIT_FAILURE);
}
--- 525,529 ----
{
fprintf (stderr, "%s: socket-name %s too long",
! progname, socket_name);
exit (EXIT_FAILURE);
}
***************
*** 388,392 ****
{
fprintf (stderr, "%s: socket-name %s too long",
! argv[0], socket_name);
exit (EXIT_FAILURE);
}
--- 560,564 ----
{
fprintf (stderr, "%s: socket-name %s too long",
! progname, socket_name);
exit (EXIT_FAILURE);
}
***************
*** 408,412 ****
{
fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
! fail (argc, argv);
}
break;
--- 580,584 ----
{
fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
! return INVALID_SOCKET;
}
break;
***************
*** 418,427 ****
"%s: can't find socket; have you started the server?\n\
To start the server in Emacs, type \"M-x server-start\".\n",
! argv[0]);
else
fprintf (stderr, "%s: can't stat %s: %s\n",
! argv[0], server.sun_path, strerror (saved_errno));
! fail (argc, argv);
! break;
}
}
--- 590,598 ----
"%s: can't find socket; have you started the server?\n\
To start the server in Emacs, type \"M-x server-start\".\n",
! progname);
else
fprintf (stderr, "%s: can't stat %s: %s\n",
! progname, server.sun_path, strerror (saved_errno));
! return INVALID_SOCKET;
}
}
***************
*** 430,458 ****
< 0)
{
! fprintf (stderr, "%s: ", argv[0]);
perror ("connect");
! fail (argc, argv);
}
! /* We use the stream OUT to send our command to the server. */
! if ((out = fdopen (s, "r+")) == NULL)
{
! fprintf (stderr, "%s: ", argv[0]);
! perror ("fdopen");
! fail (argc, argv);
}
! /* We use the stream IN to read the response.
! We used to use just one stream for both output and input
! on the socket, but reversing direction works nonportably:
! on some systems, the output appears as the first input;
! on other systems it does not. */
! if ((in = fdopen (s, "r+")) == NULL)
{
! fprintf (stderr, "%s: ", argv[0]);
! perror ("fdopen");
! fail (argc, argv);
}
#ifdef HAVE_GETCWD
cwd = getcwd (string, sizeof string);
--- 601,654 ----
< 0)
{
! fprintf (stderr, "%s: ", progname);
perror ("connect");
! return INVALID_SOCKET;
}
! return s;
! }
! #endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
!
! SOCKET
! set_socket ()
! {
! if (server_file)
! return set_tcp_socket ();
! else
! #ifndef NO_SOCKETS_IN_FILE_SYSTEM
! return set_local_socket ();
! #else
{
! fprintf (stderr, "%s: missing --server-file option", progname);
! exit (EXIT_FAILURE);
}
+ #endif
+ }
+
+ int
+ main (argc, argv)
+ int argc;
+ char **argv;
+ {
+ SOCKET s;
+ int i, rl, needlf = 0;
+ char *cwd;
+ char string[BUFSIZ+1];
+
+ progname = argv[0];
! /* Process options. */
! decode_options (argc, argv);
!
! if ((argc - optind < 1) && !eval)
{
! fprintf (stderr, "%s: file name or argument required\n", progname);
! fprintf (stderr, "Try `%s --help' for more information\n", progname);
! exit (EXIT_FAILURE);
}
+ if ((s = set_socket ()) == INVALID_SOCKET)
+ fail (argc, argv);
+
#ifdef HAVE_GETCWD
cwd = getcwd (string, sizeof string);
***************
*** 465,472 ****
#ifdef HAVE_GETCWD
! fprintf (stderr, "%s: %s (%s)\n", argv[0],
"Cannot get current working directory", strerror (errno));
#else
! fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
#endif
fail (argc, argv);
--- 661,668 ----
#ifdef HAVE_GETCWD
! fprintf (stderr, "%s: %s (%s)\n", progname,
"Cannot get current working directory", strerror (errno));
#else
! fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno));
#endif
fail (argc, argv);
***************
*** 474,487 ****
if (nowait)
! fprintf (out, "-nowait ");
if (eval)
! fprintf (out, "-eval ");
if (display)
{
! fprintf (out, "-display ");
! quote_file_name (display, out);
! fprintf (out, " ");
}
--- 670,683 ----
if (nowait)
! SEND_STRING ("-nowait ");
if (eval)
! SEND_STRING ("-eval ");
if (display)
{
! SEND_STRING ("-display ");
! SEND_QUOTED (display);
! SEND_STRING (" ");
}
***************
*** 498,531 ****
if (*p != 0)
{
! quote_file_name (cwd, out);
! fprintf (out, "/");
}
}
else if (*argv[i] != '/')
{
! quote_file_name (cwd, out);
! fprintf (out, "/");
}
! quote_file_name (argv[i], out);
! fprintf (out, " ");
}
}
else
{
! while ((str = fgets (string, BUFSIZ, stdin)))
{
! quote_file_name (str, out);
}
! fprintf (out, " ");
}
! fprintf (out, "\n");
! fflush (out);
/* Maybe wait for an answer. */
! if (nowait)
! return EXIT_SUCCESS;
!
if (!eval)
{
--- 694,734 ----
if (*p != 0)
{
! SEND_QUOTED (cwd);
! SEND_STRING ("/");
}
}
+ #ifndef WINDOWSNT
else if (*argv[i] != '/')
+ #else
+ else if ((*argv[i] != '/')
+ /* Absolute paths can also start with backslash
+ or drive letters. */
+ && (*argv[i] != '\\')
+ && (!islower (tolower (*argv[i]))
+ || (argv[i][1] != ':')))
+ #endif
{
! SEND_QUOTED (cwd);
! SEND_STRING ("/");
}
! SEND_QUOTED (argv[i]);
! SEND_STRING (" ");
}
}
else
{
! while (fgets (string, BUFSIZ, stdin))
{
! SEND_QUOTED (string);
}
! SEND_STRING (" ");
}
! SEND_STRING ("\n");
/* Maybe wait for an answer. */
! if (!nowait)
! {
if (!eval)
{
***************
*** 536,545 ****
/* Now, wait for an answer and print any messages. */
! while ((str = fgets (string, BUFSIZ, in)))
{
if (needlf == 2)
printf ("\n");
! printf ("%s", str);
! needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
}
--- 739,749 ----
/* Now, wait for an answer and print any messages. */
! while ((rl = recv (s, string, BUFSIZ, 0)) > 0)
{
+ string[rl] = '\0';
if (needlf == 2)
printf ("\n");
! printf ("%s", string);
! needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
}
***************
*** 547,551 ****
--- 751,757 ----
printf ("\n");
fflush (stdout);
+ }
+ closesocket (s);
return EXIT_SUCCESS;
}
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.46
diff -b -c -2 -r2.46 makefile.w32-in
*** lib-src/makefile.w32-in 9 Oct 2006 19:57:43 -0000 2.46
--- lib-src/makefile.w32-in 26 Oct 2006 22:23:12 -0000
***************
*** 21,25 ****
#
! ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc
.PHONY: $(ALL)
--- 21,25 ----
#
! ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc emacsclient
.PHONY: $(ALL)
***************
*** 33,37 ****
# $(BLD)/server.exe \
# $(BLD)/emacstool.exe \
- # $(BLD)/emacsclient.exe \
# $(BLD)/cvtmail.exe \
--- 33,36 ----
***************
*** 60,63 ****
--- 59,63 ----
sorted-doc: $(BLD) $(BLD)/sorted-doc.exe
digest-doc: $(BLD) $(BLD)/digest-doc.exe
+ emacsclient: $(BLD) $(BLD)/emacsclient.exe
test-distrib: $(BLD) $(BLD)/test-distrib.exe
***************
*** 75,78 ****
--- 75,91 ----
$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(MOVEMAILOBJS) $(WSOCK32) $(LIBS)
+ ECLIENT_CFLAGS = -DWINDOWSNT -DHAVE_GETCWD -DHAVE_STRERROR -c
+ ECLIENTOBJS = $(BLD)/emacsclient.$(O) \
+ $(BLD)/getopt.$(O) \
+ $(BLD)/getopt1.$(O) \
+ $(BLD)/ntlib.$(O)
+
+ $(BLD)/emacsclient.exe: $(ECLIENTOBJS)
+ # put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
+ $(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(LIBS)
+
+ $(BLD)/emacsclient.$(O): emacsclient.c
+ $(CC) $(ECLIENT_CFLAGS) $(CC_OUT)$@ emacsclient.c
+
ETAGSOBJ = $(BLD)/etags.$(O) \
$(BLD)/getopt.$(O) \
***************
*** 297,300 ****
--- 310,314 ----
$(CP) $(BLD)/sorted-doc.exe $(INSTALL_DIR)/bin
$(CP) $(BLD)/digest-doc.exe $(INSTALL_DIR)/bin
+ $(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
- mkdir "$(INSTALL_DIR)/etc"
$(CP) $(DOC) $(INSTALL_DIR)/etc
[-- Attachment #3: newserver-u.patch --]
[-- Type: application/octet-stream, Size: 24201 bytes --]
Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.113
diff -b -u -2 -r1.113 server.el
--- lisp/server.el 6 Jul 2006 22:48:16 -0000 1.113
+++ lisp/server.el 26 Oct 2006 23:06:08 -0000
@@ -83,4 +83,33 @@
:group 'external)
+(defcustom server-use-tcp nil
+ "If non-nil, use TCP sockets instead of local sockets."
+ :set #'(lambda (sym val)
+ (if (featurep 'make-network-process '(:family local))
+ (set-default sym val)
+ (unless load-in-progress
+ (message "Local sockets unsupported, using TCP sockets"))
+ (set-default sym t)))
+ :group 'server
+ :type 'boolean
+ :version "22.1")
+
+(defcustom server-host nil
+ "The name or IP address to use as host address of the server process.
+If set, the server accepts remote connections; otherwise it is local."
+ :group 'server
+ :type '(choice
+ (string :tag "Name or IP address")
+ (const :tag "Local" nil))
+ :version "22.1")
+(put 'server-host 'risky-local-variable t)
+
+(defcustom server-auth-dir "~/.emacs.d/server/"
+ "Directory for server authentication files."
+ :group 'server
+ :type 'directory
+ :version "22.1")
+(put 'server-auth-dir 'risky-local-variable t)
+
(defcustom server-visit-hook nil
"*Hook run when visiting a file for the Emacs server."
@@ -101,4 +130,7 @@
"The current server process.")
+(defvar server-auth-string nil
+ "The current server authentication string.")
+
(defvar server-clients nil
"List of current server clients.
@@ -232,11 +264,22 @@
(let ((attrs (file-attributes dir)))
(unless attrs
- (letf (((default-file-modes) ?\700)) (make-directory dir))
+ (letf (((default-file-modes) ?\700)) (make-directory dir t))
(setq attrs (file-attributes dir)))
;; Check that it's safe for use.
(unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
- (zerop (logand ?\077 (file-modes dir))))
+ (or (eq system-type 'windows-nt)
+ (zerop (logand ?\077 (file-modes dir)))))
(error "The directory %s is unsafe" dir))))
+(defun server-auth-string ()
+ (or server-auth-string
+ ;; If the authentication string does not exist, create it on the fly:
+ ;; it's a 64-byte string of random chars in the range `!'..`~'.
+ (setq server-auth-string
+ (loop
+ for i below 64
+ collect (+ 33 (random 94)) into auth
+ finally return (concat auth)))))
+
;;;###autoload
(defun server-start (&optional leave-dead)
@@ -249,11 +292,13 @@
Prefix arg means just kill any existing server communications subprocess."
(interactive "P")
+ (when server-process
;; kill it dead!
- (if server-process
- (condition-case () (delete-process server-process) (error nil)))
- ;; Delete the socket files made by previous server invocations.
- (condition-case ()
+ (ignore-errors (delete-process server-process))
+ (ignore-errors
+ ;; Delete the socket or authentication files made by previous server invocations.
+ (if (eq (process-contact server-process :family) 'local)
(delete-file (expand-file-name server-name server-socket-dir))
- (error nil))
+ (setq server-auth-string nil)
+ (delete-file (expand-file-name server-name server-auth-dir)))))
;; If this Emacs already had a server, clear out associated status.
(while server-clients
@@ -263,17 +308,35 @@
(unless leave-dead
;; Make sure there is a safe directory in which to place the socket.
- (server-ensure-safe-dir server-socket-dir)
- (if server-process
+ (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
+ (when server-process
(server-log (message "Restarting server")))
(letf (((default-file-modes) ?\700))
(setq server-process
- (make-network-process
- :name "server" :family 'local :server t :noquery t
- :service (expand-file-name server-name server-socket-dir)
- :sentinel 'server-sentinel :filter 'server-process-filter
+ (apply #'make-network-process
+ :name server-name
+ :server t
+ :noquery t
+ :sentinel 'server-sentinel
+ :filter 'server-process-filter
;; We must receive file names without being decoded.
;; Those are decoded by server-process-filter according
;; to file-name-coding-system.
- :coding 'raw-text)))))
+ :coding 'raw-text
+ ;; The rest of the arguments depend on the kind of socket used
+ (if server-use-tcp
+ (list :family nil
+ :service t
+ :host (or server-host 'local)
+ :plist '(:authenticated nil))
+ (list :family 'local
+ :service (expand-file-name server-name server-socket-dir)
+ :plist '(:authenticated t))))))
+ (unless server-process (error "Could not start server process"))
+ (when server-use-tcp
+ (with-temp-file (expand-file-name server-name server-auth-dir)
+ (set-buffer-multibyte nil)
+ (setq buffer-file-coding-system 'no-conversion)
+ (insert (format-network-address (process-contact server-process :local))
+ "\n" (server-auth-string))))))
;;;###autoload
@@ -290,12 +353,23 @@
(server-start (not server-mode)))
\f
-(defun server-process-filter (proc string)
+(defun* server-process-filter (proc string)
"Process a request from the server to edit some files.
PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
+ ;; First things first: let's check the authentication
+ (unless (process-get proc :authenticated)
+ (if (and (string-match "-auth \\(.*?\\)\n" string)
+ (string= (match-string 1 string) server-auth-string))
+ (progn
+ (setq string (substring string (match-end 0)))
+ (process-put proc :authenticated t)
+ (server-log "Authentication successful" proc))
+ (server-log "Authentication failed" proc)
+ (delete-process proc)
+ (return-from server-process-filter)))
(server-log string proc)
- (let ((prev (process-get proc 'previous-string)))
+ (let ((prev (process-get proc :previous-string)))
(when prev
(setq string (concat prev string))
- (process-put proc 'previous-string nil)))
+ (process-put proc :previous-string nil)))
;; If the input is multiple lines,
;; process each line individually.
@@ -390,5 +464,5 @@
;; Save for later any partial line that remains.
(when (> (length string) 0)
- (process-put proc 'previous-string string)))
+ (process-put proc :previous-string string)))
(defun server-goto-line-column (file-line-col)
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.77
diff -b -u -2 -r1.77 emacsclient.c
--- lib-src/emacsclient.c 18 Jul 2006 16:33:45 -0000 1.77
+++ lib-src/emacsclient.c 27 Oct 2006 00:06:01 -0000
@@ -27,9 +27,14 @@
#endif
+#ifdef WINDOWSNT
+#define HAVE_SOCKETS
+#define NO_SOCKETS_IN_FILE_SYSTEM
+#endif
+
#undef signal
#include <ctype.h>
#include <stdio.h>
-#include <getopt.h>
+#include "getopt.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -38,6 +43,10 @@
#ifdef VMS
# include "vms-pwd.h"
-#else
+#else /* not VMS */
+#ifdef WINDOWSNT
+# include <io.h>
+#else /* not WINDOWSNT */
# include <pwd.h>
+#endif /* not WINDOWSNT */
#endif /* not VMS */
@@ -49,4 +58,19 @@
#endif
\f
+#define SEND_STRING(data) (send_to_emacs (s, (data)))
+#define SEND_QUOTED(data) (quote_file_name (s, (data)))
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifndef NO_RETURN
+#define NO_RETURN
+#endif
+\f
/* Name used to invoke this program. */
char *progname;
@@ -68,4 +92,7 @@
char *socket_name = NULL;
+/* If non-NULL, the filename of the authentication file. */
+char *server_file = NULL;
+
void print_help_and_exit () NO_RETURN;
@@ -78,4 +105,5 @@
{ "alternate-editor", required_argument, NULL, 'a' },
{ "socket-name", required_argument, NULL, 's' },
+ { "server-file", required_argument, NULL, 'f' },
{ "display", required_argument, NULL, 'd' },
{ 0, 0, 0, 0 }
@@ -91,9 +119,10 @@
{
alternate_editor = getenv ("ALTERNATE_EDITOR");
+ server_file = getenv ("EMACS_SERVER_FILE");
while (1)
{
int opt = getopt_long (argc, argv,
- "VHnea:s:d:", longopts, 0);
+ "VHnea:s:f:d:", longopts, 0);
if (opt == EOF)
@@ -115,4 +144,8 @@
break;
+ case 'f':
+ server_file = optarg;
+ break;
+
case 'd':
display = optarg;
@@ -158,6 +191,12 @@
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY Visit the file in the given display\n\
--s, --socket-name=FILENAME\n\
+"
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+"-s, --socket-name=FILENAME\n\
Set the filename of the UNIX socket for communication\n\
+"
+#endif
+"-f, --server-file=FILENAME\n\
+ Set the filename of the TCP configuration file\n\
-a, --alternate-editor=EDITOR\n\
Editor to fallback to if the server is not running\n\
@@ -167,12 +206,108 @@
}
+\f
+/*
+ Try to run a different command, or --if no alternate editor is
+ defined-- exit with an errorcode.
+*/
+void
+fail (argc, argv)
+ int argc;
+ char **argv;
+{
+ if (alternate_editor)
+ {
+ int i = optind - 1;
+ execvp (alternate_editor, argv + i);
+ return;
+ }
+ else
+ {
+ exit (EXIT_FAILURE);
+ }
+}
+
+\f
+#if !defined (HAVE_SOCKETS)
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
+ argv[0]);
+ fprintf (stderr, "on systems with Berkeley sockets.\n");
+
+ fail (argc, argv);
+}
+
+#else /* HAVE_SOCKETS */
+
+#define AUTH_STRING_LENGTH 64
+#define SEND_BUFFER_SIZE 4096
+
+#ifdef WINDOWSNT
+# include <winsock2.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <sys/stat.h>
+# include <errno.h>
+#endif
+
+extern char *strerror ();
+extern int errno;
+
+/* Buffer to accumulate data to send in TCP connections. */
+char send_buffer[SEND_BUFFER_SIZE + 1];
+int sblen = 0; /* Fill pointer for the send buffer. */
+
+/* Let's send the data to Emacs when either
+ - the data ends in "\n", or
+ - the buffer is full (but this shouldn't happen)
+ Otherwise, we just accumulate it. */
+void send_to_emacs (s, data)
+ SOCKET s;
+ char *data;
+{
+ while (data)
+ {
+ int dlen = strlen (data);
+ if (dlen + sblen >= SEND_BUFFER_SIZE)
+ {
+ int part = SEND_BUFFER_SIZE - sblen;
+ strncpy (&send_buffer[sblen], data, part);
+ data += part;
+ sblen = SEND_BUFFER_SIZE;
+ }
+ else if (dlen)
+ {
+ strcpy (&send_buffer[sblen], data);
+ data = NULL;
+ sblen += dlen;
+ }
+ else
+ break;
+
+ if (sblen == SEND_BUFFER_SIZE
+ || (sblen > 0 && send_buffer[sblen-1] == '\n'))
+ {
+ int sent = send (s, send_buffer, sblen, 0);
+ if (sent != sblen)
+ strcpy (send_buffer, &send_buffer[sent]);
+ sblen -= sent;
+ }
+ }
+}
+
/* In NAME, insert a & before each &, each space, each newline, and
any initial -. Change spaces to underscores, too, so that the
return value never contains a space. */
-
void
-quote_file_name (name, stream)
+quote_file_name (s, name)
+ SOCKET s;
char *name;
- FILE *stream;
{
char *copy = (char *) malloc (strlen (name) * 2 + 1);
@@ -204,71 +339,125 @@
*q++ = 0;
- fprintf (stream, "%s", copy);
+ SEND_STRING (copy);
free (copy);
}
-/* Like malloc but get fatal error if memory is exhausted. */
+#ifdef WINDOWSNT
+/* Wrapper to make WSACleanup a cdecl, as required by atexit(). */
+void close_winsock ()
+{
+ WSACleanup ();
+}
+#endif /* WINDOWSNT */
-long *
-xmalloc (size)
- unsigned int size;
+void initialize_sockets ()
{
- long *result = (long *) malloc (size);
- if (result == NULL)
+#ifdef WINDOWSNT
+ WSADATA wsaData;
+
+ /* Initialize the WinSock2 library. */
+ if (WSAStartup (MAKEWORD (2, 0), &wsaData))
{
- perror ("malloc");
+ fprintf (stderr, "%s: error initializing WinSock2", progname);
exit (EXIT_FAILURE);
}
- return result;
+
+ atexit (close_winsock);
+#endif /* WINDOWSNT */
}
\f
/*
- Try to run a different command, or --if no alternate editor is
- defined-- exit with an errorcode.
+ * Read the information needed to set up a TCP comm channel with
+ * the Emacs server: host, port and authentication string.
*/
-void
-fail (argc, argv)
- int argc;
- char **argv;
+void get_server_config (server, authentication)
+ struct sockaddr_in *server;
+ char *authentication;
{
- if (alternate_editor)
+ FILE *config;
+ char dotted[32];
+ char *port;
+
+ if (! (config = fopen (server_file, "rb")))
{
- int i = optind - 1;
- execvp (alternate_editor, argv + i);
- return;
+ fprintf (stderr, "%s: cannot read configuration file %s",
+ progname, server_file);
+ exit (EXIT_FAILURE);
+ }
+
+ if (fgets (dotted, sizeof dotted, config)
+ && (port = strchr (dotted, ':')))
+ {
+ *port++ = '\0';
}
else
{
+ fprintf (stderr, "%s: invalid configuration info", progname);
exit (EXIT_FAILURE);
}
-}
+ server->sin_family = AF_INET;
+ server->sin_addr.s_addr = inet_addr (dotted);
+ server->sin_port = htons (atoi (port));
+ if (! fread (authentication, AUTH_STRING_LENGTH, 1, config))
+ {
+ fprintf (stderr, "%s: cannot read authentication info", progname);
+ exit (EXIT_FAILURE);
+ }
\f
-#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
+ fclose (config);
+}
-int
-main (argc, argv)
- int argc;
- char **argv;
+SOCKET
+set_tcp_socket ()
{
- fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
- argv[0]);
- fprintf (stderr, "on systems with Berkeley sockets.\n");
+ SOCKET s;
+ struct sockaddr_in server;
+ unsigned long c_arg = 0;
+ struct linger l_arg = {1, 1};
+ char auth_string[AUTH_STRING_LENGTH + 1];
- fail (argc, argv);
-}
+ initialize_sockets ();
-#else /* HAVE_SOCKETS */
+ get_server_config (&server, auth_string);
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <errno.h>
+ /*
+ * Open up an AF_INET socket
+ */
+ if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ {
+ fprintf (stderr, "%s: ", progname);
+ perror ("socket");
+ return INVALID_SOCKET;
+ }
-extern char *strerror ();
-extern int errno;
+ /*
+ * Set up the socket
+ */
+ if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
+ {
+ fprintf (stderr, "%s: ", progname);
+ perror ("connect");
+ return INVALID_SOCKET;
+ }
+
+ ioctlsocket (s, FIONBIO, &c_arg);
+ setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
+
+ /*
+ * Send the authentication
+ */
+ auth_string[AUTH_STRING_LENGTH] = '\0';
+
+ SEND_STRING ("-auth ");
+ SEND_STRING (auth_string);
+ SEND_STRING ("\n");
+
+ return s;
+}
+
+#if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
/* Three possibilities:
@@ -292,26 +481,9 @@
}
-int
-main (argc, argv)
- int argc;
- char **argv;
+SOCKET
+set_local_socket ()
{
- int s, i, needlf = 0;
- FILE *out, *in;
+ SOCKET s;
struct sockaddr_un server;
- char *cwd, *str;
- char string[BUFSIZ];
-
- progname = argv[0];
-
- /* Process options. */
- decode_options (argc, argv);
-
- if ((argc - optind < 1) && !eval)
- {
- fprintf (stderr, "%s: file name or argument required\n", progname);
- fprintf (stderr, "Try `%s --help' for more information\n", progname);
- exit (EXIT_FAILURE);
- }
/*
@@ -321,7 +493,7 @@
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
- fprintf (stderr, "%s: ", argv[0]);
+ fprintf (stderr, "%s: ", progname);
perror ("socket");
- fail (argc, argv);
+ return INVALID_SOCKET;
}
@@ -353,5 +525,5 @@
{
fprintf (stderr, "%s: socket-name %s too long",
- argv[0], socket_name);
+ progname, socket_name);
exit (EXIT_FAILURE);
}
@@ -388,5 +560,5 @@
{
fprintf (stderr, "%s: socket-name %s too long",
- argv[0], socket_name);
+ progname, socket_name);
exit (EXIT_FAILURE);
}
@@ -408,5 +580,5 @@
{
fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
- fail (argc, argv);
+ return INVALID_SOCKET;
}
break;
@@ -418,10 +590,9 @@
"%s: can't find socket; have you started the server?\n\
To start the server in Emacs, type \"M-x server-start\".\n",
- argv[0]);
+ progname);
else
fprintf (stderr, "%s: can't stat %s: %s\n",
- argv[0], server.sun_path, strerror (saved_errno));
- fail (argc, argv);
- break;
+ progname, server.sun_path, strerror (saved_errno));
+ return INVALID_SOCKET;
}
}
@@ -430,29 +601,54 @@
< 0)
{
- fprintf (stderr, "%s: ", argv[0]);
+ fprintf (stderr, "%s: ", progname);
perror ("connect");
- fail (argc, argv);
+ return INVALID_SOCKET;
}
- /* We use the stream OUT to send our command to the server. */
- if ((out = fdopen (s, "r+")) == NULL)
+ return s;
+}
+#endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
+
+SOCKET
+set_socket ()
+{
+ if (server_file)
+ return set_tcp_socket ();
+ else
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+ return set_local_socket ();
+#else
{
- fprintf (stderr, "%s: ", argv[0]);
- perror ("fdopen");
- fail (argc, argv);
+ fprintf (stderr, "%s: missing --server-file option", progname);
+ exit (EXIT_FAILURE);
}
+#endif
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ SOCKET s;
+ int i, rl, needlf = 0;
+ char *cwd;
+ char string[BUFSIZ+1];
+
+ progname = argv[0];
- /* We use the stream IN to read the response.
- We used to use just one stream for both output and input
- on the socket, but reversing direction works nonportably:
- on some systems, the output appears as the first input;
- on other systems it does not. */
- if ((in = fdopen (s, "r+")) == NULL)
+ /* Process options. */
+ decode_options (argc, argv);
+
+ if ((argc - optind < 1) && !eval)
{
- fprintf (stderr, "%s: ", argv[0]);
- perror ("fdopen");
- fail (argc, argv);
+ fprintf (stderr, "%s: file name or argument required\n", progname);
+ fprintf (stderr, "Try `%s --help' for more information\n", progname);
+ exit (EXIT_FAILURE);
}
+ if ((s = set_socket ()) == INVALID_SOCKET)
+ fail (argc, argv);
+
#ifdef HAVE_GETCWD
cwd = getcwd (string, sizeof string);
@@ -465,8 +661,8 @@
#ifdef HAVE_GETCWD
- fprintf (stderr, "%s: %s (%s)\n", argv[0],
+ fprintf (stderr, "%s: %s (%s)\n", progname,
"Cannot get current working directory", strerror (errno));
#else
- fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
+ fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno));
#endif
fail (argc, argv);
@@ -474,14 +670,14 @@
if (nowait)
- fprintf (out, "-nowait ");
+ SEND_STRING ("-nowait ");
if (eval)
- fprintf (out, "-eval ");
+ SEND_STRING ("-eval ");
if (display)
{
- fprintf (out, "-display ");
- quote_file_name (display, out);
- fprintf (out, " ");
+ SEND_STRING ("-display ");
+ SEND_QUOTED (display);
+ SEND_STRING (" ");
}
@@ -498,34 +694,41 @@
if (*p != 0)
{
- quote_file_name (cwd, out);
- fprintf (out, "/");
+ SEND_QUOTED (cwd);
+ SEND_STRING ("/");
}
}
+#ifndef WINDOWSNT
else if (*argv[i] != '/')
+#else
+ else if ((*argv[i] != '/')
+ /* Absolute paths can also start with backslash
+ or drive letters. */
+ && (*argv[i] != '\\')
+ && (!islower (tolower (*argv[i]))
+ || (argv[i][1] != ':')))
+#endif
{
- quote_file_name (cwd, out);
- fprintf (out, "/");
+ SEND_QUOTED (cwd);
+ SEND_STRING ("/");
}
- quote_file_name (argv[i], out);
- fprintf (out, " ");
+ SEND_QUOTED (argv[i]);
+ SEND_STRING (" ");
}
}
else
{
- while ((str = fgets (string, BUFSIZ, stdin)))
+ while (fgets (string, BUFSIZ, stdin))
{
- quote_file_name (str, out);
+ SEND_QUOTED (string);
}
- fprintf (out, " ");
+ SEND_STRING (" ");
}
- fprintf (out, "\n");
- fflush (out);
+ SEND_STRING ("\n");
/* Maybe wait for an answer. */
- if (nowait)
- return EXIT_SUCCESS;
-
+ if (!nowait)
+ {
if (!eval)
{
@@ -536,10 +739,11 @@
/* Now, wait for an answer and print any messages. */
- while ((str = fgets (string, BUFSIZ, in)))
+ while ((rl = recv (s, string, BUFSIZ, 0)) > 0)
{
+ string[rl] = '\0';
if (needlf == 2)
printf ("\n");
- printf ("%s", str);
- needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
+ printf ("%s", string);
+ needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
}
@@ -547,5 +751,7 @@
printf ("\n");
fflush (stdout);
+ }
+ closesocket (s);
return EXIT_SUCCESS;
}
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.46
diff -b -u -2 -r2.46 makefile.w32-in
--- lib-src/makefile.w32-in 9 Oct 2006 19:57:43 -0000 2.46
+++ lib-src/makefile.w32-in 26 Oct 2006 22:23:12 -0000
@@ -21,5 +21,5 @@
#
-ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc
+ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc emacsclient
.PHONY: $(ALL)
@@ -33,5 +33,4 @@
# $(BLD)/server.exe \
# $(BLD)/emacstool.exe \
-# $(BLD)/emacsclient.exe \
# $(BLD)/cvtmail.exe \
@@ -60,4 +59,5 @@
sorted-doc: $(BLD) $(BLD)/sorted-doc.exe
digest-doc: $(BLD) $(BLD)/digest-doc.exe
+emacsclient: $(BLD) $(BLD)/emacsclient.exe
test-distrib: $(BLD) $(BLD)/test-distrib.exe
@@ -75,4 +75,17 @@
$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(MOVEMAILOBJS) $(WSOCK32) $(LIBS)
+ECLIENT_CFLAGS = -DWINDOWSNT -DHAVE_GETCWD -DHAVE_STRERROR -c
+ECLIENTOBJS = $(BLD)/emacsclient.$(O) \
+ $(BLD)/getopt.$(O) \
+ $(BLD)/getopt1.$(O) \
+ $(BLD)/ntlib.$(O)
+
+$(BLD)/emacsclient.exe: $(ECLIENTOBJS)
+# put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
+ $(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(LIBS)
+
+$(BLD)/emacsclient.$(O): emacsclient.c
+ $(CC) $(ECLIENT_CFLAGS) $(CC_OUT)$@ emacsclient.c
+
ETAGSOBJ = $(BLD)/etags.$(O) \
$(BLD)/getopt.$(O) \
@@ -297,4 +310,5 @@
$(CP) $(BLD)/sorted-doc.exe $(INSTALL_DIR)/bin
$(CP) $(BLD)/digest-doc.exe $(INSTALL_DIR)/bin
+ $(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
- mkdir "$(INSTALL_DIR)/etc"
$(CP) $(DOC) $(INSTALL_DIR)/etc
[-- Attachment #4: Type: text/plain, Size: 142 bytes --]
_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel
next prev parent reply other threads:[~2006-10-27 0:27 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
2006-10-23 14:54 ` Jason Rumney
2006-10-23 19:48 ` Stefan Monnier
2006-10-23 21:17 ` Jason Rumney
2006-10-23 22:02 ` Andreas Schwab
2006-10-23 16:00 ` Ted Zlatanov
2006-10-23 20:09 ` Eli Zaretskii
2006-10-24 0:02 ` Ted Zlatanov
2006-10-24 4:35 ` Eli Zaretskii
2006-10-24 15:36 ` Ted Zlatanov
2006-10-24 17:31 ` Eli Zaretskii
2006-10-24 19:24 ` Ted Zlatanov
2006-10-24 22:22 ` Stefan Monnier
2006-10-25 16:33 ` Ted Zlatanov
2006-10-25 11:46 ` Michael Olson
2006-10-25 12:38 ` David Kastrup
2006-10-23 21:47 ` Juanma Barranquero
2006-10-23 23:50 ` Ted Zlatanov
2006-10-24 2:01 ` Stefan Monnier
2006-10-24 15:40 ` Ted Zlatanov
2006-10-24 18:17 ` Stefan Monnier
2006-10-24 19:31 ` Ted Zlatanov
2006-10-23 16:26 ` Jan D.
2006-10-23 19:52 ` Stefan Monnier
2006-10-23 20:35 ` Jan Djärv
2006-10-23 21:20 ` Jason Rumney
2006-10-23 21:59 ` Jason Rumney
2006-10-24 5:06 ` Jan Djärv
2006-10-24 8:37 ` Juanma Barranquero
2006-10-24 13:27 ` Jason Rumney
2006-10-23 21:57 ` Juanma Barranquero
2006-10-24 5:08 ` Jan Djärv
2006-10-24 7:32 ` Kim F. Storm
2006-10-23 19:46 ` Stefan Monnier
2006-10-23 21:54 ` Juanma Barranquero
2006-10-24 2:04 ` Stefan Monnier
2006-10-24 8:39 ` Juanma Barranquero
2006-10-27 0:27 ` Juanma Barranquero [this message]
2006-10-27 11:08 ` Juanma Barranquero
2006-10-27 12:21 ` Jason Rumney
2006-10-27 13:25 ` Stefan Monnier
2006-10-27 13:35 ` Juanma Barranquero
2006-10-27 13:29 ` Juanma Barranquero
2006-10-27 13:50 ` Slawomir Nowaczyk
2006-10-27 14:20 ` Stefan Monnier
2006-10-27 15:18 ` Juanma Barranquero
2006-10-28 18:13 ` Richard Stallman
2006-10-30 1:02 ` Stefan Monnier
2006-10-31 0:35 ` Juanma Barranquero
2006-10-28 7:27 ` Richard Stallman
2006-10-28 21:16 ` Juanma Barranquero
2006-10-28 23:38 ` Kim F. Storm
2006-10-30 13:33 ` Richard Stallman
[not found] ` <f7ccd24b0610271000p16dda672mb146860725d47e00@mail.gmail.com>
[not found] ` <45426C6B.10401@student.lu.se>
[not found] ` <f7ccd24b0610271400x343c7197jbd6b775f49834924@mail.gmail.com>
[not found] ` <454276CB.9000002@student.lu.se>
[not found] ` <f7ccd24b0610271419p51bf429fjf5fb548e613cd950@mail.gmail.com>
[not found] ` <45427A24.8020107@student.lu.se>
[not found] ` <f7ccd24b0610271438r64539e94j6b17c251b213a047@mail.gmail.com>
[not found] ` <45427F8E.5040507@student.lu.se>
[not found] ` <f7ccd24b0610271700v472f9c53v43017fce05e761e9@mail.gmail.com>
2006-10-28 0:24 ` Juanma Barranquero
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f7ccd24b0610261727t1cf8a448v36eb641348fdad1c@mail.gmail.com \
--to=lekktu@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).