Documentation ¶
Overview ¶
fbb provides a client-side implementation of the B2 Forwarding Protocol and Winlink 2000 Message Structure for transfer of messages to and from a Winlink 2000 Radio Email Server (RMS) gateway.
Index ¶
- Constants
- Variables
- func BodyFromBytes(data []byte, encoding string) (string, error)
- func GenerateMid(callsign string) string
- func IsLoginFailure(err error) bool
- func ParseDate(dateStr string) (time.Time, error)
- func ReadLine(rd io.Reader) (string, error)
- func StringToBody(str, encoding string) ([]byte, error)
- type Address
- type ByDate
- type File
- type Header
- type InboundHandler
- type MBoxHandler
- type Message
- func (m *Message) AddCc(addr ...string)
- func (m *Message) AddFile(f *File)
- func (m *Message) AddTo(addr ...string)
- func (m *Message) Body() (string, error)
- func (m *Message) BodySize() int
- func (m *Message) Bytes() ([]byte, error)
- func (m *Message) Cc() (cc []Address)
- func (m *Message) Charset() string
- func (m *Message) Date() time.Time
- func (m *Message) Files() []*File
- func (m *Message) From() Address
- func (m *Message) IsOnlyReceiver(addr Address) bool
- func (m *Message) MID() string
- func (m *Message) Mbo() string
- func (m *Message) Proposal(code PropCode) (*Proposal, error)
- func (m *Message) ReadFrom(r io.Reader) error
- func (m *Message) Receivers() []Address
- func (m *Message) SetBody(body string) error
- func (m *Message) SetBodyWithCharset(charset, body string) error
- func (m *Message) SetDate(t time.Time)
- func (m *Message) SetFrom(addr string)
- func (m *Message) SetSubject(str string)
- func (m *Message) String() string
- func (m *Message) Subject() string
- func (m *Message) To() (to []Address)
- func (m *Message) Type() MsgType
- func (m *Message) Validate() error
- func (m *Message) Write(w io.Writer) (err error)
- type MsgType
- type OutboundHandler
- type PropCode
- type Proposal
- type ProposalAnswer
- type Session
- func (s *Session) AddAuxiliaryAddress(aux ...Address)
- func (s *Session) Done() bool
- func (s *Session) Exchange(conn net.Conn) (stats TrafficStats, err error)
- func (s *Session) IsMaster(isMaster bool)
- func (s *Session) Mycall() string
- func (s *Session) RemoteForwarders() []Address
- func (s *Session) RemoteSID() string
- func (s *Session) SetLogger(logger *log.Logger)
- func (s *Session) SetMOTD(line ...string)
- func (s *Session) SetRobustMode(mode robustMode)
- func (s *Session) SetSecureLoginHandleFunc(f func(addr Address) (password string, err error))
- func (s *Session) SetStatusUpdater(updater StatusUpdater)
- func (s *Session) SetUserAgent(ua UserAgent)
- func (s *Session) Targetcall() string
- func (s *Session) UserAgent() UserAgent
- type Status
- type StatusUpdater
- type TrafficStats
- type UserAgent
- type ValidationError
- type WordDecoder
Constants ¶
const ( ProtocolOffsetSizeLimit = 999999 MaxBlockSize = 5 // Paclink-unix uses 250, protocol maximum is 255, but we use 125 to allow use of AX.25 links with a paclen of 128. // TODO: Consider setting this dynamically. MaxMsgLength = 125 )
const ( HEADER_MID = `Mid` HEADER_TO = `To` HEADER_DATE = `Date` HEADER_TYPE = `Type` HEADER_FROM = `From` HEADER_CC = `Cc` HEADER_SUBJECT = `Subject` HEADER_MBO = `Mbo` HEADER_BODY = `Body` HEADER_FILE = `File` // These headers are stripped by the winlink system, but let's // include it anyway... just in case the winlink team one day // starts taking encoding seriously. HEADER_CONTENT_TYPE = `Content-Type` HEADER_CONTENT_TRANSFER_ENCODING = `Content-Transfer-Encoding` // The default body charset seems to be ISO-8859-1 // // The Winlink Message Structure docs says that the body should // be ASCII-only, but RMS Express seems to encode the body as // ISO-8859-1. This is also the charset set (Content-Type header) // when a message reaches an SMTP server. DefaultCharset = "ISO-8859-1" // Mails going out over SMTP from the Winlink system is sent // with the header 'Content-Transfer-Encoding: 7bit', but // let's be reasonable... we don't send ASCII-only body. DefaultTransferEncoding = "8bit" // The date (in UTC) format as described in the Winlink // Message Structure docs (YYYY/MM/DD HH:MM). DateLayout = `2006/01/02 15:04` )
Common Winlink 2000 Message headers
const ( Private MsgType = "Private" Service = "Service" Inquiry = "Inquiry" PositionReport = "Position Report" Option = "Option" System = "System" )
const ( BasicProposal PropCode = 'B' // Basic ASCII proposal (or compressed binary in v0/1) AsciiProposal = 'A' // Compressed v0/1 ASCII proposal Wl2kProposal = 'C' // Compressed v2 proposal (winlink extension) GzipProposal = 'D' // Gzip compressed v2 proposal )
const ( Accept ProposalAnswer = '+' Reject = '-' Defer = '=' )
const ( RobustAuto robustMode = iota // Run the connection in robust-mode when not transferring outbound messages. RobustForced // Always run the connection in robust-mode. RobustDisabled // Never run the connection in robust-mode. )
The different robust-mode settings.
const MaxMIDLength = 12
Variables ¶
var ErrConnLost = errors.New("connection lost")
ErrConnLost is returned by Session.Exchange if the connection is prematurely closed.
var ErrNoFB2 = errors.New("Remote does not support B2 Forwarding Protocol")
var ErrOffsetLimitExceeded error = errors.New("Protocol does not support offset larger than 6 digits")
var StdUA = UserAgent{Name: "wl2kgo", Version: "0.1a"}
Functions ¶
func BodyFromBytes ¶
BodyFromBytes translated the data based on the given charset encoding into a proper utf-8 string.
func GenerateMid ¶
Generates a unique message ID in the format specified by the protocol.
func IsLoginFailure ¶
IsLoginFailure returns a boolean indicating whether the error is known to report that the secure login failed.
func StringToBody ¶
StringToBytes converts the body into a slice of bytes with the given charset encoding.
CRLF line break is enforced. Line break are inserted if a line is longer than 1000 characters (including CRLF).
Types ¶
type Address ¶
Representation of a receiver/sender address.
func AddressFromString ¶
Function that constructs a proper Address from a string.
Supported formats: foo@bar.baz (SMTP proto), N0CALL (short winlink address) or N0CALL@winlink.org (full winlink address).
func (Address) EqualString ¶
EqualString reports whether the given address string is equal to this address.
type File ¶
type File struct {
// contains filtered or unexported fields
}
File represents an attachment.
type Header ¶
A Header represents the key-value pairs in a Winlink 2000 Message header.
func (Header) Add ¶
Add adds the key, value pair to the header. It appends to any existing values associated with key.
func (Header) Get ¶
Get gets the first value associated with the given key. If there are no values associated with the key, Get returns "". To access multiple values of a key, access the map directly with CanonicalHeaderKey.
type InboundHandler ¶
type InboundHandler interface { // ProcessInbound should persist/save/process all messages received (msgs) returning an error if the operation was unsuccessful. // // The error will be delivered (if possble) to the remote to indicate that an error has occurred. ProcessInbound(msg ...*Message) error // GetInboundAnswer should return a ProposalAnwer (Accept/Reject/Defer) based on the remote's message Proposal p. // // An already successfully received message (see MID) should be rejected. GetInboundAnswer(p Proposal) ProposalAnswer }
An InboundHandler handles all messages that can/is sent from the remote node.
type MBoxHandler ¶
type MBoxHandler interface { InboundHandler OutboundHandler // Prepare is called before any other operation in a session. // // The returned error can be used to indicate that the mailbox is // not ready for a new session, the error will be forwarded to the // remote node. Prepare() error }
Objects implementing the MBoxHandler interface can be used to handle inbound and outbound messages for a Session.
type Message ¶
type Message struct { // The header names are case-insensitive. // // Users should normally access common header fields // using the appropriate Message methods. Header Header // contains filtered or unexported fields }
Message represent the Winlink 2000 Message Structure as defined in http://winlink.org/B2F.
func NewMessage ¶
NewMessage initializes and returns a new message with Type, Mbo, From and Date set.
If the message type t is empty, it defaults to Private.
func (*Message) AddCc ¶
AddCc adds a new carbon copy receiver to this message.
It adds a new Cc header field per given address. SMTP: prefix is automatically added if needed, see AddressFromString.
func (*Message) AddTo ¶
AddTo adds a new receiver for this message.
It adds a new To header field per given address. SMTP: prefix is automatically added if needed, see AddressFromString.
func (*Message) BodySize ¶
BodySize returns the expected size of the body (in bytes) as defined in the header.
func (*Message) Charset ¶
Charset returns the body character encoding as defined in the ContentType header field.
If the header field is unset, DefaultCharset is returned.
func (*Message) Date ¶
Date parses the Date header field according to the winlink format.
Parse errors are omitted, but it's checked at serialization.
func (*Message) IsOnlyReceiver ¶
Returns true if the given Address is the only receiver of this Message.
func (*Message) Proposal ¶
Method for generating a proposal of the message.
An error is returned if the Validate method fails.
func (*Message) ReadFrom ¶
Implements ReaderFrom for Message.
Reads the given io.Reader and fills in values fetched from the stream.
func (*Message) SetBody ¶
SetBody sets the given string as message body using DefaultCharset.
See SetBodyWithCharset for more info.
func (*Message) SetBodyWithCharset ¶
SetBodyWithCharset translates and sets the body according to given charset.
Header field Content-Transfer-Encoding is set to DefaultTransferEncoding. Header field Content-Type is set according to charset. All lines are modified to ensure CRLF.
Use SetBody to use default character encoding.
func (*Message) SetDate ¶
Set date sets the Date header field.
The field is set in the format DateLayout, UTC.
func (*Message) SetFrom ¶
SetFrom sets the From header field.
SMTP: prefix is automatically added if needed, see AddressFromString.
func (*Message) SetSubject ¶
SetSubject sets this message's subject field.
The Winlink Message Format only allow ASCII characters. Words containing non-ASCII characters are Q-encoded with DefaultCharset (as defined by RFC 2047).
type OutboundHandler ¶
type OutboundHandler interface { // GetOutbound should return all pending (outbound) messages addressed to (and only to) one of the fw addresses. // // No fw address implies that the remote node could be a Winlink CMS and all oubound // messages can be delivered through the connected node. GetOutbound(fw ...Address) (out []*Message) // SetSent should mark the the message identified by MID as successfully sent. // // If rejected is true, it implies that the remote node has already received the message. SetSent(MID string, rejected bool) // SetDeferred should mark the outbound message identified by MID as deferred. // // SetDeferred is called when the remote want's to receive the proposed message // (see MID) later. SetDeferred(MID string) }
An OutboundHandler offer messages that can be delivered (a proposal) to the remote node and is notified when a message is sent or defered.
type Proposal ¶
type Proposal struct {
// contains filtered or unexported fields
}
Proposal is the type representing a inbound or outbound proposal.
func NewProposal ¶
Constructor for a new Proposal given a Winlink Message.
Reads the Winlink Message given and constructs a new proposal based on what's read and prepares for outbound delivery, returning a Proposal with the given data.
func (*Proposal) DataIsComplete ¶
Method for checking if the Proposal is completely downloaded/loaded and ready to be read/sent.
Typically used to check if the whole message was successfully downloaded from the CMS.
type ProposalAnswer ¶
type ProposalAnswer byte
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session represents a B2F exchange session.
A session should only be used once.
func NewSession ¶
func NewSession(mycall, targetcall, locator string, h MBoxHandler) *Session
Constructs a new Session object.
The Handler can be nil (but no messages will be exchanged).
Mycall and targetcall will be upper-cased.
func (*Session) AddAuxiliaryAddress ¶
AddAuxiliaryAddress adds one or more addresses to request messages on behalf of.
Currently the Winlink System only support requesting messages for call signs, not full email addresses.
func (*Session) Exchange ¶
func (s *Session) Exchange(conn net.Conn) (stats TrafficStats, err error)
Exchange is the main method for exchanging messages with a remote over the B2F protocol.
Sends outbound messages and downloads inbound messages prepared for this session.
Outbound messages should be added as proposals before calling the Exchange() method.
If conn implements the transport.Robust interface, the connection is run in robust-mode except when an outbound message is transferred.
After Exchange(), messages that was accepted and delivered successfully to the RMS is available through a call to Sent(). Messages downloaded successfully from the RMS is retrieved by calling Received().
The connection is closed at the end of the exchange. If the connection is closed before the exchange is done, ErrConnLost is returned.
Subsequent Exchange calls on the same session is a noop.
func (*Session) RemoteForwarders ¶
This method returns the call signs the remote is requesting traffic on behalf of. The call signs are not available until the handshake is done.
It will typically be the call sign of the remote P2P station and empty when the remote is a Winlink CMS.
func (*Session) SetMOTD ¶
SetMOTD sets one or more lines to be sent before handshake.
The MOTD is only sent if the local node is session master.
func (*Session) SetRobustMode ¶
func (s *Session) SetRobustMode(mode robustMode)
SetRobustMode sets the RobustMode for this exchange.
The mode is ignored if the exchange connection does not implement the transport.Robust interface.
Default is RobustAuto.
func (*Session) SetSecureLoginHandleFunc ¶
SetSecureLoginHandleFunc registers a callback function used to prompt for password when a secure login challenge is received.
func (*Session) SetStatusUpdater ¶
func (s *Session) SetStatusUpdater(updater StatusUpdater)
Set callback for status updates on receiving / sending messages
func (*Session) SetUserAgent ¶
Set this session's user agent
func (*Session) Targetcall ¶
Targetcall returns the remote stations call sign (if known).
type Status ¶
type Status struct { Receiving *Proposal Sending *Proposal BytesTransferred int BytesTotal int Done bool When time.Time }
Status holds information about ongoing transfers.
type StatusUpdater ¶
type StatusUpdater interface {
UpdateStatus(s Status)
}
type TrafficStats ¶
type TrafficStats struct { Received []string // Received message MIDs. Sent []string // Sent message MIDs. }
TrafficStats holds exchange message traffic statistics.
type UserAgent ¶
Struct used to hold information that is reported during B2F handshake.
Non of the fields must contain a dash (-).
type ValidationError ¶
type ValidationError struct { Field string // The field/part of the message that is not valid Err string // Description of the error }
ValidationError is the error type returned by functions validating a message.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
type WordDecoder ¶
type WordDecoder struct{ mime.WordDecoder }
WordDecoder decodes MIME headers containing RFC 2047 encoded-words.
(See DecodeHeader for mime.WordDecoder differences).
func (*WordDecoder) DecodeHeader ¶
func (d *WordDecoder) DecodeHeader(header string) (string, error)
Decode decodes an encoded-word.
If word is not a valid RFC 2047 encoded-word, word is decoded as raw ISO-8859-1 as a work-around for RMS Express' non-conforming encoding of the Subject header.