users can list incoming message ids

master
Jordan Orelli 10 years ago
parent b8e2800df2
commit 4b4b44f448

@ -285,6 +285,8 @@ func (c *Client) exec(line string) {
c.fetchKey(parts[1:])
case "msg/send":
c.sendMessage(parts[1:])
case "msg/list":
c.listMessages(parts[1:])
default:
c.err("unrecognized client command: %s", parts[0])
}
@ -497,6 +499,42 @@ func (c *Client) sendMessage(args []string) {
c.info("%v", <-res)
}
func (c *Client) listMessages(args []string) {
r := &ListMessages{N: 10}
promise, err := c.sendRequest(r)
if err != nil {
c.err("%v", err)
}
env := <-promise
writeMessageId := func(id int, from string) {
c.mu.Lock()
defer c.mu.Unlock()
c.trunc()
fmt.Printf("%d\t%s\n", id, from)
c.renderLine()
}
var res ListMessagesResponse
if err := json.Unmarshal(env.Body, &res); err != nil {
c.err("couldn't read list messages response: %v", err)
return
}
for _, item := range res {
key, err := c.rsaDecrypt(item.Key)
if err != nil {
c.err("unable to read aes key: %v", err)
return
}
from, err := c.aesDecrypt(key, item.From)
if err != nil {
c.err("unable to read message sender: %v", err)
return
}
writeMessageId(item.Id, string(from))
}
}
func (c *Client) readTextBlock() ([]rune, error) {
// god dammit what have i gotten myself into
msg := make([]rune, 0, 400)
@ -642,6 +680,10 @@ func (c *Client) aesEncrypt(key []byte, ptxt []byte) ([]byte, error) {
return ctxt, nil
}
func (c *Client) rsaDecrypt(ctext []byte) ([]byte, error) {
return rsa.DecryptPKCS1v15(rand.Reader, c.key, ctext)
}
func connect() {
if !terminal.IsTerminal(0) {
exit(1, "yeah, this only works from a TTY for now, sry.")

34
db.go

@ -1,6 +1,7 @@
package main
import (
"bytes"
"crypto/rsa"
"encoding/json"
"fmt"
@ -51,6 +52,39 @@ func (db *userdb) nextKey(prefix string) (string, error) {
return fmt.Sprintf("%s%s", prefix, encodeInt(id)), nil
}
// iterates through a range of values, starting with a prefix, parsing the
// lexnum part on each key, and calling the callback for each value with the
// value's associated number in its lexical series
func (db *userdb) collect(prefix []byte, n int, fn func(n int, v []byte) error) error {
r := util.BytesPrefix(prefix)
it := db.NewIterator(r, nil)
defer it.Release()
var step func() bool
if n < 0 {
if !it.Last() {
return fmt.Errorf("collect unable to advance iterator to last")
}
step = it.Prev
n = -n
} else {
step = it.Next
}
for i := 0; it.Valid() && i < n; i++ {
id_s := string(bytes.TrimPrefix(it.Key(), prefix))
id, err := decodeInt(id_s)
if err != nil {
return fmt.Errorf("unable to collect on prefix %s: %v", prefix, err)
}
if err := fn(id, it.Value()); err != nil {
return fmt.Errorf("callback error in collect: %v", err)
}
step()
}
return nil
}
func getUserDB(nick string, create bool) (*userdb, error) {
if db, ok := openDBs[nick]; ok {
return &db, nil

@ -54,6 +54,8 @@ func (s *serverConnection) handleRequest(request Envelope) error {
return s.handleKeyRequest(request.Id, request.Body)
case "message":
return s.handleMessageRequest(request.Id, request.Body)
case "list-messages":
return s.handleListMessagesRequest(request.Id, request.Body)
default:
return fmt.Errorf("no such request type: %v", request.Kind)
}
@ -233,6 +235,33 @@ func (s *serverConnection) handleMessageRequest(requestId int, body json.RawMess
return s.sendResponse(requestId, Bool(true))
}
func (s *serverConnection) handleListMessagesRequest(requestId int, body json.RawMessage) error {
var req ListMessages
if err := json.Unmarshal(body, &req); err != nil {
error_log.Printf("unable to read message request: %v", err)
return err
}
prefix := []byte("messages/")
messages := make(ListMessagesResponse, 0, 10)
fn := func(n int, v []byte) error {
var msg Message
if err := json.Unmarshal(v, &msg); err != nil {
return fmt.Errorf("unable to parse message blob: %v", err)
}
messages = append(messages, ListMessagesResponseItem{
Id: n,
Key: msg.Key,
From: msg.From,
})
return nil
}
if err := s.db.collect(prefix, -10, fn); err != nil {
return fmt.Errorf("error handling listmessages request: %v", err)
}
return s.sendResponse(requestId, messages)
}
func (s *serverConnection) openDB() error {
db, err := getUserDB(s.nick, true)
if err != nil {

Loading…
Cancel
Save