1 ;;; eword-decode.el --- RFC 2047 based encoded-word decoder for GNU Emacs
3 ;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
5 ;; Author: ENAMI Tsugutomo <enami@sys.ptg.sony.co.jp>
6 ;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
7 ;; Tanaka Akira <akr@jaist.ac.jp>
8 ;; Maintainer: Tanaka Akira <akr@jaist.ac.jp>
10 ;; Original: 1992/07/20 ENAMI Tsugutomo's `mime.el'.
11 ;; Renamed: 1993/06/03 to tiny-mime.el
12 ;; Renamed: 1995/10/03 from tiny-mime.el (split off encoder)
13 ;; Renamed: 1997/02/22 from tm-ew-d.el
14 ;; Keywords: encoded-word, MIME, multilingual, header, mail, news
16 ;; This file is part of FLAM (Faithful Library About MIME).
18 ;; This program is free software; you can redistribute it and/or
19 ;; modify it under the terms of the GNU General Public License as
20 ;; published by the Free Software Foundation; either version 2, or (at
21 ;; your option) any later version.
23 ;; This program is distributed in the hope that it will be useful, but
24 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 ;; General Public License for more details.
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with GNU Emacs; see the file COPYING. If not, write to the
30 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
31 ;; Boston, MA 02111-1307, USA.
39 (defgroup eword-decode nil
40 "Encoded-word decoding"
47 (defcustom eword-decode-sticked-encoded-word nil
48 "*If non-nil, decode encoded-words sticked on atoms,
49 other encoded-words, etc.
50 however this behaviour violates RFC2047."
54 (defcustom eword-decode-quoted-encoded-word nil
55 "*If non-nil, decode encoded-words in quoted-string
56 however this behaviour violates RFC2047."
61 ;;; @ MIME encoded-word definition
64 (defconst eword-encoded-word-prefix-regexp
65 (concat (regexp-quote "=?")
66 "\\(" mime-charset-regexp "\\)"
70 (defconst eword-encoded-word-suffix-regexp
73 (defconst eword-encoded-text-in-unstructured-regexp "[!->@-~]+")
74 (defconst eword-encoded-word-in-unstructured-regexp
75 (concat eword-encoded-word-prefix-regexp
76 "\\(" eword-encoded-text-in-unstructured-regexp "\\)"
77 eword-encoded-word-suffix-regexp))
78 (defconst eword-after-encoded-word-in-unstructured-regexp "\\([ \t]\\|$\\)")
80 (defconst eword-encoded-text-in-phrase-regexp "[-A-Za-z0-9!*+/=_]+")
81 (defconst eword-encoded-word-in-phrase-regexp
82 (concat eword-encoded-word-prefix-regexp
83 "\\(" eword-encoded-text-in-phrase-regexp "\\)"
84 eword-encoded-word-suffix-regexp))
85 (defconst eword-after-encoded-word-in-phrase-regexp "\\([ \t(]\\|$\\)")
87 (defconst eword-encoded-text-in-comment-regexp "[]!-'*->@-[^-~]+")
88 (defconst eword-encoded-word-in-comment-regexp
89 (concat eword-encoded-word-prefix-regexp
90 "\\(" eword-encoded-text-in-comment-regexp "\\)"
91 eword-encoded-word-suffix-regexp))
92 (defconst eword-after-encoded-word-in-comment-regexp "\\([ \t()\\\\]\\|$\\)")
94 (defconst eword-encoded-text-in-quoted-string-regexp "[]!#->@-[^-~]+")
95 (defconst eword-encoded-word-in-quoted-string-regexp
96 (concat eword-encoded-word-prefix-regexp
97 "\\(" eword-encoded-text-in-quoted-string-regexp "\\)"
98 eword-encoded-word-suffix-regexp))
99 (defconst eword-after-encoded-word-in-quoted-string-regexp "\\([ \t\"\\\\]\\|$\\)")
102 (defconst eword-encoded-text-regexp eword-encoded-text-in-unstructured-regexp)
103 (defconst eword-encoded-word-regexp eword-encoded-word-in-unstructured-regexp)
109 (defconst base64-token-regexp "[A-Za-z0-9+/]")
110 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
112 (defconst eword-B-encoded-text-regexp
121 base64-token-padding-regexp
122 base64-token-padding-regexp
125 ;; (defconst eword-B-encoding-and-encoded-text-regexp
126 ;; (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
129 ;;; @@ Quoted-Printable
132 (defconst eword-Q-encoded-text-regexp
133 (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
134 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
135 ;; (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
138 ;;; @ internal utilities
141 (defun eword-decode-first-encoded-words (string
144 &optional must-unfold)
145 "Decode MIME encoded-words in beginning of STRING.
147 EWORD-REGEXP is the regexp that matches a encoded-word.
149 eword-encoded-word-in-unstructured-regexp,
150 eword-encoded-text-in-phrase-regexp,
151 eword-encoded-word-in-comment-regexp or
152 eword-encoded-word-in-quoted-string-regexp.
154 AFTER-REGEXP is the regexp that matches a after encoded-word.
156 eword-after-encoded-word-in-unstructured-regexp,
157 eword-after-encoded-text-in-phrase-regexp,
158 eword-after-encoded-word-in-comment-regexp or
159 eword-after-encoded-word-in-quoted-string-regexp.
161 If beginning of STRING matches EWORD-REGEXP with AFTER-REGEXP,
162 returns a cons cell of decoded string(sequence of characters) and
163 the rest(sequence of octets).
165 If beginning of STRING does not matches EWORD-REGEXP and AFTER-REGEXP,
168 If an encoded-word is broken or your emacs implementation can not
169 decode the charset included in it, it is returned in decoded part
170 as encoded-word form.
172 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
173 if there are in decoded encoded-words (generated by bad manner MUA
174 such as a version of Net$cape)."
175 (if eword-decode-sticked-encoded-word (setq after-regexp ""))
176 (let* ((between-ewords-regexp
177 (if eword-decode-sticked-encoded-word
180 (between-ewords-eword-after-regexp
181 (concat "\\`\\(" between-ewords-regexp "\\)"
182 "\\(" eword-regexp "\\)"
185 (concat "\\`\\(" eword-regexp "\\)" after-regexp))
186 (src string) ; sequence of octets.
187 (dst "")) ; sequence of characters.
188 (if (string-match eword-after-regexp src)
191 (ew (substring src 0 q))
192 (dw (eword-decode-encoded-word ew must-unfold)))
193 (setq dst (concat dst dw)
194 src (substring src q))
195 (if (not (string= ew dw))
199 (string-match between-ewords-eword-after-regexp src)
201 (setq p (match-end 1)
203 ew (substring src p q)
204 dw (eword-decode-encoded-word ew must-unfold))
207 (setq dst (concat dst (substring src 0 q))
208 src (substring src q))
211 (setq dst (concat dst dw)
212 src (substring src q)))))
216 (defun eword-decode-entire-string (string
221 delimiters ; list of chars.
224 (if (and code-conversion
225 (not (mime-charset-to-coding-system code-conversion)))
226 (setq code-conversion default-mime-charset))
227 (let ((equal-safe-regexp (concat "\\`=?" safe-regexp))
232 (while (< 0 (length src))
233 (let ((ch (aref src 0))
236 (eword-decode-first-encoded-words src
237 eword-regexp after-regexp must-unfold))))
238 (if (and (not (string= buf ""))
239 (or decoded (memq ch delimiters)))
240 (setq dst (concat dst
241 (std11-wrap-as-quoted-pairs
242 (decode-mime-charset-string buf code-conversion)
247 (setq dst (concat dst
248 (std11-wrap-as-quoted-pairs
252 ((memq ch delimiters)
253 (setq dst (concat dst (list ch))
254 src (substring src 1)
257 (setq buf (concat buf (list (aref src 1)))
258 src (substring src 2)
260 ((string-match "\\`[ \t\n]+" src)
261 (setq buf (concat buf (substring src 0 (match-end 0)))
262 src (substring src (match-end 0))
264 ((and (string-match equal-safe-regexp src)
266 (setq buf (concat buf (substring src 0 (match-end 0)))
267 src (substring src (match-end 0))
268 ew-enable eword-decode-sticked-encoded-word))
269 (t (error "something wrong")))))
270 (if (not (string= buf ""))
271 (setq dst (concat dst
272 (std11-wrap-as-quoted-pairs
273 (decode-mime-charset-string buf code-conversion)
281 (defun eword-decode-unstructured (string code-conversion &optional must-unfold)
282 (eword-decode-entire-string
284 eword-encoded-word-in-unstructured-regexp
285 eword-after-encoded-word-in-unstructured-regexp
292 (defun eword-decode-comment (string code-conversion &optional must-unfold)
293 (eword-decode-entire-string
295 eword-encoded-word-in-comment-regexp
296 eword-after-encoded-word-in-comment-regexp
303 (defun eword-decode-quoted-string (string code-conversion &optional must-unfold)
304 (eword-decode-entire-string
306 eword-encoded-word-in-quoted-string-regexp
307 eword-after-encoded-word-in-quoted-string-regexp
314 (defun eword-decode-string (string &optional must-unfold code-conversion)
315 "Decode MIME encoded-words in STRING.
317 STRING is unfolded before decoding.
319 If an encoded-word is broken or your emacs implementation can not
320 decode the charset included in it, it is not decoded.
322 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
323 if there are in decoded encoded-words (generated by bad manner MUA
324 such as a version of Net$cape).
326 If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
327 mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
328 Otherwise it decodes non-ASCII bit patterns as the
329 default-mime-charset."
330 (eword-decode-unstructured
331 (std11-unfold-string string)
339 (defun eword-decode-region (start end &optional unfolding must-unfold
341 "Decode MIME encoded-words in region between START and END.
343 If UNFOLDING is not nil, it unfolds before decoding.
345 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
346 if there are in decoded encoded-words (generated by bad manner MUA
347 such as a version of Net$cape).
349 If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
350 mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
351 Otherwise it decodes non-ASCII bit patterns as the
352 default-mime-charset."
356 (narrow-to-region start end)
358 (eword-decode-unfold)
360 (let ((str (eword-decode-unstructured
361 (buffer-substring (point-min) (point-max))
364 (delete-region (point-min) (point-max))
368 ;;; @ for message header
371 (defcustom eword-decode-ignored-field-list
372 '(newsgroups path lines nntp-posting-host received message-id date)
373 "*List of field-names to be ignored when decoding.
374 Each field name must be symbol."
376 :type '(repeat symbol))
378 (defcustom eword-decode-structured-field-list
379 '(reply-to resent-reply-to from resent-from sender resent-sender
380 to resent-to cc resent-cc bcc resent-bcc dcc
381 mime-version content-type content-transfer-encoding
383 "*List of field-names to decode as structured field.
384 Each field name must be symbol."
386 :type '(repeat symbol))
388 (defun eword-decode-header (&optional code-conversion separator)
389 "Decode MIME encoded-words in header fields.
390 If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
391 mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
392 Otherwise it decodes non-ASCII bit patterns as the
393 default-mime-charset.
394 If SEPARATOR is not nil, it is used as header separator."
396 (if (and code-conversion
397 (not (mime-charset-to-coding-system code-conversion)))
398 (setq code-conversion default-mime-charset))
401 (std11-narrow-to-header separator)
403 (let (beg p end field-name len)
404 (goto-char (point-min))
405 (while (re-search-forward std11-field-head-regexp nil t)
406 (setq beg (match-beginning 0)
408 field-name (buffer-substring beg (1- p))
409 len (string-width field-name)
410 field-name (intern (downcase field-name))
411 end (std11-field-end))
412 (cond ((memq field-name eword-decode-ignored-field-list)
415 ((memq field-name eword-decode-structured-field-list)
416 ;; Decode as structured field
417 (let ((body (buffer-substring p end)))
418 (delete-region p end)
419 (insert (eword-decode-and-fold-structured-field
423 ;; Decode as unstructured field
425 (narrow-to-region beg (1+ end))
427 (eword-decode-region beg (point-max) 'unfold nil
429 (goto-char (point-max))
431 (eword-decode-region (point-min) (point-max) t nil nil)
434 (defun eword-decode-unfold ()
435 (goto-char (point-min))
437 (while (re-search-forward std11-field-head-regexp nil t)
438 (setq beg (match-beginning 0)
439 end (std11-field-end))
440 (setq field (buffer-substring beg end))
441 (if (string-match eword-encoded-word-regexp field)
443 (narrow-to-region (goto-char beg) end)
444 (while (re-search-forward "\n\\([ \t]\\)" nil t)
445 (replace-match (match-string 1))
447 (goto-char (point-max))
452 ;;; @ encoded-word decoder
455 (defvar eword-decode-encoded-word-error-handler
456 'eword-decode-encoded-word-default-error-handler)
458 (defvar eword-warning-face nil
459 "Face used for invalid encoded-word.")
461 (defun eword-decode-encoded-word-default-error-handler (word signal)
462 (and (add-text-properties 0 (length word)
463 (and eword-warning-face
464 (list 'face eword-warning-face))
468 (defun eword-decode-encoded-word (word &optional must-unfold)
469 "Decode WORD if it is an encoded-word.
471 If your emacs implementation can not decode the charset of WORD, it
472 returns WORD. Similarly the encoded-word is broken, it returns WORD.
474 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
475 if there are in decoded encoded-word (generated by bad manner MUA such
476 as a version of Net$cape)."
477 (or (if (string-match eword-encoded-word-regexp word)
479 (substring word (match-beginning 1) (match-end 1))
483 (substring word (match-beginning 2) (match-end 2))
486 (substring word (match-beginning 3) (match-end 3))
489 (eword-decode-encoded-text charset encoding text must-unfold)
491 (funcall eword-decode-encoded-word-error-handler word err)
497 ;;; @ encoded-text decoder
500 (defun eword-decode-encoded-text (charset encoding string
501 &optional must-unfold)
502 "Decode STRING as an encoded-text.
504 If your emacs implementation can not decode CHARSET, it returns nil.
506 If ENCODING is not \"B\" or \"Q\", it occurs error.
507 So you should write error-handling code if you don't want break by errors.
509 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
510 if there are in decoded encoded-text (generated by bad manner MUA such
511 as a version of Net$cape)."
512 (let ((cs (mime-charset-to-coding-system charset)))
516 ((string-equal "B" encoding)
517 (if (and (string-match eword-B-encoded-text-regexp string)
518 (string-equal string (match-string 0 string)))
519 (base64-decode-string string)
520 (error "Invalid encoded-text %s" string)))
521 ((string-equal "Q" encoding)
522 (if (and (string-match eword-Q-encoded-text-regexp string)
523 (string-equal string (match-string 0 string)))
524 (q-encoding-decode-string string)
525 (error "Invalid encoded-text %s" string)))
527 (error "Invalid encoding %s" encoding)
532 (setq dest (decode-coding-string dest cs))
539 (t (char-to-string chr)))
541 (std11-unfold-string dest)
547 ;;; @ lexical analyze
550 (defvar eword-lexical-analyze-cache nil)
551 (defvar eword-lexical-analyze-cache-max 299
552 "*Max position of eword-lexical-analyze-cache.
553 It is max size of eword-lexical-analyze-cache - 1.")
555 (defcustom eword-lexical-analyzers
556 '(eword-analyze-quoted-string
557 eword-analyze-domain-literal
558 eword-analyze-comment
560 eword-analyze-special
561 eword-analyze-encoded-word
563 "*List of functions to return result of lexical analyze.
564 Each function must have two arguments: STRING and MUST-UNFOLD.
565 STRING is the target string to be analyzed.
566 If MUST-UNFOLD is not nil, each function must unfold and eliminate
567 bare-CR and bare-LF from the result even if they are included in
568 content of the encoded-word.
569 Each function must return nil if it can not analyze STRING as its
572 Previous function is preferred to next function. If a function
573 returns nil, next function is used. Otherwise the return value will
576 :type '(repeat function))
578 (defun eword-analyze-quoted-string (string &optional must-unfold)
579 (let ((p (std11-check-enclosure string ?\" ?\")))
581 (cons (cons 'quoted-string
582 (if eword-decode-quoted-encoded-word
583 (eword-decode-quoted-string
584 (substring string 0 p)
585 default-mime-charset)
586 (decode-mime-charset-string
587 (std11-strip-quoted-pair (substring string 0 p))
588 default-mime-charset)))
589 (substring string p)))
592 (defun eword-analyze-domain-literal (string &optional must-unfold)
593 (std11-analyze-domain-literal string))
595 (defun eword-analyze-comment (string &optional must-unfold)
596 (let ((len (length string)))
597 (if (and (< 0 len) (eq (aref string 0) ?\())
599 (while (and p (< p len) (eq (aref string p) ?\())
600 (setq p (std11-check-enclosure string ?\( ?\) t p)))
603 (eword-decode-comment
604 (std11-unfold-string (substring string 0 p))
605 default-mime-charset))
606 (substring string p)))
609 (defun eword-analyze-spaces (string &optional must-unfold)
610 (std11-analyze-spaces string))
612 (defun eword-analyze-special (string &optional must-unfold)
613 (std11-analyze-special string))
615 (defun eword-analyze-encoded-word (string &optional must-unfold)
616 (let ((decoded (eword-decode-first-encoded-words
618 eword-encoded-word-in-phrase-regexp
619 eword-after-encoded-word-in-phrase-regexp
622 (cons (cons 'atom (car decoded)) (cdr decoded)))))
624 (defun eword-analyze-atom (string &optional must-unfold)
625 (if (let ((enable-multibyte-characters nil))
626 (string-match std11-atom-regexp string))
627 (let ((end (match-end 0)))
628 (if (and eword-decode-sticked-encoded-word
629 (string-match eword-encoded-word-in-phrase-regexp
630 (substring string 0 end))
631 (< 0 (match-beginning 0)))
632 (setq end (match-beginning 0)))
633 (cons (cons 'atom (decode-mime-charset-string
634 (substring string 0 end)
635 default-mime-charset))
636 (substring string end)
639 (defun eword-lexical-analyze-internal (string must-unfold)
641 (while (not (string-equal string ""))
643 (let ((rest eword-lexical-analyzers)
645 (while (and (setq func (car rest))
646 (null (setq r (funcall func string must-unfold)))
648 (setq rest (cdr rest)))
649 (or r `((error . ,string) . ""))
651 (setq dest (cons (car ret) dest))
652 (setq string (cdr ret))
657 (defun eword-lexical-analyze (string &optional must-unfold)
658 "Return lexical analyzed list corresponding STRING.
659 It is like std11-lexical-analyze, but it decodes non us-ascii
660 characters encoded as encoded-words or invalid \"raw\" format.
661 \"Raw\" non us-ascii characters are regarded as variable
662 `default-mime-charset'."
663 (let* ((str (copy-sequence string))
664 (key (cons str (cons default-mime-charset must-unfold)))
666 (set-text-properties 0 (length str) nil str)
667 (if (setq ret (assoc key eword-lexical-analyze-cache))
669 (setq ret (eword-lexical-analyze-internal str must-unfold))
670 (setq eword-lexical-analyze-cache
672 (last eword-lexical-analyze-cache
673 eword-lexical-analyze-cache-max)))
676 (defun eword-decode-token (token)
679 (defun eword-decode-and-fold-structured-field
680 (string start-column &optional max-column must-unfold)
681 "Decode and fold (fill) STRING as structured field body.
682 It decodes non us-ascii characters in FULL-NAME encoded as
683 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
684 characters are regarded as variable `default-mime-charset'.
686 If an encoded-word is broken or your emacs implementation can not
687 decode the charset included in it, it is not decoded.
689 If MAX-COLUMN is omitted, `fill-column' is used.
691 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
692 if there are in decoded encoded-words (generated by bad manner MUA
693 such as a version of Net$cape)."
695 (setq max-column fill-column))
696 (let ((c start-column)
697 (tokens (eword-lexical-analyze string must-unfold))
700 (while (and (setq token (car tokens))
701 (setq tokens (cdr tokens)))
702 (let* ((type (car token)))
703 (if (eq type 'spaces)
704 (let* ((next-token (car tokens))
705 (next-str (eword-decode-token next-token))
706 (next-len (string-width next-str))
707 (next-c (+ c next-len 1)))
708 (if (< next-c max-column)
709 (setq result (concat result " " next-str)
711 (setq result (concat result "\n " next-str)
713 (setq tokens (cdr tokens))
715 (let* ((str (eword-decode-token token)))
716 (setq result (concat result str)
717 c (+ c (string-width str)))
720 (concat result (eword-decode-token token))
723 (defun eword-decode-and-unfold-structured-field (string)
724 "Decode and unfold STRING as structured field body.
725 It decodes non us-ascii characters in FULL-NAME encoded as
726 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
727 characters are regarded as variable `default-mime-charset'.
729 If an encoded-word is broken or your emacs implementation can not
730 decode the charset included in it, it is not decoded."
731 (let ((tokens (eword-lexical-analyze string 'must-unfold))
734 (let* ((token (car tokens))
736 (setq tokens (cdr tokens))
738 (if (eq type 'spaces)
740 (concat result (eword-decode-token token))
744 (defun eword-decode-structured-field-body (string &optional must-unfold
745 start-column max-column)
746 "Decode non us-ascii characters in STRING as structured field body.
747 STRING is unfolded before decoding.
749 It decodes non us-ascii characters in FULL-NAME encoded as
750 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
751 characters are regarded as variable `default-mime-charset'.
753 If an encoded-word is broken or your emacs implementation can not
754 decode the charset included in it, it is not decoded.
756 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
757 if there are in decoded encoded-words (generated by bad manner MUA
758 such as a version of Net$cape)."
760 ;; fold with max-column
761 (eword-decode-and-fold-structured-field
762 string start-column max-column must-unfold)
764 (mapconcat (function eword-decode-token)
765 (eword-lexical-analyze string must-unfold)
769 (defun eword-decode-unstructured-field-body (string &optional must-unfold)
770 "Decode non us-ascii characters in STRING as unstructured field body.
771 STRING is unfolded before decoding.
773 It decodes non us-ascii characters in FULL-NAME encoded as
774 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
775 characters are regarded as variable `default-mime-charset'.
777 If an encoded-word is broken or your emacs implementation can not
778 decode the charset included in it, it is not decoded.
780 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
781 if there are in decoded encoded-words (generated by bad manner MUA
782 such as a version of Net$cape)."
783 (eword-decode-string string must-unfold default-mime-charset))
785 (defun eword-extract-address-components (string)
786 "Extract full name and canonical address from STRING.
787 Returns a list of the form (FULL-NAME CANONICAL-ADDRESS).
788 If no name can be extracted, FULL-NAME will be nil.
789 It decodes non us-ascii characters in FULL-NAME encoded as
790 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
791 characters are regarded as variable `default-mime-charset'."
792 (let* ((structure (car (std11-parse-address
793 (eword-lexical-analyze
794 (std11-unfold-string string) 'must-unfold))))
795 (phrase (std11-full-name-string structure))
796 (address (std11-address-string structure))
798 (list phrase address)
805 (provide 'eword-decode)
807 ;;; eword-decode.el ends here