Move lisp/emacs-lisp/authors.el to admin/
[bpt/emacs.git] / lisp / gnus / qp.el
CommitLineData
c113de23 1;;; qp.el --- Quoted-Printable functions
657b2c65 2
ba318903 3;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
c113de23
GM
4
5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
657b2c65
DL
6;; Keywords: mail, extensions
7
c113de23
GM
8;; This file is part of GNU Emacs.
9
5e809f55 10;; GNU Emacs is free software: you can redistribute it and/or modify
c113de23 11;; it under the terms of the GNU General Public License as published by
5e809f55
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
c113de23
GM
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
5e809f55 17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c113de23
GM
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
5e809f55 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
c113de23
GM
22
23;;; Commentary:
24
657b2c65
DL
25;; Functions for encoding and decoding quoted-printable text as
26;; defined in RFC 2045.
c113de23 27
657b2c65 28;;; Code:
c113de23 29
b756f5b4 30(require 'mm-util)
9efa445f 31(defvar mm-use-ultra-safe-encoding)
d21a76da 32
23f87bed 33;;;###autoload
d21a76da 34(defun quoted-printable-decode-region (from to &optional coding-system)
657b2c65 35 "Decode quoted-printable in the region between FROM and TO, per RFC 2045.
d21a76da 36If CODING-SYSTEM is non-nil, decode bytes into characters with that
5c543a33
SZ
37coding-system.
38
39Interactively, you can supply the CODING-SYSTEM argument
23f87bed
MB
40with \\[universal-coding-system-argument].
41
42The CODING-SYSTEM argument is a historical hangover and is deprecated.
43QP encodes raw bytes and should be decoded into raw bytes. Decoding
44them into characters should be done separately."
753b4645
EZ
45 (interactive
46 ;; Let the user determine the coding system with "C-x RET c".
47 (list (region-beginning) (region-end) coding-system-for-read))
b5287163
DL
48 (unless (mm-coding-system-p coding-system) ; e.g. `ascii' from Gnus
49 (setq coding-system nil))
c113de23
GM
50 (save-excursion
51 (save-restriction
b5287163
DL
52 ;; RFC 2045: ``An "=" followed by two hexadecimal digits, one
53 ;; or both of which are lowercase letters in "abcdef", is
54 ;; formally illegal. A robust implementation might choose to
55 ;; recognize them as the corresponding uppercase letters.''
9b851e25 56 (let ((case-fold-search t))
c113de23 57 (narrow-to-region from to)
d21a76da
DL
58 ;; Do this in case we're called from Gnus, say, in a buffer
59 ;; which already contains non-ASCII characters which would
60 ;; then get doubly-decoded below.
61 (if coding-system
62 (mm-encode-coding-region (point-min) (point-max) coding-system))
63 (goto-char (point-min))
e4f99da7 64 (while (and (skip-chars-forward "^=")
657b2c65
DL
65 (not (eobp)))
66 (cond ((eq (char-after (1+ (point))) ?\n)
67 (delete-char 2))
8b0c72d3
KH
68 ((looking-at "\\(=[0-9A-F][0-9A-F]\\)+")
69 ;; Decode this sequence at once; i.e. by a single
70 ;; deletion and insertion.
71 (let* ((n (/ (- (match-end 0) (point)) 3))
72 (str (make-string n 0)))
73 (dotimes (i n)
9b851e25
SM
74 (let ((n1 (char-after (1+ (point))))
75 (n2 (char-after (+ 2 (point)))))
76 (aset str i
77 (+ (* 16 (- n1 (if (<= n1 ?9) ?0
78 (if (<= n1 ?F) (- ?A 10)
79 (- ?a 10)))))
80 (- n2 (if (<= n2 ?9) ?0
81 (if (<= n2 ?F) (- ?A 10)
82 (- ?a 10)))))))
8b0c72d3
KH
83 (forward-char 3))
84 (delete-region (match-beginning 0) (match-end 0))
85 (insert str)))
657b2c65 86 (t
23f87bed 87 (message "Malformed quoted-printable text")
d21a76da
DL
88 (forward-char)))))
89 (if coding-system
90 (mm-decode-coding-region (point-min) (point-max) coding-system)))))
c113de23 91
d21a76da 92(defun quoted-printable-decode-string (string &optional coding-system)
657b2c65 93 "Decode the quoted-printable encoded STRING and return the result.
c590ed3a 94If CODING-SYSTEM is non-nil, decode the string with coding-system.
23f87bed
MB
95Use of CODING-SYSTEM is deprecated; this function should deal with
96raw bytes, and coding conversion should be done separately."
97 (mm-with-unibyte-buffer
c113de23 98 (insert string)
d21a76da 99 (quoted-printable-decode-region (point-min) (point-max) coding-system)
c113de23
GM
100 (buffer-string)))
101
102(defun quoted-printable-encode-region (from to &optional fold class)
657b2c65 103 "Quoted-printable encode the region between FROM and TO per RFC 2045.
c113de23 104
657b2c65 105If FOLD, fold long lines at 76 characters (as required by the RFC).
e4f99da7
DL
106If CLASS is non-nil, translate the characters not matched by that
107regexp class, which is in the form expected by `skip-chars-forward'.
108You should probably avoid non-ASCII characters in this arg.
c113de23 109
657b2c65 110If `mm-use-ultra-safe-encoding' is set, fold lines unconditionally and
c113de23
GM
111encode lines starting with \"From\"."
112 (interactive "r")
657b2c65 113 (unless class
158d6e07
SZ
114 ;; Avoid using 8bit characters. = is \075.
115 ;; Equivalent to "^\000-\007\013\015-\037\200-\377="
116 (setq class "\010-\012\014\040-\074\076-\177"))
c113de23 117 (save-excursion
cd01ded9
MB
118 (goto-char from)
119 (if (re-search-forward (mm-string-to-multibyte "[^\x0-\x7f\x80-\xff]")
120 to t)
121 (error "Multibyte character in QP encoding region"))
c113de23
GM
122 (save-restriction
123 (narrow-to-region from to)
e4f99da7
DL
124 ;; Encode all the non-ascii and control characters.
125 (goto-char (point-min))
126 (while (and (skip-chars-forward class)
127 (not (eobp)))
128 (insert
129 (prog1
5f4264e5 130 ;; To unibyte in case of Emacs 23 (unicode) eight-bit.
5f8dd322 131 (format "=%02X" (mm-multibyte-char-to-unibyte (char-after)))
e4f99da7
DL
132 (delete-char 1))))
133 ;; Encode white space at the end of lines.
134 (goto-char (point-min))
135 (while (re-search-forward "[ \t]+$" nil t)
136 (goto-char (match-beginning 0))
137 (while (not (eolp))
c113de23
GM
138 (insert
139 (prog1
158d6e07 140 (format "=%02X" (char-after))
b03b1ad2
DL
141 (delete-char 1)))))
142 (let ((mm-use-ultra-safe-encoding
143 (and (boundp 'mm-use-ultra-safe-encoding)
144 mm-use-ultra-safe-encoding)))
145 (when (or fold mm-use-ultra-safe-encoding)
146 (let ((tab-width 1)) ; HTAB is one character.
147 (goto-char (point-min))
148 (while (not (eobp))
149 ;; In ultra-safe mode, encode "From " at the beginning
150 ;; of a line.
151 (when mm-use-ultra-safe-encoding
152 (if (looking-at "From ")
153 (replace-match "From=20" nil t)
154 (if (looking-at "-")
155 (replace-match "=2D" nil t))))
156 (end-of-line)
157 ;; Fold long lines.
158 (while (> (current-column) 76) ; tab-width must be 1.
159 (beginning-of-line)
160 (forward-char 75) ; 75 chars plus an "="
161 (search-backward "=" (- (point) 2) t)
162 (insert "=\n")
163 (end-of-line))
164 (forward-line))))))))
c113de23
GM
165
166(defun quoted-printable-encode-string (string)
657b2c65 167 "Encode the STRING as quoted-printable and return the result."
9c1cf631
GM
168 (with-temp-buffer
169 (if (mm-multibyte-string-p string)
170 (mm-enable-multibyte)
171 (mm-disable-multibyte))
172 (insert string)
173 (quoted-printable-encode-region (point-min) (point-max))
174 (buffer-string)))
c113de23
GM
175
176(provide 'qp)
177
657b2c65 178;;; qp.el ends here