1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.voicemail.impl.protocol;
18 
19 import android.content.Context;
20 import android.provider.VoicemailContract.Status;
21 import android.support.annotation.IntDef;
22 import android.telecom.PhoneAccountHandle;
23 import com.android.voicemail.VoicemailComponent;
24 import com.android.voicemail.impl.DefaultOmtpEventHandler;
25 import com.android.voicemail.impl.OmtpEvents;
26 import com.android.voicemail.impl.OmtpEvents.Type;
27 import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper;
28 import com.android.voicemail.impl.VoicemailStatus;
29 import com.android.voicemail.impl.VvmLog;
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 
33 /**
34  * Handles {@link OmtpEvents} when {@link Vvm3Protocol} is being used. This handler writes custom
35  * error codes into the voicemail status table so support on the dialer side is required.
36  *
37  * <p>TODO(a bug) disable VVM3 by default so support on system dialer can be ensured.
38  */
39 public class Vvm3EventHandler {
40 
41   private static final String TAG = "Vvm3EventHandler";
42 
43   @Retention(RetentionPolicy.SOURCE)
44   @IntDef({
45     VMS_DNS_FAILURE,
46     VMG_DNS_FAILURE,
47     SPG_DNS_FAILURE,
48     VMS_NO_CELLULAR,
49     VMG_NO_CELLULAR,
50     SPG_NO_CELLULAR,
51     VMS_TIMEOUT,
52     VMG_TIMEOUT,
53     STATUS_SMS_TIMEOUT,
54     SUBSCRIBER_BLOCKED,
55     UNKNOWN_USER,
56     UNKNOWN_DEVICE,
57     INVALID_PASSWORD,
58     MAILBOX_NOT_INITIALIZED,
59     SERVICE_NOT_PROVISIONED,
60     SERVICE_NOT_ACTIVATED,
61     USER_BLOCKED,
62     IMAP_GETQUOTA_ERROR,
63     IMAP_SELECT_ERROR,
64     IMAP_ERROR,
65     VMG_INTERNAL_ERROR,
66     VMG_DB_ERROR,
67     VMG_COMMUNICATION_ERROR,
68     SPG_URL_NOT_FOUND,
69     VMG_UNKNOWN_ERROR,
70     PIN_NOT_SET
71   })
72   public @interface ErrorCode {}
73 
74   public static final int VMS_DNS_FAILURE = -9001;
75   public static final int VMG_DNS_FAILURE = -9002;
76   public static final int SPG_DNS_FAILURE = -9003;
77   public static final int VMS_NO_CELLULAR = -9004;
78   public static final int VMG_NO_CELLULAR = -9005;
79   public static final int SPG_NO_CELLULAR = -9006;
80   public static final int VMS_TIMEOUT = -9007;
81   public static final int VMG_TIMEOUT = -9008;
82   public static final int STATUS_SMS_TIMEOUT = -9009;
83 
84   public static final int SUBSCRIBER_BLOCKED = -9990;
85   public static final int UNKNOWN_USER = -9991;
86   public static final int UNKNOWN_DEVICE = -9992;
87   public static final int INVALID_PASSWORD = -9993;
88   public static final int MAILBOX_NOT_INITIALIZED = -9994;
89   public static final int SERVICE_NOT_PROVISIONED = -9995;
90   public static final int SERVICE_NOT_ACTIVATED = -9996;
91   public static final int USER_BLOCKED = -9998;
92   public static final int IMAP_GETQUOTA_ERROR = -9997;
93   public static final int IMAP_SELECT_ERROR = -9989;
94   public static final int IMAP_ERROR = -9999;
95 
96   public static final int VMG_INTERNAL_ERROR = -101;
97   public static final int VMG_DB_ERROR = -102;
98   public static final int VMG_COMMUNICATION_ERROR = -103;
99   public static final int SPG_URL_NOT_FOUND = -301;
100 
101   // Non VVM3 codes:
102   public static final int VMG_UNKNOWN_ERROR = -1;
103   public static final int PIN_NOT_SET = -100;
104   // STATUS SMS returned st=U and rc!=2. The user cannot be provisioned and must contact customer
105   // support.
106   public static final int SUBSCRIBER_UNKNOWN = -99;
107 
handleEvent( Context context, OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, OmtpEvents event)108   public static void handleEvent(
109       Context context,
110       OmtpVvmCarrierConfigHelper config,
111       VoicemailStatus.Editor status,
112       OmtpEvents event) {
113     boolean handled = false;
114     switch (event.getType()) {
115       case Type.CONFIGURATION:
116         handled = handleConfigurationEvent(context, status, event);
117         break;
118       case Type.DATA_CHANNEL:
119         handled = handleDataChannelEvent(status, event);
120         break;
121       case Type.NOTIFICATION_CHANNEL:
122         handled = handleNotificationChannelEvent(status, event);
123         break;
124       case Type.OTHER:
125         handled = handleOtherEvent(status, event);
126         break;
127       default:
128         VvmLog.wtf(TAG, "invalid event type " + event.getType() + " for " + event);
129     }
130     if (!handled) {
131       DefaultOmtpEventHandler.handleEvent(context, config, status, event);
132     }
133   }
134 
handleConfigurationEvent( Context context, VoicemailStatus.Editor status, OmtpEvents event)135   private static boolean handleConfigurationEvent(
136       Context context, VoicemailStatus.Editor status, OmtpEvents event) {
137     switch (event) {
138       case CONFIG_REQUEST_STATUS_SUCCESS:
139         if (!isPinRandomized(context, status.getPhoneAccountHandle())) {
140           return false;
141         } else {
142           postError(status, PIN_NOT_SET);
143         }
144         break;
145       case CONFIG_ACTIVATING_SUBSEQUENT:
146         if (isPinRandomized(context, status.getPhoneAccountHandle())) {
147           status.setConfigurationState(PIN_NOT_SET);
148         } else {
149           status.setConfigurationState(Status.CONFIGURATION_STATE_OK);
150         }
151         status
152             .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
153             .setDataChannelState(Status.DATA_CHANNEL_STATE_OK)
154             .apply();
155         break;
156       case CONFIG_DEFAULT_PIN_REPLACED:
157         postError(status, PIN_NOT_SET);
158         break;
159       case CONFIG_STATUS_SMS_TIME_OUT:
160         postError(status, STATUS_SMS_TIMEOUT);
161         break;
162       default:
163         return false;
164     }
165     return true;
166   }
167 
handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event)168   private static boolean handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event) {
169     switch (event) {
170       case DATA_NO_CONNECTION:
171       case DATA_NO_CONNECTION_CELLULAR_REQUIRED:
172       case DATA_ALL_SOCKET_CONNECTION_FAILED:
173         postError(status, VMS_NO_CELLULAR);
174         break;
175       case DATA_SSL_INVALID_HOST_NAME:
176       case DATA_CANNOT_ESTABLISH_SSL_SESSION:
177       case DATA_IOE_ON_OPEN:
178         postError(status, VMS_TIMEOUT);
179         break;
180       case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK:
181         postError(status, VMS_DNS_FAILURE);
182         break;
183       case DATA_BAD_IMAP_CREDENTIAL:
184         postError(status, IMAP_ERROR);
185         break;
186       case DATA_AUTH_UNKNOWN_USER:
187         postError(status, UNKNOWN_USER);
188         break;
189       case DATA_AUTH_UNKNOWN_DEVICE:
190         postError(status, UNKNOWN_DEVICE);
191         break;
192       case DATA_AUTH_INVALID_PASSWORD:
193         postError(status, INVALID_PASSWORD);
194         break;
195       case DATA_AUTH_MAILBOX_NOT_INITIALIZED:
196         postError(status, MAILBOX_NOT_INITIALIZED);
197         break;
198       case DATA_AUTH_SERVICE_NOT_PROVISIONED:
199         postError(status, SERVICE_NOT_PROVISIONED);
200         break;
201       case DATA_AUTH_SERVICE_NOT_ACTIVATED:
202         postError(status, SERVICE_NOT_ACTIVATED);
203         break;
204       case DATA_AUTH_USER_IS_BLOCKED:
205         postError(status, USER_BLOCKED);
206         break;
207       case DATA_REJECTED_SERVER_RESPONSE:
208       case DATA_INVALID_INITIAL_SERVER_RESPONSE:
209       case DATA_SSL_EXCEPTION:
210         postError(status, IMAP_ERROR);
211         break;
212       default:
213         return false;
214     }
215     return true;
216   }
217 
handleNotificationChannelEvent( VoicemailStatus.Editor unusedStatus, OmtpEvents unusedEvent)218   private static boolean handleNotificationChannelEvent(
219       VoicemailStatus.Editor unusedStatus, OmtpEvents unusedEvent) {
220     return false;
221   }
222 
handleOtherEvent(VoicemailStatus.Editor status, OmtpEvents event)223   private static boolean handleOtherEvent(VoicemailStatus.Editor status, OmtpEvents event) {
224     switch (event) {
225       case VVM3_NEW_USER_SETUP_FAILED:
226         postError(status, MAILBOX_NOT_INITIALIZED);
227         break;
228       case VVM3_VMG_DNS_FAILURE:
229         postError(status, VMG_DNS_FAILURE);
230         break;
231       case VVM3_SPG_DNS_FAILURE:
232         postError(status, SPG_DNS_FAILURE);
233         break;
234       case VVM3_VMG_CONNECTION_FAILED:
235         postError(status, VMG_NO_CELLULAR);
236         break;
237       case VVM3_SPG_CONNECTION_FAILED:
238         postError(status, SPG_NO_CELLULAR);
239         break;
240       case VVM3_VMG_TIMEOUT:
241         postError(status, VMG_TIMEOUT);
242         break;
243       case VVM3_SUBSCRIBER_PROVISIONED:
244         postError(status, SERVICE_NOT_ACTIVATED);
245         break;
246       case VVM3_SUBSCRIBER_BLOCKED:
247         postError(status, SUBSCRIBER_BLOCKED);
248         break;
249       case VVM3_SUBSCRIBER_UNKNOWN:
250         postError(status, SUBSCRIBER_UNKNOWN);
251         break;
252       default:
253         return false;
254     }
255     return true;
256   }
257 
postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode)258   private static void postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode) {
259     switch (errorCode) {
260       case VMG_DNS_FAILURE:
261       case SPG_DNS_FAILURE:
262       case VMG_NO_CELLULAR:
263       case SPG_NO_CELLULAR:
264       case VMG_TIMEOUT:
265       case SUBSCRIBER_BLOCKED:
266       case UNKNOWN_USER:
267       case UNKNOWN_DEVICE:
268       case INVALID_PASSWORD:
269       case MAILBOX_NOT_INITIALIZED:
270       case SERVICE_NOT_PROVISIONED:
271       case SERVICE_NOT_ACTIVATED:
272       case USER_BLOCKED:
273       case VMG_UNKNOWN_ERROR:
274       case SPG_URL_NOT_FOUND:
275       case VMG_INTERNAL_ERROR:
276       case VMG_DB_ERROR:
277       case VMG_COMMUNICATION_ERROR:
278       case PIN_NOT_SET:
279       case SUBSCRIBER_UNKNOWN:
280         editor.setConfigurationState(errorCode);
281         break;
282       case VMS_NO_CELLULAR:
283       case VMS_DNS_FAILURE:
284       case VMS_TIMEOUT:
285       case IMAP_GETQUOTA_ERROR:
286       case IMAP_SELECT_ERROR:
287       case IMAP_ERROR:
288         editor.setDataChannelState(errorCode);
289         break;
290       case STATUS_SMS_TIMEOUT:
291         editor.setNotificationChannelState(errorCode);
292         break;
293       default:
294         VvmLog.wtf(TAG, "unknown error code: " + errorCode);
295     }
296     editor.apply();
297   }
298 
isPinRandomized(Context context, PhoneAccountHandle phoneAccountHandle)299   private static boolean isPinRandomized(Context context, PhoneAccountHandle phoneAccountHandle) {
300     if (phoneAccountHandle == null) {
301       // This should never happen.
302       VvmLog.e(TAG, "status editor has null phone account handle");
303       return false;
304     }
305     return VoicemailComponent.get(context)
306             .getVoicemailClient()
307             .createPinChanger(context, phoneAccountHandle)
308             .getScrambledPin()
309         != null;
310   }
311 }
312