Remove the concept of numeric contact IDs

In ricochet-qt, contacts were stored with a sequential numeric ID, and
that was used in various places to refer to the contact uniquely. The
habit carried over here in an attempt to keep configuration
compatibility.

These IDs are error prone (particularly over RPC) and unnecessary. This
removes the entire concept and uses addresses to index and refer
uniquely to contacts everywhere.
This commit is contained in:
John Brooks 2017-09-24 15:55:47 -06:00
parent 32230b77c1
commit d8a14fb4c5
11 changed files with 132 additions and 230 deletions

View File

@ -10,7 +10,6 @@ import (
connection "github.com/s-rah/go-ricochet/connection" connection "github.com/s-rah/go-ricochet/connection"
"golang.org/x/net/context" "golang.org/x/net/context"
"log" "log"
"strconv"
"sync" "sync"
"time" "time"
) )
@ -18,7 +17,6 @@ import (
type Contact struct { type Contact struct {
core *Ricochet core *Ricochet
id int
data *ricochet.Contact data *ricochet.Contact
mutex sync.Mutex mutex sync.Mutex
@ -35,19 +33,16 @@ type Contact struct {
conversation *Conversation conversation *Conversation
} }
func ContactFromConfig(core *Ricochet, id int, data *ricochet.Contact, events *utils.Publisher) (*Contact, error) { func ContactFromConfig(core *Ricochet, data *ricochet.Contact, events *utils.Publisher) (*Contact, error) {
contact := &Contact{ contact := &Contact{
core: core, core: core,
id: id,
data: data, data: data,
events: events, events: events,
connChannel: make(chan *connection.Connection), connChannel: make(chan *connection.Connection),
connEnabledSignal: make(chan bool), connEnabledSignal: make(chan bool),
} }
if id < 0 { if !IsAddressValid(data.Address) {
return nil, fmt.Errorf("Invalid contact ID '%d'", id)
} else if !IsAddressValid(data.Address) {
return nil, fmt.Errorf("Invalid contact address '%s", data.Address) return nil, fmt.Errorf("Invalid contact address '%s", data.Address)
} }
@ -64,10 +59,6 @@ func ContactFromConfig(core *Ricochet, id int, data *ricochet.Contact, events *u
return contact, nil return contact, nil
} }
func (c *Contact) Id() int {
return c.id
}
func (c *Contact) Nickname() string { func (c *Contact) Nickname() string {
c.mutex.Lock() c.mutex.Lock()
defer c.mutex.Unlock() defer c.mutex.Unlock()
@ -124,7 +115,6 @@ func (c *Contact) Conversation() *Conversation {
defer c.mutex.Unlock() defer c.mutex.Unlock()
if c.conversation == nil { if c.conversation == nil {
entity := &ricochet.Entity{ entity := &ricochet.Entity{
ContactId: int32(c.id),
Address: c.data.Address, Address: c.data.Address,
} }
c.conversation = NewConversation(c, entity, c.core.Identity.ConversationStream) c.conversation = NewConversation(c, entity, c.core.Identity.ConversationStream)
@ -536,7 +526,7 @@ func (c *Contact) onConnectionStateChanged() {
c.data.LastConnected = c.timeConnected.Format(time.RFC3339) c.data.LastConnected = c.timeConnected.Format(time.RFC3339)
config := c.core.Config.Lock() config := c.core.Config.Lock()
config.Contacts[strconv.Itoa(c.id)] = c.data config.Contacts[c.data.Address] = c.data
c.core.Config.Unlock() c.core.Config.Unlock()
// XXX I wonder if events and config updates can be combined now, and made safer... // XXX I wonder if events and config updates can be combined now, and made safer...
@ -644,7 +634,7 @@ func (c *Contact) updateContactRequest(status string) bool {
config := c.core.Config.Lock() config := c.core.Config.Lock()
defer c.core.Config.Unlock() defer c.core.Config.Unlock()
config.Contacts[strconv.Itoa(c.id)] = c.data config.Contacts[c.data.Address] = c.data
return re return re
} }

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"github.com/ricochet-im/ricochet-go/core/utils" "github.com/ricochet-im/ricochet-go/core/utils"
"github.com/ricochet-im/ricochet-go/rpc" "github.com/ricochet-im/ricochet-go/rpc"
"strconv"
"sync" "sync"
"time" "time"
) )
@ -16,7 +15,7 @@ type ContactList struct {
mutex sync.RWMutex mutex sync.RWMutex
events *utils.Publisher events *utils.Publisher
contacts map[int]*Contact contacts map[string]*Contact
inboundRequests map[string]*InboundContactRequest inboundRequests map[string]*InboundContactRequest
} }
@ -28,21 +27,20 @@ func LoadContactList(core *Ricochet) (*ContactList, error) {
} }
config := core.Config.Read() config := core.Config.Read()
list.contacts = make(map[int]*Contact, len(config.Contacts)) list.contacts = make(map[string]*Contact, len(config.Contacts))
for idStr, data := range config.Contacts { for addr, data := range config.Contacts {
id, err := strconv.Atoi(idStr) if _, exists := list.contacts[addr]; exists {
if err != nil { return nil, fmt.Errorf("Duplicate contact %s", addr)
return nil, fmt.Errorf("Invalid contact id '%s'", idStr)
} }
if _, exists := list.contacts[id]; exists { if addr != data.Address {
return nil, fmt.Errorf("Duplicate contact id '%d'", id) return nil, fmt.Errorf("Contact address/key do not match ('%s' and '%s')", addr, data.Address)
} }
contact, err := ContactFromConfig(core, id, data, list.events) contact, err := ContactFromConfig(core, data, list.events)
if err != nil { if err != nil {
return nil, err return nil, err
} }
list.contacts[id] = contact list.contacts[addr] = contact
} }
return list, nil return list, nil
@ -62,32 +60,16 @@ func (this *ContactList) Contacts() []*Contact {
return re return re
} }
func (this *ContactList) ContactById(id int) *Contact { func (cl *ContactList) ContactByAddress(address string) *Contact {
this.mutex.RLock() cl.mutex.RLock()
defer this.mutex.RUnlock() defer cl.mutex.RUnlock()
return this.contacts[id] return cl.contacts[address]
}
func (this *ContactList) ContactByAddress(address string) *Contact {
this.mutex.RLock()
defer this.mutex.RUnlock()
for _, contact := range this.contacts {
if contact.Address() == address {
return contact
}
}
return nil
} }
func (cl *ContactList) InboundRequestByAddress(address string) *InboundContactRequest { func (cl *ContactList) InboundRequestByAddress(address string) *InboundContactRequest {
cl.mutex.RLock() cl.mutex.RLock()
defer cl.mutex.RUnlock() defer cl.mutex.RUnlock()
for _, request := range cl.inboundRequests { return cl.inboundRequests[address]
if request.Address == address {
return request
}
}
return nil
} }
// AddNewContact adds a new contact to the persistent contact list, broadcasts a // AddNewContact adds a new contact to the persistent contact list, broadcasts a
@ -101,10 +83,10 @@ func (this *ContactList) AddNewContact(data *ricochet.Contact) (*Contact, error)
this.mutex.Lock() this.mutex.Lock()
defer this.mutex.Unlock() defer this.mutex.Unlock()
for _, contact := range this.contacts { if this.contacts[data.Address] != nil {
if contact.Address() == data.Address {
return nil, errors.New("Contact already exists with this address") return nil, errors.New("Contact already exists with this address")
} }
for _, contact := range this.contacts {
if contact.Nickname() == data.Nickname { if contact.Nickname() == data.Nickname {
return nil, errors.New("Contact already exists with this nickname") return nil, errors.New("Contact already exists with this nickname")
} }
@ -114,30 +96,18 @@ func (this *ContactList) AddNewContact(data *ricochet.Contact) (*Contact, error)
// Write new contact into config // Write new contact into config
config := this.core.Config.Lock() config := this.core.Config.Lock()
maxContactId := 0
for idstr, _ := range config.Contacts {
if id, err := strconv.Atoi(idstr); err == nil {
if maxContactId < id {
maxContactId = id
}
}
}
contactId := maxContactId + 1
if config.Contacts == nil { if config.Contacts == nil {
config.Contacts = make(map[string]*ricochet.Contact) config.Contacts = make(map[string]*ricochet.Contact)
} }
config.Contacts[strconv.Itoa(contactId)] = data config.Contacts[data.Address] = data
this.core.Config.Unlock() this.core.Config.Unlock()
// Create Contact // Create Contact
contact, err := ContactFromConfig(this.core, contactId, data, this.events) contact, err := ContactFromConfig(this.core, data, this.events)
if err != nil { if err != nil {
return nil, err return nil, err
} }
this.contacts[contactId] = contact this.contacts[data.Address] = contact
event := ricochet.ContactEvent{ event := ricochet.ContactEvent{
Type: ricochet.ContactEvent_ADD, Type: ricochet.ContactEvent_ADD,
@ -201,7 +171,8 @@ func (this *ContactList) RemoveContact(contact *Contact) error {
this.mutex.Lock() this.mutex.Lock()
defer this.mutex.Unlock() defer this.mutex.Unlock()
if this.contacts[contact.Id()] != contact { address := contact.Address()
if this.contacts[address] != contact {
return errors.New("Not in contact list") return errors.New("Not in contact list")
} }
@ -211,17 +182,16 @@ func (this *ContactList) RemoveContact(contact *Contact) error {
contact.StopConnection() contact.StopConnection()
config := this.core.Config.Lock() config := this.core.Config.Lock()
delete(config.Contacts, strconv.Itoa(contact.Id())) delete(config.Contacts, address)
this.core.Config.Unlock() this.core.Config.Unlock()
delete(this.contacts, contact.Id()) delete(this.contacts, address)
event := ricochet.ContactEvent{ event := ricochet.ContactEvent{
Type: ricochet.ContactEvent_DELETE, Type: ricochet.ContactEvent_DELETE,
Subject: &ricochet.ContactEvent_Contact{ Subject: &ricochet.ContactEvent_Contact{
Contact: &ricochet.Contact{ Contact: &ricochet.Contact{
Id: int32(contact.Id()), Address: address,
Address: contact.Address(),
}, },
}, },
} }

View File

@ -139,7 +139,7 @@ func (s *RpcServer) UpdateContact(ctx context.Context, req *ricochet.Contact) (*
func (s *RpcServer) DeleteContact(ctx context.Context, req *ricochet.DeleteContactRequest) (*ricochet.DeleteContactReply, error) { func (s *RpcServer) DeleteContact(ctx context.Context, req *ricochet.DeleteContactRequest) (*ricochet.DeleteContactReply, error) {
contactList := s.Core.Identity.ContactList() contactList := s.Core.Identity.ContactList()
contact := contactList.ContactByAddress(req.Address) contact := contactList.ContactByAddress(req.Address)
if contact == nil || (req.Id != 0 && contact.Id() != int(req.Id)) { if contact == nil {
return nil, errors.New("Contact not found") return nil, errors.New("Contact not found")
} }
@ -239,7 +239,7 @@ func (s *RpcServer) SendMessage(ctx context.Context, req *ricochet.Message) (*ri
} }
contact := s.Core.Identity.ContactList().ContactByAddress(req.Recipient.Address) contact := s.Core.Identity.ContactList().ContactByAddress(req.Recipient.Address)
if contact == nil || (req.Recipient.ContactId != 0 && int32(contact.Id()) != req.Recipient.ContactId) { if contact == nil {
return nil, errors.New("Unknown recipient") return nil, errors.New("Unknown recipient")
} }
@ -261,7 +261,7 @@ func (s *RpcServer) MarkConversationRead(ctx context.Context, req *ricochet.Mark
} }
contact := s.Core.Identity.ContactList().ContactByAddress(req.Entity.Address) contact := s.Core.Identity.ContactList().ContactByAddress(req.Entity.Address)
if contact == nil || (req.Entity.ContactId != 0 && int32(contact.Id()) != req.Entity.ContactId) { if contact == nil {
return nil, errors.New("Unknown entity") return nil, errors.New("Unknown entity")
} }

View File

@ -211,7 +211,7 @@ func (c *Client) onContactEvent(event *ricochet.ContactEvent) {
return return
} }
contact := c.Contacts.ByIdAndAddress(data.Id, data.Address) contact := c.Contacts.ByAddress(data.Address)
if contact == nil { if contact == nil {
log.Printf("Ignoring contact update event for unknown contact: %v", data) log.Printf("Ignoring contact update event for unknown contact: %v", data)
} else { } else {
@ -257,7 +257,7 @@ func (c *Client) onConversationEvent(event *ricochet.ConversationEvent) {
remoteEntity = message.Recipient remoteEntity = message.Recipient
} }
remoteContact := c.Contacts.ByIdAndAddress(remoteEntity.ContactId, remoteEntity.Address) remoteContact := c.Contacts.ByAddress(remoteEntity.Address)
if remoteContact == nil { if remoteContact == nil {
log.Printf("Ignoring conversation event with unknown contact: %v", event) log.Printf("Ignoring conversation event with unknown contact: %v", event)
return return

View File

@ -8,60 +8,48 @@ import (
type ContactList struct { type ContactList struct {
Client *Client Client *Client
Contacts map[int32]*Contact Contacts map[string]*Contact
} }
func NewContactList(client *Client) *ContactList { func NewContactList(client *Client) *ContactList {
return &ContactList{ return &ContactList{
Client: client, Client: client,
Contacts: make(map[int32]*Contact), Contacts: make(map[string]*Contact),
} }
} }
func (cl *ContactList) Populate(data *ricochet.Contact) error { func (cl *ContactList) Populate(data *ricochet.Contact) error {
if cl.Contacts[data.Id] != nil { if cl.Contacts[data.Address] != nil {
return fmt.Errorf("Duplicate contact ID %d in populate", data.Id) return fmt.Errorf("Duplicate contact %s in populate", data.Address)
} }
cl.Contacts[data.Id] = initContact(cl.Client, data) cl.Contacts[data.Address] = initContact(cl.Client, data)
return nil return nil
} }
func (cl *ContactList) Added(data *ricochet.Contact) (*Contact, error) { func (cl *ContactList) Added(data *ricochet.Contact) (*Contact, error) {
if cl.Contacts[data.Id] != nil { if cl.Contacts[data.Address] != nil {
return nil, fmt.Errorf("Duplicate contact ID %d in add", data.Id) return nil, fmt.Errorf("Duplicate contact %s in add", data.Address)
} }
contact := initContact(cl.Client, data) contact := initContact(cl.Client, data)
cl.Contacts[data.Id] = contact cl.Contacts[data.Address] = contact
return contact, nil return contact, nil
} }
func (cl *ContactList) Deleted(data *ricochet.Contact) (*Contact, error) { func (cl *ContactList) Deleted(data *ricochet.Contact) (*Contact, error) {
contact := cl.Contacts[data.Id] contact := cl.Contacts[data.Address]
if contact == nil { if contact == nil {
return nil, fmt.Errorf("Contact ID %d does not exist in delete", data.Id) return nil, fmt.Errorf("Contact %s does not exist in delete", data.Address)
}
if contact.Data.Address != data.Address {
return nil, fmt.Errorf("Contact ID %d does not match address in delete (expected %s, received %s)", data.Id, contact.Data.Address, data.Address)
} }
contact.Deleted() contact.Deleted()
delete(cl.Contacts, data.Id) delete(cl.Contacts, data.Address)
return contact, nil return contact, nil
} }
func (cl *ContactList) ById(id int32) *Contact { func (cl *ContactList) ByAddress(address string) *Contact {
return cl.Contacts[id] return cl.Contacts[address]
}
func (cl *ContactList) ByIdAndAddress(id int32, address string) *Contact {
contact := cl.Contacts[id]
if contact != nil && contact.Data.Address == address {
return contact
}
return nil
} }
type Contact struct { type Contact struct {
@ -81,8 +69,8 @@ func initContact(client *Client, data *ricochet.Contact) *Contact {
} }
func (c *Contact) Updated(newData *ricochet.Contact) error { func (c *Contact) Updated(newData *ricochet.Contact) error {
if newData.Id != c.Data.Id || newData.Address != c.Data.Address { if newData.Address != c.Data.Address {
return errors.New("Contact ID and address are immutable") return errors.New("Contact address is immutable")
} }
c.Data = newData c.Data = newData
@ -91,7 +79,6 @@ func (c *Contact) Updated(newData *ricochet.Contact) error {
func (c *Contact) Deleted() { func (c *Contact) Deleted() {
c.Data = &ricochet.Contact{ c.Data = &ricochet.Contact{
Id: c.Data.Id,
Address: c.Data.Address, Address: c.Data.Address,
} }
} }

View File

@ -36,10 +36,7 @@ type Conversation struct {
func (c *Conversation) SendMessage(text string) error { func (c *Conversation) SendMessage(text string) error {
msg, err := c.Client.Backend.SendMessage(context.Background(), &ricochet.Message{ msg, err := c.Client.Backend.SendMessage(context.Background(), &ricochet.Message{
Sender: &ricochet.Entity{IsSelf: true}, Sender: &ricochet.Entity{IsSelf: true},
Recipient: &ricochet.Entity{ Recipient: &ricochet.Entity{Address: c.Contact.Data.Address},
ContactId: c.Contact.Data.Id,
Address: c.Contact.Data.Address,
},
Text: text, Text: text,
}) })
if err != nil { if err != nil {
@ -213,13 +210,12 @@ func (c *Conversation) validateMessage(msg *ricochet.Message) error {
remoteEntity = msg.Sender remoteEntity = msg.Sender
} }
if !localEntity.IsSelf || localEntity.ContactId != 0 || if !localEntity.IsSelf ||
(len(localEntity.Address) > 0 && localEntity.Address != c.Client.Identity.Address) { (len(localEntity.Address) > 0 && localEntity.Address != c.Client.Identity.Address) {
return fmt.Errorf("Invalid self entity on message: %v", localEntity) return fmt.Errorf("Invalid self entity on message: %v", localEntity)
} }
if remoteEntity.IsSelf || remoteEntity.ContactId != c.Contact.Data.Id || if remoteEntity.IsSelf || remoteEntity.Address != c.Contact.Data.Address {
remoteEntity.Address != c.Contact.Data.Address {
return fmt.Errorf("Invalid remote entity on message: %v", remoteEntity) return fmt.Errorf("Invalid remote entity on message: %v", remoteEntity)
} }

View File

@ -8,7 +8,6 @@ import (
"github.com/ricochet-im/ricochet-go/rpc" "github.com/ricochet-im/ricochet-go/rpc"
"golang.org/x/net/context" "golang.org/x/net/context"
"io" "io"
"strconv"
"strings" "strings"
"time" "time"
) )
@ -227,20 +226,15 @@ func (ui *UI) AddContact(params []string) {
return return
} }
fmt.Fprintf(ui.Stdout, "Added contact \x1b[1m%s\x1b[0m (\x1b[1m%d\x1b[0m)\n", contact.Nickname, contact.Id) fmt.Fprintf(ui.Stdout, "Added contact \x1b[1m%s\x1b[0m (\x1b[1m%s\x1b[0m)\n", contact.Nickname, contact.Address)
} }
func (ui *UI) DeleteContact(params []string) { func (ui *UI) DeleteContact(params []string) {
if len(params) < 1 { if len(params) < 1 {
fmt.Fprintf(ui.Stdout, "Usage: delete-contact [id]\n") fmt.Fprintf(ui.Stdout, "Usage: delete-contact [address]\n")
return return
} }
id, err := strconv.Atoi(params[0]) contact := ui.Client.Contacts.ByAddress(params[0])
if err != nil {
fmt.Fprintf(ui.Stdout, "Invalid contact id '%s'\n", params[0])
return
}
contact := ui.Client.Contacts.ById(int32(id))
if contact == nil { if contact == nil {
contact = ui.ContactByPrefix(params[0]) contact = ui.ContactByPrefix(params[0])
} }
@ -261,10 +255,7 @@ func (ui *UI) DeleteContact(params []string) {
} }
_, err = ui.Client.Backend.DeleteContact(context.Background(), _, err = ui.Client.Backend.DeleteContact(context.Background(),
&ricochet.DeleteContactRequest{ &ricochet.DeleteContactRequest{Address: contact.Data.Address})
Id: contact.Data.Id,
Address: contact.Data.Address,
})
if err != nil { if err != nil {
fmt.Fprintf(ui.Stdout, "Failed: %s\n", err) fmt.Fprintf(ui.Stdout, "Failed: %s\n", err)
return return

View File

@ -141,7 +141,6 @@ func (x ContactEvent_Type) String() string {
func (ContactEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} } func (ContactEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} }
type Contact struct { type Contact struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"` Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
Nickname string `protobuf:"bytes,3,opt,name=nickname" json:"nickname,omitempty"` Nickname string `protobuf:"bytes,3,opt,name=nickname" json:"nickname,omitempty"`
WhenCreated string `protobuf:"bytes,4,opt,name=whenCreated" json:"whenCreated,omitempty"` WhenCreated string `protobuf:"bytes,4,opt,name=whenCreated" json:"whenCreated,omitempty"`
@ -155,13 +154,6 @@ func (m *Contact) String() string { return proto.CompactTextString(m)
func (*Contact) ProtoMessage() {} func (*Contact) ProtoMessage() {}
func (*Contact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*Contact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Contact) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *Contact) GetAddress() string { func (m *Contact) GetAddress() string {
if m != nil { if m != nil {
return m.Address return m.Address
@ -438,8 +430,7 @@ func (*AddContactReply) ProtoMessage() {}
func (*AddContactReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*AddContactReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
type DeleteContactRequest struct { type DeleteContactRequest struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` Address string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
} }
func (m *DeleteContactRequest) Reset() { *m = DeleteContactRequest{} } func (m *DeleteContactRequest) Reset() { *m = DeleteContactRequest{} }
@ -447,13 +438,6 @@ func (m *DeleteContactRequest) String() string { return proto.Compact
func (*DeleteContactRequest) ProtoMessage() {} func (*DeleteContactRequest) ProtoMessage() {}
func (*DeleteContactRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*DeleteContactRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *DeleteContactRequest) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *DeleteContactRequest) GetAddress() string { func (m *DeleteContactRequest) GetAddress() string {
if m != nil { if m != nil {
return m.Address return m.Address
@ -494,42 +478,41 @@ func init() {
func init() { proto.RegisterFile("contact.proto", fileDescriptor0) } func init() { proto.RegisterFile("contact.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 581 bytes of a gzipped FileDescriptorProto // 569 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x54, 0xdd, 0x6e, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x54, 0x5d, 0x73, 0x93, 0x40,
0x14, 0x5e, 0xda, 0x2c, 0x3f, 0xa7, 0x5b, 0xc9, 0xac, 0x09, 0x85, 0xed, 0x26, 0xb2, 0x10, 0xea, 0x14, 0x2d, 0x01, 0xf9, 0xb8, 0x69, 0x2b, 0xdd, 0xe9, 0x38, 0xd8, 0xbe, 0x64, 0x76, 0x1c, 0x27,
0x0d, 0x01, 0x15, 0xee, 0xd9, 0xd6, 0x64, 0xa2, 0x50, 0x92, 0xe1, 0x25, 0xe2, 0x3a, 0x4b, 0x8c, 0x2f, 0x62, 0xa7, 0xfa, 0xae, 0x6d, 0xa0, 0x63, 0x34, 0x42, 0xdd, 0xc2, 0xf8, 0x4c, 0x61, 0x9d,
0x16, 0xe8, 0xe2, 0xe2, 0xb8, 0x83, 0xbd, 0x06, 0x4f, 0xc5, 0xe3, 0xf0, 0x08, 0xc8, 0x4e, 0xd2, 0xa2, 0x29, 0x1b, 0x97, 0x4d, 0x35, 0x7f, 0xc3, 0x5f, 0xe3, 0xcf, 0xf2, 0x27, 0x38, 0xbb, 0x40,
0xad, 0x2b, 0x20, 0xc4, 0x9d, 0xcf, 0x77, 0xbe, 0x63, 0x1f, 0x7f, 0xdf, 0xb1, 0x61, 0x37, 0x67, 0x9a, 0x0f, 0xf5, 0xc1, 0xb7, 0xbd, 0xe7, 0x9e, 0x0b, 0x87, 0x7b, 0xce, 0x02, 0x7b, 0x39, 0xab,
0x95, 0xc8, 0x72, 0xe1, 0x2f, 0x38, 0x13, 0x0c, 0x59, 0xbc, 0xcc, 0x59, 0x7e, 0x49, 0x05, 0xfe, 0x44, 0x96, 0x0b, 0x7f, 0xc6, 0x99, 0x60, 0xc8, 0xe6, 0x65, 0xce, 0xf2, 0x1b, 0x2a, 0xf0, 0xcf,
0xd1, 0x03, 0x73, 0xd2, 0xe4, 0xd0, 0x10, 0x7a, 0x65, 0xe1, 0x6a, 0x9e, 0x36, 0xda, 0x26, 0xbd, 0x1e, 0x58, 0xa3, 0xa6, 0x87, 0x3c, 0xb0, 0xb2, 0xa2, 0xe0, 0xb4, 0xae, 0xbd, 0xde, 0x40, 0x1b,
0xb2, 0x40, 0x2e, 0x98, 0x59, 0x51, 0x70, 0x5a, 0xd7, 0x6e, 0xcf, 0xd3, 0x46, 0x36, 0xe9, 0x42, 0x3a, 0xa4, 0x2b, 0xd1, 0x11, 0xd8, 0x55, 0x99, 0x7f, 0xa9, 0xb2, 0x5b, 0xea, 0xe9, 0xaa, 0xb5,
0x74, 0x00, 0x56, 0x55, 0xe6, 0x9f, 0xab, 0xec, 0x8a, 0xba, 0x7d, 0x95, 0x5a, 0xc5, 0xc8, 0x83, 0xac, 0xd1, 0x00, 0xfa, 0xdf, 0x6e, 0x68, 0x35, 0xe2, 0x34, 0x13, 0xb4, 0xf0, 0x0c, 0xd5, 0x5e,
0xc1, 0xd7, 0x4b, 0x5a, 0x4d, 0x38, 0xcd, 0x04, 0x2d, 0x5c, 0x5d, 0xa5, 0xef, 0x42, 0xe8, 0x31, 0x85, 0xd0, 0x13, 0xd8, 0x9b, 0x66, 0xb5, 0x18, 0xb1, 0xaa, 0xa2, 0xb9, 0xe4, 0x3c, 0x50, 0x9c,
0xec, 0xce, 0xb3, 0x5a, 0x4c, 0x58, 0x55, 0xd1, 0x5c, 0x72, 0xb6, 0x15, 0x67, 0x1d, 0x44, 0x63, 0x75, 0x10, 0x9d, 0x82, 0xc5, 0xe9, 0xd7, 0x39, 0xad, 0x85, 0x67, 0x0e, 0xb4, 0x61, 0xff, 0xd4,
0x30, 0x39, 0xfd, 0xb2, 0xa4, 0xb5, 0x70, 0x0d, 0x4f, 0x1b, 0x0d, 0xc6, 0xae, 0xdf, 0x75, 0xed, 0xf3, 0x3b, 0x95, 0x7e, 0xab, 0x90, 0x34, 0x7d, 0xd2, 0x11, 0xd1, 0x09, 0x98, 0xb5, 0xc8, 0xc4,
0xb7, 0x1d, 0x93, 0x26, 0x4f, 0x3a, 0x22, 0x7a, 0x0e, 0x46, 0x2d, 0x32, 0xb1, 0xac, 0x5d, 0xf0, 0xbc, 0xf6, 0x60, 0xa0, 0x0d, 0xf7, 0xff, 0x30, 0xe2, 0x5f, 0xa9, 0x3e, 0x69, 0x79, 0x78, 0x0c,
0xb4, 0xd1, 0xf0, 0x37, 0x25, 0xfe, 0xb9, 0xca, 0x93, 0x96, 0x87, 0xa7, 0x60, 0x34, 0x08, 0x1a, 0x66, 0x83, 0xa0, 0x3e, 0x58, 0x69, 0xf4, 0x2e, 0x8a, 0x3f, 0x46, 0xee, 0x8e, 0x2c, 0xe2, 0x8b,
0x80, 0x99, 0x46, 0x6f, 0xa3, 0xf8, 0x43, 0xe4, 0x6c, 0xc9, 0x20, 0x3e, 0x3d, 0x9d, 0x4d, 0xa3, 0x8b, 0xc9, 0x38, 0x0a, 0x5d, 0x0d, 0x01, 0x98, 0x71, 0xa4, 0xce, 0x3d, 0xd9, 0x20, 0xe1, 0x87,
0xd0, 0xd1, 0x10, 0x80, 0x11, 0x47, 0x6a, 0xdd, 0x93, 0x09, 0x12, 0xbe, 0x4f, 0xc3, 0xf3, 0xc4, 0x34, 0xbc, 0x4a, 0x5c, 0x1d, 0xed, 0x82, 0x4d, 0xc2, 0xb7, 0xe1, 0x28, 0x09, 0x03, 0xd7, 0xc0,
0xe9, 0xa3, 0x1d, 0xb0, 0x48, 0xf8, 0x26, 0x9c, 0x24, 0x61, 0xe0, 0xe8, 0xf8, 0x7b, 0x1f, 0x86, 0x3f, 0x74, 0xd8, 0x5f, 0x17, 0x86, 0x5e, 0x83, 0x53, 0x94, 0x9c, 0xe6, 0xa2, 0x64, 0x95, 0xa7,
0xeb, 0x8d, 0xa1, 0x23, 0xb0, 0x8b, 0x92, 0xd3, 0x5c, 0x94, 0xac, 0x52, 0xc2, 0x0e, 0xc7, 0xf8, 0x29, 0x49, 0xf8, 0x6f, 0x5f, 0xe1, 0x07, 0x1d, 0x93, 0xdc, 0x0f, 0xfd, 0xa7, 0x07, 0x08, 0x0c,
0x4f, 0xb7, 0xf0, 0x83, 0x8e, 0x49, 0x6e, 0x8b, 0xfe, 0xd3, 0x03, 0x04, 0xba, 0xa0, 0xdf, 0x44, 0x41, 0xbf, 0x8b, 0x76, 0xf9, 0xea, 0x8c, 0x30, 0xec, 0x7e, 0xe2, 0xec, 0x36, 0xea, 0x66, 0x9a,
0x2b, 0xbe, 0x5a, 0x23, 0x0c, 0x3b, 0x1f, 0x39, 0xbb, 0x8a, 0xba, 0x9a, 0x46, 0xf4, 0x35, 0xec, 0xa5, 0xaf, 0x61, 0x9b, 0xde, 0x99, 0xdb, 0xde, 0x1d, 0x81, 0xcd, 0xe9, 0xe7, 0xc6, 0x36, 0x6b,
0xbe, 0x77, 0xc6, 0xa6, 0x77, 0x07, 0x60, 0x71, 0xfa, 0xa9, 0xb1, 0xcd, 0xf4, 0xb4, 0x91, 0x45, 0xa0, 0x0d, 0x6d, 0xb2, 0xac, 0xa5, 0xaf, 0x92, 0x1a, 0xd0, 0x69, 0x79, 0x47, 0x39, 0x2d, 0x3c,
0x56, 0xb1, 0xf4, 0x55, 0x52, 0x03, 0x3a, 0x2f, 0xaf, 0x29, 0xa7, 0x85, 0x6b, 0x35, 0xbe, 0xae, 0xbb, 0xf1, 0x75, 0x0d, 0x94, 0x3a, 0x24, 0x40, 0xba, 0xa7, 0x38, 0x8d, 0x8e, 0x55, 0x4c, 0xea,
0x81, 0xb2, 0x0f, 0x09, 0x90, 0x6e, 0x17, 0xbb, 0xe9, 0xe3, 0x2e, 0x26, 0xfb, 0xe0, 0xf4, 0x8a, 0xe0, 0xf4, 0x96, 0x09, 0x1a, 0x72, 0xce, 0xb8, 0x32, 0xd3, 0x21, 0xab, 0x10, 0x7e, 0x0a, 0xce,
0x09, 0x1a, 0x72, 0xce, 0xb8, 0x32, 0xd3, 0x26, 0x77, 0x21, 0xfc, 0x04, 0xec, 0x95, 0x5e, 0xd2, 0x72, 0x5f, 0xd2, 0x94, 0x71, 0x74, 0x1e, 0xa7, 0x51, 0xe0, 0xee, 0x48, 0x53, 0xe2, 0x34, 0x69,
0x94, 0x69, 0x74, 0x12, 0xa7, 0x51, 0xe0, 0x6c, 0x49, 0x53, 0xe2, 0x34, 0x69, 0x22, 0x0d, 0xbb, 0x2a, 0x0d, 0x7b, 0xf0, 0xe8, 0x3d, 0xab, 0x4a, 0xc1, 0x78, 0xbb, 0xed, 0xba, 0x5d, 0x37, 0xfe,
0xf0, 0xf0, 0x1d, 0xab, 0x4a, 0xc1, 0x78, 0xab, 0x76, 0xdd, 0xca, 0x8d, 0x7f, 0x6a, 0xb0, 0xd3, 0xa5, 0xc1, 0x6e, 0x8b, 0x85, 0x77, 0xb4, 0x12, 0xe8, 0x39, 0x18, 0x62, 0x31, 0xa3, 0xad, 0x4f,
0x62, 0xe1, 0x35, 0xad, 0x04, 0x7a, 0x06, 0xba, 0xb8, 0x59, 0xd0, 0xd6, 0xa7, 0xc3, 0x0d, 0x9f, 0xc7, 0x5b, 0x3e, 0x29, 0x96, 0x9f, 0x2c, 0x66, 0x94, 0x28, 0x22, 0x7a, 0x06, 0x56, 0x7b, 0x8d,
0x14, 0xcb, 0x4f, 0x6e, 0x16, 0x94, 0x28, 0x22, 0x7a, 0x0a, 0x66, 0xfb, 0xac, 0x94, 0x37, 0x83, 0x94, 0x37, 0xfd, 0xd3, 0x83, 0xad, 0x99, 0x37, 0x3b, 0xa4, 0xe3, 0xa0, 0x97, 0xf7, 0x81, 0xd6,
0xf1, 0xde, 0x46, 0xcd, 0xeb, 0x2d, 0xd2, 0x71, 0xd0, 0xcb, 0xdb, 0x81, 0xee, 0xff, 0x7d, 0xa0, 0xff, 0x1d, 0x68, 0x39, 0xd5, 0x52, 0xf1, 0x2b, 0x30, 0xe4, 0x2b, 0x91, 0x0d, 0x46, 0x94, 0x4e,
0x65, 0x55, 0x4b, 0xc5, 0xaf, 0x40, 0x97, 0x47, 0x22, 0x0b, 0xf4, 0x28, 0x9d, 0xcd, 0x9a, 0x0b, 0x26, 0xcd, 0x07, 0x5e, 0xc6, 0x97, 0xe9, 0xe4, 0x2c, 0x91, 0xe1, 0xb4, 0x40, 0x3f, 0x0b, 0x02,
0x9e, 0xc5, 0x67, 0xe9, 0xec, 0x38, 0x91, 0xc3, 0x69, 0x42, 0xff, 0x38, 0x08, 0x9c, 0x9e, 0x9c, 0xb7, 0x27, 0x53, 0x9a, 0x5e, 0x06, 0x12, 0xd4, 0xe5, 0x39, 0x08, 0x27, 0x61, 0x12, 0xba, 0xc6,
0xd2, 0xf4, 0x2c, 0x90, 0x60, 0x5f, 0xae, 0x83, 0x70, 0x16, 0x26, 0xa1, 0xa3, 0x9f, 0xd8, 0x60, 0xb9, 0x03, 0x56, 0x3d, 0xbf, 0x96, 0x8b, 0xc5, 0x07, 0xf0, 0xf0, 0xac, 0x28, 0x96, 0xef, 0x9a,
0xd6, 0xcb, 0x0b, 0x29, 0x2c, 0xde, 0x83, 0x07, 0xc7, 0x45, 0xb1, 0x3a, 0x6b, 0x31, 0xbf, 0xc1, 0x4d, 0x17, 0xf8, 0x04, 0x0e, 0x03, 0x3a, 0xa5, 0x82, 0x6e, 0x24, 0x77, 0x25, 0x77, 0xda, 0x5a,
0x47, 0xb0, 0x1f, 0xd0, 0x39, 0x15, 0xf4, 0xde, 0xe4, 0xfe, 0xf3, 0x5f, 0x80, 0xf7, 0x01, 0xdd, 0xee, 0xf0, 0x21, 0xa0, 0x8d, 0x09, 0xf9, 0x9c, 0x63, 0x78, 0xdc, 0xb8, 0x37, 0xae, 0xae, 0xd9,
0xdb, 0x41, 0xee, 0x7b, 0x08, 0x8f, 0x1a, 0x37, 0xa7, 0xd5, 0x05, 0x5b, 0x56, 0x45, 0xf7, 0x54, 0xbc, 0x2a, 0xba, 0xab, 0x29, 0x9b, 0xd7, 0xa6, 0xfa, 0xcb, 0xbc, 0xf8, 0x1d, 0x00, 0x00, 0xff,
0x65, 0xf2, 0xc2, 0x50, 0xbf, 0xd0, 0x8b, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x13, 0x18, 0x1c, 0xff, 0x2d, 0x76, 0xf2, 0x61, 0x76, 0x04, 0x00, 0x00,
0x90, 0x96, 0x04, 0x00, 0x00,
} }

View File

@ -1,11 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package ricochet; package ricochet;
// XXX Using integer contact IDs seems dangerous, and it's especially a
// problem that 0 is a valid contact ID. Switch to UUID? Or use address?
message Contact { message Contact {
int32 id = 1;
string address = 2; string address = 2;
string nickname = 3; string nickname = 3;
string whenCreated = 4; string whenCreated = 4;
@ -62,8 +58,7 @@ message AddContactReply {
} }
message DeleteContactRequest { message DeleteContactRequest {
int32 id = 1; string address = 1;
string address = 2;
} }
message DeleteContactReply { message DeleteContactReply {

View File

@ -114,8 +114,7 @@ func (*MonitorConversationsRequest) ProtoMessage() {}
func (*MonitorConversationsRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } func (*MonitorConversationsRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
type Entity struct { type Entity struct {
// contactId and address MAY be unspecified for self // address MAY be unspecified for self
ContactId int32 `protobuf:"varint,1,opt,name=contactId" json:"contactId,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"` Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
IsSelf bool `protobuf:"varint,3,opt,name=isSelf" json:"isSelf,omitempty"` IsSelf bool `protobuf:"varint,3,opt,name=isSelf" json:"isSelf,omitempty"`
} }
@ -125,13 +124,6 @@ func (m *Entity) String() string { return proto.CompactTextString(m)
func (*Entity) ProtoMessage() {} func (*Entity) ProtoMessage() {}
func (*Entity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } func (*Entity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} }
func (m *Entity) GetContactId() int32 {
if m != nil {
return m.ContactId
}
return 0
}
func (m *Entity) GetAddress() string { func (m *Entity) GetAddress() string {
if m != nil { if m != nil {
return m.Address return m.Address
@ -242,35 +234,34 @@ func init() {
func init() { proto.RegisterFile("conversation.proto", fileDescriptor1) } func init() { proto.RegisterFile("conversation.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{ var fileDescriptor1 = []byte{
// 467 bytes of a gzipped FileDescriptorProto // 453 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0xd1, 0x6e, 0xd3, 0x4c, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0x41, 0x8f, 0x93, 0x4c,
0x10, 0x85, 0x7f, 0x27, 0x8e, 0x93, 0x4c, 0x7e, 0xd0, 0x76, 0x2e, 0x90, 0xa5, 0x02, 0x8a, 0xcc, 0x18, 0xc7, 0x5f, 0x0a, 0xa5, 0xe5, 0xe9, 0xab, 0x99, 0x7d, 0x0e, 0x86, 0x64, 0xd5, 0x10, 0xbc,
0x4d, 0xae, 0x2c, 0x14, 0x78, 0x81, 0xa8, 0x5e, 0xa1, 0x48, 0x49, 0x1a, 0x36, 0x4d, 0x85, 0xc4, 0x70, 0x22, 0xa6, 0x7a, 0xf2, 0xd6, 0x2c, 0x13, 0xd3, 0xa4, 0xed, 0xd6, 0xe9, 0xb2, 0x17, 0x4f,
0x95, 0xb1, 0xa7, 0x65, 0x45, 0x63, 0x07, 0xef, 0x34, 0x90, 0xc7, 0xe2, 0x1d, 0x78, 0x30, 0xb4, 0x08, 0xcf, 0xae, 0x13, 0xb7, 0x80, 0xcc, 0x6c, 0xb5, 0x1f, 0xcb, 0xef, 0xe0, 0x07, 0x33, 0x4c,
0x1b, 0x57, 0xb6, 0x14, 0xb8, 0xdb, 0x9d, 0xf3, 0xed, 0x78, 0xe6, 0x1c, 0x03, 0x66, 0x65, 0x71, 0xd9, 0x40, 0x52, 0xbd, 0x31, 0xf3, 0xff, 0xcd, 0xe4, 0x99, 0xdf, 0x1f, 0xc0, 0xbc, 0x2a, 0x0f,
0xa0, 0xca, 0xa4, 0xac, 0xcb, 0x22, 0xde, 0x57, 0x25, 0x97, 0x38, 0xa8, 0x74, 0x56, 0x66, 0x5f, 0xd4, 0xa8, 0x4c, 0xcb, 0xaa, 0x8c, 0xeb, 0xa6, 0xd2, 0x15, 0x4e, 0x1b, 0x99, 0x57, 0xf9, 0x57,
0x89, 0xa3, 0x5f, 0x1e, 0x5c, 0x5c, 0xb5, 0x00, 0x79, 0xa0, 0x82, 0xf1, 0x3d, 0xf8, 0x7c, 0xdc, 0xd2, 0xe1, 0x2f, 0x0b, 0x2e, 0xae, 0x06, 0x00, 0x3f, 0x50, 0xa9, 0xf1, 0x3d, 0x38, 0xfa, 0x58,
0x53, 0xe8, 0x8d, 0xbd, 0xc9, 0xf3, 0xe9, 0x38, 0x7e, 0xc2, 0xe3, 0x33, 0x34, 0xbe, 0x39, 0xee, 0x93, 0x6f, 0x05, 0x56, 0xf4, 0x7c, 0x1e, 0xc4, 0x4f, 0x78, 0x7c, 0x86, 0xc6, 0x37, 0xc7, 0x9a,
0x49, 0x39, 0x1a, 0xdf, 0x40, 0x77, 0x67, 0xee, 0xc3, 0xce, 0xd8, 0x9b, 0x8c, 0xa6, 0x17, 0xcd, 0x84, 0xa1, 0xf1, 0x0d, 0xd8, 0x7b, 0x75, 0xef, 0x8f, 0x02, 0x2b, 0x9a, 0xcd, 0x2f, 0xfa, 0x43,
0xa3, 0x25, 0x19, 0x93, 0xde, 0x93, 0xb2, 0x6a, 0x34, 0x03, 0xdf, 0x3e, 0xc1, 0x01, 0xf8, 0xab, 0x6b, 0x52, 0x2a, 0xbb, 0x27, 0xd1, 0xa6, 0xe1, 0x02, 0x9c, 0xf6, 0x08, 0x4e, 0xc1, 0xd9, 0xa4,
0xed, 0x62, 0x21, 0xfe, 0xc3, 0xff, 0x61, 0xb0, 0xbe, 0x5e, 0x6f, 0x17, 0xb3, 0x1b, 0x29, 0x3c, 0xab, 0x15, 0xfb, 0x0f, 0xff, 0x87, 0xe9, 0xf6, 0x7a, 0x9b, 0xae, 0x16, 0x37, 0x9c, 0x59, 0x38,
0x1c, 0x41, 0x5f, 0xc9, 0x2b, 0x39, 0xbf, 0x95, 0xa2, 0x63, 0xa1, 0x8d, 0x5c, 0x25, 0xa2, 0x8b, 0x83, 0x89, 0xe0, 0x57, 0x7c, 0x79, 0xcb, 0xd9, 0xa8, 0x85, 0x76, 0x7c, 0x93, 0x30, 0x1b, 0x01,
0x00, 0xc1, 0x76, 0x9d, 0x58, 0xc4, 0x8f, 0x5e, 0xc1, 0xe5, 0xb2, 0x2c, 0x34, 0x97, 0x55, 0x7b, 0xdc, 0x74, 0x9b, 0xb4, 0x88, 0x13, 0xbe, 0x82, 0xcb, 0x75, 0x55, 0x4a, 0x5d, 0x35, 0xc3, 0x71,
0x1c, 0xa3, 0xe8, 0xfb, 0x23, 0x19, 0x8e, 0x3e, 0x41, 0x20, 0x0b, 0xd6, 0x7c, 0xc4, 0x97, 0x30, 0x94, 0xa0, 0xef, 0x8f, 0xa4, 0x74, 0xf8, 0x01, 0x5c, 0x5e, 0x6a, 0xa9, 0x8f, 0xe8, 0xc3, 0x24,
0xcc, 0xca, 0x82, 0xd3, 0x8c, 0xe7, 0xb9, 0xdb, 0xa5, 0xa7, 0x9a, 0x02, 0x86, 0xd0, 0x4f, 0xf3, 0x2b, 0x8a, 0x86, 0x94, 0x32, 0x43, 0x79, 0xe2, 0x69, 0x89, 0x2f, 0xc0, 0x95, 0x6a, 0x47, 0x0f,
0xbc, 0x22, 0x63, 0xdc, 0xc8, 0x43, 0xf5, 0x74, 0xc5, 0x17, 0x10, 0x68, 0xb3, 0xa1, 0x87, 0xbb, 0x77, 0xbe, 0x1d, 0x58, 0xd1, 0x54, 0x74, 0xab, 0xf0, 0xf7, 0x08, 0x26, 0xdd, 0xb8, 0x18, 0x81,
0xb0, 0x3b, 0xf6, 0x26, 0x03, 0x55, 0xdf, 0xa2, 0xdf, 0x1d, 0xe8, 0xd7, 0xcb, 0xe0, 0x04, 0x02, 0xab, 0xa8, 0x2c, 0xa8, 0x31, 0x1a, 0x66, 0x73, 0xd6, 0xbf, 0xe8, 0x74, 0xbf, 0xe8, 0x72, 0x8c,
0x43, 0x45, 0x4e, 0x95, 0x6b, 0x3c, 0x9a, 0x8a, 0x66, 0xdf, 0xd3, 0xd7, 0x55, 0xad, 0x63, 0x0c, 0xc1, 0x6b, 0x28, 0x97, 0xb5, 0xa4, 0x52, 0x77, 0xcf, 0x3f, 0x87, 0x7b, 0x04, 0x5f, 0x82, 0xa7,
0xc3, 0x8a, 0x32, 0xbd, 0xd7, 0x54, 0x70, 0x6d, 0xce, 0x39, 0xdc, 0x20, 0x76, 0x6a, 0xd6, 0x3b, 0xe5, 0x9e, 0x94, 0xce, 0xf6, 0xb5, 0x19, 0xc0, 0x16, 0xfd, 0x06, 0xbe, 0x06, 0x90, 0x05, 0x95,
0x32, 0x9c, 0xee, 0xf6, 0x6e, 0x80, 0xae, 0x6a, 0x0a, 0xf8, 0x1a, 0x40, 0xe7, 0x54, 0xb0, 0xbe, 0x5a, 0xde, 0x49, 0x6a, 0x7c, 0x27, 0xb0, 0x22, 0x47, 0x0c, 0x76, 0xf0, 0x2d, 0xb8, 0x4a, 0x67,
0xd3, 0x54, 0x85, 0xfe, 0xd8, 0x9b, 0xf8, 0xaa, 0x55, 0xc1, 0xb7, 0x10, 0x18, 0x4e, 0xf9, 0xd1, 0xfa, 0x51, 0xf9, 0x63, 0x53, 0x8f, 0x7f, 0x66, 0x3a, 0xde, 0x99, 0x5c, 0x74, 0x1c, 0x22, 0x38,
0x84, 0x3d, 0x17, 0x5e, 0x78, 0x96, 0x43, 0xbc, 0x71, 0xba, 0xaa, 0x39, 0x44, 0xf0, 0x99, 0x7e, 0x9a, 0x7e, 0x6a, 0xdf, 0x35, 0x12, 0xcc, 0x77, 0xf8, 0x19, 0xdc, 0x13, 0x35, 0x68, 0xc2, 0x83,
0x72, 0x18, 0x38, 0x13, 0xdc, 0x39, 0xfa, 0x0c, 0xc1, 0x89, 0x6a, 0xe5, 0x34, 0x84, 0x9e, 0x54, 0x31, 0x17, 0xe2, 0x5a, 0x30, 0xab, 0xf5, 0xfd, 0x29, 0xe5, 0x29, 0x4f, 0xd8, 0xa8, 0xad, 0xa4,
0xea, 0x5a, 0x09, 0xcf, 0xa6, 0xf1, 0x71, 0x2b, 0xb7, 0x32, 0x11, 0x1d, 0x1b, 0x98, 0xcd, 0x68, 0x6d, 0x61, 0xb9, 0xf9, 0xc8, 0x6c, 0x7c, 0x06, 0x5e, 0xc2, 0x57, 0xcb, 0x5b, 0x2e, 0x78, 0xc2,
0xbe, 0xfa, 0x20, 0xba, 0xf8, 0x0c, 0x86, 0x89, 0x5c, 0xcc, 0x6f, 0xa5, 0x92, 0x89, 0xf0, 0x5d, 0x1c, 0xd3, 0xcb, 0x46, 0xf0, 0x45, 0xc2, 0xc6, 0xed, 0x45, 0xe6, 0xcb, 0x0d, 0x7f, 0xc0, 0xe5,
0x6a, 0x2b, 0x25, 0x67, 0x89, 0xe8, 0xd9, 0x46, 0xee, 0x14, 0x44, 0x3f, 0xe0, 0x72, 0x99, 0x56, 0x3a, 0x6b, 0xbe, 0x0d, 0xeb, 0x11, 0x94, 0x15, 0x5d, 0x43, 0xad, 0x59, 0x32, 0x52, 0xfe, 0x6d,
0xdf, 0xda, 0xe1, 0x29, 0x4a, 0xf3, 0x3a, 0x3f, 0xeb, 0x2c, 0x39, 0x53, 0xfe, 0xed, 0xec, 0x49, 0xf6, 0x94, 0x63, 0x0c, 0xf8, 0x90, 0x29, 0x2d, 0x28, 0x3f, 0x2c, 0x7b, 0x27, 0x23, 0xe3, 0xe4,
0xc7, 0x18, 0xf0, 0x21, 0x35, 0xac, 0x28, 0x3b, 0xcc, 0x1b, 0x4f, 0x3a, 0xce, 0x93, 0xbf, 0x28, 0x2f, 0xc9, 0x17, 0xd7, 0xfc, 0xdf, 0xef, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5c, 0x9e, 0xac,
0x5f, 0x02, 0xf7, 0xf7, 0xbf, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, 0xa0, 0x5b, 0x0f, 0xe6, 0x13, 0x63, 0xf5, 0x02, 0x00, 0x00,
0x03, 0x00, 0x00,
} }

View File

@ -18,8 +18,7 @@ message MonitorConversationsRequest {
} }
message Entity { message Entity {
// contactId and address MAY be unspecified for self // address MAY be unspecified for self
int32 contactId = 1;
string address = 2; string address = 2;
bool isSelf = 3; bool isSelf = 3;
} }