From: Juanma Barranquero <lekktu@gmail.com>
Cc: Emacs Devel <emacs-devel@gnu.org>
Subject: Re: w32 does not have emacsclient/server
Date: Fri, 5 Aug 2005 13:06:59 +0200 [thread overview]
Message-ID: <f7ccd24b05080504067533ad37@mail.gmail.com> (raw)
In-Reply-To: <f7ccd24b050805005935d09db@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 198 bytes --]
The same patch, with a fix (there was a buffer overflow on
emacsclient; not a security problem, but still...). send_to_emacs() is
now much more rational.
--
/L/e/k/t/u
[-- Attachment #2: server.patch --]
[-- Type: application/octet-stream, Size: 36036 bytes --]
Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.104
diff -c -r1.104 server.el
*** lisp/server.el 16 Jul 2005 11:58:10 -0000 1.104
--- lisp/server.el 5 Aug 2005 07:59:08 -0000
***************
*** 82,87 ****
--- 82,103 ----
"Emacs running as a server process."
:group 'external)
+ (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")
+
+ (defcustom server-file "~/.emacs.server"
+ "The server authentication file.
+ Its value will be passed through `expand-file-name'."
+ :group 'server
+ :type 'file
+ :version "22.1")
+
(defcustom server-visit-hook nil
"*Hook run when visiting a file for the Emacs server."
:group 'server
***************
*** 100,105 ****
--- 116,124 ----
(defvar server-process nil
"The current server process.")
+ (defvar server-auth-string nil
+ "The current server authentication string.")
+
(defvar server-clients nil
"List of current server clients.
Each element is (CLIENTID BUFFERS...) where CLIENTID is a string
***************
*** 161,194 ****
(defvar server-name "server")
- (defvar server-socket-dir
- (format "/tmp/emacs%d" (user-uid)))
-
(defun server-log (string &optional client)
"If a *server* buffer exists, write STRING to it for logging purposes."
! (if (get-buffer "*server*")
! (with-current-buffer "*server*"
! (goto-char (point-max))
! (insert (current-time-string)
! (if client (format " %s:" client) " ")
! string)
! (or (bolp) (newline)))))
(defun server-sentinel (proc msg)
! (let ((client (assq proc server-clients)))
! ;; Remove PROC from the list of clients.
! (when client
! (setq server-clients (delq client server-clients))
! (dolist (buf (cdr client))
! (with-current-buffer buf
! ;; Remove PROC from the clients of each buffer.
! (setq server-buffer-clients (delq proc server-buffer-clients))
! ;; Kill the buffer if necessary.
! (when (and (null server-buffer-clients)
! (or (and server-kill-new-buffers
! (not server-existing-buffer))
! (server-temp-file-p)))
! (kill-buffer (current-buffer)))))))
(server-log (format "Status changed to %s" (process-status proc)) proc))
(defun server-select-display (display)
--- 180,213 ----
(defvar server-name "server")
(defun server-log (string &optional client)
"If a *server* buffer exists, write STRING to it for logging purposes."
! (when (get-buffer "*server*")
! (with-current-buffer "*server*"
! (goto-char (point-max))
! (insert (current-time-string)
! (if client (format " %s:" client) " ")
! string)
! (or (bolp) (newline)))))
(defun server-sentinel (proc msg)
! (if (eq proc server-process)
! (ignore-errors
! (delete-file (expand-file-name server-file)))
! (let ((client (assq proc server-clients)))
! ;; Remove PROC from the list of clients.
! (when client
! (setq server-clients (delq client server-clients))
! (dolist (buf (cdr client))
! (with-current-buffer buf
! ;; Remove PROC from the clients of each buffer.
! (setq server-buffer-clients (delq proc server-buffer-clients))
! ;; Kill the buffer if necessary.
! (when (and (null server-buffer-clients)
! (or (and server-kill-new-buffers
! (not server-existing-buffer))
! (server-temp-file-p)))
! (kill-buffer (current-buffer))))))))
(server-log (format "Status changed to %s" (process-status proc)) proc))
(defun server-select-display (display)
***************
*** 221,241 ****
(t " ")))
arg t t))
! (defun server-ensure-safe-dir (dir)
! "Make sure DIR is a directory with no race-condition issues.
! Creates the directory if necessary and makes sure:
! - there's no symlink involved
! - it's owned by us
! - it's not readable/writable by anybody else."
! (setq dir (directory-file-name dir))
! (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)
--- 240,254 ----
(t " ")))
arg t t))
! (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)
***************
*** 247,278 ****
Prefix arg means just kill any existing server communications subprocess."
(interactive "P")
! ;; Make sure there is a safe directory in which to place the socket.
! (server-ensure-safe-dir server-socket-dir)
! ;; 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
(let ((buffer (nth 1 (car server-clients))))
(server-buffer-done buffer)))
(unless leave-dead
! (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
(define-minor-mode server-mode
--- 260,301 ----
Prefix arg means just kill any existing server communications subprocess."
(interactive "P")
! ;; Kill it dead!
! (when server-process
! (condition-case ()
! (progn
! (delete-process server-process)
! (delete-file (expand-file-name server-file))
! (setq server-auth-string nil))
! (error nil)))
;; If this Emacs already had a server, clear out associated status.
(while server-clients
(let ((buffer (nth 1 (car server-clients))))
(server-buffer-done buffer)))
(unless leave-dead
! (when server-process
! (server-log (message "Restarting server")))
(letf (((default-file-modes) ?\700))
(setq server-process
(make-network-process
! :name server-name :noquery t :server t
! :service t :host (or server-host 'local)
! :filter 'server-process-filter :sentinel 'server-sentinel
! :plist '(:authenticated nil)
;; We must receive file names without being decoded.
;; Those are decoded by server-process-filter according
;; to file-name-coding-system.
! :coding 'raw-text))
! (unless server-process
! (error "Could not start server process"))
! ;; We must create the server info file, or no one will be able to contact us
! (with-temp-file (expand-file-name server-file)
! (set-buffer-multibyte nil)
! (setq buffer-file-coding-system 'no-conversion)
! (insert (format-network-address (cadr (memq :local
! (process-contact server-process
! t))))
! "\n" (server-auth-string))))))
;;;###autoload
(define-minor-mode server-mode
***************
*** 287,300 ****
;; nothing if there is one (for multiple Emacs sessions)?
(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.
(while (string-match "\n" string)
--- 310,334 ----
;; nothing if there is one (for multiple Emacs sessions)?
(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.
(while (string-match "\n" string)
***************
*** 377,383 ****
(if tmp-frame (delete-frame tmp-frame))))
;; 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)
(goto-line (nth 1 file-line-col))
--- 411,417 ----
(if tmp-frame (delete-frame tmp-frame))))
;; 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)
(goto-line (nth 1 file-line-col))
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.74
diff -c -r1.74 emacsclient.c
*** lib-src/emacsclient.c 4 Jul 2005 15:24:11 -0000 1.74
--- lib-src/emacsclient.c 5 Aug 2005 10:44:55 -0000
***************
*** 20,25 ****
--- 20,28 ----
Boston, MA 02110-1301, USA. */
+ #define AUTH_STRING_LENGTH 64
+ #define SEND_BUFFER_SIZE 4096
+
#define NO_SHORTNAMES
#ifdef HAVE_CONFIG_H
***************
*** 30,45 ****
#include <ctype.h>
#include <stdio.h>
! #include <getopt.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef VMS
! # include "vms-pwd.h"
#else
! # include <pwd.h>
#endif /* not VMS */
char *getenv (), *getwd ();
char *(getcwd) ();
--- 33,53 ----
#include <ctype.h>
#include <stdio.h>
! #include "getopt.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+ #ifdef WINDOWSNT
+ #include <winsock2.h>
+ #else /* not WINDOWSNT */
+ #include <sys/socket.h>
#ifdef VMS
! #include "vms-pwd.h"
#else
! #include <pwd.h>
#endif /* not VMS */
+ #endif /* not WINDOWSNT */
char *getenv (), *getwd ();
char *(getcwd) ();
***************
*** 47,52 ****
--- 55,72 ----
#ifndef VERSION
#define VERSION "unspecified"
#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
+
\f
/* Name used to invoke this program. */
char *progname;
***************
*** 61,71 ****
char *display = NULL;
/* If non-NULL, the name of an editor to fallback to if the server
! is not running. --alternate-editor. */
! const char * alternate_editor = NULL;
! /* If non-NULL, the filename of the UNIX socket. */
! char *socket_name = NULL;
void print_help_and_exit ();
--- 81,96 ----
char *display = NULL;
/* If non-NULL, the name of an editor to fallback to if the server
! is not running. --alternate-editor. */
! const char *alternate_editor = NULL;
! /* If non-NULL, the filename to use as configuration and
! authentication file. --server-file. */
! const char *server_file = NULL;
!
! /* Buffer to accumulate data to send. */
! char send_buffer[SEND_BUFFER_SIZE+1];
! int sblen = 0;
void print_help_and_exit ();
***************
*** 76,82 ****
{ "help", no_argument, NULL, 'H' },
{ "version", no_argument, NULL, 'V' },
{ "alternate-editor", required_argument, NULL, 'a' },
! { "socket-name", required_argument, NULL, 's' },
{ "display", required_argument, NULL, 'd' },
{ 0, 0, 0, 0 }
};
--- 101,107 ----
{ "help", no_argument, NULL, 'H' },
{ "version", no_argument, NULL, 'V' },
{ "alternate-editor", required_argument, NULL, 'a' },
! { "server-file", required_argument, NULL, 's' },
{ "display", required_argument, NULL, 'd' },
{ 0, 0, 0, 0 }
};
***************
*** 90,95 ****
--- 115,121 ----
char **argv;
{
alternate_editor = getenv ("ALTERNATE_EDITOR");
+ server_file = getenv("EMACS_SERVER_FILE");
while (1)
{
***************
*** 111,117 ****
break;
case 's':
! socket_name = optarg;
break;
case 'd':
--- 137,143 ----
break;
case 's':
! server_file = optarg;
break;
case 'd':
***************
*** 157,164 ****
-n, --no-wait Don't wait for the server to return\n\
-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\
\n\
--- 183,190 ----
-n, --no-wait Don't wait for the server to return\n\
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY Visit the file in the given display\n\
! -s, --server-file=FILENAME\n\
! Server configuration and authentication file\n\
-a, --alternate-editor=EDITOR\n\
Editor to fallback to if the server is not running\n\
\n\
***************
*** 166,179 ****
exit (EXIT_SUCCESS);
}
/* 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);
char *p, *q;
--- 192,244 ----
exit (EXIT_SUCCESS);
}
+ \f
+ /* 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);
char *p, *q;
***************
*** 203,227 ****
}
*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
--- 268,278 ----
}
*q++ = 0;
! SEND_STRING (copy);
free (copy);
}
\f
/*
Try to run a different command, or --if no alternate editor is
***************
*** 244,458 ****
}
}
-
\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:
! 2 - can't be `stat'ed (sets errno)
! 1 - isn't owned by us
! 0 - success: none of the above */
! static int
! socket_status (socket_name)
! char *socket_name;
{
! struct stat statbfr;
! if (stat (socket_name, &statbfr) == -1)
! return 2;
! if (statbfr.st_uid != geteuid ())
! return 1;
! return 0;
}
! 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);
}
/*
! * Open up an AF_UNIX socket in this person's home directory
*/
!
! if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
! fprintf (stderr, "%s: ", argv[0]);
perror ("socket");
! fail (argc, argv);
}
! server.sun_family = AF_UNIX;
! {
! int sock_status = 0;
! int default_sock = !socket_name;
! int saved_errno;
! char *server_name = "server";
!
! if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
! { /* socket_name is a file name component. */
! server_name = socket_name;
! socket_name = NULL;
! default_sock = 1; /* Try both UIDs. */
! }
! if (default_sock)
! {
! socket_name = alloca (100 + strlen (server_name));
! sprintf (socket_name, "/tmp/emacs%d/%s",
! (int) geteuid (), server_name);
! }
! if (strlen (socket_name) < sizeof (server.sun_path))
! strcpy (server.sun_path, socket_name);
! else
! {
! fprintf (stderr, "%s: socket-name %s too long",
! argv[0], socket_name);
! exit (EXIT_FAILURE);
! }
! /* See if the socket exists, and if it's owned by us. */
! sock_status = socket_status (server.sun_path);
! saved_errno = errno;
! if (sock_status && default_sock)
! {
! /* Failing that, see if LOGNAME or USER exist and differ from
! our euid. If so, look for a socket based on the UID
! associated with the name. This is reminiscent of the logic
! that init_editfns uses to set the global Vuser_full_name. */
!
! char *user_name = (char *) getenv ("LOGNAME");
!
! if (!user_name)
! user_name = (char *) getenv ("USER");
!
! if (user_name)
! {
! struct passwd *pw = getpwnam (user_name);
!
! if (pw && (pw->pw_uid != geteuid ()))
! {
! /* We're running under su, apparently. */
! socket_name = alloca (100 + strlen (server_name));
! sprintf (socket_name, "/tmp/emacs%d/%s",
! (int) pw->pw_uid, server_name);
!
! if (strlen (socket_name) < sizeof (server.sun_path))
! strcpy (server.sun_path, socket_name);
! else
! {
! fprintf (stderr, "%s: socket-name %s too long",
! argv[0], socket_name);
! exit (EXIT_FAILURE);
! }
!
! sock_status = socket_status (server.sun_path);
! saved_errno = errno;
! }
! else
! errno = saved_errno;
! }
! }
! switch (sock_status)
! {
! case 1:
! /* There's a socket, but it isn't owned by us. This is OK if
! we are root. */
! if (0 != geteuid ())
! {
! fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
! fail (argc, argv);
! }
! break;
!
! case 2:
! /* `stat' failed */
! if (saved_errno == ENOENT)
! fprintf (stderr,
! "%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;
! }
! }
! if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
! < 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);
--- 295,476 ----
}
}
\f
! /* Process options and check some sane defaults. */
! void process_options (argc, argv)
int argc;
! char *argv[];
{
! decode_options (argc, argv);
! if (!server_file)
! {
! fprintf (stderr, "%s: server configuration file required\n", progname);
! goto error;
! }
! if ((argc - optind < 1) && !eval)
! {
! fprintf (stderr, "%s: file name or argument required\n", progname);
! goto error;
! }
! return;
! error:
!
! fprintf (stderr, "Try `%s --help' for more information\n", progname);
! exit (EXIT_FAILURE);
! }
! #ifdef WINDOWSNT
! /* Wrapper to make WSACleanup a cdecl, as required by atexit(). */
! void close_winsock ()
! {
! WSACleanup();
! }
! #endif /* WINDOWSNT */
! void initialize_sockets ()
{
! #ifdef WINDOWSNT
! /* Initialize the WinSock2 library. */
! WSADATA wsaData;
! if (WSAStartup (MAKEWORD (2, 0), &wsaData))
! {
! fprintf (stderr, "%s: error initializing WinSock2", progname);
! exit (EXIT_FAILURE);
! }
! atexit (close_winsock);
! #endif
}
! /*
! * Read the information needed to set up the 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);
+ }
+
+ /*
+ * Perform all required initialization; at the end either the socket
+ * is available and correctly configured, or we've finished with an
+ * error status so the main program can try the alternate editor.
+ */
+ SOCKET
+ set_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;
! }
! /*
! * Force socket to be blocking and SO_LINGER
! */
! ioctlsocket (s, FIONBIO, &c_arg);
! setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
! /*
! * Now, let's send the authentication
! */
! auth_string[AUTH_STRING_LENGTH] = '\0';
! SEND_STRING ("-auth ");
! SEND_STRING (auth_string);
! SEND_STRING ("\n");
! return s;
! }
! \f
! #include <sys/types.h>
! #include <sys/stat.h>
! #include <errno.h>
! extern char *strerror ();
! extern int errno;
! int
! main (argc, argv)
! int argc;
! char **argv;
! {
! SOCKET s;
! int i, rl, needlf = 0;
! char *cwd, *str;
! char string[BUFSIZ+1];
! progname = argv[0];
! process_options (argc, argv);
!
! if ((s = set_socket ()) == INVALID_SOCKET)
! fail (argc, argv);
#ifdef HAVE_GETCWD
cwd = getcwd (string, sizeof string);
***************
*** 464,488 ****
/* getwd puts message in STRING if it fails. */
#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);
}
if (nowait)
! fprintf (out, "-nowait ");
if (eval)
! fprintf (out, "-eval ");
if (display)
{
! fprintf (out, "-display ");
! quote_file_name (display, out);
! fprintf (out, " ");
}
if ((argc - optind > 0))
--- 482,506 ----
/* getwd puts message in STRING if it fails. */
#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);
}
if (nowait)
! SEND_STRING ("-nowait ");
if (eval)
! SEND_STRING ("-eval ");
if (display)
{
! SEND_STRING ("-display ");
! SEND_QUOTED (display);
! SEND_STRING (" ");
}
if ((argc - optind > 0))
***************
*** 497,556 ****
while (isdigit ((unsigned char) *p) || *p == ':') p++;
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)
{
! printf ("Waiting for Emacs...");
! needlf = 2;
! }
! fflush (stdout);
! /* 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';
! }
! if (needlf)
! printf ("\n");
! fflush (stdout);
return EXIT_SUCCESS;
}
- #endif /* HAVE_SOCKETS */
\f
#ifndef HAVE_STRERROR
char *
--- 515,580 ----
while (isdigit ((unsigned char) *p) || *p == ':') p++;
if (*p != 0)
{
! SEND_QUOTED (cwd);
! SEND_STRING ("/");
}
}
! /* Absolute paths can also start with backslash or drive letters. */
! else if ((*argv[i] != '/')
! && (*argv[i] != '\\')
! && (!islower (tolower (*argv[i]))
! || (argv[i][1] != ':')))
{
! SEND_QUOTED (cwd);
! SEND_STRING ("/");
}
! SEND_QUOTED (argv[i]);
! SEND_STRING (" ");
}
}
else
{
while ((str = fgets (string, BUFSIZ, stdin)))
{
! SEND_QUOTED (str);
}
! SEND_STRING (" ");
}
! SEND_STRING ("\n");
! /* Maybe wait for an answer. */
! if (!nowait)
{
! if (!eval)
! {
! printf ("Waiting for Emacs...");
! needlf = 2;
! }
! fflush (stdout);
! /* 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", str);
! needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
! }
! if (needlf)
! printf ("\n");
! fflush (stdout);
! }
+ closesocket (s);
return EXIT_SUCCESS;
+
}
\f
#ifndef HAVE_STRERROR
char *
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.36
diff -c -r2.36 makefile.w32-in
*** lib-src/makefile.w32-in 28 Jul 2005 07:58:52 -0000 2.36
--- lib-src/makefile.w32-in 5 Aug 2005 07:59:08 -0000
***************
*** 19,25 ****
# Boston, MA 02110-1301, USA.
#
! ALL = make-docfile hexl ctags etags movemail ebrowse
.PHONY: $(ALL)
--- 19,25 ----
# Boston, MA 02110-1301, USA.
#
! ALL = make-docfile hexl ctags etags movemail ebrowse emacsclient
.PHONY: $(ALL)
***************
*** 34,40 ****
# $(BLD)/server.exe \
# $(BLD)/emacstool.exe \
# $(BLD)/leditcfns.exe \
- # $(BLD)/emacsclient.exe \
# $(BLD)/cvtmail.exe \
# $(BLD)/digest-doc.exe \
# $(BLD)/test-distrib.exe \
--- 34,39 ----
***************
*** 55,60 ****
--- 54,60 ----
hexl: $(BLD) $(BLD)/hexl.exe
movemail: $(BLD) $(BLD)/movemail.exe
fakemail: $(BLD) $(BLD)/fakemail.exe
+ emacsclient: $(BLD) $(BLD)/emacsclient.exe
GETOPTOBJS = $(BLD)/getopt.$(O) $(BLD)/getopt1.$(O)
GETOPTDEPS = $(GETOPTOBJS) getopt.h
***************
*** 67,72 ****
--- 67,85 ----
# put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
$(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) \
$(BLD)/getopt1.$(O) \
***************
*** 76,82 ****
$(BLD)/etags.exe: $(ETAGSOBJ)
$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ETAGSOBJ) $(LIBS)
-
EBROWSEOBJ = $(BLD)/ebrowse.$(O) \
$(BLD)/getopt.$(O) \
$(BLD)/getopt1.$(O) \
--- 89,94 ----
***************
*** 120,126 ****
# $(BLD)/server.exe: $(BLD)/server.$(O)
# $(BLD)/cvtmail.exe: $(BLD)/cvtmail.$(O)
# $(BLD)/digest-doc.exe: $(BLD)/digest-doc.$(O)
- # $(BLD)/emacsclient.exe: $(BLD)/emacsclient.$(O)
# $(BLD)/test-distrib.exe: $(BLD)/test-distrib.$(O)
#
--- 132,137 ----
***************
*** 130,136 ****
# as it is required by code in doc.c.
#
obj= sunfns.o dosfns.o msdos.o \
! xterm.o xfns.o xmenu.o xselect.o xrdb.o fringe.o image.o \
mac.o macterm.o macfns.o macmenu.o fontset.o \
w32.o w32bdf.o w32console.o w32fns.o w32heap.o w32inevt.o \
w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
--- 141,147 ----
# as it is required by code in doc.c.
#
obj= sunfns.o dosfns.o msdos.o \
! xterm.o xfns.o xmenu.o xselect.o xrdb.o fringe.o image.o \
mac.o macterm.o macfns.o macmenu.o fontset.o \
w32.o w32bdf.o w32console.o w32fns.o w32heap.o w32inevt.o \
w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
***************
*** 277,282 ****
--- 288,294 ----
$(CP) $(BLD)/ctags.exe $(INSTALL_DIR)/bin
$(CP) $(BLD)/hexl.exe $(INSTALL_DIR)/bin
$(CP) $(BLD)/movemail.exe $(INSTALL_DIR)/bin
+ $(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
- mkdir "$(INSTALL_DIR)/etc"
$(CP) $(DOC) $(INSTALL_DIR)/etc
[-- Attachment #3: 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:[~2005-08-05 11:06 UTC|newest]
Thread overview: 120+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-07-15 7:01 w32 does not have emacsclient/server Lennart Borgman
2005-07-15 8:29 ` Jason Rumney
2005-07-15 12:40 ` Lennart Borgman
2005-07-15 15:07 ` David Kastrup
2005-07-15 16:52 ` Lennart Borgman
2005-07-15 18:21 ` Eli Zaretskii
2005-07-16 20:45 ` Richard M. Stallman
2005-07-17 3:33 ` Eli Zaretskii
2005-07-17 17:36 ` Richard M. Stallman
2005-07-17 18:09 ` Eli Zaretskii
2005-07-18 16:33 ` Richard M. Stallman
2005-07-15 8:31 ` David Kastrup
2005-07-15 12:21 ` Lennart Borgman
2005-07-15 12:37 ` David Kastrup
2005-07-15 12:50 ` Lennart Borgman
2005-07-15 15:12 ` David Kastrup
2005-07-15 16:59 ` w32 does not have emacsclient/server - getting paper size Lennart Borgman
2005-07-15 17:13 ` David Kastrup
2005-07-15 17:55 ` Lennart Borgman
2005-07-15 21:20 ` Jason Rumney
2005-07-15 21:39 ` Lennart Borgman
2005-07-15 22:00 ` David Kastrup
2005-07-15 22:13 ` Lennart Borgman
2005-07-15 22:33 ` David Kastrup
2005-07-15 23:07 ` Lennart Borgman
2005-07-16 6:14 ` David Kastrup
2005-07-16 9:46 ` Eli Zaretskii
2005-07-16 11:56 ` David Kastrup
2005-07-17 3:30 ` Eli Zaretskii
2005-07-17 0:59 ` Richard M. Stallman
2005-07-16 9:48 ` Eli Zaretskii
2005-07-15 23:09 ` Jason Rumney
2005-07-15 23:22 ` Lennart Borgman
2005-07-15 23:40 ` Jason Rumney
2005-07-17 0:58 ` Richard M. Stallman
2005-07-16 6:02 ` David Kastrup
2005-07-16 8:31 ` Lennart Borgman
2005-07-16 9:03 ` David Kastrup
2005-07-16 9:39 ` Eli Zaretskii
2005-07-16 9:42 ` Eli Zaretskii
2005-07-16 10:00 ` Eli Zaretskii
2005-07-16 10:28 ` Lennart Borgman
2005-07-16 11:42 ` Jason Rumney
2005-07-16 12:13 ` Eli Zaretskii
2005-07-16 12:44 ` Lennart Borgman
2005-07-16 21:57 ` Jason Rumney
2005-07-16 22:30 ` David Kastrup
2005-07-16 10:58 ` Jason Rumney
2005-07-16 11:07 ` Lennart Borgman
2005-07-16 11:50 ` Jason Rumney
2005-07-16 12:26 ` Eli Zaretskii
2005-07-16 12:53 ` Lennart Borgman
2005-07-16 13:22 ` Eli Zaretskii
2005-07-16 13:36 ` Lennart Borgman
2005-07-16 12:40 ` Lennart Borgman
2005-07-16 13:29 ` Eli Zaretskii
2005-07-16 13:39 ` Lennart Borgman
2005-07-16 21:55 ` Jason Rumney
2005-07-16 12:00 ` David Kastrup
2005-07-17 3:32 ` Eli Zaretskii
2005-07-16 9:54 ` Eli Zaretskii
2005-07-16 10:10 ` Lennart Borgman
2005-07-15 14:33 ` w32 does not have emacsclient/server Jason Rumney
2005-07-15 14:52 ` Lennart Borgman
2005-07-15 15:15 ` David Kastrup
2005-07-15 20:28 ` Stefan Monnier
2005-07-27 14:34 ` Juanma Barranquero
2005-07-27 15:45 ` Jason Rumney
2005-07-27 16:16 ` Juanma Barranquero
2005-07-27 16:31 ` Jason Rumney
2005-07-28 17:20 ` Stefan Monnier
2005-08-05 1:43 ` Juanma Barranquero
2005-08-05 7:59 ` Juanma Barranquero
2005-08-05 9:02 ` Eli Zaretskii
2005-08-05 9:09 ` Juanma Barranquero
2005-08-05 18:50 ` Eli Zaretskii
2005-08-05 23:10 ` Juanma Barranquero
2005-08-06 6:55 ` Eli Zaretskii
2005-08-06 7:12 ` Jason Rumney
2005-08-06 8:10 ` Eli Zaretskii
2005-08-06 9:30 ` Lennart Borgman
2005-08-06 11:08 ` Stephan Stahl
2005-08-06 14:48 ` Eli Zaretskii
2005-08-06 11:21 ` Juanma Barranquero
2005-08-06 14:52 ` Eli Zaretskii
2005-08-05 20:38 ` Richard M. Stallman
2005-08-05 21:34 ` David Kastrup
2005-08-05 23:12 ` Juanma Barranquero
2005-08-05 23:48 ` Lennart Borgman
2005-08-06 0:02 ` Juanma Barranquero
2005-08-06 6:58 ` Eli Zaretskii
2005-08-06 11:20 ` Juanma Barranquero
2005-08-06 12:43 ` David Kastrup
2005-08-06 13:43 ` Juanma Barranquero
2005-08-06 17:45 ` Jason Rumney
2005-08-06 17:54 ` Juanma Barranquero
2005-08-06 6:59 ` David Kastrup
2005-08-06 13:45 ` Juanma Barranquero
2005-08-06 14:03 ` David Kastrup
2005-08-07 17:15 ` Richard M. Stallman
2005-08-07 20:31 ` Juanma Barranquero
2005-08-09 0:26 ` Richard M. Stallman
2005-08-09 0:39 ` Juanma Barranquero
2005-08-06 18:35 ` Richard M. Stallman
2005-08-06 18:44 ` Juanma Barranquero
2005-08-05 11:06 ` Juanma Barranquero [this message]
2005-08-08 23:49 ` Stefan Monnier
2005-08-09 0:12 ` Juanma Barranquero
2005-08-10 0:42 ` Stefan Monnier
2005-08-09 0:19 ` Juanma Barranquero
2005-08-10 0:49 ` Stefan Monnier
2005-08-10 0:58 ` Juanma Barranquero
2005-07-15 15:13 ` Juanma Barranquero
2005-07-15 15:48 ` David Kastrup
2005-07-18 6:22 ` Juanma Barranquero
2005-07-15 17:15 ` Lennart Borgman
2005-07-15 23:24 ` Robert J. Chassell
2005-07-15 17:53 ` Guy Gascoigne - Piggford
-- strict thread matches above, loose matches on Subject: below --
2005-07-15 15:36 klaus.berndl
2005-07-16 13:28 ` 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=f7ccd24b05080504067533ad37@mail.gmail.com \
--to=lekktu@gmail.com \
--cc=emacs-devel@gnu.org \
/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).