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 ;; Maintainer: MORIOKA Tomohiko <morioka@jaist.ac.jp>
9 ;; Original: 1992/07/20 ENAMI Tsugutomo's `mime.el'.
10 ;; Renamed: 1993/06/03 to tiny-mime.el
11 ;; Renamed: 1995/10/03 from tiny-mime.el (split off encoder)
12 ;; Renamed: 1997/02/22 from tm-ew-d.el
13 ;; Keywords: encoded-word, MIME, multilingual, header, mail, news
15 ;; This file is part of SEMI (Spadework for Emacs MIME Interfaces).
17 ;; This program is free software; you can redistribute it and/or
18 ;; modify it under the terms of the GNU General Public License as
19 ;; published by the Free Software Foundation; either version 2, or (at
20 ;; your option) any later version.
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 ;; General Public License for more details.
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with GNU Emacs; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
30 ;; Boston, MA 02111-1307, USA.
34 (require 'std11-parse)
38 (defgroup eword-decode nil
39 "Encoded-word decoding"
43 ;;; @ MIME encoded-word definition
46 (defconst eword-encoded-text-regexp "[!->@-~]+")
47 (defconst eword-encoded-word-regexp
48 (concat (regexp-quote "=?")
56 eword-encoded-text-regexp
59 (defconst eword-after-encoded-word-regexp "\\([ \t]\\|$\\)")
61 (defconst eword-encoded-text-in-phrase-regexp "[-A-Za-z0-9!*+/=_]+")
62 (defconst eword-encoded-word-in-phrase-regexp
63 (concat (regexp-quote "=?")
71 eword-encoded-text-in-phrase-regexp
74 (defconst eword-after-encoded-word-in-phrase-regexp "\\([ \t(]\\|$\\)")
76 (defconst eword-encoded-text-in-comment-regexp "[]!-'*->@-[^-~]+")
77 (defconst eword-encoded-word-in-comment-regexp
78 (concat (regexp-quote "=?")
86 eword-encoded-text-in-comment-regexp
89 (defconst eword-after-encoded-word-in-comment-regexp "\\([ \t()\\\\]\\|$\\)")
91 (defconst eword-encoded-text-in-quoted-string-regexp "[]!#->@-[^-~]+")
92 (defconst eword-encoded-word-in-quoted-string-regexp
93 (concat (regexp-quote "=?")
101 eword-encoded-text-in-quoted-string-regexp
103 (regexp-quote "?=")))
104 (defconst eword-after-encoded-word-in-quoted-string-regexp "\\([ \t\"\\\\]\\|$\\)")
110 (defconst base64-token-regexp "[A-Za-z0-9+/]")
111 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
113 (defconst eword-B-encoded-text-regexp
122 base64-token-padding-regexp
123 base64-token-padding-regexp
126 ;; (defconst eword-B-encoding-and-encoded-text-regexp
127 ;; (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
130 ;;; @@ Quoted-Printable
133 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
134 (defconst quoted-printable-octet-regexp
135 (concat "=[" quoted-printable-hex-chars
136 "][" quoted-printable-hex-chars "]"))
138 (defconst eword-Q-encoded-text-regexp
139 (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
140 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
141 ;; (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
147 (defcustom eword-decode-sticked-encoded-word nil
148 "*If non-nil, decode encoded-words sticked on atoms,
149 other encoded-words, etc.
150 however this behaviour violates RFC2047."
154 (defvar eword-decode-quoted-encoded-word nil
155 "*If non-nil, decode encoded-words in quoted-string
156 however this behaviour violates RFC2047.")
158 (defun eword-decode-first-encoded-words (string
161 &optional must-unfold)
162 "Decode MIME encoded-words in beginning of STRING.
164 EWORD-REGEXP is the regexp that matches a encoded-word.
165 Usual value is eword-encoded-word-regexp,
166 eword-encoded-text-in-phrase-regexp,
167 eword-encoded-word-in-comment-regexp or
168 eword-encoded-word-in-quoted-string-regexp.
170 AFTER-REGEXP is the regexp that matches a after encoded-word.
171 Usual value is eword-after-encoded-word-regexp,
172 eword-after-encoded-text-in-phrase-regexp,
173 eword-after-encoded-word-in-comment-regexp or
174 eword-after-encoded-word-in-quoted-string-regexp.
176 If beginning of STRING matches EWORD-REGEXP and AFTER-REGEXP,
177 returns a cons cell of decoded string(sequence of characters) and
178 the rest(sequence of octets).
180 If beginning of STRING does not matches EWORD-REGEXP and AFTER-REGEXP,
183 If an encoded-word is broken or your emacs implementation can not
184 decode the charset included in it, it is returned in decoded part
185 as encoded-word form.
187 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
188 if there are in decoded encoded-words (generated by bad manner MUA
189 such as a version of Net$cape)."
190 (if eword-decode-sticked-encoded-word (setq after-regexp ""))
191 (let ((between-ewords-regexp
192 (if eword-decode-sticked-encoded-word
195 (src string) ; sequence of octets.
196 (dst "")) ; sequence of characters.
198 (concat "\\`\\(" eword-regexp "\\)" after-regexp) src)
201 (ew (substring src 0 q))
202 (dw (eword-decode-encoded-word ew must-unfold)))
203 (setq dst (concat dst dw)
204 src (substring src q))
205 (if (not (string= ew dw))
210 (concat "\\`\\(" between-ewords-regexp "\\)"
211 "\\(" eword-regexp "\\)"
215 (setq p (match-end 1)
217 ew (substring src p q)
218 dw (eword-decode-encoded-word ew must-unfold))
221 (setq dst (concat dst (substring src 0 q))
222 src (substring src q))
225 (setq dst (concat dst dw)
226 src (substring src q)))))
230 (defun eword-decode-comment-string (string &optional must-unfold)
235 (while (< 0 (length src))
236 (let ((ch (aref src 0))
239 (eword-decode-first-encoded-words src
240 eword-encoded-word-in-comment-regexp
241 eword-after-encoded-word-in-comment-regexp
243 (if (and (not (string= buf ""))
244 (or decoded (eq ch ?\() (eq ch ?\))))
245 (setq dst (concat dst
246 (std11-wrap-as-quoted-pairs
247 (decode-mime-charset-string buf
248 default-mime-charset)
253 (setq dst (concat dst
254 (std11-wrap-as-quoted-pairs
258 ((or (eq ch ?\() (eq ch ?\)))
259 (setq dst (concat dst (list ch))
260 src (substring src 1)
263 (setq buf (concat buf (list (aref src 1)))
264 src (substring src 2)
266 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
267 (setq buf (concat buf (list ch))
268 src (substring src 1)
270 ((string-match "\\`=?[^ \t\n()\\\\=]*" src)
271 (setq buf (concat buf (substring src 0 (match-end 0)))
272 src (substring src (match-end 0))
273 flag-ew eword-decode-sticked-encoded-word))
274 (t (error "something wrong")))))
275 (if (not (string= buf ""))
276 (setq dst (concat dst
277 (std11-wrap-as-quoted-pairs
278 (decode-mime-charset-string buf
279 default-mime-charset)
283 (defun eword-decode-quoted-string (string &optional must-unfold)
288 (while (< 0 (length src))
289 (let ((ch (aref src 0))
291 eword-decode-quoted-encoded-word
293 (eword-decode-first-encoded-words src
294 eword-encoded-word-in-quoted-string-regexp
295 eword-after-encoded-word-in-quoted-string-regexp
297 (if (and (not (string= buf ""))
298 (or decoded (eq ch ?\")))
299 (setq dst (concat dst
300 (std11-wrap-as-quoted-pairs
301 (decode-mime-charset-string buf
302 default-mime-charset)
307 (setq dst (concat dst
308 (std11-wrap-as-quoted-pairs
313 (setq dst (concat dst (list ch))
314 src (substring src 1)
317 (setq buf (concat buf (list (aref src 1)))
318 src (substring src 2)
320 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
321 (setq buf (concat buf (list ch))
322 src (substring src 1)
324 ((string-match "\\`=?[^ \t\n\"\\\\=]*" src)
325 (setq buf (concat buf (substring src 0 (match-end 0)))
326 src (substring src (match-end 0))
327 flag-ew eword-decode-sticked-encoded-word))
328 (t (error "something wrong")))))
329 (if (not (string= buf ""))
330 (setq dst (concat dst
331 (std11-wrap-as-quoted-pairs
332 (decode-mime-charset-string buf
333 default-mime-charset)
337 (defun eword-decode-unstructured-string (string &optional must-unfold)
342 (while (< 0 (length src))
343 (let ((ch (aref src 0))
344 (decoded (and flag-ew (eword-decode-first-encoded-words src
345 eword-encoded-word-regexp
346 eword-after-encoded-word-regexp
348 (if (and (not (string= buf ""))
350 (setq dst (concat dst
351 (decode-mime-charset-string buf
352 default-mime-charset))
356 (setq dst (concat dst (car decoded))
358 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
359 (setq buf (concat buf (list ch))
360 src (substring src 1)
362 ((string-match "\\`=?[^ \t\n=]*" src)
363 (setq buf (concat buf (substring src 0 (match-end 0)))
364 src (substring src (match-end 0))
365 flag-ew eword-decode-sticked-encoded-word))
366 (t (error "something wrong")))))
367 (if (not (string= buf ""))
368 (setq dst (concat dst
369 (decode-mime-charset-string buf
370 default-mime-charset))))
373 (defun eword-decode-string (string &optional must-unfold)
374 "Decode MIME encoded-words in STRING.
376 STRING is unfolded before decoding.
378 If an encoded-word is broken or your emacs implementation can not
379 decode the charset included in it, it is not decoded.
381 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
382 if there are in decoded encoded-words (generated by bad manner MUA
383 such as a version of Net$cape)."
384 (eword-decode-unstructured-string
385 (std11-unfold-string string)
392 (defun eword-decode-region (start end &optional unfolding must-unfold)
393 "Decode MIME encoded-words in region between START and END.
395 If UNFOLDING is not nil, it unfolds before decoding.
397 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
398 if there are in decoded encoded-words (generated by bad manner MUA
399 such as a version of Net$cape)."
403 (narrow-to-region start end)
405 (eword-decode-unfold)
407 (let ((str (eword-decode-unstructured-string
408 (buffer-substring (point-min) (point-max))
410 (delete-region (point-min) (point-max))
414 ;;; @ for message header
417 (defcustom eword-decode-ignored-field-list
418 '(newsgroups path lines nntp-posting-host message-id date)
419 "*List of field-names to be ignored when decoding.
420 Each field name must be symbol."
422 :type '(repeat symbol))
424 (defcustom eword-decode-structured-field-list
425 '(reply-to resent-reply-to from resent-from sender resent-sender
426 to resent-to cc resent-cc bcc resent-bcc dcc
427 mime-version content-type content-transfer-encoding
429 "*List of field-names to decode as structured field.
430 Each field name must be symbol."
432 :type '(repeat symbol))
434 (defun eword-decode-header (&optional code-conversion separator)
435 "Decode MIME encoded-words in header fields.
436 If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
437 mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
438 Otherwise it decodes non-ASCII bit patterns as the
439 default-mime-charset.
440 If SEPARATOR is not nil, it is used as header separator."
444 (std11-narrow-to-header separator)
445 (let ((default-charset
447 (if (mime-charset-to-coding-system code-conversion)
449 default-mime-charset))))
451 (let (beg p end field-name len)
452 (goto-char (point-min))
453 (while (re-search-forward std11-field-head-regexp nil t)
454 (setq beg (match-beginning 0)
456 field-name (buffer-substring beg (1- p))
457 len (string-width field-name)
458 field-name (intern (downcase field-name))
459 end (std11-field-end))
460 (cond ((memq field-name eword-decode-ignored-field-list)
463 ((memq field-name eword-decode-structured-field-list)
464 ;; Decode as structured field
465 (let ((body (buffer-substring p end))
466 (default-mime-charset default-charset))
467 (delete-region p end)
468 (insert (eword-decode-and-fold-structured-field
472 ;; Decode as unstructured field
474 (narrow-to-region beg (1+ end))
476 (let ((default-mime-charset default-charset))
477 (eword-decode-region beg (point-max) 'unfold))
478 (goto-char (point-max))
480 (eword-decode-region (point-min) (point-max) t)
483 (defun eword-decode-unfold ()
484 (goto-char (point-min))
486 (while (re-search-forward std11-field-head-regexp nil t)
487 (setq beg (match-beginning 0)
488 end (std11-field-end))
489 (setq field (buffer-substring beg end))
490 (if (string-match eword-encoded-word-regexp field)
492 (narrow-to-region (goto-char beg) end)
493 (while (re-search-forward "\n\\([ \t]\\)" nil t)
494 (replace-match (match-string 1))
496 (goto-char (point-max))
501 ;;; @ encoded-word decoder
504 (defvar eword-warning-face nil "Face used for invalid encoded-word.")
506 (defun eword-decode-encoded-word (word &optional must-unfold)
507 "Decode WORD if it is an encoded-word.
509 If your emacs implementation can not decode the charset of WORD, it
510 returns WORD. Similarly the encoded-word is broken, it returns WORD.
512 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
513 if there are in decoded encoded-word (generated by bad manner MUA such
514 as a version of Net$cape)."
515 (or (if (string-match eword-encoded-word-regexp word)
517 (substring word (match-beginning 1) (match-end 1))
521 (substring word (match-beginning 2) (match-end 2))
524 (substring word (match-beginning 3) (match-end 3))
527 (eword-decode-encoded-text charset encoding text must-unfold)
530 (add-text-properties 0 (length word)
531 (and eword-warning-face
532 (list 'face eword-warning-face))
539 ;;; @ encoded-text decoder
542 (defun eword-decode-encoded-text (charset encoding string
543 &optional must-unfold)
544 "Decode STRING as an encoded-text.
546 If your emacs implementation can not decode CHARSET, it returns nil.
548 If ENCODING is not \"B\" or \"Q\", it occurs error.
549 So you should write error-handling code if you don't want break by errors.
551 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
552 if there are in decoded encoded-text (generated by bad manner MUA such
553 as a version of Net$cape)."
554 (let ((cs (mime-charset-to-coding-system charset)))
558 ((string-equal "B" encoding)
559 (if (and (string-match eword-B-encoded-text-regexp string)
560 (string-equal string (match-string 0 string)))
561 (base64-decode-string string)
562 (error "Invalid encoded-text %s" string)))
563 ((string-equal "Q" encoding)
564 (if (and (string-match eword-Q-encoded-text-regexp string)
565 (string-equal string (match-string 0 string)))
566 (q-encoding-decode-string string)
567 (error "Invalid encoded-text %s" string)))
569 (error "Invalid encoding %s" encoding)
574 (setq dest (decode-coding-string dest cs))
581 (t (char-to-string chr)))
583 (std11-unfold-string dest)
589 ;;; @ lexical analyze
592 (defvar eword-lexical-analyze-cache nil)
593 (defvar eword-lexical-analyze-cache-max 299
594 "*Max position of eword-lexical-analyze-cache.
595 It is max size of eword-lexical-analyze-cache - 1.")
597 (defcustom eword-lexical-analyzers
598 '(eword-analyze-quoted-string
599 eword-analyze-domain-literal
600 eword-analyze-comment
602 eword-analyze-special
603 eword-analyze-encoded-word
605 "*List of functions to return result of lexical analyze.
606 Each function must have two arguments: STRING and MUST-UNFOLD.
607 STRING is the target string to be analyzed.
608 If MUST-UNFOLD is not nil, each function must unfold and eliminate
609 bare-CR and bare-LF from the result even if they are included in
610 content of the encoded-word.
611 Each function must return nil if it can not analyze STRING as its
614 Previous function is preferred to next function. If a function
615 returns nil, next function is used. Otherwise the return value will
618 :type '(repeat function))
620 (defun eword-analyze-quoted-string (string &optional must-unfold)
621 (let ((p (std11-check-enclosure string ?\" ?\")))
623 (cons (cons 'quoted-string
624 (eword-decode-quoted-string (substring string 0 p)))
625 (substring string p))
628 (defun eword-analyze-domain-literal (string &optional must-unfold)
629 (std11-analyze-domain-literal string))
631 (defun eword-analyze-comment (string &optional must-unfold)
632 (let ((len (length string)))
633 (if (and (< 0 len) (eq (aref string 0) ?\())
635 (while (and p (< p len) (eq (aref string p) ?\())
636 (setq p (std11-check-enclosure string ?\( ?\) t p)))
639 (eword-decode-comment-string (substring string 0 p)))
640 (substring string p)))
643 (defun eword-analyze-spaces (string &optional must-unfold)
644 (std11-analyze-spaces string))
646 (defun eword-analyze-special (string &optional must-unfold)
647 (std11-analyze-special string))
649 (defun eword-analyze-encoded-word (string &optional must-unfold)
650 (let ((decoded (eword-decode-first-encoded-words
652 eword-encoded-word-in-phrase-regexp
653 eword-after-encoded-word-in-phrase-regexp
656 (cons (cons 'atom (car decoded)) (cdr decoded)))))
658 (defun eword-analyze-atom (string &optional must-unfold)
659 (if (let ((enable-multibyte-characters nil))
660 (string-match std11-atom-regexp string))
661 (let ((end (match-end 0)))
662 (if (and eword-decode-sticked-encoded-word
663 (string-match eword-encoded-word-in-phrase-regexp
664 (substring string 0 end))
665 (< 0 (match-beginning 0)))
666 (setq end (match-beginning 0)))
667 (cons (cons 'atom (decode-mime-charset-string
668 (substring string 0 end)
669 default-mime-charset))
670 (substring string end)
673 (defun eword-lexical-analyze-internal (string must-unfold)
675 (while (not (string-equal string ""))
677 (let ((rest eword-lexical-analyzers)
679 (while (and (setq func (car rest))
680 (null (setq r (funcall func string must-unfold)))
682 (setq rest (cdr rest)))
683 (or r `((error . ,string) . ""))
685 (setq dest (cons (car ret) dest))
686 (setq string (cdr ret))
691 (defun eword-lexical-analyze (string &optional must-unfold)
692 "Return lexical analyzed list corresponding STRING.
693 It is like std11-lexical-analyze, but it decodes non us-ascii
694 characters encoded as encoded-words or invalid \"raw\" format.
695 \"Raw\" non us-ascii characters are regarded as variable
696 `default-mime-charset'."
697 (let* ((str (copy-sequence string))
698 (key (cons str (cons default-mime-charset must-unfold)))
700 (set-text-properties 0 (length str) nil str)
701 (if (setq ret (assoc key eword-lexical-analyze-cache))
703 (setq ret (eword-lexical-analyze-internal str must-unfold))
704 (setq eword-lexical-analyze-cache
706 (last eword-lexical-analyze-cache
707 eword-lexical-analyze-cache-max)))
710 (defun eword-decode-token (token)
713 (defun eword-decode-and-fold-structured-field
714 (string start-column &optional max-column must-unfold)
715 "Decode and fold (fill) STRING as structured field body.
716 It decodes non us-ascii characters in FULL-NAME encoded as
717 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
718 characters are regarded as variable `default-mime-charset'.
720 If an encoded-word is broken or your emacs implementation can not
721 decode the charset included in it, it is not decoded.
723 If MAX-COLUMN is omitted, `fill-column' is used.
725 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
726 if there are in decoded encoded-words (generated by bad manner MUA
727 such as a version of Net$cape)."
729 (setq max-column fill-column))
730 (let ((c start-column)
731 (tokens (eword-lexical-analyze string must-unfold))
734 (while (and (setq token (car tokens))
735 (setq tokens (cdr tokens)))
736 (let* ((type (car token)))
737 (if (eq type 'spaces)
738 (let* ((next-token (car tokens))
739 (next-str (eword-decode-token next-token))
740 (next-len (string-width next-str))
741 (next-c (+ c next-len 1)))
742 (if (< next-c max-column)
743 (setq result (concat result " " next-str)
745 (setq result (concat result "\n " next-str)
747 (setq tokens (cdr tokens))
749 (let* ((str (eword-decode-token token)))
750 (setq result (concat result str)
751 c (+ c (string-width str)))
754 (concat result (eword-decode-token token))
757 (defun eword-decode-and-unfold-structured-field (string)
758 "Decode and unfold STRING as structured field body.
759 It decodes non us-ascii characters in FULL-NAME encoded as
760 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
761 characters are regarded as variable `default-mime-charset'.
763 If an encoded-word is broken or your emacs implementation can not
764 decode the charset included in it, it is not decoded."
765 (let ((tokens (eword-lexical-analyze string 'must-unfold))
768 (let* ((token (car tokens))
770 (setq tokens (cdr tokens))
772 (if (eq type 'spaces)
774 (concat result (eword-decode-token token))
778 (defun eword-decode-structured-field-body (string &optional must-unfold
779 start-column max-column)
780 "Decode non us-ascii characters in STRING as structured field body.
781 STRING is unfolded before decoding.
783 It decodes non us-ascii characters in FULL-NAME encoded as
784 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
785 characters are regarded as variable `default-mime-charset'.
787 If an encoded-word is broken or your emacs implementation can not
788 decode the charset included in it, it is not decoded.
790 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
791 if there are in decoded encoded-words (generated by bad manner MUA
792 such as a version of Net$cape)."
794 ;; fold with max-column
795 (eword-decode-and-fold-structured-field
796 string start-column max-column must-unfold)
798 (mapconcat (function eword-decode-token)
799 (eword-lexical-analyze string must-unfold)
803 (defun eword-decode-unstructured-field-body (string &optional must-unfold)
804 "Decode non us-ascii characters in STRING as unstructured field body.
805 STRING is unfolded before decoding.
807 It decodes non us-ascii characters in FULL-NAME encoded as
808 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
809 characters are regarded as variable `default-mime-charset'.
811 If an encoded-word is broken or your emacs implementation can not
812 decode the charset included in it, it is not decoded.
814 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
815 if there are in decoded encoded-words (generated by bad manner MUA
816 such as a version of Net$cape)."
817 (eword-decode-string string must-unfold))
819 (defun eword-extract-address-components (string)
820 "Extract full name and canonical address from STRING.
821 Returns a list of the form (FULL-NAME CANONICAL-ADDRESS).
822 If no name can be extracted, FULL-NAME will be nil.
823 It decodes non us-ascii characters in FULL-NAME encoded as
824 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
825 characters are regarded as variable `default-mime-charset'."
826 (let* ((structure (car (std11-parse-address
827 (eword-lexical-analyze
828 (std11-unfold-string string) 'must-unfold))))
829 (phrase (std11-full-name-string structure))
830 (address (std11-address-string structure))
832 (list phrase address)
839 (provide 'eword-decode)
841 ;;; eword-decode.el ends here