hotline

package module
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2021 License: MIT Imports: 26 Imported by: 0

README

Moebius

Cross-platform command line Hotline server and client

CircleCI

Getting Started

Features

  • Hotline 1.2.3

Usage

Precompiled binaries

To get started quickly, download the precompiled binaries for your platform:

Compatibility

The server has been tested with:

  • Hotline Client version 1.2.3
  • Hotline Client version 1.8.2
  • Hotline Client version 1.9.2
  • Nostalgia
Docker
docker run --mount type=bind,source=$HOME/hotline-root/config/,destination=/app/server/config/ -p 5500-5502:5500-5502 -it go-hotline:latest /app/server/server --config /app/server/config/
Build from source
make build

TODO

  • Implement 1.5+ protocol account editing
  • Implement folder transfer resume
  • Implement file transfer queuing
  • Map additional file extensions to file type and creator codes
  • Implement file comment read/write
  • Implement user banning
  • Implement Maximum Simultaneous Downloads
  • Maximum simultaneous downloads/client
  • Maximum simultaneous connections/IP
  • Implement server broadcast
  • Implement statistics:
    • Currently Connected
    • Downloads in progress
    • Uploads in progress
    • Waiting Downloads
    • Connection Peak
    • Connection Counter
    • Download Counter
    • Upload Counter
    • Since

TODO - Someday Maybe

  • Implement Pitbull protocol extensions

Documentation

Index

Constants

View Source
const (
	FileDownload   = 0
	FileUpload     = 1
	FolderDownload = 2
	FolderUpload   = 3
)

File transfer types

View Source
const GuestAccount = "guest" // default account used when no login is provided for a connection
View Source
const Version = "0.0.1"

Variables

View Source
var ChatBox *tview.TextView
View Source
var ClientHandshake = []byte{
	0x54, 0x52, 0x54, 0x50,
	0x48, 0x4f, 0x54, 0x4c,
	0x00, 0x01,
	0x00, 0x02,
}
View Source
var ServerHandshake = []byte{
	0x54, 0x52, 0x54, 0x50,
	0x00, 0x00, 0x00, 0x00,
}
View Source
var TransactionHandlers = map[uint16]TransactionType{
	// contains filtered or unexported fields
}

Functions

func CalcItemCount

func CalcItemCount(filePath string) ([]byte, error)

func CalcTotalSize

func CalcTotalSize(filePath string) ([]byte, error)

func DecodeUserString

func DecodeUserString(encodedString []byte) (decodedString string)

func EncodeFilePath

func EncodeFilePath(filePath string) []byte

func InitConfig added in v0.0.4

func InitConfig(path *string) error

InitConfig creates a config directory populated with default configuration

func NegatedUserString

func NegatedUserString(encodedString []byte) string

Take a []byte of uncoded ascii as input and encode it

func NewFlattenedFileObject

func NewFlattenedFileObject(filePath string, fileName string) (flattenedFileObject, error)

func NewsDate

func NewsDate() []byte

News article date field contains this structure: Year 2 Milliseconds 2 (seriously?) Seconds 4

func ReadFilePath

func ReadFilePath(filePathFieldData []byte) string

func ReadFlattenedFileObject

func ReadFlattenedFileObject(bytes []byte) flattenedFileObject

ReadFlattenedFileObject parses a byte slice into a flattenedFileObject

func ReadNewsPath

func ReadNewsPath(newsPath []byte) []string

Types

type Account

type Account struct {
	Login    string  `yaml:"Login"`
	Name     string  `yaml:"Name"`
	Password string  `yaml:"Password"`
	Access   *[]byte `yaml:"Access"` // 8 byte bitmap
}

func (*Account) Payload

func (a *Account) Payload() []byte

Payload marshals an account to byte slice Example:

00 04 // fieldCount?
00 66 // 102 - fieldUserName
00 0d // 13
61 64 6d 69 6e 69 73 74 72 61 74 6f 72 // administrator
00 69 // 105 fieldUserLogin (encoded)
00 05 // len
9e 9b 92 96 91 // encoded login name
00 6a // 106 fieldUserPassword
00 01  // len
78
00 6e  // fieldUserAccess
00 08
ff d3 cf ef ff 80 00 00

type Client

type Client struct {
	Connection net.Conn
	UserName   []byte
	Login      *[]byte
	Password   *[]byte
	Icon       *[]byte
	Flags      *[]byte
	ID         *[]byte
	Version    []byte
	UserAccess []byte
	Agreed     bool
	UserList   []User
	Logger     *zap.SugaredLogger

	UI *UI
	// contains filtered or unexported fields
}

func NewClient

func NewClient(username string, logger *zap.SugaredLogger) *Client

func (*Client) Connected

func (c *Client) Connected() bool

func (*Client) HandleTransaction

func (c *Client) HandleTransaction(t *Transaction) error

func (*Client) Handshake

func (c *Client) Handshake() error

func (*Client) JoinServer

func (c *Client) JoinServer(address, login, passwd string) error

JoinServer connects to a Hotline server and completes the login flow

func (*Client) LogIn

func (c *Client) LogIn(login string, password string) error

func (*Client) ReadLoop

func (c *Client) ReadLoop() error

func (*Client) Send

func (c *Client) Send(t Transaction) error

type ClientConn

type ClientConn struct {
	Connection net.Conn
	ID         *[]byte
	Icon       *[]byte
	Flags      *[]byte
	UserName   *[]byte
	Account    *Account
	IdleTime   *int
	Server     *Server
	Version    *[]byte
	Idle       bool
	AutoReply  *[]byte
	Transfers  map[int][]*FileTransfer
}

ClientConn represents a client connected to a Server

func (*ClientConn) Authenticate

func (cc *ClientConn) Authenticate(login string, password []byte) bool

func (*ClientConn) Authorize

func (cc *ClientConn) Authorize(access int) bool

Authorize checks if the user account has the specified permission

func (ClientConn) Disconnect

func (cc ClientConn) Disconnect()

Disconnect notifies other clients that a client has disconnected

func (*ClientConn) Handshake

func (cc *ClientConn) Handshake(buf []byte) error

Handshake After establishing TCP connection, both client and server start the handshake process in order to confirm that each of them comply with requirements of the other. The information provided in this initial data exchange identifies protocols, and their versions, used in the communication. In the case where, after inspection, the capabilities of one of the subjects do not comply with the requirements of the other, the connection is dropped.

The following information is sent to the server: Description Size Data Note Protocol ID 4 TRTP 0x54525450 Sub-protocol ID 4 HOTL User defined Version 2 1 Currently 1 Sub-version 2 2 User defined

The server replies with the following: Description Size Data Note Protocol ID 4 TRTP Error code 4 Error code returned by the server (0 = no error)

func (*ClientConn) NewErrReply

func (cc *ClientConn) NewErrReply(t *Transaction, errMsg string) Transaction

NewErrReply returns an error reply Transaction with errMsg

func (*ClientConn) NewReply

func (cc *ClientConn) NewReply(t *Transaction, fields ...Field) Transaction

NewReply returns a reply Transaction with fields for the ClientConn

func (ClientConn) NotifyOthers

func (cc ClientConn) NotifyOthers(t Transaction)

NotifyOthers sends transaction t to other clients connected to the server

type Config

type Config struct {
	Name                      string   `yaml:"Name"`                      // Name used for Tracker registration
	Description               string   `yaml:"Description"`               // Description used for Tracker registration
	BannerID                  int      `yaml:"BannerID"`                  // Unimplemented
	FileRoot                  string   `yaml:"FileRoot"`                  // Path to Files
	EnableTrackerRegistration bool     `yaml:"EnableTrackerRegistration"` // Toggle Tracker Registration
	Trackers                  []string `yaml:"Trackers"`                  // List of trackers that the server should register with
	NewsDelimiter             string   `yaml:"NewsDelimiter"`             // String used to separate news posts
	NewsDateFormat            string   `yaml:"NewsDateFormat"`            // Go template string to customize news date format
	MaxDownloads              int      `yaml:"MaxDownloads"`              // Global simultaneous download limit
	MaxDownloadsPerClient     int      `yaml:"MaxDownloadsPerClient"`     // Per client simultaneous download limit
	MaxConnectionsPerIP       int      `yaml:"MaxConnectionsPerIP"`       // Max connections per IP
}

func NewConfig added in v0.0.2

func NewConfig() *Config

NewConfig sets default config values and is only used during initialization of a new server config directory

type Field

type Field struct {
	ID        []byte // Type of field
	FieldSize []byte // Size of the data part
	Data      []byte // Actual field content
}

func NewField

func NewField(id uint16, data []byte) Field

func ReadFields

func ReadFields(paramCount []byte, buf []byte) ([]Field, error)

func (Field) Payload

func (f Field) Payload() []byte

func (Field) Size

func (f Field) Size() []byte

Size of the data part: maxlen 2

type FileHeader

type FileHeader struct {
	Size     []byte // Total size of FileHeader payload
	Type     []byte // 0 for file, 1 for dir
	FilePath []byte // encoded file path
}

func NewFileHeader

func NewFileHeader(fileName string, isDir bool) FileHeader

func (*FileHeader) Payload

func (fh *FileHeader) Payload() []byte

type FileNameWithInfo

type FileNameWithInfo struct {
	Type       string // file type code
	Creator    []byte // File creator code
	FileSize   uint32 // File Size in bytes
	NameScript []byte // TODO: What is this?
	NameSize   []byte // Length of name field
	Name       string // File name
}

func (FileNameWithInfo) Payload

func (f FileNameWithInfo) Payload() []byte

type FilePath

type FilePath struct {
	PathItemCount []byte
	PathItems     []FilePathItem
}

func NewFilePath

func NewFilePath(b []byte) FilePath

func (*FilePath) String

func (fp *FilePath) String() string

type FilePathItem

type FilePathItem struct {
	Len  byte
	Name []byte
}

FilePathItem represents the file or directory portion of a delimited file path (e.g. foo and bar in "/foo/bar") 00 00 09 73 75 62 66 6f 6c 64 65 72 // "subfolder"

func NewFilePathItem

func NewFilePathItem(b []byte) FilePathItem

type FileTransfer

type FileTransfer struct {
	FileName        []byte
	FilePath        []byte
	ReferenceNumber []byte
	Type            int
	TransferSize    []byte // total size of all items in the folder. Only used in FolderUpload action
	FolderItemCount []byte
	BytesSent       int
	// contains filtered or unexported fields
}

func (*FileTransfer) String

func (ft *FileTransfer) String() string

type FlatFileDataForkHeader

type FlatFileDataForkHeader struct {
	ForkType        []byte
	CompressionType []byte
	RSVD            []byte
	DataSize        []byte
}

func NewFlatFileDataForkHeader

func NewFlatFileDataForkHeader() FlatFileDataForkHeader

type FlatFileHeader

type FlatFileHeader struct {
	Format    []byte // Always "FILP"
	Version   []byte // Always 1
	RSVD      []byte // Always empty zeros
	ForkCount []byte // Always 2
}

FlatFileHeader is the first section of a "Flattened File Object". All fields have static values.

func NewFlatFileHeader

func NewFlatFileHeader() FlatFileHeader

NewFlatFileHeader returns a FlatFileHeader struct

type FlatFileInformationFork

type FlatFileInformationFork struct {
	Platform         []byte // Operating System used. ("AMAC" or "MWIN")
	TypeSignature    []byte // File type signature
	CreatorSignature []byte // File creator signature
	Flags            []byte
	PlatformFlags    []byte
	RSVD             []byte
	CreateDate       []byte
	ModifyDate       []byte
	NameScript       []byte // TODO: what is this?
	NameSize         []byte // Length of file name (Maximum 128 characters)
	Name             []byte // File name
	CommentSize      []byte // Length of file comment
	Comment          []byte // File comment
}

func NewFlatFileInformationFork

func NewFlatFileInformationFork(fileName string) FlatFileInformationFork

func (FlatFileInformationFork) DataSize

func (ffif FlatFileInformationFork) DataSize() []byte

Size of the flat file information fork, which is the fixed size of 72 bytes plus the number of bytes in the FileName TODO: plus the size of the Comment!

func (FlatFileInformationFork) ReadNameSize

func (ffif FlatFileInformationFork) ReadNameSize() []byte

type FlatFileInformationForkHeader

type FlatFileInformationForkHeader struct {
	ForkType        []byte // Always "INFO"
	CompressionType []byte // Always 0; Compression was never implemented in the Hotline protocol
	RSVD            []byte // Always zeros
	DataSize        []byte // Size of the flat file information fork
}

FlatFileInformationForkHeader is the second section of a "Flattened File Object"

type NewsArtData

type NewsArtData struct {
	Title         string `yaml:"Title"`
	Poster        string `yaml:"Poster"`
	Date          []byte `yaml:"Date"`             //size 8
	PrevArt       []byte `yaml:"PrevArt"`          //size 4
	NextArt       []byte `yaml:"NextArt"`          //size 4
	ParentArt     []byte `yaml:"ParentArt"`        //size 4
	FirstChildArt []byte `yaml:"FirstChildArtArt"` //size 4
	DataFlav      []byte `yaml:"DataFlav"`         // "text/plain"
	Data          string `yaml:"Data"`
}

NewsArtData repsents a single news article

func (*NewsArtData) DataSize

func (art *NewsArtData) DataSize() []byte

type NewsArtList

type NewsArtList struct {
	ID          []byte // Size 4
	TimeStamp   []byte // Year (2 bytes), milliseconds (2 bytes) and seconds (4 bytes)
	ParentID    []byte // Size 4
	Flags       []byte // Size 4
	FlavorCount []byte // Size 2
	// Title size	1
	Title []byte // string
	// Poster size	1
	// Poster	Poster string
	Poster     []byte
	FlavorList []NewsFlavorList
	// Flavor list…			Optional (if flavor count > 0)
	ArticleSize []byte // Size 2
}

NewsArtList is a summarized ver sion of a NewArtData record for display in list view

func (*NewsArtList) Payload

func (nal *NewsArtList) Payload() []byte

type NewsArtListData

type NewsArtListData struct {
	ID          []byte `yaml:"ID"` // Size 4
	Name        []byte `yaml:"Name"`
	Description []byte `yaml:"Description"` // not used?
	NewsArtList []byte // List of articles			Optional (if article count > 0)
}

func (*NewsArtListData) Payload

func (nald *NewsArtListData) Payload() []byte

type NewsCategoryListData15

type NewsCategoryListData15 struct {
	Type     []byte                            `yaml:"Type"`     //Size 2 ; Bundle (2) or category (3)
	Name     string                            `yaml:"Name"`     //
	Articles map[uint32]*NewsArtData           `yaml:"Articles"` // Optional, if Type is Category
	SubCats  map[string]NewsCategoryListData15 `yaml:"SubCats"`
	Count    []byte                            // Article or SubCategory count Size 2
	AddSN    []byte                            // Size 4
	DeleteSN []byte                            // Size 4
	GUID     []byte                            // Size 16
}

func ReadNewsCategoryListData

func ReadNewsCategoryListData(payload []byte) NewsCategoryListData15

ReadNewsCategoryListData parses a byte slice into a NewsCategoryListData15 struct For use on the client side

func (*NewsCategoryListData15) GetNewsArtListData

func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData

func (*NewsCategoryListData15) Payload

func (newscat *NewsCategoryListData15) Payload() []byte

type NewsFlavorList

type NewsFlavorList struct {
}

type NewsPath

type NewsPath struct {
	Paths []string
}

func (*NewsPath) Payload

func (np *NewsPath) Payload() []byte

type PrivateChat

type PrivateChat struct {
	Subject    string
	ClientConn map[uint16]*ClientConn
}

type Server

type Server struct {
	Addr          int
	Accounts      map[string]*Account
	Agreement     []byte
	Clients       map[uint16]*ClientConn
	FlatNews      []byte
	ThreadedNews  *ThreadedNews
	FileTransfers map[uint32]*FileTransfer
	Config        *Config
	ConfigDir     string
	Logger        *zap.SugaredLogger
	PrivateChats  map[uint32]*PrivateChat
	NextGuestID   *uint16
	TrackerPassID []byte
	Stats         *Stats
	// contains filtered or unexported fields
}

func NewServer

func NewServer(configDir string, addr int, logger *zap.SugaredLogger) (*Server, error)

NewServer constructs a new Server from a config dir

func (*Server) DeleteUser

func (s *Server) DeleteUser(login string) error

DeleteUser deletes the user account

func (*Server) GetNewsCatByPath

func (s *Server) GetNewsCatByPath(paths []string) map[string]NewsCategoryListData15

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

func (*Server) NewClientConn

func (s *Server) NewClientConn(conn net.Conn) *ClientConn

func (*Server) NewPrivateChat

func (s *Server) NewPrivateChat(cc *ClientConn) []byte

func (*Server) NewTransactionRef

func (s *Server) NewTransactionRef() []byte

NewTransactionRef generates a random ID for the file transfer. The Hotline client includes this ID in the file transfer request payload, and the file transfer server will use it to map the request to a transfer

func (*Server) NewUser

func (s *Server) NewUser(login, name, password string, access []byte) error

NewUser creates a new user account entry in the server map and config file

func (*Server) Serve

func (s *Server) Serve(ln net.Listener) error

func (*Server) ServeFileTransfers

func (s *Server) ServeFileTransfers(ln net.Listener) error

func (*Server) TransferFile

func (s *Server) TransferFile(conn net.Conn) error

type Stats

type Stats struct {
	LoginCount int           `yaml:"login count"`
	StartTime  time.Time     `yaml:"start time"`
	Uptime     time.Duration `yaml:"uptime"`
}

func (*Stats) String

func (s *Stats) String() string

type ThreadedNews

type ThreadedNews struct {
	Categories map[string]NewsCategoryListData15 `yaml:"Categories"`
}

type TrackerRegistration

type TrackerRegistration struct {
	Port        []byte // Server’s listening UDP port number TODO: wat?
	UserCount   int    // Number of users connected to this particular server
	PassID      []byte // Random number generated by the server
	Name        string // Server’s name
	Description string // Description of the server
}

func (*TrackerRegistration) Payload

func (tr *TrackerRegistration) Payload() []byte

type Transaction

type Transaction struct {
	Flags      byte   // Reserved (should be 0)
	IsReply    byte   // Request (0) or reply (1)
	Type       []byte // Requested operation (user defined)
	ID         []byte // Unique transaction ID (must be != 0)
	ErrorCode  []byte // Used in the reply (user defined, 0 = no error)
	TotalSize  []byte // Total data size for the transaction (all parts)
	DataSize   []byte // Size of data in this transaction part. This allows splitting large transactions into smaller parts.
	ParamCount []byte // Number of the parameters for this transaction
	Fields     []Field
	// contains filtered or unexported fields
}

func HandleChatSend

func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDelNewsArt

func HandleDelNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDelNewsItem

func HandleDelNewsItem(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDeleteFile

func HandleDeleteFile(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleDeleteFile deletes a file or folder Fields used in the request: * 201 File name * 202 File path Fields used in the reply: none

func HandleDeleteUser

func HandleDeleteUser(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDisconnectUser

func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDownloadFile

func HandleDownloadFile(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleDownloadFolder

func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error)

Download all files from the specified folder and sub-folders response example

00
01
00 00
00 00 00 11
00 00 00 00
00 00 00 18
00 00 00 18

00 03

00 6c // transfer size
00 04 // len
00 0f d5 ae

00 dc // field Folder item count
00 02 // len
00 02

00 6b // ref number
00 04 // len
00 03 64 b1

func HandleGetClientConnInfoText

func HandleGetClientConnInfoText(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetFileInfo

func HandleGetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetFileNameList

func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetMsgs

func HandleGetMsgs(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleGetMsgs returns the flat news data

func HandleGetNewsArtData

func HandleGetNewsArtData(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetNewsArtNameList

func HandleGetNewsArtNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error)

Fields used in the request: 325 News path Optional

Reply fields: 321 News article list data Optional

func HandleGetNewsCatNameList

func HandleGetNewsCatNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetUser

func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleGetUserNameList

func HandleGetUserNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleInviteNewChat

func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleInviteNewChat invites users to new private chat

func HandleInviteToChat

func HandleInviteToChat(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleJoinChat

func HandleJoinChat(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleJoinChat is sent from a v1.8+ Hotline client when the joins a private chat Fields used in the reply: * 115 Chat subject * 300 User name with info (Optional) * 300 (more user names with info)

func HandleKeepAlive

func HandleKeepAlive(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleKeepAlive response to keepalive transactions with an empty reply HL 1.9.2 Client sends keepalive msg every 3 minutes HL 1.2.3 Client doesn't send keepalives

func HandleLeaveChat

func HandleLeaveChat(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleLeaveChat is sent from a v1.8+ Hotline client when the user exits a private chat Fields used in the request:

  • 114 fieldChatID

Reply is not expected.

func HandleListUsers

func HandleListUsers(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleMoveFile

func HandleMoveFile(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleMoveFile moves files or folders. Note: seemingly not documented

func HandleNewFolder

func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleNewNewsCat

func HandleNewNewsCat(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleNewNewsFldr

func HandleNewNewsFldr(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleNewUser

func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleNewUser creates a new user account

func HandlePostNewsArt

func HandlePostNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleRejectChatInvite

func HandleRejectChatInvite(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleSendInstantMsg

func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleSendInstantMsg sends instant message to the user on the current server. Fields used in the request:

103	User ID
113	Options
	One of the following values:
	- User message (myOpt_UserMessage = 1)
	- Refuse message (myOpt_RefuseMessage = 2)
	- Refuse chat (myOpt_RefuseChat  = 3)
	- Automatic response (myOpt_AutomaticResponse = 4)"
101	Data	Optional
214	Quoting message	Optional

Fields used in the reply: None

func HandleSetChatSubject

func HandleSetChatSubject(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleSetChatSubject is sent from a v1.8+ Hotline client when the user sets a private chat subject Fields used in the request: * 114 Chat ID * 115 Chat subject Chat subject string Reply is not expected.

func HandleSetClientUserInfo

func HandleSetClientUserInfo(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleSetFileInfo

func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleSetFileInfo updates a file or folder name and/or comment from the Get Info window TODO: Implement support for comments Fields used in the request: * 201 File name * 202 File path Optional * 211 File new name Optional * 210 File comment Optional Fields used in the reply: None

func HandleSetUser

func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleTranAgreed

func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleTranOldPostNews

func HandleTranOldPostNews(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleTranOldPostNews updates the flat news Fields used in this request: 101 Data

func HandleUploadFile

func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err error)

func HandleUploadFolder

func HandleUploadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error)

Upload all files from the local folder and its subfolders to the specified path on the server Fields used in the request 201 File name 202 File path 108 Transfer size Total size of all items in the folder 220 Folder item count 204 File transfer options "Optional Currently set to 1" (TODO: ??)

func HandleUserBroadcast

func HandleUserBroadcast(cc *ClientConn, t *Transaction) (res []Transaction, err error)

HandleUserBroadcast sends an Administrator Message to all connected clients of the server

func NewTransaction

func NewTransaction(t int, clientID *[]byte, fields ...Field) *Transaction

func ReadTransaction

func ReadTransaction(buf []byte) (*Transaction, int, error)

ReadTransaction parses a byte slice into a struct. The input slice may be shorter or longer that the transaction size depending on what was read from the network connection.

func (Transaction) GetField

func (t Transaction) GetField(id int) Field

func (Transaction) Payload

func (t Transaction) Payload() []byte

func (Transaction) Size

func (t Transaction) Size() []byte

Size returns the total size of the transaction payload

type TransactionType

type TransactionType struct {
	Access         int                                                    // Specifies access privilege required to perform the transaction
	DenyMsg        string                                                 // The error reply message when user does not have access
	Handler        func(*ClientConn, *Transaction) ([]Transaction, error) // function for handling the transaction type
	Name           string                                                 // Name of transaction as it will appear in logging
	RequiredFields []requiredField
}

type Transfer

type Transfer struct {
	Protocol        [4]byte // "HTXF" 0x48545846
	ReferenceNumber [4]byte // Unique ID generated for the transfer
	DataSize        [4]byte // File size
	RSVD            [4]byte // Not implemented in Hotline Protocol
}

func NewReadTransfer

func NewReadTransfer(b []byte) (Transfer, error)

type UI

type UI struct {
	App   *tview.Application
	Pages *tview.Pages

	HLClient *Client
	// contains filtered or unexported fields
}

func NewUI

func NewUI(c *Client) *UI

func (*UI) Start

func (ui *UI) Start()

type User

type User struct {
	ID    []byte // Size 2
	Icon  []byte // Size 2
	Flags []byte // Size 2
	Name  string // Variable length user name
}

func ReadUser

func ReadUser(b []byte) *User

func (User) Payload

func (u User) Payload() []byte

Directories

Path Synopsis
ui

Jump to

Keyboard shortcuts

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