server.el (server-visit-files): Run pre-command-hook and
[bpt/emacs.git] / lisp / server.el
index e06fb03..f0e88d0 100644 (file)
@@ -1,7 +1,8 @@
 ;;; server.el --- Lisp code for GNU Emacs running as server process
 
 ;; Copyright (C) 1986, 1987, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: William Sommerfeld <wesommer@athena.mit.edu>
 ;; Maintainer: FSF
@@ -112,7 +113,12 @@ If set, the server accepts remote connections; otherwise it is local."
 (put 'server-host 'risky-local-variable t)
 
 (defcustom server-auth-dir (locate-user-emacs-file "server/")
-  "Directory for server authentication files."
+  "Directory for server authentication files.
+
+NOTE: On FAT32 filesystems, directories are not secure;
+files can be read and modified by any user or process.
+It is strongly suggested to set `server-auth-dir' to a
+directory residing in a NTFS partition instead."
   :group 'server
   :type 'directory
   :version "22.1")
@@ -338,7 +344,8 @@ If CLIENT is non-nil, add a description of it to the logged message."
   ;; for possible servers before doing anything, so it *should* be ours.
   (and (process-contact proc :server)
        (eq (process-status proc) 'closed)
-       (ignore-errors (delete-file (process-get proc :server-file))))
+       (ignore-errors
+       (delete-file (process-get proc :server-file))))
   (server-log (format "Status changed to %s: %s" (process-status proc) msg) proc)
   (server-delete-client proc))
 
@@ -448,15 +455,35 @@ Creates the directory if necessary and makes sure:
 - it's owned by us
 - it's not readable/writable by anybody else."
   (setq dir (directory-file-name dir))
-  (let ((attrs (file-attributes dir)))
+  (let ((attrs (file-attributes dir 'integer)))
     (unless attrs
       (letf (((default-file-modes) ?\700)) (make-directory dir t))
-      (setq attrs (file-attributes dir)))
+      (setq attrs (file-attributes dir 'integer)))
+
     ;; Check that it's safe for use.
-    (unless (and (eq t (car attrs)) (eql (nth 2 attrs) (user-uid))
-                 (or (eq system-type 'windows-nt)
-                     (zerop (logand ?\077 (file-modes dir)))))
-      (error "The directory %s is unsafe" dir))))
+    (let* ((uid (nth 2 attrs))
+          (w32 (eq system-type 'windows-nt))
+          (safe (catch :safe
+                  (unless (eq t (car attrs))   ; is a dir?
+                    (throw :safe nil))
+                  (when (and w32 (zerop uid))  ; on FAT32?
+                    (display-warning
+                     'server
+                     (format "Using `%s' to store Emacs-server authentication files.
+Directories on FAT32 filesystems are NOT secure against tampering.
+See variable `server-auth-dir' for details."
+                             (file-name-as-directory dir))
+                     :warning)
+                    (throw :safe t))
+                  (unless (eql uid (user-uid)) ; is the dir ours?
+                    (throw :safe nil))
+                  (when w32                    ; on NTFS?
+                    (throw :safe t))
+                  (unless (zerop (logand ?\077 (file-modes dir)))
+                    (throw :safe nil))
+                  t)))
+      (unless safe
+       (error "The directory `%s' is unsafe" dir)))))
 
 ;;;###autoload
 (defun server-start (&optional leave-dead)
@@ -491,7 +518,9 @@ To force-start a server, do \\[server-force-delete] and then
       ;; Delete the socket files made by previous server invocations.
       (if (not (eq t (server-running-p server-name)))
          ;; Remove any leftover socket or authentication file
-         (ignore-errors (delete-file server-file))
+         (ignore-errors
+          (let (delete-by-moving-to-trash)
+            (delete-file server-file)))
        (setq server-mode nil) ;; already set by the minor mode code
        (display-warning
         'server
@@ -534,9 +563,9 @@ server or call `M-x server-force-delete' to forcibly disconnect it.")
                       :coding 'raw-text-unix
                       ;; The other args depend on the kind of socket used.
                       (if server-use-tcp
-                          (list :family nil
+                          (list :family 'ipv4  ;; We're not ready for IPv6 yet
                                 :service t
-                                :host (or server-host 'local)
+                                :host (or server-host "127.0.0.1") ;; See bug#6781
                                 :plist '(:authenticated nil))
                         (list :family 'local
                               :service server-file
@@ -548,7 +577,7 @@ server or call `M-x server-force-delete' to forcibly disconnect it.")
                   (loop
                      ;; The auth key is a 64-byte string of random chars in the
                      ;; range `!'..`~'.
-                     for i below 64
+                     repeat 64
                      collect (+ 33 (random 94)) into auth
                      finally return (concat auth))))
              (process-put server-process :auth-key auth-key)
@@ -574,7 +603,7 @@ NAME defaults to `server-name'.  With argument, ask for NAME."
                                    server-auth-dir
                                  server-socket-dir))))
     (condition-case nil
-       (progn
+       (let (delete-by-moving-to-trash)
          (delete-file file)
          (message "Connection file %S deleted" file))
       (file-error
@@ -682,7 +711,7 @@ Server mode runs a process that accepts commands from the
                                      (number-to-string (emacs-pid)) "\n"))
     frame))
 
-(defun server-create-window-system-frame (display nowait proc)
+(defun server-create-window-system-frame (display nowait proc parent-id)
   (add-to-list 'frame-inherited-parameters 'client)
   (if (not (fboundp 'make-frame-on-display))
       (progn
@@ -698,12 +727,14 @@ Server mode runs a process that accepts commands from the
     (let* ((params `((client . ,(if nowait 'nowait proc))
                      ;; This is a leftover, see above.
                      (environment . ,(process-get proc 'env))))
-           (frame (make-frame-on-display
-                   (or display
-                       (frame-parameter nil 'display)
-                       (getenv "DISPLAY")
-                       (error "Please specify display"))
-                   params)))
+          (display (or display
+                       (frame-parameter nil 'display)
+                       (getenv "DISPLAY")
+                       (error "Please specify display")))
+          frame)
+      (if parent-id
+         (push (cons 'parent-id (string-to-number parent-id)) params))
+      (setq frame (make-frame-on-display display params))
       (server-log (format "%s created" frame) proc)
       (select-frame frame)
       (process-put proc 'frame frame)
@@ -868,18 +899,19 @@ The following commands are accepted by the client:
           ;; supported any more.
           (assert (eq (match-end 0) (length string)))
          (let ((request (substring string 0 (match-beginning 0)))
-               (coding-system (and default-enable-multibyte-characters
+               (coding-system (and (default-value 'enable-multibyte-characters)
                                    (or file-name-coding-system
                                        default-file-name-coding-system)))
-               nowait ; t if emacsclient does not want to wait for us.
-               frame ; The frame that was opened for the client (if any).
-               display              ; Open the frame on this display.
-               dontkill       ; t if the client should not be killed.
+               nowait     ; t if emacsclient does not want to wait for us.
+               frame      ; Frame opened for the client (if any).
+               display    ; Open frame on this display.
+               parent-id  ; Window ID for XEmbed
+               dontkill   ; t if client should not be killed.
                commands
                dir
                use-current-frame
-               tty-name       ;nil, `window-system', or the tty name.
-               tty-type             ;string.
+               tty-name   nil, `window-system', or the tty name.
+               tty-type   string.
                files
                filepos
                command-line-args-left
@@ -906,6 +938,12 @@ The following commands are accepted by the client:
                  (setq display (pop command-line-args-left))
                   (if (zerop (length display)) (setq display nil)))
 
+                ;; -parent-id ID:
+                ;; Open X frame within window ID, via XEmbed.
+                ((and (equal "-parent-id" arg) command-line-args-left)
+                 (setq parent-id (pop command-line-args-left))
+                  (if (zerop (length parent-id)) (setq parent-id nil)))
+
                 ;; -window-system:  Open a new X frame.
                 ((equal "-window-system" arg)
                   (setq dontkill t)
@@ -1010,7 +1048,8 @@ The following commands are accepted by the client:
                    (setq tty-name nil tty-type nil)
                    (if display (server-select-display display)))
                   ((eq tty-name 'window-system)
-                   (server-create-window-system-frame display nowait proc))
+                   (server-create-window-system-frame display nowait proc
+                                                      parent-id))
                   ;; When resuming on a tty, tty-name is nil.
                   (tty-name
                    (server-create-tty-frame tty-name tty-type proc))))
@@ -1054,9 +1093,7 @@ The following commands are accepted by the client:
     (condition-case err
         (let* ((buffers
                 (when files
-                  (run-hooks 'pre-command-hook)
-                  (prog1 (server-visit-files files proc nowait)
-                    (run-hooks 'post-command-hook)))))
+                  (server-visit-files files proc nowait))))
 
           (mapc 'funcall (nreverse commands))
 
@@ -1098,7 +1135,8 @@ The following commands are accepted by the client:
   "Move point to the position indicated in LINE-COL.
 LINE-COL should be a pair (LINE . COL)."
   (when line-col
-    (goto-line (car line-col))
+    (goto-char (point-min))
+    (forward-line (1- (car line-col)))
     (let ((column-number (cdr line-col)))
       (when (> column-number 0)
         (move-to-column (1- column-number))))))
@@ -1126,8 +1164,13 @@ so don't mark these buffers specially, just visit them normally."
               (obuf (get-file-buffer filen)))
          (add-to-history 'file-name-history filen)
          (if (null obuf)
-              (set-buffer (find-file-noselect filen))
+             (progn
+               (run-hooks 'pre-command-hook)  
+               (set-buffer (find-file-noselect filen)))
             (set-buffer obuf)
+           ;; separately for each file, in sync with post-command hooks,
+           ;; with the new buffer current:
+           (run-hooks 'pre-command-hook)  
             (cond ((file-exists-p filen)
                    (when (not (verify-visited-file-modtime obuf))
                      (revert-buffer t nil)))
@@ -1139,7 +1182,9 @@ so don't mark these buffers specially, just visit them normally."
             (unless server-buffer-clients
               (setq server-existing-buffer t)))
           (server-goto-line-column (cdr file))
-          (run-hooks 'server-visit-hook))
+          (run-hooks 'server-visit-hook)
+         ;; hooks may be specific to current buffer:
+         (run-hooks 'post-command-hook)) 
        (unless nowait
          ;; When the buffer is killed, inform the clients.
          (add-hook 'kill-buffer-hook 'server-kill-buffer nil t)