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

unix.superglobalmegacorp.com

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