]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/openpgp/packet: add UserId packet type
authorAdam Langley <agl@golang.org>
Tue, 8 Feb 2011 02:40:33 +0000 (21:40 -0500)
committerAdam Langley <agl@golang.org>
Tue, 8 Feb 2011 02:40:33 +0000 (21:40 -0500)
This was split from CL 4124054

R=bradfitzgo
CC=golang-dev
https://golang.org/cl/4126057

src/pkg/crypto/openpgp/packet/userid.go [new file with mode: 0644]
src/pkg/crypto/openpgp/packet/userid_test.go [new file with mode: 0644]

diff --git a/src/pkg/crypto/openpgp/packet/userid.go b/src/pkg/crypto/openpgp/packet/userid.go
new file mode 100644 (file)
index 0000000..ed2ad77
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+       "io"
+       "io/ioutil"
+       "os"
+       "strings"
+)
+
+// UserId contains text that is intended to represent the name and email
+// address of the key holder. See RFC 4880, section 5.11. By convention, this
+// takes the form "Full Name (Comment) <email@example.com>"
+type UserId struct {
+       Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
+
+       Name, Comment, Email string
+}
+
+func (uid *UserId) parse(r io.Reader) (err os.Error) {
+       // RFC 4880, section 5.11
+       b, err := ioutil.ReadAll(r)
+       if err != nil {
+               return
+       }
+       uid.Id = string(b)
+       uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
+       return
+}
+
+// parseUserId extracts the name, comment and email from a user id string that
+// is formatted as "Full Name (Comment) <email@example.com>".
+func parseUserId(id string) (name, comment, email string) {
+       var n, c, e struct {
+               start, end int
+       }
+       var state int
+
+       for offset, rune := range id {
+               switch state {
+               case 0:
+                       // Entering name
+                       n.start = offset
+                       state = 1
+                       fallthrough
+               case 1:
+                       // In name
+                       if rune == '(' {
+                               state = 2
+                               n.end = offset
+                       } else if rune == '<' {
+                               state = 5
+                               n.end = offset
+                       }
+               case 2:
+                       // Entering comment
+                       c.start = offset
+                       state = 3
+                       fallthrough
+               case 3:
+                       // In comment
+                       if rune == ')' {
+                               state = 4
+                               c.end = offset
+                       }
+               case 4:
+                       // Between comment and email
+                       if rune == '<' {
+                               state = 5
+                       }
+               case 5:
+                       // Entering email
+                       e.start = offset
+                       state = 6
+                       fallthrough
+               case 6:
+                       // In email
+                       if rune == '>' {
+                               state = 7
+                               e.end = offset
+                       }
+               default:
+                       // After email
+               }
+       }
+       switch state {
+       case 1:
+               // ended in the name
+               n.end = len(id)
+       case 3:
+               // ended in comment
+               c.end = len(id)
+       case 6:
+               // ended in email
+               e.end = len(id)
+       }
+
+       name = strings.TrimSpace(id[n.start:n.end])
+       comment = strings.TrimSpace(id[c.start:c.end])
+       email = strings.TrimSpace(id[e.start:e.end])
+       return
+}
diff --git a/src/pkg/crypto/openpgp/packet/userid_test.go b/src/pkg/crypto/openpgp/packet/userid_test.go
new file mode 100644 (file)
index 0000000..394873d
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+       "testing"
+)
+
+var userIdTests = []struct {
+       id                   string
+       name, comment, email string
+}{
+       {"", "", "", ""},
+       {"John Smith", "John Smith", "", ""},
+       {"John Smith ()", "John Smith", "", ""},
+       {"John Smith () <>", "John Smith", "", ""},
+       {"(comment", "", "comment", ""},
+       {"(comment)", "", "comment", ""},
+       {"<email", "", "", "email"},
+       {"<email>   sdfk", "", "", "email"},
+       {"  John Smith  (  Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
+       {"  John Smith  < email > lksdfj", "John Smith", "", "email"},
+       {"(<foo", "", "<foo", ""},
+       {"René Descartes (العربي)", "René Descartes", "العربي", ""},
+}
+
+func TestParseUserId(t *testing.T) {
+       for i, test := range userIdTests {
+               name, comment, email := parseUserId(test.id)
+               if name != test.name {
+                       t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
+               }
+               if comment != test.comment {
+                       t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
+               }
+               if email != test.email {
+                       t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
+               }
+       }
+}