all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
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

  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

* 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 external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.