2016-02-12 04:03:42 +00:00
|
|
|
// libnmdc project UserInfo.go
|
|
|
|
package libnmdc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2016-05-09 06:13:38 +00:00
|
|
|
"strings"
|
2016-02-12 04:03:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// This structure represents a user connected to a hub.
|
|
|
|
type UserInfo struct {
|
|
|
|
Nick string
|
|
|
|
Description string
|
|
|
|
ClientTag string
|
2016-05-09 06:13:38 +00:00
|
|
|
ClientVersion string
|
2016-02-12 04:03:42 +00:00
|
|
|
Email string
|
|
|
|
ShareSize uint64
|
|
|
|
ConnectionMode ConnectionMode
|
|
|
|
Flag UserFlag
|
|
|
|
Slots uint64
|
|
|
|
Speed string
|
|
|
|
HubsUnregistered uint64
|
|
|
|
HubsRegistered uint64
|
|
|
|
HubsOperator uint64
|
2016-05-08 00:49:36 +00:00
|
|
|
IsOperator bool
|
2016-02-12 04:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var rx_myinfo *regexp.Regexp
|
|
|
|
var rx_myinfo_notag *regexp.Regexp
|
|
|
|
|
|
|
|
func init() {
|
2016-11-29 06:23:00 +00:00
|
|
|
// Format: $ALL <nick> <description>$ $<connection><flag>$<e-mail>$<sharesize>$
|
2016-08-27 03:22:39 +00:00
|
|
|
|
|
|
|
HEAD := `(?ms)^\$ALL ([^ ]+) `
|
|
|
|
FOOT := `\$.\$([^$]+)\$([^$]*)\$([0-9]*)\$$`
|
|
|
|
|
|
|
|
rx_myinfo = regexp.MustCompile(HEAD + `([^<]*)<(.+?) V:([^,]+),M:(.),H:([0-9]+)/([0-9]+)/([0-9]+),S:([0-9]+)>` + FOOT)
|
|
|
|
rx_myinfo_notag = regexp.MustCompile(HEAD + `([^$]*)` + FOOT) // Fallback for no tag
|
2016-02-12 04:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewUserInfo(username string) *UserInfo {
|
|
|
|
return &UserInfo{
|
|
|
|
Nick: username,
|
|
|
|
ConnectionMode: CONNECTIONMODE_PASSIVE,
|
|
|
|
HubsUnregistered: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func maybeParse(str string, dest *uint64, default_val uint64) {
|
|
|
|
sz, err := strconv.ParseUint(str, 10, 64)
|
|
|
|
if err == nil {
|
|
|
|
*dest = sz
|
|
|
|
} else {
|
|
|
|
*dest = default_val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *UserInfo) fromMyINFO(protomsg string) error {
|
2016-08-27 03:22:39 +00:00
|
|
|
|
2016-05-09 06:13:38 +00:00
|
|
|
// Normal format (with tag in exact V/M/H/S order)
|
2016-02-12 04:03:42 +00:00
|
|
|
matches := rx_myinfo.FindStringSubmatch(protomsg)
|
|
|
|
if matches != nil {
|
|
|
|
this.Nick = matches[1]
|
|
|
|
this.Description = NMDCUnescape(matches[2])
|
|
|
|
this.ClientTag = NMDCUnescape(matches[3])
|
2016-05-09 06:13:38 +00:00
|
|
|
this.ClientVersion = matches[4]
|
2016-11-29 06:23:00 +00:00
|
|
|
this.ConnectionMode = ConnectionMode(matches[5][0])
|
2016-05-09 06:13:38 +00:00
|
|
|
maybeParse(matches[6], &this.HubsUnregistered, 0)
|
|
|
|
maybeParse(matches[7], &this.HubsRegistered, 0)
|
|
|
|
maybeParse(matches[8], &this.HubsOperator, 0)
|
|
|
|
maybeParse(matches[9], &this.Slots, 0)
|
2016-08-27 03:22:39 +00:00
|
|
|
if len(matches[10]) > 1 {
|
|
|
|
this.Speed = matches[10][:len(matches[10])-2]
|
|
|
|
} else {
|
|
|
|
this.Speed = ""
|
|
|
|
}
|
|
|
|
this.Flag = UserFlag(matches[10][len(matches[10])-1])
|
|
|
|
this.Email = NMDCUnescape(matches[11])
|
|
|
|
maybeParse(matches[12], &this.ShareSize, 0)
|
|
|
|
|
2016-02-12 04:03:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// No-tag format, used in early connection
|
|
|
|
matches = rx_myinfo_notag.FindStringSubmatch(protomsg)
|
|
|
|
if matches != nil {
|
|
|
|
this.Nick = matches[1]
|
|
|
|
this.Description = NMDCUnescape(matches[2])
|
|
|
|
this.ClientTag = ""
|
2016-05-09 06:13:38 +00:00
|
|
|
this.ClientVersion = "0"
|
2016-02-12 04:03:42 +00:00
|
|
|
this.ConnectionMode = CONNECTIONMODE_PASSIVE
|
|
|
|
this.HubsUnregistered = 0
|
|
|
|
this.HubsRegistered = 0
|
|
|
|
this.HubsOperator = 0
|
|
|
|
this.Slots = 0
|
2016-08-27 03:22:39 +00:00
|
|
|
|
|
|
|
if len(matches[3]) > 1 {
|
|
|
|
this.Speed = matches[3][:len(matches[3])-2]
|
|
|
|
} else {
|
|
|
|
this.Speed = ""
|
|
|
|
}
|
|
|
|
this.Flag = UserFlag(matches[3][len(matches[3])-1])
|
|
|
|
this.Email = NMDCUnescape(matches[4])
|
|
|
|
maybeParse(matches[5], &this.ShareSize, 0)
|
|
|
|
|
2016-02-12 04:03:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Couldn't get anything out of it...
|
|
|
|
return errors.New("Malformed MyINFO")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the MyINFO command, WITH leading $MyINFO, and WITHOUT trailing pipe
|
|
|
|
func (this *UserInfo) toMyINFO() string {
|
|
|
|
return fmt.Sprintf(
|
2016-05-09 06:13:38 +00:00
|
|
|
"$MyINFO $ALL %s %s<%s V:%s,M:%c,H:%d/%d/%d,S:%d>$ $%s%c$%s$%d$",
|
2016-02-12 04:03:42 +00:00
|
|
|
this.Nick,
|
|
|
|
this.Description,
|
|
|
|
this.ClientTag,
|
2016-05-09 06:13:38 +00:00
|
|
|
strings.Replace(this.ClientVersion, ",", "-", -1), // just in case
|
2016-02-12 04:03:42 +00:00
|
|
|
this.ConnectionMode,
|
|
|
|
this.HubsUnregistered,
|
|
|
|
this.HubsRegistered,
|
|
|
|
this.HubsOperator,
|
|
|
|
this.Slots,
|
|
|
|
this.Speed,
|
|
|
|
this.Flag,
|
|
|
|
this.Email,
|
|
|
|
this.ShareSize,
|
|
|
|
)
|
|
|
|
}
|