ExchPub string `json:"exchpub"`
SignPub string `json:"signpub"`
NoisePub *string `json:"noisepub,omitempty"`
- Exec map[string][]string `json:"exec,omitempty"`
Incoming *string `json:"incoming,omitempty"`
+ Exec map[string][]string `json:"exec,omitempty"`
Freq *NodeFreqJSON `json:"freq,omitempty"`
Via []string `json:"via,omitempty"`
Calls []CallJSON `json:"calls,omitempty"`
}
type CallJSON struct {
- Cron string
+ Cron string `json:"cron"`
Nice *string `json:"nice,omitempty"`
Xx *string `json:"xx,omitempty"`
RxRate *int `json:"rxrate,omitempty"`
Addr *string `json:"addr,omitempty"`
OnlineDeadline *uint `json:"onlinedeadline,omitempty"`
MaxOnlineTime *uint `json:"maxonlinetime,omitempty"`
- WhenTxExists *bool `json:"when-tx-exists,omitempty"`
- NoCK *bool `json:"nock"`
- MCDIgnore *bool `json:"mcd-ignore"`
-
- AutoToss *bool `json:"autotoss,omitempty"`
- AutoTossDoSeen *bool `json:"autotoss-doseen,omitempty"`
- AutoTossNoFile *bool `json:"autotoss-nofile,omitempty"`
- AutoTossNoFreq *bool `json:"autotoss-nofreq,omitempty"`
- AutoTossNoExec *bool `json:"autotoss-noexec,omitempty"`
- AutoTossNoTrns *bool `json:"autotoss-notrns,omitempty"`
- AutoTossNoArea *bool `json:"autotoss-noarea,omitempty"`
+ WhenTxExists bool `json:"when-tx-exists,omitempty"`
+ NoCK bool `json:"nock,omitempty"`
+ MCDIgnore bool `json:"mcd-ignore,omitempty"`
+
+ AutoToss bool `json:"autotoss,omitempty"`
+ AutoTossDoSeen bool `json:"autotoss-doseen,omitempty"`
+ AutoTossNoFile bool `json:"autotoss-nofile,omitempty"`
+ AutoTossNoFreq bool `json:"autotoss-nofreq,omitempty"`
+ AutoTossNoExec bool `json:"autotoss-noexec,omitempty"`
+ AutoTossNoTrns bool `json:"autotoss-notrns,omitempty"`
+ AutoTossNoArea bool `json:"autotoss-noarea,omitempty"`
}
type NodeOurJSON struct {
ExchPrv string `json:"exchprv"`
SignPub string `json:"signpub"`
SignPrv string `json:"signprv"`
- NoisePrv string `json:"noiseprv"`
NoisePub string `json:"noisepub"`
+ NoisePrv string `json:"noiseprv"`
}
type FromToJSON struct {
- From string
- To string
+ From string `json:"from"`
+ To string `json:"to"`
}
type NotifyJSON struct {
type AreaJSON struct {
Id string `json:"id"`
- Pub string `json:"pub"`
+ Pub *string `json:"pub,omitempty"`
Prv *string `json:"prv,omitempty"`
Subs []string `json:"subs"`
- Exec map[string][]string `json:"exec,omitempty"`
Incoming *string `json:"incoming,omitempty"`
+ Exec map[string][]string `json:"exec,omitempty"`
- AllowUnknown *bool `json:"allow-unknown,omitempty"`
+ AllowUnknown bool `json:"allow-unknown,omitempty"`
}
type CfgJSON struct {
- Spool string `json:"spool"`
- Log string `json:"log"`
- Umask string `json:"umask,omitempty"`
+ Spool string `json:"spool"`
+ Log string `json:"log"`
+ Umask *string `json:"umask,omitempty"`
OmitPrgrs bool `json:"noprogress,omitempty"`
NoHdr bool `json:"nohdr,omitempty"`
+ MCDRxIfis []string `json:"mcd-listen,omitempty"`
+ MCDTxIfis map[string]int `json:"mcd-send,omitempty"`
+
Notify *NotifyJSON `json:"notify,omitempty"`
Self *NodeOurJSON `json:"self"`
Neigh map[string]NodeJSON `json:"neigh"`
- MCDRxIfis []string `json:"mcd-listen"`
- MCDTxIfis map[string]int `json:"mcd-send"`
-
- Areas map[string]AreaJSON `json:"areas"`
+ Areas map[string]AreaJSON `json:"areas,omitempty"`
}
func NewNode(name string, cfg NodeJSON) (*Node, error) {
if callCfg.MaxOnlineTime != nil {
call.MaxOnlineTime = time.Duration(*callCfg.MaxOnlineTime) * time.Second
}
- if callCfg.WhenTxExists != nil {
- call.WhenTxExists = *callCfg.WhenTxExists
- }
- if callCfg.NoCK != nil {
- call.NoCK = *callCfg.NoCK
- }
- if callCfg.MCDIgnore != nil {
- call.MCDIgnore = *callCfg.MCDIgnore
- }
- if callCfg.AutoToss != nil {
- call.AutoToss = *callCfg.AutoToss
- }
- if callCfg.AutoTossDoSeen != nil {
- call.AutoTossDoSeen = *callCfg.AutoTossDoSeen
- }
- if callCfg.AutoTossNoFile != nil {
- call.AutoTossNoFile = *callCfg.AutoTossNoFile
- }
- if callCfg.AutoTossNoFreq != nil {
- call.AutoTossNoFreq = *callCfg.AutoTossNoFreq
- }
- if callCfg.AutoTossNoExec != nil {
- call.AutoTossNoExec = *callCfg.AutoTossNoExec
- }
- if callCfg.AutoTossNoTrns != nil {
- call.AutoTossNoTrns = *callCfg.AutoTossNoTrns
- }
- if callCfg.AutoTossNoArea != nil {
- call.AutoTossNoArea = *callCfg.AutoTossNoArea
- }
+ call.WhenTxExists = callCfg.WhenTxExists
+ call.NoCK = callCfg.NoCK
+ call.MCDIgnore = callCfg.MCDIgnore
+ call.AutoToss = callCfg.AutoToss
+ call.AutoTossDoSeen = callCfg.AutoTossDoSeen
+ call.AutoTossNoFile = callCfg.AutoTossNoFile
+ call.AutoTossNoFreq = callCfg.AutoTossNoFreq
+ call.AutoTossNoExec = callCfg.AutoTossNoExec
+ call.AutoTossNoTrns = callCfg.AutoTossNoTrns
+ call.AutoTossNoArea = callCfg.AutoTossNoArea
calls = append(calls, &call)
}
area := Area{
Name: name,
Id: areaId,
- Pub: new([32]byte),
Subs: subs,
Exec: cfg.Exec,
Incoming: cfg.Incoming,
}
- pub, err := Base32Codec.DecodeString(cfg.Pub)
- if err != nil {
- return nil, err
- }
- if len(pub) != 32 {
- return nil, errors.New("Invalid pub size")
+ if cfg.Pub != nil {
+ pub, err := Base32Codec.DecodeString(*cfg.Pub)
+ if err != nil {
+ return nil, err
+ }
+ if len(pub) != 32 {
+ return nil, errors.New("Invalid pub size")
+ }
+ area.Pub = new([32]byte)
+ copy(area.Pub[:], pub)
}
- copy(area.Pub[:], pub)
if cfg.Prv != nil {
prv, err := Base32Codec.DecodeString(*cfg.Prv)
if err != nil {
area.Prv = new([32]byte)
copy(area.Prv[:], prv)
}
- if cfg.AllowUnknown != nil {
- area.AllowUnknown = *cfg.AllowUnknown
- }
+ area.AllowUnknown = cfg.AllowUnknown
return &area, nil
}
-func CfgParse(data []byte) (*Ctx, error) {
+func CfgParse(data []byte) (*CfgJSON, error) {
var err error
if bytes.Compare(data[:8], MagicNNCPBv3.B[:]) == 0 {
os.Stderr.WriteString("Passphrase:") // #nosec G104
return nil, err
}
var cfgJSON CfgJSON
- if err = json.Unmarshal(marshaled, &cfgJSON); err != nil {
- return nil, err
- }
+ err = json.Unmarshal(marshaled, &cfgJSON)
+ return &cfgJSON, err
+}
+
+func Cfg2Ctx(cfgJSON *CfgJSON) (*Ctx, error) {
if _, exists := cfgJSON.Neigh["self"]; !exists {
return nil, errors.New("self neighbour missing")
}
var self *NodeOur
if cfgJSON.Self != nil {
+ var err error
self, err = NewNodeOur(cfgJSON.Self)
if err != nil {
return nil, err
return nil, errors.New("Log path must be absolute")
}
var umaskForce *int
- if cfgJSON.Umask != "" {
- r, err := strconv.ParseUint(cfgJSON.Umask, 8, 16)
+ if cfgJSON.Umask != nil {
+ r, err := strconv.ParseUint(*cfgJSON.Umask, 8, 16)
if err != nil {
return nil, err
}
--- /dev/null
+/*
+NNCP -- Node to Node copy, utilities for store-and-forward data exchange
+Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package nncp
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+func cfgDirMkdir(dst ...string) error {
+ return os.MkdirAll(filepath.Join(dst...), os.FileMode(0777))
+}
+
+func cfgDirSave(v interface{}, dst ...string) error {
+ var r string
+ switch v := v.(type) {
+ case *string:
+ if v == nil {
+ return nil
+ }
+ r = *v
+ case string:
+ r = v
+ case *int:
+ if v == nil {
+ return nil
+ }
+ r = strconv.Itoa(*v)
+ case *uint:
+ if v == nil {
+ return nil
+ }
+ r = strconv.Itoa(int(*v))
+ case *uint64:
+ if v == nil {
+ return nil
+ }
+ r = strconv.FormatUint(*v, 10)
+ case int:
+ r = strconv.Itoa(v)
+ default:
+ panic("unsupported value type")
+ }
+ mode := os.FileMode(0666)
+ if strings.HasSuffix(dst[len(dst)-1], "prv") {
+ mode = os.FileMode(0600)
+ }
+ return ioutil.WriteFile(filepath.Join(dst...), []byte(r+"\n"), mode)
+}
+
+func cfgDirTouch(dst ...string) error {
+ if fd, err := os.Create(filepath.Join(dst...)); err == nil {
+ fd.Close()
+ } else {
+ return err
+ }
+ return nil
+}
+
+func CfgToDir(dst string, cfg *CfgJSON) (err error) {
+ if err = cfgDirMkdir(dst); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Spool, dst, "spool"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Log, dst, "log"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Umask, dst, "umask"); err != nil {
+ return
+ }
+ if cfg.OmitPrgrs {
+ if err = cfgDirTouch(dst, "noprogress"); err != nil {
+ return
+ }
+ }
+ if cfg.NoHdr {
+ if err = cfgDirTouch(dst, "nohdr"); err != nil {
+ return
+ }
+ }
+
+ if len(cfg.MCDRxIfis) > 0 {
+ if err = cfgDirSave(
+ strings.Join(cfg.MCDRxIfis, "\n"),
+ dst, "mcd-listen",
+ ); err != nil {
+ return
+ }
+ }
+ if len(cfg.MCDTxIfis) > 0 {
+ if err = cfgDirMkdir(dst, "mcd-send"); err != nil {
+ return
+ }
+ for ifi, t := range cfg.MCDTxIfis {
+ if err = cfgDirSave(t, dst, "mcd-send", ifi); err != nil {
+ return
+ }
+ }
+ }
+
+ if cfg.Notify != nil {
+ if cfg.Notify.File != nil {
+ if err = cfgDirMkdir(dst, "notify", "file"); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ cfg.Notify.File.From,
+ dst, "notify", "file", "from",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ cfg.Notify.File.To,
+ dst, "notify", "file", "to",
+ ); err != nil {
+ return
+ }
+ }
+ if cfg.Notify.Freq != nil {
+ if err = cfgDirMkdir(dst, "notify", "freq"); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ cfg.Notify.Freq.From,
+ dst, "notify", "freq", "from",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ cfg.Notify.Freq.To,
+ dst, "notify", "freq", "to",
+ ); err != nil {
+ return
+ }
+ }
+ for k, v := range cfg.Notify.Exec {
+ if err = cfgDirMkdir(dst, "notify", "exec", k); err != nil {
+ return
+ }
+ if err = cfgDirSave(v.From, dst, "notify", "exec", k, "from"); err != nil {
+ return
+ }
+ if err = cfgDirSave(v.To, dst, "notify", "exec", k, "to"); err != nil {
+ return
+ }
+ }
+ }
+
+ if err = cfgDirMkdir(dst, "self"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.Id, dst, "self", "id"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.ExchPub, dst, "self", "exchpub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.ExchPrv, dst, "self", "exchprv"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.SignPub, dst, "self", "signpub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.SignPrv, dst, "self", "signprv"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.NoisePub, dst, "self", "noisepub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(cfg.Self.NoisePrv, dst, "self", "noiseprv"); err != nil {
+ return
+ }
+
+ for name, n := range cfg.Neigh {
+ if err = cfgDirMkdir(dst, "neigh", name); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.Id, dst, "neigh", name, "id"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.ExchPub, dst, "neigh", name, "exchpub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.SignPub, dst, "neigh", name, "signpub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.NoisePub, dst, "neigh", name, "noisepub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.Incoming, dst, "neigh", name, "incoming"); err != nil {
+ return
+ }
+
+ if len(n.Exec) > 0 {
+ if err = cfgDirMkdir(dst, "neigh", name, "exec"); err != nil {
+ return
+ }
+ for k, v := range n.Exec {
+ if err = cfgDirSave(
+ strings.Join(v, "\n"),
+ dst, "neigh", name, "exec", k,
+ ); err != nil {
+ return
+ }
+ }
+ }
+
+ if n.Freq != nil {
+ if err = cfgDirMkdir(dst, "neigh", name, "freq"); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.Freq.Path,
+ dst, "neigh", name, "freq", "path",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.Freq.Chunked,
+ dst, "neigh", name, "freq", "chunked",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.Freq.MinSize,
+ dst, "neigh", name, "freq", "minsize",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.Freq.MaxSize,
+ dst, "neigh", name, "freq", "maxsize",
+ ); err != nil {
+ return
+ }
+ }
+
+ if len(n.Via) > 0 {
+ if err = cfgDirSave(
+ strings.Join(n.Via, "\n"),
+ dst, "neigh", name, "via",
+ ); err != nil {
+ return
+ }
+ }
+
+ if len(n.Addrs) > 0 {
+ if err = cfgDirMkdir(dst, "neigh", name, "addrs"); err != nil {
+ return
+ }
+ for k, v := range n.Addrs {
+ if err = cfgDirSave(v, dst, "neigh", name, "addrs", k); err != nil {
+ return
+ }
+ }
+ }
+
+ if err = cfgDirSave(n.RxRate, dst, "neigh", name, "rxrate"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.TxRate, dst, "neigh", name, "txrate"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.OnlineDeadline, dst, "neigh", name, "onlinedeadline"); err != nil {
+ return
+ }
+ if err = cfgDirSave(n.MaxOnlineTime, dst, "neigh", name, "maxonlinetime"); err != nil {
+ return
+ }
+
+ for i, call := range n.Calls {
+ is := strconv.Itoa(i)
+ if err = cfgDirMkdir(dst, "neigh", name, "calls", is); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.Cron, dst, "neigh", name, "calls", is, "cron"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.Nice, dst, "neigh", name, "calls", is, "nice"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.Xx, dst, "neigh", name, "calls", is, "xx"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.RxRate, dst, "neigh", name, "calls", is, "rxrate"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.TxRate, dst, "neigh", name, "calls", is, "txrate"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.Addr, dst, "neigh", name, "calls", is, "addr"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.OnlineDeadline, dst, "neigh", name, "calls", is, "onlinedeadline"); err != nil {
+ return
+ }
+ if err = cfgDirSave(call.MaxOnlineTime, dst, "neigh", name, "calls", is, "maxonlinetime"); err != nil {
+ return
+ }
+ if call.WhenTxExists {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "when-tx-exists"); err != nil {
+ return
+ }
+ }
+ if call.NoCK {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "nock"); err != nil {
+ return
+ }
+ }
+ if call.MCDIgnore {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "mcd-ignore"); err != nil {
+ return
+ }
+ }
+ if call.AutoToss {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossDoSeen {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-doseen"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossNoFile {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-nofile"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossNoFreq {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-nofreq"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossNoExec {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noexec"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossNoTrns {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-notrns"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossNoArea {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noarea"); err != nil {
+ return
+ }
+ }
+ }
+ }
+
+ for name, a := range cfg.Areas {
+ if err = cfgDirMkdir(dst, "areas", name); err != nil {
+ return
+ }
+ if err = cfgDirSave(a.Id, dst, "areas", name, "id"); err != nil {
+ return
+ }
+ if err = cfgDirSave(a.Pub, dst, "areas", name, "pub"); err != nil {
+ return
+ }
+ if err = cfgDirSave(a.Prv, dst, "areas", name, "prv"); err != nil {
+ return
+ }
+ if err = cfgDirSave(a.Incoming, dst, "areas", name, "incoming"); err != nil {
+ return
+ }
+ if a.AllowUnknown {
+ if err = cfgDirTouch(dst, "areas", name, "allow-unknown"); err != nil {
+ return
+ }
+ }
+ if len(a.Exec) > 0 {
+ if err = cfgDirMkdir(dst, "areas", name, "exec"); err != nil {
+ return
+ }
+ for k, v := range a.Exec {
+ if err = cfgDirSave(
+ strings.Join(v, "\n"),
+ dst, "areas", name, "exec", k,
+ ); err != nil {
+ return
+ }
+ }
+ }
+ if len(a.Subs) > 0 {
+ if err = cfgDirSave(
+ strings.Join(a.Subs, "\n"),
+ dst, "areas", name, "subs",
+ ); err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
+
+func cfgDirLoad(src ...string) (v string, exists bool, err error) {
+ b, err := ioutil.ReadFile(filepath.Join(src...))
+ if err != nil {
+ if os.IsNotExist(err) {
+ return "", false, nil
+ }
+ return "", false, err
+ }
+ return strings.TrimSuffix(string(b), "\n"), true, nil
+}
+
+func cfgDirLoadMust(src ...string) (v string, err error) {
+ s, exists, err := cfgDirLoad(src...)
+ if err != nil {
+ return "", err
+ }
+ if !exists {
+ return "", fmt.Errorf("required \"%s\" does not exist", src[len(src)-1])
+ }
+ return s, nil
+}
+
+func cfgDirLoadOpt(src ...string) (v *string, err error) {
+ s, exists, err := cfgDirLoad(src...)
+ if err != nil {
+ return nil, err
+ }
+ if !exists {
+ return nil, nil
+ }
+ return &s, nil
+}
+
+func cfgDirLoadIntOpt(src ...string) (i64 *int64, err error) {
+ s, err := cfgDirLoadOpt(src...)
+ if err != nil {
+ return nil, err
+ }
+ if s == nil {
+ return nil, nil
+ }
+ i, err := strconv.ParseInt(*s, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ return &i, nil
+}
+
+func cfgDirExists(src ...string) bool {
+ if _, err := os.Stat(filepath.Join(src...)); err == nil {
+ return true
+ }
+ return false
+}
+
+func cfgDirReadFromTo(src ...string) (*FromToJSON, error) {
+ fromTo := FromToJSON{}
+
+ var err error
+ fromTo.From, err = cfgDirLoadMust(append(src, "from")...)
+ if err != nil {
+ return nil, err
+ }
+
+ fromTo.To, err = cfgDirLoadMust(append(src, "to")...)
+ if err != nil {
+ return nil, err
+ }
+
+ return &fromTo, nil
+}
+
+func DirToCfg(src string) (*CfgJSON, error) {
+ cfg := CfgJSON{}
+ var err error
+
+ cfg.Spool, err = cfgDirLoadMust(src, "spool")
+ if err != nil {
+ return nil, err
+ }
+ cfg.Log, err = cfgDirLoadMust(src, "log")
+ if err != nil {
+ return nil, err
+ }
+
+ if cfg.Umask, err = cfgDirLoadOpt(src, "umask"); err != nil {
+ return nil, err
+ }
+ cfg.OmitPrgrs = cfgDirExists(src, "noprogress")
+ cfg.NoHdr = cfgDirExists(src, "nohdr")
+
+ sp, err := cfgDirLoadOpt(src, "mcd-listen")
+ if err != nil {
+ return nil, err
+ }
+ if sp != nil {
+ cfg.MCDRxIfis = strings.Split(*sp, "\n")
+ }
+
+ fis, err := ioutil.ReadDir(filepath.Join(src, "mcd-send"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ if len(fis) > 0 {
+ cfg.MCDTxIfis = make(map[string]int, len(fis))
+ }
+ for _, fi := range fis {
+ n := fi.Name()
+ if n[0] == '.' {
+ continue
+ }
+ b, err := ioutil.ReadFile(filepath.Join(src, "mcd-send", fi.Name()))
+ if err != nil {
+ return nil, err
+ }
+ i, err := strconv.Atoi(strings.TrimSuffix(string(b), "\n"))
+ if err != nil {
+ return nil, err
+ }
+ cfg.MCDTxIfis[n] = i
+ }
+
+ notify := NotifyJSON{Exec: make(map[string]*FromToJSON)}
+ if cfgDirExists(src, "notify", "file") {
+ if notify.File, err = cfgDirReadFromTo(src, "notify", "file"); err != nil {
+ return nil, err
+ }
+ }
+ if cfgDirExists(src, "notify", "freq") {
+ if notify.Freq, err = cfgDirReadFromTo(src, "notify", "freq"); err != nil {
+ return nil, err
+ }
+ }
+ fis, err = ioutil.ReadDir(filepath.Join(src, "notify", "exec"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi := range fis {
+ n := fi.Name()
+ if n[0] == '.' || !fi.IsDir() {
+ continue
+ }
+ if notify.Exec[fi.Name()], err = cfgDirReadFromTo(src, "notify", "exec", n); err != nil {
+ return nil, err
+ }
+ }
+ if notify.File != nil || notify.Freq != nil || len(notify.Exec) > 0 {
+ cfg.Notify = ¬ify
+ }
+
+ self := NodeOurJSON{}
+ if self.Id, err = cfgDirLoadMust(src, "self", "id"); err != nil {
+ return nil, err
+ }
+ if self.ExchPub, err = cfgDirLoadMust(src, "self", "exchpub"); err != nil {
+ return nil, err
+ }
+ if self.ExchPrv, err = cfgDirLoadMust(src, "self", "exchprv"); err != nil {
+ return nil, err
+ }
+ if self.SignPub, err = cfgDirLoadMust(src, "self", "signpub"); err != nil {
+ return nil, err
+ }
+ if self.SignPrv, err = cfgDirLoadMust(src, "self", "signprv"); err != nil {
+ return nil, err
+ }
+ if self.NoisePub, err = cfgDirLoadMust(src, "self", "noisepub"); err != nil {
+ return nil, err
+ }
+ if self.NoisePrv, err = cfgDirLoadMust(src, "self", "noiseprv"); err != nil {
+ return nil, err
+ }
+ cfg.Self = &self
+
+ cfg.Neigh = make(map[string]NodeJSON)
+ fis, err = ioutil.ReadDir(filepath.Join(src, "neigh"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi := range fis {
+ n := fi.Name()
+ if n[0] == '.' {
+ continue
+ }
+ node := NodeJSON{}
+ if node.Id, err = cfgDirLoadMust(src, "neigh", n, "id"); err != nil {
+ return nil, err
+ }
+ if node.ExchPub, err = cfgDirLoadMust(src, "neigh", n, "exchpub"); err != nil {
+ return nil, err
+ }
+ if node.SignPub, err = cfgDirLoadMust(src, "neigh", n, "signpub"); err != nil {
+ return nil, err
+ }
+ if node.NoisePub, err = cfgDirLoadOpt(src, "neigh", n, "noisepub"); err != nil {
+ return nil, err
+ }
+ if node.Incoming, err = cfgDirLoadOpt(src, "neigh", n, "incoming"); err != nil {
+ return nil, err
+ }
+
+ node.Exec = make(map[string][]string)
+ fis2, err := ioutil.ReadDir(filepath.Join(src, "neigh", n, "exec"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi2 := range fis2 {
+ n2 := fi2.Name()
+ if n2[0] == '.' {
+ continue
+ }
+ s, err := cfgDirLoadMust(src, "neigh", n, "exec", n2)
+ if err != nil {
+ return nil, err
+ }
+ node.Exec[n2] = strings.Split(s, "\n")
+ }
+
+ if cfgDirExists(src, "neigh", n, "freq") {
+ node.Freq = &NodeFreqJSON{}
+ if node.Freq.Path, err = cfgDirLoadOpt(src, "neigh", n, "freq", "path"); err != nil {
+ return nil, err
+ }
+
+ i64, err := cfgDirLoadIntOpt(src, "neigh", n, "freq", "chunked")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint64(*i64)
+ node.Freq.Chunked = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "freq", "minsize")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint64(*i64)
+ node.Freq.MinSize = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "freq", "maxsize")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint64(*i64)
+ node.Freq.MaxSize = &i
+ }
+ }
+
+ via, err := cfgDirLoadOpt(src, "neigh", n, "via")
+ if err != nil {
+ return nil, err
+ }
+ if via != nil {
+ node.Via = strings.Split(*via, "\n")
+ }
+
+ node.Addrs = make(map[string]string)
+ fis2, err = ioutil.ReadDir(filepath.Join(src, "neigh", n, "addrs"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi2 := range fis2 {
+ n2 := fi2.Name()
+ if n2[0] == '.' {
+ continue
+ }
+ if node.Addrs[n2], err = cfgDirLoadMust(src, "neigh", n, "addrs", n2); err != nil {
+ return nil, err
+ }
+ }
+
+ i64, err := cfgDirLoadIntOpt(src, "neigh", n, "rxrate")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := int(*i64)
+ node.RxRate = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "txrate")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := int(*i64)
+ node.TxRate = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "onlinedeadline")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint(*i64)
+ node.OnlineDeadline = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "maxonlinetime")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint(*i64)
+ node.MaxOnlineTime = &i
+ }
+
+ fis2, err = ioutil.ReadDir(filepath.Join(src, "neigh", n, "calls"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ callsIdx := make([]int, 0, len(fis2))
+ for _, fi2 := range fis2 {
+ n2 := fi2.Name()
+ if !fi2.IsDir() {
+ continue
+ }
+ i, err := strconv.Atoi(n2)
+ if err != nil {
+ continue
+ }
+ callsIdx = append(callsIdx, i)
+ }
+ sort.Ints(callsIdx)
+ for _, i := range callsIdx {
+ call := CallJSON{}
+ is := strconv.Itoa(i)
+ if call.Cron, err = cfgDirLoadMust(
+ src, "neigh", n, "calls", is, "cron",
+ ); err != nil {
+ return nil, err
+ }
+ if call.Nice, err = cfgDirLoadOpt(
+ src, "neigh", n, "calls", is, "nice",
+ ); err != nil {
+ return nil, err
+ }
+ if call.Xx, err = cfgDirLoadOpt(
+ src, "neigh", n, "calls", is, "xx",
+ ); err != nil {
+ return nil, err
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "rxrate")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := int(*i64)
+ call.RxRate = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "txrate")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := int(*i64)
+ call.TxRate = &i
+ }
+
+ if call.Addr, err = cfgDirLoadOpt(
+ src, "neigh", n, "calls", is, "addr",
+ ); err != nil {
+ return nil, err
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "onlinedeadline")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint(*i64)
+ call.OnlineDeadline = &i
+ }
+
+ i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "maxonlinetime")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint(*i64)
+ call.MaxOnlineTime = &i
+ }
+
+ if cfgDirExists(src, "neigh", n, "calls", is, "when-tx-exists") {
+ call.WhenTxExists = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "nock") {
+ call.NoCK = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "mcd-ignore") {
+ call.MCDIgnore = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss") {
+ call.AutoToss = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-doseen") {
+ call.AutoTossDoSeen = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-nofile") {
+ call.AutoTossNoFile = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-nofreq") {
+ call.AutoTossNoFreq = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noexec") {
+ call.AutoTossNoExec = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-notrns") {
+ call.AutoTossNoTrns = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noarea") {
+ call.AutoTossNoArea = true
+ }
+ node.Calls = append(node.Calls, call)
+ }
+ cfg.Neigh[n] = node
+ }
+
+ cfg.Areas = make(map[string]AreaJSON)
+ fis, err = ioutil.ReadDir(filepath.Join(src, "areas"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi := range fis {
+ n := fi.Name()
+ if n[0] == '.' {
+ continue
+ }
+ area := AreaJSON{}
+ if area.Id, err = cfgDirLoadMust(src, "areas", n, "id"); err != nil {
+ return nil, err
+ }
+ if area.Pub, err = cfgDirLoadOpt(src, "areas", n, "pub"); err != nil {
+ return nil, err
+ }
+ if area.Prv, err = cfgDirLoadOpt(src, "areas", n, "prv"); err != nil {
+ return nil, err
+ }
+
+ subs, err := cfgDirLoadOpt(src, "areas", n, "subs")
+ if err != nil {
+ return nil, err
+ }
+ if subs != nil {
+ area.Subs = strings.Split(*subs, "\n")
+ }
+
+ area.Exec = make(map[string][]string)
+ fis2, err := ioutil.ReadDir(filepath.Join(src, "areas", n, "exec"))
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ for _, fi2 := range fis2 {
+ n2 := fi2.Name()
+ if n2[0] == '.' {
+ continue
+ }
+ s, err := cfgDirLoadMust(src, "areas", n, "exec", n2)
+ if err != nil {
+ return nil, err
+ }
+ area.Exec[n2] = strings.Split(s, "\n")
+ }
+
+ if area.Incoming, err = cfgDirLoadOpt(src, "areas", n, "incoming"); err != nil {
+ return nil, err
+ }
+
+ if cfgDirExists(src, "areas", n, "allow-unknown") {
+ area.AllowUnknown = true
+ }
+ cfg.Areas[n] = area
+ }
+
+ return &cfg, nil
+}