func (j *JAM) GetMsg(position uint32) (*Message, error) {
	if len(j.indexStructure) == 0 {
		return nil, nil
	}
	if position == 0 {
		position = 1
	}
	fJhr, err := os.Open(j.AreaPath + ".jhr")
	if err != nil {
		return nil, err
	}
	defer fJhr.Close()
	_, err = fJhr.Seek(int64(j.indexStructure[position-1].jamsh.Offset), 0)
	if err != nil {
		return nil, err
	}
	header := make([]byte, 76)
	fJhr.Read(header)
	headerb := bytes.NewBuffer(header)
	var jamh jamH
	if err = utils.ReadStructFromBuffer(headerb, &jamh); err != nil {
		return nil, err
	}
	if jamh.Signature != 0x4d414a {
		return nil, errors.New("wrong message signature")
	}
	rm := &Message{Area: j.AreaName,
		MsgNum:      position,
		MaxNum:      uint32(len(j.indexStructure)),
		DateWritten: time.Unix(int64(jamh.DateWritten), 0)}
	_, tofs := rm.DateWritten.Zone()
	if jamh.DateReceived > 0 {
		rm.DateArrived = time.Unix(int64(jamh.DateReceived), 0)
	} else {
		rm.DateArrived = time.Unix(int64(jamh.DateProcessed), 0)
	}
	rm.DateWritten = rm.DateWritten.Add(time.Duration(tofs) * -time.Second)
	rm.DateArrived = rm.DateArrived.Add(time.Duration(tofs) * -time.Second)
	rm.Attrs = j.getAttrs(jamh.Attribute)
	if jamh.ReplyTo > 0 {
		rm.ReplyTo = j.getOffsetByNum(jamh.ReplyTo)
	} else {
		jamh.ReplyTo = 0
	}
	if jamh.Reply1st > 0 {
		rm.Replies = append(rm.Replies, j.getOffsetByNum(jamh.Reply1st))
	}
	deleted := false
	if jamh.Attribute&0x80000000 > 0 {
		deleted = true
	}
	rm.Body += ""
	kl := make([]byte, jamh.SubfieldLen)
	fJhr.Read(kl)
	klb := bytes.NewBuffer(kl)
	afterBody := ""
	for {
		var LoID, HiID uint16
		var datLen uint32
		err = binary.Read(klb, binary.LittleEndian, &LoID)
		if err != nil {
			break
		}
		binary.Read(klb, binary.LittleEndian, &HiID)
		binary.Read(klb, binary.LittleEndian, &datLen)
		if datLen > 80 {
			datLen = 80
		}
		val := make([]byte, datLen)
		binary.Read(klb, binary.LittleEndian, &val)
		switch LoID {
		case 0:
			fr := types.AddrFromString(string(val))
			if fr != nil {
				rm.FromAddr = fr
			}
		case 1:
			if j.AreaType != EchoAreaTypeLocal && j.AreaType != EchoAreaTypeEcho {
				rm.ToAddr = types.AddrFromString(string(val))
			}
		case 2:
			rm.From = string(val)
		case 3:
			if !deleted {
				if crc32r(string(val)) != j.indexStructure[position-1].jamsh.ToCRC {
					rm.Corrupted = true
				}
			}
			rm.To = string(val)
		case 4:
			if crc32r(string(val)) != jamh.MSGIDcrc {
				rm.Corrupted = true
			}
			rm.Body += "\x01MSGID: " + string(val) + "\x0d"
		case 5:
			if crc32r(string(val)) != jamh.REPLYcrc {
				rm.Corrupted = true
			}
			rm.Body += "\x01REPLYID: " + string(val) + "\x0d"
		case 6:
			rm.Subject = string(val)
		case 7:
			rm.Body += "\x01PID: " + string(val) + "\x0d"
		case 8:
			afterBody += "\x01Via " + string(val) + "\x0d"
		case 2004:
			rm.Body += "\x01TZUTC: " + string(val) + "\x0d"
		case 2000:
			rm.Body += "\x01" + string(val) + "\x0d"
		case 2001:
			afterBody += "SEEN-BY: " + string(val) + "\x0d"
		case 2002:
			afterBody += "\x01PATH: " + string(val) + "\x0d"
		}
	}
	fJdt, err := os.Open(j.AreaPath + ".jdt")
	if err != nil {
		return nil, err
	}
	defer fJdt.Close()
	fJdt.Seek(int64(jamh.Offset), 0)
	txt := make([]byte, jamh.TxtLen)
	fJdt.Read(txt)
	rm.Body += string(txt)
	rm.Body += afterBody
	err = rm.ParseRaw()
	if err != nil {
		return nil, err
	}
	return rm, nil
}
GetMsg return msg
package msgapi
import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"github.com/askovpen/gossiped/pkg/config"
	"github.com/askovpen/gossiped/pkg/types"
	"github.com/askovpen/gossiped/pkg/utils"
	"io"
	"io/ioutil"
	"os"
	"time"
)
type JAM struct {
	AreaPath, AreaName string
	AreaType           EchoAreaType
	Chrs               string
	indexStructure     []jamS
	lastRead           []jamL
	messages           []MessageListItem
	headerStructure    jhrS
}
type jamS struct {
	MessageNum uint32
	jamsh      jamSH
}
type jamSH struct {
	ToCRC, Offset uint32
}
type jhrS struct {
	Signature                           uint32
	DateCreated, ModCounter, ActiveMsgs uint32
	PasswordCRC, BaseMsgNum, Highwater  uint32
	RSRVD                               [996]byte
}
type jamH struct {
	Signature                               uint32
	Revision, ReservedWord                  uint16
	SubfieldLen, TimesRead, MSGIDcrc        uint32
	REPLYcrc, ReplyTo, Reply1st             uint32
	ReplyNext, DateWritten, DateReceived    uint32
	DateProcessed, MessageNumber, Attribute uint32
	Attribute2, Offset, TxtLen              uint32
	PasswordCRC, Cost                       uint32
}
type jamL struct {
	UserCRC, UserID, LastReadMsg, HighReadMsg uint32
}
func (j *JAM) getAttrs(a uint32) (attrs []string) {
	datr := []string{
		"Loc", "", "Pvt", "Rcv",
		"Snt", "", "", "",
		"", "", "", "",
		"", "", "", "",
		"", "", "", "",
		"", "", "", "",
		"", "", "", "",
		"", "", "", "[red]Del[silver]",
	}
	i := 0
	for a > 0 {
		if a&1 > 0 {
			if datr[i] != "" {
				attrs = append(attrs, datr[i])
			}
		}
		i++
		a >>= 1
	}
	return
}
func (j *JAM) getOffsetByNum(num uint32) (offset uint32) {
	for i, is := range j.indexStructure {
		if is.MessageNum == num {
			return uint32(i) + 1
		}
	}
	return 0
}