Annotation of GNUtools/emacs/lisp/rfc822.el, revision 1.1

1.1     ! root        1: ;; Hairy rfc822 parser for mail and news and suchlike
        !             2: ;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
        !             3: ;; Author Richard Mlynarik.
        !             4: 
        !             5: ;; This file is part of GNU Emacs.
        !             6: 
        !             7: ;; GNU Emacs is free software; you can redistribute it and/or modify
        !             8: ;; it under the terms of the GNU General Public License as published by
        !             9: ;; the Free Software Foundation; either version 1, or (at your option)
        !            10: ;; any later version.
        !            11: 
        !            12: ;; GNU Emacs is distributed in the hope that it will be useful,
        !            13: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15: ;; GNU General Public License for more details.
        !            16: 
        !            17: ;; You should have received a copy of the GNU General Public License
        !            18: ;; along with GNU Emacs; see the file COPYING.  If not, write to
        !            19: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
        !            20: 
        !            21: (provide 'rfc822)
        !            22: 
        !            23: ;; uses address-start free, throws to address
        !            24: (defun rfc822-bad-address (reason)
        !            25:   (save-restriction
        !            26:     (insert "_^_")
        !            27:     (narrow-to-region address-start
        !            28:                      (if (re-search-forward "[,;]" nil t)
        !            29:                          (max (point-min) (1- (point)))
        !            30:                        (point-max)))
        !            31:     ;; make the error string be suitable for inclusion in (...)
        !            32:     (let ((losers '("\\" "(" ")" "\n")))
        !            33:       (while losers
        !            34:        (goto-char (point-min))
        !            35:        (while (search-forward (car losers) nil t)
        !            36:          (backward-char 1)
        !            37:          (insert ?\\)
        !            38:          (forward-char 1))
        !            39:        (setq losers (cdr losers))))
        !            40:     (goto-char (point-min)) (insert "(Unparsable address -- "
        !            41:                                    reason
        !            42:                                    ":\n\t  \"")
        !            43:     (goto-char (point-max)) (insert "\")"))
        !            44:   (rfc822-nuke-whitespace)
        !            45:   (throw 'address (buffer-substring address-start (point))))
        !            46: 
        !            47: (defun rfc822-nuke-whitespace (&optional leave-space)
        !            48:   (let (ch)
        !            49:     (while (cond ((eobp)
        !            50:                  nil)
        !            51:                 ((= (setq ch (following-char)) ?\()
        !            52:                  (forward-char 1)
        !            53:                  (while (if (eobp)
        !            54:                             (rfc822-bad-address "Unbalanced comment (...)")
        !            55:                           (/= (setq ch (following-char)) ?\)))
        !            56:                    (cond ((looking-at "[^()\\]+")
        !            57:                           (replace-match ""))
        !            58:                          ((= ch ?\()
        !            59:                           (rfc822-nuke-whitespace))
        !            60:                          ((< (point) (1- (point-max)))
        !            61:                           (delete-char 2))
        !            62:                          (t
        !            63:                           (rfc822-bad-address "orphaned backslash"))))
        !            64:                  ;; delete remaining "()"
        !            65:                  (forward-char -1)
        !            66:                  (delete-char 2)
        !            67:                  t)
        !            68:                 ((memq ch '(?\ ?\t ?\n))
        !            69:                  (delete-region (point)
        !            70:                                 (progn (skip-chars-forward " \t\n") (point)))
        !            71:                  t)
        !            72:                 (t
        !            73:                  nil)))
        !            74:     (or (not leave-space)
        !            75:        (eobp)
        !            76:        (bobp)
        !            77:        (= (preceding-char) ?\ )
        !            78:        (insert ?\ ))))
        !            79: 
        !            80: (defun rfc822-looking-at (regex &optional leave-space)
        !            81:   (if (cond ((stringp regex)
        !            82:             (if (looking-at regex)
        !            83:                 (progn (goto-char (match-end 0))
        !            84:                        t)))
        !            85:            (t
        !            86:             (if (and (not (eobp))
        !            87:                      (= (following-char) regex))
        !            88:                 (progn (forward-char 1)
        !            89:                        t))))
        !            90:       (let ((tem (match-data)))
        !            91:        (rfc822-nuke-whitespace leave-space)
        !            92:        (store-match-data tem)
        !            93:        t)))
        !            94: 
        !            95: (defun rfc822-snarf-word ()
        !            96:   ;; word is atom | quoted-string
        !            97:   (cond ((= (following-char) ?\")
        !            98:         ;; quoted-string
        !            99:         (or (rfc822-looking-at "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"")
        !           100:             (rfc822-bad-address "Unterminated quoted string")))
        !           101:        ((rfc822-looking-at "[^][\000-\037\177-\377 ()<>@,;:\\\".]+")
        !           102:         ;; atom
        !           103:         )
        !           104:        (t
        !           105:         (rfc822-bad-address "Rubbish in address"))))
        !           106: 
        !           107: (defun rfc822-snarf-words ()
        !           108:   (rfc822-snarf-word)
        !           109:   (while (rfc822-looking-at ?.)
        !           110:     (rfc822-snarf-word)))
        !           111: 
        !           112: (defun rfc822-snarf-subdomain ()
        !           113:   ;; sub-domain is domain-ref | domain-literal
        !           114:   (cond ((= (following-char) ?\[)
        !           115:         ;; domain-ref
        !           116:         (or (rfc822-looking-at "\\[\\([^][\\\n]\\|\\\\.\\|\\\\\n\\)*\\]")
        !           117:             (rfc822-bad-address "Unterminated domain literal [...]")))
        !           118:        ((rfc822-looking-at "[^][\000-\037\177-\377 ()<>@,;:\\\".]+")
        !           119:         ;; domain-literal = atom
        !           120:         )
        !           121:        (t
        !           122:         (rfc822-bad-address "Rubbish in host/domain specification"))))
        !           123: 
        !           124: (defun rfc822-snarf-domain ()
        !           125:   (rfc822-snarf-subdomain)
        !           126:   (while (rfc822-looking-at ?.)
        !           127:     (rfc822-snarf-subdomain)))
        !           128: 
        !           129: (defun rfc822-snarf-frob-list (name separator terminator snarfer
        !           130:                                    &optional return)
        !           131:   (let ((first t)
        !           132:        (list ())
        !           133:        tem)
        !           134:     (while (cond ((eobp)
        !           135:                  (rfc822-bad-address
        !           136:                    (format "End of addresses in middle of %s" name)))
        !           137:                 ((rfc822-looking-at terminator)
        !           138:                  nil)
        !           139:                 ((rfc822-looking-at separator)
        !           140:                  ;; multiple separators are allowed and do nothing.
        !           141:                  (while (rfc822-looking-at separator))
        !           142:                  t)
        !           143:                 (first
        !           144:                  t)
        !           145:                 (t
        !           146:                  (rfc822-bad-address
        !           147:                    (format "Gubbish in middle of %s" name))))
        !           148:       (setq tem (funcall snarfer)
        !           149:            first nil)
        !           150:       (and return tem
        !           151:           (setq list (if (listp tem)
        !           152:                          (nconc (reverse tem) list)
        !           153:                          (cons tem list)))))
        !           154:     (nreverse list)))
        !           155: 
        !           156: ;; return either an address (a string) or a list of addresses
        !           157: (defun rfc822-addresses-1 (&optional allow-groups)
        !           158:   ;; Looking for an rfc822 `address'
        !           159:   ;; Either a group (1*word ":" [#mailbox] ";")
        !           160:   ;; or a mailbox (addr-spec | 1*word route-addr)
        !           161:   ;;  addr-spec is (local-part "@" domain)
        !           162:   ;;  route-addr is ("<" [1#("@" domain) ":"] addr-spec ">")
        !           163:   ;;  local-part is (word *("." word))
        !           164:   ;;  word is (atom | quoted-string)
        !           165:   ;;  quoted-string is ("\([^\"\\n]\|\\.\|\\\n\)")
        !           166:   ;;  atom is [^\000-\037\177 ()<>@,;:\".[]]+
        !           167:   ;;  domain is sub-domain *("." sub-domain)
        !           168:   ;;  sub-domain is domain-ref | domain-literal
        !           169:   ;;  domain-literal is  "[" *(dtext | quoted-pair) "]"
        !           170:   ;;  dtext is "[^][\\n"
        !           171:   ;;  domain-ref is atom
        !           172:   (let ((address-start (point))
        !           173:        (n 0))
        !           174:     (catch 'address
        !           175:       ;; optimize common cases:
        !           176:       ;;  foo
        !           177:       ;;  [email protected]
        !           178:       ;; followed by "\\'\\|,\\|([^()\\]*)\\'"
        !           179:       ;; other common cases are:
        !           180:       ;;  foo bar <[email protected]>
        !           181:       ;;  "foo bar" <[email protected]>
        !           182:       ;;  those aren't hacked yet.
        !           183:       (if (and (rfc822-looking-at "[^][\000-\037\177-\377 ()<>@,;:\\\"]+\\(\\|@[^][\000-\037\177-\377 ()<>@,;:\\\"]+\\)" t)
        !           184:               (progn (or (eobp)
        !           185:                          (rfc822-looking-at ?,))))
        !           186:          (progn
        !           187:            ;; rfc822-looking-at may have inserted a space
        !           188:            (or (bobp) (/= (preceding-char) ?\ ) (delete-char -1))
        !           189:            ;; relying on the fact that rfc822-looking-at <char>
        !           190:            ;;  doesn't mung match-data
        !           191:            (throw 'address (buffer-substring address-start (match-end 0)))))
        !           192:       (goto-char address-start)
        !           193:       (while t
        !           194:        (cond ((and (= n 1) (rfc822-looking-at ?@))
        !           195:               ;; local-part@domain
        !           196:               (rfc822-snarf-domain)
        !           197:               (throw 'address
        !           198:                 (buffer-substring address-start (point))))
        !           199:              ((rfc822-looking-at ?:)
        !           200:               (cond ((not allow-groups)
        !           201:                      (rfc822-bad-address "A group name may not appear here"))
        !           202:                     ((= n 0)
        !           203:                      (rfc822-bad-address "No name for :...; group")))
        !           204:               ;; group
        !           205:               (throw 'address
        !           206:                 ;; return a list of addresses
        !           207:                 (rfc822-snarf-frob-list ":...; group" ?\, ?\;
        !           208:                                         'rfc822-addresses-1 t)))
        !           209:              ((rfc822-looking-at ?<)
        !           210:               (let ((start (point))
        !           211:                     (strip t))
        !           212:                 (cond ((rfc822-looking-at ?>)
        !           213:                        ;; empty path
        !           214:                        ())
        !           215:                       ((and (not (eobp)) (= (following-char) ?\@))
        !           216:                        ;; <@foo.bar,@baz:[email protected]>
        !           217:                        (rfc822-snarf-frob-list "<...> address" ?\, ?\:
        !           218:                          (function (lambda ()
        !           219:                                      (if (rfc822-looking-at ?\@)
        !           220:                                          (rfc822-snarf-domain)
        !           221:                                        (rfc822-bad-address
        !           222:                                          "Gubbish in route-addr")))))
        !           223:                        (rfc822-snarf-words)
        !           224:                        (or (rfc822-looking-at ?@)
        !           225:                            (rfc822-bad-address "Malformed <..@..> address"))
        !           226:                        (rfc822-snarf-domain)
        !           227:                        (setq strip nil))
        !           228:                       ((progn (rfc822-snarf-words) (rfc822-looking-at ?@))
        !           229:                        ; allow <foo> (losing unix seems to do this)
        !           230:                        (rfc822-snarf-domain)))
        !           231:                 (let ((end (point)))
        !           232:                   (if (rfc822-looking-at ?\>)
        !           233:                       (throw 'address
        !           234:                         (buffer-substring (if strip start (1- start))
        !           235:                                           (if strip end (1+ end))))
        !           236:                     (rfc822-bad-address "Unterminated <...> address")))))
        !           237:              ((looking-at "[^][\000-\037\177-\377 ()<>@,;:\\.]")
        !           238:               ;; this allows "." to be part of the words preceding
        !           239:               ;; an addr-spec, since many broken mailers output
        !           240:               ;; "Hern K. Herklemeyer III
        !           241:               ;;   <[email protected]>"
        !           242:                (let ((again t))
        !           243:                  (while again
        !           244:                    (or (= n 0) (bobp) (= (preceding-char) ?\ )
        !           245:                        (insert ?\ ))
        !           246:                    (rfc822-snarf-words)
        !           247:                    (setq n (1+ n))
        !           248:                    (setq again (or (rfc822-looking-at ?.)
        !           249:                                    (looking-at "[^][\000-\037\177-\377 ()<>@,;:\\.]"))))))
        !           250:              ((= n 0)
        !           251:               (throw 'address nil))
        !           252:              ((= n 1) ; allow "foo" (losing unix seems to do this)
        !           253:               (throw 'address
        !           254:                 (buffer-substring address-start (point))))
        !           255:               ((> n 1)
        !           256:                (rfc822-bad-address "Missing comma between addresses or badly-formatted address"))
        !           257:              ((or (eobp) (= (following-char) ?,))
        !           258:               (rfc822-bad-address "Missing comma or route-spec"))
        !           259:              (t
        !           260:               (rfc822-bad-address "Strange character or missing comma")))))))
        !           261: 
        !           262:                           
        !           263: (defun rfc822-addresses (header-text)
        !           264:   (if (string-match "\\`[ \t]*\\([^][\000-\037\177-\377 ()<>@,;:\\\".]+\\)[ \t]*\\'"
        !           265:                     header-text)
        !           266:       ;; Make very simple case moderately fast.
        !           267:       (list (substring header-text (match-beginning 1) (match-end 1)))
        !           268:     (let ((buf (generate-new-buffer " rfc822")))
        !           269:       (unwind-protect
        !           270:        (save-excursion
        !           271:          (set-buffer buf)
        !           272:          (make-local-variable 'case-fold-search)
        !           273:          (setq case-fold-search nil)   ;For speed(?)
        !           274:          (insert header-text)
        !           275:          ;; unfold continuation lines
        !           276:          (goto-char (point-min))
        !           277: 
        !           278:          (while (re-search-forward "\\([^\\]\\(\\\\\\\\\\)*\\)\n[ \t]" nil t)
        !           279:            (replace-match "\\1 " t))
        !           280: 
        !           281:          (goto-char (point-min))
        !           282:          (rfc822-nuke-whitespace)
        !           283:          (let ((list ())
        !           284:                tem
        !           285:                address-start); this is for rfc822-bad-address
        !           286:            (while (not (eobp))
        !           287:              (setq address-start (point))
        !           288:              (setq tem
        !           289:                    (catch 'address ; this is for rfc822-bad-address
        !           290:                      (cond ((rfc822-looking-at ?\,)
        !           291:                             nil)
        !           292:                            ((looking-at "[][\000-\037\177-\377@;:\\.>)]")
        !           293:                             (forward-char)
        !           294:                             (rfc822-bad-address
        !           295:                               (format "Strange character \\%c found"
        !           296:                                       (preceding-char))))
        !           297:                            (t
        !           298:                             (rfc822-addresses-1 t)))))
        !           299:              (cond ((null tem))
        !           300:                    ((stringp tem)
        !           301:                     (setq list (cons tem list)))
        !           302:                    (t
        !           303:                     (setq list (nconc (nreverse tem) list)))))
        !           304:            (nreverse list)))
        !           305:       (and buf (kill-buffer buf))))))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.