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