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 final String question = mSharedSecretHint.getText().toString();
54 final String secret = mSharedSecretSecret.getText().toString();
55 if (!initSmp(question,secret)) {
56 Toast.makeText(getApplicationContext(),"smp failed",Toast.LENGTH_SHORT).show();
57 }
58 updateView();
59 }
60 };
61 private View.OnClickListener mCancelSharedSecretListener = new View.OnClickListener() {
62 @Override
63 public void onClick(View view) {
64 abortSmp();
65 updateView();
66 }
67 };
68 private View.OnClickListener mRespondSharedSecretListener = new View.OnClickListener() {
69
70 @Override
71 public void onClick(View view) {
72 final String question = mSharedSecretHint.getText().toString();
73 final String secret = mSharedSecretSecret.getText().toString();
74 respondSmp(question,secret);
75 updateView();
76 }
77 };
78 private View.OnClickListener mRetrySharedSecretListener = new View.OnClickListener() {
79 @Override
80 public void onClick(View view) {
81 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
82 mConversation.smp().hint = null;
83 mConversation.smp().secret = null;
84 updateView();
85 }
86 };
87 private View.OnClickListener mFinishListener = new View.OnClickListener() {
88 @Override
89 public void onClick(View view) {
90 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
91 finish();
92 }
93 };
94
95 protected boolean initSmp(final String question, final String secret) {
96 final Session session = mConversation.getOtrSession();
97 if (session!=null) {
98 try {
99 session.initSmp(question, secret);
100 mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED;
101 return true;
102 } catch (OtrException e) {
103 return false;
104 }
105 } else {
106 return false;
107 }
108 }
109
110 protected boolean abortSmp() {
111 final Session session = mConversation.getOtrSession();
112 if (session!=null) {
113 try {
114 session.abortSmp();
115 mConversation.smp().status = Conversation.Smp.STATUS_NONE;
116 mConversation.smp().hint = null;
117 mConversation.smp().secret = null;
118 return true;
119 } catch (OtrException e) {
120 return false;
121 }
122 } else {
123 return false;
124 }
125 }
126
127 protected boolean respondSmp(final String question, final String secret) {
128 final Session session = mConversation.getOtrSession();
129 if (session!=null) {
130 try {
131 session.respondSmp(question,secret);
132 return true;
133 } catch (OtrException e) {
134 return false;
135 }
136 } else {
137 return false;
138 }
139 }
140
141 protected boolean handleIntent(Intent intent) {
142 if (intent.getAction().equals(ACTION_VERIFY_CONTACT)) {
143 try {
144 this.mAccount = this.xmppConnectionService.findAccountByJid(Jid.fromString(intent.getExtras().getString("account")));
145 } catch (final InvalidJidException ignored) {
146 return false;
147 }
148 try {
149 this.mConversation = this.xmppConnectionService.find(this.mAccount,Jid.fromString(intent.getExtras().getString("contact")));
150 if (this.mConversation == null) {
151 return false;
152 }
153 } catch (final InvalidJidException ignored) {
154 return false;
155 }
156 return true;
157 } else {
158 return false;
159 }
160 }
161
162 @Override
163 protected void onBackendConnected() {
164 if (handleIntent(getIntent())) {
165 updateView();
166 }
167 }
168
169 protected void updateView() {
170 if (this.mConversation.hasValidOtrSession()) {
171 this.mVerificationAreaOne.setVisibility(View.VISIBLE);
172 this.mVerificationAreaTwo.setVisibility(View.VISIBLE);
173 this.mErrorNoSession.setVisibility(View.GONE);
174 this.mYourFingerprint.setText(this.mAccount.getOtrFingerprint(xmppConnectionService));
175 this.mRemoteFingerprint.setText(this.mConversation.getOtrFingerprint());
176 this.mRemoteJid.setText(this.mConversation.getContact().getJid().toBareJid().toString());
177 Conversation.Smp smp = mConversation.smp();
178 Session session = mConversation.getOtrSession();
179 if (mConversation.isOtrFingerprintVerified()) {
180 deactivateButton(mButtonVerifyFingerprint, R.string.verified);
181 } else {
182 activateButton(mButtonVerifyFingerprint, R.string.verify, mVerifyFingerprintListener);
183 }
184 if (smp.status == Conversation.Smp.STATUS_NONE) {
185 activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener);
186 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
187 this.mSharedSecretHint.setFocusableInTouchMode(true);
188 this.mSharedSecretSecret.setFocusableInTouchMode(true);
189 this.mSharedSecretSecret.setText("");
190 this.mSharedSecretHint.setText("");
191 this.mSharedSecretHint.setVisibility(View.VISIBLE);
192 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
193 this.mStatusMessage.setVisibility(View.GONE);
194 } else if (smp.status == Conversation.Smp.STATUS_CONTACT_REQUESTED) {
195 this.mSharedSecretHint.setFocusable(false);
196 this.mSharedSecretHint.setText(smp.hint);
197 this.mSharedSecretSecret.setFocusableInTouchMode(true);
198 this.mSharedSecretHint.setVisibility(View.VISIBLE);
199 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
200 this.mStatusMessage.setVisibility(View.GONE);
201 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
202 activateButton(mButtonSharedSecretPositive, R.string.respond, mRespondSharedSecretListener);
203 } else if (smp.status == Conversation.Smp.STATUS_FAILED) {
204 activateButton(mButtonSharedSecretNegative, R.string.cancel, mFinishListener);
205 activateButton(mButtonSharedSecretPositive, R.string.try_again, mRetrySharedSecretListener);
206 this.mSharedSecretHint.setVisibility(View.GONE);
207 this.mSharedSecretSecret.setVisibility(View.GONE);
208 this.mStatusMessage.setVisibility(View.VISIBLE);
209 this.mStatusMessage.setText(R.string.secrets_do_not_match);
210 this.mStatusMessage.setTextColor(getWarningTextColor());
211 } else if (smp.status == Conversation.Smp.STATUS_VERIFIED) {
212 this.mSharedSecretHint.setVisibility(View.GONE);
213 this.mSharedSecretSecret.setVisibility(View.GONE);
214 this.mStatusMessage.setVisibility(View.VISIBLE);
215 this.mStatusMessage.setText(R.string.verified);
216 this.mStatusMessage.setTextColor(getPrimaryColor());
217 deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
218 activateButton(mButtonSharedSecretPositive, R.string.finish, mFinishListener);
219 } else if (session != null && session.isSmpInProgress()) {
220 deactivateButton(mButtonSharedSecretPositive, R.string.in_progress);
221 activateButton(mButtonSharedSecretNegative, R.string.cancel, mCancelSharedSecretListener);
222 this.mSharedSecretHint.setVisibility(View.VISIBLE);
223 this.mSharedSecretSecret.setVisibility(View.VISIBLE);
224 this.mSharedSecretHint.setFocusable(false);
225 this.mSharedSecretSecret.setFocusable(false);
226 }
227 } else {
228 this.mVerificationAreaOne.setVisibility(View.GONE);
229 this.mVerificationAreaTwo.setVisibility(View.GONE);
230 this.mErrorNoSession.setVisibility(View.VISIBLE);
231 }
232 }
233
234 protected void activateButton(Button button, int text, View.OnClickListener listener) {
235 button.setEnabled(true);
236 button.setTextColor(getPrimaryTextColor());
237 button.setText(text);
238 button.setOnClickListener(listener);
239 }
240
241 protected void deactivateButton(Button button, int text) {
242 button.setEnabled(false);
243 button.setTextColor(getSecondaryTextColor());
244 button.setText(text);
245 button.setOnClickListener(null);
246 }
247
248 @Override
249 protected void onCreate(Bundle savedInstanceState) {
250 super.onCreate(savedInstanceState);
251 setContentView(R.layout.activity_verify_otr);
252 this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint);
253 this.mRemoteJid = (TextView) findViewById(R.id.remote_jid);
254 this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
255 this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative);
256 this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive);
257 this.mButtonVerifyFingerprint = (Button) findViewById(R.id.button_verify_fingerprint);
258 this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
259 this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint);
260 this.mStatusMessage= (TextView) findViewById(R.id.status_message);
261 this.mVerificationAreaOne = (RelativeLayout) findViewById(R.id.verification_area_one);
262 this.mVerificationAreaTwo = (RelativeLayout) findViewById(R.id.verification_area_two);
263 this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session);
264 }
265
266 @Override
267 protected String getShareableUri() {
268 if (mAccount!=null) {
269 return "xmpp:"+mAccount.getJid().toBareJid();
270 } else {
271 return "";
272 }
273 }
274
275 @Override
276 public void onConversationUpdate() {
277 runOnUiThread(new Runnable() {
278 @Override
279 public void run() {
280 updateView();
281 }
282 });
283 }
284}