1package eu.siacs.conversations.ui;
2
3import android.content.Intent;
4import android.os.Bundle;
5import android.util.Log;
6import android.view.View;
7import android.widget.Button;
8import android.widget.EditText;
9import android.widget.ImageView;
10import android.widget.TextView;
11import android.widget.Toast;
12
13import net.java.otr4j.OtrException;
14import net.java.otr4j.crypto.OtrCryptoException;
15import net.java.otr4j.session.Session;
16
17import eu.siacs.conversations.Config;
18import eu.siacs.conversations.R;
19import eu.siacs.conversations.entities.Account;
20import eu.siacs.conversations.entities.Contact;
21import eu.siacs.conversations.entities.Conversation;
22import eu.siacs.conversations.services.XmppConnectionService;
23import eu.siacs.conversations.xmpp.jid.InvalidJidException;
24import eu.siacs.conversations.xmpp.jid.Jid;
25
26public class VerifyOTRActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
27
28 public static final String ACTION_VERIFY_CONTACT = "verify_contact";
29
30 private TextView mRemoteJid;
31 private TextView mRemoteFingerprint;
32 private TextView mYourFingerprint;
33 private EditText mSharedSecretHint;
34 private EditText mSharedSecretSecret;
35 private Button mButtonVerifyFingerprint;
36 private Button mButtonSharedSecretPositive;
37 private Button mButtonSharedSecretNegative;
38 private TextView mStatusMessage;
39 private Account mAccount;
40 private Conversation mConversation;
41 private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() {
42 @Override
43 public void onClick(final View view) {
44 final String question = mSharedSecretHint.getText().toString();
45 final String secret = mSharedSecretSecret.getText().toString();
46 if (!initSmp(question,secret)) {
47 Toast.makeText(getApplicationContext(),"smp failed",Toast.LENGTH_SHORT).show();
48 }
49 updateView();
50 }
51 };
52 private View.OnClickListener mCancelSharedSecretListener = new View.OnClickListener() {
53 @Override
54 public void onClick(View view) {
55 abortSmp();
56 }
57 };
58 private View.OnClickListener mRespondSharedSecretListener = new View.OnClickListener() {
59
60 @Override
61 public void onClick(View view) {
62 final String question = mSharedSecretHint.getText().toString();
63 final String secret = mSharedSecretSecret.getText().toString();
64 respondSmp(question,secret);
65 updateView();
66 }
67 };
68 private View.OnClickListener mRetrySharedSecretListener = new View.OnClickListener() {
69 @Override
70 public void onClick(View view) {
71 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
72 mConversation.smp().hint = null;
73 mConversation.smp().secret = null;
74 updateView();
75 }
76 };
77 private View.OnClickListener mFinishListener = new View.OnClickListener() {
78 @Override
79 public void onClick(View view) {
80 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
81 finish();
82 }
83 };
84
85 protected boolean initSmp(final String question, final String secret) {
86 final Session session = mConversation.getOtrSession();
87 if (session!=null) {
88 try {
89 session.initSmp(question, secret);
90 mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED;
91 return true;
92 } catch (OtrException e) {
93 return false;
94 }
95 } else {
96 return false;
97 }
98 }
99
100 protected boolean abortSmp() {
101 final Session session = mConversation.getOtrSession();
102 if (session!=null) {
103 try {
104 session.abortSmp();
105 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
106 return true;
107 } catch (OtrException e) {
108 return false;
109 }
110 } else {
111 return false;
112 }
113 }
114
115 protected boolean respondSmp(final String question, final String secret) {
116 final Session session = mConversation.getOtrSession();
117 if (session!=null) {
118 try {
119 session.respondSmp(question,secret);
120 return true;
121 } catch (OtrException e) {
122 return false;
123 }
124 } else {
125 return false;
126 }
127 }
128
129 protected boolean handleIntent(Intent intent) {
130 if (getIntent().getAction().equals(ACTION_VERIFY_CONTACT)) {
131 try {
132 this.mAccount = this.xmppConnectionService.findAccountByJid(Jid.fromString(getIntent().getExtras().getString("account")));
133 } catch (final InvalidJidException ignored) {
134 return false;
135 }
136 try {
137 this.mConversation = this.xmppConnectionService.find(this.mAccount,Jid.fromString(getIntent().getExtras().getString("contact")));
138 if (this.mConversation == null) {
139 return false;
140 }
141 } catch (final InvalidJidException ignored) {
142 return false;
143 }
144 return true;
145 } else {
146 return false;
147 }
148 }
149
150 @Override
151 protected void onBackendConnected() {
152 if (handleIntent(getIntent())) {
153 updateView();
154 }
155 this.xmppConnectionService.setOnConversationListChangedListener(this);
156 }
157
158 protected void updateView() {
159 this.mYourFingerprint.setText(this.mAccount.getOtrFingerprint(xmppConnectionService));
160 this.mRemoteFingerprint.setText(this.mConversation.getOtrFingerprint());
161 this.mRemoteJid.setText(this.mConversation.getContact().getJid().toBareJid().toString());
162 Conversation.Smp smp = mConversation.smp();
163 Session session = mConversation.getOtrSession();
164 if (smp.status == Conversation.Smp.STATUS_NONE) {
165 activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener);
166 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
167 this.mSharedSecretHint.setFocusableInTouchMode(true);
168 this.mSharedSecretSecret.setFocusableInTouchMode(true);
169 this.mSharedSecretSecret.setText("");
170 this.mSharedSecretHint.setText("");
171 this.mSharedSecretHint.setVisibility(View.VISIBLE);
172 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
173 this.mStatusMessage.setVisibility(View.GONE);
174 } else if (smp.status == Conversation.Smp.STATUS_CONTACT_REQUESTED) {
175 this.mSharedSecretHint.setFocusable(false);
176 this.mSharedSecretHint.setText(smp.hint);
177 this.mSharedSecretSecret.setFocusableInTouchMode(true);
178 this.mSharedSecretHint.setVisibility(View.VISIBLE);
179 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
180 this.mStatusMessage.setVisibility(View.GONE);
181 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
182 activateButton(mButtonSharedSecretPositive, R.string.respond, mRespondSharedSecretListener);
183 } else if (smp.status == Conversation.Smp.STATUS_FAILED) {
184 activateButton(mButtonSharedSecretNegative, R.string.cancel, mFinishListener);
185 activateButton(mButtonSharedSecretPositive, R.string.try_again, mRetrySharedSecretListener);
186 this.mSharedSecretHint.setVisibility(View.GONE);
187 this.mSharedSecretSecret.setVisibility(View.GONE);
188 this.mStatusMessage.setVisibility(View.VISIBLE);
189 this.mStatusMessage.setText(R.string.secrets_do_not_match);
190 this.mStatusMessage.setTextColor(getWarningTextColor());
191 } else if (smp.status == Conversation.Smp.STATUS_VERIFIED) {
192 this.mSharedSecretHint.setVisibility(View.GONE);
193 this.mSharedSecretSecret.setVisibility(View.GONE);
194 this.mStatusMessage.setVisibility(View.VISIBLE);
195 this.mStatusMessage.setText(R.string.verified);
196 this.mStatusMessage.setTextColor(getPrimaryColor());
197 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
198 activateButton(mButtonSharedSecretPositive, R.string.finish, mFinishListener);
199 } else if (session != null && session.isSmpInProgress()) {
200 deactivateButton(mButtonSharedSecretPositive,R.string.in_progress);
201 activateButton(mButtonSharedSecretNegative,R.string.cancel,mCancelSharedSecretListener);
202 this.mSharedSecretHint.setVisibility(View.VISIBLE);
203 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
204 this.mSharedSecretHint.setFocusable(false);
205 this.mSharedSecretSecret.setFocusable(false);
206 }
207 }
208
209 protected void activateButton(Button button, int text, View.OnClickListener listener) {
210 button.setEnabled(true);
211 button.setTextColor(getPrimaryTextColor());
212 button.setText(text);
213 button.setOnClickListener(listener);
214 }
215
216 protected void deactivateButton(Button button, int text) {
217 button.setEnabled(false);
218 button.setTextColor(getSecondaryTextColor());
219 button.setText(text);
220 button.setOnClickListener(null);
221 }
222
223 @Override
224 protected void onCreate(Bundle savedInstanceState) {
225 super.onCreate(savedInstanceState);
226 setContentView(R.layout.activity_verify_otr);
227 this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint);
228 this.mRemoteJid = (TextView) findViewById(R.id.remote_jid);
229 this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
230 this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative);
231 this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive);
232 this.mButtonVerifyFingerprint = (Button) findViewById(R.id.button_verify_fingerprint);
233 this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
234 this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint);
235 this.mStatusMessage= (TextView) findViewById(R.id.status_message);
236 }
237
238 @Override
239 protected String getShareableUri() {
240 if (mAccount!=null) {
241 return "xmpp:"+mAccount.getJid().toBareJid();
242 } else {
243 return "";
244 }
245 }
246
247 @Override
248 protected void onStop() {
249 if (xmppConnectionServiceBound) {
250 xmppConnectionService.removeOnConversationListChangedListener();
251 }
252 super.onStop();
253 }
254
255 @Override
256 public void onConversationUpdate() {
257 runOnUiThread(new Runnable() {
258 @Override
259 public void run() {
260 updateView();
261 }
262 });
263 }
264}