Documentation
¶
Overview ¶
Package incident handles collections of messages stored in the same directory. Semantically, these are messages that belong to the same incident, i.e., that are recorded on the same ICS-309 form.
Incidents are identified by the full absolute path of their directory. At a high level, there are only three operations one can perform: Read, Write, and Watch. These are the three exported functions in this package.
Index ¶
- Constants
- Variables
- func BBSExchange(ctx context.Context, dir string, immOnly bool, updates BBSExchangeWatcher)
- func CompareLogEntries(a, b *LogEntry) int
- func Create(dir string, fn func(*Incident) error) (err error)
- func ICS309FormDef() *formdef.FormDef
- func IsIncident(dir string) bool
- func IsUnsafeIncidentDir(dir string) bool
- func Read(dir string, fn func(*Incident) error) (err error)
- func ToPDF(txt string) string
- func Watch(ctx context.Context, dir string, seq int, stop <-chan struct{}) (err error)
- func Write(dir string, fn func(*Incident) error) (err error)
- type BBSExchangeWatcher
- type CheckFrequency
- type Config
- type IncDefaults
- type Incident
- func (i *Incident) AddDraftMessage(msg *message.DraftMessage) (le *LogEntry, err error)
- func (i *Incident) AddLogEntry(le *LogEntry)
- func (i *Incident) ApplyDefaults(dm *message.DraftMessage)
- func (inc *Incident) BulletinAreaChecked(area string, at time.Time)
- func (inc *Incident) BulletinAreasToCheck() (areas []string)
- func (i *Incident) DeleteLogEntry(le *LogEntry) (err error)
- func (i *Incident) DeleteMessage(le *LogEntry) (err error)
- func (i *Incident) GenerateICS309(signature string) (err error)
- func (i *Incident) GetLogEntryByIdent(ident int) *LogEntry
- func (i *Incident) GetMessageByLMI(lmi string) (msg message.Message, err error)
- func (i *Incident) GetMessageFromLogEntry(entry *LogEntry) (msg message.Message, err error)
- func (i *Incident) MakeDeliveryReceipt(msg message.Message, le *LogEntry) (dr *message.DraftMessage, err error)
- func (i *Incident) MarkMessageSent(dm *message.DraftMessage, le *LogEntry) (err error)
- func (i *Incident) ReceiveMessage(msg *message.JustReceivedMessage) (dr *message.DraftMessage, le *LogEntry, err error)
- func (i *Incident) ResendMessageID(sentID string) (resendID string, err error)
- func (i *Incident) ResetLogEntry(le *LogEntry) (err error)
- func (inc *Incident) UpdateConfig(c *Config)
- func (i *Incident) UpdateDraftMessage(ident int, msg *message.DraftMessage) (err error)
- func (inc *Incident) UpdateIncDefaults()
- func (i *Incident) UpdateLogEntry(le *LogEntry)
- type LogEntry
- type LogEntryFlags
- type LogEntryStatus
- type ViewFlag
Constants ¶
const ( // ConnectNone means there is no connection to the BBS. ConnectNone = "" // ConnectSerialTNC is connection to a BBS over the air using a serial // connection to a TNC. ConnectSerialTNC = "serial-tnc" // ConnectTelnet is connection to a BBS over the Internet using the // Telnet protocol. ConnectTelnet = "telnet" )
Methods for connecting to a BBS (i.e., values for Config.ConnectType).
Variables ¶
var (
ErrNotIncident = errors.New("not a valid incident directory")
)
Functions ¶
func BBSExchange ¶
func BBSExchange(ctx context.Context, dir string, immOnly bool, updates BBSExchangeWatcher)
BBSExchange connects to a BBS and exchanges messages with it for the incident in the named directory (which should not be locked when the call is issued). The connection will be aborted if the supplied context is canceled. If immOnly is true, only IMMEDIATE messages are transferred (and no bulletin checks are performed). Progress updates and results are sent to the supplied watcher. BBSExchange blocks, and should be run in a goroutine.
func CompareLogEntries ¶
CompareLogEntries is a comparison function for slices.SortFunc and similar, that puts log entries in order by timestamp and within that by index.
func Create ¶
Create creates a new incident in the named directory, which must not already be an incident directory. It calls the supplied function while holding the write lock on the new incident. If the supplied function returns nil, the new incident is saved; otherwise, no change is made to the named directory and the error is returned.
func ICS309FormDef ¶
ICS309FormDef returns the form definition for the ICS-309 form. This is used by other code to determine edit widths for the ICS-309 fields.
func IsIncident ¶
IsIncident returns whether the named directory is an incident directory. (This is mostly used when presenting the user with a list of past incidents, to weed out past incident directories that no longer exist or no longer contain incident data.)
func IsUnsafeIncidentDir ¶
IsUnsafeIncidentDir returns whether the named directory is unsafe for use as an incident directory. Unsafe directories are the root directory of any volume, the user's home directory, the Desktop or Documents subdirectory of the user's home directory, or (on Windows) C:\PackItForms. These are considered unsafe because they are semantically too global to keep a single incident in.
func Read ¶
Read opens the incident in the named directory for read-only operations and invokes the supplied function while holding the read lock. Read returns any error it encounters or any error returned by the supplied function.
func Watch ¶
Watch monitors the incident in the named directory for changes. It returns nil when a change is observed or the stop channel (if any) is closed, and a context error when the supplied context is canceled. If seq is less than the current sequence number of the incident, Watch returns nil immediately.
func Write ¶
Write opens the incident in the named directory for write operations and invokes the supplied function while holding the write lock. If Write encounters any error, it will return it. If the supplied function returns nil, any changes it made to the Incident will be applied. If it returns an error, no changes will be applied and Write will return the error.
Types ¶
type BBSExchangeWatcher ¶
type BBSExchangeWatcher interface {
// Progress is called with messages indicating the progress of the BBS
// exchange.
Progress(string)
// LogEntry is called with the log entry for a received or transmitted
// message.
LogEntry(*LogEntry)
// Error is called if an error occurs during the BBS exchange.
Error(string)
// Finished is called when the BBS exchange has finished, whether or not
// it was successful. (It was successful if Error was never called.)
Finished()
}
BBSExchangeWatcher is the interface required for the "updates" parameter to BBSExchange; it is an object to which progress of the BBS exchange is reported.
type CheckFrequency ¶
type Config ¶
type Config struct {
// IncidentName is the name of the incident on the ICS-309 log.
IncidentName string `json:"incName,omitempty"`
// ActivationNum is the activation number of the incident on the
// ICS-309 log.
ActivationNum string `json:"actNum,omitempty"`
// OpStart is the start time of the operational period on the ICS-309
// log.
OpStart time.Time `json:"opStart,omitzero,format:'2006-01-02T15:04'"`
// OpEnd is the end time of the operational period on the ICS-309 log.
OpEnd time.Time `json:"opEnd,omitzero,format:'2006-01-02T15:04'"`
// OpCall is the FCC call sign of the operator.
OpCall string `json:"opCall,omitempty"`
// OpName is the name of the operator.
OpName string `json:"opName,omitempty"`
// TacCall is the tactical call sign of the local station, if any.
TacCall string `json:"tacCall,omitempty"`
// TacName is the name of the local station, if any.
TacName string `json:"tacName,omitempty"`
// TxMessageID is the start of the message number sequence for outgoing
// messages.
TxMessageID string `json:"txMsgID,omitempty"`
// RxMessageID is the start of the message number sequence for incoming
// messages.
RxMessageID string `json:"rxMsgID,omitempty"`
// DefaultTo is the default To: destination for outgoing messages.
DefaultTo string `json:"defTo,omitempty"`
// DefaultToPos is the default value for the To ICS Position field for
// outgoing forms messages.
DefaultToPos string `json:"defToPos,omitempty"`
// DefaultToLoc is the default value for the To Location field for
// outgoing forms messages.
DefaultToLoc string `json:"defToLoc,omitempty"`
// DefaultFromPos is the default value for the From ICS Position field
// for outgoing forms messages.
DefaultFromPos string `json:"defFromPos,omitempty"`
// DefaultFromLoc is the default value for the From Location field for
// outgoing forms messages.
DefaultFromLoc string `json:"defFromLoc,omitempty"`
// DefaultBody is default contents for the primary body field of
// outgoing messages (often used for "**** This is drill traffic ****").
DefaultBody string `json:"defBody,omitempty"`
// ConnectType is the method to use to connect to the BBS. Options are
// ConnectNone, ConnectSerialTNC, or ConnectTelnet.
ConnectType string `json:"connType,omitempty"`
// ConnectBBS is the name of the BBS that we are connecting to.
ConnectBBS string `json:"connBBS,omitempty"`
// ConnectAddress is the address of the BBS that we're connecting to.
// If ConnectType is ConnectSerialTNC, this should be an AX.25 address
// (e.g., "W5XSC-1"). If ConnectType is ConnectTelnet, this should be
// a hostname:port or ipaddr:port string.
ConnectAddress string `json:"connAddr,omitempty"`
// SerialPort is the pathname of the serial port to use to communicate
// with the TNC (e.g., "COM3" on Windows or "/dev/tty.something" on
// Mac or Linux). It is relevant only when ConnectType is
// ConnectSerialTNC.
SerialPort string `json:"serialPort,omitempty"`
// TNCType is the type of TNC in use. Relevant only when ConnectType is
// ConnectSerialTNC.
TNCType string `json:"tncType,omitempty"`
// TelnetUser is the username to use to log in to the BBS. Relevant
// only when ConnectType is ConnectTelnet.
TelnetUser string `json:"telnetUser,omitempty"`
// TelnetPassword is the username to use to log in to the BBS.
// Relevant only when ConnectType is ConnectTelnet.
TelnetPassword string `json:"telnetPwd,omitempty"`
// BulletinChecks is the set of bulletin areas that should be checked,
// and the check frequency for each.
BulletinChecks map[string]CheckFrequency `json:"bulletinChecks,omitempty"`
// NoSendReceipts is a flag indicating that delivery receipts should
// not be automatically generated and sent for received messages.
NoSendReceipts bool `json:"noSendReceipts,omitempty"`
// ViewFlags is a bitmask of flags describing how the incident log is
// displayed.
ViewFlags ViewFlag `json:"viewFlags,omitempty"`
// AlLowVoice is a flag indicating that log entries can be marked as
// voice messages to be put on a separate ICS-309.
AllowVoice bool `json:"allowVoice,omitempty"`
}
A Config represents the configuration of an incident, i.e., all of the data and behavior that are not message-specific.
func (*Config) ActiveCall ¶
ActiveCall returns the active call sign in the configuration.
func (*Config) ActiveName ¶
ActiveName returns the active station name in the configuration.
func (*Config) FromAddress ¶
FromAddress returns the From address for messages sent using the config.
type IncDefaults ¶
type IncDefaults struct {
// OpCall is the FCC call sign of the operator.
OpCall string `json:"opCall,omitempty"`
// OpName is the name of the operator.
OpName string `json:"opName,omitempty"`
// ConnectType is the method to use to connect to the BBS. Options are
// ConnectNone, ConnectSerialTNC, or ConnectTelnet.
ConnectType string `json:"connType,omitempty"`
// ConnectBBS is the name of the BBS that we are connecting to.
ConnectBBS string `json:"connBBS,omitempty"`
// ConnectAddress is the address of the BBS that we're connecting to.
// If ConnectType is ConnectSerialTNC, this should be an AX.25 address
// (e.g., "W5XSC-1"). If ConnectType is ConnectTelnet, this should be
// a hostname:port or ipaddr:port string.
ConnectAddress string `json:"connAddr,omitempty"`
// SerialPort is the pathname of the serial port to use to communicate
// with the TNC (e.g., "COM3" on Windows or "/dev/tty.something" on
// Mac or Linux). It is relevant only when ConnectType is
// ConnectSerialTNC.
SerialPort string `json:"serialPort,omitempty"`
// TNCType is the type of TNC in use. Currently the only supported
// value is TNCKPC3Plus. Relevant only when ConnectType is
// ConnectSerialTNC.
TNCType string `json:"tncType,omitempty"`
// TCPAddresses is a map from ConnectBBS to ConnectAddress for Telnet
// connections.
TCPAddresses map[string]string `json:"tcpAddrs,omitempty"`
// TelnetPasswords is a map from TelnetUser to TelnetPassword.
TelnetPasswords map[string]string `json:"telnetPwds,omitempty"`
// IncidentDirs is a list of recent incident directories, used to make
// it easy for the user to return to them.
IncidentDirs []string `json:"incidentDirs,omitempty"`
// ViewFlags is a bitmask of flags describing how the incident log is
// displayed.
ViewFlags ViewFlag `json:"viewFlags,omitempty"`
}
The IncDefaults structure contains default values for some incident config settings: those that tend to be the same for all incidents. Most fields are updated whenever an incident is configured, and contain the most recently used value of that field. TelnetPasswords is cumulative, retaining the most recently used password for any BBS and user. IncidentDirs is cumulative with a limit.
func GetIncDefaults ¶
func GetIncDefaults() (idef *IncDefaults)
GetIncDefaults retrieves the current incident defaults. It returns a valid structure even if there are errors or no saved defaults.
type Incident ¶
type Incident struct {
// Dir is the absolute path to the directory for the incident.
Dir string `json:"-"`
// Seq is the sequence number, incremented with every change to the
// incident.
Seq int `json:"seq"`
// Config is the configuration of the incident, i.e., the details that
// (usually) don't change over time.
Config *Config `json:"conf"`
// BulletinChecks is a map from bulletin area name to the time at which
// it was last checked.
BulletinChecks map[string]time.Time `json:"bull"`
// Log is an ordered list of log messages for the incident. The first
// element is always nil so that the slice index equals the item Index.
Log []*LogEntry `json:"log"`
}
An Incident is a collection of related messages stored in the same directory.
func (*Incident) AddDraftMessage ¶
func (i *Incident) AddDraftMessage(msg *message.DraftMessage) (le *LogEntry, err error)
AddDraftMessage takes a DraftMessage and saves it in the incident, assigning it a local message ID along the way unless the message already has one. The function returns the ident of the corresponding new log entry.
func (*Incident) AddLogEntry ¶
AddLogEntry adds a (manual) log entry to the incident.
func (*Incident) ApplyDefaults ¶
func (i *Incident) ApplyDefaults(dm *message.DraftMessage)
ApplyDefaults applies the default field values from the incident configuration to the supplied draft message, overriding any values already contained in those fields.
func (*Incident) BulletinAreaChecked ¶
BullletinAreaChecked marks the named bulletin area as having been checked at the specified time (usually now, but sometimes time.Time{} in order to force a check).
func (*Incident) BulletinAreasToCheck ¶
BulletinAreasToCheck returns the list of bulletin areas that are overdue to be checked for new bulletins.
func (*Incident) DeleteLogEntry ¶
DeleteLogEntry removes a hand-entered log entry.
func (*Incident) DeleteMessage ¶
DeleteMessage deletes an unsent message from the incident.
func (*Incident) GenerateICS309 ¶
GenerateICS309 creates ics309.pdf in the incident directory.
func (*Incident) GetLogEntryByIdent ¶
GetLogEntryByIdent returns the log entry with the specified ident, if any.
func (*Incident) GetMessageByLMI ¶
GetMessageByLMI returns the message with the specified local message ID, if any. If the returned message is non-nil, the returned error is non-fatal.
func (*Incident) GetMessageFromLogEntry ¶
GetMessageFromLogEntry returns the message described by the provided log entry, if any. If the returned message is non-nil, any returned error is non-fatal.
func (*Incident) MakeDeliveryReceipt ¶
func (i *Incident) MakeDeliveryReceipt(msg message.Message, le *LogEntry) (dr *message.DraftMessage, err error)
MakeDeliveryReceipt makes a delivery receipt for the supplied received message.
func (*Incident) MarkMessageSent ¶
func (i *Incident) MarkMessageSent(dm *message.DraftMessage, le *LogEntry) (err error)
MarkMessageSent marks a draft message as having been sent. The parameters are the message and its log entry.
func (*Incident) ReceiveMessage ¶
func (i *Incident) ReceiveMessage(msg *message.JustReceivedMessage) (dr *message.DraftMessage, le *LogEntry, err error)
ReceiveMessage takes a JustReceivedMessage received from JNOS and saves it in the incident. ReceiveMessage returns the delivery receipt that should be sent for the message, if any; it is up to the caller to queue the delivery receipt for sending. It also returns the log entry for the received message.
func (*Incident) ResendMessageID ¶
ResendMessageID sets the local message ID of the supplied draft message to the local message ID of the supplied sent message, with the suffix changed to 'R'.
func (*Incident) ResetLogEntry ¶
ResetLogEntry resets the data in a log entry to match the contents of a message.
func (*Incident) UpdateConfig ¶
UpdateConfig applies a new configuration to the incident, logging the changes made.
func (*Incident) UpdateDraftMessage ¶
func (i *Incident) UpdateDraftMessage(ident int, msg *message.DraftMessage) (err error)
UpdateDraftMessage saves changes to an existing DraftMessage in the incident.
func (*Incident) UpdateIncDefaults ¶
func (inc *Incident) UpdateIncDefaults()
UpdateIncDefaults updates the incident defaults based on the configuration of the receiver incident. Errors are logged and ignored.
func (*Incident) UpdateLogEntry ¶
UpdateLogEntry records updates to a log entry.
type LogEntry ¶
type LogEntry struct {
// Ident is a unique identifier of the log entry within the incident.
// It is immutable.
Ident int `json:"id"`
// Index identifies the location of the log entry in the sorted list of
// log entries. It can change whenever the list is sorted. The
// LogEntry with index N is always available at incident.Log[N].
Index int `json:"idx"`
// Seq is the sequence number of the incident at the time this log
// entry was last changed (either in content or in placement).
Seq int `json:"seq"`
// Status is the status of the log entry.
Status LogEntryStatus `json:"st"`
// Flags is a bitmask of flags associated with the log entry.
Flags LogEntryFlags `json:"f"`
// Time is the timestamp of the log entry.
Time time.Time `json:"t"`
// FromCall is the call sign of the station that sent the message. It
// will be empty for an outgoing message. It will be the bulletin area
// name for a received bulletin. It may be hand-edited.
FromCall string `json:"fc,omitempty"`
// FromMsgID is the message ID assigned to the message by the sending
// station. It may be hand-edited.
FromMsgID string `json:"fi,omitempty"`
// LocalMsgID is the message ID assigned to the message by the local
// station (us). For receipt messages, it is the local message ID of
// the message being receipted.
LocalMsgID string `json:"li,omitempty"`
// ToCall is the call sign of a station to which the message was sent.
// It will be empty for a received message. It may be hand-edited.
ToCall string `json:"tc,omitempty"`
// ToMsgID is the message ID assigned to the message by the receiving
// station identified in ToCall (or by us, for a received message). It
// may be hand-edited.
ToMsgID string `json:"ti,omitempty"`
// Subject is the message subject line, or log entry description. It
// may be hand-edited.
Subject string `json:"s,omitempty"`
}
A LogEntry represents a single line in the ICS-309 log for the incident. There is one LogEntry for each received or draft message. For sent messages, there is one LogEntry per recipient. There can also be LogEntries unrelated to a packet message.
type LogEntryFlags ¶
type LogEntryFlags uint
LogEntryFlags is a bitmask of flags associated with a log entry.
const ( // FBulletin is set when the log entry is for a bulletin message. FBulletin LogEntryFlags = 1 << iota // FFollowup is set when the log entry needs followup. FFollowup // FHasReceipt is set when a receipt has been received for the message // and recipient identified in the log entry. FHasReceipt // FImmediate is set when the log entry is for a message with immediate // handling order. FImmediate // FIsReceipt is set when the log entry is for a receipt message. FIsReceipt // FNeedsReceipt is set when a receipt is expected, and has not yet // been received, for the message and recipient identified in the log // entry. FNeedsReceipt // FPriority is set when the log entry is for a message with priority // handling order. FPriority // FUnread is set on received messages (other than receipts) that // haven't been read. FUnread // FVoice is set when the (hand-entered) log entry is for a voice // message. FVoice )
Values for LogEntryFlags.
func (LogEntryFlags) MarshalJSONTo ¶
func (f LogEntryFlags) MarshalJSONTo(enc *jsontext.Encoder) (err error)
func (*LogEntryFlags) UnmarshalJSONFrom ¶
func (f *LogEntryFlags) UnmarshalJSONFrom(dec *jsontext.Decoder) (err error)
type LogEntryStatus ¶
type LogEntryStatus string
LogEntryStatus is the status of a log entry, stored in LogEntry.Status.
const ( // StatusDraft is a log message for an outgoing message not yet ready // to send. StatusDraft LogEntryStatus = "D" // StatusHandEntered is a log entry not associated with a message. StatusHandEntered LogEntryStatus = "H" // StatusQueued is a log entry for an outgoing message ready to send // but not yet sent. StatusQueued LogEntryStatus = "Q" // StatusReceived is a log entry for a received message. StatusReceived LogEntryStatus = "R" // StatusSent is a log entry for a sent message. StatusSent LogEntryStatus = "S" // StatusDeleted is a log entry that has been deleted. StatusDeleted LogEntryStatus = "X" )
Values for LogEntryStatus.
type ViewFlag ¶
type ViewFlag uint8
A ViewFlag is a flag (or bitmask of flags) describing how the incident log is displayed.
const ( // ViewFull is a flag indicating that the incident log view should be in // full (vs. compact) format. ViewFull ViewFlag = 1 << iota // ViewReceipts is a flag indicating that the incident log view should // include receipt messages. ViewReceipts // ViewLarge is a flag indicating that the incident log view should use // a large font. ViewLarge )
Values for ViewFlag