commit fac72dc32f3f7bca1001d1583901bcc686a36f46 from: Dustin Sallings date: Thu Feb 23 19:06:56 2012 UTC Updated some docs. commit - fbf58614130284b70ad1d159ac900973ee2d96aa commit + fac72dc32f3f7bca1001d1583901bcc686a36f46 blob - 562d2c56bebbf073be73c2b9a3cf1b8c4fb8e482 blob + b893ee94bd59433fd33b35183639bbb607e011da --- client/client.go +++ client/client.go @@ -1,3 +1,4 @@ +// NNTP Client library. package nntpclient import ( @@ -10,11 +11,13 @@ import ( "github.com/dustin/go-nntp" ) +// The client type Client struct { conn *textproto.Conn Banner string } +// Connect a client to an NNTP server. func New(net, addr string) (*Client, error) { conn, err := textproto.Dial(net, addr) if err != nil { @@ -32,6 +35,7 @@ func New(net, addr string) (*Client, error) { }, nil } +// Authenticate against an NNTP server using authinfo user/pass func (c *Client) Authenticate(user, pass string) (msg string, err error) { err = c.conn.PrintfLine("authinfo user %s", user) if err != nil { @@ -50,6 +54,7 @@ func (c *Client) Authenticate(user, pass string) (msg return } +// Select a group. func (c *Client) Group(name string) (rv nntp.Group, err error) { var msg string _, msg, err = c.Command("GROUP "+name, 211) @@ -78,6 +83,7 @@ func (c *Client) Group(name string) (rv nntp.Group, er return } +// Grab an article func (c *Client) Article(specifier string) (int64, string, io.Reader, error) { err := c.conn.PrintfLine("ARTICLE %s", specifier) if err != nil { @@ -86,6 +92,7 @@ func (c *Client) Article(specifier string) (int64, str return c.articleish(220) } +// Get the headers for an article func (c *Client) Head(specifier string) (int64, string, io.Reader, error) { err := c.conn.PrintfLine("HEAD %s", specifier) if err != nil { @@ -94,6 +101,7 @@ func (c *Client) Head(specifier string) (int64, string return c.articleish(221) } +// Get the body of an article func (c *Client) Body(specifier string) (int64, string, io.Reader, error) { err := c.conn.PrintfLine("BODY %s", specifier) if err != nil { @@ -115,6 +123,10 @@ func (c *Client) articleish(expected int) (int64, stri return n, parts[1], c.conn.DotReader(), nil } +// Post a new article +// +// The reader should contain the entire article, headers and body in +// RFC822ish format. func (c *Client) Post(r io.Reader) error { err := c.conn.PrintfLine("POST") if err != nil { @@ -135,6 +147,13 @@ func (c *Client) Post(r io.Reader) error { return err } +// Send a low-level command and get a response. +// +// This will return an error if the code doesn't match the expectCode +// prefix. For example, if you specify "200", the response code MUST +// be 200 or you'll get an error. If you specify "2", any code from +// 200 (inclusive) to 300 (exclusive) will be success. An expectCode +// of -1 disables this behavior. func (c *Client) Command(cmd string, expectCode int) (int, string, error) { err := c.conn.PrintfLine(cmd) if err != nil { blob - 6526b96e2fb854dd3897584f9b4b96c9cc92edce blob + e9d06c94738fa3c3253d28936d68c3cd26cb010c --- nntp.go +++ nntp.go @@ -1,3 +1,4 @@ +// NNTP definitions. package nntp import ( @@ -6,6 +7,7 @@ import ( "net/textproto" ) +// Posting status type for groups. type PostingStatus byte const ( @@ -19,6 +21,7 @@ func (ps PostingStatus) String() string { return fmt.Sprintf("%c", ps) } +// A usenet newsgroup. type Group struct { Name string Description string @@ -28,13 +31,19 @@ type Group struct { Posting PostingStatus } +// An article that may appear in one or more groups. type Article struct { + // The article's headers Header textproto.MIMEHeader - Body io.Reader - Bytes int - Lines int + // The article's body + Body io.Reader + // Number of bytes in the article body (used by OVER/XOVER) + Bytes int + // Number of lines in the article body (used by OVER/XOVER) + Lines int } +// Convenient access to the article's Message ID. func (a *Article) MessageId() string { return a.Header.Get("Message-Id") } blob - 131f148a4571f0deff0cd0630d5ce57a6998c227 blob + 1d5a2d2313ebc67933c43e5cf2f0c46701e3181a --- server/server.go +++ server/server.go @@ -1,3 +1,4 @@ +// Everything you need for your own NNTP server. package nntpserver import ( @@ -13,6 +14,7 @@ import ( "github.com/dustin/go-nntp" ) +// Coded NNTP error message. type NNTPError struct { Code int Msg string @@ -39,6 +41,8 @@ var AuthRejected = &NNTPError{452, "authorization reje // Low-level protocol handler type Handler func(args []string, s *Server, c *textproto.Conn) error +// When listing articles in a group, this provides local sequence +// numbers to articles. type NumberedArticle struct { Num int64 Article *nntp.Article @@ -56,12 +60,16 @@ type Backend interface { Post(article *nntp.Article) error } +// The server handle. type Server struct { + // Handlers are dispatched by command name. Handlers map[string]Handler - Backend Backend - group *nntp.Group + // The backend (your code) that provides data + Backend Backend + group *nntp.Group } +// Build a new server handle request to a backend. func NewServer(backend Backend) *Server { rv := Server{ Handlers: make(map[string]Handler), @@ -102,6 +110,7 @@ func (s *Server) dispatchCommand(cmd string, args []st return handler(args, s, c) } +// Process an NNTP session. func (s *Server) Process(tc *net.TCPConn) { defer tc.Close() c := textproto.NewConn(tc)