incident

package
v4.0.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: BSD-3-Clause Imports: 35 Imported by: 0

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

View Source
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

View Source
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

func CompareLogEntries(a, b *LogEntry) int

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

func Create(dir string, fn func(*Incident) error) (err error)

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

func ICS309FormDef() *formdef.FormDef

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

func IsIncident(dir string) bool

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

func IsUnsafeIncidentDir(dir string) bool

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

func Read(dir string, fn func(*Incident) error) (err error)

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 ToPDF

func ToPDF(txt string) string

ToPDF converts a .txt filename into a .pdf filename.

func Watch

func Watch(ctx context.Context, dir string, seq int, stop <-chan struct{}) (err error)

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

func Write(dir string, fn func(*Incident) error) (err error)

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 CheckFrequency struct {
	time.Duration `json:"d,format:sec"`
}

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

func (c *Config) ActiveCall() string

ActiveCall returns the active call sign in the configuration.

func (*Config) ActiveName

func (c *Config) ActiveName() string

ActiveName returns the active station name in the configuration.

func (*Config) Clone

func (c *Config) Clone() (n *Config)

Clone creates a clone of the configuration.

func (*Config) FromAddress

func (c *Config) FromAddress() string

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

func (i *Incident) AddLogEntry(le *LogEntry)

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

func (inc *Incident) BulletinAreaChecked(area string, at time.Time)

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

func (inc *Incident) BulletinAreasToCheck() (areas []string)

BulletinAreasToCheck returns the list of bulletin areas that are overdue to be checked for new bulletins.

func (*Incident) DeleteLogEntry

func (i *Incident) DeleteLogEntry(le *LogEntry) (err error)

DeleteLogEntry removes a hand-entered log entry.

func (*Incident) DeleteMessage

func (i *Incident) DeleteMessage(le *LogEntry) (err error)

DeleteMessage deletes an unsent message from the incident.

func (*Incident) GenerateICS309

func (i *Incident) GenerateICS309(signature string) (err error)

GenerateICS309 creates ics309.pdf in the incident directory.

func (*Incident) GetLogEntryByIdent

func (i *Incident) GetLogEntryByIdent(ident int) *LogEntry

GetLogEntryByIdent returns the log entry with the specified ident, if any.

func (*Incident) GetMessageByLMI

func (i *Incident) GetMessageByLMI(lmi string) (msg message.Message, err error)

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

func (i *Incident) GetMessageFromLogEntry(entry *LogEntry) (msg message.Message, err error)

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

func (i *Incident) ResendMessageID(sentID string) (resendID string, err error)

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

func (i *Incident) ResetLogEntry(le *LogEntry) (err error)

ResetLogEntry resets the data in a log entry to match the contents of a message.

func (*Incident) UpdateConfig

func (inc *Incident) UpdateConfig(c *Config)

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

func (i *Incident) UpdateLogEntry(le *LogEntry)

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.

func (*LogEntry) Filename

func (e *LogEntry) Filename() string

Filename returns the filename of the message associated with the log entry, if any.

func (*LogEntry) Linkname

func (e *LogEntry) Linkname() string

Linkname returns the name of the symbolic link to be created for the log entry, if any.

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

func ParseViewFlags

func ParseViewFlags(s string) (f ViewFlag, err error)

func (ViewFlag) MarshalJSONTo

func (f ViewFlag) MarshalJSONTo(enc *jsontext.Encoder) (err error)

func (ViewFlag) String

func (f ViewFlag) String() string

func (*ViewFlag) UnmarshalJSONFrom

func (f *ViewFlag) UnmarshalJSONFrom(dec *jsontext.Decoder) (err error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL