Automatic group adding
This commit is contained in:
parent
f3ed0fe6c0
commit
fe7055298a
4 changed files with 178 additions and 162 deletions
307
boddle.go
307
boddle.go
|
|
@ -10,6 +10,7 @@ type irc_msg struct {
|
||||||
channel string
|
channel string
|
||||||
msg string
|
msg string
|
||||||
author string
|
author string
|
||||||
|
retmsg string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cmd struct {
|
type cmd struct {
|
||||||
|
|
@ -65,20 +66,6 @@ func unique_int(intSlice []int) []int {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func unique[T any](tSlice []T) []T {
|
|
||||||
keys := make(map[T]bool)
|
|
||||||
list := []T{}
|
|
||||||
for _, entry := range tSlice {
|
|
||||||
if _, value := keys[entry]; !value {
|
|
||||||
keys[entry] = true
|
|
||||||
list = append(list, entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// function to split advise message correctly
|
// function to split advise message correctly
|
||||||
func filter(msg string, foo bot) cmd {
|
func filter(msg string, foo bot) cmd {
|
||||||
var c cmd
|
var c cmd
|
||||||
|
|
@ -125,18 +112,18 @@ func filter(msg string, foo bot) cmd {
|
||||||
LOG_WARN.Printf("invalid query.")
|
LOG_WARN.Printf("invalid query.")
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
group_id := 0
|
|
||||||
if rows.Next() {
|
if rows.Next() {
|
||||||
|
group_id := 0
|
||||||
rows.Scan(&group_id)
|
rows.Scan(&group_id)
|
||||||
c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
|
c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
|
||||||
rows.Close()
|
|
||||||
} else {
|
} else {
|
||||||
c.valid = false
|
if c.add {
|
||||||
c.error = "Group name " + group + " is invalid."
|
c.groups = append(c.groups, addgroups([]string{group}, nil)...)
|
||||||
rows.Close()
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rows.Close()
|
||||||
|
defer stmt.Close()
|
||||||
|
}
|
||||||
c.suffix = res[3]
|
c.suffix = res[3]
|
||||||
c.valid = true
|
c.valid = true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -158,6 +145,7 @@ func filter(msg string, foo bot) cmd {
|
||||||
}
|
}
|
||||||
c.cmd = strings.TrimSpace(c.cmd)
|
c.cmd = strings.TrimSpace(c.cmd)
|
||||||
c.suffix = strings.TrimSpace(c.suffix)
|
c.suffix = strings.TrimSpace(c.suffix)
|
||||||
|
c.groups = unique_str(c.groups)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
@ -174,23 +162,162 @@ func getRandomEntry(c cmd) string {
|
||||||
return task
|
return task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addgroups(new_groups []string, msg *irc_msg) []string {
|
||||||
|
stat_sel, err := db.Prepare("select id from groups where name = ?")
|
||||||
|
checkErr(err)
|
||||||
|
stat_ins, err := db.Prepare("insert into groups(name) values (?)")
|
||||||
|
checkErr(err)
|
||||||
|
var groups_added []string
|
||||||
|
var groupids_added []string
|
||||||
|
for _, group := range new_groups {
|
||||||
|
ret, err := stat_sel.Query(group)
|
||||||
|
if ret.Next() {
|
||||||
|
ret.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
groupid_res, err := stat_ins.Exec(group)
|
||||||
|
checkErr(err)
|
||||||
|
defer stat_ins.Close()
|
||||||
|
groupid, err := groupid_res.LastInsertId()
|
||||||
|
checkErr(err)
|
||||||
|
groupids_added = append(groupids_added, fmt.Sprintf("%d", groupid))
|
||||||
|
groups_added = append(groups_added, group)
|
||||||
|
}
|
||||||
|
if msg != nil {
|
||||||
|
if len(groups_added) > 0 {
|
||||||
|
(*msg).retmsg = "Added " + strings.Join(groups_added, ", ") + " to groups-table!"
|
||||||
|
} else {
|
||||||
|
(*msg).retmsg = "Added nothing to groups-table! :("
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupids_added
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSorter(msg *irc_msg, c *cmd) bool {
|
||||||
|
sorter_row_sel, err := db.Prepare("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = ?")
|
||||||
|
checkErr(err)
|
||||||
|
sorter_row, err := sorter_row_sel.Query((*c).cmd)
|
||||||
|
checkErr(err)
|
||||||
|
if sorter_row.Next() {
|
||||||
|
var sorter_id string
|
||||||
|
var tag_id string
|
||||||
|
var groups_allow int
|
||||||
|
var name_allow int
|
||||||
|
var has_groups int
|
||||||
|
sorter_row.Scan(&sorter_id, &tag_id, &groups_allow, &name_allow, &has_groups)
|
||||||
|
sorter_row.Close()
|
||||||
|
|
||||||
|
if groups_allow != 0 {
|
||||||
|
(*msg).retmsg = "This command does not allow groups. :("
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if name_allow != 0 && !(*c).add {
|
||||||
|
// warning: not allowed
|
||||||
|
(*c).suffix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
(*c).cmd = tag_id
|
||||||
|
|
||||||
|
if has_groups == 0 {
|
||||||
|
group_sel, err := db.Prepare("select group_id from sorter_groups where sorter_id = ?")
|
||||||
|
checkErr(err)
|
||||||
|
sorter_groups_row, err := group_sel.Query(sorter_id)
|
||||||
|
//sorter_groups_row, err := db.Query(fmt.Sprintf("select group_id from sorter_groups where sorter_id = '%s'", sorter_id))
|
||||||
|
checkErr(err)
|
||||||
|
if sorter_groups_row.Next() {
|
||||||
|
var group_id int
|
||||||
|
sorter_groups_row.Scan(&group_id)
|
||||||
|
(*c).groups = append((*c).groups, fmt.Sprintf("%d", group_id))
|
||||||
|
}
|
||||||
|
sorter_groups_row.Close()
|
||||||
|
if (*c).add {
|
||||||
|
var tag_name string
|
||||||
|
tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %d", tag_id))
|
||||||
|
checkErr(err)
|
||||||
|
if tag_name_row.Next() {
|
||||||
|
tag_name_row.Scan(&tag_name)
|
||||||
|
}
|
||||||
|
tag_name_row.Close()
|
||||||
|
LOG_WARN.Printf("Alias used. Tell the user about that.\n")
|
||||||
|
(*msg).retmsg = "You're using an alias. Please try again with 'add " + tag_name + " [" + strings.Join((*c).groups, " ") + "]. Thanks!"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARN.Printf("no sorter entry, no translation possible\n")
|
||||||
|
(*msg).retmsg = "No entry found, sorry..."
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func chooseEntry(msg *irc_msg, c *cmd) {
|
||||||
|
task := getRandomEntry(*c)
|
||||||
|
|
||||||
|
LOG_INFO.Printf(task)
|
||||||
|
row, err := db.Query(task)
|
||||||
|
checkErr(err)
|
||||||
|
if row.Next() {
|
||||||
|
row.Scan(&((*msg).retmsg))
|
||||||
|
}
|
||||||
|
row.Close()
|
||||||
|
|
||||||
|
if len((*msg).retmsg) <= 0 {
|
||||||
|
LOG_WARN.Printf("no entry found\n")
|
||||||
|
(*msg).retmsg = "No matching entry found :("
|
||||||
|
} else if len((*c).suffix) > 0 {
|
||||||
|
(*msg).retmsg = fmt.Sprintf("%s... %s", (*c).suffix, (*msg).retmsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLine(msg *irc_msg, line string, groups []string, cmd string) string {
|
||||||
|
LOG_WARN.Printf("adding new stuff: %s from %s.\n", line, (*msg).author)
|
||||||
|
|
||||||
|
res, err := db.Exec("insert into line (content, author) values (?,?)", line, (*msg).author)
|
||||||
|
checkErr(err)
|
||||||
|
LOG_WARN.Printf("added line to table.\n")
|
||||||
|
|
||||||
|
// get ID of content...
|
||||||
|
line_id, err := res.LastInsertId();
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
LOG_WARN.Printf("line_id: %d, tag_id: %d, groups: %s\n", line_id, cmd, strings.Join(groups, "-"))
|
||||||
|
// for tag and all groups
|
||||||
|
if len(groups) == 0 {
|
||||||
|
stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)")
|
||||||
|
checkErr(err)
|
||||||
|
_, err = stat.Exec(line_id, cmd)
|
||||||
|
checkErr(err)
|
||||||
|
defer stat.Close()
|
||||||
|
} else {
|
||||||
|
stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)")
|
||||||
|
checkErr(err)
|
||||||
|
for _, group := range groups {
|
||||||
|
_, err = stat.Exec(line_id, cmd, group)
|
||||||
|
checkErr(err)
|
||||||
|
}
|
||||||
|
defer stat.Close()
|
||||||
|
}
|
||||||
|
(*msg).retmsg = fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id)
|
||||||
|
return fmt.Sprintf("new line: > %s < (ID %d), into groups %s", line, line_id, strings.Join(groups,","))
|
||||||
|
}
|
||||||
// line:
|
// line:
|
||||||
// >befehl <[groups]> <name>
|
// >befehl <[groups]> <name>
|
||||||
// befehl ist genau ein wort
|
// befehl ist genau ein wort
|
||||||
func parsemsg(msg irc_msg, foo bot) bool {
|
func parsemsg(msg *irc_msg, foo bot) bool {
|
||||||
if len(msg.msg) <= 0 {
|
if len((*msg).msg) <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !in(msg.msg[0], begin_char) {
|
if !in((*msg).msg[0], begin_char) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
msg.msg = msg.msg[1:]
|
(*msg).msg = (*msg).msg[1:]
|
||||||
|
|
||||||
c := filter(msg.msg, foo)
|
c := filter((*msg).msg, foo)
|
||||||
if !c.valid {
|
if !c.valid {
|
||||||
LOG_WARN.Printf("non valid input found.\n")
|
LOG_WARN.Printf("non valid input found.\n")
|
||||||
if c.error != "" {
|
if c.error != "" {
|
||||||
sendmsg(foo.conn, msg.channel, "Falscher input du SP-Ersti... " + c.error)
|
(*msg).retmsg = "Falscher input du SP-Ersti... " + c.error
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -205,141 +332,27 @@ func parsemsg(msg irc_msg, foo bot) bool {
|
||||||
// hard code 'groups' to add new groups to the groups-table
|
// hard code 'groups' to add new groups to the groups-table
|
||||||
if c.add && (c.cmd == "groups" || c.cmd == "group") {
|
if c.add && (c.cmd == "groups" || c.cmd == "group") {
|
||||||
if (c.groups != nil) {
|
if (c.groups != nil) {
|
||||||
sendmsg(foo.conn, msg.channel, "Ignoring groups for the groups-adding. Well, what were you expecting...?")
|
(*msg).retmsg = "Ignoring groups for the groups-adding. Well, what were you expecting...?"
|
||||||
}
|
|
||||||
new_groups := strings.Fields(c.suffix)
|
|
||||||
stat_sel, err := db.Prepare("select id from groups where name = ?")
|
|
||||||
checkErr(err)
|
|
||||||
stat_ins, err := db.Prepare("insert into groups(name) values (?)")
|
|
||||||
checkErr(err)
|
|
||||||
var groups_added []string
|
|
||||||
for _, group := range new_groups {
|
|
||||||
fmt.Println(group)
|
|
||||||
ret, err := stat_sel.Query(group)
|
|
||||||
if ret.Next() {
|
|
||||||
ret.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, err = stat_ins.Exec(group)
|
|
||||||
checkErr(err)
|
|
||||||
groups_added = append(groups_added, group)
|
|
||||||
}
|
|
||||||
if len(groups_added) > 0 {
|
|
||||||
sendmsg(foo.conn, msg.channel, "Added " + strings.Join(groups_added, ", ") + " to groups-table!")
|
|
||||||
} else {
|
|
||||||
sendmsg(foo.conn, msg.channel, "Added nothing to groups-table! :(")
|
|
||||||
}
|
}
|
||||||
|
addgroups(strings.Fields((&c).suffix), msg)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sorter_row, err := db.Query(fmt.Sprintf("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = '%s'", c.cmd))
|
// have a look at sorter table if command is valid
|
||||||
checkErr(err)
|
if !checkSorter(msg, &c) {
|
||||||
if sorter_row.Next() {
|
|
||||||
var sorter_id string
|
|
||||||
var tag_id string
|
|
||||||
var groups_allow int
|
|
||||||
var name_allow int
|
|
||||||
var has_groups int
|
|
||||||
sorter_row.Scan(&sorter_id, &tag_id, &groups_allow, &name_allow, &has_groups)
|
|
||||||
sorter_row.Close()
|
|
||||||
|
|
||||||
if groups_allow != 0 {
|
|
||||||
sendmsg(foo.conn, msg.channel, "This command does not allow groups. :(")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if name_allow != 0 && !c.add {
|
|
||||||
// warning: not allowed
|
|
||||||
c.suffix = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cmd = tag_id
|
|
||||||
|
|
||||||
if has_groups == 0 {
|
|
||||||
sorter_groups_row, err := db.Query(fmt.Sprintf("select group_id from sorter_groups where sorter_id = '%s'", sorter_id))
|
|
||||||
checkErr(err)
|
|
||||||
if sorter_groups_row.Next() {
|
|
||||||
var group_id int
|
|
||||||
sorter_groups_row.Scan(&group_id)
|
|
||||||
c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
|
|
||||||
}
|
|
||||||
sorter_groups_row.Close()
|
|
||||||
if c.add {
|
|
||||||
var tag_name string
|
|
||||||
tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %d", tag_id))
|
|
||||||
checkErr(err)
|
|
||||||
if tag_name_row.Next() {
|
|
||||||
tag_name_row.Scan(&tag_name)
|
|
||||||
}
|
|
||||||
tag_name_row.Close()
|
|
||||||
LOG_WARN.Printf("Alias used. Tell the user about that.\n")
|
|
||||||
sendmsg(foo.conn, msg.channel, "You're using an alias. Please try again with 'add " + tag_name + " [" + strings.Join(c.groups, " ") + "]. Thanks!")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG_WARN.Printf("no sorter entry, no translation possible\n")
|
|
||||||
sendmsg(foo.conn, msg.channel, "No entry found, sorry...")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new line for database
|
||||||
if c.add {
|
if c.add {
|
||||||
// if there is nothing to add, just return. :-)
|
// if there is nothing to add, just return. :-)
|
||||||
if (len(c.suffix) <= 0) {
|
if (len(c.suffix) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
c.suffix = strings.Replace(c.suffix,"\"","'", -1)
|
c.suffix = strings.Replace(c.suffix,"\"","'", -1)
|
||||||
LOG_WARN.Printf("adding new stuff: %s from %s.\n", c.suffix, msg.author)
|
sendmsg(foo.conn, "horscchtey", addLine(msg, c.suffix, c.groups, c.cmd))
|
||||||
|
|
||||||
res, err := db.Exec("insert into line (content, author) values (?,?)", c.suffix, msg.author)
|
|
||||||
checkErr(err)
|
|
||||||
LOG_WARN.Printf("added line to table.\n")
|
|
||||||
|
|
||||||
// get ID of content...
|
|
||||||
line_id, err := res.LastInsertId();
|
|
||||||
checkErr(err)
|
|
||||||
|
|
||||||
LOG_WARN.Printf("line_id: %d, tag_id: %d, groups: %s\n", line_id, c.cmd, strings.Join(c.groups, "-"))
|
|
||||||
// for tag and all groups
|
|
||||||
if len(c.groups) == 0 {
|
|
||||||
stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)")
|
|
||||||
checkErr(err)
|
|
||||||
_, err = stat.Exec(line_id, c.cmd)
|
|
||||||
checkErr(err)
|
|
||||||
LOG_INFO.Printf("inserted foo! \n")
|
|
||||||
defer stat.Close()
|
|
||||||
} else {
|
} else {
|
||||||
stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)")
|
chooseEntry(msg, &c)
|
||||||
checkErr(err)
|
|
||||||
for _, group := range c.groups {
|
|
||||||
_, err = stat.Exec(line_id, c.cmd, group)
|
|
||||||
checkErr(err)
|
|
||||||
}
|
}
|
||||||
LOG_INFO.Printf("inserted foo! \n")
|
|
||||||
defer stat.Close()
|
|
||||||
}
|
|
||||||
sendmsg(foo.conn, msg.channel, fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id))
|
|
||||||
sendmsg(foo.conn, "horscchtey", fmt.Sprintf("new line: > %s < (ID %d), into groups %s", c.suffix, line_id, strings.Join(c.groups,",")))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
task := getRandomEntry(c)
|
|
||||||
|
|
||||||
LOG_INFO.Printf(task)
|
|
||||||
row, err := db.Query(task)
|
|
||||||
checkErr(err)
|
|
||||||
res := ""
|
|
||||||
if row.Next() {
|
|
||||||
row.Scan(&res)
|
|
||||||
}
|
|
||||||
row.Close()
|
|
||||||
|
|
||||||
if len(res) <= 0 {
|
|
||||||
LOG_WARN.Printf("no entry found\n")
|
|
||||||
res = "No matching entry found :("
|
|
||||||
} else if len(c.suffix) > 0 {
|
|
||||||
res = fmt.Sprintf("%s... %s", c.suffix, res)
|
|
||||||
}
|
|
||||||
sendmsg(foo.conn, msg.channel, res)
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
bot.go
6
bot.go
|
|
@ -31,12 +31,6 @@ func main() {
|
||||||
if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil {
|
if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
// boddle := bot {
|
|
||||||
// name: "boddle",
|
|
||||||
// channel: []string{"#faui2k16", "#fau", "#sigbike", "#sigfreibad"},
|
|
||||||
// port: 6667,
|
|
||||||
// server: "irc.fau.de",
|
|
||||||
// }
|
|
||||||
|
|
||||||
LOG_INFO.Println("bot started!")
|
LOG_INFO.Println("bot started!")
|
||||||
|
|
||||||
|
|
|
||||||
8
conf.go
Normal file
8
conf.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Boddle struct {
|
||||||
|
name string `cfg:"name; boddle; printableascii; IRC nick of bot"`
|
||||||
|
channels []string `cfg:"channels; required; printableascii; Channel list to join to"`
|
||||||
|
server string `cfg:"server; required; netaddr; Server name to connect to"`
|
||||||
|
database string `cfg:"database; ./boddle.db; path; Path to database"`
|
||||||
|
}
|
||||||
15
ircfoo.go
15
ircfoo.go
|
|
@ -32,6 +32,7 @@ func scanline_privmsg (msg string) irc_msg {
|
||||||
if ! strings.HasPrefix(irc.channel, "#") {
|
if ! strings.HasPrefix(irc.channel, "#") {
|
||||||
irc.channel = irc.author
|
irc.channel = irc.author
|
||||||
}
|
}
|
||||||
|
irc.retmsg = ""
|
||||||
return irc
|
return irc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,12 +45,9 @@ func listenToIRC (foo bot) <-chan []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var line []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
line, err = reader.ReadBytes('\n')
|
line, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LOG_ERR.Printf("Error while reading bytes from connection.\n")
|
LOG_ERR.Printf("Error while reading bytes from connection.\n")
|
||||||
dead = true
|
dead = true
|
||||||
|
|
@ -57,7 +55,7 @@ func listenToIRC (foo bot) <-chan []byte {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c <- line
|
c <- []byte(line)
|
||||||
|
|
||||||
if bytes.Contains([]byte(line), []byte("PING :")) {
|
if bytes.Contains([]byte(line), []byte("PING :")) {
|
||||||
v := []byte(bytes.Replace([]byte(line), []byte("PING"), []byte("PONG"), 1))
|
v := []byte(bytes.Replace([]byte(line), []byte("PING"), []byte("PONG"), 1))
|
||||||
|
|
@ -69,8 +67,11 @@ func listenToIRC (foo bot) <-chan []byte {
|
||||||
if !bytes.Contains([]byte(line), []byte("PRIVMSG")) {
|
if !bytes.Contains([]byte(line), []byte("PRIVMSG")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
msg := scanline_privmsg(string(line))
|
||||||
parsemsg(scanline_privmsg(string(line)), foo)
|
parsemsg(&msg, foo)
|
||||||
|
if msg.retmsg != "" {
|
||||||
|
sendmsg(foo.conn, msg.channel, msg.retmsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} ()
|
} ()
|
||||||
return c
|
return c
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue