1package otr_client
2
3import (
4	"fmt"
5	"log"
6
7	"github.com/coyim/coyim/xmpp/jid"
8	"github.com/coyim/otr3"
9)
10
11var (
12	// ErrorPrefix can be used to make an OTR error by appending an error message
13	// to it.
14	ErrorPrefix = "?OTR Error:"
15)
16
17// EventHandler is used to contain information pertaining to the events of a specific OTR interaction
18type EventHandler struct {
19	SmpQuestion        string
20	securityChange     SecurityChange
21	WaitingForSecret   bool
22	account            string
23	peer               jid.Any
24	notifications      chan<- string
25	delayedMessageSent chan<- int
26	delays             map[int]bool
27	pendingDelays      int
28}
29
30// ConsumeDelayedState returns whether the given trace has been delayed or not, blanking out that status as a side effect
31func (e *EventHandler) ConsumeDelayedState(trace int) bool {
32	val, ok := e.delays[trace]
33	delete(e.delays, trace)
34	return ok && val
35}
36
37func (e *EventHandler) notify(s string) {
38	e.notifications <- s
39}
40
41// HandleErrorMessage is called when asked to handle a specific error message
42func (e *EventHandler) HandleErrorMessage(error otr3.ErrorCode) []byte {
43	log.Printf("[%s] HandleErrorMessage(%s)", e.account, error.String())
44
45	switch error {
46	case otr3.ErrorCodeEncryptionError:
47		return []byte("Error occurred encrypting message.")
48	case otr3.ErrorCodeMessageUnreadable:
49		return []byte("You transmitted an unreadable encrypted message.")
50	case otr3.ErrorCodeMessageMalformed:
51		return []byte("You transmitted a malformed data message.")
52	case otr3.ErrorCodeMessageNotInPrivate:
53		return []byte("You sent encrypted data to a peer, who wasn't expecting it.")
54	}
55
56	return nil
57}
58
59// HandleSecurityEvent is called to handle a specific security event
60func (e *EventHandler) HandleSecurityEvent(event otr3.SecurityEvent) {
61	log.Printf("[%s] HandleSecurityEvent(%s)", e.account, event.String())
62	switch event {
63	case otr3.GoneSecure:
64		e.pendingDelays = 0
65		e.securityChange = NewKeys
66	case otr3.StillSecure:
67		e.securityChange = RenewedKeys
68	case otr3.GoneInsecure:
69		e.securityChange = ConversationEnded
70	}
71}
72
73// HandleSMPEvent is called to handle a specific SMP event
74func (e *EventHandler) HandleSMPEvent(event otr3.SMPEvent, progressPercent int, question string) {
75	log.Printf("[%s] HandleSMPEvent(%s, %d, %s)", e.account, event.String(), progressPercent, question)
76	switch event {
77	case otr3.SMPEventAskForSecret, otr3.SMPEventAskForAnswer:
78		e.securityChange = SMPSecretNeeded
79		e.SmpQuestion = question
80		e.WaitingForSecret = true
81	case otr3.SMPEventSuccess:
82		if progressPercent == 100 {
83			e.securityChange = SMPComplete
84		}
85	case otr3.SMPEventAbort, otr3.SMPEventFailure, otr3.SMPEventCheated:
86		e.securityChange = SMPFailed
87	}
88}
89
90// HandleMessageEvent is called to handle a specific message event
91func (e *EventHandler) HandleMessageEvent(event otr3.MessageEvent, message []byte, err error, trace ...interface{}) {
92	switch event {
93	case otr3.MessageEventLogHeartbeatReceived:
94		log.Printf("[%s] Heartbeat received from %s.", e.account, e.peer)
95	case otr3.MessageEventLogHeartbeatSent:
96		log.Printf("[%s] Heartbeat sent to %s.", e.account, e.peer)
97	case otr3.MessageEventReceivedMessageUnrecognized:
98		log.Printf("[%s] Unrecognized OTR message received from %s.", e.account, e.peer)
99	case otr3.MessageEventEncryptionRequired:
100		e.delays[trace[0].(int)] = true
101		e.pendingDelays++
102		if e.pendingDelays == 1 {
103			e.notify("Attempting to start a private conversation...")
104		}
105	case otr3.MessageEventEncryptionError:
106		// This happens when something goes wrong putting together a new data packet in OTR
107		e.notify("An error occurred when encrypting your message. The message was not sent.")
108	case otr3.MessageEventConnectionEnded:
109		// This happens when we have finished a conversation and tries to send a message afterwards
110		e.notify("Your message was not sent, since the other person has already closed their private connection to you.")
111	case otr3.MessageEventMessageReflected:
112		e.notify("We are receiving our own OTR messages. You are either trying to talk to yourself, or someone is reflecting your messages back at you.")
113	case otr3.MessageEventSetupError:
114		e.notify("Error setting up private conversation.")
115		if err != nil {
116			log.Printf("[%s] Error setting up private conversation with %s: %s.", e.account, e.peer, err.Error())
117		}
118	case otr3.MessageEventMessageSent:
119		if len(trace) > 0 {
120			e.delayedMessageSent <- trace[0].(int)
121		}
122	case otr3.MessageEventMessageResent:
123		e.notify("The last message to the other person was resent, since we couldn't deliver the message previously.")
124	case otr3.MessageEventReceivedMessageUnreadable:
125		// This happens when the authenticator is wrong, message counters are out of whack
126		// or several other things that indicate tampering or attack
127		e.notify("We received an unreadable encrypted message. It has probably been tampered with, or was sent from an older client.")
128	case otr3.MessageEventReceivedMessageMalformed:
129		// This happens when the OTR header is malformed, or different deserialization issues
130		e.notify("We received a malformed data message.")
131	case otr3.MessageEventReceivedMessageGeneralError:
132		// This happens when we receive an error from the other party
133		e.notify(fmt.Sprintf("We received this error from the other person: %s.", string(message)))
134	case otr3.MessageEventReceivedMessageNotInPrivate:
135		// This happens when we receive what looks like a data message, but we're not in encrypted state
136		// TODO: this should open conversation window
137		e.notify("We received an encrypted message which can't be read, since private communication is not currently turned on. You should ask your peer to repeat what they said.")
138	case otr3.MessageEventReceivedMessageUnencrypted:
139		// This happens when we receive a non-OTR message, even though we have require encryption turned on
140		e.notify("We received a message that was transferred without encryption")
141	case otr3.MessageEventReceivedMessageForOtherInstance:
142		// We ignore this message on purpose, for now it would be too noisy to notify about it
143	default:
144		log.Printf("[%s] Unhandled OTR3 Message Event(%s, %s, %v)", e.account, event.String(), message, err)
145	}
146}
147
148// ConsumeSecurityChange is called to get the current security change and forget the old one
149func (e *EventHandler) ConsumeSecurityChange() SecurityChange {
150	ret := e.securityChange
151	e.securityChange = NoChange
152	return ret
153}
154