~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/mail/message.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-08-03 17:04:59 UTC
  • mfrom: (14.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110803170459-wzd99m3567y80ila
Tags: 1:59-1
* Imported Upstream version 59
* Refresh patches to a new release
* Fix FTBFS on ARM (Closes: #634270)
* Update version.bash to work with Debian packaging and not hg
  repository

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
import (
19
19
        "bufio"
20
20
        "bytes"
 
21
        "encoding/base64"
21
22
        "fmt"
22
23
        "io"
 
24
        "io/ioutil"
23
25
        "log"
24
26
        "net/textproto"
25
27
        "os"
94
96
                        return t, nil
95
97
                }
96
98
        }
97
 
        return nil, os.ErrorString("mail: header could not be parsed")
 
99
        return nil, os.NewError("mail: header could not be parsed")
98
100
}
99
101
 
100
102
// A Header represents the key-value pairs in a mail message header.
106
108
        return textproto.MIMEHeader(h).Get(key)
107
109
}
108
110
 
109
 
var ErrHeaderNotPresent = os.ErrorString("mail: header not in message")
 
111
var ErrHeaderNotPresent = os.NewError("mail: header not in message")
110
112
 
111
113
// Date parses the Date header field.
112
114
func (h Header) Date() (*time.Time, os.Error) {
202
204
                        break
203
205
                }
204
206
                if !p.consume(',') {
205
 
                        return nil, os.ErrorString("mail: expected comma")
 
207
                        return nil, os.NewError("mail: expected comma")
206
208
                }
207
209
        }
208
210
        return list, nil
213
215
        debug.Printf("parseAddress: %q", *p)
214
216
        p.skipSpace()
215
217
        if p.empty() {
216
 
                return nil, os.ErrorString("mail: no address")
 
218
                return nil, os.NewError("mail: no address")
217
219
        }
218
220
 
219
221
        // address = name-addr / addr-spec
244
246
        // angle-addr = "<" addr-spec ">"
245
247
        p.skipSpace()
246
248
        if !p.consume('<') {
247
 
                return nil, os.ErrorString("mail: no angle-addr")
 
249
                return nil, os.NewError("mail: no angle-addr")
248
250
        }
249
251
        spec, err = p.consumeAddrSpec()
250
252
        if err != nil {
251
253
                return nil, err
252
254
        }
253
255
        if !p.consume('>') {
254
 
                return nil, os.ErrorString("mail: unclosed angle-addr")
 
256
                return nil, os.NewError("mail: unclosed angle-addr")
255
257
        }
256
258
        debug.Printf("parseAddress: spec=%q", spec)
257
259
 
276
278
        var localPart string
277
279
        p.skipSpace()
278
280
        if p.empty() {
279
 
                return "", os.ErrorString("mail: no addr-spec")
 
281
                return "", os.NewError("mail: no addr-spec")
280
282
        }
281
283
        if p.peek() == '"' {
282
284
                // quoted-string
293
295
        }
294
296
 
295
297
        if !p.consume('@') {
296
 
                return "", os.ErrorString("mail: missing @ in addr-spec")
 
298
                return "", os.NewError("mail: missing @ in addr-spec")
297
299
        }
298
300
 
299
301
        // domain = dot-atom / domain-literal
300
302
        var domain string
301
303
        p.skipSpace()
302
304
        if p.empty() {
303
 
                return "", os.ErrorString("mail: no domain in addr-spec")
 
305
                return "", os.NewError("mail: no domain in addr-spec")
304
306
        }
305
307
        // TODO(dsymonds): Handle domain-literal
306
308
        domain, err = p.consumeAtom(true)
321
323
                var word string
322
324
                p.skipSpace()
323
325
                if p.empty() {
324
 
                        return "", os.ErrorString("mail: missing phrase")
 
326
                        return "", os.NewError("mail: missing phrase")
325
327
                }
326
328
                if p.peek() == '"' {
327
329
                        // quoted-string
345
347
        // Ignore any error if we got at least one word.
346
348
        if err != nil && len(words) == 0 {
347
349
                debug.Printf("consumePhrase: hit err: %v", err)
348
 
                return "", os.ErrorString("mail: missing word in phrase")
 
350
                return "", os.NewError("mail: missing word in phrase")
349
351
        }
350
352
        phrase = strings.Join(words, " ")
351
353
        return phrase, nil
359
361
Loop:
360
362
        for {
361
363
                if i >= p.len() {
362
 
                        return "", os.ErrorString("mail: unclosed quoted-string")
 
364
                        return "", os.NewError("mail: unclosed quoted-string")
363
365
                }
364
366
                switch c := (*p)[i]; {
365
367
                case c == '"':
366
368
                        break Loop
367
369
                case c == '\\':
368
370
                        if i+1 == p.len() {
369
 
                                return "", os.ErrorString("mail: unclosed quoted-string")
 
371
                                return "", os.NewError("mail: unclosed quoted-string")
370
372
                        }
371
373
                        qsb = append(qsb, (*p)[i+1])
372
374
                        i += 2
387
389
// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
388
390
func (p *addrParser) consumeAtom(dot bool) (atom string, err os.Error) {
389
391
        if !isAtext(p.peek(), false) {
390
 
                return "", os.ErrorString("mail: invalid string")
 
392
                return "", os.NewError("mail: invalid string")
391
393
        }
392
394
        i := 1
393
395
        for ; i < p.len() && isAtext((*p)[i], dot); i++ {
423
425
}
424
426
 
425
427
func decodeRFC2047Word(s string) (string, os.Error) {
426
 
        fields := strings.Split(s, "?", -1)
 
428
        fields := strings.Split(s, "?")
427
429
        if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
428
 
                return "", os.ErrorString("mail: address not RFC 2047 encoded")
 
430
                return "", os.NewError("mail: address not RFC 2047 encoded")
429
431
        }
430
432
        charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
431
 
        // TODO(dsymonds): Support "b" encoding too.
432
 
        if enc != "q" {
433
 
                return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
434
 
        }
435
433
        if charset != "iso-8859-1" && charset != "utf-8" {
436
434
                return "", fmt.Errorf("mail: charset not supported: %q", charset)
437
435
        }
438
436
 
439
 
        in := fields[3]
440
 
        b := new(bytes.Buffer)
441
 
        for i := 0; i < len(in); i++ {
442
 
                switch c := in[i]; {
443
 
                case c == '=' && i+2 < len(in):
444
 
                        x, err := strconv.Btoi64(in[i+1:i+3], 16)
445
 
                        if err != nil {
446
 
                                return "", fmt.Errorf("mail: invalid RFC 2047 encoding: %q", in[i:i+3])
447
 
                        }
448
 
                        i += 2
449
 
                        switch charset {
450
 
                        case "iso-8859-1":
451
 
                                b.WriteRune(int(x))
452
 
                        case "utf-8":
453
 
                                b.WriteByte(byte(x))
454
 
                        }
455
 
                case c == '_':
456
 
                        b.WriteByte(' ')
457
 
                default:
458
 
                        b.WriteByte(c)
459
 
                }
460
 
        }
461
 
        return b.String(), nil
 
437
        in := bytes.NewBufferString(fields[3])
 
438
        var r io.Reader
 
439
        switch enc {
 
440
        case "b":
 
441
                r = base64.NewDecoder(base64.StdEncoding, in)
 
442
        case "q":
 
443
                r = qDecoder{r: in}
 
444
        default:
 
445
                return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
 
446
        }
 
447
 
 
448
        dec, err := ioutil.ReadAll(r)
 
449
        if err != nil {
 
450
                return "", err
 
451
        }
 
452
 
 
453
        switch charset {
 
454
        case "iso-8859-1":
 
455
                b := new(bytes.Buffer)
 
456
                for _, c := range dec {
 
457
                        b.WriteRune(int(c))
 
458
                }
 
459
                return b.String(), nil
 
460
        case "utf-8":
 
461
                return string(dec), nil
 
462
        }
 
463
        panic("unreachable")
 
464
}
 
465
 
 
466
type qDecoder struct {
 
467
        r       io.Reader
 
468
        scratch [2]byte
 
469
}
 
470
 
 
471
func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
 
472
        // This method writes at most one byte into p.
 
473
        if len(p) == 0 {
 
474
                return 0, nil
 
475
        }
 
476
        if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
 
477
                return 0, err
 
478
        }
 
479
        switch c := qd.scratch[0]; {
 
480
        case c == '=':
 
481
                if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
 
482
                        return 0, err
 
483
                }
 
484
                x, err := strconv.Btoi64(string(qd.scratch[:2]), 16)
 
485
                if err != nil {
 
486
                        return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
 
487
                }
 
488
                p[0] = byte(x)
 
489
        case c == '_':
 
490
                p[0] = ' '
 
491
        default:
 
492
                p[0] = c
 
493
        }
 
494
        return 1, nil
462
495
}
463
496
 
464
497
var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +