/[emacs]/emacs/lisp/net/tramp.el
ViewVC logotype

Diff of /emacs/lisp/net/tramp.el

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.39.2.4 by miles, Sat Jul 17 02:46:47 2004 UTC revision 1.39.2.5 by miles, Fri Jul 23 04:30:38 2004 UTC
# Line 916  The answer will be provided by `tramp-ac Line 916  The answer will be provided by `tramp-ac
916    "Regular expression indicating a process has finished.    "Regular expression indicating a process has finished.
917  In fact this expression is empty by intention, it will be used only to  In fact this expression is empty by intention, it will be used only to
918  check regularly the status of the associated process.  check regularly the status of the associated process.
919  The answer will be provided by `tramp-action-process-alive' and  The answer will be provided by `tramp-action-process-alive',
920  `tramp-action-out-of-band', which see."  `tramp-multi-action-process-alive' and`tramp-action-out-of-band', which see."
921    :group 'tramp    :group 'tramp
922    :type 'regexp)    :type 'regexp)
923    
# Line 1321  See `tramp-actions-before-shell' for mor Line 1321  See `tramp-actions-before-shell' for mor
1321      (shell-prompt-pattern tramp-multi-action-succeed)      (shell-prompt-pattern tramp-multi-action-succeed)
1322      (tramp-shell-prompt-pattern tramp-multi-action-succeed)      (tramp-shell-prompt-pattern tramp-multi-action-succeed)
1323      (tramp-wrong-passwd-regexp tramp-multi-action-permission-denied)      (tramp-wrong-passwd-regexp tramp-multi-action-permission-denied)
1324      (tramp-process-alive-regexp tramp-action-process-alive))      (tramp-process-alive-regexp tramp-multi-action-process-alive))
1325    "List of pattern/action pairs.    "List of pattern/action pairs.
1326  This list is used for each hop in multi-hop connections.  This list is used for each hop in multi-hop connections.
1327  See `tramp-actions-before-shell' for more info."  See `tramp-actions-before-shell' for more info."
# Line 2165  target of the symlink differ." Line 2165  target of the symlink differ."
2165    (let ((nonnumeric (and id-format (equal id-format 'string)))    (let ((nonnumeric (and id-format (equal id-format 'string)))
2166          result)          result)
2167      (with-parsed-tramp-file-name filename nil      (with-parsed-tramp-file-name filename nil
2168        (when (tramp-handle-file-exists-p filename)        (when (file-exists-p filename)
2169          ;; file exists, find out stuff          ;; file exists, find out stuff
2170          (save-excursion          (save-excursion
2171            (if (tramp-get-remote-perl multi-method method user host)            (if (tramp-get-remote-perl multi-method method user host)
# Line 2331  If it doesn't exist, generate a new one. Line 2331  If it doesn't exist, generate a new one.
2331  ;; This function makes the same assumption as  ;; This function makes the same assumption as
2332  ;; `tramp-handle-set-visited-file-modtime'.  ;; `tramp-handle-set-visited-file-modtime'.
2333  (defun tramp-handle-verify-visited-file-modtime (buf)  (defun tramp-handle-verify-visited-file-modtime (buf)
2334    "Like `verify-visited-file-modtime' for tramp files."    "Like `verify-visited-file-modtime' for tramp files.
2335    At the time `verify-visited-file-modtime' calls this function, we
2336    already know that the buffer is visiting a file and that
2337    `visited-file-modtime' does not return 0.  Do not call this
2338    function directly, unless those two cases are already taken care
2339    of."
2340    (with-current-buffer buf    (with-current-buffer buf
2341      (let ((f (buffer-file-name)))      (let ((f (buffer-file-name)))
2342        (with-parsed-tramp-file-name f nil        (with-parsed-tramp-file-name f nil
# Line 2509  if the remote host can't provide the mod Line 2514  if the remote host can't provide the mod
2514  (defun tramp-handle-file-writable-p (filename)  (defun tramp-handle-file-writable-p (filename)
2515    "Like `file-writable-p' for tramp files."    "Like `file-writable-p' for tramp files."
2516    (with-parsed-tramp-file-name filename nil    (with-parsed-tramp-file-name filename nil
2517      (if (tramp-handle-file-exists-p filename)      (if (file-exists-p filename)
2518          ;; Existing files must be writable.          ;; Existing files must be writable.
2519          (zerop (tramp-run-test "-w" filename))          (zerop (tramp-run-test "-w" filename))
2520        ;; If file doesn't exist, check if directory is writable.        ;; If file doesn't exist, check if directory is writable.
2521        (and (zerop (tramp-run-test        (and (zerop (tramp-run-test
2522                     "-d" (tramp-handle-file-name-directory filename)))                     "-d" (file-name-directory filename)))
2523             (zerop (tramp-run-test             (zerop (tramp-run-test
2524                     "-w" (tramp-handle-file-name-directory filename)))))))                     "-w" (file-name-directory filename)))))))
2525    
2526  (defun tramp-handle-file-ownership-preserved-p (filename)  (defun tramp-handle-file-ownership-preserved-p (filename)
2527    "Like `file-ownership-preserved-p' for tramp files."    "Like `file-ownership-preserved-p' for tramp files."
2528    (with-parsed-tramp-file-name filename nil    (with-parsed-tramp-file-name filename nil
2529      (or (not (tramp-handle-file-exists-p filename))      (or (not (file-exists-p filename))
2530          ;; Existing files must be writable.          ;; Existing files must be writable.
2531          (zerop (tramp-run-test "-O" filename)))))          (zerop (tramp-run-test "-O" filename)))))
2532    
# Line 3064  This is like `dired-recursive-delete-dir Line 3069  This is like `dired-recursive-delete-dir
3069    (with-parsed-tramp-file-name filename nil    (with-parsed-tramp-file-name filename nil
3070      ;; run a shell command 'rm -r <localname>'      ;; run a shell command 'rm -r <localname>'
3071      ;; Code shamelessly stolen for the dired implementation and, um, hacked :)      ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
3072      (or (tramp-handle-file-exists-p filename)      (or (file-exists-p filename)
3073          (signal          (signal
3074           'file-error           'file-error
3075           (list "Removing old file name" "no such directory" filename)))           (list "Removing old file name" "no such directory" filename)))
# Line 3075  This is like `dired-recursive-delete-dir Line 3080  This is like `dired-recursive-delete-dir
3080      ;; This might take a while, allow it plenty of time.      ;; This might take a while, allow it plenty of time.
3081      (tramp-wait-for-output 120)      (tramp-wait-for-output 120)
3082      ;; Make sure that it worked...      ;; Make sure that it worked...
3083      (and (tramp-handle-file-exists-p filename)      (and (file-exists-p filename)
3084           (error "Failed to recusively delete %s" filename))))           (error "Failed to recusively delete %s" filename))))
3085                    
3086  (defun tramp-handle-dired-call-process (program discard &rest arguments)  (defun tramp-handle-dired-call-process (program discard &rest arguments)
# Line 3607  This will break if COMMAND prints a newl Line 3612  This will break if COMMAND prints a newl
3612    
3613  (defun tramp-handle-find-backup-file-name (filename)  (defun tramp-handle-find-backup-file-name (filename)
3614    "Like `find-backup-file-name' for tramp files."    "Like `find-backup-file-name' for tramp files."
3615      (with-parsed-tramp-file-name filename nil
3616        ;; We set both variables. It doesn't matter whether it is
3617        ;; Emacs or XEmacs
3618        (let ((backup-directory-alist
3619               ;; Emacs case
3620               (when (boundp 'backup-directory-alist)
3621                 (if (boundp 'tramp-backup-directory-alist)
3622                     (mapcar
3623                      '(lambda (x)
3624                         (cons
3625                          (car x)
3626                          (if (and (stringp (cdr x))
3627                                   (file-name-absolute-p (cdr x))
3628                                   (not (tramp-file-name-p (cdr x))))
3629                              (tramp-make-tramp-file-name
3630                               multi-method method user host (cdr x))
3631                            (cdr x))))
3632                      (symbol-value 'tramp-backup-directory-alist))
3633                   (symbol-value 'backup-directory-alist))))
3634    
3635              (bkup-backup-directory-info
3636               ;; XEmacs case
3637               (when (boundp 'bkup-backup-directory-info)
3638                 (if (boundp 'tramp-bkup-backup-directory-info)
3639                     (mapcar
3640                      '(lambda (x)
3641                         (nconc
3642                          (list (car x))
3643                          (list
3644                           (if (and (stringp (car (cdr x)))
3645                                    (file-name-absolute-p (car (cdr x)))
3646                                    (not (tramp-file-name-p (car (cdr x)))))
3647                               (tramp-make-tramp-file-name
3648                                multi-method method user host (car (cdr x)))
3649                             (car (cdr x))))
3650                          (cdr (cdr x))))
3651                      (symbol-value 'tramp-bkup-backup-directory-info))
3652                   (symbol-value 'bkup-backup-directory-info)))))
3653    
3654    (if (or (and (not (featurep 'xemacs))        (tramp-run-real-handler 'find-backup-file-name (list filename)))))
                (not (boundp 'tramp-backup-directory-alist)))  
           (and (featurep 'xemacs)  
                (not (boundp 'tramp-bkup-backup-directory-info))))  
   
       ;; No tramp backup directory alist defined, or nil  
       (tramp-run-real-handler 'find-backup-file-name (list filename))  
   
     (with-parsed-tramp-file-name filename nil  
       (let* ((backup-var  
               (copy-tree  
                (if (featurep 'xemacs)  
                    ;; XEmacs case  
                    (symbol-value 'tramp-bkup-backup-directory-info)  
                  ;; Emacs case  
                  (symbol-value 'tramp-backup-directory-alist))))  
   
              ;; We set both variables. It doesn't matter whether it is  
              ;; Emacs or XEmacs  
              (backup-directory-alist backup-var)  
              (bkup-backup-directory-info backup-var))  
   
         (mapcar  
          '(lambda (x)  
             (let ((dir (if (consp (cdr x)) (car (cdr x)) (cdr x))))  
               (when (and (stringp dir)  
                          (file-name-absolute-p dir)  
                          (not (tramp-file-name-p dir)))  
                 ;; Prepend absolute directory names with tramp prefix  
                 (if (consp (cdr x))  
                     (setcar (cdr x)  
                             (tramp-make-tramp-file-name  
                              multi-method method user host dir))  
                   (setcdr x (tramp-make-tramp-file-name  
                              multi-method method user host dir))))))  
          backup-var)  
3655    
         (tramp-run-real-handler 'find-backup-file-name (list filename))))))  
3656    
3657  ;; CCC grok APPEND, LOCKNAME, CONFIRM  ;; CCC grok APPEND, LOCKNAME, CONFIRM
3658  (defun tramp-handle-write-region  (defun tramp-handle-write-region
# Line 3689  This will break if COMMAND prints a newl Line 3696  This will break if COMMAND prints a newl
3696        ;; use an encoding function, but currently we use it always        ;; use an encoding function, but currently we use it always
3697        ;; because this makes the logic simpler.        ;; because this makes the logic simpler.
3698        (setq tmpfil (tramp-make-temp-file))        (setq tmpfil (tramp-make-temp-file))
3699          ;; Set current buffer.  If connection wasn't open, `file-modes' has
3700          ;; changed it accidently.
3701          (set-buffer curbuf)
3702        ;; We say `no-message' here because we don't want the visited file        ;; We say `no-message' here because we don't want the visited file
3703        ;; modtime data to be clobbered from the temp file.  We call        ;; modtime data to be clobbered from the temp file.  We call
3704        ;; `set-visited-file-modtime' ourselves later on.        ;; `set-visited-file-modtime' ourselves later on.
# Line 3972  Falls back to normal file name handler i Line 3982  Falls back to normal file name handler i
3982         (foreign (apply foreign operation args))         (foreign (apply foreign operation args))
3983         (t (tramp-run-real-handler operation args))))))         (t (tramp-run-real-handler operation args))))))
3984    
3985    
3986    ;; In Emacs, there is some concurrency due to timers.  If a timer
3987    ;; interrupts Tramp and wishes to use the same connection buffer as
3988    ;; the "main" Emacs, then garbage might occur in the connection
3989    ;; buffer.  Therefore, we need to make sure that a timer does not use
3990    ;; the same connection buffer as the "main" Emacs.  We implement a
3991    ;; cheap global lock, instead of locking each connection buffer
3992    ;; separately.  The global lock is based on two variables,
3993    ;; `tramp-locked' and `tramp-locker'.  `tramp-locked' is set to true
3994    ;; (with setq) to indicate a lock.  But Tramp also calls itself during
3995    ;; processing of a single file operation, so we need to allow
3996    ;; recursive calls.  That's where the `tramp-locker' variable comes in
3997    ;; -- it is let-bound to t during the execution of the current
3998    ;; handler.  So if `tramp-locked' is t and `tramp-locker' is also t,
3999    ;; then we should just proceed because we have been called
4000    ;; recursively.  But if `tramp-locker' is nil, then we are a timer
4001    ;; interrupting the "main" Emacs, and then we signal an error.
4002    
4003    (defvar tramp-locked nil
4004      "If non-nil, then Tramp is currently busy.
4005    Together with `tramp-locker', this implements a locking mechanism
4006    preventing reentrant calls of Tramp.")
4007    
4008    (defvar tramp-locker nil
4009      "If non-nil, then a caller has locked Tramp.
4010    Together with `tramp-locked', this implements a locking mechanism
4011    preventing reentrant calls of Tramp.")
4012    
4013  (defun tramp-sh-file-name-handler (operation &rest args)  (defun tramp-sh-file-name-handler (operation &rest args)
4014    "Invoke remote-shell Tramp file name handler.    "Invoke remote-shell Tramp file name handler.
4015  Fall back to normal file name handler if no Tramp handler exists."  Fall back to normal file name handler if no Tramp handler exists."
4016    (save-match-data    (when (and tramp-locked (not tramp-locker))
4017      (let ((fn (assoc operation tramp-file-name-handler-alist)))      (signal 'file-error "Forbidden reentrant call of Tramp"))
4018        (if fn    (let ((tl tramp-locked))
4019            (apply (cdr fn) args)      (unwind-protect
4020          (tramp-run-real-handler operation args)))))          (progn
4021              (setq tramp-locked t)
4022              (let ((tramp-locker t))
4023                (save-match-data
4024                  (let ((fn (assoc operation tramp-file-name-handler-alist)))
4025                    (if fn
4026                        (apply (cdr fn) args)
4027                      (tramp-run-real-handler operation args))))))
4028          (setq tramp-locked tl))))
4029    
4030  ;;;###autoload  ;;;###autoload
4031  (defun tramp-completion-file-name-handler (operation &rest args)  (defun tramp-completion-file-name-handler (operation &rest args)
# Line 4062  necessary anymore." Line 4108  necessary anymore."
4108                               (tramp-make-tramp-file-name multi-method method                               (tramp-make-tramp-file-name multi-method method
4109                                                           user host x)))                                                           user host x)))
4110                   (read (current-buffer))))))                   (read (current-buffer))))))
4111          (list (tramp-handle-expand-file-name name))))))          (list (expand-file-name name))))))
4112    
4113  ;; Check for complete.el and override PC-expand-many-files if appropriate.  ;; Check for complete.el and override PC-expand-many-files if appropriate.
4114  (eval-and-compile  (eval-and-compile
# Line 4073  necessary anymore." Line 4119  necessary anymore."
4119          (symbol-function 'PC-expand-many-files))          (symbol-function 'PC-expand-many-files))
4120    (defun PC-expand-many-files (name)    (defun PC-expand-many-files (name)
4121      (if (tramp-tramp-file-p name)      (if (tramp-tramp-file-p name)
4122          (tramp-handle-expand-many-files name)          (expand-many-files name)
4123        (tramp-save-PC-expand-many-files name))))        (tramp-save-PC-expand-many-files name))))
4124    
4125  ;; Why isn't eval-after-load sufficient?  ;; Why isn't eval-after-load sufficient?
# Line 4824  file exists and nonzero exit status othe Line 4870  file exists and nonzero exit status othe
4870      ;; `/usr/bin/test -e'       In case `/bin/test' does not exist.      ;; `/usr/bin/test -e'       In case `/bin/test' does not exist.
4871      (unless (or      (unless (or
4872               (and (setq tramp-file-exists-command "test -e %s")               (and (setq tramp-file-exists-command "test -e %s")
4873                    (tramp-handle-file-exists-p existing)                    (file-exists-p existing)
4874                    (not (tramp-handle-file-exists-p nonexisting)))                    (not (file-exists-p nonexisting)))
4875               (and (setq tramp-file-exists-command "/bin/test -e %s")               (and (setq tramp-file-exists-command "/bin/test -e %s")
4876                    (tramp-handle-file-exists-p existing)                    (file-exists-p existing)
4877                    (not (tramp-handle-file-exists-p nonexisting)))                    (not (file-exists-p nonexisting)))
4878               (and (setq tramp-file-exists-command "/usr/bin/test -e %s")               (and (setq tramp-file-exists-command "/usr/bin/test -e %s")
4879                    (tramp-handle-file-exists-p existing)                    (file-exists-p existing)
4880                    (not (tramp-handle-file-exists-p nonexisting)))                    (not (file-exists-p nonexisting)))
4881               (and (setq tramp-file-exists-command "ls -d %s")               (and (setq tramp-file-exists-command "ls -d %s")
4882                    (tramp-handle-file-exists-p existing)                    (file-exists-p existing)
4883                    (not (tramp-handle-file-exists-p nonexisting))))                    (not (file-exists-p nonexisting))))
4884        (error "Couldn't find command to check if file exists."))))        (error "Couldn't find command to check if file exists."))))
4885            
4886    
# Line 4896  file exists and nonzero exit status othe Line 4942  file exists and nonzero exit status othe
4942  METHOD, USER and HOST specify the connection, CMD (the absolute file name of)  METHOD, USER and HOST specify the connection, CMD (the absolute file name of)
4943  the `ls' executable.  Returns t if CMD supports the `-n' option, nil  the `ls' executable.  Returns t if CMD supports the `-n' option, nil
4944  otherwise."  otherwise."
4945    (tramp-message 9 "Checking remote `%s' command for `-n' option"    (tramp-message 9 "Checking remote `%s' command for `-n' option" cmd)
4946                 cmd)    (when (file-executable-p
   (when (tramp-handle-file-executable-p  
4947           (tramp-make-tramp-file-name multi-method method user host cmd))           (tramp-make-tramp-file-name multi-method method user host cmd))
4948      (let ((result nil))      (let ((result nil))
4949        (tramp-message 7 "Testing remote command `%s' for -n..." cmd)        (tramp-message 7 "Testing remote command `%s' for -n..." cmd)
# Line 4956  Returns nil if none was found, else the Line 5001  Returns nil if none was found, else the
5001    "Query the user for a password."    "Query the user for a password."
5002    (let ((pw-prompt (match-string 0)))    (let ((pw-prompt (match-string 0)))
5003      (tramp-message 9 "Sending password")      (tramp-message 9 "Sending password")
5004      (tramp-enter-password p pw-prompt)))      (tramp-enter-password p pw-prompt user host)))
5005    
5006  (defun tramp-action-succeed (p multi-method method user host)  (defun tramp-action-succeed (p multi-method method user host)
5007    "Signal success in finding shell prompt."    "Signal success in finding shell prompt."
# Line 5034  The terminal type can be configured with Line 5079  The terminal type can be configured with
5079  (defun tramp-multi-action-password (p method user host)  (defun tramp-multi-action-password (p method user host)
5080    "Query the user for a password."    "Query the user for a password."
5081    (tramp-message 9 "Sending password")    (tramp-message 9 "Sending password")
5082    (tramp-enter-password p (match-string 0)))    (tramp-enter-password p (match-string 0) user host))
5083    
5084  (defun tramp-multi-action-succeed (p method user host)  (defun tramp-multi-action-succeed (p method user host)
5085    "Signal success in finding shell prompt."    "Signal success in finding shell prompt."
# Line 5049  The terminal type can be configured with Line 5094  The terminal type can be configured with
5094    (erase-buffer)    (erase-buffer)
5095    (throw 'tramp-action 'permission-denied))    (throw 'tramp-action 'permission-denied))
5096    
5097    (defun tramp-multi-action-process-alive (p method user host)
5098      "Check whether a process has finished."
5099      (unless (memq (process-status p) '(run open))
5100        (throw 'tramp-action 'process-died)))
5101    
5102  ;; Functions for processing the actions.  ;; Functions for processing the actions.
5103    
5104  (defun tramp-process-one-action (p multi-method method user host actions)  (defun tramp-process-one-action (p multi-method method user host actions)
# Line 5246  arguments, and xx will be used as the ho Line 5296  arguments, and xx will be used as the ho
5296            (login-args (tramp-get-method-parameter            (login-args (tramp-get-method-parameter
5297                       multi-method                       multi-method
5298                       (tramp-find-method multi-method method user host)                       (tramp-find-method multi-method method user host)
5299                       user host 'tramp-login-args)))                       user host 'tramp-login-args))
5300              (real-host host))
5301        ;; The following should be changed.  We need a more general        ;; The following should be changed.  We need a more general
5302        ;; mechanism to parse extra host args.        ;; mechanism to parse extra host args.
5303        (when (string-match "\\([^#]*\\)#\\(.*\\)" host)        (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
5304          (setq login-args (cons "-p" (cons (match-string 2 host) login-args)))          (setq login-args (cons "-p" (cons (match-string 2 host) login-args)))
5305          (setq host (match-string 1 host)))          (setq real-host (match-string 1 host)))
5306        (setenv "TERM" tramp-terminal-type)        (setenv "TERM" tramp-terminal-type)
5307        (let* ((default-directory (tramp-temporary-file-directory))        (let* ((default-directory (tramp-temporary-file-directory))
5308               ;; If we omit the conditional, we would use               ;; If we omit the conditional, we would use
# Line 5262  arguments, and xx will be used as the ho Line 5313  arguments, and xx will be used as the ho
5313                                         tramp-dos-coding-system))                                         tramp-dos-coding-system))
5314               (p (if (and user (not (string= user "")))               (p (if (and user (not (string= user "")))
5315                      (apply #'start-process bufnam buf login-program                        (apply #'start-process bufnam buf login-program  
5316                             host "-l" user login-args)                             real-host "-l" user login-args)
5317                    (apply #'start-process bufnam buf login-program                    (apply #'start-process bufnam buf login-program
5318                           host login-args)))                           real-host login-args)))
5319               (found nil))               (found nil))
5320          (tramp-set-process-query-on-exit-flag p nil)          (tramp-set-process-query-on-exit-flag p nil)
5321    
# Line 5547  seconds.  If not, it produces an error m Line 5598  seconds.  If not, it produces an error m
5598      (pop-to-buffer (buffer-name))      (pop-to-buffer (buffer-name))
5599      (apply 'error error-args)))      (apply 'error error-args)))
5600    
5601  (defun tramp-enter-password (p prompt)  (defun tramp-enter-password (p prompt user host)
5602    "Prompt for a password and send it to the remote end.    "Prompt for a password and send it to the remote end.
5603  Uses PROMPT as a prompt and sends the password to process P."  Uses PROMPT as a prompt and sends the password to process P."
5604    (let ((pw (tramp-read-passwd prompt)))    (let ((pw (tramp-read-passwd user host prompt)))
5605      (erase-buffer)      (erase-buffer)
5606      (process-send-string      (process-send-string
5607       p (concat pw       p (concat pw
# Line 6717  this is the function `temp-directory'." Line 6768  this is the function `temp-directory'."
6768                              "`temp-directory' is defined -- using /tmp."))                              "`temp-directory' is defined -- using /tmp."))
6769             (file-name-as-directory "/tmp"))))             (file-name-as-directory "/tmp"))))
6770    
6771  (defun tramp-read-passwd (prompt)  (defun tramp-read-passwd (user host prompt)
6772    "Read a password from user (compat function).    "Read a password from user (compat function).
6773  Invokes `password-read' if available, `read-passwd' else."  Invokes `password-read' if available, `read-passwd' else."
6774    (if (functionp 'password-read)    (if (functionp 'password-read)
6775        (let* ((user (or tramp-current-user (user-login-name)))        (let* ((key (concat (or user (user-login-name)) "@" host))
              (host (or tramp-current-host (system-name)))  
              (key (if (and (stringp user) (stringp host))  
                       (concat user "@" host)  
                     (concat "[" (mapconcat 'identity user "/") "]@["  
                             (mapconcat 'identity host "/") "]")))  
6776               (password (apply #'password-read (list prompt key))))               (password (apply #'password-read (list prompt key))))
6777          (apply #'password-cache-add (list key password))          (apply #'password-cache-add (list key password))
6778          password)          password)

Legend:
Removed from v.1.39.2.4  
changed lines
  Added in v.1.39.2.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26