1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

ERC: Sync version 5.3, release candidate 1.

This commit is contained in:
Michael Olson 2008-01-25 03:28:10 +00:00
parent 409dd1209d
commit 5e56b3fb5a
17 changed files with 2022 additions and 1038 deletions

View file

@ -60,6 +60,12 @@
(require 'cl)
(require 'pcomplete))
;;;###autoload (autoload 'erc-dcc-mode "erc-dcc")
(define-erc-module dcc nil
"Provide Direct Client-to-Client support for ERC."
((add-hook 'erc-server-401-functions 'erc-dcc-no-such-nick))
((remove-hook 'erc-server-401-functions 'erc-dcc-no-such-nick)))
(defgroup erc-dcc nil
"DCC stands for Direct Client Communication, where you and your
friend's client programs connect directly to each other,
@ -70,7 +76,7 @@ Using DCC get and send, you can transfer files directly from and to other
IRC users."
:group 'erc)
(defcustom erc-verbose-dcc t
(defcustom erc-dcc-verbose nil
"*If non-nil, be verbose about DCC activity reporting."
:group 'erc-dcc
:type 'boolean)
@ -195,20 +201,22 @@ compared with `erc-nick-equal-p' which is IRC case-insensitive."
(setq list (cdr list)))))
result))
;; msa wrote this nifty little frob to convert an n-byte integer to a packed
;; string.
(defun erc-pack-int (value count)
(if (> count 0)
(concat (erc-pack-int (/ value 256) (1- count))
(char-to-string (% value 256)))
""))
(defun erc-pack-int (value)
"Convert an integer into a packed string."
(let* ((len (ceiling (/ value 256.0)))
(str (make-string len ?a))
(i (1- len)))
(while (>= i 0)
(aset str i (% value 256))
(setq value (/ value 256))
(setq i (1- i)))
str))
(defun erc-unpack-int (str)
"Unpack a 1-4 character packed string into an integer."
"Unpack a packed string into an integer."
(let ((len (length str))
(num 0)
(count 0))
(erc-assert (<= len 4)) ;; this isn't going to fit in elisp bounds
(while (< count len)
(setq num (+ num (lsh (aref str (- len count 1)) (* 8 count))))
(setq count (1+ count)))
@ -256,15 +264,24 @@ The result is also a string."
;;; Server code
(defcustom erc-dcc-host nil
"*IP address to use for outgoing DCC offers.
Should be set to a string or nil, if nil, automatic detection of the
host interface to use will be attempted."
(defcustom erc-dcc-listen-host nil
"IP address to listen on when offering files.
Should be set to a string or nil. If nil, automatic detection of
the host interface to use will be attempted."
:group 'erc-dcc
:type (list 'choice (list 'const :tag "Auto-detect" nil)
(list 'string :tag "IP-address"
:valid-regexp erc-dcc-ipv4-regexp)))
(defcustom erc-dcc-public-host nil
"IP address to use for outgoing DCC offers.
Should be set to a string or nil. If nil, use the value of
`erc-dcc-listen-host'."
:group 'erc-dcc
:type (list 'choice (list 'const :tag "Same as erc-dcc-listen-host" nil)
(list 'string :tag "IP-address"
:valid-regexp erc-dcc-ipv4-regexp)))
(defcustom erc-dcc-send-request 'ask
"*How to treat incoming DCC Send requests.
'ask - Report the Send request, and wait for the user to manually accept it
@ -282,7 +299,7 @@ host interface to use will be attempted."
"Determine the IP address we are using.
If variable `erc-dcc-host' is non-nil, use it. Otherwise call
`erc-dcc-get-host' on the erc-server-process."
(or erc-dcc-host (erc-dcc-get-host erc-server-process)
(or erc-dcc-listen-host (erc-dcc-get-host erc-server-process)
(error "Unable to determine local address")))
(defcustom erc-dcc-port-range nil
@ -311,6 +328,7 @@ created subprocess, or nil."
process)
(while (not process)
(condition-case err
(progn
(setq process
(make-network-process :name name
:buffer nil
@ -322,6 +340,11 @@ created subprocess, or nil."
:sentinel sentinel
:log #'erc-dcc-server-accept
:server t))
(when (processp process)
(when (fboundp 'set-process-coding-system)
(set-process-coding-system process 'binary 'binary))
(when (fboundp 'set-process-filter-multibyte)
(set-process-filter-multibyte process nil))))
(file-error
(unless (and (string= "Cannot bind server socket" (cadr err))
(string= "address already in use" (caddr err)))
@ -698,7 +721,7 @@ bytes sent."
(confirmed-marker (plist-get elt :sent))
(sent-marker (plist-get elt :sent)))
(with-current-buffer (process-buffer proc)
(when erc-verbose-dcc
(when erc-dcc-verbose
(erc-display-message
nil 'notice (erc-dcc-get-parent proc)
(format "DCC: Confirmed %d, sent %d, sending block now"
@ -713,8 +736,7 @@ bytes sent."
(length string)))))
(defun erc-dcc-send-filter (proc string)
(erc-assert (= (% (length string) 4) 0))
(let* ((size (erc-unpack-int (substring string (- (length string) 4))))
(let* ((size (erc-unpack-int string))
(elt (erc-dcc-member :peer proc))
(parent (plist-get elt :parent))
(sent-marker (plist-get elt :sent))
@ -742,16 +764,21 @@ bytes sent."
((> confirmed-marker sent-marker)
(erc-display-message
nil 'notice parent
(format "DCC: Client confirmed too much!"))
(format "DCC: Client confirmed too much (%s vs %s)!"
(marker-position confirmed-marker)
(marker-position sent-marker)))
(set-buffer-modified-p nil)
(kill-buffer (current-buffer))
(delete-process proc))))))
(defun erc-dcc-display-send (proc)
(erc-display-message
nil 'notice (erc-dcc-get-parent proc)
(format "DCC: SEND connect from %s"
(format-network-address (process-contact proc :remote)))))
(defcustom erc-dcc-send-connect-hook
'((lambda (proc)
(erc-display-message
nil 'notice (erc-dcc-get-parent proc)
(format "DCC: SEND connect from %s"
(format-network-address (process-contact proc :remote)))))
erc-dcc-send-block)
'(erc-dcc-display-send erc-dcc-send-block)
"*Hook run whenever the remote end of a DCC SEND offer connected to your
listening port."
:group 'erc-dcc
@ -762,14 +789,14 @@ listening port."
(erc-extract-nick (plist-get plist :nick)))
(defun erc-dcc-send-sentinel (proc event)
(let* ((elt (erc-dcc-member :peer proc))
(buf (marker-buffer (plist-get elt :sent))))
(let* ((elt (erc-dcc-member :peer proc)))
(cond
((string-match "^open from " event)
(when elt
(with-current-buffer buf
(set-process-buffer proc buf)
(setq erc-dcc-entry-data elt))
(let ((buf (marker-buffer (plist-get elt :sent))))
(with-current-buffer buf
(set-process-buffer proc buf)
(setq erc-dcc-entry-data elt)))
(run-hook-with-args 'erc-dcc-send-connect-hook proc))))))
(defun erc-dcc-find-file (file)
@ -807,15 +834,23 @@ other client."
(process-send-string
pproc (format "PRIVMSG %s :\C-aDCC SEND %s %s %d %d\C-a\n"
nick (erc-dcc-file-to-name file)
(erc-ip-to-decimal (nth 0 contact))
(erc-ip-to-decimal (or erc-dcc-public-host
(nth 0 contact)))
(nth 1 contact)
size)))
(error "`make-network-process' not supported by your Emacs")))
;;; GET handling
(defcustom erc-dcc-receive-cache (* 1024 512)
"Number of bytes to let the receive buffer grow before flushing it."
:group 'erc-dcc
:type 'integer)
(defvar erc-dcc-byte-count nil)
(make-variable-buffer-local 'erc-dcc-byte-count)
(defvar erc-dcc-file-name nil)
(make-variable-buffer-local 'erc-dcc-file-name)
(defun erc-dcc-get-file (entry file parent-proc)
"This function does the work of setting up a transfer from the remote client
@ -825,6 +860,7 @@ filter and a process sentinel, and making the connection."
proc)
(with-current-buffer buffer
(fundamental-mode)
(buffer-disable-undo (current-buffer))
;; This is necessary to have the buffer saved as-is in GNU
;; Emacs.
;; XEmacs change: We don't have `set-buffer-multibyte', setting
@ -835,7 +871,10 @@ filter and a process sentinel, and making the connection."
(setq mode-line-process '(":%s")
buffer-file-type t
buffer-read-only t)
(set-visited-file-name file)
(setq erc-dcc-file-name file)
;; Truncate the given file to size 0 before appending to it.
(write-region (point) (point) erc-dcc-file-name nil 'nomessage)
(setq erc-server-process parent-proc
erc-dcc-entry-data entry)
@ -847,7 +886,6 @@ filter and a process sentinel, and making the connection."
(string-to-number (plist-get entry :port))
entry))
(set-process-buffer proc buffer)
;; The following two lines make saving as-is work under Windows
(set-process-coding-system proc 'binary 'binary)
(set-buffer-file-coding-system 'binary t)
@ -856,6 +894,14 @@ filter and a process sentinel, and making the connection."
(setq entry (plist-put entry :start-time (erc-current-time)))
(setq entry (plist-put entry :peer proc)))))
(defun erc-dcc-append-contents (buffer file)
"Append the contents of BUFFER to FILE.
The contents of the BUFFER will then be erased."
(with-current-buffer buffer
(let ((coding-system-for-write 'binary))
(write-region (point-min) (point-max) erc-dcc-file-name t 'nomessage)
(erase-buffer))))
(defun erc-dcc-get-filter (proc str)
"This is the process filter for transfers from other clients to this one.
It reads incoming bytes from the network and stores them in the DCC
@ -868,8 +914,10 @@ rather than every 1024 byte block, but nobody seems to care."
(insert (string-make-unibyte str))
(setq erc-dcc-byte-count (+ (length str) erc-dcc-byte-count))
(erc-assert (= erc-dcc-byte-count (1- (point-max))))
(and erc-verbose-dcc
(when (> (point-max) erc-dcc-receive-cache)
(erc-dcc-append-contents (current-buffer) erc-dcc-file-name))
(and erc-dcc-verbose
(erc-display-message
nil 'notice erc-server-process
'dcc-get-bytes-received
@ -885,7 +933,7 @@ rather than every 1024 byte block, but nobody seems to care."
(delete-process proc))
(t
(process-send-string
proc (erc-pack-int erc-dcc-byte-count 4)))))))
proc (erc-pack-int erc-dcc-byte-count)))))))
(defun erc-dcc-get-sentinel (proc event)
@ -895,17 +943,18 @@ transfer is complete."
;; FIXME, we should look at EVENT, and also check size.
(with-current-buffer (process-buffer proc)
(delete-process proc)
(setq buffer-read-only nil)
(setq erc-dcc-list (delete erc-dcc-entry-data erc-dcc-list))
(unless (= (point-min) (point-max))
(setq erc-dcc-byte-count (+ (buffer-size) erc-dcc-byte-count))
(erc-dcc-append-contents (current-buffer) erc-dcc-file-name))
(erc-display-message
nil 'notice erc-server-process
'dcc-get-complete
?f (file-name-nondirectory buffer-file-name)
?s (number-to-string (buffer-size))
?f erc-dcc-file-name
?s (number-to-string erc-dcc-byte-count)
?t (format "%.0f"
(erc-time-diff (plist-get erc-dcc-entry-data :start-time)
(erc-current-time))))
(save-buffer))
(erc-current-time)))))
(kill-buffer (process-buffer proc))
(delete-process proc))
@ -1126,8 +1175,6 @@ other client."
(if (processp peer) (delete-process peer)))
nil))
(add-hook 'erc-server-401-functions 'erc-dcc-no-such-nick)
(provide 'erc-dcc)
;;; erc-dcc.el ends here