¶
+
+
+
+Request list of channels and users that client can send messages to. Number of retrieved items can be limited using count and offset fields.¶
+
+ Table 13
+
+
+ | Type |
+ Name |
+
+
+
+
+ | int64 |
+ count |
+
+
+ | int64 |
+ offset |
+
+
+
+
+
+
+
+
+ListItem is send as a reply to List request. Multiple list items are sent in separate payloads.¶
+
+ Table 14
+
+
+ | Type |
+ Name |
+
+
+
+
+ | string |
+ address |
+
+
+
+
+
diff --git a/docs/rfc.md b/docs/rfc.md
index d6c8085..ecfbdc0 100644
--- a/docs/rfc.md
+++ b/docs/rfc.md
@@ -161,9 +161,11 @@ Payload type attributes describes following characteristics:
| 0x03 | Handshake | SC |
| 0x04 | UserAuth | C |
| 0x05 | Message | SC |
-| 0x06 | ServerAuth | S |
-| 0x07 | UserMode | C |
-| 0x08 | History. | C |
+| 0x06 | ServerAuth | S |
+| 0x07 | UserMode | C |
+| 0x08 | History | C |
+| 0x09 | List | CE |
+| 0x10 | ListItem | S |
| 0xFF | Test | R |
### Success
@@ -273,6 +275,24 @@ should ignore this kind of payload.
| string | str3 |
| uint64 | num4 |
+### List
+
+Request list of channels and users that client can send messages to. Number of retrieved items can be limited using *count* and *offset* fields.
+
+| Type | Name |
+|-----------|-----------------|
+| int64 | count |
+| int64 | offset |
+
+### ListItem
+
+*ListItem* is send as a reply to *List* request. Multiple list items are sent in separate payloads.
+
+| Type | Name |
+|--------|---------|
+| string | address |
+
+
## Sequential operations
Some operations require multiple rounds of communication.
diff --git a/docs/rfc.txt b/docs/rfc.txt
index 335ea3d..173c1bd 100644
--- a/docs/rfc.txt
+++ b/docs/rfc.txt
@@ -35,6 +35,8 @@ Table of Contents
2.4.7. Usermode
2.4.8. History
2.4.9. Test
+ 2.4.10. List
+ 2.4.11. ListItem
2.5. Sequential operations
2.6. Client-Server connection initialisation
2.7. Exchanging messages between servers
@@ -180,7 +182,11 @@ Table of Contents
+------+------------+------------+
| 0x07 | UserMode | C |
+------+------------+------------+
- | 0x08 | History. | C |
+ | 0x08 | History | C |
+ +------+------------+------------+
+ | 0x09 | List | CE |
+ +------+------------+------------+
+ | 0x10 | ListItem | S |
+------+------------+------------+
| 0xFF | Test | R |
+------+------------+------------+
@@ -368,6 +374,35 @@ Table of Contents
Table 12
+2.4.10. List
+
+ Request list of channels and users that client can send messages to.
+ Number of retrieved items can be limited using _count_ and _offset_
+ fields.
+
+ +=======+========+
+ | Type | Name |
+ +=======+========+
+ | int64 | count |
+ +-------+--------+
+ | int64 | offset |
+ +-------+--------+
+
+ Table 13
+
+2.4.11. ListItem
+
+ _ListItem_ is send as a reply to _List_ request. Multiple list items
+ are sent in separate payloads.
+
+ +========+=========+
+ | Type | Name |
+ +========+=========+
+ | string | address |
+ +--------+---------+
+
+ Table 14
+
2.5. Sequential operations
Some operations require multiple rounds of communication. In this
diff --git a/server/storage.go b/server/storage.go
index 99402c8..bffb783 100644
--- a/server/storage.go
+++ b/server/storage.go
@@ -8,8 +8,8 @@ import (
type Storage interface {
AddMessage(msg core.Message) (err error)
- GetHistory(target string, since time.Time, num, offset int) (history []core.Message, err error)
- GetHistoryUser(user1, user2 string, since time.Time, num, offset int) (history []core.Message, err error)
+ GetHistory(target string, since time.Time, count, offset int) (history []core.Message, err error)
+ GetHistoryUser(user1, user2 string, since time.Time, count, offset int) (history []core.Message, err error)
SetUser(user core.UserData) error
DelUser(name string) error
@@ -17,5 +17,7 @@ type Storage interface {
SetPermission(data core.PermissionData) error
GetPermission(user, channel string) (core.PermissionData, error)
+
GetChannelUsers(channel string) ([]string, error)
+ GetUserChannels(user string, count, offset int) ([]string, error)
}
diff --git a/server/user.go b/server/user.go
index 69b7ced..5e29c8d 100644
--- a/server/user.go
+++ b/server/user.go
@@ -126,6 +126,8 @@ func (s *Server) handleUserPayload(user *User, sender net.Conn, payload any) err
return s.handleUsermode(user, sender, v)
case core.History:
return s.handleHistory(user, sender, v)
+ case core.List:
+ return s.handleList(user, sender, v)
default:
return core.ErrUnexpectedPayloadType
}
@@ -206,3 +208,23 @@ func (s *Server) handleHistory(user *User, conn net.Conn, hist core.History) err
return nil
}
+
+func (s *Server) handleList(user *User, conn net.Conn, list core.List) error {
+ channels, err := s.Storage.GetUserChannels(user.Addr, int(list.Count), int(list.Offset))
+ if err != nil {
+ return fmt.Errorf("cannot get user channels list: %v", err)
+ }
+
+ for _, c := range channels {
+ li := core.ListItem{c}
+ data, err := core.Encode(li)
+ if err != nil {
+ return err
+ }
+ if _, err := conn.Write(data); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/storage/storage.go b/storage/storage.go
index a32c4a0..6455876 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -169,6 +169,31 @@ func (db *Database) GetChannelUsers(channel string) (users []string, err error)
return users, nil
}
+func (db *Database) GetUserChannels(user string, count, offset int) (channels []string, err error) {
+ rows, err := db.Query("SELECT channel FROM permissions WHERE user = ? AND write = 1;", user)
+ defer func() {
+ if rows == nil {
+ return
+ }
+ if err := rows.Close(); err != nil {
+ log.Println("cannot close database row:", err)
+ }
+ }()
+ if err != nil {
+ return channels, err
+ }
+
+ for rows.Next() {
+ var channel string
+ if err := rows.Scan(&channel); err != nil {
+ return channels, err
+ }
+ channels = append(channels, channel)
+ }
+
+ return channels, nil
+}
+
func itob(v int) bool {
if v == 1 {
return true
--
cgit v1.2.3