home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / emacslisp / emkermit.el next >
Lisp/Scheme  |  2020-01-01  |  26KB  |  770 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;; kermit.el - transfer buffers to and from emacs with kermit protocol
  3. ;;;
  4. ;;; Bob Manson <manson@piglet.cr.usgs.gov>
  5. ;;; Ben Mesander <ben@gnu.ai.mit.edu>
  6. ;;;
  7. ;;; kermit|Ben A. Mesander|ben@gnu.ai.mit.edu|
  8. ;;; Transfer buffers to and from Emacs with kermit protocol.|
  9. ;;; 04-Jun-1994|1.4|~/misc/kermit.el.Z|
  10. ;;;
  11. ;;; $Revision: 1.4 $
  12. ;;;
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14. ;;; README
  15. ;;;
  16. ;;; This lisp library adds three commands:
  17. ;;; kermit-send-current-buffer sends the current buffer to stdio
  18. ;;;     with kermit protocol.
  19. ;;; kermit-send-buffer sends its argument (a buffer or buffer name ) 
  20. ;;;     to stdio with kermit protocol.
  21. ;;; kermit-receive-buffer receives a file you send to emacs's stdio
  22. ;;;     with kermit protocol.
  23. ;;;
  24. ;;; All transfers are done in image mode if `kermit-text-mode' is nil.
  25. ;;; Otherwise, transfers are done in ASCII mode.
  26. ;;; All transfers are done assuming a 7-bit data path - working over
  27. ;;; emacs's stdio is enough of a hack without complicating things further.
  28. ;;;
  29. ;;; To abort a transfer, connect to your emacs, send a C-g, and kill
  30. ;;; the blank buffer (C-x C-k RET), and repaint the screen with C-l .
  31. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  32.  
  33. ;;; Wow.  I am surprised, and repulsed! - jwz@lucid.com
  34.  
  35. ;;;
  36. ;;; NOTE: All lines must be less than 80 characters in length in order
  37. ;;; to conform to the requirements of the kermit archive.
  38. ;;;
  39.  
  40. ;;; Code:
  41.  
  42. (require 'backquote)
  43.  
  44. ;; USER SETTABLE VARIABLES
  45.  
  46. (defvar kermit-debugging nil
  47.   "Set to t in order to log kermit packet debugging information in a buffer
  48.     named `kermit-debugging'.")
  49.  
  50. (defvar kermit-read-char-timeout 5
  51.   "How long to wait to read a character before timing out")
  52.  
  53. (defvar kermit-mark-char "\C-a"
  54.   "Control character used to mark the start of a packet.")
  55.  
  56. (defvar kermit-line-terminator "\C-m"
  57.   "Line terminator to use at the end of every packet.")
  58.  
  59. (defvar kermit-max-packet-len 94
  60.   "The maximum size packet kermit can send (up to 94 characters).")
  61.  
  62. (defvar kermit-send-quotechar "#"
  63.   "Character kermit uses to quote characters")
  64.  
  65. (defvar kermit-quote-8bit-char "&"
  66.   "Character kermit uses to quote 8 bit characters")
  67.  
  68. (defvar kermit-text-mode nil
  69.   "Set to t to do text mode file transfers")
  70.  
  71. ;; END OF USER SETTABLE VARIABLES
  72.  
  73. ;; buffer emacs uses to transfer characters from/to
  74. (defvar kermit-transfer-buffer nil)
  75.  
  76. ;; buffer emacs uses to blank the screen with
  77. (defvar kermit-blank-buffer nil)
  78.  
  79. ;; prefix encoding table
  80. (defvar kermit-prefix-table nil)
  81.  
  82. ;; prefix encoding length table
  83. (defvar kermit-prefix-table-len nil)
  84.  
  85. ;; name of buffer kermit is transferring
  86. (defvar kermit-filename nil)
  87.  
  88. ;; accumulator for packet checksum
  89. (defvar kermit-checksum-total 0)
  90.  
  91. ;; return value from character read functions
  92. (defvar kermit-gotten-char nil)
  93.  
  94. ;; number of times calling input-pending-p is 1 second
  95. (defvar kermit-delay-count 0)
  96.  
  97. ;; sequence number of packet read
  98. (defvar kermit-receive-seq nil)
  99.  
  100. ;; sequence number of packet sent
  101. (defvar kermit-seq-number nil)
  102.  
  103. ;; length of received packet
  104. (defvar kermit-packet-len nil)
  105.  
  106. ;; kermit packet being built
  107. (defvar kermit-packet-in-progress nil)
  108.  
  109. ;; packet type of packet read
  110. (defvar kermit-packet-type nil)
  111.  
  112. ;; global kermit packet
  113. (defvar kermit-packet nil)
  114.  
  115. ;; used to decode data
  116. (defvar kermit-prefix-add 0)
  117.  
  118. ;; flag used to decode data
  119. (defvar kermit-got-stdquote nil)
  120.  
  121. (defmacro kermit-do-log (inlist)
  122.   (` (and kermit-debugging 
  123.       (kermit-do-real-log (, inlist)))))
  124.  
  125. ;;
  126. ;; Transform c, which is assumed to lie in the range 0 to 94
  127. ;; into a printable ASCII character; 0 becomes SP, 1 becomes "!", 3 becomes
  128. ;; "#", etc.
  129. ;;
  130. (defmacro kermit-tochar (c) "Converts a number into an ASCII character."
  131.   (list 'char-to-string (list '+ c 32)))
  132.  
  133. ;;
  134. ;; Transforms the character c, which is assumed to be in the printable range
  135. ;; (SP through tilde), into an integer in the range 0 to 94.
  136. ;;
  137. (defmacro kermit-fromchar (c) 
  138.   "Converts a character into its integer equivalent."
  139.   (list '- (list 'string-to-char c) 32))
  140.  
  141. ;; Call FUN with an argument of each character in STRING, and concat the 
  142. ;; results, if DOCONCAT is non-nil.
  143. (defun kermit-mapstring (fun string &rest doconcat) 
  144.   (let (
  145.     (result "")
  146.     (index 0)
  147.     (slength (length string)))
  148.     (if doconcat
  149.     (while (< index slength)
  150.       (setq result
  151.         (concat result
  152.             (apply fun (list (aref string index)))))
  153.       (setq index (+ index 1)))
  154.       (while (< index slength)
  155.     (apply fun (list (aref string index)))
  156.     (setq index (+ index 1))))
  157.       
  158.     result))
  159.  
  160. (defun kermit-checksum-add (i) "add I to the checksum"
  161.   (setq kermit-checksum-total (+ kermit-checksum-total i))
  162.   nil)
  163.  
  164. ;; Return a single-character checksum based on kermit-checksum-total.
  165.  
  166. (defun kermit-checksum-char () 
  167.   (setq kermit-checksum-total (mod kermit-checksum-total 256))
  168.   (kermit-tochar (logand 63 (+ (mod kermit-checksum-total 64)
  169.                    (/ kermit-checksum-total 64)))))
  170.  
  171. (defun kermit-checksum (packet) "Generate a single byte checksum from PACKET."
  172.   (setq kermit-checksum-total 0)
  173.   (kermit-mapstring 'kermit-checksum-add packet nil)
  174.   (kermit-checksum-char))
  175.  
  176. ;;
  177. ;; Send a kermit packet of type TYPE, sequence number SEQUENCE, containing 
  178. ;; DATA. DATA must already be in its proper quoted form.
  179. ;;
  180. ;;Basic Kermit Packet Layout
  181. ;;
  182. ;;       |<------Included in CHECK------>|
  183. ;;       |                               |
  184. ;;+------+-----+-----+------+------ - - -+-------+
  185. ;;| MARK | LEN | SEQ | TYPE | DATA       | CHECK |<terminator>
  186. ;;+------+-----+-----+------+------ - - -+-------+
  187. ;;             |                                 |
  188. ;;             |<--------LEN-32 characters------>|
  189. ;;
  190. ;; MARK   A real control character, usually CTRL-A.
  191. ;;  LEN   One character, length of remainder of packet + 32, max 95
  192. ;;  SEQ   One character, packet sequence number + 32, modulo 64
  193. ;; TYPE   One character, an uppercase letter
  194. ;;CHECK   One, two, or three characters, as negotiated.
  195. ;;
  196. ;;<terminator>  Any control character required for reading the packet.
  197. ;;
  198. (defun kermit-send-packet (type sequence data) 
  199.   (let (thepacket)
  200.     (kermit-discard-input)
  201.     ;; NOTE: + 3 will have to be changed if
  202.     ;; extended-length packets are ever implemented.
  203.     (setq thepacket (concat (kermit-tochar (+ 3 (length data)))
  204.                 (kermit-tochar sequence) type data))
  205.     (setq thepacket (concat kermit-mark-char thepacket (kermit-checksum 
  206.                             thepacket)
  207.                 kermit-line-terminator))
  208.     (send-string-to-terminal thepacket)
  209.     (kermit-do-log (concat "sent: " thepacket)))
  210.   t)
  211.  
  212. ;;
  213. ;; Transforms the character `data' back and forth between their printable
  214. ;; and control representations, preserving the high order bit. A becomes
  215. ;; control-A, and vice versa, etc.
  216. ;;
  217. (defun kermit-ctl (data)
  218.   (if (not (equal data (string-to-char kermit-send-quotechar)))
  219.       (char-to-string (logxor data 64))
  220.     kermit-send-quotechar))
  221.  
  222. (setq kermit-prefix-table (make-vector 256 ""))
  223. (setq kermit-prefix-table-len (make-vector 256 0))
  224.  
  225. (defun kermit-prefix (c) "Do an aref insead of all that nastiness."
  226.   (aref kermit-prefix-table c))
  227.  
  228. (defmacro kermit-size-of-char (chari) 
  229.   "Tells how many bytes CHAR will use when transmitted."
  230.   (list 'aref 'kermit-prefix-table-len chari))
  231.  
  232. (defun init-kermit-prefix () 
  233.   (let ((i))
  234.     (setq i 0)
  235.     (while (< i 256) (progn
  236.                (aset kermit-prefix-table i (kermit-prefix-slow i))
  237.                (aset kermit-prefix-table-len i 
  238.                  (length (aref kermit-prefix-table i)))
  239.                (setq i (1+ i))))))
  240.  
  241. ;; Handle quoting. Given a single character DATA, return a string that will 
  242. ;; represent DATA in kermit.
  243. (defun kermit-prefix-slow (c) 
  244.   (let* ((data (char-to-string c)))
  245.     (cond ((equal data kermit-send-quotechar) 
  246.        (concat kermit-send-quotechar data))
  247.       ((equal data kermit-quote-8bit-char)
  248.        (concat kermit-send-quotechar data))
  249.       ; map LF to CRLF if text mode
  250.       ((and kermit-text-mode (eq c 10))
  251.        (concat kermit-send-quotechar (kermit-ctl 13) 
  252.            kermit-send-quotechar (kermit-ctl c)))
  253.       ((> c 127)
  254.        (concat kermit-quote-8bit-char (kermit-prefix-slow (- c 128))))
  255.       ((or (< c 32) (= c 127))
  256.        (concat kermit-send-quotechar (kermit-ctl c)))
  257.       (t  data))))
  258.  
  259. ;; Convert PACKET into a kermit-quoted packet. 
  260. ;; Returns the string containing the properly quoted packet.
  261. (defun kermit-make-data-packet (data) 
  262.   (kermit-mapstring 'kermit-prefix data t))
  263.  
  264. ;; state 0 - unquoted char
  265. ;; state 1 - #-quoted
  266. ;; state 2 - 8th bit set (&-quoted)
  267. ;; state 3 - 8th bit + #-quoted
  268. ;; string - thing to return
  269. (setq kermit-decode-table (make-vector 4 nil))
  270.  
  271. (defun kermit-decode-init ()
  272.   (let ((i 0) (table nil))
  273.     (while (< i 4)
  274.       (aset kermit-decode-table i (setq table (make-vector 256 0)))
  275.       (let ((ichar 0))
  276.     (while (< ichar 256)
  277.       (cond ((equal i 0)
  278.          (aset table ichar (char-to-string ichar)))
  279.         ((equal i 1)
  280.          (aset table ichar (kermit-ctl ichar)))
  281.         ((equal i 2)
  282.          (aset table ichar (char-to-string (+ ichar 128))))
  283.         ((equal i 3)
  284.          (aset table ichar (char-to-string
  285.                     (+ 
  286.                      128 
  287.                      (string-to-char (kermit-ctl ichar))))))
  288.         )
  289.       (setq ichar (1+ ichar))
  290.       )
  291.     )
  292.       (setq i (1+ i))
  293.       )
  294.     )
  295.   (if kermit-text-mode
  296.       (aset (aref kermit-decode-table 1) (string-to-char "M") ""))
  297.   (aset (aref kermit-decode-table 0) (string-to-char kermit-send-quotechar) 1)
  298.   (aset (aref kermit-decode-table 0) (string-to-char kermit-quote-8bit-char) 2)
  299.   (aset (aref kermit-decode-table 2) (string-to-char kermit-send-quotechar) 3)
  300.   (aset (aref kermit-decode-table 1) (string-to-char kermit-quote-8bit-char)
  301.     kermit-quote-8bit-char)
  302.   (aset (aref kermit-decode-table 1) (string-to-char kermit-send-quotechar)
  303.     kermit-send-quotechar)
  304.   (aset (aref kermit-decode-table 3) (string-to-char kermit-send-quotechar)
  305.     (char-to-string (+ 128 (string-to-char kermit-send-quotechar)))))
  306.  
  307. (defvar kermit-decode-state 0 "Current state of the decoding machine")
  308.  
  309. ;; Process a single character CHAR from an input packet. 
  310. ;; Returns the next character to be appended to the resulting packet.
  311. ;; This is a lot smaller than it used to be, yes?
  312. (defun kermit-deprefix (ichar)
  313.   (let ((rchar (aref (aref kermit-decode-table kermit-decode-state) ichar)))
  314.     (if (integerp rchar)
  315.     (progn (setq kermit-decode-state rchar) nil)
  316.       (progn (setq kermit-decode-state 0) rchar))))
  317.          
  318. ;; Convert the packet DATA into its proper representation (dequote it, 
  319. ;; basically). Returns a string with the data.
  320. (defun kermit-splode-data-packet (data) 
  321.   (kermit-mapstring 'kermit-deprefix data t))
  322.  
  323. (defun kermit-send-ack (seqnum) 
  324.   "Send an ack for packet SEQNUM to the other end."
  325.   (kermit-send-packet "Y" seqnum ""))
  326.  
  327. (defun kermit-send-nak (seqnum)
  328.   (kermit-send-packet "N" seqnum ""))
  329.  
  330.  
  331. (defun kermit-discard-input () "Trash input."
  332.   (while (input-pending-p) (read-char))
  333.   nil)
  334.  
  335. ;; Read in a character from the sender, and store in kermit-gotten-char. 
  336. ;; Return T on success, NIL on timeout.
  337. (defun kermit-do-read-char-nosum (count) 
  338.   (if (< kermit-read-char-timeout count) nil
  339.     (let ((dcount 0))
  340.       (while (and (not (input-pending-p)) (< dcount kermit-delay-count))
  341.       (accept-process-output) ; reschedule hack
  342.     (setq dcount (1+ dcount)))
  343.       (if (input-pending-p) (progn (setq kermit-gotten-char (read-char)) t)
  344.     (kermit-do-read-char-nosum (+ count 1))))))
  345.  
  346. ;; Read in a character from the sender, store it in kermit-gotten-char, and 
  347. ;; add it to kermit-checksum-total. Return T on success, NIL on timeout.
  348. (defun kermit-do-read-char ()  
  349.   (if (not (kermit-do-read-char-nosum 0)) nil
  350.     (progn
  351.       (setq kermit-checksum-total 
  352.         (+ kermit-checksum-total kermit-gotten-char))
  353.       (setq kermit-gotten-char (char-to-string kermit-gotten-char))
  354.       t)))
  355.  
  356. (defun kermit-do-read-packet () "Actually read it."
  357.   (setq kermit-packet "")
  358.   (let ((len) (kermit-len-char))
  359.     (if (not (= (read-char) (string-to-char kermit-mark-char)))
  360.     (progn (kermit-do-log "no kermit-mark-char!") (kermit-discard-input))
  361.       (progn 
  362.     (setq kermit-checksum-total 0)
  363.     (setq kermit-packet "")
  364.     (if (eq nil (catch 'kermit-getout
  365.               (if (not (kermit-do-read-char)) 
  366.               (throw 'kermit-getout nil))
  367.               (setq kermit-len-char kermit-gotten-char)
  368.               (setq len (- (kermit-fromchar kermit-gotten-char) 3))
  369.               (if (not (kermit-do-read-char)) 
  370.               (throw 'kermit-getout nil))
  371.               (setq kermit-receive-seq 
  372.                 (kermit-fromchar kermit-gotten-char))
  373.               (if (not (kermit-do-read-char)) 
  374.               (throw 'kermit-getout nil))
  375.               (setq kermit-packet-type kermit-gotten-char)
  376.               (while (> len 0)
  377.             (if (not (kermit-do-read-char)) 
  378.                 (progn 
  379.                   (kermit-do-log "short packet") 
  380.                   (throw 'kermit-getout nil)))
  381.             (setq kermit-packet 
  382.                   (concat kermit-packet kermit-gotten-char))
  383.             (setq len (1- len)))
  384.               (if (not (kermit-do-read-char-nosum 0)) 
  385.               (progn (kermit-do-log "short packet 2") 
  386.                  (throw 'kermit-getout nil)))
  387.               (if (not (equal (char-to-string kermit-gotten-char)
  388.                       (kermit-checksum-char))) 
  389.               (progn 
  390.                 (kermit-do-log 
  391.                  (concat "checksum mismatch mine is "
  392.                      (string-to-char (kermit-checksum-char))
  393.                      " his is " 
  394.                      kermit-gotten-char))
  395.                 (throw 'kermit-getout nil)))
  396.               (progn (kermit-do-log
  397.                   (concat "got good packet: " kermit-mark-char
  398.                       kermit-len-char kermit-receive-seq 
  399.                       kermit-packet-type kermit-packet 
  400.                       (kermit-checksum-char)))
  401.                  (throw 'kermit-getout t))))
  402.         (kermit-discard-input)
  403.       t)
  404.     ))
  405.     ))
  406.  
  407. (defun kermit-read-packet (count) 
  408.   "Read one packet in, and store it in kermit-packet. Return T on success."
  409.   (if (< 5 count) nil
  410.     (let ((dcount 0))
  411.       (while (and (not (input-pending-p)) (< dcount kermit-delay-count))
  412.      (accept-process-output)
  413.     (setq dcount (1+ dcount)))
  414.       (if (input-pending-p) (kermit-do-read-packet)
  415.     (kermit-read-packet (1+ count))))))
  416.  
  417. ;;
  418. ;; read initial packet & set transfer parameters - return t if successful, 
  419. ;; nil if not.
  420. ;;                     
  421. ;; 1 - maxl (max len packet) - if blank use 80
  422. ;; 2 - timeout - if blank use 5 seconds
  423. ;; 3 - number of padding chars - no padding 
  424. ;; 4 - padding characters - to be ignored if it is 0 (ctl) NUL
  425. ;; 5 - EOL char (tochar) - CR
  426. ;; 6 - QCTL control quote char - # 
  427. ;; -optional-
  428. ;; 7 - QBIN binary quote character (just send &)
  429. ;; 8 - CHKT check type (just send 1)
  430. ;; 9 - REPT repeat (just send SP)
  431. ;; 10 - ? CAPAS and beyond - ignore    
  432. ;;
  433. (defun kermit-read-init () "Read the init packet"
  434.   (let ((length-packet))
  435.     (if (not (kermit-read-packet 0))
  436.     (progn (kermit-do-log "read-packet failed") nil)
  437.       ;; decode other kermit's init packet
  438.       (setq length-packet (length kermit-packet))
  439.       (kermit-do-log "read init packet")
  440.       (if (> length-packet 0)
  441.       (progn
  442.         ;; negotiate max packet length
  443.         (setq kermit-max-packet-len 
  444.           (min kermit-max-packet-len
  445.                (if (eq (aref kermit-packet 0) 32)
  446.                80 ; space means 80 columns
  447.              (kermit-fromchar (char-to-string 
  448.                        (aref kermit-packet 0))))))))
  449.       (kermit-do-log (format "negotiated max packet length %d" 
  450.                  kermit-max-packet-len))
  451.       (if (> length-packet 1)
  452.       (progn
  453.         ;; negotiate timeout
  454.         (setq kermit-read-char-timeout
  455.           (max kermit-read-char-timeout
  456.                (if (eq (aref kermit-packet 1) 32)
  457.                5 ; space means 5 seconds
  458.              (kermit-fromchar (char-to-string
  459.                        (aref kermit-packet 1))))))))
  460. ;; if we're going to use kermit-time-loops...
  461. ;      (setq kermit-delay-count (/ (* 5 kermit-delay-count ) 
  462. ;                  kermit-read-char-timeout))
  463.       (kermit-do-log 
  464.        (format "negotiated timeout %d" kermit-read-char-timeout))
  465.       ;; we can't negotiate padding - we send what we need.
  466.       (if (> length-packet 4)
  467.       ;; negotiate EOL character - we use what other side sends
  468.       (setq kermit-line-terminator
  469.         (char-to-string 
  470.          (kermit-fromchar (char-to-string (aref kermit-packet 4))))))
  471.       (kermit-do-log
  472.        (format "negotiated end of line character ASCII %d" 
  473.            (string-to-char kermit-line-terminator)))
  474.       ;; rest of parameters we send what we need in our init packet,
  475.       ;; or we don't understand, so ignore
  476.       t)))
  477.  
  478. (defun kermit-send-init (string) "Send the init packet"
  479.   (kermit-send-packet string 0
  480.               (concat 
  481.                (kermit-tochar kermit-max-packet-len) ; MAXL
  482.                (kermit-tochar kermit-read-char-timeout) ; timeout
  483.                (kermit-tochar 0) ; number of padding chars
  484.                (kermit-tochar 0) ; pad char
  485.                (kermit-tochar (string-to-char 
  486.                        kermit-line-terminator)) ; EOL char
  487.                kermit-send-quotechar ; control quote char
  488.                kermit-quote-8bit-char))) ; binary quote char
  489.  
  490. (setq kermit-packet-in-progress "")
  491. (setq kermit-seq-number 0)
  492. (setq kermit-packet-len 0)
  493.  
  494. (defun kermit-incr-seq-number ()
  495.   (setq kermit-seq-number (mod (1+ kermit-seq-number) 64)))
  496.  
  497. (defun kermit-do-send-data (char) "Add char to be output."
  498.   (if (< (- kermit-max-packet-len 3) ; -3 for length byte, seq, and type
  499.      (+ kermit-packet-len (kermit-size-of-char char)))
  500.       (progn
  501.     (while (and 
  502.         (kermit-send-packet "D" 
  503.                     kermit-seq-number 
  504.                     kermit-packet-in-progress) 
  505.             (not (kermit-receive-ack kermit-seq-number))))
  506.     (kermit-incr-seq-number)
  507.     (setq kermit-packet-len 0)
  508.     (setq kermit-packet-in-progress "")))
  509.   (setq kermit-packet-in-progress
  510.     (concat kermit-packet-in-progress (kermit-prefix char)))
  511.   (setq kermit-packet-len (+ kermit-packet-len (kermit-size-of-char char)))
  512.   nil
  513.   )
  514.  
  515. (defun kermit-finish-file () 
  516.   "Send the final packet + EOF packet + end of transfers packet."
  517.   (if (< 0 (length kermit-packet-in-progress))
  518.       (while (and (kermit-send-packet "D" kermit-seq-number 
  519.                       kermit-packet-in-progress)
  520.           (not (kermit-receive-ack kermit-seq-number)))))
  521.   (kermit-incr-seq-number)
  522.   (while (and (kermit-send-packet "Z" kermit-seq-number "") 
  523.           (not (kermit-receive-ack kermit-seq-number))))
  524.   (kermit-incr-seq-number)
  525.   (while (and (kermit-send-packet "B" kermit-seq-number "") 
  526.           (not (kermit-receive-ack kermit-seq-number)))))
  527. ;;
  528. ;; log to a buffer for debugging porpoises
  529. ;;
  530. (defun kermit-do-real-log (list)
  531.       (save-excursion
  532.     (let ((kermit-log-buffer (get-buffer "kermit-debugging")))
  533.       (if (not kermit-log-buffer)
  534.           (setq kermit-log-buffer (generate-new-buffer 
  535.                        "kermit-debugging")))
  536.       (set-buffer kermit-log-buffer)
  537.       (insert (concat list "\C-j"))))
  538.   nil)
  539.  
  540. (defun kermit-receive-ack (sequence-number)
  541.   (kermit-do-log "called kermit-receive-ack")
  542.   (if (not (kermit-read-packet 0)) nil
  543.     (progn 
  544.       (kermit-do-log (concat "Got packet of" kermit-packet-type 
  545.                  kermit-receive-seq kermit-packet))
  546.       (if (and (equal kermit-packet-type "Y") 
  547.            (equal kermit-receive-seq sequence-number))
  548.       t 
  549.     (kermit-do-log "ack failed")))))
  550.  
  551. ;;
  552. ;; send F packet with filename argument NAME
  553. ;;
  554. (defun kermit-send-filename (name) 
  555.   (kermit-do-log "kermit-send-filename called")
  556.   (while (and (kermit-send-packet "F" kermit-seq-number name) 
  557.           (not (kermit-receive-ack kermit-seq-number))))
  558.   (kermit-incr-seq-number))
  559.  
  560. (defun kermit-receive-packet-num (number)
  561.   (catch 'kermit-doexit
  562.     (while (kermit-read-packet 0)
  563.       (if (equal kermit-receive-seq number)
  564.       (progn
  565.         (kermit-send-ack number)
  566.         (throw 'kermit-doexit t)
  567.         )
  568.     (kermit-send-nak number)))))
  569.  
  570. (defun kermit-receive-filename ()
  571.   (kermit-receive-packet-num kermit-seq-number)
  572.   (if (equal kermit-packet-type "F")
  573.       (progn
  574.     (setq kermit-filename (kermit-splode-data-packet kermit-packet))
  575.     t)
  576.     (progn
  577.       (if (equal kermit-packet-type "S") (kermit-send-init "Y"))
  578.       nil))
  579.   )
  580.  
  581. ;;
  582. ;; receive D packets until E, B, or Z packet terminates transfer
  583. ;;
  584. (defun kermit-receive-data-packets ()
  585.   (save-excursion
  586.     (set-buffer kermit-transfer-buffer)
  587.     (catch 'kermit-leave
  588.       (while (kermit-receive-packet-num kermit-seq-number)
  589.     (kermit-incr-seq-number)
  590.     (set-buffer kermit-transfer-buffer)
  591.     (goto-char (point-max))
  592.     (if (equal kermit-packet-type "Z") (throw 'kermit-leave t))
  593.     (if (or (equal kermit-packet-type "B") 
  594.         (equal kermit-packet-type "E"))
  595.         (throw 'kermit-leave nil))
  596.                     ; Ze bed, boss, ze bed!
  597.     (if (equal kermit-packet-type "D")
  598.         (insert-string (kermit-splode-data-packet kermit-packet)))))))
  599.  
  600. (defun kermit-send-buffer (buffer) 
  601.   "Sends the buffer via the Kermit protocol to the other end." 
  602.   (interactive "bSend buffer: ")
  603.   (kermit-blank-screen)
  604.   (kermit-time-loops 500)
  605.   (setq kermit-seq-number 0)
  606.   (setq kermit-transfer-buffer (get-buffer buffer))
  607.   (while (and (kermit-send-init "S") (not (kermit-read-init))))
  608.   (init-kermit-prefix)
  609.   (kermit-decode-init)
  610.   (kermit-incr-seq-number)
  611.   (save-excursion
  612.     (set-buffer kermit-transfer-buffer)
  613.     (kermit-send-filename (buffer-name kermit-transfer-buffer))
  614.     (setq kermit-packet-in-progress "")
  615.     (setq kermit-packet-len 0)
  616.     (kermit-mapstring 'kermit-do-send-data (buffer-string) nil)
  617.     (kermit-finish-file))
  618.   (kermit-unblank-screen))
  619.  
  620. ;;
  621. ;; M-x kermit-receive-buffer, escape back to your local system
  622. ;; and issue the send command.
  623. ;;
  624. (defun kermit-receive-buffer () "Receive a file into a buffer."
  625.   (interactive)
  626.   (setq kermit-seq-number 0)
  627.   (kermit-blank-screen)
  628.   (kermit-time-loops 500)
  629.   (while (and (not (kermit-read-init)) (kermit-send-nak 0)))
  630.   (kermit-send-init "Y")
  631.   (init-kermit-prefix)
  632.   (kermit-decode-init)
  633.   (kermit-incr-seq-number)
  634.   (while (not (kermit-receive-filename)))
  635.   (kermit-incr-seq-number)
  636.   (save-excursion
  637.     (setq kermit-transfer-buffer (generate-new-buffer kermit-filename))
  638.     (set-buffer kermit-transfer-buffer)
  639.     (kermit-receive-data-packets)
  640.     (kermit-receive-packet-num kermit-seq-number)
  641.     (set-visited-file-name kermit-filename))
  642.   (kermit-unblank-screen)
  643.   (switch-to-buffer kermit-transfer-buffer))
  644.  
  645. (defun kermit-send-current-buffer () (interactive) 
  646.   (kermit-send-buffer (current-buffer)))
  647.  
  648. ;;
  649. ;; blank the screen to minimize the effect of (display-time) and other 
  650. ;; processes might have on kermit
  651. ;;
  652. (defun kermit-blank-screen ()
  653.   (setq kermit-transfer-buffer (current-buffer))
  654.   (setq kermit-blank-buffer (get-buffer-create "*kermit*"))
  655.   (switch-to-buffer kermit-blank-buffer)
  656.   (delete-other-windows)
  657.   (redraw-display)
  658.   (make-local-variable 'echo-keystrokes)
  659.   (setq echo-keystrokes 0)
  660.   (setq mode-line-format '("")))
  661.     
  662. ;;
  663. ;; remove the blank buffer
  664. ;;
  665. (defun kermit-unblank-screen ()
  666.   (switch-to-buffer kermit-blank-buffer)
  667.   (kill-buffer (current-buffer)))
  668.  
  669. ;;
  670. ;; Use adaptive timing renooberation technology to determine just how many
  671. ;; times we gotta call (input-pending-p) to make up 1 second. 
  672. ;;
  673.  
  674. (defun kermit-time-loops (try)
  675.   (if (= kermit-delay-count 0)
  676.       (let ((currtime) (count))
  677.     (setq count try)
  678.     (setq currtime (kermit-time-to-int (current-time-string)))
  679.     (while (> count 0)
  680.       (input-pending-p)
  681.       (accept-process-output) 
  682.       (setq count (1- count)))
  683.     (setq currtime (car (cdr (kermit-time-diff 
  684.                   (kermit-time-to-int (current-time-string)) 
  685.                   currtime))))
  686.     (if (> currtime 2)
  687.         (setq kermit-delay-count (/ try currtime))
  688.       (kermit-time-loops (* 3 try))))))
  689.  
  690.       
  691. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  692. ;;; These functions are used to implement time handling.
  693. ;;; Much of this code was lifted from the Kiwi 4.30 irc client.
  694. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  695. (defun kermit-time-to-int (timestr)
  696.   "Convert from time in string format as returned by current-time-string
  697. to a double integer format, as returned by file-attributes.
  698.  
  699. Written by Stephen Ma <ma_s@maths.su.oz.au>"
  700.   (let* ((norm+ '(lambda (num1 num2)
  701.           (let ((sumh (+ (car num1) (car num2)))
  702.             (suml (+ (car (cdr num1)) (car (cdr num2)))))
  703.             (list (+ sumh (/ suml 65536)) (% suml 65536)))))
  704.      (norm* '(lambda (num1 num2)
  705.           (let ((prodh (* num1 (car num2)))
  706.             (prodl (* num1 (car (cdr num2)))))
  707.             (list (+ prodh (/ prodl 65536)) (% prodl 65536)))))
  708.      (seconds (string-to-int (substring timestr 17 19)))
  709.      (minutes (string-to-int (substring timestr 14 16)))
  710.      (hours (string-to-int (substring timestr 11 13)))
  711.      (partdays (1- (string-to-int (substring timestr 8 10))))
  712.      (years (string-to-int (substring timestr 20 24)))
  713.      (days (+ partdays
  714.           (cond ((and (= (% years 4) 0)
  715.                   (/= (% years 100) 0))
  716.              (cdr (assoc (substring timestr 4 7)
  717.                      '(("Jan" . 0)
  718.                        ("Feb" . 31)
  719.                        ("Mar" . 60)
  720.                        ("Apr" . 91)
  721.                        ("May" . 121)
  722.                        ("Jun" . 152)
  723.                        ("Jul" . 182)
  724.                        ("Aug" . 213)
  725.                        ("Sep" . 244)
  726.                        ("Oct" . 274)
  727.                        ("Nov" . 305)
  728.                        ("Dec" . 335)))))
  729.             (t (cdr (assoc (substring timestr 4 7)
  730.                        '(("Jan" . 0)
  731.                      ("Feb" . 31)
  732.                      ("Mar" . 59)
  733.                      ("Apr" . 90)
  734.                      ("May" . 120)
  735.                      ("Jun" . 151)
  736.                      ("Jul" . 181)
  737.                      ("Aug" . 212)
  738.                      ("Sep" . 243)
  739.                      ("Oct" . 273)
  740.                      ("Nov" . 304)
  741.                      ("Dec" . 334))))))
  742.           (* (- years 1970) 365)
  743.           (/ (- years 1969) 4)
  744.           (- (/ (- years 1901) 100)))))
  745.     (funcall norm+
  746.          (funcall norm*
  747.               60
  748.               (funcall norm+
  749.                    (funcall norm*
  750.                     60
  751.                     (funcall norm+
  752.                          (funcall norm*
  753.                               24
  754.                               (list 0 days))
  755.                          (list 0 hours)))
  756.                    (list 0 minutes)))
  757.          (list 0 seconds))))
  758. ;;
  759. (defun kermit-time-diff (a b)
  760.   "Return the difference between two times. This function requires
  761. the second argument to be earlier in time than the first argument."
  762.   (cond ((= (nth 0 a) (nth 0 b)) (list 0 (- (nth 1 a) (nth 1  b))))
  763.     ((> (nth 1 b) (nth 1 a)) (list (- (nth 0 a) (nth 0 b) 1)
  764.                        (- (+ 65536 (nth 1 a)) (nth 1 b))))
  765.     (t (list (- (nth 0 a) (nth 0 b))
  766.          (- (nth 1 a) (nth 1 b))))))
  767.  
  768.  
  769. ;;; End of kermit.el
  770.