Documentation ¶
Overview ¶
nntp client/server
Index ¶
Constants ¶
const ( // accepted article ARTICLE_ACCEPT = iota // reject article, don't send again ARTICLE_REJECT // defer article, send later ARTICLE_DEFER // reject + ban ARTICLE_BAN )
const LinePrefix_Mode = "MODE "
line prefix for mode
const Line_InvalidMode = RPL_SyntaxError + " Invalid Mode Selected"
line sent on invalid mode
const Line_PostingAllowed = RPL_PostingAllowed + " Posting Allowed"
line sent for posting allowed
const Line_PostingNotAllowed = RPL_PostingNotAllowed + " Posting Not Allowed"
line sent for posting not allowed
const Line_RPLQuit = RPL_Quit + " bai"
send this when we handle a QUIT command
const Line_StreamingAllowed = RPL_PostingStreaming + " aw yeh streamit brah"
line sent on successful streaming
const MODE_READER = Mode("reader")
reader mode
const MODE_STREAM = Mode("stream")
streaming mode
const MODE_UNSET = Mode("")
mode is not set
const ModeReader = ModeCommand("mode reader")
reader mode command
const ModeStream = ModeCommand("mode stream")
streaming mode command
const PolicyAccept = PolicyStatus(ARTICLE_ACCEPT)
const PolicyBan = PolicyStatus(ARTICLE_BAN)
const PolicyDefer = PolicyStatus(ARTICLE_DEFER)
const PolicyReject = PolicyStatus(ARTICLE_REJECT)
const RPL_Article = "220"
article follows
const RPL_ArticleBody = "222"
article body follows
const RPL_ArticleHeaders = "221"
article headers follows
const RPL_ArticleSelectedExists = "223"
selected article exists
const RPL_AuthAccepted = "281"
authentication creds have been accepted
const RPL_AuthInfoAccepted = "250"
AUTHINFO SIMPLE accepted
const RPL_AuthenticateRejected = "482"
authentication creds rejected
const RPL_AuthenticateRequired = "480"
command unavaibale until client has authenticated
const RPL_AuthorizeRejected = "452"
authorization rejected
const RPL_AuthorizeRequired = "450"
authorization required
const RPL_Binary = "288"
binary content follows
const RPL_Capabilities = "101"
capabilities info follows
const RPL_ContinueAuthorization = "350"
continue with authorization
const RPL_Date = "111"
server date time follows
const RPL_EncodingError = "504"
message encoding is bad
const RPL_EncryptionRequired = "483"
command unavailable until connection is encrypted
const RPL_FeatureNotSupported = "503"
feature is not supported
const RPL_GenericError = "403"
generic fault prevent action from being taken
const RPL_GenericFatal = "502"
fatal error happened and connection will close
const RPL_Group = "211"
reply for GROUP and LISTGROUP commands
const RPL_HeadersList = "225"
list of article heards follows
const RPL_Help = "100"
help info follows
const RPL_Index = "218"
index follows
const RPL_List = "215"
info list follows
const RPL_MoreAuth = "381"
more authentication info required
const RPL_NewArticles = "230"
list of new articles follows
const RPL_NewsgroupList = "231"
list of newsgroups followes
const RPL_NoArticleMsgID = "430"
no article with that message-id
const RPL_NoArticleNum = "420"
current article number is invalid
const RPL_NoArticleRange = "423"
no article in specified range
const RPL_NoGroupSelected = "412"
no newsgroup has been selected
const RPL_NoIndex = "418"
no tin style index available
const RPL_NoNextArticle = "421"
no next article in this group (NEXT)
const RPL_NoPrevArticle = "422"
no previous article in this group (LAST)
const RPL_NoSuchGroup = "411"
newsgroup does not exist
const RPL_NotAvaiable = "400"
server says servive is not avaiable on initial connection
const RPL_Overview = "224"
overview info follows
const RPL_PostAccepted = "340"
article was accepted via POST
const RPL_PostReceived = "240"
article was transfered by POST command successfully
const RPL_PostingAllowed = "200"
posting is allowed
const RPL_PostingFailed = "441"
posting failed (2nd stage of POST command)
const RPL_PostingNotAllowed = "201"
posting is not allowed
const RPL_PostingNotPermitted = "440"
posting not permitted (1st stage of POST command)
const RPL_PostingStreaming = "203"
streaming mode enabled
const RPL_Quit = "205"
reply to QUIT command, we will close the connection
const RPL_StreamingAccept = "238"
article is not found by CHECK and we want it
const RPL_StreamingDefer = "431"
defer article asked by CHECK comamnd
const RPL_StreamingFailed = "439"
article transfer via streaming failed (TAKETHIS)
const RPL_StreamingReject = "438"
reject article and don't ask again (CHECK command)
const RPL_StreamingTransfered = "239"
article was transfered via TAKETHIS successfully
const RPL_SyntaxError = "501"
got a command with invalid syntax
const RPL_TransferAccepted = "335"
article is accepted via IHAVE
const RPL_TransferDefer = "436"
article was not sent defer sending (either stage of IHAVE)
const RPL_TransferNotWanted = "435"
article is not wanted (1st stage of IHAVE)
const RPL_TransferOkay = "235"
article was transfered okay by IHAVE command
const RPL_TransferReject = "437"
reject transfer do not retry (2nd stage IHAVE)
const RPL_UnknownCommand = "500"
got an unknown command
const RPL_WrongMode = "401"
server is in the wrong mode
Variables ¶
var DefaultFeedPolicy = &FeedPolicy{ Whitelist: []string{"ctl", "overchan.test"}, Blacklist: []string{`!^overchan\.`}, AllowAnonPosts: true, AllowAnonAttachments: false, UntrustedRequiresPoW: true, AllowAttachments: true, }
default feed policy to be used if not configured explicitly
var ErrArticleNotFound = errors.New("article not found")
var ErrAuthRejected = errors.New("authentication rejected")
authentication was rejected
var ErrInvalidMode = errors.New("invalid mode set")
var ErrPostRejected = errors.New("post rejected")
Functions ¶
This section is empty.
Types ¶
type ArticleAcceptor ¶
type ArticleAcceptor interface { // check article given an article header CheckHeader(hdr message.Header) PolicyStatus // check article given a message id CheckMessageID(msgid MessageID) PolicyStatus // get max article size in bytes MaxArticleSize() int64 }
type defining a policy that determines if we want to accept/reject/defer an incoming article
type ArticleEntry ¶
type ArticleEntry [2]string
(message-id, newsgroup) tuple
func (ArticleEntry) MessageID ¶
func (e ArticleEntry) MessageID() MessageID
func (ArticleEntry) Newsgroup ¶
func (e ArticleEntry) Newsgroup() Newsgroup
type ArticleFilter ¶
type ArticleFilter interface { // filter the article header // returns the modified Header and an error if one occurs FilterHeader(hdr message.Header) (message.Header, error) // reads the article's body and write the filtered version to an io.Writer // returns the number of bytes written to the io.Writer, true if the body was // modifed (or false if body is unchanged) and an error if one occurs FilterAndWriteBody(body io.Reader, wr io.Writer) (int64, bool, error) }
defines interface for filtering an nntp article filters can (and does) modify the article it operates on
type Client ¶
type Client interface { // obtain article by message id // returns an article and nil if obtained // returns nil and an error if an error occured while obtaining the article, // error is ErrArticleNotFound if the remote server doesn't have that article Article(msgid MessageID) (*message.Article, error) // check if the remote server has an article given its message-id // return true and nil if the server has the article // return false and nil if the server doesn't have the article // returns false and error if an error occured while checking Check(msgid MessageID) (bool, error) // check if the remote server carries a newsgroup // return true and nil if the server carries this newsgroup // return false and nil if the server doesn't carry this newsgroup // returns false and error if an error occured while checking NewsgroupExists(group Newsgroup) (bool, error) // return true and nil if posting is allowed // return false and nil if posting is not allowed // return false and error if an error occured PostingAllowed() (bool, error) // post an nntp article to remote server // returns nil on success // returns error if an error ocurred during post // returns ErrPostRejected if the remote server rejected our post Post(a *message.Article) error // connect to remote server // returns nil on success // returns error if one occurs during dial or handshake Connect(d Dialer) error // send quit and disconnects from server // blocks until done Quit() // get client authentication strategy // return nil if no authentication strategy is to be used Auth() ClientAuth }
an nntp client obtains articles from remote nntp server
type ClientAuth ¶
type ClientAuth interface { // send authenticate to server connected via established nntp connection // returns nil on success otherwise an error // retirns ErrAuthRejected if the authentication was rejected SendAuth(c *Conn) error }
defines type for nntp authentication mechanism on client side
type Conn ¶
type Conn interface { // negotiate an nntp session on this connection // returns nil if we negitated successfully // returns ErrAuthRejected if the remote server rejected any authentication // we sent or another error if one occured while negotiating Negotiate() error // obtain connection state GetState() *ConnState // retutrn true if posting is allowed // return false if posting is not allowed PostingAllowed() bool // handle inbound non-streaming connection // call event hooks on event ProcessInbound(hooks EventHooks) // does this connection want to do nntp streaming? WantsStreaming() bool // what mode are we in? // returns mode in all caps Mode() Mode // initiate nntp streaming // after calling this the caller MUST call StreamAndQuit() // returns a channel for message ids, true if caller sends on the channel or // false if the channel is for the caller to recv with // returns nil and ErrStreamingNotAllowed if streaming is not allowed on this // connection or another error if one occurs while trying to start streaming StartStreaming() (chan ArticleEntry, bool, error) // stream articles and quit when the channel obtained by StartStreaming() is // closed, after which this nntp connection is no longer open StreamAndQuit(hooks EventHooks) // is this nntp connection open? IsOpen() bool // send quit command and close connection Quit() }
an nntp connection
type ConnState ¶
type ConnState struct { // name of parent feed FeedName string `json:"feedname"` // name of the connection ConnName string `json:"connname"` // hostname of remote connection HostName string `json:"hostname"` // current nntp mode Mode Mode `json:"mode"` // current selected nntp newsgroup Group Newsgroup `json:"newsgroup"` // current selected nntp article Article string `json:"article"` // parent feed's policy Policy *FeedPolicy `json:"feedpolicy"` // is this connection open? Open bool `json:"open"` }
state of an nntp connection
type Dialer ¶
type Dialer interface { // dial out with a dialer // if cfg is not nil, try to establish a tls connection with STARTTLS // returns a new nntp connection and nil on successful handshake and login // returns nil and an error if an error happened Dial(d network.Dialer, cfg *tls.Config) (*Conn, error) }
establishes an outbound nntp connection to a remote server
type EventHooks ¶
type EventHooks interface { // called when we have obtained an article given its message-id GotArticle(msgid MessageID, group Newsgroup) // called when we have sent an article to a single remote feed SentArticleVia(msgid MessageID, feedname string) }
callback hooks fired on certain events
type FeedPolicy ¶
type FeedPolicy struct { // whitelist list for newsgroups to always allow Whitelist []string `json:"whitelist"` // list of blacklist regexps Blacklist []string `json:"blacklist"` // are anon posts of any kind allowed? AllowAnonPosts bool `json:"anon"` // are anon posts with attachments allowed? AllowAnonAttachments bool `json:"anon_attachments"` // are any attachments allowed? AllowAttachments bool `json:"attachments"` // do we require Proof Of Work for untrusted connections? UntrustedRequiresPoW bool `json:"pow"` }
a policy that governs whether we federate an article via a feed
type MessageID ¶
type MessageID string
func GenMessageID ¶
generate a new message id given name of server
func (MessageID) Blake2Hash ¶
compute blake2 hash of message id
type ModeCommand ¶
type ModeCommand string
a switch mode command
func (ModeCommand) Is ¶
func (m ModeCommand) Is(cmd ModeCommand) bool
check if this mode command is equal to an existing one
func (ModeCommand) Mode ¶
func (m ModeCommand) Mode() Mode
get the mode selected in this mode command
func (ModeCommand) Valid ¶
func (m ModeCommand) Valid() bool
is this mode command well formed? does not check the actual mode sent.
type PolicyStatus ¶
type PolicyStatus int
func (PolicyStatus) String ¶
func (s PolicyStatus) String() string
type Server ¶
type Server struct { // user callbacks Hooks EventHooks // filters to apply Filters []ArticleFilter // database driver DB database.DB // global article acceptor Acceptor ArticleAcceptor // name of this server Name string // article storage Storage store.Storage }
an nntp server
func (*Server) GotArticle ¶
func (*Server) SentArticleVia ¶
type ServerAuth ¶
type ServerAuth interface { // handle authentication phase with an established nntp connection // returns nil on success otherwise error if one occurs during authentication // returns ErrAuthRejected if we rejected the authentication HandleAuth(c *Conn) error }
defines server side authentication mechanism
type StreamEvent ¶
type StreamEvent string
an nntp stream event these are pipelined between nntp servers
func (StreamEvent) Command ¶
func (ev StreamEvent) Command() string
func (StreamEvent) MessageID ¶
func (ev StreamEvent) MessageID() MessageID
func (StreamEvent) String ¶
func (ev StreamEvent) String() string
func (StreamEvent) Valid ¶
func (ev StreamEvent) Valid() bool