commit - /dev/null
commit + c95413d6ce7857ed77579a3c8bbcce6e00d0cf92
blob - /dev/null
blob + 32e47df45d5a504f9960679933f6a37c1dc4aeae (mode 644)
--- /dev/null
+++ .gitignore
+*~
+#*
+/examples/client/client
blob - /dev/null
blob + f7fad25b82812636e323f6614970f86d1298339c (mode 644)
--- /dev/null
+++ client/client.go
+package nntpclient
+
+import (
+ "errors"
+ "io"
+ "net/textproto"
+ "strconv"
+ "strings"
+
+ "github.com/dustin/go-nntp"
+)
+
+type Client struct {
+ conn *textproto.Conn
+ Banner string
+}
+
+func New(net, addr string) (*Client, error) {
+ conn, err := textproto.Dial(net, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ _, msg, err := conn.ReadCodeLine(200)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Client{
+ conn: conn,
+ Banner: msg,
+ }, nil
+}
+
+func (c *Client) Authenticate(user, pass string) (msg string, err error) {
+ err = c.conn.PrintfLine("authinfo user %s", user)
+ if err != nil {
+ return
+ }
+ _, _, err = c.conn.ReadCodeLine(381)
+ if err != nil {
+ return
+ }
+
+ err = c.conn.PrintfLine("authinfo pass %s", pass)
+ if err != nil {
+ return
+ }
+ _, msg, err = c.conn.ReadCodeLine(281)
+ return
+}
+
+func (c *Client) Group(name string) (rv nntp.Group, err error) {
+ var msg string
+ _, msg, err = c.Command("GROUP "+name, 211)
+ if err != nil {
+ return
+ }
+ // count first last name
+ parts := strings.Split(msg, " ")
+ if len(parts) != 4 {
+ err = errors.New("Don't know how to parse result: " + msg)
+ }
+ rv.Count, err = strconv.ParseInt(parts[0], 10, 64)
+ if err != nil {
+ return
+ }
+ rv.Low, err = strconv.ParseInt(parts[1], 10, 64)
+ if err != nil {
+ return
+ }
+ rv.High, err = strconv.ParseInt(parts[2], 10, 64)
+ if err != nil {
+ return
+ }
+ rv.Name = parts[3]
+
+ return
+}
+
+func (c *Client) Article(specifier string) (int64, string, io.Reader, error) {
+ err := c.conn.PrintfLine("ARTICLE %s", specifier)
+ if err != nil {
+ return 0, "", nil, err
+ }
+ return c.articleish(220)
+}
+
+func (c *Client) Head(specifier string) (int64, string, io.Reader, error) {
+ err := c.conn.PrintfLine("HEAD %s", specifier)
+ if err != nil {
+ return 0, "", nil, err
+ }
+ return c.articleish(221)
+}
+
+func (c *Client) Body(specifier string) (int64, string, io.Reader, error) {
+ err := c.conn.PrintfLine("BODY %s", specifier)
+ if err != nil {
+ return 0, "", nil, err
+ }
+ return c.articleish(222)
+}
+
+func (c *Client) articleish(expected int) (int64, string, io.Reader, error) {
+ _, msg, err := c.conn.ReadCodeLine(expected)
+ if err != nil {
+ return 0, "", nil, err
+ }
+ parts := strings.SplitN(msg, " ", 2)
+ n, err := strconv.ParseInt(parts[0], 10, 64)
+ if err != nil {
+ return 0, "", nil, err
+ }
+ return n, parts[1], c.conn.DotReader(), nil
+}
+
+func (c *Client) Command(cmd string, expectCode int) (int, string, error) {
+ err := c.conn.PrintfLine(cmd)
+ if err != nil {
+ return 0, "", err
+ }
+ return c.conn.ReadCodeLine(expectCode)
+}
blob - /dev/null
blob + 657477b660e0d4cd844499e0883fc7df0fffa9c8 (mode 644)
--- /dev/null
+++ examples/client/exampleclient.go
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "os"
+
+ "github.com/dustin/go-nntp/client"
+)
+
+func maybefatal(s string, e error) {
+ if e != nil {
+ log.Fatalf("Error in %s: %v", s, e)
+ }
+}
+
+func main() {
+ server, user, pass := os.Args[1], os.Args[2], os.Args[3]
+ c, err := nntpclient.New("tcp", server)
+ maybefatal("connecting", err)
+ log.Printf("Got banner: %v", c.Banner)
+
+ // Set the reader mode
+ _, _, err = c.Command("mode reader", 2)
+ maybefatal("setting reader mode", err)
+
+ // Authenticate
+ msg, err := c.Authenticate(user, pass)
+ maybefatal("authenticating", err)
+ log.Printf("Post authentication message: %v", msg)
+
+ g, err := c.Group("comp.lang.lisp")
+ maybefatal("grouping", err)
+ log.Printf("Got %#v", g)
+
+ n, id, r, err := c.Head(fmt.Sprintf("%v", g.High-1))
+ maybefatal("getting head", err)
+ log.Printf("msg %d has id %v and the following headers", n, id)
+ io.Copy(os.Stdout, r)
+
+ n, id, r, err = c.Body(fmt.Sprintf("%v", n))
+ maybefatal("getting body", err)
+ log.Printf("Body of message %v", id)
+ io.Copy(os.Stdout, r)
+
+ n, id, r, err = c.Article(fmt.Sprintf("%v", n))
+ maybefatal("getting the whole thing", err)
+ log.Printf("Full message %v", id)
+ io.Copy(os.Stdout, r)
+}
blob - /dev/null
blob + d8ec5e9ca77aa52080bf3c80ed7f36a5a6ecbae8 (mode 644)
--- /dev/null
+++ nntp.go
+package nntp
+
+type PostingStatus byte
+
+const (
+ Unknown = PostingStatus(0)
+ PostingPermitted = PostingStatus('y')
+ PostingNotPermitted = PostingStatus('n')
+ PostingModerated = PostingStatus('m')
+)
+
+type Group struct {
+ Name string
+ Count int64
+ High int64
+ Low int64
+ Posting PostingStatus
+}