diff options
| author | Michael Olson | 2008-10-08 04:05:10 +0000 |
|---|---|---|
| committer | Michael Olson | 2008-10-08 04:05:10 +0000 |
| commit | 1c86baa408007e4ab3774ebdb53e620eacb7a4c1 (patch) | |
| tree | 0b0e18c0481d7de26ff1f09614c25ef2a24ddd9b | |
| parent | f2602864b661c32888029f38921fb19f65bf337e (diff) | |
| download | emacs-1c86baa408007e4ab3774ebdb53e620eacb7a4c1.tar.gz emacs-1c86baa408007e4ab3774ebdb53e620eacb7a4c1.zip | |
ERC: DCC fixes.
| -rw-r--r-- | lisp/erc/ChangeLog | 34 | ||||
| -rw-r--r-- | lisp/erc/erc-dcc.el | 151 |
2 files changed, 142 insertions, 43 deletions
diff --git a/lisp/erc/ChangeLog b/lisp/erc/ChangeLog index 5d93364dc4a..3d1ac3baab0 100644 --- a/lisp/erc/ChangeLog +++ b/lisp/erc/ChangeLog | |||
| @@ -1,3 +1,37 @@ | |||
| 1 | 2008-10-03 Michael Olson <mwolson@gnu.org> | ||
| 2 | |||
| 3 | * erc-dcc.el (english): Increase size heading by two places. | ||
| 4 | (erc-dcc-byte-count): Move higher. | ||
| 5 | (erc-dcc-do-LIST-command): Use erc-dcc-byte-count to get accurate | ||
| 6 | count. Coerce byte total to floating point before performing | ||
| 7 | computation, otherwise division will truncate to 0. | ||
| 8 | (erc-dcc-append-contents): Update erc-dcc-byte-count. | ||
| 9 | (erc-dcc-get-filter): Don't update erc-dcc-byte-count, because | ||
| 10 | that will give incorrect size totals. Instead, figure out how | ||
| 11 | much we have by summing byte count and current buffer size. | ||
| 12 | (erc-dcc-get-sentinel): Don't update erc-dcc-byte-count. | ||
| 13 | |||
| 14 | 2008-10-01 Michael Olson <mwolson@gnu.org> | ||
| 15 | |||
| 16 | * erc-dcc.el (erc-pack-int): Make sure returned string is within 4 | ||
| 17 | bytes. Always return a 4-byte string, so that we conform to the | ||
| 18 | CTCP spec. | ||
| 19 | (erc-most-positive-int-bytes): New constant representing the | ||
| 20 | number of bytes that most-positive-fixnum can be stored in. | ||
| 21 | (erc-most-positive-int-msb): New constant representing the | ||
| 22 | contents of the most significant byte of most-positive-fixnum. | ||
| 23 | (erc-unpack-int): Make sure that the integer we get back can be | ||
| 24 | represented in Emacs. | ||
| 25 | (erc-dcc-do-CLOSE-command): Update docstring. Don't use the line | ||
| 26 | variable. Try to disambiguate between type and nick when only one | ||
| 27 | is provided. Validate both type and nick arguments. Allow | ||
| 28 | matching by just nick. | ||
| 29 | (erc-dcc-append-contents): Set inhibit-read-only to t. Prevent | ||
| 30 | auto-compression from triggering when we write the contents to a | ||
| 31 | file. | ||
| 32 | (erc-dcc-get-file): Prevent auto-compression from triggering when | ||
| 33 | we truncate a file. | ||
| 34 | |||
| 1 | 2008-07-27 Dan Nicolaescu <dann@ics.uci.edu> | 35 | 2008-07-27 Dan Nicolaescu <dann@ics.uci.edu> |
| 2 | 36 | ||
| 3 | * erc.el: Remove code for Carbon. | 37 | * erc.el: Remove code for Carbon. |
diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el index 2877107bb96..e6329c10cbb 100644 --- a/lisp/erc/erc-dcc.el +++ b/lisp/erc/erc-dcc.el | |||
| @@ -79,6 +79,11 @@ IRC users." | |||
| 79 | :group 'erc-dcc | 79 | :group 'erc-dcc |
| 80 | :type 'boolean) | 80 | :type 'boolean) |
| 81 | 81 | ||
| 82 | (defconst erc-dcc-connection-types | ||
| 83 | '("CHAT" "GET" "SEND") | ||
| 84 | "List of valid DCC connection types. | ||
| 85 | All values of the list must be uppercase strings.") | ||
| 86 | |||
| 82 | (defvar erc-dcc-list nil | 87 | (defvar erc-dcc-list nil |
| 83 | "List of DCC connections. Looks like: | 88 | "List of DCC connections. Looks like: |
| 84 | ((:nick \"nick!user@host\" :type GET :peer proc :parent proc :size size :file file) | 89 | ((:nick \"nick!user@host\" :type GET :peer proc :parent proc :size size :file file) |
| @@ -145,9 +150,9 @@ IRC users." | |||
| 145 | (dcc-get-file-too-long | 150 | (dcc-get-file-too-long |
| 146 | . "DCC: %f: File longer than sender claimed; aborting transfer") | 151 | . "DCC: %f: File longer than sender claimed; aborting transfer") |
| 147 | (dcc-get-notfound . "DCC: %n hasn't offered %f for DCC transfer") | 152 | (dcc-get-notfound . "DCC: %n hasn't offered %f for DCC transfer") |
| 148 | (dcc-list-head . "DCC: From Type Active Size Filename") | 153 | (dcc-list-head . "DCC: From Type Active Size Filename") |
| 149 | (dcc-list-line . "DCC: -------- ---- ------ ------------ --------") | 154 | (dcc-list-line . "DCC: -------- ---- ------ -------------- --------") |
| 150 | (dcc-list-item . "DCC: %-8n %-4t %-6a %-12s %f") | 155 | (dcc-list-item . "DCC: %-8n %-4t %-6a %-14s %f") |
| 151 | (dcc-list-end . "DCC: End of list.") | 156 | (dcc-list-end . "DCC: End of list.") |
| 152 | (dcc-malformed . "DCC: error: %n (%u@%h) sent malformed request: %q") | 157 | (dcc-malformed . "DCC: error: %n (%u@%h) sent malformed request: %q") |
| 153 | (dcc-privileged-port | 158 | (dcc-privileged-port |
| @@ -200,25 +205,55 @@ compared with `erc-nick-equal-p' which is IRC case-insensitive." | |||
| 200 | result)) | 205 | result)) |
| 201 | 206 | ||
| 202 | (defun erc-pack-int (value) | 207 | (defun erc-pack-int (value) |
| 203 | "Convert an integer into a packed string." | 208 | "Convert an integer into a packed string in network byte order, |
| 204 | (let* ((len (ceiling (/ value 256.0))) | 209 | which is big-endian." |
| 205 | (str (make-string len ?a)) | 210 | ;; make sure value is not negative |
| 206 | (i (1- len))) | 211 | (when (< value 0) |
| 207 | (while (>= i 0) | 212 | (error "ERC-DCC (erc-pack-int): packet size is negative")) |
| 213 | ;; make sure size is not larger than 4 bytes | ||
| 214 | (let ((len (if (= value 0) 0 | ||
| 215 | (ceiling (/ (ceiling (/ (log value) (log 2))) 8.0))))) | ||
| 216 | (when (> len 4) | ||
| 217 | (error "ERC-DCC (erc-pack-int): packet too large"))) | ||
| 218 | ;; pack | ||
| 219 | (let ((str (make-string 4 0)) | ||
| 220 | (i 3)) | ||
| 221 | (while (and (>= i 0) (> value 0)) | ||
| 208 | (aset str i (% value 256)) | 222 | (aset str i (% value 256)) |
| 209 | (setq value (/ value 256)) | 223 | (setq value (/ value 256)) |
| 210 | (setq i (1- i))) | 224 | (setq i (1- i))) |
| 211 | str)) | 225 | str)) |
| 212 | 226 | ||
| 227 | (defconst erc-most-positive-int-bytes | ||
| 228 | (ceiling (/ (ceiling (/ (log most-positive-fixnum) (log 2))) 8.0)) | ||
| 229 | "Maximum number of bytes for a fixnum.") | ||
| 230 | |||
| 231 | (defconst erc-most-positive-int-msb | ||
| 232 | (lsh most-positive-fixnum (- 0 (* 8 (1- erc-most-positive-int-bytes)))) | ||
| 233 | "Content of the most significant byte of most-positive-fixnum.") | ||
| 234 | |||
| 213 | (defun erc-unpack-int (str) | 235 | (defun erc-unpack-int (str) |
| 214 | "Unpack a packed string into an integer." | 236 | "Unpack a packed string into an integer." |
| 215 | (let ((len (length str)) | 237 | (let ((len (length str))) |
| 216 | (num 0) | 238 | ;; strip leading 0-bytes |
| 217 | (count 0)) | 239 | (let ((start 0)) |
| 218 | (while (< count len) | 240 | (while (and (> len start) (eq (aref str start) 0)) |
| 219 | (setq num (+ num (lsh (aref str (- len count 1)) (* 8 count)))) | 241 | (setq start (1+ start))) |
| 220 | (setq count (1+ count))) | 242 | (when (> start 0) |
| 221 | num)) | 243 | (setq str (substring str start)) |
| 244 | (setq len (- len start)))) | ||
| 245 | ;; make sure size is not larger than Emacs can handle | ||
| 246 | (when (or (> len (min 4 erc-most-positive-int-bytes)) | ||
| 247 | (and (eq len erc-most-positive-int-bytes) | ||
| 248 | (> (aref str 0) erc-most-positive-int-msb))) | ||
| 249 | (error "ERC-DCC (erc-unpack-int): packet to send is too large")) | ||
| 250 | ;; unpack | ||
| 251 | (let ((num 0) | ||
| 252 | (count 0)) | ||
| 253 | (while (< count len) | ||
| 254 | (setq num (+ num (lsh (aref str (- len count 1)) (* 8 count)))) | ||
| 255 | (setq count (1+ count))) | ||
| 256 | num))) | ||
| 222 | 257 | ||
| 223 | (defconst erc-dcc-ipv4-regexp | 258 | (defconst erc-dcc-ipv4-regexp |
| 224 | (concat "^" | 259 | (concat "^" |
| @@ -447,19 +482,32 @@ where FOO is one of CLOSE, GET, SEND, LIST, CHAT, etc." | |||
| 447 | t)))) | 482 | t)))) |
| 448 | 483 | ||
| 449 | (defun erc-dcc-do-CLOSE-command (proc &optional type nick) | 484 | (defun erc-dcc-do-CLOSE-command (proc &optional type nick) |
| 450 | "/dcc close type nick | 485 | "Close a connection. Usage: /dcc close type nick. |
| 451 | type and nick are optional." | 486 | At least one of TYPE and NICK must be provided." |
| 452 | ;; FIXME, should also work if only nick is specified | 487 | ;; disambiguate type and nick if only one is provided |
| 453 | (when (string-match (concat "^\\s-*\\(\\S-+\\)? *\\(" | 488 | (when (and type (null nick) |
| 454 | erc-valid-nick-regexp "\\)?\\s-*$") line) | 489 | (not (member (upcase type) erc-dcc-connection-types))) |
| 455 | (let ((type (when (match-string 1 line) | 490 | (setq nick type) |
| 456 | (intern (upcase (match-string 1 line))))) | 491 | (setq type nil)) |
| 457 | (nick (match-string 2 line)) | 492 | ;; validate nick argument |
| 458 | (ret t)) | 493 | (unless (and nick (string-match (concat "\\`" erc-valid-nick-regexp "\\'") |
| 494 | nick)) | ||
| 495 | (setq nick nil)) | ||
| 496 | ;; validate type argument | ||
| 497 | (if (and type (member (upcase type) erc-dcc-connection-types)) | ||
| 498 | (setq type (intern (upcase type))) | ||
| 499 | (setq type nil)) | ||
| 500 | (when (or nick type) | ||
| 501 | (let ((ret t)) | ||
| 459 | (while ret | 502 | (while ret |
| 460 | (if nick | 503 | (cond ((and nick type) |
| 461 | (setq ret (erc-dcc-member :type type :nick nick)) | 504 | (setq ret (erc-dcc-member :type type :nick nick))) |
| 462 | (setq ret (erc-dcc-member :type type))) | 505 | (nick |
| 506 | (setq ret (erc-dcc-member :nick nick))) | ||
| 507 | (type | ||
| 508 | (setq ret (erc-dcc-member :type type))) | ||
| 509 | (t | ||
| 510 | (setq ret nil))) | ||
| 463 | (when ret | 511 | (when ret |
| 464 | ;; found a match - delete process if it exists. | 512 | ;; found a match - delete process if it exists. |
| 465 | (and (processp (plist-get ret :peer)) | 513 | (and (processp (plist-get ret :peer)) |
| @@ -470,7 +518,7 @@ type and nick are optional." | |||
| 470 | 'dcc-closed | 518 | 'dcc-closed |
| 471 | ?T (plist-get ret :type) | 519 | ?T (plist-get ret :type) |
| 472 | ?n (erc-extract-nick (plist-get ret :nick)))))) | 520 | ?n (erc-extract-nick (plist-get ret :nick)))))) |
| 473 | t)) | 521 | t)) |
| 474 | 522 | ||
| 475 | (defun erc-dcc-do-GET-command (proc nick &rest file) | 523 | (defun erc-dcc-do-GET-command (proc nick &rest file) |
| 476 | "Do a DCC GET command. NICK is the person who is sending the file. | 524 | "Do a DCC GET command. NICK is the person who is sending the file. |
| @@ -503,6 +551,9 @@ PROC is the server process." | |||
| 503 | nil '(notice error) 'active | 551 | nil '(notice error) 'active |
| 504 | 'dcc-get-notfound ?n nick ?f filename)))) | 552 | 'dcc-get-notfound ?n nick ?f filename)))) |
| 505 | 553 | ||
| 554 | (defvar erc-dcc-byte-count nil) | ||
| 555 | (make-variable-buffer-local 'erc-dcc-byte-count) | ||
| 556 | |||
| 506 | (defun erc-dcc-do-LIST-command (proc) | 557 | (defun erc-dcc-do-LIST-command (proc) |
| 507 | "This is the handler for the /dcc list command. | 558 | "This is the handler for the /dcc list command. |
| 508 | It lists the current state of `erc-dcc-list' in an easy to read manner." | 559 | It lists the current state of `erc-dcc-list' in an easy to read manner." |
| @@ -538,12 +589,18 @@ It lists the current state of `erc-dcc-list' in an easy to read manner." | |||
| 538 | (plist-member elt :file) | 589 | (plist-member elt :file) |
| 539 | (buffer-live-p (get-buffer (plist-get elt :file))) | 590 | (buffer-live-p (get-buffer (plist-get elt :file))) |
| 540 | (plist-member elt :size)) | 591 | (plist-member elt :size)) |
| 541 | (concat " (" (number-to-string | 592 | (let ((byte-count (with-current-buffer |
| 593 | (get-buffer (plist-get elt :file)) | ||
| 594 | (+ (buffer-size) 0.0 | ||
| 595 | erc-dcc-byte-count)))) | ||
| 596 | (concat " (" | ||
| 597 | (if (= byte-count 0) | ||
| 598 | "0" | ||
| 599 | (number-to-string | ||
| 600 | (truncate | ||
| 542 | (* 100 | 601 | (* 100 |
| 543 | (/ (buffer-size | 602 | (/ byte-count (plist-get elt :size)))))) |
| 544 | (get-buffer (plist-get elt :file))) | 603 | "%)")))) |
| 545 | (plist-get elt :size)))) | ||
| 546 | "%)"))) | ||
| 547 | ?f (or (and (plist-member elt :file) (plist-get elt :file)) ""))) | 604 | ?f (or (and (plist-member elt :file) (plist-get elt :file)) ""))) |
| 548 | (erc-display-message | 605 | (erc-display-message |
| 549 | nil 'notice 'active | 606 | nil 'notice 'active |
| @@ -853,8 +910,6 @@ other client." | |||
| 853 | :group 'erc-dcc | 910 | :group 'erc-dcc |
| 854 | :type 'integer) | 911 | :type 'integer) |
| 855 | 912 | ||
| 856 | (defvar erc-dcc-byte-count nil) | ||
| 857 | (make-variable-buffer-local 'erc-dcc-byte-count) | ||
| 858 | (defvar erc-dcc-file-name nil) | 913 | (defvar erc-dcc-file-name nil) |
| 859 | (make-variable-buffer-local 'erc-dcc-file-name) | 914 | (make-variable-buffer-local 'erc-dcc-file-name) |
| 860 | 915 | ||
| @@ -880,7 +935,11 @@ filter and a process sentinel, and making the connection." | |||
| 880 | (setq erc-dcc-file-name file) | 935 | (setq erc-dcc-file-name file) |
| 881 | 936 | ||
| 882 | ;; Truncate the given file to size 0 before appending to it. | 937 | ;; Truncate the given file to size 0 before appending to it. |
| 883 | (write-region (point) (point) erc-dcc-file-name nil 'nomessage) | 938 | (let ((inhibit-file-name-handlers |
| 939 | (append '(jka-compr-handler image-file-handler) | ||
| 940 | inhibit-file-name-handlers)) | ||
| 941 | (inhibit-file-name-operation 'write-region)) | ||
| 942 | (write-region (point) (point) erc-dcc-file-name nil 'nomessage)) | ||
| 884 | 943 | ||
| 885 | (setq erc-server-process parent-proc | 944 | (setq erc-server-process parent-proc |
| 886 | erc-dcc-entry-data entry) | 945 | erc-dcc-entry-data entry) |
| @@ -904,8 +963,14 @@ filter and a process sentinel, and making the connection." | |||
| 904 | "Append the contents of BUFFER to FILE. | 963 | "Append the contents of BUFFER to FILE. |
| 905 | The contents of the BUFFER will then be erased." | 964 | The contents of the BUFFER will then be erased." |
| 906 | (with-current-buffer buffer | 965 | (with-current-buffer buffer |
| 907 | (let ((coding-system-for-write 'binary)) | 966 | (let ((coding-system-for-write 'binary) |
| 967 | (inhibit-read-only t) | ||
| 968 | (inhibit-file-name-handlers | ||
| 969 | (append '(jka-compr-handler image-file-handler) | ||
| 970 | inhibit-file-name-handlers)) | ||
| 971 | (inhibit-file-name-operation 'write-region)) | ||
| 908 | (write-region (point-min) (point-max) erc-dcc-file-name t 'nomessage) | 972 | (write-region (point-min) (point-max) erc-dcc-file-name t 'nomessage) |
| 973 | (setq erc-dcc-byte-count (+ (buffer-size) erc-dcc-byte-count)) | ||
| 909 | (erase-buffer)))) | 974 | (erase-buffer)))) |
| 910 | 975 | ||
| 911 | (defun erc-dcc-get-filter (proc str) | 976 | (defun erc-dcc-get-filter (proc str) |
| @@ -915,23 +980,24 @@ buffer, and sends back the replies after each block of data per the DCC | |||
| 915 | protocol spec. Well not really. We write back a reply after each read, | 980 | protocol spec. Well not really. We write back a reply after each read, |
| 916 | rather than every 1024 byte block, but nobody seems to care." | 981 | rather than every 1024 byte block, but nobody seems to care." |
| 917 | (with-current-buffer (process-buffer proc) | 982 | (with-current-buffer (process-buffer proc) |
| 918 | (let ((inhibit-read-only t)) | 983 | (let ((inhibit-read-only t) |
| 984 | received-bytes) | ||
| 919 | (goto-char (point-max)) | 985 | (goto-char (point-max)) |
| 920 | (insert (string-make-unibyte str)) | 986 | (insert (string-make-unibyte str)) |
| 921 | 987 | ||
| 922 | (setq erc-dcc-byte-count (+ (length str) erc-dcc-byte-count)) | ||
| 923 | (when (> (point-max) erc-dcc-receive-cache) | 988 | (when (> (point-max) erc-dcc-receive-cache) |
| 924 | (erc-dcc-append-contents (current-buffer) erc-dcc-file-name)) | 989 | (erc-dcc-append-contents (current-buffer) erc-dcc-file-name)) |
| 990 | (setq received-bytes (+ (buffer-size) erc-dcc-byte-count)) | ||
| 925 | 991 | ||
| 926 | (and erc-dcc-verbose | 992 | (and erc-dcc-verbose |
| 927 | (erc-display-message | 993 | (erc-display-message |
| 928 | nil 'notice erc-server-process | 994 | nil 'notice erc-server-process |
| 929 | 'dcc-get-bytes-received | 995 | 'dcc-get-bytes-received |
| 930 | ?f (file-name-nondirectory buffer-file-name) | 996 | ?f (file-name-nondirectory buffer-file-name) |
| 931 | ?b (number-to-string erc-dcc-byte-count))) | 997 | ?b (number-to-string received-bytes))) |
| 932 | (cond | 998 | (cond |
| 933 | ((and (> (plist-get erc-dcc-entry-data :size) 0) | 999 | ((and (> (plist-get erc-dcc-entry-data :size) 0) |
| 934 | (> erc-dcc-byte-count (plist-get erc-dcc-entry-data :size))) | 1000 | (> received-bytes (plist-get erc-dcc-entry-data :size))) |
| 935 | (erc-display-message | 1001 | (erc-display-message |
| 936 | nil '(error notice) 'active | 1002 | nil '(error notice) 'active |
| 937 | 'dcc-get-file-too-long | 1003 | 'dcc-get-file-too-long |
| @@ -939,7 +1005,7 @@ rather than every 1024 byte block, but nobody seems to care." | |||
| 939 | (delete-process proc)) | 1005 | (delete-process proc)) |
| 940 | (t | 1006 | (t |
| 941 | (process-send-string | 1007 | (process-send-string |
| 942 | proc (erc-pack-int erc-dcc-byte-count))))))) | 1008 | proc (erc-pack-int received-bytes))))))) |
| 943 | 1009 | ||
| 944 | 1010 | ||
| 945 | (defun erc-dcc-get-sentinel (proc event) | 1011 | (defun erc-dcc-get-sentinel (proc event) |
| @@ -951,7 +1017,6 @@ transfer is complete." | |||
| 951 | (delete-process proc) | 1017 | (delete-process proc) |
| 952 | (setq erc-dcc-list (delete erc-dcc-entry-data erc-dcc-list)) | 1018 | (setq erc-dcc-list (delete erc-dcc-entry-data erc-dcc-list)) |
| 953 | (unless (= (point-min) (point-max)) | 1019 | (unless (= (point-min) (point-max)) |
| 954 | (setq erc-dcc-byte-count (+ (buffer-size) erc-dcc-byte-count)) | ||
| 955 | (erc-dcc-append-contents (current-buffer) erc-dcc-file-name)) | 1020 | (erc-dcc-append-contents (current-buffer) erc-dcc-file-name)) |
| 956 | (erc-display-message | 1021 | (erc-display-message |
| 957 | nil 'notice erc-server-process | 1022 | nil 'notice erc-server-process |