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.
35 (require 'std11-parse)
39 (defgroup eword-decode nil
40 "Encoded-word decoding"
44 ;;; @ MIME encoded-word definition
47 (defconst eword-encoded-text-regexp "[!->@-~]+")
48 (defconst eword-encoded-word-regexp
49 (concat (regexp-quote "=?")
57 eword-encoded-text-regexp
60 (defconst eword-after-encoded-word-regexp "\\([ \t]\\|$\\)")
62 (defconst eword-encoded-text-in-phrase-regexp "[-A-Za-z0-9!*+/=_]+")
63 (defconst eword-encoded-word-in-phrase-regexp
64 (concat (regexp-quote "=?")
72 eword-encoded-text-in-phrase-regexp
75 (defconst eword-after-encoded-word-in-phrase-regexp "\\([ \t(]\\|$\\)")
77 (defconst eword-encoded-text-in-comment-regexp "[]!-'*->@-[^-~]+")
78 (defconst eword-encoded-word-in-comment-regexp
79 (concat (regexp-quote "=?")
87 eword-encoded-text-in-comment-regexp
90 (defconst eword-after-encoded-word-in-comment-regexp "\\([ \t()\\\\]\\|$\\)")
92 (defconst eword-encoded-text-in-quoted-string-regexp "[]!#->@-[^-~]+")
93 (defconst eword-encoded-word-in-quoted-string-regexp
94 (concat (regexp-quote "=?")
102 eword-encoded-text-in-quoted-string-regexp
104 (regexp-quote "?=")))
105 (defconst eword-after-encoded-word-in-quoted-string-regexp "\\([ \t\"\\\\]\\|$\\)")
111 (defconst base64-token-regexp "[A-Za-z0-9+/]")
112 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
114 (defconst eword-B-encoded-text-regexp
123 base64-token-padding-regexp
124 base64-token-padding-regexp
127 ;; (defconst eword-B-encoding-and-encoded-text-regexp
128 ;; (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
131 ;;; @@ Quoted-Printable
134 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
135 (defconst quoted-printable-octet-regexp
136 (concat "=[" quoted-printable-hex-chars
137 "][" quoted-printable-hex-chars "]"))
139 (defconst eword-Q-encoded-text-regexp
140 (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
141 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
142 ;; (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
148 (defcustom eword-decode-sticked-encoded-word nil
149 "*If non-nil, decode encoded-words sticked on atoms,
150 other encoded-words, etc.
151 however this behaviour violates RFC2047."
155 (defcustom eword-decode-quoted-encoded-word nil
156 "*If non-nil, decode encoded-words in quoted-string
157 however this behaviour violates RFC2047."
161 (defun eword-decode-first-encoded-words (string
164 &optional must-unfold)
165 "Decode MIME encoded-words in beginning of STRING.
167 EWORD-REGEXP is the regexp that matches a encoded-word.
168 Usual value is eword-encoded-word-regexp,
169 eword-encoded-text-in-phrase-regexp,
170 eword-encoded-word-in-comment-regexp or
171 eword-encoded-word-in-quoted-string-regexp.
173 AFTER-REGEXP is the regexp that matches a after encoded-word.
174 Usual value is eword-after-encoded-word-regexp,
175 eword-after-encoded-text-in-phrase-regexp,
176 eword-after-encoded-word-in-comment-regexp or
177 eword-after-encoded-word-in-quoted-string-regexp.
179 If beginning of STRING matches EWORD-REGEXP and AFTER-REGEXP,
180 returns a cons cell of decoded string(sequence of characters) and
181 the rest(sequence of octets).
183 If beginning of STRING does not matches EWORD-REGEXP and AFTER-REGEXP,
186 If an encoded-word is broken or your emacs implementation can not
187 decode the charset included in it, it is returned in decoded part
188 as encoded-word form.
190 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
191 if there are in decoded encoded-words (generated by bad manner MUA
192 such as a version of Net$cape)."
193 (if eword-decode-sticked-encoded-word (setq after-regexp ""))
194 (let ((between-ewords-regexp
195 (if eword-decode-sticked-encoded-word
198 (src string) ; sequence of octets.
199 (dst "")) ; sequence of characters.
201 (concat "\\`\\(" eword-regexp "\\)" after-regexp) src)
204 (ew (substring src 0 q))
205 (dw (eword-decode-encoded-word ew must-unfold)))
206 (setq dst (concat dst dw)
207 src (substring src q))
208 (if (not (string= ew dw))
213 (concat "\\`\\(" between-ewords-regexp "\\)"
214 "\\(" eword-regexp "\\)"
218 (setq p (match-end 1)
220 ew (substring src p q)
221 dw (eword-decode-encoded-word ew must-unfold))
224 (setq dst (concat dst (substring src 0 q))
225 src (substring src q))
228 (setq dst (concat dst dw)
229 src (substring src q)))))
233 (defun eword-decode-comment-string (string &optional must-unfold)
238 (while (< 0 (length src))
239 (let ((ch (aref src 0))
242 (eword-decode-first-encoded-words src
243 eword-encoded-word-in-comment-regexp
244 eword-after-encoded-word-in-comment-regexp
246 (if (and (not (string= buf ""))
247 (or decoded (eq ch ?\() (eq ch ?\))))
248 (setq dst (concat dst
249 (std11-wrap-as-quoted-pairs
250 (decode-mime-charset-string buf
251 default-mime-charset)
256 (setq dst (concat dst
257 (std11-wrap-as-quoted-pairs
261 ((or (eq ch ?\() (eq ch ?\)))
262 (setq dst (concat dst (list ch))
263 src (substring src 1)
266 (setq buf (concat buf (list (aref src 1)))
267 src (substring src 2)
269 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
270 (setq buf (concat buf (list ch))
271 src (substring src 1)
273 ((string-match "\\`=?[^ \t\n()\\\\=]*" src)
274 (setq buf (concat buf (substring src 0 (match-end 0)))
275 src (substring src (match-end 0))
276 flag-ew eword-decode-sticked-encoded-word))
277 (t (error "something wrong")))))
278 (if (not (string= buf ""))
279 (setq dst (concat dst
280 (std11-wrap-as-quoted-pairs
281 (decode-mime-charset-string buf
282 default-mime-charset)
286 (defun eword-decode-quoted-string (string &optional must-unfold)
291 (while (< 0 (length src))
292 (let ((ch (aref src 0))
294 eword-decode-quoted-encoded-word
296 (eword-decode-first-encoded-words src
297 eword-encoded-word-in-quoted-string-regexp
298 eword-after-encoded-word-in-quoted-string-regexp
300 (if (and (not (string= buf ""))
301 (or decoded (eq ch ?\")))
302 (setq dst (concat dst
303 (std11-wrap-as-quoted-pairs
304 (decode-mime-charset-string buf
305 default-mime-charset)
310 (setq dst (concat dst
311 (std11-wrap-as-quoted-pairs
316 (setq dst (concat dst (list ch))
317 src (substring src 1)
320 (setq buf (concat buf (list (aref src 1)))
321 src (substring src 2)
323 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
324 (setq buf (concat buf (list ch))
325 src (substring src 1)
327 ((string-match "\\`=?[^ \t\n\"\\\\=]*" src)
328 (setq buf (concat buf (substring src 0 (match-end 0)))
329 src (substring src (match-end 0))
330 flag-ew eword-decode-sticked-encoded-word))
331 (t (error "something wrong")))))
332 (if (not (string= buf ""))
333 (setq dst (concat dst
334 (std11-wrap-as-quoted-pairs
335 (decode-mime-charset-string buf
336 default-mime-charset)
340 (defun eword-decode-unstructured-string (string &optional must-unfold)
345 (while (< 0 (length src))
346 (let ((ch (aref src 0))
347 (decoded (and flag-ew (eword-decode-first-encoded-words src
348 eword-encoded-word-regexp
349 eword-after-encoded-word-regexp
351 (if (and (not (string= buf ""))
353 (setq dst (concat dst
354 (decode-mime-charset-string buf
355 default-mime-charset))
359 (setq dst (concat dst (car decoded))
361 ((or (eq ch ?\ ) (eq ch ?\t) (eq ch ?\n))
362 (setq buf (concat buf (list ch))
363 src (substring src 1)
365 ((string-match "\\`=?[^ \t\n=]*" src)
366 (setq buf (concat buf (substring src 0 (match-end 0)))
367 src (substring src (match-end 0))
368 flag-ew eword-decode-sticked-encoded-word))
369 (t (error "something wrong")))))
370 (if (not (string= buf ""))
371 (setq dst (concat dst
372 (decode-mime-charset-string buf
373 default-mime-charset))))
376 (defun eword-decode-string (string &optional must-unfold)
377 "Decode MIME encoded-words in STRING.
379 STRING is unfolded before decoding.
381 If an encoded-word is broken or your emacs implementation can not
382 decode the charset included in it, it is not decoded.
384 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
385 if there are in decoded encoded-words (generated by bad manner MUA
386 such as a version of Net$cape)."
387 (eword-decode-unstructured-string
388 (std11-unfold-string string)
395 (defun eword-decode-region (start end &optional unfolding must-unfold)
396 "Decode MIME encoded-words in region between START and END.
398 If UNFOLDING is not nil, it unfolds before decoding.
400 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
401 if there are in decoded encoded-words (generated by bad manner MUA
402 such as a version of Net$cape)."
406 (narrow-to-region start end)
408 (eword-decode-unfold)
410 (let ((str (eword-decode-unstructured-string
411 (buffer-substring (point-min) (point-max))
413 (delete-region (point-min) (point-max))
417 ;;; @ for message header
420 (defcustom eword-decode-ignored-field-list
421 '(newsgroups path lines nntp-posting-host message-id date)
422 "*List of field-names to be ignored when decoding.
423 Each field name must be symbol."
425 :type '(repeat symbol))
427 (defcustom eword-decode-structured-field-list
428 '(reply-to resent-reply-to from resent-from sender resent-sender
429 to resent-to cc resent-cc bcc resent-bcc dcc
430 mime-version content-type content-transfer-encoding
432 "*List of field-names to decode as structured field.
433 Each field name must be symbol."
435 :type '(repeat symbol))
437 (defun eword-decode-header (&optional code-conversion separator)
438 "Decode MIME encoded-words in header fields.
439 If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
440 mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
441 Otherwise it decodes non-ASCII bit patterns as the
442 default-mime-charset.
443 If SEPARATOR is not nil, it is used as header separator."
447 (std11-narrow-to-header separator)
448 (let ((default-mime-charset
450 (if (mime-charset-to-coding-system code-conversion)
452 default-mime-charset))))
453 (if default-mime-charset
454 (let (beg p end field-name len)
455 (goto-char (point-min))
456 (while (re-search-forward std11-field-head-regexp nil t)
457 (setq beg (match-beginning 0)
459 field-name (buffer-substring beg (1- p))
460 len (string-width field-name)
461 field-name (intern (downcase field-name))
462 end (std11-field-end))
463 (cond ((memq field-name eword-decode-ignored-field-list)
466 ((memq field-name eword-decode-structured-field-list)
467 ;; Decode as structured field
468 (let ((body (buffer-substring p end)))
469 (delete-region p end)
470 (insert (eword-decode-and-fold-structured-field
474 ;; Decode as unstructured field
476 (narrow-to-region beg (1+ end))
478 (eword-decode-region beg (point-max) 'unfold)
479 (goto-char (point-max))
481 (eword-decode-region (point-min) (point-max) t)
484 (defun eword-decode-unfold ()
485 (goto-char (point-min))
487 (while (re-search-forward std11-field-head-regexp nil t)
488 (setq beg (match-beginning 0)
489 end (std11-field-end))
490 (setq field (buffer-substring beg end))
491 (if (string-match eword-encoded-word-regexp field)
493 (narrow-to-region (goto-char beg) end)
494 (while (re-search-forward "\n\\([ \t]\\)" nil t)
495 (replace-match (match-string 1))
497 (goto-char (point-max))
502 ;;; @ encoded-word decoder
505 (defvar eword-warning-face nil "Face used for invalid encoded-word.")
507 (defun eword-decode-encoded-word (word &optional must-unfold)
508 "Decode WORD if it is an encoded-word.
510 If your emacs implementation can not decode the charset of WORD, it
511 returns WORD. Similarly the encoded-word is broken, it returns WORD.
513 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
514 if there are in decoded encoded-word (generated by bad manner MUA such
515 as a version of Net$cape)."
516 (or (if (string-match eword-encoded-word-regexp word)
518 (substring word (match-beginning 1) (match-end 1))
522 (substring word (match-beginning 2) (match-end 2))
525 (substring word (match-beginning 3) (match-end 3))
528 (eword-decode-encoded-text charset encoding text must-unfold)
531 (add-text-properties 0 (length word)
532 (and eword-warning-face
533 (list 'face eword-warning-face))
540 ;;; @ encoded-text decoder
543 (defun eword-decode-encoded-text (charset encoding string
544 &optional must-unfold)
545 "Decode STRING as an encoded-text.
547 If your emacs implementation can not decode CHARSET, it returns nil.
549 If ENCODING is not \"B\" or \"Q\", it occurs error.
550 So you should write error-handling code if you don't want break by errors.
552 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
553 if there are in decoded encoded-text (generated by bad manner MUA such
554 as a version of Net$cape)."
555 (let ((cs (mime-charset-to-coding-system charset)))
559 ((string-equal "B" encoding)
560 (if (and (string-match eword-B-encoded-text-regexp string)
561 (string-equal string (match-string 0 string)))
562 (base64-decode-string string)
563 (error "Invalid encoded-text %s" string)))
564 ((string-equal "Q" encoding)
565 (if (and (string-match eword-Q-encoded-text-regexp string)
566 (string-equal string (match-string 0 string)))
567 (q-encoding-decode-string string)
568 (error "Invalid encoded-text %s" string)))
570 (error "Invalid encoding %s" encoding)
575 (setq dest (decode-coding-string dest cs))
582 (t (char-to-string chr)))
584 (std11-unfold-string dest)
590 ;;; @ lexical analyze
593 (defvar eword-lexical-analyze-cache nil)
594 (defvar eword-lexical-analyze-cache-max 299
595 "*Max position of eword-lexical-analyze-cache.
596 It is max size of eword-lexical-analyze-cache - 1.")
598 (defcustom eword-lexical-analyzers
599 '(eword-analyze-quoted-string
600 eword-analyze-domain-literal
601 eword-analyze-comment
603 eword-analyze-special
604 eword-analyze-encoded-word
606 "*List of functions to return result of lexical analyze.
607 Each function must have two arguments: STRING and MUST-UNFOLD.
608 STRING is the target string to be analyzed.
609 If MUST-UNFOLD is not nil, each function must unfold and eliminate
610 bare-CR and bare-LF from the result even if they are included in
611 content of the encoded-word.
612 Each function must return nil if it can not analyze STRING as its
615 Previous function is preferred to next function. If a function
616 returns nil, next function is used. Otherwise the return value will
619 :type '(repeat function))
621 (defun eword-analyze-quoted-string (string &optional must-unfold)
622 (let ((p (std11-check-enclosure string ?\" ?\")))
624 (cons (cons 'quoted-string
625 (eword-decode-quoted-string (substring string 0 p)))
626 (substring string p))
629 (defun eword-analyze-domain-literal (string &optional must-unfold)
630 (std11-analyze-domain-literal string))
632 (defun eword-analyze-comment (string &optional must-unfold)
633 (let ((len (length string)))
634 (if (and (< 0 len) (eq (aref string 0) ?\())
636 (while (and p (< p len) (eq (aref string p) ?\())
637 (setq p (std11-check-enclosure string ?\( ?\) t p)))
640 (eword-decode-comment-string (substring string 0 p)))
641 (substring string p)))
644 (defun eword-analyze-spaces (string &optional must-unfold)
645 (std11-analyze-spaces string))
647 (defun eword-analyze-special (string &optional must-unfold)
648 (std11-analyze-special string))
650 (defun eword-analyze-encoded-word (string &optional must-unfold)
651 (let ((decoded (eword-decode-first-encoded-words
653 eword-encoded-word-in-phrase-regexp
654 eword-after-encoded-word-in-phrase-regexp
657 (cons (cons 'atom (car decoded)) (cdr decoded)))))
659 (defun eword-analyze-atom (string &optional must-unfold)
660 (if (let ((enable-multibyte-characters nil))
661 (string-match std11-atom-regexp string))
662 (let ((end (match-end 0)))
663 (if (and eword-decode-sticked-encoded-word
664 (string-match eword-encoded-word-in-phrase-regexp
665 (substring string 0 end))
666 (< 0 (match-beginning 0)))
667 (setq end (match-beginning 0)))
668 (cons (cons 'atom (decode-mime-charset-string
669 (substring string 0 end)
670 default-mime-charset))
671 (substring string end)
674 (defun eword-lexical-analyze-internal (string must-unfold)
676 (while (not (string-equal string ""))
678 (let ((rest eword-lexical-analyzers)
680 (while (and (setq func (car rest))
681 (null (setq r (funcall func string must-unfold)))
683 (setq rest (cdr rest)))
684 (or r `((error . ,string) . ""))
686 (setq dest (cons (car ret) dest))
687 (setq string (cdr ret))
692 (defun eword-lexical-analyze (string &optional must-unfold)
693 "Return lexical analyzed list corresponding STRING.
694 It is like std11-lexical-analyze, but it decodes non us-ascii
695 characters encoded as encoded-words or invalid \"raw\" format.
696 \"Raw\" non us-ascii characters are regarded as variable
697 `default-mime-charset'."
698 (let* ((str (copy-sequence string))
699 (key (cons str (cons default-mime-charset must-unfold)))
701 (set-text-properties 0 (length str) nil str)
702 (if (setq ret (assoc key eword-lexical-analyze-cache))
704 (setq ret (eword-lexical-analyze-internal str must-unfold))
705 (setq eword-lexical-analyze-cache
707 (last eword-lexical-analyze-cache
708 eword-lexical-analyze-cache-max)))
711 (defun eword-decode-token (token)
714 (defun eword-decode-and-fold-structured-field
715 (string start-column &optional max-column must-unfold)
716 "Decode and fold (fill) STRING as structured field body.
717 It decodes non us-ascii characters in FULL-NAME encoded as
718 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
719 characters are regarded as variable `default-mime-charset'.
721 If an encoded-word is broken or your emacs implementation can not
722 decode the charset included in it, it is not decoded.
724 If MAX-COLUMN is omitted, `fill-column' is used.
726 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
727 if there are in decoded encoded-words (generated by bad manner MUA
728 such as a version of Net$cape)."
730 (setq max-column fill-column))
731 (let ((c start-column)
732 (tokens (eword-lexical-analyze string must-unfold))
735 (while (and (setq token (car tokens))
736 (setq tokens (cdr tokens)))
737 (let* ((type (car token)))
738 (if (eq type 'spaces)
739 (let* ((next-token (car tokens))
740 (next-str (eword-decode-token next-token))
741 (next-len (string-width next-str))
742 (next-c (+ c next-len 1)))
743 (if (< next-c max-column)
744 (setq result (concat result " " next-str)
746 (setq result (concat result "\n " next-str)
748 (setq tokens (cdr tokens))
750 (let* ((str (eword-decode-token token)))
751 (setq result (concat result str)
752 c (+ c (string-width str)))
755 (concat result (eword-decode-token token))
758 (defun eword-decode-and-unfold-structured-field (string)
759 "Decode and unfold STRING as structured field body.
760 It decodes non us-ascii characters in FULL-NAME encoded as
761 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
762 characters are regarded as variable `default-mime-charset'.
764 If an encoded-word is broken or your emacs implementation can not
765 decode the charset included in it, it is not decoded."
766 (let ((tokens (eword-lexical-analyze string 'must-unfold))
769 (let* ((token (car tokens))
771 (setq tokens (cdr tokens))
773 (if (eq type 'spaces)
775 (concat result (eword-decode-token token))
779 (defun eword-decode-structured-field-body (string &optional must-unfold
780 start-column max-column)
781 "Decode non us-ascii characters in STRING as structured field body.
782 STRING is unfolded before decoding.
784 It decodes non us-ascii characters in FULL-NAME encoded as
785 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
786 characters are regarded as variable `default-mime-charset'.
788 If an encoded-word is broken or your emacs implementation can not
789 decode the charset included in it, it is not decoded.
791 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
792 if there are in decoded encoded-words (generated by bad manner MUA
793 such as a version of Net$cape)."
795 ;; fold with max-column
796 (eword-decode-and-fold-structured-field
797 string start-column max-column must-unfold)
799 (mapconcat (function eword-decode-token)
800 (eword-lexical-analyze string must-unfold)
804 (defun eword-decode-unstructured-field-body (string &optional must-unfold)
805 "Decode non us-ascii characters in STRING as unstructured field body.
806 STRING is unfolded before decoding.
808 It decodes non us-ascii characters in FULL-NAME encoded as
809 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
810 characters are regarded as variable `default-mime-charset'.
812 If an encoded-word is broken or your emacs implementation can not
813 decode the charset included in it, it is not decoded.
815 If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
816 if there are in decoded encoded-words (generated by bad manner MUA
817 such as a version of Net$cape)."
818 (eword-decode-string string must-unfold))
820 (defun eword-extract-address-components (string)
821 "Extract full name and canonical address from STRING.
822 Returns a list of the form (FULL-NAME CANONICAL-ADDRESS).
823 If no name can be extracted, FULL-NAME will be nil.
824 It decodes non us-ascii characters in FULL-NAME encoded as
825 encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
826 characters are regarded as variable `default-mime-charset'."
827 (let* ((structure (car (std11-parse-address
828 (eword-lexical-analyze
829 (std11-unfold-string string) 'must-unfold))))
830 (phrase (std11-full-name-string structure))
831 (address (std11-address-string structure))
833 (list phrase address)
840 (provide 'eword-decode)
842 ;;; eword-decode.el ends here