diff options
Diffstat (limited to 'java/com/android/voicemailomtp')
198 files changed, 0 insertions, 34649 deletions
diff --git a/java/com/android/voicemailomtp/ActivationTask.java b/java/com/android/voicemailomtp/ActivationTask.java deleted file mode 100644 index 7de81e685..000000000 --- a/java/com/android/voicemailomtp/ActivationTask.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.database.ContentObserver; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.provider.Settings; -import android.provider.Settings.Global; -import android.support.annotation.Nullable; -import android.support.annotation.WorkerThread; -import android.telecom.PhoneAccountHandle; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import com.android.voicemailomtp.protocol.VisualVoicemailProtocol; -import com.android.voicemailomtp.scheduling.BaseTask; -import com.android.voicemailomtp.scheduling.RetryPolicy; -import com.android.voicemailomtp.sms.StatusMessage; -import com.android.voicemailomtp.sms.StatusSmsFetcher; -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; -import com.android.voicemailomtp.sync.OmtpVvmSyncService; -import com.android.voicemailomtp.sync.SyncTask; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -/** - * Task to activate the visual voicemail service. A request to activate VVM will be sent to the - * carrier, which will respond with a STATUS SMS. The credentials will be updated from the SMS. If - * the user is not provisioned provisioning will be attempted. Activation happens when the phone - * boots, the SIM is inserted, signal returned when VVM is not activated yet, and when the carrier - * spontaneously sent a STATUS SMS. - */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class ActivationTask extends BaseTask { - - private static final String TAG = "VvmActivationTask"; - - private static final int RETRY_TIMES = 4; - private static final int RETRY_INTERVAL_MILLIS = 5_000; - - private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle"; - - @Nullable - private static DeviceProvisionedObserver sDeviceProvisionedObserver; - - private final RetryPolicy mRetryPolicy; - - private Bundle mMessageData; - - public ActivationTask() { - super(TASK_ACTIVATION); - mRetryPolicy = new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS); - addPolicy(mRetryPolicy); - } - - /** - * Has the user gone through the setup wizard yet. - */ - private static boolean isDeviceProvisioned(Context context) { - return Settings.Global.getInt( - context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1; - } - - /** - * @param messageData The optional bundle from {@link android.provider.VoicemailContract# - * EXTRA_VOICEMAIL_SMS_FIELDS}, if the task is initiated by a status SMS. If null the task will - * request a status SMS itself. - */ - public static void start(Context context, PhoneAccountHandle phoneAccountHandle, - @Nullable Bundle messageData) { - if (!isDeviceProvisioned(context)) { - VvmLog.i(TAG, "Activation requested while device is not provisioned, postponing"); - // Activation might need information such as system language to be set, so wait until - // the setup wizard is finished. The data bundle from the SMS will be re-requested upon - // activation. - queueActivationAfterProvisioned(context, phoneAccountHandle); - return; - } - - Intent intent = BaseTask.createIntent(context, ActivationTask.class, phoneAccountHandle); - if (messageData != null) { - intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, messageData); - } - context.startService(intent); - } - - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE); - } - - @Override - public Intent createRestartIntent() { - Intent intent = super.createRestartIntent(); - // mMessageData is discarded, request a fresh STATUS SMS for retries. - return intent; - } - - @Override - @WorkerThread - public void onExecuteInBackgroundThread() { - Assert.isNotMainThread(); - - PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(); - if (phoneAccountHandle == null) { - // This should never happen - VvmLog.e(TAG, "null PhoneAccountHandle"); - return; - } - - OmtpVvmCarrierConfigHelper helper = - new OmtpVvmCarrierConfigHelper(getContext(), phoneAccountHandle); - if (!helper.isValid()) { - VvmLog.i(TAG, "VVM not supported on phoneAccountHandle " + phoneAccountHandle); - VoicemailStatus.disable(getContext(), phoneAccountHandle); - return; - } - - // OmtpVvmCarrierConfigHelper can start the activation process; it will pass in a vvm - // content provider URI which we will use. On some occasions, setting that URI will - // fail, so we will perform a few attempts to ensure that the vvm content provider has - // a good chance of being started up. - if (!VoicemailStatus.edit(getContext(), phoneAccountHandle) - .setType(helper.getVvmType()) - .apply()) { - VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType()); - fail(); - } - VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType()); - - if (!OmtpVvmSourceManager.getInstance(getContext()) - .isVvmSourceRegistered(phoneAccountHandle)) { - // This account has not been activated before during the lifetime of this boot. - VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(), - phoneAccountHandle); - if (preferences.getString(OmtpConstants.SERVER_ADDRESS, null) == null) { - // Only show the "activating" message if activation has not been completed before. - // Subsequent activations are more of a status check and usually does not - // concern the user. - helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle), - OmtpEvents.CONFIG_ACTIVATING); - } else { - // The account has been activated on this device before. Pretend it is already - // activated. If there are any activation error it will overwrite this status. - helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle), - OmtpEvents.CONFIG_ACTIVATING_SUBSEQUENT); - } - - } - if (!hasSignal(getContext(), phoneAccountHandle)) { - VvmLog.i(TAG, "Service lost during activation, aborting"); - // Restore the "NO SIGNAL" state since it will be overwritten by the CONFIG_ACTIVATING - // event. - helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle), - OmtpEvents.NOTIFICATION_SERVICE_LOST); - // Don't retry, a new activation will be started after the signal returned. - return; - } - - helper.activateSmsFilter(); - VoicemailStatus.Editor status = mRetryPolicy.getVoicemailStatusEditor(); - - VisualVoicemailProtocol protocol = helper.getProtocol(); - - Bundle data; - if (mMessageData != null) { - // The content of STATUS SMS is provided to launch this task, no need to request it - // again. - data = mMessageData; - } else { - try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), - phoneAccountHandle)) { - protocol.startActivation(helper, fetcher.getSentIntent()); - // Both the fetcher and OmtpMessageReceiver will be triggered, but - // OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be - // rejected because the task is still running. - data = fetcher.get(); - } catch (TimeoutException e) { - // The carrier is expected to return an STATUS SMS within STATUS_SMS_TIMEOUT_MILLIS - // handleEvent() will do the logging. - helper.handleEvent(status, OmtpEvents.CONFIG_STATUS_SMS_TIME_OUT); - fail(); - return; - } catch (CancellationException e) { - VvmLog.e(TAG, "Unable to send status request SMS"); - fail(); - return; - } catch (InterruptedException | ExecutionException | IOException e) { - VvmLog.e(TAG, "can't get future STATUS SMS", e); - fail(); - return; - } - } - - StatusMessage message = new StatusMessage(data); - VvmLog.d(TAG, "STATUS SMS received: st=" + message.getProvisioningStatus() - + ", rc=" + message.getReturnCode()); - - if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) { - VvmLog.d(TAG, "subscriber ready, no activation required"); - updateSource(getContext(), phoneAccountHandle, status, message); - } else { - if (helper.supportsProvisioning()) { - VvmLog.i(TAG, "Subscriber not ready, start provisioning"); - helper.startProvisioning(this, phoneAccountHandle, status, message, data); - - } else if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_NEW)) { - VvmLog.i(TAG, "Subscriber new but provisioning is not supported"); - // Ignore the non-ready state and attempt to use the provided info as is. - // This is probably caused by not completing the new user tutorial. - updateSource(getContext(), phoneAccountHandle, status, message); - } else { - VvmLog.i(TAG, "Subscriber not ready but provisioning is not supported"); - helper.handleEvent(status, OmtpEvents.CONFIG_SERVICE_NOT_AVAILABLE); - } - } - } - - public static void updateSource(Context context, PhoneAccountHandle phone, - VoicemailStatus.Editor status, StatusMessage message) { - OmtpVvmSourceManager vvmSourceManager = - OmtpVvmSourceManager.getInstance(context); - - if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) { - OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phone); - helper.handleEvent(status, OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS); - - // Save the IMAP credentials in preferences so they are persistent and can be retrieved. - VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phone); - message.putStatus(prefs.edit()).apply(); - - // Add the source to indicate that it is active. - vvmSourceManager.addSource(phone); - - SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_FULL_SYNC); - } else { - VvmLog.e(TAG, "Visual voicemail not available for subscriber."); - } - } - - private static boolean hasSignal(Context context, PhoneAccountHandle phoneAccountHandle) { - TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) - .createForPhoneAccountHandle(phoneAccountHandle); - return telephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE; - } - - private static void queueActivationAfterProvisioned(Context context, - PhoneAccountHandle phoneAccountHandle) { - if (sDeviceProvisionedObserver == null) { - sDeviceProvisionedObserver = new DeviceProvisionedObserver(context); - context.getContentResolver() - .registerContentObserver(Settings.Global.getUriFor(Global.DEVICE_PROVISIONED), - false, sDeviceProvisionedObserver); - } - sDeviceProvisionedObserver.addPhoneAcountHandle(phoneAccountHandle); - } - - private static class DeviceProvisionedObserver extends ContentObserver { - - private final Context mContext; - private final Set<PhoneAccountHandle> mPhoneAccountHandles = new HashSet<>(); - - private DeviceProvisionedObserver(Context context) { - super(null); - mContext = context; - } - - public void addPhoneAcountHandle(PhoneAccountHandle phoneAccountHandle) { - mPhoneAccountHandles.add(phoneAccountHandle); - } - - @Override - public void onChange(boolean selfChange) { - if (isDeviceProvisioned(mContext)) { - VvmLog.i(TAG, "device provisioned, resuming activation"); - for (PhoneAccountHandle phoneAccountHandle : mPhoneAccountHandles) { - start(mContext, phoneAccountHandle, null); - } - mContext.getContentResolver().unregisterContentObserver(sDeviceProvisionedObserver); - sDeviceProvisionedObserver = null; - } - } - } -} diff --git a/java/com/android/voicemailomtp/AndroidManifest.xml b/java/com/android/voicemailomtp/AndroidManifest.xml deleted file mode 100644 index 282a923d2..000000000 --- a/java/com/android/voicemailomtp/AndroidManifest.xml +++ /dev/null @@ -1,105 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2007 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - package="com.android.voicemailomtp" -> - - <uses-sdk - android:minSdkVersion="23" - android:targetSdkVersion="25" /> - - <application - android:allowBackup="false" - android:supportsRtl="true" - android:usesCleartextTraffic="true" - android:defaultToDeviceProtectedStorage="true" - android:directBootAware="true"> - - <activity android:name="com.android.voicemailomtp.settings.VoicemailSettingsActivity" - android:label="@string/voicemail_settings_label"> - <intent-filter > - <!-- DO NOT RENAME. There are existing apps which use this string. --> - <action android:name="com.android.voicemailomtp.CallFeaturesSetting.ADD_VOICEMAIL" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - <intent-filter> - <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - - <receiver android:name="com.android.voicemailomtp.sms.OmtpMessageReceiver" - android:exported="false" - androidprv:systemUserOnly="true"> - <intent-filter> - <action android:name="com.android.vociemailomtp.sms.sms_received"/> - </intent-filter> - </receiver> - - <receiver - android:name="com.android.voicemailomtp.fetch.FetchVoicemailReceiver" - android:exported="true" - android:permission="com.android.voicemail.permission.READ_VOICEMAIL" - androidprv:systemUserOnly="true"> - <intent-filter> - <action android:name="android.intent.action.FETCH_VOICEMAIL" /> - <data - android:scheme="content" - android:host="com.android.voicemail" - android:mimeType="vnd.android.cursor.item/voicemail" /> - </intent-filter> - </receiver> - <receiver - android:name="com.android.voicemailomtp.sync.OmtpVvmSyncReceiver" - android:exported="true" - android:permission="com.android.voicemail.permission.READ_VOICEMAIL" - androidprv:systemUserOnly="true"> - <intent-filter> - <action android:name="android.provider.action.SYNC_VOICEMAIL"/> - </intent-filter> - </receiver> - <receiver - android:name="com.android.voicemailomtp.sync.VoicemailProviderChangeReceiver" - android:exported="true"> - <intent-filter> - <action android:name="android.intent.action.PROVIDER_CHANGED" /> - <data - android:scheme="content" - android:host="com.android.voicemail" - android:mimeType="vnd.android.cursor.dir/voicemails"/> - </intent-filter> - </receiver> - - <service - android:name="com.android.voicemailomtp.scheduling.TaskSchedulerService" - android:exported="false" /> - - <service - android:name="com.android.voicemailomtp.OmtpService" - android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE" - android:exported="true"> - <intent-filter> - <action android:name="android.telephony.VisualVoicemailService"/> - </intent-filter> - </service> - <activity android:name=".settings.VoicemailChangePinActivity" - android:exported="false" - android:windowSoftInputMode="stateVisible|adjustResize"> - </activity> - </application> -</manifest> diff --git a/java/com/android/voicemailomtp/Assert.java b/java/com/android/voicemailomtp/Assert.java deleted file mode 100644 index 1d295bed1..000000000 --- a/java/com/android/voicemailomtp/Assert.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - - -package com.android.voicemailomtp; - -import android.os.Looper; - -/** - * Assertions which will result in program termination. - */ -public class Assert { - - private static Boolean sIsMainThreadForTest; - - public static void isTrue(boolean condition) { - if (!condition) { - throw new AssertionError("Expected condition to be true"); - } - } - - public static void isMainThread() { - if (sIsMainThreadForTest != null) { - isTrue(sIsMainThreadForTest); - return; - } - isTrue(Looper.getMainLooper().equals(Looper.myLooper())); - } - - public static void isNotMainThread() { - if (sIsMainThreadForTest != null) { - isTrue(!sIsMainThreadForTest); - return; - } - isTrue(!Looper.getMainLooper().equals(Looper.myLooper())); - } - - public static void fail() { - throw new AssertionError("Fail"); - } - - /** - * Override the main thread status for tests. Set to null to revert to normal behavior - */ - @NeededForTesting - public static void setIsMainThreadForTesting(Boolean isMainThread) { - sIsMainThreadForTest = isMainThread; - } -} diff --git a/java/com/android/voicemailomtp/DefaultOmtpEventHandler.java b/java/com/android/voicemailomtp/DefaultOmtpEventHandler.java deleted file mode 100644 index 6a4b5104a..000000000 --- a/java/com/android/voicemailomtp/DefaultOmtpEventHandler.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.content.Context; -import android.provider.VoicemailContract; -import android.provider.VoicemailContract.Status; - -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.OmtpEvents.Type; - -public class DefaultOmtpEventHandler { - - private static final String TAG = "DefErrorCodeHandler"; - - public static void handleEvent(Context context, OmtpVvmCarrierConfigHelper config, - VoicemailStatus.Editor status, OmtpEvents event) { - switch (event.getType()) { - case Type.CONFIGURATION: - handleConfigurationEvent(context, status, event); - break; - case Type.DATA_CHANNEL: - handleDataChannelEvent(context, status, event); - break; - case Type.NOTIFICATION_CHANNEL: - handleNotificationChannelEvent(context, config, status, event); - break; - case Type.OTHER: - handleOtherEvent(context, status, event); - break; - default: - VvmLog.wtf(TAG, "invalid event type " + event.getType() + " for " + event); - } - } - - private static void handleConfigurationEvent(Context context, VoicemailStatus.Editor status, - OmtpEvents event) { - switch (event) { - case CONFIG_DEFAULT_PIN_REPLACED: - case CONFIG_REQUEST_STATUS_SUCCESS: - case CONFIG_PIN_SET: - status - .setConfigurationState(VoicemailContract.Status.CONFIGURATION_STATE_OK) - .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK) - .apply(); - break; - case CONFIG_ACTIVATING: - // Wipe all errors from the last activation. All errors shown should be new errors - // for this activation. - status - .setConfigurationState(Status.CONFIGURATION_STATE_CONFIGURING) - .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK) - .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply(); - break; - case CONFIG_ACTIVATING_SUBSEQUENT: - status - .setConfigurationState(Status.CONFIGURATION_STATE_OK) - .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK) - .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply(); - break; - case CONFIG_SERVICE_NOT_AVAILABLE: - status - .setConfigurationState(Status.CONFIGURATION_STATE_FAILED) - .apply(); - break; - case CONFIG_STATUS_SMS_TIME_OUT: - status - .setConfigurationState(Status.CONFIGURATION_STATE_FAILED) - .apply(); - break; - default: - VvmLog.wtf(TAG, "invalid configuration event " + event); - } - } - - private static void handleDataChannelEvent(Context context, VoicemailStatus.Editor status, - OmtpEvents event) { - switch (event) { - case DATA_IMAP_OPERATION_STARTED: - case DATA_IMAP_OPERATION_COMPLETED: - status - .setDataChannelState(Status.DATA_CHANNEL_STATE_OK) - .apply(); - break; - - case DATA_NO_CONNECTION: - status - .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION) - .apply(); - break; - - case DATA_NO_CONNECTION_CELLULAR_REQUIRED: - status - .setDataChannelState( - Status.DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED) - .apply(); - break; - case DATA_INVALID_PORT: - status - .setDataChannelState( - VoicemailContract.Status.DATA_CHANNEL_STATE_BAD_CONFIGURATION) - .apply(); - break; - case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK: - status - .setDataChannelState( - VoicemailContract.Status.DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR) - .apply(); - break; - case DATA_SSL_INVALID_HOST_NAME: - case DATA_CANNOT_ESTABLISH_SSL_SESSION: - case DATA_IOE_ON_OPEN: - case DATA_GENERIC_IMAP_IOE: - status - .setDataChannelState( - VoicemailContract.Status.DATA_CHANNEL_STATE_COMMUNICATION_ERROR) - .apply(); - break; - case DATA_BAD_IMAP_CREDENTIAL: - case DATA_AUTH_UNKNOWN_USER: - case DATA_AUTH_UNKNOWN_DEVICE: - case DATA_AUTH_INVALID_PASSWORD: - case DATA_AUTH_MAILBOX_NOT_INITIALIZED: - case DATA_AUTH_SERVICE_NOT_PROVISIONED: - case DATA_AUTH_SERVICE_NOT_ACTIVATED: - case DATA_AUTH_USER_IS_BLOCKED: - status - .setDataChannelState( - VoicemailContract.Status.DATA_CHANNEL_STATE_BAD_CONFIGURATION) - .apply(); - break; - - case DATA_REJECTED_SERVER_RESPONSE: - case DATA_INVALID_INITIAL_SERVER_RESPONSE: - case DATA_MAILBOX_OPEN_FAILED: - case DATA_SSL_EXCEPTION: - case DATA_ALL_SOCKET_CONNECTION_FAILED: - status - .setDataChannelState( - VoicemailContract.Status.DATA_CHANNEL_STATE_SERVER_ERROR) - .apply(); - break; - - default: - VvmLog.wtf(TAG, "invalid data channel event " + event); - } - } - - private static void handleNotificationChannelEvent(Context context, - OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, OmtpEvents event) { - switch (event) { - case NOTIFICATION_IN_SERVICE: - status - .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK) - // Clear the error state. A sync should follow signal return so any error - // will be reposted. - .setDataChannelState(Status.DATA_CHANNEL_STATE_OK) - .apply(); - break; - case NOTIFICATION_SERVICE_LOST: - status.setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION); - if (config.isCellularDataRequired()) { - status.setDataChannelState( - Status.DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED); - } - status.apply(); - break; - default: - VvmLog.wtf(TAG, "invalid notification channel event " + event); - } - } - - private static void handleOtherEvent(Context context, VoicemailStatus.Editor status, - OmtpEvents event) { - switch (event) { - case OTHER_SOURCE_REMOVED: - status - .setConfigurationState(Status.CONFIGURATION_STATE_NOT_CONFIGURED) - .setNotificationChannelState( - Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION) - .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION) - .apply(); - break; - default: - VvmLog.wtf(TAG, "invalid other event " + event); - } - } -} diff --git a/java/com/android/voicemailomtp/NeededForTesting.java b/java/com/android/voicemailomtp/NeededForTesting.java deleted file mode 100644 index 20517fed8..000000000 --- a/java/com/android/voicemailomtp/NeededForTesting.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.SOURCE) -public @interface NeededForTesting { - -} diff --git a/java/com/android/voicemailomtp/OmtpConstants.java b/java/com/android/voicemailomtp/OmtpConstants.java deleted file mode 100644 index da2b998b6..000000000 --- a/java/com/android/voicemailomtp/OmtpConstants.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.support.annotation.IntDef; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.HashMap; -import java.util.Map; - -/** - * Wrapper class to hold relevant OMTP constants as defined in the OMTP spec. <p> In essence this is - * a programmatic representation of the relevant portions of OMTP spec. - */ -public class OmtpConstants { - public static final String SMS_FIELD_SEPARATOR = ";"; - public static final String SMS_KEY_VALUE_SEPARATOR = "="; - public static final String SMS_PREFIX_SEPARATOR = ":"; - - public static final String SYNC_SMS_PREFIX = "SYNC"; - public static final String STATUS_SMS_PREFIX = "STATUS"; - - // This is the format designated by the OMTP spec. - public static final String DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm Z"; - - /** OMTP protocol versions. */ - public static final String PROTOCOL_VERSION1_1 = "11"; - public static final String PROTOCOL_VERSION1_2 = "12"; - public static final String PROTOCOL_VERSION1_3 = "13"; - - ///////////////////////// Client/Mobile originated SMS ////////////////////// - - /** Mobile Originated requests */ - public static final String ACTIVATE_REQUEST = "Activate"; - public static final String DEACTIVATE_REQUEST = "Deactivate"; - public static final String STATUS_REQUEST = "Status"; - - /** fields that can be present in a Mobile Originated OMTP SMS */ - public static final String CLIENT_TYPE = "ct"; - public static final String APPLICATION_PORT = "pt"; - public static final String PROTOCOL_VERSION = "pv"; - - - //////////////////////////////// Sync SMS fields //////////////////////////// - - /** - * Sync SMS fields. - * <p> - * Each string constant is the field's key in the SMS body which is used by the parser to - * identify the field's value, if present, in the SMS body. - */ - - /** - * The event that triggered this SYNC SMS. - * See {@link OmtpConstants#SYNC_TRIGGER_EVENT_VALUES} - */ - public static final String SYNC_TRIGGER_EVENT = "ev"; - public static final String MESSAGE_UID = "id"; - public static final String MESSAGE_LENGTH = "l"; - public static final String NUM_MESSAGE_COUNT = "c"; - /** See {@link OmtpConstants#CONTENT_TYPE_VALUES} */ - public static final String CONTENT_TYPE = "t"; - public static final String SENDER = "s"; - public static final String TIME = "dt"; - - /** - * SYNC message trigger events. - * <p> - * These are the possible values of {@link OmtpConstants#SYNC_TRIGGER_EVENT}. - */ - public static final String NEW_MESSAGE = "NM"; - public static final String MAILBOX_UPDATE = "MBU"; - public static final String GREETINGS_UPDATE = "GU"; - - public static final String[] SYNC_TRIGGER_EVENT_VALUES = { - NEW_MESSAGE, - MAILBOX_UPDATE, - GREETINGS_UPDATE - }; - - /** - * Content types supported by OMTP VVM. - * <p> - * These are the possible values of {@link OmtpConstants#CONTENT_TYPE}. - */ - public static final String VOICE = "v"; - public static final String VIDEO = "o"; - public static final String FAX = "f"; - /** Voice message deposited by an external application */ - public static final String INFOTAINMENT = "i"; - /** Empty Call Capture - i.e. voicemail with no voice message. */ - public static final String ECC = "e"; - - public static final String[] CONTENT_TYPE_VALUES = {VOICE, VIDEO, FAX, INFOTAINMENT, ECC}; - - ////////////////////////////// Status SMS fields //////////////////////////// - - /** - * Status SMS fields. - * <p> - * Each string constant is the field's key in the SMS body which is used by the parser to - * identify the field's value, if present, in the SMS body. - */ - /** See {@link OmtpConstants#PROVISIONING_STATUS_VALUES} */ - public static final String PROVISIONING_STATUS = "st"; - /** See {@link OmtpConstants#RETURN_CODE_VALUES} */ - public static final String RETURN_CODE = "rc"; - /** URL to send users to for activation VVM */ - public static final String SUBSCRIPTION_URL = "rs"; - /** IMAP4/SMTP server IP address or fully qualified domain name */ - public static final String SERVER_ADDRESS = "srv"; - /** Phone number to access voicemails through Telephony User Interface */ - public static final String TUI_ACCESS_NUMBER = "tui"; - public static final String TUI_PASSWORD_LENGTH = "pw_len"; - /** Number to send client origination SMS */ - public static final String CLIENT_SMS_DESTINATION_NUMBER = "dn"; - public static final String IMAP_PORT = "ipt"; - public static final String IMAP_USER_NAME = "u"; - public static final String IMAP_PASSWORD = "pw"; - public static final String SMTP_PORT = "spt"; - public static final String SMTP_USER_NAME = "smtp_u"; - public static final String SMTP_PASSWORD = "smtp_pw"; - - /** - * User provisioning status values. - * <p> - * Referred by {@link OmtpConstants#PROVISIONING_STATUS}. - */ - public static final String SUBSCRIBER_NEW = "N"; - public static final String SUBSCRIBER_READY = "R"; - public static final String SUBSCRIBER_PROVISIONED = "P"; - public static final String SUBSCRIBER_UNKNOWN = "U"; - public static final String SUBSCRIBER_BLOCKED = "B"; - - public static final String[] PROVISIONING_STATUS_VALUES = { - SUBSCRIBER_NEW, - SUBSCRIBER_READY, - SUBSCRIBER_PROVISIONED, - SUBSCRIBER_UNKNOWN, - SUBSCRIBER_BLOCKED - }; - - /** - * The return code included in a status message. - * <p> - * These are the possible values of {@link OmtpConstants#RETURN_CODE}. - */ - public static final String SUCCESS = "0"; - public static final String SYSTEM_ERROR = "1"; - public static final String SUBSCRIBER_ERROR = "2"; - public static final String MAILBOX_UNKNOWN = "3"; - public static final String VVM_NOT_ACTIVATED = "4"; - public static final String VVM_NOT_PROVISIONED = "5"; - public static final String VVM_CLIENT_UKNOWN = "6"; - public static final String VVM_MAILBOX_NOT_INITIALIZED = "7"; - - public static final String[] RETURN_CODE_VALUES = { - SUCCESS, - SYSTEM_ERROR, - SUBSCRIBER_ERROR, - MAILBOX_UNKNOWN, - VVM_NOT_ACTIVATED, - VVM_NOT_PROVISIONED, - VVM_CLIENT_UKNOWN, - VVM_MAILBOX_NOT_INITIALIZED, - }; - - /** - * A map of all the field keys to the possible values they can have. - */ - public static final Map<String, String[]> possibleValuesMap = new HashMap<String, String[]>() {{ - put(SYNC_TRIGGER_EVENT, SYNC_TRIGGER_EVENT_VALUES); - put(CONTENT_TYPE, CONTENT_TYPE_VALUES); - put(PROVISIONING_STATUS, PROVISIONING_STATUS_VALUES); - put(RETURN_CODE, RETURN_CODE_VALUES); - }}; - - /** - * IMAP command extensions - */ - - /** - * OMTP spec v1.3 2.3.1 Change password request syntax - * - * This changes the PIN to access the Telephone User Interface, the traditional voicemail - * system. - */ - public static final String IMAP_CHANGE_TUI_PWD_FORMAT = "XCHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s"; - - /** - * OMTP spec v1.3 2.4.1 Change languate request syntax - * - * This changes the language in the Telephone User Interface. - */ - public static final String IMAP_CHANGE_VM_LANG_FORMAT = "XCHANGE_VM_LANG LANG=%1$s"; - - /** - * OMTP spec v1.3 2.5.1 Close NUT Request syntax - * - * This disables the new user tutorial, the message played to new users calling in the Telephone - * User Interface. - */ - public static final String IMAP_CLOSE_NUT = "XCLOSE_NUT"; - - /** - * Possible NO responses for CHANGE_TUI_PWD - */ - - public static final String RESPONSE_CHANGE_PIN_TOO_SHORT = "password too short"; - public static final String RESPONSE_CHANGE_PIN_TOO_LONG = "password too long"; - public static final String RESPONSE_CHANGE_PIN_TOO_WEAK = "password too weak"; - public static final String RESPONSE_CHANGE_PIN_MISMATCH = "old password mismatch"; - public static final String RESPONSE_CHANGE_PIN_INVALID_CHARACTER = - "password contains invalid characters"; - - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {CHANGE_PIN_SUCCESS, CHANGE_PIN_TOO_SHORT, CHANGE_PIN_TOO_LONG, - CHANGE_PIN_TOO_WEAK, CHANGE_PIN_MISMATCH, CHANGE_PIN_INVALID_CHARACTER, - CHANGE_PIN_SYSTEM_ERROR}) - - public @interface ChangePinResult { - - } - - public static final int CHANGE_PIN_SUCCESS = 0; - public static final int CHANGE_PIN_TOO_SHORT = 1; - public static final int CHANGE_PIN_TOO_LONG = 2; - public static final int CHANGE_PIN_TOO_WEAK = 3; - public static final int CHANGE_PIN_MISMATCH = 4; - public static final int CHANGE_PIN_INVALID_CHARACTER = 5; - public static final int CHANGE_PIN_SYSTEM_ERROR = 6; - - /** Indicates the client is Google visual voicemail version 1.0. */ - public static final String CLIENT_TYPE_GOOGLE_10 = "google.vvm.10"; -} diff --git a/java/com/android/voicemailomtp/OmtpEvents.java b/java/com/android/voicemailomtp/OmtpEvents.java deleted file mode 100644 index d5c2a8b03..000000000 --- a/java/com/android/voicemailomtp/OmtpEvents.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.support.annotation.IntDef; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Events internal to the OMTP client. These should be translated into {@link - * android.provider.VoicemailContract.Status} error codes before writing into the voicemail status - * table. - */ -public enum OmtpEvents { - - // Configuration State - CONFIG_REQUEST_STATUS_SUCCESS(Type.CONFIGURATION, true), - - CONFIG_PIN_SET(Type.CONFIGURATION, true), - // The voicemail PIN is replaced with a generated PIN, user should change it. - CONFIG_DEFAULT_PIN_REPLACED(Type.CONFIGURATION, true), - CONFIG_ACTIVATING(Type.CONFIGURATION, true), - // There are already activation records, this is only a book-keeping activation. - CONFIG_ACTIVATING_SUBSEQUENT(Type.CONFIGURATION, true), - CONFIG_STATUS_SMS_TIME_OUT(Type.CONFIGURATION), - CONFIG_SERVICE_NOT_AVAILABLE(Type.CONFIGURATION), - - // Data channel State - - // A new sync has started, old errors in data channel should be cleared. - DATA_IMAP_OPERATION_STARTED(Type.DATA_CHANNEL, true), - // Successfully downloaded/uploaded data from the server, which means the data channel is clear. - DATA_IMAP_OPERATION_COMPLETED(Type.DATA_CHANNEL, true), - // The port provided in the STATUS SMS is invalid. - DATA_INVALID_PORT(Type.DATA_CHANNEL), - // No connection to the internet, and the carrier requires cellular data - DATA_NO_CONNECTION_CELLULAR_REQUIRED(Type.DATA_CHANNEL), - // No connection to the internet. - DATA_NO_CONNECTION(Type.DATA_CHANNEL), - // Address lookup for the server hostname failed. DNS error? - DATA_CANNOT_RESOLVE_HOST_ON_NETWORK(Type.DATA_CHANNEL), - // All destination address that resolves to the server hostname are rejected or timed out - DATA_ALL_SOCKET_CONNECTION_FAILED(Type.DATA_CHANNEL), - // Failed to establish SSL with the server, either with a direct SSL connection or by - // STARTTLS command - DATA_CANNOT_ESTABLISH_SSL_SESSION(Type.DATA_CHANNEL), - // Identity of the server cannot be verified. - DATA_SSL_INVALID_HOST_NAME(Type.DATA_CHANNEL), - // The server rejected our username/password - DATA_BAD_IMAP_CREDENTIAL(Type.DATA_CHANNEL), - - DATA_AUTH_UNKNOWN_USER(Type.DATA_CHANNEL), - DATA_AUTH_UNKNOWN_DEVICE(Type.DATA_CHANNEL), - DATA_AUTH_INVALID_PASSWORD(Type.DATA_CHANNEL), - DATA_AUTH_MAILBOX_NOT_INITIALIZED(Type.DATA_CHANNEL), - DATA_AUTH_SERVICE_NOT_PROVISIONED(Type.DATA_CHANNEL), - DATA_AUTH_SERVICE_NOT_ACTIVATED(Type.DATA_CHANNEL), - DATA_AUTH_USER_IS_BLOCKED(Type.DATA_CHANNEL), - - // A command to the server didn't result with an "OK" or continuation request - DATA_REJECTED_SERVER_RESPONSE(Type.DATA_CHANNEL), - // The server did not greet us with a "OK", possibly not a IMAP server. - DATA_INVALID_INITIAL_SERVER_RESPONSE(Type.DATA_CHANNEL), - // An IOException occurred while trying to open an ImapConnection - // TODO: reduce scope - DATA_IOE_ON_OPEN(Type.DATA_CHANNEL), - // The SELECT command on a mailbox is rejected - DATA_MAILBOX_OPEN_FAILED(Type.DATA_CHANNEL), - // An IOException has occurred - // TODO: reduce scope - DATA_GENERIC_IMAP_IOE(Type.DATA_CHANNEL), - // An SslException has occurred while opening an ImapConnection - // TODO: reduce scope - DATA_SSL_EXCEPTION(Type.DATA_CHANNEL), - - // Notification Channel - - // Cell signal restored, can received VVM SMSs - NOTIFICATION_IN_SERVICE(Type.NOTIFICATION_CHANNEL, true), - // Cell signal lost, cannot received VVM SMSs - NOTIFICATION_SERVICE_LOST(Type.NOTIFICATION_CHANNEL, false), - - - // Other - OTHER_SOURCE_REMOVED(Type.OTHER, false), - - // VVM3 - VVM3_NEW_USER_SETUP_FAILED, - // Table 4. client internal error handling - VVM3_VMG_DNS_FAILURE, - VVM3_SPG_DNS_FAILURE, - VVM3_VMG_CONNECTION_FAILED, - VVM3_SPG_CONNECTION_FAILED, - VVM3_VMG_TIMEOUT, - VVM3_STATUS_SMS_TIMEOUT, - - VVM3_SUBSCRIBER_PROVISIONED, - VVM3_SUBSCRIBER_BLOCKED, - VVM3_SUBSCRIBER_UNKNOWN; - - public static class Type { - - @Retention(RetentionPolicy.SOURCE) - @IntDef({CONFIGURATION, DATA_CHANNEL, NOTIFICATION_CHANNEL, OTHER}) - public @interface Values { - - } - - public static final int CONFIGURATION = 1; - public static final int DATA_CHANNEL = 2; - public static final int NOTIFICATION_CHANNEL = 3; - public static final int OTHER = 4; - } - - private final int mType; - private final boolean mIsSuccess; - - OmtpEvents(int type, boolean isSuccess) { - mType = type; - mIsSuccess = isSuccess; - } - - OmtpEvents(int type) { - mType = type; - mIsSuccess = false; - } - - OmtpEvents() { - mType = Type.OTHER; - mIsSuccess = false; - } - - @Type.Values - public int getType() { - return mType; - } - - public boolean isSuccess() { - return mIsSuccess; - } - -} diff --git a/java/com/android/voicemailomtp/OmtpService.java b/java/com/android/voicemailomtp/OmtpService.java deleted file mode 100644 index 261a7cb32..000000000 --- a/java/com/android/voicemailomtp/OmtpService.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.content.Intent; -import android.telecom.PhoneAccountHandle; -import android.telephony.VisualVoicemailService; -import android.telephony.VisualVoicemailSms; - -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; - -public class OmtpService extends VisualVoicemailService { - - private static String TAG = "VvmOmtpService"; - - public static final String ACTION_SMS_RECEIVED = "com.android.vociemailomtp.sms.sms_received"; - - public static final String EXTRA_VOICEMAIL_SMS = "extra_voicemail_sms"; - - @Override - public void onCellServiceConnected(VisualVoicemailTask task, - final PhoneAccountHandle phoneAccountHandle) { - VvmLog.i(TAG, "onCellServiceConnected"); - ActivationTask - .start(OmtpService.this, phoneAccountHandle, null); - task.finish(); - } - - @Override - public void onSmsReceived(VisualVoicemailTask task, final VisualVoicemailSms sms) { - VvmLog.i(TAG, "onSmsReceived"); - Intent intent = new Intent(ACTION_SMS_RECEIVED); - intent.setPackage(getPackageName()); - intent.putExtra(EXTRA_VOICEMAIL_SMS, sms); - sendBroadcast(intent); - task.finish(); - } - - @Override - public void onSimRemoved(final VisualVoicemailTask task, - final PhoneAccountHandle phoneAccountHandle) { - VvmLog.i(TAG, "onSimRemoved"); - OmtpVvmSourceManager.getInstance(OmtpService.this).removeSource(phoneAccountHandle); - task.finish(); - } - - @Override - public void onStopped(VisualVoicemailTask task) { - VvmLog.i(TAG, "onStopped"); - } -} diff --git a/java/com/android/voicemailomtp/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemailomtp/OmtpVvmCarrierConfigHelper.java deleted file mode 100644 index b3e72d215..000000000 --- a/java/com/android/voicemailomtp/OmtpVvmCarrierConfigHelper.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.app.PendingIntent; -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.os.PersistableBundle; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.telecom.PhoneAccountHandle; -import android.telephony.CarrierConfigManager; -import android.telephony.TelephonyManager; -import android.telephony.VisualVoicemailService; -import android.telephony.VisualVoicemailSmsFilterSettings; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.voicemailomtp.protocol.VisualVoicemailProtocol; -import com.android.voicemailomtp.protocol.VisualVoicemailProtocolFactory; -import com.android.voicemailomtp.sms.StatusMessage; - -import java.util.Arrays; -import java.util.Set; - -/** - * Manages carrier dependent visual voicemail configuration values. The primary source is the value - * retrieved from CarrierConfigManager. If CarrierConfigManager does not provide the config - * (KEY_VVM_TYPE_STRING is empty, or "hidden" configs), then the value hardcoded in telephony will - * be used (in res/xml/vvm_config.xml) - * - * Hidden configs are new configs that are planned for future APIs, or miscellaneous settings that - * may clutter CarrierConfigManager too much. - * - * The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()} - */ -public class OmtpVvmCarrierConfigHelper { - - private static final String TAG = "OmtpVvmCarrierCfgHlpr"; - - static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING; - static final String KEY_VVM_DESTINATION_NUMBER_STRING = - CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING; - static final String KEY_VVM_PORT_NUMBER_INT = - CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT; - static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = - CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING; - static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = - "carrier_vvm_package_name_string_array"; - static final String KEY_VVM_PREFETCH_BOOL = - CarrierConfigManager.KEY_VVM_PREFETCH_BOOL; - static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = - CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL; - - /** - * @see #getSslPort() - */ - static final String KEY_VVM_SSL_PORT_NUMBER_INT = - "vvm_ssl_port_number_int"; - - /** - * @see #isLegacyModeEnabled() - */ - static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = - "vvm_legacy_mode_enabled_bool"; - - /** - * Ban a capability reported by the server from being used. The array of string should be a - * subset of the capabilities returned IMAP CAPABILITY command. - * - * @see #getDisabledCapabilities() - */ - static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = - "vvm_disabled_capabilities_string_array"; - static final String KEY_VVM_CLIENT_PREFIX_STRING = - "vvm_client_prefix_string"; - - private final Context mContext; - private final PersistableBundle mCarrierConfig; - private final String mVvmType; - private final VisualVoicemailProtocol mProtocol; - private final PersistableBundle mTelephonyConfig; - - private PhoneAccountHandle mPhoneAccountHandle; - - public OmtpVvmCarrierConfigHelper(Context context, PhoneAccountHandle handle) { - mContext = context; - mPhoneAccountHandle = handle; - mCarrierConfig = getCarrierConfig(); - - TelephonyManager telephonyManager = - (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - mTelephonyConfig = new TelephonyVvmConfigManager(context.getResources()) - .getConfig(telephonyManager.createForPhoneAccountHandle(mPhoneAccountHandle) - .getSimOperator()); - - mVvmType = getVvmType(); - mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType); - - } - - @VisibleForTesting - OmtpVvmCarrierConfigHelper(Context context, PersistableBundle carrierConfig, - PersistableBundle telephonyConfig) { - mContext = context; - mCarrierConfig = carrierConfig; - mTelephonyConfig = telephonyConfig; - mVvmType = getVvmType(); - mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType); - } - - public Context getContext() { - return mContext; - } - - @Nullable - public PhoneAccountHandle getPhoneAccountHandle() { - return mPhoneAccountHandle; - } - - /** - * return whether the carrier's visual voicemail is supported, with KEY_VVM_TYPE_STRING set as a - * known protocol. - */ - public boolean isValid() { - return mProtocol != null; - } - - @Nullable - public String getVvmType() { - return (String) getValue(KEY_VVM_TYPE_STRING); - } - - @Nullable - public VisualVoicemailProtocol getProtocol() { - return mProtocol; - } - - /** - * @returns arbitrary String stored in the config file. Used for protocol specific values. - */ - @Nullable - public String getString(String key) { - return (String) getValue(key); - } - - @Nullable - public Set<String> getCarrierVvmPackageNames() { - Set<String> names = getCarrierVvmPackageNames(mCarrierConfig); - if (names != null) { - return names; - } - return getCarrierVvmPackageNames(mTelephonyConfig); - } - - private static Set<String> getCarrierVvmPackageNames(@Nullable PersistableBundle bundle) { - if (bundle == null) { - return null; - } - Set<String> names = new ArraySet<>(); - if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING)) { - names.add(bundle.getString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING)); - } - if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY)) { - names.addAll(Arrays.asList( - bundle.getStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY))); - } - if (names.isEmpty()) { - return null; - } - return names; - } - - /** - * For checking upon sim insertion whether visual voicemail should be enabled. This method does - * so by checking if the carrier's voicemail app is installed. - */ - public boolean isEnabledByDefault() { - if (!isValid()) { - return false; - } - - Set<String> carrierPackages = getCarrierVvmPackageNames(); - if (carrierPackages == null) { - return true; - } - for (String packageName : carrierPackages) { - try { - mContext.getPackageManager().getPackageInfo(packageName, 0); - return false; - } catch (NameNotFoundException e) { - // Do nothing. - } - } - return true; - } - - public boolean isCellularDataRequired() { - return (boolean) getValue(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false); - } - - public boolean isPrefetchEnabled() { - return (boolean) getValue(KEY_VVM_PREFETCH_BOOL, true); - } - - - public int getApplicationPort() { - return (int) getValue(KEY_VVM_PORT_NUMBER_INT, 0); - } - - @Nullable - public String getDestinationNumber() { - return (String) getValue(KEY_VVM_DESTINATION_NUMBER_STRING); - } - - /** - * Hidden config. - * - * @return Port to start a SSL IMAP connection directly. - * - * TODO: make config public and add to CarrierConfigManager - */ - public int getSslPort() { - return (int) getValue(KEY_VVM_SSL_PORT_NUMBER_INT, 0); - } - - /** - * Hidden Config. - * - * <p>Sometimes the server states it supports a certain feature but we found they have bug on - * the server side. For example, in b/28717550 the server reported AUTH=DIGEST-MD5 capability - * but using it to login will cause subsequent response to be erroneous. - * - * @return A set of capabilities that is reported by the IMAP CAPABILITY command, but determined - * to have issues and should not be used. - */ - @Nullable - public Set<String> getDisabledCapabilities() { - Set<String> disabledCapabilities = getDisabledCapabilities(mCarrierConfig); - if (disabledCapabilities != null) { - return disabledCapabilities; - } - return getDisabledCapabilities(mTelephonyConfig); - } - - @Nullable - private static Set<String> getDisabledCapabilities(@Nullable PersistableBundle bundle) { - if (bundle == null) { - return null; - } - if (!bundle.containsKey(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY)) { - return null; - } - ArraySet<String> result = new ArraySet<String>(); - result.addAll( - Arrays.asList(bundle.getStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY))); - return result; - } - - public String getClientPrefix() { - String prefix = (String) getValue(KEY_VVM_CLIENT_PREFIX_STRING); - if (prefix != null) { - return prefix; - } - return "//VVM"; - } - - /** - * Should legacy mode be used when the OMTP VVM client is disabled? - * - * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on - * the client side all network operations are disabled. SMSs are still monitored so a new - * message SYNC SMS will be translated to show a message waiting indicator, like traditional - * voicemails. - * - * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to - * function without the data cost. - */ - public boolean isLegacyModeEnabled() { - return (boolean) getValue(KEY_VVM_LEGACY_MODE_ENABLED_BOOL, false); - } - - public void startActivation() { - PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(); - if (phoneAccountHandle == null) { - // This should never happen - // Error logged in getPhoneAccountHandle(). - return; - } - - if (mVvmType == null || mVvmType.isEmpty()) { - // The VVM type is invalid; we should never have gotten here in the first place since - // this is loaded initially in the constructor, and callers should check isValid() - // before trying to start activation anyways. - VvmLog.e(TAG, "startActivation : vvmType is null or empty for account " + - phoneAccountHandle); - return; - } - - if (mProtocol != null) { - ActivationTask.start(mContext, mPhoneAccountHandle, null); - } - } - - public void activateSmsFilter() { - VisualVoicemailService.setSmsFilterSettings(mContext, getPhoneAccountHandle(), - new VisualVoicemailSmsFilterSettings.Builder() - .setClientPrefix(getClientPrefix()) - .build()); - } - - public void startDeactivation() { - if (!isLegacyModeEnabled()) { - // SMS should still be filtered in legacy mode - VisualVoicemailService.setSmsFilterSettings(mContext, getPhoneAccountHandle(), null); - } - if (mProtocol != null) { - mProtocol.startDeactivation(this); - } - } - - public boolean supportsProvisioning() { - if (mProtocol != null) { - return mProtocol.supportsProvisioning(); - } - return false; - } - - public void startProvisioning(ActivationTask task, PhoneAccountHandle phone, - VoicemailStatus.Editor status, StatusMessage message, Bundle data) { - if (mProtocol != null) { - mProtocol.startProvisioning(task, phone, this, status, message, data); - } - } - - public void requestStatus(@Nullable PendingIntent sentIntent) { - if (mProtocol != null) { - mProtocol.requestStatus(this, sentIntent); - } - } - - public void handleEvent(VoicemailStatus.Editor status, OmtpEvents event) { - VvmLog.i(TAG, "OmtpEvent:" + event); - if (mProtocol != null) { - mProtocol.handleEvent(mContext, this, status, event); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("OmtpVvmCarrierConfigHelper ["); - builder.append("phoneAccountHandle: ").append(mPhoneAccountHandle) - .append(", carrierConfig: ").append(mCarrierConfig != null) - .append(", telephonyConfig: ").append(mTelephonyConfig != null) - .append(", type: ").append(getVvmType()) - .append(", destinationNumber: ").append(getDestinationNumber()) - .append(", applicationPort: ").append(getApplicationPort()) - .append(", sslPort: ").append(getSslPort()) - .append(", isEnabledByDefault: ").append(isEnabledByDefault()) - .append(", isCellularDataRequired: ").append(isCellularDataRequired()) - .append(", isPrefetchEnabled: ").append(isPrefetchEnabled()) - .append(", isLegacyModeEnabled: ").append(isLegacyModeEnabled()) - .append("]"); - return builder.toString(); - } - - @Nullable - private PersistableBundle getCarrierConfig() { - - CarrierConfigManager carrierConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (carrierConfigManager == null) { - VvmLog.w(TAG, "No carrier config service found."); - return null; - } - - PersistableBundle config = TelephonyManagerStub - .getCarrirConfigForPhoneAccountHandle(getContext(), mPhoneAccountHandle); - - if (TextUtils.isEmpty(config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING))) { - return null; - } - return config; - } - - @Nullable - private Object getValue(String key) { - return getValue(key, null); - } - - @Nullable - private Object getValue(String key, Object defaultValue) { - Object result; - if (mCarrierConfig != null) { - result = mCarrierConfig.get(key); - if (result != null) { - return result; - } - } - if (mTelephonyConfig != null) { - result = mTelephonyConfig.get(key); - if (result != null) { - return result; - } - } - return defaultValue; - } - -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/SubscriptionInfoHelper.java b/java/com/android/voicemailomtp/SubscriptionInfoHelper.java deleted file mode 100644 index b916247ad..000000000 --- a/java/com/android/voicemailomtp/SubscriptionInfoHelper.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.app.ActionBar; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.text.TextUtils; - -/** - * Helper for manipulating intents or components with subscription-related information. - * - * In settings, subscription ids and labels are passed along to indicate that settings - * are being changed for particular subscriptions. This helper provides functions for - * helping extract this info and perform common operations using this info. - */ -public class SubscriptionInfoHelper { - public static final int NO_SUB_ID = -1; - - // Extra on intent containing the id of a subscription. - public static final String SUB_ID_EXTRA = - "com.android.voicemailomtp.settings.SubscriptionInfoHelper.SubscriptionId"; - // Extra on intent containing the label of a subscription. - private static final String SUB_LABEL_EXTRA = - "com.android.voicemailomtp.settings.SubscriptionInfoHelper.SubscriptionLabel"; - - private static Context mContext; - - private static int mSubId = NO_SUB_ID; - private static String mSubLabel; - - /** - * Instantiates the helper, by extracting the subscription id and label from the intent. - */ - public SubscriptionInfoHelper(Context context, Intent intent) { - mContext = context; - mSubId = intent.getIntExtra(SUB_ID_EXTRA, NO_SUB_ID); - mSubLabel = intent.getStringExtra(SUB_LABEL_EXTRA); - } - - /** - * Sets the action bar title to the string specified by the given resource id, formatting - * it with the subscription label. This assumes the resource string is formattable with a - * string-type specifier. - * - * If the subscription label does not exists, leave the existing title. - */ - public void setActionBarTitle(ActionBar actionBar, Resources res, int resId) { - if (actionBar == null || TextUtils.isEmpty(mSubLabel)) { - return; - } - - String title = String.format(res.getString(resId), mSubLabel); - actionBar.setTitle(title); - } - - public int getSubId() { - return mSubId; - } -} diff --git a/java/com/android/voicemailomtp/TelephonyManagerStub.java b/java/com/android/voicemailomtp/TelephonyManagerStub.java deleted file mode 100644 index e2e5dacdb..000000000 --- a/java/com/android/voicemailomtp/TelephonyManagerStub.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build.VERSION_CODES; -import android.os.PersistableBundle; -import android.telecom.PhoneAccount; -import android.telecom.PhoneAccountHandle; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import java.lang.reflect.Method; - -/** - * Temporary stub for public APIs that should be added into telephony manager. - * - * <p>TODO(b/32637799) remove this. - */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class TelephonyManagerStub { - - private static final String TAG = "TelephonyManagerStub"; - - public static void showVoicemailNotification(int voicemailCount) { - - } - - /** - * Dismisses the message waiting (voicemail) indicator. - * - * @param subId the subscription id we should dismiss the notification for. - */ - public static void clearMwiIndicator(int subId) { - - } - - public static void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, - boolean enabled) { - - } - - public static int getSubIdForPhoneAccount(Context context, PhoneAccount phoneAccount) { - // Hidden - TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); - try { - Method method = TelephonyManager.class - .getMethod("getSubIdForPhoneAccount", PhoneAccount.class); - return (int) method.invoke(telephonyManager, phoneAccount); - } catch (Exception e) { - VvmLog.e(TAG, "reflection call to getSubIdForPhoneAccount failed:", e); - } - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } - - public static String getNetworkSpecifierForPhoneAccountHandle(Context context, - PhoneAccountHandle phoneAccountHandle) { - return String.valueOf(SubscriptionManager.getDefaultDataSubscriptionId()); - } - - public static PersistableBundle getCarrirConfigForPhoneAccountHandle(Context context, - PhoneAccountHandle phoneAccountHandle) { - return context.getSystemService(CarrierConfigManager.class).getConfig(); - } -} diff --git a/java/com/android/voicemailomtp/TelephonyVvmConfigManager.java b/java/com/android/voicemailomtp/TelephonyVvmConfigManager.java deleted file mode 100644 index ab13d36ad..000000000 --- a/java/com/android/voicemailomtp/TelephonyVvmConfigManager.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.content.res.Resources; -import android.os.PersistableBundle; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.util.ArrayMap; -import com.android.voicemailomtp.utils.XmlUtils; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Map; -import java.util.Map.Entry; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -/** - * Load and caches telephony vvm config from res/xml/vvm_config.xml - */ -public class TelephonyVvmConfigManager { - - private static final String TAG = "TelephonyVvmCfgMgr"; - - private static final boolean USE_DEBUG_CONFIG = false; - - private static final String TAG_PERSISTABLEMAP = "pbundle_as_map"; - - static final String KEY_MCCMNC = "mccmnc"; - - private static Map<String, PersistableBundle> sCachedConfigs; - - private final Map<String, PersistableBundle> mConfigs; - - public TelephonyVvmConfigManager(Resources resources) { - if (sCachedConfigs == null) { - sCachedConfigs = loadConfigs(resources.getXml(R.xml.vvm_config)); - } - mConfigs = sCachedConfigs; - } - - @VisibleForTesting - TelephonyVvmConfigManager(XmlPullParser parser) { - mConfigs = loadConfigs(parser); - } - - @Nullable - public PersistableBundle getConfig(String mccMnc) { - if (USE_DEBUG_CONFIG) { - return mConfigs.get("TEST"); - } - return mConfigs.get(mccMnc); - } - - private static Map<String, PersistableBundle> loadConfigs(XmlPullParser parser) { - Map<String, PersistableBundle> configs = new ArrayMap<>(); - try { - ArrayList list = readBundleList(parser); - for (Object object : list) { - if (!(object instanceof PersistableBundle)) { - throw new IllegalArgumentException("PersistableBundle expected, got " + object); - } - PersistableBundle bundle = (PersistableBundle) object; - String[] mccMncs = bundle.getStringArray(KEY_MCCMNC); - if (mccMncs == null) { - throw new IllegalArgumentException("MCCMNC is null"); - } - for (String mccMnc : mccMncs) { - configs.put(mccMnc, bundle); - } - } - } catch (IOException | XmlPullParserException e) { - throw new RuntimeException(e); - } - return configs; - } - - @Nullable - public static ArrayList readBundleList(XmlPullParser in) throws IOException, - XmlPullParserException { - final int outerDepth = in.getDepth(); - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { - if (event == XmlPullParser.START_TAG) { - final String startTag = in.getName(); - final String[] tagName = new String[1]; - in.next(); - return XmlUtils.readThisListXml(in, startTag, tagName, - new MyReadMapCallback(), false); - } - } - return null; - } - - public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException, - XmlPullParserException { - final int outerDepth = in.getDepth(); - final String startTag = in.getName(); - final String[] tagName = new String[1]; - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { - if (event == XmlPullParser.START_TAG) { - ArrayMap<String, ?> map = - XmlUtils.readThisArrayMapXml(in, startTag, tagName, - new MyReadMapCallback()); - PersistableBundle result = new PersistableBundle(); - for (Entry<String, ?> entry : map.entrySet()) { - Object value = entry.getValue(); - if (value instanceof Integer) { - result.putInt(entry.getKey(), (int) value); - } else if (value instanceof Boolean) { - result.putBoolean(entry.getKey(), (boolean) value); - } else if (value instanceof String) { - result.putString(entry.getKey(), (String) value); - } else if (value instanceof String[]) { - result.putStringArray(entry.getKey(), (String[]) value); - } else if (value instanceof PersistableBundle) { - result.putPersistableBundle(entry.getKey(), (PersistableBundle) value); - } - } - return result; - } - } - return PersistableBundle.EMPTY; - } - - static class MyReadMapCallback implements XmlUtils.ReadMapCallback { - - @Override - public Object readThisUnknownObjectXml(XmlPullParser in, String tag) - throws XmlPullParserException, IOException { - if (TAG_PERSISTABLEMAP.equals(tag)) { - return restoreFromXml(in); - } - throw new XmlPullParserException("Unknown tag=" + tag); - } - } -} diff --git a/java/com/android/voicemailomtp/VisualVoicemailPreferences.java b/java/com/android/voicemailomtp/VisualVoicemailPreferences.java deleted file mode 100644 index 5bc2c6951..000000000 --- a/java/com/android/voicemailomtp/VisualVoicemailPreferences.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import java.util.Set; - -/** - * Save visual voicemail values in shared preferences to be retrieved later. Because a voicemail - * source is tied 1:1 to a phone account, the phone account handle is used in the key for each - * voicemail source and the associated data. - */ -public class VisualVoicemailPreferences { - - private static final String VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX = - "visual_voicemail_"; - - private final SharedPreferences mPreferences; - private final PhoneAccountHandle mPhoneAccountHandle; - - public VisualVoicemailPreferences(Context context, PhoneAccountHandle phoneAccountHandle) { - mPreferences = PreferenceManager.getDefaultSharedPreferences(context); - mPhoneAccountHandle = phoneAccountHandle; - } - - public class Editor { - - private final SharedPreferences.Editor mEditor; - - private Editor() { - mEditor = mPreferences.edit(); - } - - public void apply() { - mEditor.apply(); - } - - public Editor putBoolean(String key, boolean value) { - mEditor.putBoolean(getKey(key), value); - return this; - } - - @NeededForTesting - public Editor putFloat(String key, float value) { - mEditor.putFloat(getKey(key), value); - return this; - } - - public Editor putInt(String key, int value) { - mEditor.putInt(getKey(key), value); - return this; - } - - @NeededForTesting - public Editor putLong(String key, long value) { - mEditor.putLong(getKey(key), value); - return this; - } - - public Editor putString(String key, String value) { - mEditor.putString(getKey(key), value); - return this; - } - - @NeededForTesting - public Editor putStringSet(String key, Set<String> value) { - mEditor.putStringSet(getKey(key), value); - return this; - } - } - - public Editor edit() { - return new Editor(); - } - - public boolean getBoolean(String key, boolean defValue) { - return getValue(key, defValue); - } - - @NeededForTesting - public float getFloat(String key, float defValue) { - return getValue(key, defValue); - } - - public int getInt(String key, int defValue) { - return getValue(key, defValue); - } - - @NeededForTesting - public long getLong(String key, long defValue) { - return getValue(key, defValue); - } - - public String getString(String key, String defValue) { - return getValue(key, defValue); - } - - @Nullable - public String getString(String key) { - return getValue(key, null); - } - - @NeededForTesting - public Set<String> getStringSet(String key, Set<String> defValue) { - return getValue(key, defValue); - } - - public boolean contains(String key) { - return mPreferences.contains(getKey(key)); - } - - private <T> T getValue(String key, T defValue) { - if (!contains(key)) { - return defValue; - } - Object object = mPreferences.getAll().get(getKey(key)); - if (object == null) { - return defValue; - } - return (T) object; - } - - private String getKey(String key) { - return VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX + key + "_" + mPhoneAccountHandle.getId(); - } -} diff --git a/java/com/android/voicemailomtp/Voicemail.java b/java/com/android/voicemailomtp/Voicemail.java deleted file mode 100644 index 9d8395142..000000000 --- a/java/com/android/voicemailomtp/Voicemail.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp; - -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import android.telecom.PhoneAccountHandle; -import android.text.TextUtils; - -/** - * Represents a single voicemail stored in the voicemail content provider. - */ -public class Voicemail implements Parcelable { - - private final Long mTimestamp; - private final String mNumber; - private final PhoneAccountHandle mPhoneAccount; - private final Long mId; - private final Long mDuration; - private final String mSource; - private final String mProviderData; - private final Uri mUri; - private final Boolean mIsRead; - private final Boolean mHasContent; - private final String mTranscription; - - private Voicemail(Long timestamp, String number, PhoneAccountHandle phoneAccountHandle, Long id, - Long duration, String source, String providerData, Uri uri, Boolean isRead, - Boolean hasContent, String transcription) { - mTimestamp = timestamp; - mNumber = number; - mPhoneAccount = phoneAccountHandle; - mId = id; - mDuration = duration; - mSource = source; - mProviderData = providerData; - mUri = uri; - mIsRead = isRead; - mHasContent = hasContent; - mTranscription = transcription; - } - - /** - * Create a {@link Builder} for a new {@link Voicemail} to be inserted. <p> The number and the - * timestamp are mandatory for insertion. - */ - public static Builder createForInsertion(long timestamp, String number) { - return new Builder().setNumber(number).setTimestamp(timestamp); - } - - /** - * Create a {@link Builder} for a {@link Voicemail} to be updated (or deleted). <p> The id and - * source data fields are mandatory for update - id is necessary for updating the database and - * source data is necessary for updating the server. - */ - public static Builder createForUpdate(long id, String sourceData) { - return new Builder().setId(id).setSourceData(sourceData); - } - - /** - * Builder pattern for creating a {@link Voicemail}. The builder must be created with the {@link - * #createForInsertion(long, String)} method. <p> This class is <b>not thread safe</b> - */ - public static class Builder { - - private Long mBuilderTimestamp; - private String mBuilderNumber; - private PhoneAccountHandle mBuilderPhoneAccount; - private Long mBuilderId; - private Long mBuilderDuration; - private String mBuilderSourcePackage; - private String mBuilderSourceData; - private Uri mBuilderUri; - private Boolean mBuilderIsRead; - private boolean mBuilderHasContent; - private String mBuilderTranscription; - - /** - * You should use the correct factory method to construct a builder. - */ - private Builder() { - } - - public Builder setNumber(String number) { - mBuilderNumber = number; - return this; - } - - public Builder setTimestamp(long timestamp) { - mBuilderTimestamp = timestamp; - return this; - } - - public Builder setPhoneAccount(PhoneAccountHandle phoneAccount) { - mBuilderPhoneAccount = phoneAccount; - return this; - } - - public Builder setId(long id) { - mBuilderId = id; - return this; - } - - public Builder setDuration(long duration) { - mBuilderDuration = duration; - return this; - } - - public Builder setSourcePackage(String sourcePackage) { - mBuilderSourcePackage = sourcePackage; - return this; - } - - public Builder setSourceData(String sourceData) { - mBuilderSourceData = sourceData; - return this; - } - - public Builder setUri(Uri uri) { - mBuilderUri = uri; - return this; - } - - public Builder setIsRead(boolean isRead) { - mBuilderIsRead = isRead; - return this; - } - - public Builder setHasContent(boolean hasContent) { - mBuilderHasContent = hasContent; - return this; - } - - public Builder setTranscription(String transcription) { - mBuilderTranscription = transcription; - return this; - } - - public Voicemail build() { - mBuilderId = mBuilderId == null ? -1 : mBuilderId; - mBuilderTimestamp = mBuilderTimestamp == null ? 0 : mBuilderTimestamp; - mBuilderDuration = mBuilderDuration == null ? 0 : mBuilderDuration; - mBuilderIsRead = mBuilderIsRead == null ? false : mBuilderIsRead; - return new Voicemail(mBuilderTimestamp, mBuilderNumber, mBuilderPhoneAccount, - mBuilderId, mBuilderDuration, mBuilderSourcePackage, mBuilderSourceData, - mBuilderUri, mBuilderIsRead, mBuilderHasContent, mBuilderTranscription); - } - } - - /** - * The identifier of the voicemail in the content provider. <p> This may be missing in the case - * of a new {@link Voicemail} that we plan to insert into the content provider, since until it - * has been inserted we don't know what id it should have. If none is specified, we return -1. - */ - public long getId() { - return mId; - } - - /** - * The number of the person leaving the voicemail, empty string if unknown, null if not set. - */ - public String getNumber() { - return mNumber; - } - - /** - * The phone account associated with the voicemail, null if not set. - */ - public PhoneAccountHandle getPhoneAccount() { - return mPhoneAccount; - } - - /** - * The timestamp the voicemail was received, in millis since the epoch, zero if not set. - */ - public long getTimestampMillis() { - return mTimestamp; - } - - /** - * Gets the duration of the voicemail in millis, or zero if the field is not set. - */ - public long getDuration() { - return mDuration; - } - - /** - * Returns the package name of the source that added this voicemail, or null if this field is - * not set. - */ - public String getSourcePackage() { - return mSource; - } - - /** - * Returns the application-specific data type stored with the voicemail, or null if this field - * is not set. <p> Source data is typically used as an identifier to uniquely identify the - * voicemail against the voicemail server. This is likely to be something like the IMAP UID, or - * some other server-generated identifying string. - */ - public String getSourceData() { - return mProviderData; - } - - /** - * Gets the Uri that can be used to refer to this voicemail, and to make it play. <p> Returns - * null if we don't know the Uri. - */ - public Uri getUri() { - return mUri; - } - - /** - * Tells us if the voicemail message has been marked as read. <p> Always returns false if this - * field has not been set, i.e. if hasRead() returns false. - */ - public boolean isRead() { - return mIsRead; - } - - /** - * Tells us if there is content stored at the Uri. - */ - public boolean hasContent() { - return mHasContent; - } - - /** - * Returns the text transcription of this voicemail, or null if this field is not set. - */ - public String getTranscription() { - return mTranscription; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mTimestamp); - writeCharSequence(dest, mNumber); - if (mPhoneAccount == null) { - dest.writeInt(0); - } else { - dest.writeInt(1); - mPhoneAccount.writeToParcel(dest, flags); - } - dest.writeLong(mId); - dest.writeLong(mDuration); - writeCharSequence(dest, mSource); - writeCharSequence(dest, mProviderData); - if (mUri == null) { - dest.writeInt(0); - } else { - dest.writeInt(1); - mUri.writeToParcel(dest, flags); - } - if (mIsRead) { - dest.writeInt(1); - } else { - dest.writeInt(0); - } - if (mHasContent) { - dest.writeInt(1); - } else { - dest.writeInt(0); - } - writeCharSequence(dest, mTranscription); - } - - public static final Creator<Voicemail> CREATOR - = new Creator<Voicemail>() { - @Override - public Voicemail createFromParcel(Parcel in) { - return new Voicemail(in); - } - - @Override - public Voicemail[] newArray(int size) { - return new Voicemail[size]; - } - }; - - private Voicemail(Parcel in) { - mTimestamp = in.readLong(); - mNumber = (String) readCharSequence(in); - if (in.readInt() > 0) { - mPhoneAccount = PhoneAccountHandle.CREATOR.createFromParcel(in); - } else { - mPhoneAccount = null; - } - mId = in.readLong(); - mDuration = in.readLong(); - mSource = (String) readCharSequence(in); - mProviderData = (String) readCharSequence(in); - if (in.readInt() > 0) { - mUri = Uri.CREATOR.createFromParcel(in); - } else { - mUri = null; - } - mIsRead = in.readInt() > 0 ? true : false; - mHasContent = in.readInt() > 0 ? true : false; - mTranscription = (String) readCharSequence(in); - } - - private static CharSequence readCharSequence(Parcel in) { - return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - } - - public static void writeCharSequence(Parcel dest, CharSequence val) { - TextUtils.writeToParcel(val, dest, 0); - } -} diff --git a/java/com/android/voicemailomtp/VoicemailStatus.java b/java/com/android/voicemailomtp/VoicemailStatus.java deleted file mode 100644 index 63007932e..000000000 --- a/java/com/android/voicemailomtp/VoicemailStatus.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.net.Uri; -import android.provider.VoicemailContract; -import android.provider.VoicemailContract.Status; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; - -public class VoicemailStatus { - - private static final String TAG = "VvmStatus"; - - public static class Editor { - - private final Context mContext; - @Nullable - private final PhoneAccountHandle mPhoneAccountHandle; - - private ContentValues mValues = new ContentValues(); - - private Editor(Context context, PhoneAccountHandle phoneAccountHandle) { - mContext = context; - mPhoneAccountHandle = phoneAccountHandle; - if (mPhoneAccountHandle == null) { - VvmLog.w(TAG, "VoicemailStatus.Editor created with null phone account, status will" - + " not be written"); - } - } - - @Nullable - public PhoneAccountHandle getPhoneAccountHandle() { - return mPhoneAccountHandle; - } - - public Editor setType(String type) { - mValues.put(Status.SOURCE_TYPE, type); - return this; - } - - public Editor setConfigurationState(int configurationState) { - mValues.put(Status.CONFIGURATION_STATE, configurationState); - return this; - } - - public Editor setDataChannelState(int dataChannelState) { - mValues.put(Status.DATA_CHANNEL_STATE, dataChannelState); - return this; - } - - public Editor setNotificationChannelState(int notificationChannelState) { - mValues.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState); - return this; - } - - public Editor setQuota(int occupied, int total) { - if (occupied == VoicemailContract.Status.QUOTA_UNAVAILABLE - && total == VoicemailContract.Status.QUOTA_UNAVAILABLE) { - return this; - } - - mValues.put(Status.QUOTA_OCCUPIED, occupied); - mValues.put(Status.QUOTA_TOTAL, total); - return this; - } - - /** - * Apply the changes to the {@link VoicemailStatus} {@link #Editor}. - * - * @return {@code true} if the changes were successfully applied, {@code false} otherwise. - */ - public boolean apply() { - if (mPhoneAccountHandle == null) { - return false; - } - mValues.put(Status.PHONE_ACCOUNT_COMPONENT_NAME, - mPhoneAccountHandle.getComponentName().flattenToString()); - mValues.put(Status.PHONE_ACCOUNT_ID, mPhoneAccountHandle.getId()); - ContentResolver contentResolver = mContext.getContentResolver(); - Uri statusUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName()); - try { - contentResolver.insert(statusUri, mValues); - } catch (IllegalArgumentException iae) { - VvmLog.e(TAG, "apply :: failed to insert content resolver ", iae); - mValues.clear(); - return false; - } - mValues.clear(); - return true; - } - - public ContentValues getValues() { - return mValues; - } - } - - /** - * A voicemail status editor that the decision of whether to actually write to the database can - * be deferred. This object will be passed around as a usual {@link Editor}, but {@link - * #apply()} doesn't do anything. If later the creator of this object decides any status changes - * written to it should be committed, {@link #deferredApply()} should be called. - */ - public static class DeferredEditor extends Editor { - - private DeferredEditor(Context context, PhoneAccountHandle phoneAccountHandle) { - super(context, phoneAccountHandle); - } - - @Override - public boolean apply() { - // Do nothing - return true; - } - - public void deferredApply() { - super.apply(); - } - } - - public static Editor edit(Context context, PhoneAccountHandle phoneAccountHandle) { - return new Editor(context, phoneAccountHandle); - } - - /** - * Reset the status to the "disabled" state, which the UI should not show anything for this - * phoneAccountHandle. - */ - public static void disable(Context context, PhoneAccountHandle phoneAccountHandle) { - edit(context, phoneAccountHandle) - .setConfigurationState(Status.CONFIGURATION_STATE_NOT_CONFIGURED) - .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION) - .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION) - .apply(); - } - - public static DeferredEditor deferredEdit(Context context, - PhoneAccountHandle phoneAccountHandle) { - return new DeferredEditor(context, phoneAccountHandle); - } -} diff --git a/java/com/android/voicemailomtp/VvmLog.java b/java/com/android/voicemailomtp/VvmLog.java deleted file mode 100644 index 2add66a53..000000000 --- a/java/com/android/voicemailomtp/VvmLog.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.util.Log; -import com.android.voicemailomtp.utils.IndentingPrintWriter; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayDeque; -import java.util.Calendar; -import java.util.Deque; -import java.util.Iterator; - -/** - * Helper methods for adding to OMTP visual voicemail local logs. - */ -public class VvmLog { - - private static final int MAX_OMTP_VVM_LOGS = 100; - - private static final LocalLog sLocalLog = new LocalLog(MAX_OMTP_VVM_LOGS); - - public static void log(String tag, String log) { - sLocalLog.log(tag + ": " + log); - } - - public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) { - IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(printwriter, " "); - indentingPrintWriter.increaseIndent(); - sLocalLog.dump(fd, indentingPrintWriter, args); - indentingPrintWriter.decreaseIndent(); - } - - public static int e(String tag, String log) { - log(tag, log); - return Log.e(tag, log); - } - - public static int e(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.e(tag, log, e); - } - - public static int w(String tag, String log) { - log(tag, log); - return Log.w(tag, log); - } - - public static int w(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.w(tag, log, e); - } - - public static int i(String tag, String log) { - log(tag, log); - return Log.i(tag, log); - } - - public static int i(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.i(tag, log, e); - } - - public static int d(String tag, String log) { - log(tag, log); - return Log.d(tag, log); - } - - public static int d(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.d(tag, log, e); - } - - public static int v(String tag, String log) { - log(tag, log); - return Log.v(tag, log); - } - - public static int v(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.v(tag, log, e); - } - - public static int wtf(String tag, String log) { - log(tag, log); - return Log.wtf(tag, log); - } - - public static int wtf(String tag, String log, Throwable e) { - log(tag, log + " " + e); - return Log.wtf(tag, log, e); - } - - /** - * Redact personally identifiable information for production users. If we are running in verbose - * mode, return the original string, otherwise return a SHA-1 hash of the input string. - */ - public static String pii(Object pii) { - if (pii == null) { - return String.valueOf(pii); - } - return "[PII]"; - } - - public static class LocalLog { - - private final Deque<String> mLog; - private final int mMaxLines; - - public LocalLog(int maxLines) { - mMaxLines = Math.max(0, maxLines); - mLog = new ArrayDeque<>(mMaxLines); - } - - public void log(String msg) { - if (mMaxLines <= 0) { - return; - } - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(System.currentTimeMillis()); - append(String.format("%tm-%td %tH:%tM:%tS.%tL - %s", c, c, c, c, c, c, msg)); - } - - private synchronized void append(String logLine) { - while (mLog.size() >= mMaxLines) { - mLog.remove(); - } - mLog.add(logLine); - } - - public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - Iterator<String> itr = mLog.iterator(); - while (itr.hasNext()) { - pw.println(itr.next()); - } - } - - public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { - Iterator<String> itr = mLog.descendingIterator(); - while (itr.hasNext()) { - pw.println(itr.next()); - } - } - - public static class ReadOnlyLocalLog { - - private final LocalLog mLog; - - ReadOnlyLocalLog(LocalLog log) { - mLog = log; - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mLog.dump(fd, pw, args); - } - - public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { - mLog.reverseDump(fd, pw, args); - } - } - - public ReadOnlyLocalLog readOnlyLocalLog() { - return new ReadOnlyLocalLog(this); - } - } -} diff --git a/java/com/android/voicemailomtp/VvmPackageInstallReceiver.java b/java/com/android/voicemailomtp/VvmPackageInstallReceiver.java deleted file mode 100644 index 7d9eee9f8..000000000 --- a/java/com/android/voicemailomtp/VvmPackageInstallReceiver.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.settings.VisualVoicemailSettingsUtil; -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; - -import java.util.Set; - -/** - * When a new package is installed, check if it matches any of the vvm carrier apps of the currently - * enabled dialer vvm sources. - */ -public class VvmPackageInstallReceiver extends BroadcastReceiver { - - private static final String TAG = "VvmPkgInstallReceiver"; - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getData() == null) { - return; - } - - String packageName = intent.getData().getSchemeSpecificPart(); - if (packageName == null) { - return; - } - - OmtpVvmSourceManager vvmSourceManager = OmtpVvmSourceManager.getInstance(context); - Set<PhoneAccountHandle> phoneAccounts = vvmSourceManager.getOmtpVvmSources(); - for (PhoneAccountHandle phoneAccount : phoneAccounts) { - if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) { - // Skip the check if this voicemail source's setting is overridden by the user. - continue; - } - - OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper( - context, phoneAccount); - if (carrierConfigHelper.getCarrierVvmPackageNames() == null) { - continue; - } - if (carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) { - // Force deactivate the client. The user can re-enable it in the settings. - // There are no need to update the settings for deactivation. At this point, if the - // default value is used it should be false because a carrier package is present. - VvmLog.i(TAG, "Carrier VVM package installed, disabling system VVM client"); - OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount); - carrierConfigHelper.startDeactivation(); - } - } - } -} diff --git a/java/com/android/voicemailomtp/VvmPhoneStateListener.java b/java/com/android/voicemailomtp/VvmPhoneStateListener.java deleted file mode 100644 index 1a3013d1f..000000000 --- a/java/com/android/voicemailomtp/VvmPhoneStateListener.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; - -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; -import com.android.voicemailomtp.sync.OmtpVvmSyncService; -import com.android.voicemailomtp.sync.SyncTask; -import com.android.voicemailomtp.sync.VoicemailStatusQueryHelper; - -/** - * Check if service is lost and indicate this in the voicemail status. - */ -public class VvmPhoneStateListener extends PhoneStateListener { - - private static final String TAG = "VvmPhoneStateListener"; - - private PhoneAccountHandle mPhoneAccount; - private Context mContext; - private int mPreviousState = -1; - - public VvmPhoneStateListener(Context context, PhoneAccountHandle accountHandle) { - // TODO: b/32637799 too much trouble to call super constructor through reflection, - // just use non-phoneAccountHandle version for now. - super(); - mContext = context; - mPhoneAccount = accountHandle; - } - - @Override - public void onServiceStateChanged(ServiceState serviceState) { - if (mPhoneAccount == null) { - VvmLog.e(TAG, "onServiceStateChanged on phoneAccount " + mPhoneAccount - + " with invalid phoneAccountHandle, ignoring"); - return; - } - - int state = serviceState.getState(); - if (state == mPreviousState || (state != ServiceState.STATE_IN_SERVICE - && mPreviousState != ServiceState.STATE_IN_SERVICE)) { - // Only interested in state changes or transitioning into or out of "in service". - // Otherwise just quit. - mPreviousState = state; - return; - } - - OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext, mPhoneAccount); - - if (state == ServiceState.STATE_IN_SERVICE) { - VoicemailStatusQueryHelper voicemailStatusQueryHelper = - new VoicemailStatusQueryHelper(mContext); - if (voicemailStatusQueryHelper.isVoicemailSourceConfigured(mPhoneAccount)) { - if (!voicemailStatusQueryHelper.isNotificationsChannelActive(mPhoneAccount)) { - VvmLog - .v(TAG, "Notifications channel is active for " + mPhoneAccount); - helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount), - OmtpEvents.NOTIFICATION_IN_SERVICE); - } - } - - if (OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) { - VvmLog - .v(TAG, "Signal returned: requesting resync for " + mPhoneAccount); - // If the source is already registered, run a full sync in case something was missed - // while signal was down. - SyncTask.start(mContext, mPhoneAccount, OmtpVvmSyncService.SYNC_FULL_SYNC); - } else { - VvmLog.v(TAG, - "Signal returned: reattempting activation for " + mPhoneAccount); - // Otherwise initiate an activation because this means that an OMTP source was - // recognized but either the activation text was not successfully sent or a response - // was not received. - helper.startActivation(); - } - } else { - VvmLog.v(TAG, "Notifications channel is inactive for " + mPhoneAccount); - - if (!OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) { - return; - } - helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount), - OmtpEvents.NOTIFICATION_SERVICE_LOST); - } - mPreviousState = state; - } -} diff --git a/java/com/android/voicemailomtp/fetch/FetchVoicemailReceiver.java b/java/com/android/voicemailomtp/fetch/FetchVoicemailReceiver.java deleted file mode 100644 index 85fea80d7..000000000 --- a/java/com/android/voicemailomtp/fetch/FetchVoicemailReceiver.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.fetch; - -import android.annotation.TargetApi; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Network; -import android.net.Uri; -import android.os.Build.VERSION_CODES; -import android.provider.VoicemailContract; -import android.provider.VoicemailContract.Voicemails; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.os.BuildCompat; -import android.telecom.PhoneAccountHandle; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.imap.ImapHelper.InitializingException; -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; -import com.android.voicemailomtp.sync.VvmNetworkRequestCallback; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class FetchVoicemailReceiver extends BroadcastReceiver { - - private static final String TAG = "FetchVoicemailReceiver"; - - final static String[] PROJECTION = new String[]{ - Voicemails.SOURCE_DATA, // 0 - Voicemails.PHONE_ACCOUNT_ID, // 1 - Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, // 2 - }; - - public static final int SOURCE_DATA = 0; - public static final int PHONE_ACCOUNT_ID = 1; - public static final int PHONE_ACCOUNT_COMPONENT_NAME = 2; - - // Number of retries - private static final int NETWORK_RETRY_COUNT = 3; - - private ContentResolver mContentResolver; - private Uri mUri; - private VvmNetworkRequestCallback mNetworkCallback; - private Context mContext; - private String mUid; - private PhoneAccountHandle mPhoneAccount; - private int mRetryCount = NETWORK_RETRY_COUNT; - - @Override - public void onReceive(final Context context, Intent intent) { - if (VoicemailContract.ACTION_FETCH_VOICEMAIL.equals(intent.getAction())) { - VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL received"); - mContext = context; - mContentResolver = context.getContentResolver(); - mUri = intent.getData(); - - if (mUri == null) { - VvmLog.w(TAG, - VoicemailContract.ACTION_FETCH_VOICEMAIL + " intent sent with no data"); - return; - } - - if (!context.getPackageName().equals( - mUri.getQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE))) { - // Ignore if the fetch request is for a voicemail not from this package. - VvmLog.e(TAG, - "ACTION_FETCH_VOICEMAIL from foreign pacakge " + context.getPackageName()); - return; - } - - Cursor cursor = mContentResolver.query(mUri, PROJECTION, null, null, null); - if (cursor == null) { - VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL query returned null"); - return; - } - try { - if (cursor.moveToFirst()) { - mUid = cursor.getString(SOURCE_DATA); - String accountId = cursor.getString(PHONE_ACCOUNT_ID); - if (TextUtils.isEmpty(accountId)) { - TelephonyManager telephonyManager = (TelephonyManager) - context.getSystemService(Context.TELEPHONY_SERVICE); - accountId = telephonyManager.getSimSerialNumber(); - - if (TextUtils.isEmpty(accountId)) { - VvmLog.e(TAG, "Account null and no default sim found."); - return; - } - } - - mPhoneAccount = new PhoneAccountHandle( - ComponentName.unflattenFromString( - cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)), - cursor.getString(PHONE_ACCOUNT_ID)); - if (!OmtpVvmSourceManager.getInstance(context) - .isVvmSourceRegistered(mPhoneAccount)) { - mPhoneAccount = getAccountFromMarshmallowAccount(context, mPhoneAccount); - if (mPhoneAccount == null) { - VvmLog.w(TAG, "Account not registered - cannot retrieve message."); - return; - } - VvmLog.i(TAG, "Fetching voicemail with Marshmallow PhoneAccountHandle"); - } - VvmLog.i(TAG, "Requesting network to fetch voicemail"); - mNetworkCallback = new fetchVoicemailNetworkRequestCallback(context, - mPhoneAccount); - mNetworkCallback.requestNetwork(); - } - } finally { - cursor.close(); - } - } - } - - /** - * In ag/930496 the format of PhoneAccountHandle has changed between Marshmallow and Nougat. - * This method attempts to search the account from the old database in registered sources using - * the old format. There's a chance of M phone account collisions on multi-SIM devices, but - * visual voicemail is not supported on M multi-SIM. - */ - @Nullable - private static PhoneAccountHandle getAccountFromMarshmallowAccount(Context context, - PhoneAccountHandle oldAccount) { - if (!BuildCompat.isAtLeastN()) { - return null; - } - for (PhoneAccountHandle handle : OmtpVvmSourceManager.getInstance(context) - .getOmtpVvmSources()) { - if (getIccSerialNumberFromFullIccSerialNumber(handle.getId()) - .equals(oldAccount.getId())) { - return handle; - } - } - return null; - } - - /** - * getIccSerialNumber() is used for ID before N, and getFullIccSerialNumber() after. - * getIccSerialNumber() stops at the first hex char. - */ - @NonNull - private static String getIccSerialNumberFromFullIccSerialNumber(@NonNull String id) { - for(int i =0;i<id.length();i++){ - if(!Character.isDigit(id.charAt(i))){ - return id.substring(0,i); - } - } - return id; - } - - private class fetchVoicemailNetworkRequestCallback extends VvmNetworkRequestCallback { - - public fetchVoicemailNetworkRequestCallback(Context context, - PhoneAccountHandle phoneAccount) { - super(context, phoneAccount, VoicemailStatus.edit(context, phoneAccount)); - } - - @Override - public void onAvailable(final Network network) { - super.onAvailable(network); - fetchVoicemail(network, getVoicemailStatusEditor()); - } - } - - private void fetchVoicemail(final Network network, final VoicemailStatus.Editor status) { - Executor executor = Executors.newCachedThreadPool(); - executor.execute(new Runnable() { - @Override - public void run() { - try { - while (mRetryCount > 0) { - VvmLog.i(TAG, "fetching voicemail, retry count=" + mRetryCount); - try (ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, - network, status)) { - boolean success = imapHelper.fetchVoicemailPayload( - new VoicemailFetchedCallback(mContext, mUri, mPhoneAccount), - mUid); - if (!success && mRetryCount > 0) { - VvmLog.i(TAG, "fetch voicemail failed, retrying"); - mRetryCount--; - } else { - return; - } - } catch (InitializingException e) { - VvmLog.w(TAG, "Can't retrieve Imap credentials ", e); - return; - } - } - } finally { - if (mNetworkCallback != null) { - mNetworkCallback.releaseNetwork(); - } - } - } - }); - } -} diff --git a/java/com/android/voicemailomtp/fetch/VoicemailFetchedCallback.java b/java/com/android/voicemailomtp/fetch/VoicemailFetchedCallback.java deleted file mode 100644 index 7479c4c4e..000000000 --- a/java/com/android/voicemailomtp/fetch/VoicemailFetchedCallback.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.fetch; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.net.Uri; -import android.provider.VoicemailContract.Voicemails; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telecom.TelecomManager; -import com.android.voicemailomtp.R; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.imap.VoicemailPayload; -import java.io.IOException; -import java.io.OutputStream; -import org.apache.commons.io.IOUtils; - -/** - * Callback for when a voicemail payload is fetched. It copies the returned stream to the data - * file corresponding to the voicemail. - */ -public class VoicemailFetchedCallback { - private static final String TAG = "VoicemailFetchedCallback"; - - private final Context mContext; - private final ContentResolver mContentResolver; - private final Uri mUri; - private final PhoneAccountHandle mPhoneAccountHandle; - - public VoicemailFetchedCallback(Context context, Uri uri, - PhoneAccountHandle phoneAccountHandle) { - mContext = context; - mContentResolver = context.getContentResolver(); - mUri = uri; - mPhoneAccountHandle = phoneAccountHandle; - } - - /** - * Saves the voicemail payload data into the voicemail provider then sets the "has_content" bit - * of the voicemail to "1". - * - * @param voicemailPayload The object containing the content data for the voicemail - */ - public void setVoicemailContent(@Nullable VoicemailPayload voicemailPayload) { - if (voicemailPayload == null) { - VvmLog.i(TAG, "Payload not found, message has unsupported format"); - ContentValues values = new ContentValues(); - values.put(Voicemails.TRANSCRIPTION, - mContext.getString(R.string.vvm_unsupported_message_format, - mContext.getSystemService(TelecomManager.class) - .getVoiceMailNumber(mPhoneAccountHandle))); - updateVoicemail(values); - return; - } - - VvmLog.d(TAG, String.format("Writing new voicemail content: %s", mUri)); - OutputStream outputStream = null; - - try { - outputStream = mContentResolver.openOutputStream(mUri); - byte[] inputBytes = voicemailPayload.getBytes(); - if (inputBytes != null) { - outputStream.write(inputBytes); - } - } catch (IOException e) { - VvmLog.w(TAG, String.format("File not found for %s", mUri)); - return; - } finally { - IOUtils.closeQuietly(outputStream); - } - - // Update mime_type & has_content after we are done with file update. - ContentValues values = new ContentValues(); - values.put(Voicemails.MIME_TYPE, voicemailPayload.getMimeType()); - values.put(Voicemails.HAS_CONTENT, true); - updateVoicemail(values); - } - - private void updateVoicemail(ContentValues values) { - int updatedCount = mContentResolver.update(mUri, values, null, null); - if (updatedCount != 1) { - VvmLog - .e(TAG, "Updating voicemail should have updated 1 row, was: " + updatedCount); - } - } -} diff --git a/java/com/android/voicemailomtp/imap/ImapHelper.java b/java/com/android/voicemailomtp/imap/ImapHelper.java deleted file mode 100644 index b2a40fb64..000000000 --- a/java/com/android/voicemailomtp/imap/ImapHelper.java +++ /dev/null @@ -1,711 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.imap; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkInfo; -import android.provider.VoicemailContract; -import android.telecom.PhoneAccountHandle; -import android.util.Base64; - -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpConstants.ChangePinResult; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VisualVoicemailPreferences; -import com.android.voicemailomtp.Voicemail; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.fetch.VoicemailFetchedCallback; -import com.android.voicemailomtp.mail.Address; -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.BodyPart; -import com.android.voicemailomtp.mail.FetchProfile; -import com.android.voicemailomtp.mail.Flag; -import com.android.voicemailomtp.mail.Message; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.Multipart; -import com.android.voicemailomtp.mail.TempDirectory; -import com.android.voicemailomtp.mail.internet.MimeMessage; -import com.android.voicemailomtp.mail.store.ImapConnection; -import com.android.voicemailomtp.mail.store.ImapFolder; -import com.android.voicemailomtp.mail.store.ImapStore; -import com.android.voicemailomtp.mail.store.imap.ImapConstants; -import com.android.voicemailomtp.mail.store.imap.ImapResponse; -import com.android.voicemailomtp.mail.utils.LogUtils; -import com.android.voicemailomtp.sync.OmtpVvmSyncService.TranscriptionFetchedCallback; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import org.apache.commons.io.IOUtils; - -/** - * A helper interface to abstract commands sent across IMAP interface for a given account. - */ -public class ImapHelper implements Closeable { - - private static final String TAG = "ImapHelper"; - - private ImapFolder mFolder; - private ImapStore mImapStore; - - private final Context mContext; - private final PhoneAccountHandle mPhoneAccount; - private final Network mNetwork; - private final VoicemailStatus.Editor mStatus; - - VisualVoicemailPreferences mPrefs; - private static final String PREF_KEY_QUOTA_OCCUPIED = "quota_occupied_"; - private static final String PREF_KEY_QUOTA_TOTAL = "quota_total_"; - - private int mQuotaOccupied; - private int mQuotaTotal; - - private final OmtpVvmCarrierConfigHelper mConfig; - - public class InitializingException extends Exception { - - public InitializingException(String message) { - super(message); - } - } - - public ImapHelper(Context context, PhoneAccountHandle phoneAccount, Network network, - VoicemailStatus.Editor status) - throws InitializingException { - this(context, - new OmtpVvmCarrierConfigHelper( - context, - phoneAccount), - phoneAccount, - network, - status); - } - - public ImapHelper(Context context, OmtpVvmCarrierConfigHelper config, - PhoneAccountHandle phoneAccount, Network network, VoicemailStatus.Editor status) - throws InitializingException { - mContext = context; - mPhoneAccount = phoneAccount; - mNetwork = network; - mStatus = status; - mConfig = config; - mPrefs = new VisualVoicemailPreferences(context, - phoneAccount); - - try { - TempDirectory.setTempDirectory(context); - - String username = mPrefs.getString(OmtpConstants.IMAP_USER_NAME, null); - String password = mPrefs.getString(OmtpConstants.IMAP_PASSWORD, null); - String serverName = mPrefs.getString(OmtpConstants.SERVER_ADDRESS, null); - int port = Integer.parseInt( - mPrefs.getString(OmtpConstants.IMAP_PORT, null)); - int auth = ImapStore.FLAG_NONE; - - int sslPort = mConfig.getSslPort(); - if (sslPort != 0) { - port = sslPort; - auth = ImapStore.FLAG_SSL; - } - - mImapStore = new ImapStore( - context, this, username, password, port, serverName, auth, network); - } catch (NumberFormatException e) { - handleEvent(OmtpEvents.DATA_INVALID_PORT); - LogUtils.w(TAG, "Could not parse port number"); - throw new InitializingException("cannot initialize ImapHelper:" + e.toString()); - } - - mQuotaOccupied = mPrefs - .getInt(PREF_KEY_QUOTA_OCCUPIED, VoicemailContract.Status.QUOTA_UNAVAILABLE); - mQuotaTotal = mPrefs - .getInt(PREF_KEY_QUOTA_TOTAL, VoicemailContract.Status.QUOTA_UNAVAILABLE); - } - - @Override - public void close() { - mImapStore.closeConnection(); - } - - public boolean isRoaming() { - ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - NetworkInfo info = connectivityManager.getNetworkInfo(mNetwork); - if (info == null) { - return false; - } - return info.isRoaming(); - } - - public OmtpVvmCarrierConfigHelper getConfig() { - return mConfig; - } - - public ImapConnection connect() { - return mImapStore.getConnection(); - } - - /** - * The caller thread will block until the method returns. - */ - public boolean markMessagesAsRead(List<Voicemail> voicemails) { - return setFlags(voicemails, Flag.SEEN); - } - - /** - * The caller thread will block until the method returns. - */ - public boolean markMessagesAsDeleted(List<Voicemail> voicemails) { - return setFlags(voicemails, Flag.DELETED); - } - - public void handleEvent(OmtpEvents event) { - mConfig.handleEvent(mStatus, event); - } - - /** - * Set flags on the server for a given set of voicemails. - * - * @param voicemails The voicemails to set flags for. - * @param flags The flags to set on the voicemails. - * @return {@code true} if the operation completes successfully, {@code false} otherwise. - */ - private boolean setFlags(List<Voicemail> voicemails, String... flags) { - if (voicemails.size() == 0) { - return false; - } - try { - mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE); - if (mFolder != null) { - mFolder.setFlags(convertToImapMessages(voicemails), flags, true); - return true; - } - return false; - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging exception"); - return false; - } finally { - closeImapFolder(); - } - } - - /** - * Fetch a list of voicemails from the server. - * - * @return A list of voicemail objects containing data about voicemails stored on the server. - */ - public List<Voicemail> fetchAllVoicemails() { - List<Voicemail> result = new ArrayList<Voicemail>(); - Message[] messages; - try { - mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE); - if (mFolder == null) { - // This means we were unable to successfully open the folder. - return null; - } - - // This method retrieves lightweight messages containing only the uid of the message. - messages = mFolder.getMessages(null); - - for (Message message : messages) { - // Get the voicemail details (message structure). - MessageStructureWrapper messageStructureWrapper = fetchMessageStructure(message); - if (messageStructureWrapper != null) { - result.add(getVoicemailFromMessageStructure(messageStructureWrapper)); - } - } - return result; - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - return null; - } finally { - closeImapFolder(); - } - } - - /** - * Extract voicemail details from the message structure. Also fetch transcription if a - * transcription exists. - */ - private Voicemail getVoicemailFromMessageStructure( - MessageStructureWrapper messageStructureWrapper) throws MessagingException { - Message messageDetails = messageStructureWrapper.messageStructure; - - TranscriptionFetchedListener listener = new TranscriptionFetchedListener(); - if (messageStructureWrapper.transcriptionBodyPart != null) { - FetchProfile fetchProfile = new FetchProfile(); - fetchProfile.add(messageStructureWrapper.transcriptionBodyPart); - - mFolder.fetch(new Message[]{messageDetails}, fetchProfile, listener); - } - - // Found an audio attachment, this is a valid voicemail. - long time = messageDetails.getSentDate().getTime(); - String number = getNumber(messageDetails.getFrom()); - boolean isRead = Arrays.asList(messageDetails.getFlags()).contains(Flag.SEEN); - return Voicemail.createForInsertion(time, number) - .setPhoneAccount(mPhoneAccount) - .setSourcePackage(mContext.getPackageName()) - .setSourceData(messageDetails.getUid()) - .setIsRead(isRead) - .setTranscription(listener.getVoicemailTranscription()) - .build(); - } - - /** - * The "from" field of a visual voicemail IMAP message is the number of the caller who left the - * message. Extract this number from the list of "from" addresses. - * - * @param fromAddresses A list of addresses that comprise the "from" line. - * @return The number of the voicemail sender. - */ - private String getNumber(Address[] fromAddresses) { - if (fromAddresses != null && fromAddresses.length > 0) { - if (fromAddresses.length != 1) { - LogUtils.w(TAG, "More than one from addresses found. Using the first one."); - } - String sender = fromAddresses[0].getAddress(); - int atPos = sender.indexOf('@'); - if (atPos != -1) { - // Strip domain part of the address. - sender = sender.substring(0, atPos); - } - return sender; - } - return null; - } - - /** - * Fetches the structure of the given message and returns a wrapper containing the message - * structure and the transcription structure (if applicable). - * - * @throws MessagingException if fetching the structure of the message fails - */ - private MessageStructureWrapper fetchMessageStructure(Message message) - throws MessagingException { - LogUtils.d(TAG, "Fetching message structure for " + message.getUid()); - - MessageStructureFetchedListener listener = new MessageStructureFetchedListener(); - - FetchProfile fetchProfile = new FetchProfile(); - fetchProfile.addAll(Arrays.asList(FetchProfile.Item.FLAGS, FetchProfile.Item.ENVELOPE, - FetchProfile.Item.STRUCTURE)); - - // The IMAP folder fetch method will call "messageRetrieved" on the listener when the - // message is successfully retrieved. - mFolder.fetch(new Message[]{message}, fetchProfile, listener); - return listener.getMessageStructure(); - } - - public boolean fetchVoicemailPayload(VoicemailFetchedCallback callback, final String uid) { - try { - mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE); - if (mFolder == null) { - // This means we were unable to successfully open the folder. - return false; - } - Message message = mFolder.getMessage(uid); - if (message == null) { - return false; - } - VoicemailPayload voicemailPayload = fetchVoicemailPayload(message); - callback.setVoicemailContent(voicemailPayload); - return true; - } catch (MessagingException e) { - } finally { - closeImapFolder(); - } - return false; - } - - /** - * Fetches the body of the given message and returns the parsed voicemail payload. - * - * @throws MessagingException if fetching the body of the message fails - */ - private VoicemailPayload fetchVoicemailPayload(Message message) - throws MessagingException { - LogUtils.d(TAG, "Fetching message body for " + message.getUid()); - - MessageBodyFetchedListener listener = new MessageBodyFetchedListener(); - - FetchProfile fetchProfile = new FetchProfile(); - fetchProfile.add(FetchProfile.Item.BODY); - - mFolder.fetch(new Message[]{message}, fetchProfile, listener); - return listener.getVoicemailPayload(); - } - - public boolean fetchTranscription(TranscriptionFetchedCallback callback, String uid) { - try { - mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE); - if (mFolder == null) { - // This means we were unable to successfully open the folder. - return false; - } - - Message message = mFolder.getMessage(uid); - if (message == null) { - return false; - } - - MessageStructureWrapper messageStructureWrapper = fetchMessageStructure(message); - if (messageStructureWrapper != null) { - TranscriptionFetchedListener listener = new TranscriptionFetchedListener(); - if (messageStructureWrapper.transcriptionBodyPart != null) { - FetchProfile fetchProfile = new FetchProfile(); - fetchProfile.add(messageStructureWrapper.transcriptionBodyPart); - - // This method is called synchronously so the transcription will be populated - // in the listener once the next method is called. - mFolder.fetch(new Message[]{message}, fetchProfile, listener); - callback.setVoicemailTranscription(listener.getVoicemailTranscription()); - } - } - return true; - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - return false; - } finally { - closeImapFolder(); - } - } - - - @ChangePinResult - public int changePin(String oldPin, String newPin) - throws MessagingException { - ImapConnection connection = mImapStore.getConnection(); - try { - String command = getConfig().getProtocol() - .getCommand(OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT); - connection.sendCommand( - String.format(Locale.US, command, newPin, oldPin), true); - return getChangePinResultFromImapResponse(connection.readResponse()); - } catch (IOException ioe) { - VvmLog.e(TAG, "changePin: ", ioe); - return OmtpConstants.CHANGE_PIN_SYSTEM_ERROR; - } finally { - connection.destroyResponses(); - } - } - - public void changeVoicemailTuiLanguage(String languageCode) - throws MessagingException { - ImapConnection connection = mImapStore.getConnection(); - try { - String command = getConfig().getProtocol() - .getCommand(OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT); - connection.sendCommand( - String.format(Locale.US, command, languageCode), true); - } catch (IOException ioe) { - LogUtils.e(TAG, ioe.toString()); - } finally { - connection.destroyResponses(); - } - } - - public void closeNewUserTutorial() throws MessagingException { - ImapConnection connection = mImapStore.getConnection(); - try { - String command = getConfig().getProtocol() - .getCommand(OmtpConstants.IMAP_CLOSE_NUT); - connection.executeSimpleCommand(command, false); - } catch (IOException ioe) { - throw new MessagingException(MessagingException.SERVER_ERROR, ioe.toString()); - } finally { - connection.destroyResponses(); - } - } - - @ChangePinResult - private static int getChangePinResultFromImapResponse(ImapResponse response) - throws MessagingException { - if (!response.isTagged()) { - throw new MessagingException(MessagingException.SERVER_ERROR, - "tagged response expected"); - } - if (!response.isOk()) { - String message = response.getStringOrEmpty(1).getString(); - LogUtils.d(TAG, "change PIN failed: " + message); - if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_SHORT.equals(message)) { - return OmtpConstants.CHANGE_PIN_TOO_SHORT; - } - if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_LONG.equals(message)) { - return OmtpConstants.CHANGE_PIN_TOO_LONG; - } - if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_WEAK.equals(message)) { - return OmtpConstants.CHANGE_PIN_TOO_WEAK; - } - if (OmtpConstants.RESPONSE_CHANGE_PIN_MISMATCH.equals(message)) { - return OmtpConstants.CHANGE_PIN_MISMATCH; - } - if (OmtpConstants.RESPONSE_CHANGE_PIN_INVALID_CHARACTER.equals(message)) { - return OmtpConstants.CHANGE_PIN_INVALID_CHARACTER; - } - return OmtpConstants.CHANGE_PIN_SYSTEM_ERROR; - } - LogUtils.d(TAG, "change PIN succeeded"); - return OmtpConstants.CHANGE_PIN_SUCCESS; - } - - public void updateQuota() { - try { - mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE); - if (mFolder == null) { - // This means we were unable to successfully open the folder. - return; - } - updateQuota(mFolder); - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - } finally { - closeImapFolder(); - } - } - - private void updateQuota(ImapFolder folder) throws MessagingException { - setQuota(folder.getQuota()); - } - - private void setQuota(ImapFolder.Quota quota) { - if (quota == null) { - return; - } - if (quota.occupied == mQuotaOccupied && quota.total == mQuotaTotal) { - VvmLog.v(TAG, "Quota hasn't changed"); - return; - } - mQuotaOccupied = quota.occupied; - mQuotaTotal = quota.total; - VoicemailStatus.edit(mContext, mPhoneAccount) - .setQuota(mQuotaOccupied, mQuotaTotal) - .apply(); - mPrefs.edit() - .putInt(PREF_KEY_QUOTA_OCCUPIED, mQuotaOccupied) - .putInt(PREF_KEY_QUOTA_TOTAL, mQuotaTotal) - .apply(); - VvmLog.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal); - } - - /** - * A wrapper to hold a message with its header details and the structure for transcriptions (so - * they can be fetched in the future). - */ - public class MessageStructureWrapper { - - public Message messageStructure; - public BodyPart transcriptionBodyPart; - - public MessageStructureWrapper() { - } - } - - /** - * Listener for the message structure being fetched. - */ - private final class MessageStructureFetchedListener - implements ImapFolder.MessageRetrievalListener { - - private MessageStructureWrapper mMessageStructure; - - public MessageStructureFetchedListener() { - } - - public MessageStructureWrapper getMessageStructure() { - return mMessageStructure; - } - - @Override - public void messageRetrieved(Message message) { - LogUtils.d(TAG, "Fetched message structure for " + message.getUid()); - LogUtils.d(TAG, "Message retrieved: " + message); - try { - mMessageStructure = getMessageOrNull(message); - if (mMessageStructure == null) { - LogUtils.d(TAG, "This voicemail does not have an attachment..."); - return; - } - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - closeImapFolder(); - } - } - - /** - * Check if this IMAP message is a valid voicemail and whether it contains a transcription. - * - * @param message The IMAP message. - * @return The MessageStructureWrapper object corresponding to an IMAP message and - * transcription. - */ - private MessageStructureWrapper getMessageOrNull(Message message) - throws MessagingException { - if (!message.getMimeType().startsWith("multipart/")) { - LogUtils.w(TAG, "Ignored non multi-part message"); - return null; - } - - MessageStructureWrapper messageStructureWrapper = new MessageStructureWrapper(); - - Multipart multipart = (Multipart) message.getBody(); - for (int i = 0; i < multipart.getCount(); ++i) { - BodyPart bodyPart = multipart.getBodyPart(i); - String bodyPartMimeType = bodyPart.getMimeType().toLowerCase(); - LogUtils.d(TAG, "bodyPart mime type: " + bodyPartMimeType); - - if (bodyPartMimeType.startsWith("audio/")) { - messageStructureWrapper.messageStructure = message; - } else if (bodyPartMimeType.startsWith("text/")) { - messageStructureWrapper.transcriptionBodyPart = bodyPart; - } else { - VvmLog.v(TAG, "Unknown bodyPart MIME: " + bodyPartMimeType); - } - } - - if (messageStructureWrapper.messageStructure != null) { - return messageStructureWrapper; - } - - // No attachment found, this is not a voicemail. - return null; - } - } - - /** - * Listener for the message body being fetched. - */ - private final class MessageBodyFetchedListener implements ImapFolder.MessageRetrievalListener { - - private VoicemailPayload mVoicemailPayload; - - /** - * Returns the fetch voicemail payload. - */ - public VoicemailPayload getVoicemailPayload() { - return mVoicemailPayload; - } - - @Override - public void messageRetrieved(Message message) { - LogUtils.d(TAG, "Fetched message body for " + message.getUid()); - LogUtils.d(TAG, "Message retrieved: " + message); - try { - mVoicemailPayload = getVoicemailPayloadFromMessage(message); - } catch (MessagingException e) { - LogUtils.e(TAG, "Messaging Exception:", e); - } catch (IOException e) { - LogUtils.e(TAG, "IO Exception:", e); - } - } - - private VoicemailPayload getVoicemailPayloadFromMessage(Message message) - throws MessagingException, IOException { - Multipart multipart = (Multipart) message.getBody(); - List<String> mimeTypes = new ArrayList<>(); - for (int i = 0; i < multipart.getCount(); ++i) { - BodyPart bodyPart = multipart.getBodyPart(i); - String bodyPartMimeType = bodyPart.getMimeType().toLowerCase(); - mimeTypes.add(bodyPartMimeType); - if (bodyPartMimeType.startsWith("audio/")) { - byte[] bytes = getDataFromBody(bodyPart.getBody()); - LogUtils.d(TAG, String.format("Fetched %s bytes of data", bytes.length)); - return new VoicemailPayload(bodyPartMimeType, bytes); - } - } - LogUtils.e(TAG, "No audio attachment found on this voicemail, mimeTypes:" + mimeTypes); - return null; - } - } - - /** - * Listener for the transcription being fetched. - */ - private final class TranscriptionFetchedListener implements - ImapFolder.MessageRetrievalListener { - - private String mVoicemailTranscription; - - /** - * Returns the fetched voicemail transcription. - */ - public String getVoicemailTranscription() { - return mVoicemailTranscription; - } - - @Override - public void messageRetrieved(Message message) { - LogUtils.d(TAG, "Fetched transcription for " + message.getUid()); - try { - mVoicemailTranscription = new String(getDataFromBody(message.getBody())); - } catch (MessagingException e) { - LogUtils.e(TAG, "Messaging Exception:", e); - } catch (IOException e) { - LogUtils.e(TAG, "IO Exception:", e); - } - } - } - - private ImapFolder openImapFolder(String modeReadWrite) { - try { - if (mImapStore == null) { - return null; - } - ImapFolder folder = new ImapFolder(mImapStore, ImapConstants.INBOX); - folder.open(modeReadWrite); - return folder; - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - } - return null; - } - - private Message[] convertToImapMessages(List<Voicemail> voicemails) { - Message[] messages = new Message[voicemails.size()]; - for (int i = 0; i < voicemails.size(); ++i) { - messages[i] = new MimeMessage(); - messages[i].setUid(voicemails.get(i).getSourceData()); - } - return messages; - } - - private void closeImapFolder() { - if (mFolder != null) { - mFolder.close(true); - } - } - - private byte[] getDataFromBody(Body body) throws IOException, MessagingException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - BufferedOutputStream bufferedOut = new BufferedOutputStream(out); - try { - body.writeTo(bufferedOut); - return Base64.decode(out.toByteArray(), Base64.DEFAULT); - } finally { - IOUtils.closeQuietly(bufferedOut); - IOUtils.closeQuietly(out); - } - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/imap/VoicemailPayload.java b/java/com/android/voicemailomtp/imap/VoicemailPayload.java deleted file mode 100644 index 04c69dea5..000000000 --- a/java/com/android/voicemailomtp/imap/VoicemailPayload.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.imap; - -/** - * The payload for a voicemail, usually audio data. - */ -public class VoicemailPayload { - private final String mMimeType; - private final byte[] mBytes; - - public VoicemailPayload(String mimeType, byte[] bytes) { - mMimeType = mimeType; - mBytes = bytes; - } - - public byte[] getBytes() { - return mBytes; - } - - public String getMimeType() { - return mMimeType; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/Address.java b/java/com/android/voicemailomtp/mail/Address.java deleted file mode 100644 index ed3f44c03..000000000 --- a/java/com/android/voicemailomtp/mail/Address.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import android.os.Parcel; -import android.os.Parcelable; -import android.support.annotation.VisibleForTesting; -import android.text.Html; -import android.text.TextUtils; -import android.text.util.Rfc822Token; -import android.text.util.Rfc822Tokenizer; -import com.android.voicemailomtp.mail.utils.LogUtils; -import java.util.ArrayList; -import java.util.regex.Pattern; -import org.apache.james.mime4j.codec.EncoderUtil; -import org.apache.james.mime4j.decoder.DecoderUtil; - -/** - * This class represent email address. - * - * RFC822 email address may have following format. - * "name" <address> (comment) - * "name" <address> - * name <address> - * address - * Name and comment part should be MIME/base64 encoded in header if necessary. - * - */ -public class Address implements Parcelable { - public static final String ADDRESS_DELIMETER = ","; - /** - * Address part, in the form local_part@domain_part. No surrounding angle brackets. - */ - private String mAddress; - - /** - * Name part. No surrounding double quote, and no MIME/base64 encoding. - * This must be null if Address has no name part. - */ - private String mPersonal; - - /** - * When personal is set, it will return the first token of the personal - * string. Otherwise, it will return the e-mail address up to the '@' sign. - */ - private String mSimplifiedName; - - // Regex that matches address surrounded by '<>' optionally. '^<?([^>]+)>?$' - private static final Pattern REMOVE_OPTIONAL_BRACKET = Pattern.compile("^<?([^>]+)>?$"); - // Regex that matches personal name surrounded by '""' optionally. '^"?([^"]+)"?$' - private static final Pattern REMOVE_OPTIONAL_DQUOTE = Pattern.compile("^\"?([^\"]*)\"?$"); - // Regex that matches escaped character '\\([\\"])' - private static final Pattern UNQUOTE = Pattern.compile("\\\\([\\\\\"])"); - - // TODO: LOCAL_PART and DOMAIN_PART_PART are too permissive and can be improved. - // TODO: Fix this to better constrain comments. - /** Regex for the local part of an email address. */ - private static final String LOCAL_PART = "[^@]+"; - /** Regex for each part of the domain part, i.e. the thing between the dots. */ - private static final String DOMAIN_PART_PART = "[[\\w][\\d]\\-\\(\\)\\[\\]]+"; - /** Regex for the domain part, which is two or more {@link #DOMAIN_PART_PART} separated by . */ - private static final String DOMAIN_PART = - "(" + DOMAIN_PART_PART + "\\.)+" + DOMAIN_PART_PART; - - /** Pattern to check if an email address is valid. */ - private static final Pattern EMAIL_ADDRESS = - Pattern.compile("\\A" + LOCAL_PART + "@" + DOMAIN_PART + "\\z"); - - private static final Address[] EMPTY_ADDRESS_ARRAY = new Address[0]; - - // delimiters are chars that do not appear in an email address, used by fromHeader - private static final char LIST_DELIMITER_EMAIL = '\1'; - private static final char LIST_DELIMITER_PERSONAL = '\2'; - - private static final String LOG_TAG = "Email Address"; - - @VisibleForTesting - public Address(String address) { - setAddress(address); - } - - public Address(String address, String personal) { - setPersonal(personal); - setAddress(address); - } - - /** - * Returns a simplified string for this e-mail address. - * When a name is known, it will return the first token of that name. Otherwise, it will - * return the e-mail address up to the '@' sign. - */ - public String getSimplifiedName() { - if (mSimplifiedName == null) { - if (TextUtils.isEmpty(mPersonal) && !TextUtils.isEmpty(mAddress)) { - int atSign = mAddress.indexOf('@'); - mSimplifiedName = (atSign != -1) ? mAddress.substring(0, atSign) : ""; - } else if (!TextUtils.isEmpty(mPersonal)) { - - // TODO: use Contacts' NameSplitter for more reliable first-name extraction - - int end = mPersonal.indexOf(' '); - while (end > 0 && mPersonal.charAt(end - 1) == ',') { - end--; - } - mSimplifiedName = (end < 1) ? mPersonal : mPersonal.substring(0, end); - - } else { - LogUtils.w(LOG_TAG, "Unable to get a simplified name"); - mSimplifiedName = ""; - } - } - return mSimplifiedName; - } - - public static synchronized Address getEmailAddress(String rawAddress) { - if (TextUtils.isEmpty(rawAddress)) { - return null; - } - String name, address; - final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(rawAddress); - if (tokens.length > 0) { - final String tokenizedName = tokens[0].getName(); - name = tokenizedName != null ? Html.fromHtml(tokenizedName.trim()).toString() - : ""; - address = Html.fromHtml(tokens[0].getAddress()).toString(); - } else { - name = ""; - address = rawAddress == null ? - "" : Html.fromHtml(rawAddress).toString(); - } - return new Address(address, name); - } - - public String getAddress() { - return mAddress; - } - - public void setAddress(String address) { - mAddress = REMOVE_OPTIONAL_BRACKET.matcher(address).replaceAll("$1"); - } - - /** - * Get name part as UTF-16 string. No surrounding double quote, and no MIME/base64 encoding. - * - * @return Name part of email address. Returns null if it is omitted. - */ - public String getPersonal() { - return mPersonal; - } - - /** - * Set personal part from UTF-16 string. Optional surrounding double quote will be removed. - * It will be also unquoted and MIME/base64 decoded. - * - * @param personal name part of email address as UTF-16 string. Null is acceptable. - */ - public void setPersonal(String personal) { - mPersonal = decodeAddressPersonal(personal); - } - - /** - * Decodes name from UTF-16 string. Optional surrounding double quote will be removed. - * It will be also unquoted and MIME/base64 decoded. - * - * @param personal name part of email address as UTF-16 string. Null is acceptable. - */ - public static String decodeAddressPersonal(String personal) { - if (personal != null) { - personal = REMOVE_OPTIONAL_DQUOTE.matcher(personal).replaceAll("$1"); - personal = UNQUOTE.matcher(personal).replaceAll("$1"); - personal = DecoderUtil.decodeEncodedWords(personal); - if (personal.length() == 0) { - personal = null; - } - } - return personal; - } - - /** - * This method is used to check that all the addresses that the user - * entered in a list (e.g. To:) are valid, so that none is dropped. - */ - @VisibleForTesting - public static boolean isAllValid(String addressList) { - // This code mimics the parse() method below. - // I don't know how to better avoid the code-duplication. - if (addressList != null && addressList.length() > 0) { - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressList); - for (int i = 0, length = tokens.length; i < length; ++i) { - Rfc822Token token = tokens[i]; - String address = token.getAddress(); - if (!TextUtils.isEmpty(address) && !isValidAddress(address)) { - return false; - } - } - } - return true; - } - - /** - * Parse a comma-delimited list of addresses in RFC822 format and return an - * array of Address objects. - * - * @param addressList Address list in comma-delimited string. - * @return An array of 0 or more Addresses. - */ - public static Address[] parse(String addressList) { - if (addressList == null || addressList.length() == 0) { - return EMPTY_ADDRESS_ARRAY; - } - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressList); - ArrayList<Address> addresses = new ArrayList<Address>(); - for (int i = 0, length = tokens.length; i < length; ++i) { - Rfc822Token token = tokens[i]; - String address = token.getAddress(); - if (!TextUtils.isEmpty(address)) { - if (isValidAddress(address)) { - String name = token.getName(); - if (TextUtils.isEmpty(name)) { - name = null; - } - addresses.add(new Address(address, name)); - } - } - } - return addresses.toArray(new Address[addresses.size()]); - } - - /** - * Checks whether a string email address is valid. - * E.g. name@domain.com is valid. - */ - @VisibleForTesting - static boolean isValidAddress(final String address) { - return EMAIL_ADDRESS.matcher(address).find(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof Address) { - // It seems that the spec says that the "user" part is case-sensitive, - // while the domain part in case-insesitive. - // So foo@yahoo.com and Foo@yahoo.com are different. - // This may seem non-intuitive from the user POV, so we - // may re-consider it if it creates UI trouble. - // A problem case is "replyAll" sending to both - // a@b.c and to A@b.c, which turn out to be the same on the server. - // Leave unchanged for now (i.e. case-sensitive). - return getAddress().equals(((Address) o).getAddress()); - } - return super.equals(o); - } - - @Override - public int hashCode() { - return getAddress().hashCode(); - } - - /** - * Get human readable address string. - * Do not use this for email header. - * - * @return Human readable address string. Not quoted and not encoded. - */ - @Override - public String toString() { - if (mPersonal != null && !mPersonal.equals(mAddress)) { - if (mPersonal.matches(".*[\\(\\)<>@,;:\\\\\".\\[\\]].*")) { - return ensureQuotedString(mPersonal) + " <" + mAddress + ">"; - } else { - return mPersonal + " <" + mAddress + ">"; - } - } else { - return mAddress; - } - } - - /** - * Ensures that the given string starts and ends with the double quote character. The string is - * not modified in any way except to add the double quote character to start and end if it's not - * already there. - * - * sample -> "sample" - * "sample" -> "sample" - * ""sample"" -> "sample" - * "sample"" -> "sample" - * sa"mp"le -> "sa"mp"le" - * "sa"mp"le" -> "sa"mp"le" - * (empty string) -> "" - * " -> "" - */ - private static String ensureQuotedString(String s) { - if (s == null) { - return null; - } - if (!s.matches("^\".*\"$")) { - return "\"" + s + "\""; - } else { - return s; - } - } - - /** - * Get human readable comma-delimited address string. - * - * @param addresses Address array - * @return Human readable comma-delimited address string. - */ - @VisibleForTesting - public static String toString(Address[] addresses) { - return toString(addresses, ADDRESS_DELIMETER); - } - - /** - * Get human readable address strings joined with the specified separator. - * - * @param addresses Address array - * @param separator Separator - * @return Human readable comma-delimited address string. - */ - public static String toString(Address[] addresses, String separator) { - if (addresses == null || addresses.length == 0) { - return null; - } - if (addresses.length == 1) { - return addresses[0].toString(); - } - StringBuilder sb = new StringBuilder(addresses[0].toString()); - for (int i = 1; i < addresses.length; i++) { - sb.append(separator); - // TODO: investigate why this .trim() is needed. - sb.append(addresses[i].toString().trim()); - } - return sb.toString(); - } - - /** - * Get RFC822/MIME compatible address string. - * - * @return RFC822/MIME compatible address string. - * It may be surrounded by double quote or quoted and MIME/base64 encoded if necessary. - */ - public String toHeader() { - if (mPersonal != null) { - return EncoderUtil.encodeAddressDisplayName(mPersonal) + " <" + mAddress + ">"; - } else { - return mAddress; - } - } - - /** - * Get RFC822/MIME compatible comma-delimited address string. - * - * @param addresses Address array - * @return RFC822/MIME compatible comma-delimited address string. - * it may be surrounded by double quoted or quoted and MIME/base64 encoded if necessary. - */ - public static String toHeader(Address[] addresses) { - if (addresses == null || addresses.length == 0) { - return null; - } - if (addresses.length == 1) { - return addresses[0].toHeader(); - } - StringBuilder sb = new StringBuilder(addresses[0].toHeader()); - for (int i = 1; i < addresses.length; i++) { - // We need space character to be able to fold line. - sb.append(", "); - sb.append(addresses[i].toHeader()); - } - return sb.toString(); - } - - /** - * Get Human friendly address string. - * - * @return the personal part of this Address, or the address part if the - * personal part is not available - */ - @VisibleForTesting - public String toFriendly() { - if (mPersonal != null && mPersonal.length() > 0) { - return mPersonal; - } else { - return mAddress; - } - } - - /** - * Creates a comma-delimited list of addresses in the "friendly" format (see toFriendly() for - * details on the per-address conversion). - * - * @param addresses Array of Address[] values - * @return A comma-delimited string listing all of the addresses supplied. Null if source - * was null or empty. - */ - @VisibleForTesting - public static String toFriendly(Address[] addresses) { - if (addresses == null || addresses.length == 0) { - return null; - } - if (addresses.length == 1) { - return addresses[0].toFriendly(); - } - StringBuilder sb = new StringBuilder(addresses[0].toFriendly()); - for (int i = 1; i < addresses.length; i++) { - sb.append(", "); - sb.append(addresses[i].toFriendly()); - } - return sb.toString(); - } - - /** - * Returns exactly the same result as Address.toString(Address.fromHeader(addressList)). - */ - @VisibleForTesting - public static String fromHeaderToString(String addressList) { - return toString(fromHeader(addressList)); - } - - /** - * Returns exactly the same result as Address.toHeader(Address.parse(addressList)). - */ - @VisibleForTesting - public static String parseToHeader(String addressList) { - return Address.toHeader(Address.parse(addressList)); - } - - /** - * Returns null if the addressList has 0 addresses, otherwise returns the first address. - * The same as Address.fromHeader(addressList)[0] for non-empty list. - * This is an utility method that offers some performance optimization opportunities. - */ - @VisibleForTesting - public static Address firstAddress(String addressList) { - Address[] array = fromHeader(addressList); - return array.length > 0 ? array[0] : null; - } - - /** - * This method exists to convert an address list formatted in a deprecated legacy format to the - * standard RFC822 header format. {@link #fromHeader(String)} is capable of reading the legacy - * format and the RFC822 format. {@link #toHeader()} always produces the RFC822 format. - * - * This implementation is brute-force, and could be replaced with a more efficient version - * if desired. - */ - public static String reformatToHeader(String addressList) { - return toHeader(fromHeader(addressList)); - } - - /** - * @param addressList a CSV of RFC822 addresses or the deprecated legacy string format - * @return array of addresses parsed from <code>addressList</code> - */ - @VisibleForTesting - public static Address[] fromHeader(String addressList) { - if (addressList == null || addressList.length() == 0) { - return EMPTY_ADDRESS_ARRAY; - } - // IF we're CSV, just parse - if ((addressList.indexOf(LIST_DELIMITER_PERSONAL) == -1) && - (addressList.indexOf(LIST_DELIMITER_EMAIL) == -1)) { - return Address.parse(addressList); - } - // Otherwise, do backward-compatible unpack - ArrayList<Address> addresses = new ArrayList<Address>(); - int length = addressList.length(); - int pairStartIndex = 0; - int pairEndIndex; - - /* addressEndIndex is only re-scanned (indexOf()) when a LIST_DELIMITER_PERSONAL - is used, not for every email address; i.e. not for every iteration of the while(). - This reduces the theoretical complexity from quadratic to linear, - and provides some speed-up in practice by removing redundant scans of the string. - */ - int addressEndIndex = addressList.indexOf(LIST_DELIMITER_PERSONAL); - - while (pairStartIndex < length) { - pairEndIndex = addressList.indexOf(LIST_DELIMITER_EMAIL, pairStartIndex); - if (pairEndIndex == -1) { - pairEndIndex = length; - } - Address address; - if (addressEndIndex == -1 || pairEndIndex <= addressEndIndex) { - // in this case the DELIMITER_PERSONAL is in a future pair, - // so don't use personal, and don't update addressEndIndex - address = new Address(addressList.substring(pairStartIndex, pairEndIndex), null); - } else { - address = new Address(addressList.substring(pairStartIndex, addressEndIndex), - addressList.substring(addressEndIndex + 1, pairEndIndex)); - // only update addressEndIndex when we use the LIST_DELIMITER_PERSONAL - addressEndIndex = addressList.indexOf(LIST_DELIMITER_PERSONAL, pairEndIndex + 1); - } - addresses.add(address); - pairStartIndex = pairEndIndex + 1; - } - return addresses.toArray(new Address[addresses.size()]); - } - - public static final Creator<Address> CREATOR = new Creator<Address>() { - @Override - public Address createFromParcel(Parcel parcel) { - return new Address(parcel); - } - - @Override - public Address[] newArray(int size) { - return new Address[size]; - } - }; - - public Address(Parcel in) { - setPersonal(in.readString()); - setAddress(in.readString()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeString(mPersonal); - out.writeString(mAddress); - } -} diff --git a/java/com/android/voicemailomtp/mail/AuthenticationFailedException.java b/java/com/android/voicemailomtp/mail/AuthenticationFailedException.java deleted file mode 100644 index 995d5d348..000000000 --- a/java/com/android/voicemailomtp/mail/AuthenticationFailedException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail; - -public class AuthenticationFailedException extends MessagingException { - public static final long serialVersionUID = -1; - - public AuthenticationFailedException(String message) { - super(MessagingException.AUTHENTICATION_FAILED, message); - } - - public AuthenticationFailedException(int exceptionType, String message) { - super(exceptionType, message); - } - - public AuthenticationFailedException(String message, Throwable throwable) { - super(MessagingException.AUTHENTICATION_FAILED, message, throwable); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/Base64Body.java b/java/com/android/voicemailomtp/mail/Base64Body.java deleted file mode 100644 index 6e1deff44..000000000 --- a/java/com/android/voicemailomtp/mail/Base64Body.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import android.util.Base64; -import android.util.Base64OutputStream; - -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public class Base64Body implements Body { - private final InputStream mSource; - // Because we consume the input stream, we can only write out once - private boolean mAlreadyWritten; - - public Base64Body(InputStream source) { - mSource = source; - } - - @Override - public InputStream getInputStream() throws MessagingException { - return mSource; - } - - /** - * This method consumes the input stream, so can only be called once - * @param out Stream to write to - * @throws IllegalStateException If called more than once - * @throws IOException - * @throws MessagingException - */ - @Override - public void writeTo(OutputStream out) - throws IllegalStateException, IOException, MessagingException { - if (mAlreadyWritten) { - throw new IllegalStateException("Base64Body can only be written once"); - } - mAlreadyWritten = true; - try { - final Base64OutputStream b64out = new Base64OutputStream(out, Base64.DEFAULT); - IOUtils.copyLarge(mSource, b64out); - } finally { - mSource.close(); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/Body.java b/java/com/android/voicemailomtp/mail/Body.java deleted file mode 100644 index 393e1823c..000000000 --- a/java/com/android/voicemailomtp/mail/Body.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public interface Body { - public InputStream getInputStream() throws MessagingException; - public void writeTo(OutputStream out) throws IOException, MessagingException; -} diff --git a/java/com/android/voicemailomtp/mail/BodyPart.java b/java/com/android/voicemailomtp/mail/BodyPart.java deleted file mode 100644 index 62390a43e..000000000 --- a/java/com/android/voicemailomtp/mail/BodyPart.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -public abstract class BodyPart implements Part { - protected Multipart mParent; - - public Multipart getParent() { - return mParent; - } -} diff --git a/java/com/android/voicemailomtp/mail/CertificateValidationException.java b/java/com/android/voicemailomtp/mail/CertificateValidationException.java deleted file mode 100644 index 8ebe5480b..000000000 --- a/java/com/android/voicemailomtp/mail/CertificateValidationException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail; - -public class CertificateValidationException extends MessagingException { - public static final long serialVersionUID = -1; - - public CertificateValidationException(String message) { - super(MessagingException.CERTIFICATE_VALIDATION_ERROR, message); - } - - public CertificateValidationException(String message, Throwable throwable) { - super(MessagingException.CERTIFICATE_VALIDATION_ERROR, message, throwable); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/FetchProfile.java b/java/com/android/voicemailomtp/mail/FetchProfile.java deleted file mode 100644 index d050692cc..000000000 --- a/java/com/android/voicemailomtp/mail/FetchProfile.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.util.ArrayList; - -/** - * <pre> - * A FetchProfile is a list of items that should be downloaded in bulk for a set of messages. - * FetchProfile can contain the following objects: - * FetchProfile.Item: Described below. - * Message: Indicates that the body of the entire message should be fetched. - * Synonymous with FetchProfile.Item.BODY. - * Part: Indicates that the given Part should be fetched. The provider - * is expected have previously created the given BodyPart and stored - * any information it needs to download the content. - * </pre> - */ -public class FetchProfile extends ArrayList<Fetchable> { - /** - * Default items available for pre-fetching. It should be expected that any - * item fetched by using these items could potentially include all of the - * previous items. - */ - public enum Item implements Fetchable { - /** - * Download the flags of the message. - */ - FLAGS, - - /** - * Download the envelope of the message. This should include at minimum - * the size and the following headers: date, subject, from, content-type, to, cc - */ - ENVELOPE, - - /** - * Download the structure of the message. This maps directly to IMAP's BODYSTRUCTURE - * and may map to other providers. - * The provider should, if possible, fill in a properly formatted MIME structure in - * the message without actually downloading any message data. If the provider is not - * capable of this operation it should specifically set the body of the message to null - * so that upper levels can detect that a full body download is needed. - */ - STRUCTURE, - - /** - * A sane portion of the entire message, cut off at a provider determined limit. - * This should generally be around 50kB. - */ - BODY_SANE, - - /** - * The entire message. - */ - BODY, - } - - /** - * @return the first {@link Part} in this collection, or null if it doesn't contain - * {@link Part}. - */ - public Part getFirstPart() { - for (Fetchable o : this) { - if (o instanceof Part) { - return (Part) o; - } - } - return null; - } -} diff --git a/java/com/android/voicemailomtp/mail/Fetchable.java b/java/com/android/voicemailomtp/mail/Fetchable.java deleted file mode 100644 index 1d8d0005b..000000000 --- a/java/com/android/voicemailomtp/mail/Fetchable.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -/** - * Interface for classes that can be added to {@link FetchProfile}. - * i.e. {@link Part} and its subclasses, and {@link FetchProfile.Item}. - */ -public interface Fetchable { -} diff --git a/java/com/android/voicemailomtp/mail/FixedLengthInputStream.java b/java/com/android/voicemailomtp/mail/FixedLengthInputStream.java deleted file mode 100644 index 65655efd5..000000000 --- a/java/com/android/voicemailomtp/mail/FixedLengthInputStream.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering InputStream that stops allowing reads after the given length has been read. This - * is used to allow a client to read directly from an underlying protocol stream without reading - * past where the protocol handler intended the client to read. - */ -public class FixedLengthInputStream extends InputStream { - private final InputStream mIn; - private final int mLength; - private int mCount; - - public FixedLengthInputStream(InputStream in, int length) { - this.mIn = in; - this.mLength = length; - } - - @Override - public int available() throws IOException { - return mLength - mCount; - } - - @Override - public int read() throws IOException { - if (mCount < mLength) { - mCount++; - return mIn.read(); - } else { - return -1; - } - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mCount < mLength) { - int d = mIn.read(b, offset, Math.min(mLength - mCount, length)); - if (d == -1) { - return -1; - } else { - mCount += d; - return d; - } - } else { - return -1; - } - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - public int getLength() { - return mLength; - } - - @Override - public String toString() { - return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/Flag.java b/java/com/android/voicemailomtp/mail/Flag.java deleted file mode 100644 index a9f927099..000000000 --- a/java/com/android/voicemailomtp/mail/Flag.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -/** - * Flags that can be applied to Messages. - */ -public class Flag { - // If adding new flags: ALL FLAGS MUST BE UPPER CASE. - public static final String DELETED = "deleted"; - public static final String SEEN = "seen"; - public static final String ANSWERED = "answered"; - public static final String FLAGGED = "flagged"; - public static final String DRAFT = "draft"; - public static final String RECENT = "recent"; -} diff --git a/java/com/android/voicemailomtp/mail/MailTransport.java b/java/com/android/voicemailomtp/mail/MailTransport.java deleted file mode 100644 index 3bf851fd8..000000000 --- a/java/com/android/voicemailomtp/mail/MailTransport.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import android.content.Context; -import android.net.Network; -import android.support.annotation.VisibleForTesting; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.mail.store.ImapStore; -import com.android.voicemailomtp.mail.utils.LogUtils; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.List; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; - -/** - * Make connection and perform operations on mail server by reading and writing lines. - */ -public class MailTransport { - private static final String TAG = "MailTransport"; - - // TODO protected eventually - /*protected*/ public static final int SOCKET_CONNECT_TIMEOUT = 10000; - /*protected*/ public static final int SOCKET_READ_TIMEOUT = 60000; - - private static final HostnameVerifier HOSTNAME_VERIFIER = - HttpsURLConnection.getDefaultHostnameVerifier(); - - private final Context mContext; - private final ImapHelper mImapHelper; - private final Network mNetwork; - private final String mHost; - private final int mPort; - private Socket mSocket; - private BufferedInputStream mIn; - private BufferedOutputStream mOut; - private final int mFlags; - private SocketCreator mSocketCreator; - private InetSocketAddress mAddress; - - public MailTransport(Context context, ImapHelper imapHelper, Network network, String address, - int port, int flags) { - mContext = context; - mImapHelper = imapHelper; - mNetwork = network; - mHost = address; - mPort = port; - mFlags = flags; - } - - /** - * Returns a new transport, using the current transport as a model. The new transport is - * configured identically, but not opened or connected in any way. - */ - @Override - public MailTransport clone() { - return new MailTransport(mContext, mImapHelper, mNetwork, mHost, mPort, mFlags); - } - - public boolean canTrySslSecurity() { - return (mFlags & ImapStore.FLAG_SSL) != 0; - } - - public boolean canTrustAllCertificates() { - return (mFlags & ImapStore.FLAG_TRUST_ALL) != 0; - } - - /** - * Attempts to open a connection using the Uri supplied for connection parameters. Will attempt - * an SSL connection if indicated. - */ - public void open() throws MessagingException { - LogUtils.d(TAG, "*** IMAP open " + mHost + ":" + String.valueOf(mPort)); - - List<InetSocketAddress> socketAddresses = new ArrayList<InetSocketAddress>(); - - if (mNetwork == null) { - socketAddresses.add(new InetSocketAddress(mHost, mPort)); - } else { - try { - InetAddress[] inetAddresses = mNetwork.getAllByName(mHost); - if (inetAddresses.length == 0) { - throw new MessagingException(MessagingException.IOERROR, - "Host name " + mHost + "cannot be resolved on designated network"); - } - for (int i = 0; i < inetAddresses.length; i++) { - socketAddresses.add(new InetSocketAddress(inetAddresses[i], mPort)); - } - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_RESOLVE_HOST_ON_NETWORK); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - boolean success = false; - while (socketAddresses.size() > 0) { - mSocket = createSocket(); - try { - mAddress = socketAddresses.remove(0); - mSocket.connect(mAddress, SOCKET_CONNECT_TIMEOUT); - - if (canTrySslSecurity()) { - /* - SSLSocket cannot be created with a connection timeout, so instead of doing a - direct SSL connection, we connect with a normal connection and upgrade it into - SSL - */ - reopenTls(); - } else { - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - } - success = true; - return; - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - if (socketAddresses.size() == 0) { - // Only throw an error when there are no more sockets to try. - mImapHelper.handleEvent(OmtpEvents.DATA_ALL_SOCKET_CONNECTION_FAILED); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } finally { - if (!success) { - try { - mSocket.close(); - mSocket = null; - } catch (IOException ioe) { - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - - } - } - } - } - - // For testing. We need something that can replace the behavior of "new Socket()" - @VisibleForTesting - interface SocketCreator { - - Socket createSocket() throws MessagingException; - } - - @VisibleForTesting - void setSocketCreator(SocketCreator creator) { - mSocketCreator = creator; - } - - protected Socket createSocket() throws MessagingException { - if (mSocketCreator != null) { - return mSocketCreator.createSocket(); - } - - if (mNetwork == null) { - LogUtils.v(TAG, "createSocket: network not specified"); - return new Socket(); - } - - try { - LogUtils.v(TAG, "createSocket: network specified"); - return mNetwork.getSocketFactory().createSocket(); - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - /** - * Attempts to reopen a normal connection into a TLS connection. - */ - public void reopenTls() throws MessagingException { - try { - LogUtils.d(TAG, "open: converting to TLS socket"); - mSocket = HttpsURLConnection.getDefaultSSLSocketFactory() - .createSocket(mSocket, mAddress.getHostName(), mAddress.getPort(), true); - // After the socket connects to an SSL server, confirm that the hostname is as - // expected - if (!canTrustAllCertificates()) { - verifyHostname(mSocket, mHost); - } - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - - } catch (SSLException e) { - LogUtils.d(TAG, e.toString()); - throw new CertificateValidationException(e.getMessage(), e); - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - /** - * Lightweight version of SSLCertificateSocketFactory.verifyHostname, which provides this - * service but is not in the public API. - * - * Verify the hostname of the certificate used by the other end of a - * connected socket. It is harmless to call this method redundantly if the hostname has already - * been verified. - * - * <p>Wildcard certificates are allowed to verify any matching hostname, - * so "foo.bar.example.com" is verified if the peer has a certificate - * for "*.example.com". - * - * @param socket An SSL socket which has been connected to a server - * @param hostname The expected hostname of the remote server - * @throws IOException if something goes wrong handshaking with the server - * @throws SSLPeerUnverifiedException if the server cannot prove its identity - */ - private void verifyHostname(Socket socket, String hostname) throws IOException { - // The code at the start of OpenSSLSocketImpl.startHandshake() - // ensures that the call is idempotent, so we can safely call it. - SSLSocket ssl = (SSLSocket) socket; - ssl.startHandshake(); - - SSLSession session = ssl.getSession(); - if (session == null) { - mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_ESTABLISH_SSL_SESSION); - throw new SSLException("Cannot verify SSL socket without session"); - } - // TODO: Instead of reporting the name of the server we think we're connecting to, - // we should be reporting the bad name in the certificate. Unfortunately this is buried - // in the verifier code and is not available in the verifier API, and extracting the - // CN & alts is beyond the scope of this patch. - if (!HOSTNAME_VERIFIER.verify(hostname, session)) { - mImapHelper.handleEvent(OmtpEvents.DATA_SSL_INVALID_HOST_NAME); - throw new SSLPeerUnverifiedException("Certificate hostname not useable for server: " - + session.getPeerPrincipal()); - } - } - - public boolean isOpen() { - return (mIn != null && mOut != null && - mSocket != null && mSocket.isConnected() && !mSocket.isClosed()); - } - - /** - * Close the connection. MUST NOT return any exceptions - must be "best effort" and safe. - */ - public void close() { - try { - mIn.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - try { - mOut.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - try { - mSocket.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - mIn = null; - mOut = null; - mSocket = null; - } - - public String getHost() { - return mHost; - } - - public InputStream getInputStream() { - return mIn; - } - - public OutputStream getOutputStream() { - return mOut; - } - - /** - * Writes a single line to the server using \r\n termination. - */ - public void writeLine(String s, String sensitiveReplacement) throws IOException { - if (sensitiveReplacement != null) { - LogUtils.d(TAG, ">>> " + sensitiveReplacement); - } else { - LogUtils.d(TAG, ">>> " + s); - } - - OutputStream out = getOutputStream(); - out.write(s.getBytes()); - out.write('\r'); - out.write('\n'); - out.flush(); - } - - /** - * Reads a single line from the server, using either \r\n or \n as the delimiter. The - * delimiter char(s) are not included in the result. - */ - public String readLine(boolean loggable) throws IOException { - StringBuffer sb = new StringBuffer(); - InputStream in = getInputStream(); - int d; - while ((d = in.read()) != -1) { - if (((char)d) == '\r') { - continue; - } else if (((char)d) == '\n') { - break; - } else { - sb.append((char)d); - } - } - if (d == -1) { - LogUtils.d(TAG, "End of stream reached while trying to read line."); - } - String ret = sb.toString(); - if (loggable) { - LogUtils.d(TAG, "<<< " + ret); - } - return ret; - } -} diff --git a/java/com/android/voicemailomtp/mail/MeetingInfo.java b/java/com/android/voicemailomtp/mail/MeetingInfo.java deleted file mode 100644 index 0505bbf2c..000000000 --- a/java/com/android/voicemailomtp/mail/MeetingInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -public class MeetingInfo { - // Predefined tags; others can be added - public static final String MEETING_DTSTAMP = "DTSTAMP"; - public static final String MEETING_UID = "UID"; - public static final String MEETING_ORGANIZER_EMAIL = "ORGMAIL"; - public static final String MEETING_DTSTART = "DTSTART"; - public static final String MEETING_DTEND = "DTEND"; - public static final String MEETING_TITLE = "TITLE"; - public static final String MEETING_LOCATION = "LOC"; - public static final String MEETING_RESPONSE_REQUESTED = "RESPONSE"; - public static final String MEETING_ALL_DAY = "ALLDAY"; -} diff --git a/java/com/android/voicemailomtp/mail/Message.java b/java/com/android/voicemailomtp/mail/Message.java deleted file mode 100644 index 41555690f..000000000 --- a/java/com/android/voicemailomtp/mail/Message.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import android.support.annotation.VisibleForTesting; -import java.util.Date; -import java.util.HashSet; - -public abstract class Message implements Part, Body { - public static final Message[] EMPTY_ARRAY = new Message[0]; - - public static final String RECIPIENT_TYPE_TO = "to"; - public static final String RECIPIENT_TYPE_CC = "cc"; - public static final String RECIPIENT_TYPE_BCC = "bcc"; - public enum RecipientType { - TO, CC, BCC, - } - - protected String mUid; - - private HashSet<String> mFlags = null; - - protected Date mInternalDate; - - public String getUid() { - return mUid; - } - - public void setUid(String uid) { - this.mUid = uid; - } - - public abstract String getSubject() throws MessagingException; - - public abstract void setSubject(String subject) throws MessagingException; - - public Date getInternalDate() { - return mInternalDate; - } - - public void setInternalDate(Date internalDate) { - this.mInternalDate = internalDate; - } - - public abstract Date getReceivedDate() throws MessagingException; - - public abstract Date getSentDate() throws MessagingException; - - public abstract void setSentDate(Date sentDate) throws MessagingException; - - public abstract Address[] getRecipients(String type) throws MessagingException; - - public abstract void setRecipients(String type, Address[] addresses) - throws MessagingException; - - public void setRecipient(String type, Address address) throws MessagingException { - setRecipients(type, new Address[] { - address - }); - } - - public abstract Address[] getFrom() throws MessagingException; - - public abstract void setFrom(Address from) throws MessagingException; - - public abstract Address[] getReplyTo() throws MessagingException; - - public abstract void setReplyTo(Address[] from) throws MessagingException; - - // Always use these instead of getHeader("Message-ID") or setHeader("Message-ID"); - public abstract void setMessageId(String messageId) throws MessagingException; - public abstract String getMessageId() throws MessagingException; - - @Override - public boolean isMimeType(String mimeType) throws MessagingException { - return getContentType().startsWith(mimeType); - } - - private HashSet<String> getFlagSet() { - if (mFlags == null) { - mFlags = new HashSet<String>(); - } - return mFlags; - } - - /* - * TODO Refactor Flags at some point to be able to store user defined flags. - */ - public String[] getFlags() { - return getFlagSet().toArray(new String[] {}); - } - - /** - * Set/clear a flag directly, without involving overrides of {@link #setFlag} in subclasses. - * Only used for testing. - */ - @VisibleForTesting - private final void setFlagDirectlyForTest(String flag, boolean set) throws MessagingException { - if (set) { - getFlagSet().add(flag); - } else { - getFlagSet().remove(flag); - } - } - - public void setFlag(String flag, boolean set) throws MessagingException { - setFlagDirectlyForTest(flag, set); - } - - /** - * This method calls setFlag(String, boolean) - * @param flags - * @param set - */ - public void setFlags(String[] flags, boolean set) throws MessagingException { - for (String flag : flags) { - setFlag(flag, set); - } - } - - public boolean isSet(String flag) { - return getFlagSet().contains(flag); - } - - public abstract void saveChanges() throws MessagingException; - - @Override - public String toString() { - return getClass().getSimpleName() + ':' + mUid; - } -} diff --git a/java/com/android/voicemailomtp/mail/MessageDateComparator.java b/java/com/android/voicemailomtp/mail/MessageDateComparator.java deleted file mode 100644 index 37071034a..000000000 --- a/java/com/android/voicemailomtp/mail/MessageDateComparator.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.util.Comparator; - -public class MessageDateComparator implements Comparator<Message> { - @Override - public int compare(Message o1, Message o2) { - try { - if (o1.getSentDate() == null) { - return 1; - } else if (o2.getSentDate() == null) { - return -1; - } else - return o2.getSentDate().compareTo(o1.getSentDate()); - } catch (Exception e) { - return 0; - } - } -} diff --git a/java/com/android/voicemailomtp/mail/MessagingException.java b/java/com/android/voicemailomtp/mail/MessagingException.java deleted file mode 100644 index 28550527f..000000000 --- a/java/com/android/voicemailomtp/mail/MessagingException.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail; - -/** - * This exception is used for most types of failures that occur during server interactions. - * - * Data passed through this exception should be considered non-localized. Any strings should - * either be internal-only (for debugging) or server-generated. - * - * TO DO: Does it make sense to further collapse AuthenticationFailedException and - * CertificateValidationException and any others into this? - */ -public class MessagingException extends Exception { - public static final long serialVersionUID = -1; - - public static final int NO_ERROR = -1; - /** Any exception that does not specify a specific issue */ - public static final int UNSPECIFIED_EXCEPTION = 0; - /** Connection or IO errors */ - public static final int IOERROR = 1; - /** The configuration requested TLS but the server did not support it. */ - public static final int TLS_REQUIRED = 2; - /** Authentication is required but the server did not support it. */ - public static final int AUTH_REQUIRED = 3; - /** General security failures */ - public static final int GENERAL_SECURITY = 4; - /** Authentication failed */ - public static final int AUTHENTICATION_FAILED = 5; - /** Attempt to create duplicate account */ - public static final int DUPLICATE_ACCOUNT = 6; - /** Required security policies reported - advisory only */ - public static final int SECURITY_POLICIES_REQUIRED = 7; - /** Required security policies not supported */ - public static final int SECURITY_POLICIES_UNSUPPORTED = 8; - /** The protocol (or protocol version) isn't supported */ - public static final int PROTOCOL_VERSION_UNSUPPORTED = 9; - /** The server's SSL certificate couldn't be validated */ - public static final int CERTIFICATE_VALIDATION_ERROR = 10; - /** Authentication failed during autodiscover */ - public static final int AUTODISCOVER_AUTHENTICATION_FAILED = 11; - /** Autodiscover completed with a result (non-error) */ - public static final int AUTODISCOVER_AUTHENTICATION_RESULT = 12; - /** Ambiguous failure; server error or bad credentials */ - public static final int AUTHENTICATION_FAILED_OR_SERVER_ERROR = 13; - /** The server refused access */ - public static final int ACCESS_DENIED = 14; - /** The server refused access */ - public static final int ATTACHMENT_NOT_FOUND = 15; - /** A client SSL certificate is required for connections to the server */ - public static final int CLIENT_CERTIFICATE_REQUIRED = 16; - /** The client SSL certificate specified is invalid */ - public static final int CLIENT_CERTIFICATE_ERROR = 17; - /** The server indicates it does not support OAuth authentication */ - public static final int OAUTH_NOT_SUPPORTED = 18; - /** The server indicates it experienced an internal error */ - public static final int SERVER_ERROR = 19; - - protected int mExceptionType; - // Exception type-specific data - protected Object mExceptionData; - - public MessagingException(String message, Throwable throwable) { - this(UNSPECIFIED_EXCEPTION, message, throwable); - } - - public MessagingException(int exceptionType, String message, Throwable throwable) { - super(message, throwable); - mExceptionType = exceptionType; - mExceptionData = null; - } - - /** - * Constructs a MessagingException with an exceptionType and a null message. - * @param exceptionType The exception type to set for this exception. - */ - public MessagingException(int exceptionType) { - this(exceptionType, null, null); - } - - /** - * Constructs a MessagingException with a message. - * @param message the message for this exception - */ - public MessagingException(String message) { - this(UNSPECIFIED_EXCEPTION, message, null); - } - - /** - * Constructs a MessagingException with an exceptionType and a message. - * @param exceptionType The exception type to set for this exception. - */ - public MessagingException(int exceptionType, String message) { - this(exceptionType, message, null); - } - - /** - * Constructs a MessagingException with an exceptionType, a message, and data - * @param exceptionType The exception type to set for this exception. - * @param message the message for the exception (or null) - * @param data exception-type specific data for the exception (or null) - */ - public MessagingException(int exceptionType, String message, Object data) { - super(message); - mExceptionType = exceptionType; - mExceptionData = data; - } - - /** - * Return the exception type. Will be OTHER_EXCEPTION if not explicitly set. - * - * @return Returns the exception type. - */ - public int getExceptionType() { - return mExceptionType; - } - /** - * Return the exception data. Will be null if not explicitly set. - * - * @return Returns the exception data. - */ - public Object getExceptionData() { - return mExceptionData; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/Multipart.java b/java/com/android/voicemailomtp/mail/Multipart.java deleted file mode 100644 index b45ebab3d..000000000 --- a/java/com/android/voicemailomtp/mail/Multipart.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.util.ArrayList; - -public abstract class Multipart implements Body { - protected Part mParent; - - protected ArrayList<BodyPart> mParts = new ArrayList<BodyPart>(); - - protected String mContentType; - - public void addBodyPart(BodyPart part) throws MessagingException { - mParts.add(part); - } - - public void addBodyPart(BodyPart part, int index) throws MessagingException { - mParts.add(index, part); - } - - public BodyPart getBodyPart(int index) throws MessagingException { - return mParts.get(index); - } - - public String getContentType() throws MessagingException { - return mContentType; - } - - public int getCount() throws MessagingException { - return mParts.size(); - } - - public boolean removeBodyPart(BodyPart part) throws MessagingException { - return mParts.remove(part); - } - - public void removeBodyPart(int index) throws MessagingException { - mParts.remove(index); - } - - public Part getParent() throws MessagingException { - return mParent; - } - - public void setParent(Part parent) throws MessagingException { - this.mParent = parent; - } -} diff --git a/java/com/android/voicemailomtp/mail/PackedString.java b/java/com/android/voicemailomtp/mail/PackedString.java deleted file mode 100644 index 585759611..000000000 --- a/java/com/android/voicemailomtp/mail/PackedString.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.util.HashMap; -import java.util.Map; - -/** - * A utility class for creating and modifying Strings that are tagged and packed together. - * - * Uses non-printable (control chars) for internal delimiters; Intended for regular displayable - * strings only, so please use base64 or other encoding if you need to hide any binary data here. - * - * Binary compatible with Address.pack() format, which should migrate to use this code. - */ -public class PackedString { - - /** - * Packing format is: - * element : [ value ] or [ value TAG-DELIMITER tag ] - * packed-string : [ element ] [ ELEMENT-DELIMITER [ element ] ]* - */ - private static final char DELIMITER_ELEMENT = '\1'; - private static final char DELIMITER_TAG = '\2'; - - private String mString; - private HashMap<String, String> mExploded; - private static final HashMap<String, String> EMPTY_MAP = new HashMap<String, String>(); - - /** - * Create a packed string using an already-packed string (e.g. from database) - * @param string packed string - */ - public PackedString(String string) { - mString = string; - mExploded = null; - } - - /** - * Get the value referred to by a given tag. If the tag does not exist, return null. - * @param tag identifier of string of interest - * @return returns value, or null if no string is found - */ - public String get(String tag) { - if (mExploded == null) { - mExploded = explode(mString); - } - return mExploded.get(tag); - } - - /** - * Return a map of all of the values referred to by a given tag. This is a shallow - * copy, don't edit the values. - * @return a map of the values in the packed string - */ - public Map<String, String> unpack() { - if (mExploded == null) { - mExploded = explode(mString); - } - return new HashMap<String,String>(mExploded); - } - - /** - * Read out all values into a map. - */ - private static HashMap<String, String> explode(String packed) { - if (packed == null || packed.length() == 0) { - return EMPTY_MAP; - } - HashMap<String, String> map = new HashMap<String, String>(); - - int length = packed.length(); - int elementStartIndex = 0; - int elementEndIndex = 0; - int tagEndIndex = packed.indexOf(DELIMITER_TAG); - - while (elementStartIndex < length) { - elementEndIndex = packed.indexOf(DELIMITER_ELEMENT, elementStartIndex); - if (elementEndIndex == -1) { - elementEndIndex = length; - } - String tag; - String value; - if (tagEndIndex == -1 || elementEndIndex <= tagEndIndex) { - // in this case the DELIMITER_PERSONAL is in a future pair (or not found) - // so synthesize a positional tag for the value, and don't update tagEndIndex - value = packed.substring(elementStartIndex, elementEndIndex); - tag = Integer.toString(map.size()); - } else { - value = packed.substring(elementStartIndex, tagEndIndex); - tag = packed.substring(tagEndIndex + 1, elementEndIndex); - // scan forward for next tag, if any - tagEndIndex = packed.indexOf(DELIMITER_TAG, elementEndIndex + 1); - } - map.put(tag, value); - elementStartIndex = elementEndIndex + 1; - } - - return map; - } - - /** - * Builder class for creating PackedString values. Can also be used for editing existing - * PackedString representations. - */ - static public class Builder { - HashMap<String, String> mMap; - - /** - * Create a builder that's empty (for filling) - */ - public Builder() { - mMap = new HashMap<String, String>(); - } - - /** - * Create a builder using the values of an existing PackedString (for editing). - */ - public Builder(String packed) { - mMap = explode(packed); - } - - /** - * Add a tagged value - * @param tag identifier of string of interest - * @param value the value to record in this position. null to delete entry. - */ - public void put(String tag, String value) { - if (value == null) { - mMap.remove(tag); - } else { - mMap.put(tag, value); - } - } - - /** - * Get the value referred to by a given tag. If the tag does not exist, return null. - * @param tag identifier of string of interest - * @return returns value, or null if no string is found - */ - public String get(String tag) { - return mMap.get(tag); - } - - /** - * Pack the values and return a single, encoded string - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (Map.Entry<String,String> entry : mMap.entrySet()) { - if (sb.length() > 0) { - sb.append(DELIMITER_ELEMENT); - } - sb.append(entry.getValue()); - sb.append(DELIMITER_TAG); - sb.append(entry.getKey()); - } - return sb.toString(); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/Part.java b/java/com/android/voicemailomtp/mail/Part.java deleted file mode 100644 index 51f8a4c38..000000000 --- a/java/com/android/voicemailomtp/mail/Part.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import java.io.IOException; -import java.io.OutputStream; - -public interface Part extends Fetchable { - public void addHeader(String name, String value) throws MessagingException; - - public void removeHeader(String name) throws MessagingException; - - public void setHeader(String name, String value) throws MessagingException; - - public Body getBody() throws MessagingException; - - public String getContentType() throws MessagingException; - - public String getDisposition() throws MessagingException; - - public String getContentId() throws MessagingException; - - public String[] getHeader(String name) throws MessagingException; - - public void setExtendedHeader(String name, String value) throws MessagingException; - - public String getExtendedHeader(String name) throws MessagingException; - - public int getSize() throws MessagingException; - - public boolean isMimeType(String mimeType) throws MessagingException; - - public String getMimeType() throws MessagingException; - - public void setBody(Body body) throws MessagingException; - - public void writeTo(OutputStream out) throws IOException, MessagingException; -} diff --git a/java/com/android/voicemailomtp/mail/PeekableInputStream.java b/java/com/android/voicemailomtp/mail/PeekableInputStream.java deleted file mode 100644 index c1181d189..000000000 --- a/java/com/android/voicemailomtp/mail/PeekableInputStream.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering InputStream that allows single byte "peeks" without consuming the byte. The - * client of this stream can call peek() to see the next available byte in the stream - * and a subsequent read will still return the peeked byte. - */ -public class PeekableInputStream extends InputStream { - private final InputStream mIn; - private boolean mPeeked; - private int mPeekedByte; - - public PeekableInputStream(InputStream in) { - this.mIn = in; - } - - @Override - public int read() throws IOException { - if (!mPeeked) { - return mIn.read(); - } else { - mPeeked = false; - return mPeekedByte; - } - } - - public int peek() throws IOException { - if (!mPeeked) { - mPeekedByte = read(); - mPeeked = true; - } - return mPeekedByte; - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (!mPeeked) { - return mIn.read(b, offset, length); - } else { - b[0] = (byte)mPeekedByte; - mPeeked = false; - int r = mIn.read(b, offset + 1, length - 1); - if (r == -1) { - return 1; - } else { - return r + 1; - } - } - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public String toString() { - return String.format("PeekableInputStream(in=%s, peeked=%b, peekedByte=%d)", - mIn.toString(), mPeeked, mPeekedByte); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/TempDirectory.java b/java/com/android/voicemailomtp/mail/TempDirectory.java deleted file mode 100644 index dfae36026..000000000 --- a/java/com/android/voicemailomtp/mail/TempDirectory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail; - -import android.content.Context; - -import java.io.File; - -/** - * TempDirectory caches the directory used for caching file. It is set up during application - * initialization. - */ -public class TempDirectory { - private static File sTempDirectory = null; - - public static void setTempDirectory(Context context) { - sTempDirectory = context.getCacheDir(); - } - - public static File getTempDirectory() { - if (sTempDirectory == null) { - throw new RuntimeException( - "TempDirectory not set. " + - "If in a unit test, call Email.setTempDirectory(context) in setUp()."); - } - return sTempDirectory; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/internet/BinaryTempFileBody.java b/java/com/android/voicemailomtp/mail/internet/BinaryTempFileBody.java deleted file mode 100644 index 52c43de16..000000000 --- a/java/com/android/voicemailomtp/mail/internet/BinaryTempFileBody.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.TempDirectory; - -import org.apache.commons.io.IOUtils; - -import android.util.Base64; -import android.util.Base64OutputStream; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * A Body that is backed by a temp file. The Body exposes a getOutputStream method that allows - * the user to write to the temp file. After the write the body is available via getInputStream - * and writeTo one time. After writeTo is called, or the InputStream returned from - * getInputStream is closed the file is deleted and the Body should be considered disposed of. - */ -public class BinaryTempFileBody implements Body { - private File mFile; - - /** - * An alternate way to put data into a BinaryTempFileBody is to simply supply an already- - * created file. Note that this file will be deleted after it is read. - * @param filePath The file containing the data to be stored on disk temporarily - */ - public void setFile(String filePath) { - mFile = new File(filePath); - } - - public OutputStream getOutputStream() throws IOException { - mFile = File.createTempFile("body", null, TempDirectory.getTempDirectory()); - mFile.deleteOnExit(); - return new FileOutputStream(mFile); - } - - @Override - public InputStream getInputStream() throws MessagingException { - try { - return new BinaryTempFileBodyInputStream(new FileInputStream(mFile)); - } - catch (IOException ioe) { - throw new MessagingException("Unable to open body", ioe); - } - } - - @Override - public void writeTo(OutputStream out) throws IOException, MessagingException { - InputStream in = getInputStream(); - Base64OutputStream base64Out = new Base64OutputStream( - out, Base64.CRLF | Base64.NO_CLOSE); - IOUtils.copy(in, base64Out); - base64Out.close(); - mFile.delete(); - in.close(); - } - - class BinaryTempFileBodyInputStream extends FilterInputStream { - public BinaryTempFileBodyInputStream(InputStream in) { - super(in); - } - - @Override - public void close() throws IOException { - super.close(); - mFile.delete(); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/MimeBodyPart.java b/java/com/android/voicemailomtp/mail/internet/MimeBodyPart.java deleted file mode 100644 index 8a9c45cf9..000000000 --- a/java/com/android/voicemailomtp/mail/internet/MimeBodyPart.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.BodyPart; -import com.android.voicemailomtp.mail.MessagingException; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.regex.Pattern; - -/** - * TODO this is a close approximation of Message, need to update along with - * Message. - */ -public class MimeBodyPart extends BodyPart { - protected MimeHeader mHeader = new MimeHeader(); - protected MimeHeader mExtendedHeader; - protected Body mBody; - protected int mSize; - - // regex that matches content id surrounded by "<>" optionally. - private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$"); - // regex that matches end of line. - private static final Pattern END_OF_LINE = Pattern.compile("\r?\n"); - - public MimeBodyPart() throws MessagingException { - this(null); - } - - public MimeBodyPart(Body body) throws MessagingException { - this(body, null); - } - - public MimeBodyPart(Body body, String mimeType) throws MessagingException { - if (mimeType != null) { - setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); - } - setBody(body); - } - - protected String getFirstHeader(String name) throws MessagingException { - return mHeader.getFirstHeader(name); - } - - @Override - public void addHeader(String name, String value) throws MessagingException { - mHeader.addHeader(name, value); - } - - @Override - public void setHeader(String name, String value) throws MessagingException { - mHeader.setHeader(name, value); - } - - @Override - public String[] getHeader(String name) throws MessagingException { - return mHeader.getHeader(name); - } - - @Override - public void removeHeader(String name) throws MessagingException { - mHeader.removeHeader(name); - } - - @Override - public Body getBody() throws MessagingException { - return mBody; - } - - @Override - public void setBody(Body body) throws MessagingException { - this.mBody = body; - if (body instanceof com.android.voicemailomtp.mail.Multipart) { - com.android.voicemailomtp.mail.Multipart multipart = - ((com.android.voicemailomtp.mail.Multipart)body); - multipart.setParent(this); - setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); - } - else if (body instanceof TextBody) { - String contentType = String.format("%s;\n charset=utf-8", getMimeType()); - String name = MimeUtility.getHeaderParameter(getContentType(), "name"); - if (name != null) { - contentType += String.format(";\n name=\"%s\"", name); - } - setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); - setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - } - } - - @Override - public String getContentType() throws MessagingException { - String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); - if (contentType == null) { - return "text/plain"; - } else { - return contentType; - } - } - - @Override - public String getDisposition() throws MessagingException { - String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); - if (contentDisposition == null) { - return null; - } else { - return contentDisposition; - } - } - - @Override - public String getContentId() throws MessagingException { - String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID); - if (contentId == null) { - return null; - } else { - // remove optionally surrounding brackets. - return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1"); - } - } - - @Override - public String getMimeType() throws MessagingException { - return MimeUtility.getHeaderParameter(getContentType(), null); - } - - @Override - public boolean isMimeType(String mimeType) throws MessagingException { - return getMimeType().equals(mimeType); - } - - public void setSize(int size) { - this.mSize = size; - } - - @Override - public int getSize() throws MessagingException { - return mSize; - } - - /** - * Set extended header - * - * @param name Extended header name - * @param value header value - flattened by removing CR-NL if any - * remove header if value is null - * @throws MessagingException - */ - @Override - public void setExtendedHeader(String name, String value) throws MessagingException { - if (value == null) { - if (mExtendedHeader != null) { - mExtendedHeader.removeHeader(name); - } - return; - } - if (mExtendedHeader == null) { - mExtendedHeader = new MimeHeader(); - } - mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll("")); - } - - /** - * Get extended header - * - * @param name Extended header name - * @return header value - null if header does not exist - * @throws MessagingException - */ - @Override - public String getExtendedHeader(String name) throws MessagingException { - if (mExtendedHeader == null) { - return null; - } - return mExtendedHeader.getFirstHeader(name); - } - - /** - * Write the MimeMessage out in MIME format. - */ - @Override - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - mHeader.writeTo(out); - writer.write("\r\n"); - writer.flush(); - if (mBody != null) { - mBody.writeTo(out); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/MimeHeader.java b/java/com/android/voicemailomtp/mail/internet/MimeHeader.java deleted file mode 100644 index 4b0aea749..000000000 --- a/java/com/android/voicemailomtp/mail/internet/MimeHeader.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import com.android.voicemailomtp.mail.MessagingException; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.ArrayList; - -public class MimeHeader { - /** - * Application specific header that contains Store specific information about an attachment. - * In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later - * retrieve the attachment at will from the server. - * The info is recorded from this header on LocalStore.appendMessage and is put back - * into the MIME data by LocalStore.fetch. - */ - public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData"; - - public static final String HEADER_CONTENT_TYPE = "Content-Type"; - public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; - public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; - public static final String HEADER_CONTENT_ID = "Content-ID"; - - /** - * Fields that should be omitted when writing the header using writeTo() - */ - private static final String[] WRITE_OMIT_FIELDS = { -// HEADER_ANDROID_ATTACHMENT_DOWNLOADED, -// HEADER_ANDROID_ATTACHMENT_ID, - HEADER_ANDROID_ATTACHMENT_STORE_DATA - }; - - protected final ArrayList<Field> mFields = new ArrayList<Field>(); - - public void clear() { - mFields.clear(); - } - - public String getFirstHeader(String name) throws MessagingException { - String[] header = getHeader(name); - if (header == null) { - return null; - } - return header[0]; - } - - public void addHeader(String name, String value) throws MessagingException { - mFields.add(new Field(name, value)); - } - - public void setHeader(String name, String value) throws MessagingException { - if (name == null || value == null) { - return; - } - removeHeader(name); - addHeader(name, value); - } - - public String[] getHeader(String name) throws MessagingException { - ArrayList<String> values = new ArrayList<String>(); - for (Field field : mFields) { - if (field.name.equalsIgnoreCase(name)) { - values.add(field.value); - } - } - if (values.size() == 0) { - return null; - } - return values.toArray(new String[] {}); - } - - public void removeHeader(String name) throws MessagingException { - ArrayList<Field> removeFields = new ArrayList<Field>(); - for (Field field : mFields) { - if (field.name.equalsIgnoreCase(name)) { - removeFields.add(field); - } - } - mFields.removeAll(removeFields); - } - - /** - * Write header into String - * - * @return CR-NL separated header string except the headers in writeOmitFields - * null if header is empty - */ - public String writeToString() { - if (mFields.size() == 0) { - return null; - } - StringBuilder builder = new StringBuilder(); - for (Field field : mFields) { - if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) { - builder.append(field.name + ": " + field.value + "\r\n"); - } - } - return builder.toString(); - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - for (Field field : mFields) { - if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) { - writer.write(field.name + ": " + field.value + "\r\n"); - } - } - writer.flush(); - } - - private static class Field { - final String name; - final String value; - - public Field(String name, String value) { - this.name = name; - this.value = value; - } - - @Override - public String toString() { - return name + "=" + value; - } - } - - @Override - public String toString() { - return (mFields == null) ? null : mFields.toString(); - } - - public final static boolean arrayContains(Object[] a, Object o) { - int index = arrayIndex(a, o); - return (index >= 0); - } - - public final static int arrayIndex(Object[] a, Object o) { - for (int i = 0, count = a.length; i < count; i++) { - if (a[i].equals(o)) { - return i; - } - } - return -1; - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/MimeMessage.java b/java/com/android/voicemailomtp/mail/internet/MimeMessage.java deleted file mode 100644 index a11cd6d83..000000000 --- a/java/com/android/voicemailomtp/mail/internet/MimeMessage.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import com.android.voicemailomtp.mail.Address; -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.BodyPart; -import com.android.voicemailomtp.mail.Message; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.Multipart; -import com.android.voicemailomtp.mail.Part; -import com.android.voicemailomtp.mail.utils.LogUtils; - -import org.apache.james.mime4j.BodyDescriptor; -import org.apache.james.mime4j.ContentHandler; -import org.apache.james.mime4j.EOLConvertingInputStream; -import org.apache.james.mime4j.MimeStreamParser; -import org.apache.james.mime4j.field.DateTimeField; -import org.apache.james.mime4j.field.Field; - -import android.text.TextUtils; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Stack; -import java.util.regex.Pattern; - -/** - * An implementation of Message that stores all of its metadata in RFC 822 and - * RFC 2045 style headers. - * - * NOTE: Automatic generation of a local message-id is becoming unwieldy and should be removed. - * It would be better to simply do it explicitly on local creation of new outgoing messages. - */ -public class MimeMessage extends Message { - private MimeHeader mHeader; - private MimeHeader mExtendedHeader; - - // NOTE: The fields here are transcribed out of headers, and values stored here will supersede - // the values found in the headers. Use caution to prevent any out-of-phase errors. In - // particular, any adds/changes/deletes here must be echoed by changes in the parse() function. - private Address[] mFrom; - private Address[] mTo; - private Address[] mCc; - private Address[] mBcc; - private Address[] mReplyTo; - private Date mSentDate; - private Body mBody; - protected int mSize; - private boolean mInhibitLocalMessageId = false; - private boolean mComplete = true; - - // Shared random source for generating local message-id values - private static final java.util.Random sRandom = new java.util.Random(); - - // In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to - // "Jan", not the other localized format like "Ene" (meaning January in locale es). - // This conversion is used when generating outgoing MIME messages. Incoming MIME date - // headers are parsed by org.apache.james.mime4j.field.DateTimeField which does not have any - // localization code. - private static final SimpleDateFormat DATE_FORMAT = - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); - - // regex that matches content id surrounded by "<>" optionally. - private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$"); - // regex that matches end of line. - private static final Pattern END_OF_LINE = Pattern.compile("\r?\n"); - - public MimeMessage() { - mHeader = null; - } - - /** - * Generate a local message id. This is only used when none has been assigned, and is - * installed lazily. Any remote (typically server-assigned) message id takes precedence. - * @return a long, locally-generated message-ID value - */ - private static String generateMessageId() { - final StringBuilder sb = new StringBuilder(); - sb.append("<"); - for (int i = 0; i < 24; i++) { - // We'll use a 5-bit range (0..31) - final int value = sRandom.nextInt() & 31; - final char c = "0123456789abcdefghijklmnopqrstuv".charAt(value); - sb.append(c); - } - sb.append("."); - sb.append(Long.toString(System.currentTimeMillis())); - sb.append("@email.android.com>"); - return sb.toString(); - } - - /** - * Parse the given InputStream using Apache Mime4J to build a MimeMessage. - * - * @param in InputStream providing message content - * @throws IOException - * @throws MessagingException - */ - public MimeMessage(InputStream in) throws IOException, MessagingException { - parse(in); - } - - private MimeStreamParser init() { - // Before parsing the input stream, clear all local fields that may be superceded by - // the new incoming message. - getMimeHeaders().clear(); - mInhibitLocalMessageId = true; - mFrom = null; - mTo = null; - mCc = null; - mBcc = null; - mReplyTo = null; - mSentDate = null; - mBody = null; - - final MimeStreamParser parser = new MimeStreamParser(); - parser.setContentHandler(new MimeMessageBuilder()); - return parser; - } - - protected void parse(InputStream in) throws IOException, MessagingException { - final MimeStreamParser parser = init(); - parser.parse(new EOLConvertingInputStream(in)); - mComplete = !parser.getPrematureEof(); - } - - public void parse(InputStream in, EOLConvertingInputStream.Callback callback) - throws IOException, MessagingException { - final MimeStreamParser parser = init(); - parser.parse(new EOLConvertingInputStream(in, getSize(), callback)); - mComplete = !parser.getPrematureEof(); - } - - /** - * Return the internal mHeader value, with very lazy initialization. - * The goal is to save memory by not creating the headers until needed. - */ - private MimeHeader getMimeHeaders() { - if (mHeader == null) { - mHeader = new MimeHeader(); - } - return mHeader; - } - - @Override - public Date getReceivedDate() throws MessagingException { - return null; - } - - @Override - public Date getSentDate() throws MessagingException { - if (mSentDate == null) { - try { - DateTimeField field = (DateTimeField)Field.parse("Date: " - + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); - mSentDate = field.getDate(); - // TODO: We should make it more clear what exceptions can be thrown here, - // and whether they reflect a normal or error condition. - } catch (Exception e) { - LogUtils.v(LogUtils.TAG, "Message missing Date header"); - } - } - if (mSentDate == null) { - // If we still don't have a date, fall back to "Delivery-date" - try { - DateTimeField field = (DateTimeField)Field.parse("Date: " - + MimeUtility.unfoldAndDecode(getFirstHeader("Delivery-date"))); - mSentDate = field.getDate(); - // TODO: We should make it more clear what exceptions can be thrown here, - // and whether they reflect a normal or error condition. - } catch (Exception e) { - LogUtils.v(LogUtils.TAG, "Message also missing Delivery-Date header"); - } - } - return mSentDate; - } - - @Override - public void setSentDate(Date sentDate) throws MessagingException { - setHeader("Date", DATE_FORMAT.format(sentDate)); - this.mSentDate = sentDate; - } - - @Override - public String getContentType() throws MessagingException { - final String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); - if (contentType == null) { - return "text/plain"; - } else { - return contentType; - } - } - - @Override - public String getDisposition() throws MessagingException { - return getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); - } - - @Override - public String getContentId() throws MessagingException { - final String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID); - if (contentId == null) { - return null; - } else { - // remove optionally surrounding brackets. - return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1"); - } - } - - public boolean isComplete() { - return mComplete; - } - - @Override - public String getMimeType() throws MessagingException { - return MimeUtility.getHeaderParameter(getContentType(), null); - } - - @Override - public int getSize() throws MessagingException { - return mSize; - } - - /** - * Returns a list of the given recipient type from this message. If no addresses are - * found the method returns an empty array. - */ - @Override - public Address[] getRecipients(String type) throws MessagingException { - if (type == RECIPIENT_TYPE_TO) { - if (mTo == null) { - mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To"))); - } - return mTo; - } else if (type == RECIPIENT_TYPE_CC) { - if (mCc == null) { - mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC"))); - } - return mCc; - } else if (type == RECIPIENT_TYPE_BCC) { - if (mBcc == null) { - mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC"))); - } - return mBcc; - } else { - throw new MessagingException("Unrecognized recipient type."); - } - } - - @Override - public void setRecipients(String type, Address[] addresses) throws MessagingException { - final int TO_LENGTH = 4; // "To: " - final int CC_LENGTH = 4; // "Cc: " - final int BCC_LENGTH = 5; // "Bcc: " - if (type == RECIPIENT_TYPE_TO) { - if (addresses == null || addresses.length == 0) { - removeHeader("To"); - this.mTo = null; - } else { - setHeader("To", MimeUtility.fold(Address.toHeader(addresses), TO_LENGTH)); - this.mTo = addresses; - } - } else if (type == RECIPIENT_TYPE_CC) { - if (addresses == null || addresses.length == 0) { - removeHeader("CC"); - this.mCc = null; - } else { - setHeader("CC", MimeUtility.fold(Address.toHeader(addresses), CC_LENGTH)); - this.mCc = addresses; - } - } else if (type == RECIPIENT_TYPE_BCC) { - if (addresses == null || addresses.length == 0) { - removeHeader("BCC"); - this.mBcc = null; - } else { - setHeader("BCC", MimeUtility.fold(Address.toHeader(addresses), BCC_LENGTH)); - this.mBcc = addresses; - } - } else { - throw new MessagingException("Unrecognized recipient type."); - } - } - - /** - * Returns the unfolded, decoded value of the Subject header. - */ - @Override - public String getSubject() throws MessagingException { - return MimeUtility.unfoldAndDecode(getFirstHeader("Subject")); - } - - @Override - public void setSubject(String subject) throws MessagingException { - final int HEADER_NAME_LENGTH = 9; // "Subject: " - setHeader("Subject", MimeUtility.foldAndEncode2(subject, HEADER_NAME_LENGTH)); - } - - @Override - public Address[] getFrom() throws MessagingException { - if (mFrom == null) { - String list = MimeUtility.unfold(getFirstHeader("From")); - if (list == null || list.length() == 0) { - list = MimeUtility.unfold(getFirstHeader("Sender")); - } - mFrom = Address.parse(list); - } - return mFrom; - } - - @Override - public void setFrom(Address from) throws MessagingException { - final int FROM_LENGTH = 6; // "From: " - if (from != null) { - setHeader("From", MimeUtility.fold(from.toHeader(), FROM_LENGTH)); - this.mFrom = new Address[] { - from - }; - } else { - this.mFrom = null; - } - } - - @Override - public Address[] getReplyTo() throws MessagingException { - if (mReplyTo == null) { - mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to"))); - } - return mReplyTo; - } - - @Override - public void setReplyTo(Address[] replyTo) throws MessagingException { - final int REPLY_TO_LENGTH = 10; // "Reply-to: " - if (replyTo == null || replyTo.length == 0) { - removeHeader("Reply-to"); - mReplyTo = null; - } else { - setHeader("Reply-to", MimeUtility.fold(Address.toHeader(replyTo), REPLY_TO_LENGTH)); - mReplyTo = replyTo; - } - } - - /** - * Set the mime "Message-ID" header - * @param messageId the new Message-ID value - * @throws MessagingException - */ - @Override - public void setMessageId(String messageId) throws MessagingException { - setHeader("Message-ID", messageId); - } - - /** - * Get the mime "Message-ID" header. This value will be preloaded with a locally-generated - * random ID, if the value has not previously been set. Local generation can be inhibited/ - * overridden by explicitly clearing the headers, removing the message-id header, etc. - * @return the Message-ID header string, or null if explicitly has been set to null - */ - @Override - public String getMessageId() throws MessagingException { - String messageId = getFirstHeader("Message-ID"); - if (messageId == null && !mInhibitLocalMessageId) { - messageId = generateMessageId(); - setMessageId(messageId); - } - return messageId; - } - - @Override - public void saveChanges() throws MessagingException { - throw new MessagingException("saveChanges not yet implemented"); - } - - @Override - public Body getBody() throws MessagingException { - return mBody; - } - - @Override - public void setBody(Body body) throws MessagingException { - this.mBody = body; - if (body instanceof Multipart) { - final Multipart multipart = ((Multipart)body); - multipart.setParent(this); - setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); - setHeader("MIME-Version", "1.0"); - } - else if (body instanceof TextBody) { - setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8", - getMimeType())); - setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - } - } - - protected String getFirstHeader(String name) throws MessagingException { - return getMimeHeaders().getFirstHeader(name); - } - - @Override - public void addHeader(String name, String value) throws MessagingException { - getMimeHeaders().addHeader(name, value); - } - - @Override - public void setHeader(String name, String value) throws MessagingException { - getMimeHeaders().setHeader(name, value); - } - - @Override - public String[] getHeader(String name) throws MessagingException { - return getMimeHeaders().getHeader(name); - } - - @Override - public void removeHeader(String name) throws MessagingException { - getMimeHeaders().removeHeader(name); - if ("Message-ID".equalsIgnoreCase(name)) { - mInhibitLocalMessageId = true; - } - } - - /** - * Set extended header - * - * @param name Extended header name - * @param value header value - flattened by removing CR-NL if any - * remove header if value is null - * @throws MessagingException - */ - @Override - public void setExtendedHeader(String name, String value) throws MessagingException { - if (value == null) { - if (mExtendedHeader != null) { - mExtendedHeader.removeHeader(name); - } - return; - } - if (mExtendedHeader == null) { - mExtendedHeader = new MimeHeader(); - } - mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll("")); - } - - /** - * Get extended header - * - * @param name Extended header name - * @return header value - null if header does not exist - * @throws MessagingException - */ - @Override - public String getExtendedHeader(String name) throws MessagingException { - if (mExtendedHeader == null) { - return null; - } - return mExtendedHeader.getFirstHeader(name); - } - - /** - * Set entire extended headers from String - * - * @param headers Extended header and its value - "CR-NL-separated pairs - * if null or empty, remove entire extended headers - * @throws MessagingException - */ - public void setExtendedHeaders(String headers) throws MessagingException { - if (TextUtils.isEmpty(headers)) { - mExtendedHeader = null; - } else { - mExtendedHeader = new MimeHeader(); - for (final String header : END_OF_LINE.split(headers)) { - final String[] tokens = header.split(":", 2); - if (tokens.length != 2) { - throw new MessagingException("Illegal extended headers: " + headers); - } - mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim()); - } - } - } - - /** - * Get entire extended headers as String - * - * @return "CR-NL-separated extended headers - null if extended header does not exist - */ - public String getExtendedHeaders() { - if (mExtendedHeader != null) { - return mExtendedHeader.writeToString(); - } - return null; - } - - /** - * Write message header and body to output stream - * - * @param out Output steam to write message header and body. - */ - @Override - public void writeTo(OutputStream out) throws IOException, MessagingException { - final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - // Force creation of local message-id - getMessageId(); - getMimeHeaders().writeTo(out); - // mExtendedHeader will not be write out to external output stream, - // because it is intended to internal use. - writer.write("\r\n"); - writer.flush(); - if (mBody != null) { - mBody.writeTo(out); - } - } - - @Override - public InputStream getInputStream() throws MessagingException { - return null; - } - - class MimeMessageBuilder implements ContentHandler { - private final Stack<Object> stack = new Stack<Object>(); - - public MimeMessageBuilder() { - } - - private void expect(Class<?> c) { - if (!c.isInstance(stack.peek())) { - throw new IllegalStateException("Internal stack error: " + "Expected '" - + c.getName() + "' found '" + stack.peek().getClass().getName() + "'"); - } - } - - @Override - public void startMessage() { - if (stack.isEmpty()) { - stack.push(MimeMessage.this); - } else { - expect(Part.class); - try { - final MimeMessage m = new MimeMessage(); - ((Part)stack.peek()).setBody(m); - stack.push(m); - } catch (MessagingException me) { - throw new Error(me); - } - } - } - - @Override - public void endMessage() { - expect(MimeMessage.class); - stack.pop(); - } - - @Override - public void startHeader() { - expect(Part.class); - } - - @Override - public void field(String fieldData) { - expect(Part.class); - try { - final String[] tokens = fieldData.split(":", 2); - ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim()); - } catch (MessagingException me) { - throw new Error(me); - } - } - - @Override - public void endHeader() { - expect(Part.class); - } - - @Override - public void startMultipart(BodyDescriptor bd) { - expect(Part.class); - - final Part e = (Part)stack.peek(); - try { - final MimeMultipart multiPart = new MimeMultipart(e.getContentType()); - e.setBody(multiPart); - stack.push(multiPart); - } catch (MessagingException me) { - throw new Error(me); - } - } - - @Override - public void body(BodyDescriptor bd, InputStream in) throws IOException { - expect(Part.class); - final Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding()); - try { - ((Part)stack.peek()).setBody(body); - } catch (MessagingException me) { - throw new Error(me); - } - } - - @Override - public void endMultipart() { - stack.pop(); - } - - @Override - public void startBodyPart() { - expect(MimeMultipart.class); - - try { - final MimeBodyPart bodyPart = new MimeBodyPart(); - ((MimeMultipart)stack.peek()).addBodyPart(bodyPart); - stack.push(bodyPart); - } catch (MessagingException me) { - throw new Error(me); - } - } - - @Override - public void endBodyPart() { - expect(BodyPart.class); - stack.pop(); - } - - @Override - public void epilogue(InputStream is) throws IOException { - expect(MimeMultipart.class); - final StringBuilder sb = new StringBuilder(); - int b; - while ((b = is.read()) != -1) { - sb.append((char)b); - } - // TODO: why is this commented out? - // ((Multipart) stack.peek()).setEpilogue(sb.toString()); - } - - @Override - public void preamble(InputStream is) throws IOException { - expect(MimeMultipart.class); - final StringBuilder sb = new StringBuilder(); - int b; - while ((b = is.read()) != -1) { - sb.append((char)b); - } - try { - ((MimeMultipart)stack.peek()).setPreamble(sb.toString()); - } catch (MessagingException me) { - throw new Error(me); - } - } - - @Override - public void raw(InputStream is) throws IOException { - throw new UnsupportedOperationException("Not supported"); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/MimeMultipart.java b/java/com/android/voicemailomtp/mail/internet/MimeMultipart.java deleted file mode 100644 index 111924336..000000000 --- a/java/com/android/voicemailomtp/mail/internet/MimeMultipart.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import com.android.voicemailomtp.mail.BodyPart; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.Multipart; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; - -public class MimeMultipart extends Multipart { - protected String mPreamble; - - protected String mContentType; - - protected String mBoundary; - - protected String mSubType; - - public MimeMultipart() throws MessagingException { - mBoundary = generateBoundary(); - setSubType("mixed"); - } - - public MimeMultipart(String contentType) throws MessagingException { - this.mContentType = contentType; - try { - mSubType = MimeUtility.getHeaderParameter(contentType, null).split("/")[1]; - mBoundary = MimeUtility.getHeaderParameter(contentType, "boundary"); - if (mBoundary == null) { - throw new MessagingException("MultiPart does not contain boundary: " + contentType); - } - } catch (Exception e) { - throw new MessagingException( - "Invalid MultiPart Content-Type; must contain subtype and boundary. (" - + contentType + ")", e); - } - } - - public String generateBoundary() { - StringBuffer sb = new StringBuffer(); - sb.append("----"); - for (int i = 0; i < 30; i++) { - sb.append(Integer.toString((int)(Math.random() * 35), 36)); - } - return sb.toString().toUpperCase(); - } - - public String getPreamble() throws MessagingException { - return mPreamble; - } - - public void setPreamble(String preamble) throws MessagingException { - this.mPreamble = preamble; - } - - @Override - public String getContentType() throws MessagingException { - return mContentType; - } - - public void setSubType(String subType) throws MessagingException { - this.mSubType = subType; - mContentType = String.format("multipart/%s; boundary=\"%s\"", subType, mBoundary); - } - - @Override - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - - if (mPreamble != null) { - writer.write(mPreamble + "\r\n"); - } - - for (int i = 0, count = mParts.size(); i < count; i++) { - BodyPart bodyPart = mParts.get(i); - writer.write("--" + mBoundary + "\r\n"); - writer.flush(); - bodyPart.writeTo(out); - writer.write("\r\n"); - } - - writer.write("--" + mBoundary + "--\r\n"); - writer.flush(); - } - - @Override - public InputStream getInputStream() throws MessagingException { - return null; - } - - public String getSubTypeForTest() { - return mSubType; - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/MimeUtility.java b/java/com/android/voicemailomtp/mail/internet/MimeUtility.java deleted file mode 100644 index 4d310b0f5..000000000 --- a/java/com/android/voicemailomtp/mail/internet/MimeUtility.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import android.text.TextUtils; -import android.util.Base64; -import android.util.Base64DataException; -import android.util.Base64InputStream; - -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.BodyPart; -import com.android.voicemailomtp.mail.Message; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.Multipart; -import com.android.voicemailomtp.mail.Part; -import com.android.voicemailomtp.VvmLog; - -import org.apache.commons.io.IOUtils; -import org.apache.james.mime4j.codec.EncoderUtil; -import org.apache.james.mime4j.decoder.DecoderUtil; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; -import org.apache.james.mime4j.util.CharsetUtil; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class MimeUtility { - private static final String LOG_TAG = "Email"; - - public static final String MIME_TYPE_RFC822 = "message/rfc822"; - private final static Pattern PATTERN_CR_OR_LF = Pattern.compile("\r|\n"); - - /** - * Replace sequences of CRLF+WSP with WSP. Tries to preserve original string - * object whenever possible. - */ - public static String unfold(String s) { - if (s == null) { - return null; - } - Matcher patternMatcher = PATTERN_CR_OR_LF.matcher(s); - if (patternMatcher.find()) { - patternMatcher.reset(); - s = patternMatcher.replaceAll(""); - } - return s; - } - - public static String decode(String s) { - if (s == null) { - return null; - } - return DecoderUtil.decodeEncodedWords(s); - } - - public static String unfoldAndDecode(String s) { - return decode(unfold(s)); - } - - // TODO implement proper foldAndEncode - // NOTE: When this really works, we *must* remove all calls to foldAndEncode2() to prevent - // duplication of encoding. - public static String foldAndEncode(String s) { - return s; - } - - /** - * INTERIM version of foldAndEncode that will be used only by Subject: headers. - * This is safer than implementing foldAndEncode() (see above) and risking unknown damage - * to other headers. - * - * TODO: Copy this code to foldAndEncode(), get rid of this function, confirm all working OK. - * - * @param s original string to encode and fold - * @param usedCharacters number of characters already used up by header name - - * @return the String ready to be transmitted - */ - public static String foldAndEncode2(String s, int usedCharacters) { - // james.mime4j.codec.EncoderUtil.java - // encode: encodeIfNecessary(text, usage, numUsedInHeaderName) - // Usage.TEXT_TOKENlooks like the right thing for subjects - // use WORD_ENTITY for address/names - - String encoded = EncoderUtil.encodeIfNecessary(s, EncoderUtil.Usage.TEXT_TOKEN, - usedCharacters); - - return fold(encoded, usedCharacters); - } - - /** - * INTERIM: From newer version of org.apache.james (but we don't want to import - * the entire MimeUtil class). - * - * Splits the specified string into a multiple-line representation with - * lines no longer than 76 characters (because the line might contain - * encoded words; see <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC - * 2047</a> section 2). If the string contains non-whitespace sequences - * longer than 76 characters a line break is inserted at the whitespace - * character following the sequence resulting in a line longer than 76 - * characters. - * - * @param s - * string to split. - * @param usedCharacters - * number of characters already used up. Usually the number of - * characters for header field name plus colon and one space. - * @return a multiple-line representation of the given string. - */ - public static String fold(String s, int usedCharacters) { - final int maxCharacters = 76; - - final int length = s.length(); - if (usedCharacters + length <= maxCharacters) - return s; - - StringBuilder sb = new StringBuilder(); - - int lastLineBreak = -usedCharacters; - int wspIdx = indexOfWsp(s, 0); - while (true) { - if (wspIdx == length) { - sb.append(s.substring(Math.max(0, lastLineBreak))); - return sb.toString(); - } - - int nextWspIdx = indexOfWsp(s, wspIdx + 1); - - if (nextWspIdx - lastLineBreak > maxCharacters) { - sb.append(s.substring(Math.max(0, lastLineBreak), wspIdx)); - sb.append("\r\n"); - lastLineBreak = wspIdx; - } - - wspIdx = nextWspIdx; - } - } - - /** - * INTERIM: From newer version of org.apache.james (but we don't want to import - * the entire MimeUtil class). - * - * Search for whitespace. - */ - private static int indexOfWsp(String s, int fromIndex) { - final int len = s.length(); - for (int index = fromIndex; index < len; index++) { - char c = s.charAt(index); - if (c == ' ' || c == '\t') - return index; - } - return len; - } - - /** - * Returns the named parameter of a header field. If name is null the first - * parameter is returned, or if there are no additional parameters in the - * field the entire field is returned. Otherwise the named parameter is - * searched for in a case insensitive fashion and returned. If the parameter - * cannot be found the method returns null. - * - * TODO: quite inefficient with the inner trimming & splitting. - * TODO: Also has a latent bug: uses "startsWith" to match the name, which can false-positive. - * TODO: The doc says that for a null name you get the first param, but you get the header. - * Should probably just fix the doc, but if other code assumes that behavior, fix the code. - * TODO: Need to decode %-escaped strings, as in: filename="ab%22d". - * ('+' -> ' ' conversion too? check RFC) - * - * @param header - * @param name - * @return the entire header (if name=null), the found parameter, or null - */ - public static String getHeaderParameter(String header, String name) { - if (header == null) { - return null; - } - String[] parts = unfold(header).split(";"); - if (name == null) { - return parts[0].trim(); - } - String lowerCaseName = name.toLowerCase(); - for (String part : parts) { - if (part.trim().toLowerCase().startsWith(lowerCaseName)) { - String[] parameterParts = part.split("=", 2); - if (parameterParts.length < 2) { - return null; - } - String parameter = parameterParts[1].trim(); - if (parameter.startsWith("\"") && parameter.endsWith("\"")) { - return parameter.substring(1, parameter.length() - 1); - } else { - return parameter; - } - } - } - return null; - } - - /** - * Reads the Part's body and returns a String based on any charset conversion that needed - * to be done. - * @param part The part containing a body - * @return a String containing the converted text in the body, or null if there was no text - * or an error during conversion. - */ - public static String getTextFromPart(Part part) { - try { - if (part != null && part.getBody() != null) { - InputStream in = part.getBody().getInputStream(); - String mimeType = part.getMimeType(); - if (mimeType != null && MimeUtility.mimeTypeMatches(mimeType, "text/*")) { - /* - * Now we read the part into a buffer for further processing. Because - * the stream is now wrapped we'll remove any transfer encoding at this point. - */ - ByteArrayOutputStream out = new ByteArrayOutputStream(); - IOUtils.copy(in, out); - in.close(); - in = null; // we want all of our memory back, and close might not release - - /* - * We've got a text part, so let's see if it needs to be processed further. - */ - String charset = getHeaderParameter(part.getContentType(), "charset"); - if (charset != null) { - /* - * See if there is conversion from the MIME charset to the Java one. - */ - charset = CharsetUtil.toJavaCharset(charset); - } - /* - * No encoding, so use us-ascii, which is the standard. - */ - if (charset == null) { - charset = "ASCII"; - } - /* - * Convert and return as new String - */ - String result = out.toString(charset); - out.close(); - return result; - } - } - - } - catch (OutOfMemoryError oom) { - /* - * If we are not able to process the body there's nothing we can do about it. Return - * null and let the upper layers handle the missing content. - */ - VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + oom.toString()); - } - catch (Exception e) { - /* - * If we are not able to process the body there's nothing we can do about it. Return - * null and let the upper layers handle the missing content. - */ - VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + e.toString()); - } - return null; - } - - /** - * Returns true if the given mimeType matches the matchAgainst specification. The comparison - * ignores case and the matchAgainst string may include "*" for a wildcard (e.g. "image/*"). - * - * @param mimeType A MIME type to check. - * @param matchAgainst A MIME type to check against. May include wildcards. - * @return true if the mimeType matches - */ - public static boolean mimeTypeMatches(String mimeType, String matchAgainst) { - Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"), - Pattern.CASE_INSENSITIVE); - return p.matcher(mimeType).matches(); - } - - /** - * Returns true if the given mimeType matches any of the matchAgainst specifications. The - * comparison ignores case and the matchAgainst strings may include "*" for a wildcard - * (e.g. "image/*"). - * - * @param mimeType A MIME type to check. - * @param matchAgainst An array of MIME types to check against. May include wildcards. - * @return true if the mimeType matches any of the matchAgainst strings - */ - public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst) { - for (String matchType : matchAgainst) { - if (mimeTypeMatches(mimeType, matchType)) { - return true; - } - } - return false; - } - - /** - * Given an input stream and a transfer encoding, return a wrapped input stream for that - * encoding (or the original if none is required) - * @param in the input stream - * @param contentTransferEncoding the content transfer encoding - * @return a properly wrapped stream - */ - public static InputStream getInputStreamForContentTransferEncoding(InputStream in, - String contentTransferEncoding) { - if (contentTransferEncoding != null) { - contentTransferEncoding = - MimeUtility.getHeaderParameter(contentTransferEncoding, null); - if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { - in = new QuotedPrintableInputStream(in); - } - else if ("base64".equalsIgnoreCase(contentTransferEncoding)) { - in = new Base64InputStream(in, Base64.DEFAULT); - } - } - return in; - } - - /** - * Removes any content transfer encoding from the stream and returns a Body. - */ - public static Body decodeBody(InputStream in, String contentTransferEncoding) - throws IOException { - /* - * We'll remove any transfer encoding by wrapping the stream. - */ - in = getInputStreamForContentTransferEncoding(in, contentTransferEncoding); - BinaryTempFileBody tempBody = new BinaryTempFileBody(); - OutputStream out = tempBody.getOutputStream(); - try { - IOUtils.copy(in, out); - } catch (Base64DataException bde) { - // TODO Need to fix this somehow - //String warning = "\n\n" + Email.getMessageDecodeErrorString(); - //out.write(warning.getBytes()); - } finally { - out.close(); - } - return tempBody; - } - - /** - * Recursively scan a Part (usually a Message) and sort out which of its children will be - * "viewable" and which will be attachments. - * - * @param part The part to be broken down - * @param viewables This arraylist will be populated with all parts that appear to be - * the "message" (e.g. text/plain & text/html) - * @param attachments This arraylist will be populated with all parts that appear to be - * attachments (including inlines) - * @throws MessagingException - */ - public static void collectParts(Part part, ArrayList<Part> viewables, - ArrayList<Part> attachments) throws MessagingException { - String disposition = part.getDisposition(); - String dispositionType = MimeUtility.getHeaderParameter(disposition, null); - // If a disposition is not specified, default to "inline" - boolean inline = - TextUtils.isEmpty(dispositionType) || "inline".equalsIgnoreCase(dispositionType); - // The lower-case mime type - String mimeType = part.getMimeType().toLowerCase(); - - if (part.getBody() instanceof Multipart) { - // If the part is Multipart but not alternative it's either mixed or - // something we don't know about, which means we treat it as mixed - // per the spec. We just process its pieces recursively. - MimeMultipart mp = (MimeMultipart)part.getBody(); - boolean foundHtml = false; - if (mp.getSubTypeForTest().equals("alternative")) { - for (int i = 0; i < mp.getCount(); i++) { - if (mp.getBodyPart(i).isMimeType("text/html")) { - foundHtml = true; - break; - } - } - } - for (int i = 0; i < mp.getCount(); i++) { - // See if we have text and html - BodyPart bp = mp.getBodyPart(i); - // If there's html, don't bother loading text - if (foundHtml && bp.isMimeType("text/plain")) { - continue; - } - collectParts(bp, viewables, attachments); - } - } else if (part.getBody() instanceof Message) { - // If the part is an embedded message we just continue to process - // it, pulling any viewables or attachments into the running list. - Message message = (Message)part.getBody(); - collectParts(message, viewables, attachments); - } else if (inline && (mimeType.startsWith("text") || (mimeType.startsWith("image")))) { - // We'll treat text and images as viewables - viewables.add(part); - } else { - // Everything else is an attachment. - attachments.add(part); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/internet/TextBody.java b/java/com/android/voicemailomtp/mail/internet/TextBody.java deleted file mode 100644 index 578193eff..000000000 --- a/java/com/android/voicemailomtp/mail/internet/TextBody.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.internet; - -import android.util.Base64; - -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.MessagingException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -public class TextBody implements Body { - String mBody; - - public TextBody(String body) { - this.mBody = body; - } - - @Override - public void writeTo(OutputStream out) throws IOException, MessagingException { - byte[] bytes = mBody.getBytes("UTF-8"); - out.write(Base64.encode(bytes, Base64.CRLF)); - } - - /** - * Get the text of the body in it's unencoded format. - * @return - */ - public String getText() { - return mBody; - } - - /** - * Returns an InputStream that reads this body's text in UTF-8 format. - */ - @Override - public InputStream getInputStream() throws MessagingException { - try { - byte[] b = mBody.getBytes("UTF-8"); - return new ByteArrayInputStream(b); - } - catch (UnsupportedEncodingException usee) { - return null; - } - } -} diff --git a/java/com/android/voicemailomtp/mail/store/ImapConnection.java b/java/com/android/voicemailomtp/mail/store/ImapConnection.java deleted file mode 100644 index 61dcf1281..000000000 --- a/java/com/android/voicemailomtp/mail/store/ImapConnection.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.store; - -import android.util.ArraySet; -import android.util.Base64; -import com.android.voicemailomtp.mail.AuthenticationFailedException; -import com.android.voicemailomtp.mail.CertificateValidationException; -import com.android.voicemailomtp.mail.MailTransport; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.store.ImapStore.ImapException; -import com.android.voicemailomtp.mail.store.imap.DigestMd5Utils; -import com.android.voicemailomtp.mail.store.imap.ImapConstants; -import com.android.voicemailomtp.mail.store.imap.ImapResponse; -import com.android.voicemailomtp.mail.store.imap.ImapResponseParser; -import com.android.voicemailomtp.mail.store.imap.ImapUtility; -import com.android.voicemailomtp.mail.utils.LogUtils; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.VvmLog; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import javax.net.ssl.SSLException; - -/** - * A cacheable class that stores the details for a single IMAP connection. - */ -public class ImapConnection { - private final String TAG = "ImapConnection"; - - private String mLoginPhrase; - private ImapStore mImapStore; - private MailTransport mTransport; - private ImapResponseParser mParser; - private Set<String> mCapabilities = new ArraySet<>(); - - static final String IMAP_REDACTED_LOG = "[IMAP command redacted]"; - - /** - * Next tag to use. All connections associated to the same ImapStore instance share the same - * counter to make tests simpler. - * (Some of the tests involve multiple connections but only have a single counter to track the - * tag.) - */ - private final AtomicInteger mNextCommandTag = new AtomicInteger(0); - - ImapConnection(ImapStore store) { - setStore(store); - } - - void setStore(ImapStore store) { - // TODO: maybe we should throw an exception if the connection is not closed here, - // if it's not currently closed, then we won't reopen it, so if the credentials have - // changed, the connection will not be reestablished. - mImapStore = store; - mLoginPhrase = null; - } - - /** - * Generates and returns the phrase to be used for authentication. This will be a LOGIN with - * username and password. - * - * @return the login command string to sent to the IMAP server - */ - String getLoginPhrase() { - if (mLoginPhrase == null) { - if (mImapStore.getUsername() != null && mImapStore.getPassword() != null) { - // build the LOGIN string once (instead of over-and-over again.) - // apply the quoting here around the built-up password - mLoginPhrase = ImapConstants.LOGIN + " " + mImapStore.getUsername() + " " - + ImapUtility.imapQuoted(mImapStore.getPassword()); - } - } - return mLoginPhrase; - } - - public void open() throws IOException, MessagingException { - if (mTransport != null && mTransport.isOpen()) { - return; - } - - try { - // copy configuration into a clean transport, if necessary - if (mTransport == null) { - mTransport = mImapStore.cloneTransport(); - } - - mTransport.open(); - - createParser(); - - // The server should greet us with something like - // * OK IMAP4rev1 Server - // consume the response before doing anything else. - ImapResponse response = mParser.readResponse(false); - if (!response.isOk()) { - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_INVALID_INITIAL_SERVER_RESPONSE); - throw new MessagingException( - MessagingException.AUTHENTICATION_FAILED_OR_SERVER_ERROR, - "Invalid server initial response"); - } - - queryCapability(); - - maybeDoStartTls(); - - // LOGIN - doLogin(); - } catch (SSLException e) { - LogUtils.d(TAG, "SSLException ", e); - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_SSL_EXCEPTION); - throw new CertificateValidationException(e.getMessage(), e); - } catch (IOException ioe) { - LogUtils.d(TAG, "IOException", ioe); - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_IOE_ON_OPEN); - throw ioe; - } finally { - destroyResponses(); - } - } - - void logout() { - try { - sendCommand(ImapConstants.LOGOUT, false); - if (!mParser.readResponse(true).is(0, ImapConstants.BYE)) { - VvmLog.e(TAG, "Server did not respond LOGOUT with BYE"); - } - if (!mParser.readResponse(false).isOk()) { - VvmLog.e(TAG, "Server did not respond OK after LOGOUT"); - } - } catch (IOException | MessagingException e) { - VvmLog.e(TAG, "Error while logging out:" + e); - } - } - - /** - * Closes the connection and releases all resources. This connection can not be used again - * until {@link #setStore(ImapStore)} is called. - */ - void close() { - if (mTransport != null) { - logout(); - mTransport.close(); - mTransport = null; - } - destroyResponses(); - mParser = null; - mImapStore = null; - } - - /** - * Attempts to convert the connection into secure connection. - */ - private void maybeDoStartTls() throws IOException, MessagingException { - // STARTTLS is required in the OMTP standard but not every implementation support it. - // Make sure the server does have this capability - if (hasCapability(ImapConstants.CAPABILITY_STARTTLS)) { - executeSimpleCommand(ImapConstants.STARTTLS); - mTransport.reopenTls(); - createParser(); - // The cached capabilities should be refreshed after TLS is established. - queryCapability(); - } - } - - /** - * Logs into the IMAP server - */ - private void doLogin() throws IOException, MessagingException, AuthenticationFailedException { - try { - if (mCapabilities.contains(ImapConstants.CAPABILITY_AUTH_DIGEST_MD5)) { - doDigestMd5Auth(); - } else { - executeSimpleCommand(getLoginPhrase(), true); - } - } catch (ImapException ie) { - LogUtils.d(TAG, "ImapException", ie); - String status = ie.getStatus(); - String statusMessage = ie.getStatusMessage(); - String alertText = ie.getAlertText(); - - if (ImapConstants.NO.equals(status)) { - switch (statusMessage) { - case ImapConstants.NO_UNKNOWN_USER: - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_AUTH_UNKNOWN_USER); - break; - case ImapConstants.NO_UNKNOWN_CLIENT: - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_AUTH_UNKNOWN_DEVICE); - break; - case ImapConstants.NO_INVALID_PASSWORD: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_AUTH_INVALID_PASSWORD); - break; - case ImapConstants.NO_MAILBOX_NOT_INITIALIZED: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_AUTH_MAILBOX_NOT_INITIALIZED); - break; - case ImapConstants.NO_SERVICE_IS_NOT_PROVISIONED: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_AUTH_SERVICE_NOT_PROVISIONED); - break; - case ImapConstants.NO_SERVICE_IS_NOT_ACTIVATED: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_AUTH_SERVICE_NOT_ACTIVATED); - break; - case ImapConstants.NO_USER_IS_BLOCKED: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_AUTH_USER_IS_BLOCKED); - break; - case ImapConstants.NO_APPLICATION_ERROR: - mImapStore.getImapHelper() - .handleEvent(OmtpEvents.DATA_REJECTED_SERVER_RESPONSE); - default: - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_BAD_IMAP_CREDENTIAL); - } - throw new AuthenticationFailedException(alertText, ie); - } - - mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_REJECTED_SERVER_RESPONSE); - throw new MessagingException(alertText, ie); - } - } - - private void doDigestMd5Auth() throws IOException, MessagingException { - - // Initiate the authentication. - // The server will issue us a challenge, asking to run MD5 on the nonce with our password - // and other data, including the cnonce we randomly generated. - // - // C: a AUTHENTICATE DIGEST-MD5 - // S: (BASE64) realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth", - // algorithm=md5-sess,charset=utf-8 - List<ImapResponse> responses = executeSimpleCommand( - ImapConstants.AUTHENTICATE + " " + ImapConstants.AUTH_DIGEST_MD5); - String decodedChallenge = decodeBase64(responses.get(0).getStringOrEmpty(0).getString()); - - Map<String, String> challenge = DigestMd5Utils.parseDigestMessage(decodedChallenge); - DigestMd5Utils.Data data = new DigestMd5Utils.Data(mImapStore, mTransport, challenge); - - String response = data.createResponse(); - // Respond to the challenge. If the server accepts it, it will reply a response-auth which - // is the MD5 of our password and the cnonce we've provided, to prove the server does know - // the password. - // - // C: (BASE64) charset=utf-8,username="chris",realm="elwood.innosoft.com", - // nonce="OA6MG9tEQGm2hh",nc=00000001,cnonce="OA6MHXh6VqTrRk", - // digest-uri="imap/elwood.innosoft.com", - // response=d388dad90d4bbd760a152321f2143af7,qop=auth - // S: (BASE64) rspauth=ea40f60335c427b5527b84dbabcdfffd - - responses = executeContinuationResponse(encodeBase64(response), true); - - // Verify response-auth. - // If failed verifyResponseAuth() will throw a MessagingException, terminating the - // connection - String decodedResponseAuth = decodeBase64(responses.get(0).getStringOrEmpty(0).getString()); - data.verifyResponseAuth(decodedResponseAuth); - - // Send a empty response to indicate we've accepted the response-auth - // - // C: (empty) - // S: a OK User logged in - executeContinuationResponse("", false); - - } - - private static String decodeBase64(String string) { - return new String(Base64.decode(string, Base64.DEFAULT)); - } - - private static String encodeBase64(String string) { - return Base64.encodeToString(string.getBytes(), Base64.NO_WRAP); - } - - private void queryCapability() throws IOException, MessagingException { - List<ImapResponse> responses = executeSimpleCommand(ImapConstants.CAPABILITY); - mCapabilities.clear(); - Set<String> disabledCapabilities = mImapStore.getImapHelper().getConfig() - .getDisabledCapabilities(); - for (ImapResponse response : responses) { - if (response.isTagged()) { - continue; - } - for (int i = 0; i < response.size(); i++) { - String capability = response.getStringOrEmpty(i).getString(); - if (disabledCapabilities != null) { - if (!disabledCapabilities.contains(capability)) { - mCapabilities.add(capability); - } - } else { - mCapabilities.add(capability); - } - } - } - - LogUtils.d(TAG, "Capabilities: " + mCapabilities.toString()); - } - - private boolean hasCapability(String capability) { - return mCapabilities.contains(capability); - } - /** - * Create an {@link ImapResponseParser} from {@code mTransport.getInputStream()} and - * set it to {@link #mParser}. - * - * If we already have an {@link ImapResponseParser}, we - * {@link #destroyResponses()} and throw it away. - */ - private void createParser() { - destroyResponses(); - mParser = new ImapResponseParser(mTransport.getInputStream()); - } - - - public void destroyResponses() { - if (mParser != null) { - mParser.destroyResponses(); - } - } - - public ImapResponse readResponse() throws IOException, MessagingException { - return mParser.readResponse(false); - } - - public List<ImapResponse> executeSimpleCommand(String command) - throws IOException, MessagingException{ - return executeSimpleCommand(command, false); - } - - /** - * Send a single command to the server. The command will be preceded by an IMAP command - * tag and followed by \r\n (caller need not supply them). - * Execute a simple command at the server, a simple command being one that is sent in a single - * line of text - * - * @param command the command to send to the server - * @param sensitive whether the command should be redacted in logs (used for login) - * @return a list of ImapResponses - * @throws IOException - * @throws MessagingException - */ - public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive) - throws IOException, MessagingException { - // TODO: It may be nice to catch IOExceptions and close the connection here. - // Currently, we expect callers to do that, but if they fail to we'll be in a broken state. - sendCommand(command, sensitive); - return getCommandResponses(); - } - - public String sendCommand(String command, boolean sensitive) - throws IOException, MessagingException { - open(); - - if (mTransport == null) { - throw new IOException("Null transport"); - } - String tag = Integer.toString(mNextCommandTag.incrementAndGet()); - String commandToSend = tag + " " + command; - mTransport.writeLine(commandToSend, (sensitive ? IMAP_REDACTED_LOG : command)); - return tag; - } - - List<ImapResponse> executeContinuationResponse(String response, boolean sensitive) - throws IOException, MessagingException { - mTransport.writeLine(response, (sensitive ? IMAP_REDACTED_LOG : response)); - return getCommandResponses(); - } - - /** - * Read and return all of the responses from the most recent command sent to the server - * - * @return a list of ImapResponses - * @throws IOException - * @throws MessagingException - */ - List<ImapResponse> getCommandResponses() - throws IOException, MessagingException { - final List<ImapResponse> responses = new ArrayList<ImapResponse>(); - ImapResponse response; - do { - response = mParser.readResponse(false); - responses.add(response); - } while (!(response.isTagged() || response.isContinuationRequest())); - - if (!(response.isOk() || response.isContinuationRequest())) { - final String toString = response.toString(); - final String status = response.getStatusOrEmpty().getString(); - final String statusMessage = response.getStatusResponseTextOrEmpty().getString(); - final String alert = response.getAlertTextOrEmpty().getString(); - final String responseCode = response.getResponseCodeOrEmpty().getString(); - destroyResponses(); - throw new ImapException(toString, status, statusMessage, alert, responseCode); - } - return responses; - } -} diff --git a/java/com/android/voicemailomtp/mail/store/ImapFolder.java b/java/com/android/voicemailomtp/mail/store/ImapFolder.java deleted file mode 100644 index eca349876..000000000 --- a/java/com/android/voicemailomtp/mail/store/ImapFolder.java +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.store; - -import android.content.Context; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; -import android.util.Base64DataException; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.mail.AuthenticationFailedException; -import com.android.voicemailomtp.mail.Body; -import com.android.voicemailomtp.mail.FetchProfile; -import com.android.voicemailomtp.mail.Flag; -import com.android.voicemailomtp.mail.Message; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.Part; -import com.android.voicemailomtp.mail.internet.BinaryTempFileBody; -import com.android.voicemailomtp.mail.internet.MimeBodyPart; -import com.android.voicemailomtp.mail.internet.MimeHeader; -import com.android.voicemailomtp.mail.internet.MimeMultipart; -import com.android.voicemailomtp.mail.internet.MimeUtility; -import com.android.voicemailomtp.mail.store.ImapStore.ImapException; -import com.android.voicemailomtp.mail.store.ImapStore.ImapMessage; -import com.android.voicemailomtp.mail.store.imap.ImapConstants; -import com.android.voicemailomtp.mail.store.imap.ImapElement; -import com.android.voicemailomtp.mail.store.imap.ImapList; -import com.android.voicemailomtp.mail.store.imap.ImapResponse; -import com.android.voicemailomtp.mail.store.imap.ImapString; -import com.android.voicemailomtp.mail.utils.LogUtils; -import com.android.voicemailomtp.mail.utils.Utility; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; - -public class ImapFolder { - private static final String TAG = "ImapFolder"; - private final static String[] PERMANENT_FLAGS = - { Flag.DELETED, Flag.SEEN, Flag.FLAGGED, Flag.ANSWERED }; - private static final int COPY_BUFFER_SIZE = 16*1024; - - private final ImapStore mStore; - private final String mName; - private int mMessageCount = -1; - private ImapConnection mConnection; - private String mMode; - private boolean mExists; - /** A set of hashes that can be used to track dirtiness */ - Object mHash[]; - - public static final String MODE_READ_ONLY = "mode_read_only"; - public static final String MODE_READ_WRITE = "mode_read_write"; - - public ImapFolder(ImapStore store, String name) { - mStore = store; - mName = name; - } - - /** - * Callback for each message retrieval. - */ - public interface MessageRetrievalListener { - public void messageRetrieved(Message message); - } - - private void destroyResponses() { - if (mConnection != null) { - mConnection.destroyResponses(); - } - } - - public void open(String mode) throws MessagingException { - try { - if (isOpen()) { - throw new AssertionError("Duplicated open on ImapFolder"); - } - synchronized (this) { - mConnection = mStore.getConnection(); - } - // * FLAGS (\Answered \Flagged \Deleted \Seen \Draft NonJunk - // $MDNSent) - // * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft - // NonJunk $MDNSent \*)] Flags permitted. - // * 23 EXISTS - // * 0 RECENT - // * OK [UIDVALIDITY 1125022061] UIDs valid - // * OK [UIDNEXT 57576] Predicted next UID - // 2 OK [READ-WRITE] Select completed. - try { - doSelect(); - } catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } finally { - destroyResponses(); - } - } catch (AuthenticationFailedException e) { - // Don't cache this connection, so we're forced to try connecting/login again - mConnection = null; - close(false); - throw e; - } catch (MessagingException e) { - mExists = false; - close(false); - throw e; - } - } - - public boolean isOpen() { - return mExists && mConnection != null; - } - - public String getMode() { - return mMode; - } - - public void close(boolean expunge) { - if (expunge) { - try { - expunge(); - } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); - } - } - mMessageCount = -1; - synchronized (this) { - mConnection = null; - } - } - - public int getMessageCount() { - return mMessageCount; - } - - String[] getSearchUids(List<ImapResponse> responses) { - // S: * SEARCH 2 3 6 - final ArrayList<String> uids = new ArrayList<String>(); - for (ImapResponse response : responses) { - if (!response.isDataResponse(0, ImapConstants.SEARCH)) { - continue; - } - // Found SEARCH response data - for (int i = 1; i < response.size(); i++) { - ImapString s = response.getStringOrEmpty(i); - if (s.isString()) { - uids.add(s.getString()); - } - } - } - return uids.toArray(Utility.EMPTY_STRINGS); - } - - @VisibleForTesting - String[] searchForUids(String searchCriteria) throws MessagingException { - checkOpen(); - try { - try { - final String command = ImapConstants.UID_SEARCH + " " + searchCriteria; - final String[] result = getSearchUids(mConnection.executeSimpleCommand(command)); - LogUtils.d(TAG, "searchForUids '" + searchCriteria + "' results: " + - result.length); - return result; - } catch (ImapException me) { - LogUtils.d(TAG, "ImapException in search: " + searchCriteria, me); - return Utility.EMPTY_STRINGS; // Not found - } catch (IOException ioe) { - LogUtils.d(TAG, "IOException in search: " + searchCriteria, ioe); - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); - throw ioExceptionHandler(mConnection, ioe); - } - } finally { - destroyResponses(); - } - } - - @Nullable - public Message getMessage(String uid) throws MessagingException { - checkOpen(); - - final String[] uids = searchForUids(ImapConstants.UID + " " + uid); - for (int i = 0; i < uids.length; i++) { - if (uids[i].equals(uid)) { - return new ImapMessage(uid, this); - } - } - LogUtils.e(TAG, "UID " + uid + " not found on server"); - return null; - } - - @VisibleForTesting - protected static boolean isAsciiString(String str) { - int len = str.length(); - for (int i = 0; i < len; i++) { - char c = str.charAt(i); - if (c >= 128) return false; - } - return true; - } - - public Message[] getMessages(String[] uids) throws MessagingException { - if (uids == null) { - uids = searchForUids("1:* NOT DELETED"); - } - return getMessagesInternal(uids); - } - - public Message[] getMessagesInternal(String[] uids) { - final ArrayList<Message> messages = new ArrayList<Message>(uids.length); - for (int i = 0; i < uids.length; i++) { - final String uid = uids[i]; - final ImapMessage message = new ImapMessage(uid, this); - messages.add(message); - } - return messages.toArray(Message.EMPTY_ARRAY); - } - - public void fetch(Message[] messages, FetchProfile fp, - MessageRetrievalListener listener) throws MessagingException { - try { - fetchInternal(messages, fp, listener); - } catch (RuntimeException e) { // Probably a parser error. - LogUtils.w(TAG, "Exception detected: " + e.getMessage()); - throw e; - } - } - - public void fetchInternal(Message[] messages, FetchProfile fp, - MessageRetrievalListener listener) throws MessagingException { - if (messages.length == 0) { - return; - } - checkOpen(); - HashMap<String, Message> messageMap = new HashMap<String, Message>(); - for (Message m : messages) { - messageMap.put(m.getUid(), m); - } - - /* - * Figure out what command we are going to run: - * FLAGS - UID FETCH (FLAGS) - * ENVELOPE - UID FETCH (INTERNALDATE UID RFC822.SIZE FLAGS BODY.PEEK[ - * HEADER.FIELDS (date subject from content-type to cc)]) - * STRUCTURE - UID FETCH (BODYSTRUCTURE) - * BODY_SANE - UID FETCH (BODY.PEEK[]<0.N>) where N = max bytes returned - * BODY - UID FETCH (BODY.PEEK[]) - * Part - UID FETCH (BODY.PEEK[ID]) where ID = mime part ID - */ - - final LinkedHashSet<String> fetchFields = new LinkedHashSet<String>(); - - fetchFields.add(ImapConstants.UID); - if (fp.contains(FetchProfile.Item.FLAGS)) { - fetchFields.add(ImapConstants.FLAGS); - } - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - fetchFields.add(ImapConstants.INTERNALDATE); - fetchFields.add(ImapConstants.RFC822_SIZE); - fetchFields.add(ImapConstants.FETCH_FIELD_HEADERS); - } - if (fp.contains(FetchProfile.Item.STRUCTURE)) { - fetchFields.add(ImapConstants.BODYSTRUCTURE); - } - - if (fp.contains(FetchProfile.Item.BODY_SANE)) { - fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_SANE); - } - if (fp.contains(FetchProfile.Item.BODY)) { - fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK); - } - - // TODO Why are we only fetching the first part given? - final Part fetchPart = fp.getFirstPart(); - if (fetchPart != null) { - final String[] partIds = - fetchPart.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); - // TODO Why can a single part have more than one Id? And why should we only fetch - // the first id if there are more than one? - if (partIds != null) { - fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_BARE - + "[" + partIds[0] + "]"); - } - } - - try { - mConnection.sendCommand(String.format(Locale.US, - ImapConstants.UID_FETCH + " %s (%s)", ImapStore.joinMessageUids(messages), - Utility.combine(fetchFields.toArray(new String[fetchFields.size()]), ' ') - ), false); - ImapResponse response; - do { - response = null; - try { - response = mConnection.readResponse(); - - if (!response.isDataResponse(1, ImapConstants.FETCH)) { - continue; // Ignore - } - final ImapList fetchList = response.getListOrEmpty(2); - final String uid = fetchList.getKeyedStringOrEmpty(ImapConstants.UID) - .getString(); - if (TextUtils.isEmpty(uid)) continue; - - ImapMessage message = (ImapMessage) messageMap.get(uid); - if (message == null) continue; - - if (fp.contains(FetchProfile.Item.FLAGS)) { - final ImapList flags = - fetchList.getKeyedListOrEmpty(ImapConstants.FLAGS); - for (int i = 0, count = flags.size(); i < count; i++) { - final ImapString flag = flags.getStringOrEmpty(i); - if (flag.is(ImapConstants.FLAG_DELETED)) { - message.setFlagInternal(Flag.DELETED, true); - } else if (flag.is(ImapConstants.FLAG_ANSWERED)) { - message.setFlagInternal(Flag.ANSWERED, true); - } else if (flag.is(ImapConstants.FLAG_SEEN)) { - message.setFlagInternal(Flag.SEEN, true); - } else if (flag.is(ImapConstants.FLAG_FLAGGED)) { - message.setFlagInternal(Flag.FLAGGED, true); - } - } - } - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - final Date internalDate = fetchList.getKeyedStringOrEmpty( - ImapConstants.INTERNALDATE).getDateOrNull(); - final int size = fetchList.getKeyedStringOrEmpty( - ImapConstants.RFC822_SIZE).getNumberOrZero(); - final String header = fetchList.getKeyedStringOrEmpty( - ImapConstants.BODY_BRACKET_HEADER, true).getString(); - - message.setInternalDate(internalDate); - message.setSize(size); - message.parse(Utility.streamFromAsciiString(header)); - } - if (fp.contains(FetchProfile.Item.STRUCTURE)) { - ImapList bs = fetchList.getKeyedListOrEmpty( - ImapConstants.BODYSTRUCTURE); - if (!bs.isEmpty()) { - try { - parseBodyStructure(bs, message, ImapConstants.TEXT); - } catch (MessagingException e) { - LogUtils.v(TAG, e, "Error handling message"); - message.setBody(null); - } - } - } - if (fp.contains(FetchProfile.Item.BODY) - || fp.contains(FetchProfile.Item.BODY_SANE)) { - // Body is keyed by "BODY[]...". - // Previously used "BODY[..." but this can be confused with "BODY[HEADER..." - // TODO Should we accept "RFC822" as well?? - ImapString body = fetchList.getKeyedStringOrEmpty("BODY[]", true); - InputStream bodyStream = body.getAsStream(); - message.parse(bodyStream); - } - if (fetchPart != null) { - InputStream bodyStream = - fetchList.getKeyedStringOrEmpty("BODY[", true).getAsStream(); - String encodings[] = fetchPart.getHeader( - MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING); - - String contentTransferEncoding = null; - if (encodings != null && encodings.length > 0) { - contentTransferEncoding = encodings[0]; - } else { - // According to http://tools.ietf.org/html/rfc2045#section-6.1 - // "7bit" is the default. - contentTransferEncoding = "7bit"; - } - - try { - // TODO Don't create 2 temp files. - // decodeBody creates BinaryTempFileBody, but we could avoid this - // if we implement ImapStringBody. - // (We'll need to share a temp file. Protect it with a ref-count.) - message.setBody(decodeBody(mStore.getContext(), bodyStream, - contentTransferEncoding, fetchPart.getSize(), listener)); - } catch(Exception e) { - // TODO: Figure out what kinds of exceptions might actually be thrown - // from here. This blanket catch-all is because we're not sure what to - // do if we don't have a contentTransferEncoding, and we don't have - // time to figure out what exceptions might be thrown. - LogUtils.e(TAG, "Error fetching body %s", e); - } - } - - if (listener != null) { - listener.messageRetrieved(message); - } - } finally { - destroyResponses(); - } - } while (!response.isTagged()); - } catch (IOException ioe) { - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); - throw ioExceptionHandler(mConnection, ioe); - } - } - - /** - * Removes any content transfer encoding from the stream and returns a Body. - * This code is taken/condensed from MimeUtility.decodeBody - */ - private static Body decodeBody(Context context,InputStream in, String contentTransferEncoding, - int size, MessageRetrievalListener listener) throws IOException { - // Get a properly wrapped input stream - in = MimeUtility.getInputStreamForContentTransferEncoding(in, contentTransferEncoding); - BinaryTempFileBody tempBody = new BinaryTempFileBody(); - OutputStream out = tempBody.getOutputStream(); - try { - byte[] buffer = new byte[COPY_BUFFER_SIZE]; - int n = 0; - int count = 0; - while (-1 != (n = in.read(buffer))) { - out.write(buffer, 0, n); - count += n; - } - } catch (Base64DataException bde) { - String warning = "\n\nThere was an error while decoding the message."; - out.write(warning.getBytes()); - } finally { - out.close(); - } - return tempBody; - } - - public String[] getPermanentFlags() { - return PERMANENT_FLAGS; - } - - /** - * Handle any untagged responses that the caller doesn't care to handle themselves. - * @param responses - */ - private void handleUntaggedResponses(List<ImapResponse> responses) { - for (ImapResponse response : responses) { - handleUntaggedResponse(response); - } - } - - /** - * Handle an untagged response that the caller doesn't care to handle themselves. - * @param response - */ - private void handleUntaggedResponse(ImapResponse response) { - if (response.isDataResponse(1, ImapConstants.EXISTS)) { - mMessageCount = response.getStringOrEmpty(0).getNumberOrZero(); - } - } - - private static void parseBodyStructure(ImapList bs, Part part, String id) - throws MessagingException { - if (bs.getElementOrNone(0).isList()) { - /* - * This is a multipart/* - */ - MimeMultipart mp = new MimeMultipart(); - for (int i = 0, count = bs.size(); i < count; i++) { - ImapElement e = bs.getElementOrNone(i); - if (e.isList()) { - /* - * For each part in the message we're going to add a new BodyPart and parse - * into it. - */ - MimeBodyPart bp = new MimeBodyPart(); - if (id.equals(ImapConstants.TEXT)) { - parseBodyStructure(bs.getListOrEmpty(i), bp, Integer.toString(i + 1)); - - } else { - parseBodyStructure(bs.getListOrEmpty(i), bp, id + "." + (i + 1)); - } - mp.addBodyPart(bp); - - } else { - if (e.isString()) { - mp.setSubType(bs.getStringOrEmpty(i).getString().toLowerCase(Locale.US)); - } - break; // Ignore the rest of the list. - } - } - part.setBody(mp); - } else { - /* - * This is a body. We need to add as much information as we can find out about - * it to the Part. - */ - - /* - body type - body subtype - body parameter parenthesized list - body id - body description - body encoding - body size - */ - - final ImapString type = bs.getStringOrEmpty(0); - final ImapString subType = bs.getStringOrEmpty(1); - final String mimeType = - (type.getString() + "/" + subType.getString()).toLowerCase(Locale.US); - - final ImapList bodyParams = bs.getListOrEmpty(2); - final ImapString cid = bs.getStringOrEmpty(3); - final ImapString encoding = bs.getStringOrEmpty(5); - final int size = bs.getStringOrEmpty(6).getNumberOrZero(); - - if (MimeUtility.mimeTypeMatches(mimeType, MimeUtility.MIME_TYPE_RFC822)) { - // A body type of type MESSAGE and subtype RFC822 - // contains, immediately after the basic fields, the - // envelope structure, body structure, and size in - // text lines of the encapsulated message. - // [MESSAGE, RFC822, [NAME, filename.eml], NIL, NIL, 7BIT, 5974, NIL, - // [INLINE, [FILENAME*0, Fwd: Xxx..., FILENAME*1, filename.eml]], NIL] - /* - * This will be caught by fetch and handled appropriately. - */ - throw new MessagingException("BODYSTRUCTURE " + MimeUtility.MIME_TYPE_RFC822 - + " not yet supported."); - } - - /* - * Set the content type with as much information as we know right now. - */ - final StringBuilder contentType = new StringBuilder(mimeType); - - /* - * If there are body params we might be able to get some more information out - * of them. - */ - for (int i = 1, count = bodyParams.size(); i < count; i += 2) { - - // TODO We need to convert " into %22, but - // because MimeUtility.getHeaderParameter doesn't recognize it, - // we can't fix it for now. - contentType.append(String.format(";\n %s=\"%s\"", - bodyParams.getStringOrEmpty(i - 1).getString(), - bodyParams.getStringOrEmpty(i).getString())); - } - - part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType.toString()); - - // Extension items - final ImapList bodyDisposition; - - if (type.is(ImapConstants.TEXT) && bs.getElementOrNone(9).isList()) { - // If media-type is TEXT, 9th element might be: [body-fld-lines] := number - // So, if it's not a list, use 10th element. - // (Couldn't find evidence in the RFC if it's ALWAYS 10th element.) - bodyDisposition = bs.getListOrEmpty(9); - } else { - bodyDisposition = bs.getListOrEmpty(8); - } - - final StringBuilder contentDisposition = new StringBuilder(); - - if (bodyDisposition.size() > 0) { - final String bodyDisposition0Str = - bodyDisposition.getStringOrEmpty(0).getString().toLowerCase(Locale.US); - if (!TextUtils.isEmpty(bodyDisposition0Str)) { - contentDisposition.append(bodyDisposition0Str); - } - - final ImapList bodyDispositionParams = bodyDisposition.getListOrEmpty(1); - if (!bodyDispositionParams.isEmpty()) { - /* - * If there is body disposition information we can pull some more - * information about the attachment out. - */ - for (int i = 1, count = bodyDispositionParams.size(); i < count; i += 2) { - - // TODO We need to convert " into %22. See above. - contentDisposition.append(String.format(Locale.US, ";\n %s=\"%s\"", - bodyDispositionParams.getStringOrEmpty(i - 1) - .getString().toLowerCase(Locale.US), - bodyDispositionParams.getStringOrEmpty(i).getString())); - } - } - } - - if ((size > 0) - && (MimeUtility.getHeaderParameter(contentDisposition.toString(), "size") - == null)) { - contentDisposition.append(String.format(Locale.US, ";\n size=%d", size)); - } - - if (contentDisposition.length() > 0) { - /* - * Set the content disposition containing at least the size. Attachment - * handling code will use this down the road. - */ - part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, - contentDisposition.toString()); - } - - /* - * Set the Content-Transfer-Encoding header. Attachment code will use this - * to parse the body. - */ - if (!encoding.isEmpty()) { - part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, - encoding.getString()); - } - - /* - * Set the Content-ID header. - */ - if (!cid.isEmpty()) { - part.setHeader(MimeHeader.HEADER_CONTENT_ID, cid.getString()); - } - - if (size > 0) { - if (part instanceof ImapMessage) { - ((ImapMessage) part).setSize(size); - } else if (part instanceof MimeBodyPart) { - ((MimeBodyPart) part).setSize(size); - } else { - throw new MessagingException("Unknown part type " + part.toString()); - } - } - part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); - } - - } - - public Message[] expunge() throws MessagingException { - checkOpen(); - try { - handleUntaggedResponses(mConnection.executeSimpleCommand(ImapConstants.EXPUNGE)); - } catch (IOException ioe) { - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); - throw ioExceptionHandler(mConnection, ioe); - } finally { - destroyResponses(); - } - return null; - } - - public void setFlags(Message[] messages, String[] flags, boolean value) - throws MessagingException { - checkOpen(); - - String allFlags = ""; - if (flags.length > 0) { - StringBuilder flagList = new StringBuilder(); - for (int i = 0, count = flags.length; i < count; i++) { - String flag = flags[i]; - if (flag == Flag.SEEN) { - flagList.append(" " + ImapConstants.FLAG_SEEN); - } else if (flag == Flag.DELETED) { - flagList.append(" " + ImapConstants.FLAG_DELETED); - } else if (flag == Flag.FLAGGED) { - flagList.append(" " + ImapConstants.FLAG_FLAGGED); - } else if (flag == Flag.ANSWERED) { - flagList.append(" " + ImapConstants.FLAG_ANSWERED); - } - } - allFlags = flagList.substring(1); - } - try { - mConnection.executeSimpleCommand(String.format(Locale.US, - ImapConstants.UID_STORE + " %s %s" + ImapConstants.FLAGS_SILENT + " (%s)", - ImapStore.joinMessageUids(messages), - value ? "+" : "-", - allFlags)); - - } catch (IOException ioe) { - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); - throw ioExceptionHandler(mConnection, ioe); - } finally { - destroyResponses(); - } - } - - /** - * Selects the folder for use. Before performing any operations on this folder, it - * must be selected. - */ - private void doSelect() throws IOException, MessagingException { - final List<ImapResponse> responses = mConnection.executeSimpleCommand( - String.format(Locale.US, ImapConstants.SELECT + " \"%s\"", mName)); - - // Assume the folder is opened read-write; unless we are notified otherwise - mMode = MODE_READ_WRITE; - int messageCount = -1; - for (ImapResponse response : responses) { - if (response.isDataResponse(1, ImapConstants.EXISTS)) { - messageCount = response.getStringOrEmpty(0).getNumberOrZero(); - } else if (response.isOk()) { - final ImapString responseCode = response.getResponseCodeOrEmpty(); - if (responseCode.is(ImapConstants.READ_ONLY)) { - mMode = MODE_READ_ONLY; - } else if (responseCode.is(ImapConstants.READ_WRITE)) { - mMode = MODE_READ_WRITE; - } - } else if (response.isTagged()) { // Not OK - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_MAILBOX_OPEN_FAILED); - throw new MessagingException("Can't open mailbox: " - + response.getStatusResponseTextOrEmpty()); - } - } - if (messageCount == -1) { - throw new MessagingException("Did not find message count during select"); - } - mMessageCount = messageCount; - mExists = true; - } - - public class Quota { - - public final int occupied; - public final int total; - - public Quota(int occupied, int total) { - this.occupied = occupied; - this.total = total; - } - } - - public Quota getQuota() throws MessagingException { - try { - final List<ImapResponse> responses = mConnection.executeSimpleCommand( - String.format(Locale.US, ImapConstants.GETQUOTAROOT + " \"%s\"", mName)); - - for (ImapResponse response : responses) { - if (!response.isDataResponse(0, ImapConstants.QUOTA)) { - continue; - } - ImapList list = response.getListOrEmpty(2); - for (int i = 0; i < list.size(); i += 3) { - if (!list.getStringOrEmpty(i).is("voice")) { - continue; - } - return new Quota( - list.getStringOrEmpty(i + 1).getNumber(-1), - list.getStringOrEmpty(i + 2).getNumber(-1)); - } - } - } catch (IOException ioe) { - mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); - throw ioExceptionHandler(mConnection, ioe); - } finally { - destroyResponses(); - } - return null; - } - - private void checkOpen() throws MessagingException { - if (!isOpen()) { - throw new MessagingException("Folder " + mName + " is not open."); - } - } - - private MessagingException ioExceptionHandler(ImapConnection connection, IOException ioe) { - LogUtils.d(TAG, "IO Exception detected: ", ioe); - connection.close(); - if (connection == mConnection) { - mConnection = null; // To prevent close() from returning the connection to the pool. - close(false); - } - return new MessagingException(MessagingException.IOERROR, "IO Error", ioe); - } - - public Message createMessage(String uid) { - return new ImapMessage(uid, this); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/ImapStore.java b/java/com/android/voicemailomtp/mail/store/ImapStore.java deleted file mode 100644 index f3e0c098e..000000000 --- a/java/com/android/voicemailomtp/mail/store/ImapStore.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store; - -import android.content.Context; -import android.net.Network; - -import com.android.voicemailomtp.mail.MailTransport; -import com.android.voicemailomtp.mail.Message; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.internet.MimeMessage; -import com.android.voicemailomtp.imap.ImapHelper; - -import java.io.IOException; -import java.io.InputStream; - -public class ImapStore { - /** - * A global suggestion to Store implementors on how much of the body - * should be returned on FetchProfile.Item.BODY_SANE requests. We'll use 125k now. - */ - public static final int FETCH_BODY_SANE_SUGGESTED_SIZE = (125 * 1024); - private final Context mContext; - private final ImapHelper mHelper; - private final String mUsername; - private final String mPassword; - private final MailTransport mTransport; - private ImapConnection mConnection; - - public static final int FLAG_NONE = 0x00; // No flags - public static final int FLAG_SSL = 0x01; // Use SSL - public static final int FLAG_TLS = 0x02; // Use TLS - public static final int FLAG_AUTHENTICATE = 0x04; // Use name/password for authentication - public static final int FLAG_TRUST_ALL = 0x08; // Trust all certificates - public static final int FLAG_OAUTH = 0x10; // Use OAuth for authentication - - /** - * Contains all the information necessary to log into an imap server - */ - public ImapStore(Context context, ImapHelper helper, String username, String password, int port, - String serverName, int flags, Network network) { - mContext = context; - mHelper = helper; - mUsername = username; - mPassword = password; - mTransport = new MailTransport(context, this.getImapHelper(), - network, serverName, port, flags); - } - - public Context getContext() { - return mContext; - } - - public ImapHelper getImapHelper() { - return mHelper; - } - - public String getUsername() { - return mUsername; - } - - public String getPassword() { - return mPassword; - } - - /** Returns a clone of the transport associated with this store. */ - MailTransport cloneTransport() { - return mTransport.clone(); - } - - /** - * Returns UIDs of Messages joined with "," as the separator. - */ - static String joinMessageUids(Message[] messages) { - StringBuilder sb = new StringBuilder(); - boolean notFirst = false; - for (Message m : messages) { - if (notFirst) { - sb.append(','); - } - sb.append(m.getUid()); - notFirst = true; - } - return sb.toString(); - } - - static class ImapMessage extends MimeMessage { - private ImapFolder mFolder; - - ImapMessage(String uid, ImapFolder folder) { - mUid = uid; - mFolder = folder; - } - - public void setSize(int size) { - mSize = size; - } - - @Override - public void parse(InputStream in) throws IOException, MessagingException { - super.parse(in); - } - - public void setFlagInternal(String flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - } - - @Override - public void setFlag(String flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - mFolder.setFlags(new Message[] { this }, new String[] { flag }, set); - } - } - - static class ImapException extends MessagingException { - private static final long serialVersionUID = 1L; - - private final String mStatus; - private final String mStatusMessage; - private final String mAlertText; - private final String mResponseCode; - - public ImapException(String message, String status, String statusMessage, String alertText, - String responseCode) { - super(message); - mStatus = status; - mStatusMessage = statusMessage; - mAlertText = alertText; - mResponseCode = responseCode; - } - - public String getStatus() { - return mStatus; - } - - public String getStatusMessage() { - return mStatusMessage; - } - - public String getAlertText() { - return mAlertText; - } - - public String getResponseCode() { - return mResponseCode; - } - } - - public void closeConnection() { - if (mConnection != null) { - mConnection.close(); - mConnection = null; - } - } - - public ImapConnection getConnection() { - if (mConnection == null) { - mConnection = new ImapConnection(this); - } - return mConnection; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/DigestMd5Utils.java b/java/com/android/voicemailomtp/mail/store/imap/DigestMd5Utils.java deleted file mode 100644 index b78f55293..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/DigestMd5Utils.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import android.annotation.TargetApi; -import android.os.Build.VERSION_CODES; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.util.ArrayMap; -import android.util.Base64; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.mail.MailTransport; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.store.ImapStore; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Map; - -@SuppressWarnings("AndroidApiChecker") // Map.getOrDefault() is java8 -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class DigestMd5Utils { - - private static final String TAG = "DigestMd5Utils"; - - private static final String DIGEST_CHARSET = "CHARSET"; - private static final String DIGEST_USERNAME = "username"; - private static final String DIGEST_REALM = "realm"; - private static final String DIGEST_NONCE = "nonce"; - private static final String DIGEST_NC = "nc"; - private static final String DIGEST_CNONCE = "cnonce"; - private static final String DIGEST_URI = "digest-uri"; - private static final String DIGEST_RESPONSE = "response"; - private static final String DIGEST_QOP = "qop"; - - private static final String RESPONSE_AUTH_HEADER = "rspauth="; - private static final String HEX_CHARS = "0123456789abcdef"; - - /** - * Represents the set of data we need to generate the DIGEST-MD5 response. - */ - public static class Data { - - private static final String CHARSET = "utf-8"; - - public String username; - public String password; - public String realm; - public String nonce; - public String nc; - public String cnonce; - public String digestUri; - public String qop; - - @VisibleForTesting - Data() { - // Do nothing - } - - public Data(ImapStore imapStore, MailTransport transport, Map<String, String> challenge) { - username = imapStore.getUsername(); - password = imapStore.getPassword(); - realm = challenge.getOrDefault(DIGEST_REALM, ""); - nonce = challenge.get(DIGEST_NONCE); - cnonce = createCnonce(); - nc = "00000001"; // Subsequent Authentication not supported, nounce count always 1. - qop = "auth"; // Other config not supported - digestUri = "imap/" + transport.getHost(); - } - - private static String createCnonce() { - SecureRandom generator = new SecureRandom(); - - // At least 64 bits of entropy is required - byte[] rawBytes = new byte[8]; - generator.nextBytes(rawBytes); - - return Base64.encodeToString(rawBytes, Base64.NO_WRAP); - } - - /** - * Verify the response-auth returned by the server is correct. - */ - public void verifyResponseAuth(String response) - throws MessagingException { - if (!response.startsWith(RESPONSE_AUTH_HEADER)) { - throw new MessagingException("response-auth expected"); - } - if (!response.substring(RESPONSE_AUTH_HEADER.length()) - .equals(DigestMd5Utils.getResponse(this, true))) { - throw new MessagingException("invalid response-auth return from the server."); - } - } - - public String createResponse() { - String response = getResponse(this, false); - ResponseBuilder builder = new ResponseBuilder(); - builder - .append(DIGEST_CHARSET, CHARSET) - .appendQuoted(DIGEST_USERNAME, username) - .appendQuoted(DIGEST_REALM, realm) - .appendQuoted(DIGEST_NONCE, nonce) - .append(DIGEST_NC, nc) - .appendQuoted(DIGEST_CNONCE, cnonce) - .appendQuoted(DIGEST_URI, digestUri) - .append(DIGEST_RESPONSE, response) - .append(DIGEST_QOP, qop); - return builder.toString(); - } - - private static class ResponseBuilder { - - private StringBuilder mBuilder = new StringBuilder(); - - public ResponseBuilder appendQuoted(String key, String value) { - if (mBuilder.length() != 0) { - mBuilder.append(","); - } - mBuilder.append(key).append("=\"").append(value).append("\""); - return this; - } - - public ResponseBuilder append(String key, String value) { - if (mBuilder.length() != 0) { - mBuilder.append(","); - } - mBuilder.append(key).append("=").append(value); - return this; - } - - @Override - public String toString() { - return mBuilder.toString(); - } - } - } - - /* - response-value = - toHex( getKeyDigest ( toHex(getMd5(a1)), - { nonce-value, ":" nc-value, ":", - cnonce-value, ":", qop-value, ":", toHex(getMd5(a2)) })) - * @param isResponseAuth is the response the one the server is returning us. response-auth has - * different a2 format. - */ - @VisibleForTesting - static String getResponse(Data data, boolean isResponseAuth) { - StringBuilder a1 = new StringBuilder(); - a1.append(new String( - getMd5(data.username + ":" + data.realm + ":" + data.password), - StandardCharsets.ISO_8859_1)); - a1.append(":").append(data.nonce).append(":").append(data.cnonce); - - StringBuilder a2 = new StringBuilder(); - if (!isResponseAuth) { - a2.append("AUTHENTICATE"); - } - a2.append(":").append(data.digestUri); - - return toHex(getKeyDigest( - toHex(getMd5(a1.toString())), - data.nonce + ":" + data.nc + ":" + data.cnonce + ":" + data.qop + ":" + toHex( - getMd5(a2.toString())) - )); - } - - /** - * Let getMd5(s) be the 16 octet MD5 hash [RFC 1321] of the octet string s. - */ - private static byte[] getMd5(String s) { - try { - MessageDigest digester = MessageDigest.getInstance("MD5"); - digester.update(s.getBytes(StandardCharsets.ISO_8859_1)); - return digester.digest(); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } - } - - /** - * Let getKeyDigest(k, s) be getMd5({k, ":", s}), i.e., the 16 octet hash of the string k, a colon and the - * string s. - */ - private static byte[] getKeyDigest(String k, String s) { - StringBuilder builder = new StringBuilder(k).append(":").append(s); - return getMd5(builder.toString()); - } - - /** - * Let toHex(n) be the representation of the 16 octet MD5 hash n as a string of 32 hex digits - * (with alphabetic characters always in lower case, since MD5 is case sensitive). - */ - private static String toHex(byte[] n) { - StringBuilder result = new StringBuilder(); - for (byte b : n) { - int unsignedByte = b & 0xFF; - result.append(HEX_CHARS.charAt(unsignedByte / 16)) - .append(HEX_CHARS.charAt(unsignedByte % 16)); - } - return result.toString(); - } - - public static Map<String, String> parseDigestMessage(String message) throws MessagingException { - Map<String, String> result = new DigestMessageParser(message).parse(); - if (!result.containsKey(DIGEST_NONCE)) { - throw new MessagingException("nonce missing from server DIGEST-MD5 challenge"); - } - return result; - } - - /** - * Parse the key-value pair returned by the server. - */ - private static class DigestMessageParser { - - private final String mMessage; - private int mPosition = 0; - private Map<String, String> mResult = new ArrayMap<>(); - - public DigestMessageParser(String message) { - mMessage = message; - } - - @Nullable - public Map<String, String> parse() { - try { - while (mPosition < mMessage.length()) { - parsePair(); - if (mPosition != mMessage.length()) { - expect(','); - } - } - } catch (IndexOutOfBoundsException e) { - VvmLog.e(TAG, e.toString()); - return null; - } - return mResult; - } - - private void parsePair() { - String key = parseKey(); - expect('='); - String value = parseValue(); - mResult.put(key, value); - } - - private void expect(char c) { - if (pop() != c) { - throw new IllegalStateException( - "unexpected character " + mMessage.charAt(mPosition)); - } - } - - private char pop() { - char result = peek(); - mPosition++; - return result; - } - - private char peek() { - return mMessage.charAt(mPosition); - } - - private void goToNext(char c) { - while (peek() != c) { - mPosition++; - } - } - - private String parseKey() { - int start = mPosition; - goToNext('='); - return mMessage.substring(start, mPosition); - } - - private String parseValue() { - if (peek() == '"') { - return parseQuotedValue(); - } else { - return parseUnquotedValue(); - } - } - - private String parseQuotedValue() { - expect('"'); - StringBuilder result = new StringBuilder(); - while (true) { - char c = pop(); - if (c == '\\') { - result.append(pop()); - } else if (c == '"') { - break; - } else { - result.append(c); - } - } - return result.toString(); - } - - private String parseUnquotedValue() { - StringBuilder result = new StringBuilder(); - while (true) { - char c = pop(); - if (c == '\\') { - result.append(pop()); - } else if (c == ',') { - mPosition--; - break; - } else { - result.append(c); - } - - if (mPosition == mMessage.length()) { - break; - } - } - return result.toString(); - } - } -} diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapConstants.java b/java/com/android/voicemailomtp/mail/store/imap/ImapConstants.java deleted file mode 100644 index d8e75752f..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapConstants.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.mail.store.ImapStore; - -import java.util.Locale; - -public final class ImapConstants { - private ImapConstants() {} - - public static final String FETCH_FIELD_BODY_PEEK_BARE = "BODY.PEEK"; - public static final String FETCH_FIELD_BODY_PEEK = FETCH_FIELD_BODY_PEEK_BARE + "[]"; - public static final String FETCH_FIELD_BODY_PEEK_SANE = String.format( - Locale.US, "BODY.PEEK[]<0.%d>", ImapStore.FETCH_BODY_SANE_SUGGESTED_SIZE); - public static final String FETCH_FIELD_HEADERS = - "BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc message-id)]"; - - public static final String ALERT = "ALERT"; - public static final String APPEND = "APPEND"; - public static final String AUTHENTICATE = "AUTHENTICATE"; - public static final String BAD = "BAD"; - public static final String BADCHARSET = "BADCHARSET"; - public static final String BODY = "BODY"; - public static final String BODY_BRACKET_HEADER = "BODY[HEADER"; - public static final String BODYSTRUCTURE = "BODYSTRUCTURE"; - public static final String BYE = "BYE"; - public static final String CAPABILITY = "CAPABILITY"; - public static final String CHECK = "CHECK"; - public static final String CLOSE = "CLOSE"; - public static final String COPY = "COPY"; - public static final String COPYUID = "COPYUID"; - public static final String CREATE = "CREATE"; - public static final String DELETE = "DELETE"; - public static final String EXAMINE = "EXAMINE"; - public static final String EXISTS = "EXISTS"; - public static final String EXPUNGE = "EXPUNGE"; - public static final String FETCH = "FETCH"; - public static final String FLAG_ANSWERED = "\\ANSWERED"; - public static final String FLAG_DELETED = "\\DELETED"; - public static final String FLAG_FLAGGED = "\\FLAGGED"; - public static final String FLAG_NO_SELECT = "\\NOSELECT"; - public static final String FLAG_SEEN = "\\SEEN"; - public static final String FLAGS = "FLAGS"; - public static final String FLAGS_SILENT = "FLAGS.SILENT"; - public static final String ID = "ID"; - public static final String INBOX = "INBOX"; - public static final String INTERNALDATE = "INTERNALDATE"; - public static final String LIST = "LIST"; - public static final String LOGIN = "LOGIN"; - public static final String LOGOUT = "LOGOUT"; - public static final String LSUB = "LSUB"; - public static final String NAMESPACE = "NAMESPACE"; - public static final String NO = "NO"; - public static final String NOOP = "NOOP"; - public static final String OK = "OK"; - public static final String PARSE = "PARSE"; - public static final String PERMANENTFLAGS = "PERMANENTFLAGS"; - public static final String PREAUTH = "PREAUTH"; - public static final String READ_ONLY = "READ-ONLY"; - public static final String READ_WRITE = "READ-WRITE"; - public static final String RENAME = "RENAME"; - public static final String RFC822_SIZE = "RFC822.SIZE"; - public static final String SEARCH = "SEARCH"; - public static final String SELECT = "SELECT"; - public static final String STARTTLS = "STARTTLS"; - public static final String STATUS = "STATUS"; - public static final String STORE = "STORE"; - public static final String SUBSCRIBE = "SUBSCRIBE"; - public static final String TEXT = "TEXT"; - public static final String TRYCREATE = "TRYCREATE"; - public static final String UID = "UID"; - public static final String UID_COPY = "UID COPY"; - public static final String UID_FETCH = "UID FETCH"; - public static final String UID_SEARCH = "UID SEARCH"; - public static final String UID_STORE = "UID STORE"; - public static final String UIDNEXT = "UIDNEXT"; - public static final String UIDPLUS = "UIDPLUS"; - public static final String UIDVALIDITY = "UIDVALIDITY"; - public static final String UNSEEN = "UNSEEN"; - public static final String UNSUBSCRIBE = "UNSUBSCRIBE"; - public static final String XOAUTH2 = "XOAUTH2"; - public static final String APPENDUID = "APPENDUID"; - public static final String NIL = "NIL"; - - /** - * NO responses - */ - public static final String NO_COMMAND_NOT_ALLOWED = "command not allowed"; - public static final String NO_RESERVATION_FAILED = "reservation failed"; - public static final String NO_APPLICATION_ERROR = "application error"; - public static final String NO_INVALID_PARAMETER = "invalid parameter"; - public static final String NO_INVALID_COMMAND = "invalid command"; - public static final String NO_UNKNOWN_COMMAND = "unknown command"; - // AUTHENTICATE - // The subscriber can not be located in the system. - public static final String NO_UNKNOWN_USER = "unknown user"; - // The Client Type or Protocol Version is unknown. - public static final String NO_UNKNOWN_CLIENT = "unknown client"; - // The password received from the client does not match the password defined in the subscriber's profile. - public static final String NO_INVALID_PASSWORD = "invalid password"; - // The subscriber's mailbox has not yet been initialised via the TUI - public static final String NO_MAILBOX_NOT_INITIALIZED = "mailbox not initialized"; - // The subscriber has not been provisioned for the VVM service. - public static final String NO_SERVICE_IS_NOT_PROVISIONED = - "service is not provisioned"; - // The subscriber is provisioned for the VVM service but the VVM service is currently not active - public static final String NO_SERVICE_IS_NOT_ACTIVATED = "service is not activated"; - // The Voice Mail Blocked flag in the subscriber's profile is set to YES. - public static final String NO_USER_IS_BLOCKED = "user is blocked"; - - /** - * extensions - */ - public static final String GETQUOTA = "GETQUOTA"; - public static final String GETQUOTAROOT = "GETQUOTAROOT"; - public static final String QUOTAROOT = "QUOTAROOT"; - public static final String QUOTA = "QUOTA"; - - /** - * capabilities - */ - public static final String CAPABILITY_AUTH_DIGEST_MD5 = "AUTH=DIGEST-MD5"; - public static final String CAPABILITY_STARTTLS = "STARTTLS"; - - /** - * authentication - */ - public static final String AUTH_DIGEST_MD5 = "DIGEST-MD5"; -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapElement.java b/java/com/android/voicemailomtp/mail/store/imap/ImapElement.java deleted file mode 100644 index 9f272e31c..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapElement.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -/** - * Class representing "element"s in IMAP responses. - * - * <p>Class hierarchy: - * <pre> - * ImapElement - * | - * |-- ImapElement.NONE (for 'index out of range') - * | - * |-- ImapList (isList() == true) - * | | - * | |-- ImapList.EMPTY - * | | - * | --- ImapResponse - * | - * --- ImapString (isString() == true) - * | - * |-- ImapString.EMPTY - * | - * |-- ImapSimpleString - * | - * |-- ImapMemoryLiteral - * | - * --- ImapTempFileLiteral - * </pre> - */ -public abstract class ImapElement { - /** - * An element that is returned by {@link ImapList#getElementOrNone} to indicate an index - * is out of range. - */ - public static final ImapElement NONE = new ImapElement() { - @Override public void destroy() { - // Don't call super.destroy(). - // It's a shared object. We don't want the mDestroyed to be set on this. - } - - @Override public boolean isList() { - return false; - } - - @Override public boolean isString() { - return false; - } - - @Override public String toString() { - return "[NO ELEMENT]"; - } - - @Override - public boolean equalsForTest(ImapElement that) { - return super.equalsForTest(that); - } - }; - - private boolean mDestroyed = false; - - public abstract boolean isList(); - - public abstract boolean isString(); - - protected boolean isDestroyed() { - return mDestroyed; - } - - /** - * Clean up the resources used by the instance. - * It's for removing a temp file used by {@link ImapTempFileLiteral}. - */ - public void destroy() { - mDestroyed = true; - } - - /** - * Throws {@link RuntimeException} if it's already destroyed. - */ - protected final void checkNotDestroyed() { - if (mDestroyed) { - throw new RuntimeException("Already destroyed"); - } - } - - /** - * Return a string that represents this object; it's purely for the debug purpose. Don't - * mistake it for {@link ImapString#getString}. - * - * Abstract to force subclasses to implement it. - */ - @Override - public abstract String toString(); - - /** - * The equals implementation that is intended to be used only for unit testing. - * (Because it may be heavy and has a special sense of "equal" for testing.) - */ - public boolean equalsForTest(ImapElement that) { - if (that == null) { - return false; - } - return this.getClass() == that.getClass(); // Has to be the same class. - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapList.java b/java/com/android/voicemailomtp/mail/store/imap/ImapList.java deleted file mode 100644 index 970423cbd..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapList.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import java.util.ArrayList; - -/** - * Class represents an IMAP list. - */ -public class ImapList extends ImapElement { - /** - * {@link ImapList} representing an empty list. - */ - public static final ImapList EMPTY = new ImapList() { - @Override public void destroy() { - // Don't call super.destroy(). - // It's a shared object. We don't want the mDestroyed to be set on this. - } - - @Override void add(ImapElement e) { - throw new RuntimeException(); - } - }; - - private ArrayList<ImapElement> mList = new ArrayList<ImapElement>(); - - /* package */ void add(ImapElement e) { - if (e == null) { - throw new RuntimeException("Can't add null"); - } - mList.add(e); - } - - @Override - public final boolean isString() { - return false; - } - - @Override - public final boolean isList() { - return true; - } - - public final int size() { - return mList.size(); - } - - public final boolean isEmpty() { - return size() == 0; - } - - /** - * Return true if the element at {@code index} exists, is string, and equals to {@code s}. - * (case insensitive) - */ - public final boolean is(int index, String s) { - return is(index, s, false); - } - - /** - * Same as {@link #is(int, String)}, but does the prefix match if {@code prefixMatch}. - */ - public final boolean is(int index, String s, boolean prefixMatch) { - if (!prefixMatch) { - return getStringOrEmpty(index).is(s); - } else { - return getStringOrEmpty(index).startsWith(s); - } - } - - /** - * Return the element at {@code index}. - * If {@code index} is out of range, returns {@link ImapElement#NONE}. - */ - public final ImapElement getElementOrNone(int index) { - return (index >= mList.size()) ? ImapElement.NONE : mList.get(index); - } - - /** - * Return the element at {@code index} if it's a list. - * If {@code index} is out of range or not a list, returns {@link ImapList#EMPTY}. - */ - public final ImapList getListOrEmpty(int index) { - ImapElement el = getElementOrNone(index); - return el.isList() ? (ImapList) el : EMPTY; - } - - /** - * Return the element at {@code index} if it's a string. - * If {@code index} is out of range or not a string, returns {@link ImapString#EMPTY}. - */ - public final ImapString getStringOrEmpty(int index) { - ImapElement el = getElementOrNone(index); - return el.isString() ? (ImapString) el : ImapString.EMPTY; - } - - /** - * Return an element keyed by {@code key}. Return null if not found. {@code key} has to be - * at an even index. - */ - /* package */ final ImapElement getKeyedElementOrNull(String key, boolean prefixMatch) { - for (int i = 1; i < size(); i += 2) { - if (is(i-1, key, prefixMatch)) { - return mList.get(i); - } - } - return null; - } - - /** - * Return an {@link ImapList} keyed by {@code key}. - * Return {@link ImapList#EMPTY} if not found. - */ - public final ImapList getKeyedListOrEmpty(String key) { - return getKeyedListOrEmpty(key, false); - } - - /** - * Return an {@link ImapList} keyed by {@code key}. - * Return {@link ImapList#EMPTY} if not found. - */ - public final ImapList getKeyedListOrEmpty(String key, boolean prefixMatch) { - ImapElement e = getKeyedElementOrNull(key, prefixMatch); - return (e != null) ? ((ImapList) e) : ImapList.EMPTY; - } - - /** - * Return an {@link ImapString} keyed by {@code key}. - * Return {@link ImapString#EMPTY} if not found. - */ - public final ImapString getKeyedStringOrEmpty(String key) { - return getKeyedStringOrEmpty(key, false); - } - - /** - * Return an {@link ImapString} keyed by {@code key}. - * Return {@link ImapString#EMPTY} if not found. - */ - public final ImapString getKeyedStringOrEmpty(String key, boolean prefixMatch) { - ImapElement e = getKeyedElementOrNull(key, prefixMatch); - return (e != null) ? ((ImapString) e) : ImapString.EMPTY; - } - - /** - * Return true if it contains {@code s}. - */ - public final boolean contains(String s) { - for (int i = 0; i < size(); i++) { - if (getStringOrEmpty(i).is(s)) { - return true; - } - } - return false; - } - - @Override - public void destroy() { - if (mList != null) { - for (ImapElement e : mList) { - e.destroy(); - } - mList = null; - } - super.destroy(); - } - - @Override - public String toString() { - return mList.toString(); - } - - /** - * Return the text representations of the contents concatenated with ",". - */ - public final String flatten() { - return flatten(new StringBuilder()).toString(); - } - - /** - * Returns text representations (i.e. getString()) of contents joined together with - * "," as the separator. - * - * Only used for building the capability string passed to vendor policies. - * - * We can't use toString(), because it's for debugging (meaning the format may change any time), - * and it won't expand literals. - */ - private final StringBuilder flatten(StringBuilder sb) { - sb.append('['); - for (int i = 0; i < mList.size(); i++) { - if (i > 0) { - sb.append(','); - } - final ImapElement e = getElementOrNone(i); - if (e.isList()) { - getListOrEmpty(i).flatten(sb); - } else if (e.isString()) { - sb.append(getStringOrEmpty(i).getString()); - } - } - sb.append(']'); - return sb; - } - - @Override - public boolean equalsForTest(ImapElement that) { - if (!super.equalsForTest(that)) { - return false; - } - ImapList thatList = (ImapList) that; - if (size() != thatList.size()) { - return false; - } - for (int i = 0; i < size(); i++) { - if (!mList.get(i).equalsForTest(thatList.getElementOrNone(i))) { - return false; - } - } - return true; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapMemoryLiteral.java b/java/com/android/voicemailomtp/mail/store/imap/ImapMemoryLiteral.java deleted file mode 100644 index ad60ca7a4..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapMemoryLiteral.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.mail.FixedLengthInputStream; -import com.android.voicemailomtp.VvmLog; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; - -/** - * Subclass of {@link ImapString} used for literals backed by an in-memory byte array. - */ -public class ImapMemoryLiteral extends ImapString { - private final String TAG = "ImapMemoryLiteral"; - private byte[] mData; - - /* package */ ImapMemoryLiteral(FixedLengthInputStream in) throws IOException { - // We could use ByteArrayOutputStream and IOUtils.copy, but it'd perform an unnecessary - // copy.... - mData = new byte[in.getLength()]; - int pos = 0; - while (pos < mData.length) { - int read = in.read(mData, pos, mData.length - pos); - if (read < 0) { - break; - } - pos += read; - } - if (pos != mData.length) { - VvmLog.w(TAG, "length mismatch"); - } - } - - @Override - public void destroy() { - mData = null; - super.destroy(); - } - - @Override - public String getString() { - try { - return new String(mData, "US-ASCII"); - } catch (UnsupportedEncodingException e) { - VvmLog.e(TAG, "Unsupported encoding: ", e); - } - return null; - } - - @Override - public InputStream getAsStream() { - return new ByteArrayInputStream(mData); - } - - @Override - public String toString() { - return String.format("{%d byte literal(memory)}", mData.length); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapResponse.java b/java/com/android/voicemailomtp/mail/store/imap/ImapResponse.java deleted file mode 100644 index 412f16d8a..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapResponse.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -/** - * Class represents an IMAP response. - */ -public class ImapResponse extends ImapList { - private final String mTag; - private final boolean mIsContinuationRequest; - - /* package */ ImapResponse(String tag, boolean isContinuationRequest) { - mTag = tag; - mIsContinuationRequest = isContinuationRequest; - } - - /* package */ static boolean isStatusResponse(String symbol) { - return ImapConstants.OK.equalsIgnoreCase(symbol) - || ImapConstants.NO.equalsIgnoreCase(symbol) - || ImapConstants.BAD.equalsIgnoreCase(symbol) - || ImapConstants.PREAUTH.equalsIgnoreCase(symbol) - || ImapConstants.BYE.equalsIgnoreCase(symbol); - } - - /** - * @return whether it's a tagged response. - */ - public boolean isTagged() { - return mTag != null; - } - - /** - * @return whether it's a continuation request. - */ - public boolean isContinuationRequest() { - return mIsContinuationRequest; - } - - public boolean isStatusResponse() { - return isStatusResponse(getStringOrEmpty(0).getString()); - } - - /** - * @return whether it's an OK response. - */ - public boolean isOk() { - return is(0, ImapConstants.OK); - } - - /** - * @return whether it's an BAD response. - */ - public boolean isBad() { - return is(0, ImapConstants.BAD); - } - - /** - * @return whether it's an NO response. - */ - public boolean isNo() { - return is(0, ImapConstants.NO); - } - - /** - * @return whether it's an {@code responseType} data response. (i.e. not tagged). - * @param index where {@code responseType} should appear. e.g. 1 for "FETCH" - * @param responseType e.g. "FETCH" - */ - public final boolean isDataResponse(int index, String responseType) { - return !isTagged() && getStringOrEmpty(index).is(responseType); - } - - /** - * @return Response code (RFC 3501 7.1) if it's a status response. - * - * e.g. "ALERT" for "* OK [ALERT] System shutdown in 10 minutes" - */ - public ImapString getResponseCodeOrEmpty() { - if (!isStatusResponse()) { - return ImapString.EMPTY; // Not a status response. - } - return getListOrEmpty(1).getStringOrEmpty(0); - } - - /** - * @return Alert message it it has ALERT response code. - * - * e.g. "System shutdown in 10 minutes" for "* OK [ALERT] System shutdown in 10 minutes" - */ - public ImapString getAlertTextOrEmpty() { - if (!getResponseCodeOrEmpty().is(ImapConstants.ALERT)) { - return ImapString.EMPTY; // Not an ALERT - } - // The 3rd element contains all the rest of line. - return getStringOrEmpty(2); - } - - /** - * @return Response text in a status response. - */ - public ImapString getStatusResponseTextOrEmpty() { - if (!isStatusResponse()) { - return ImapString.EMPTY; - } - return getStringOrEmpty(getElementOrNone(1).isList() ? 2 : 1); - } - - public ImapString getStatusOrEmpty() { - if (!isStatusResponse()) { - return ImapString.EMPTY; - } - return getStringOrEmpty(0); - } - - @Override - public String toString() { - String tag = mTag; - if (isContinuationRequest()) { - tag = "+"; - } - return "#" + tag + "# " + super.toString(); - } - - @Override - public boolean equalsForTest(ImapElement that) { - if (!super.equalsForTest(that)) { - return false; - } - final ImapResponse thatResponse = (ImapResponse) that; - if (mTag == null) { - if (thatResponse.mTag != null) { - return false; - } - } else { - if (!mTag.equals(thatResponse.mTag)) { - return false; - } - } - if (mIsContinuationRequest != thatResponse.mIsContinuationRequest) { - return false; - } - return true; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapResponseParser.java b/java/com/android/voicemailomtp/mail/store/imap/ImapResponseParser.java deleted file mode 100644 index 692596f14..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapResponseParser.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import android.text.TextUtils; -import android.util.Log; - -import com.android.voicemailomtp.mail.FixedLengthInputStream; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.mail.PeekableInputStream; -import com.android.voicemailomtp.VvmLog; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; - -/** - * IMAP response parser. - */ -public class ImapResponseParser { - private static final String TAG = "ImapResponseParser"; - - /** - * Literal larger than this will be stored in temp file. - */ - public static final int LITERAL_KEEP_IN_MEMORY_THRESHOLD = 2 * 1024 * 1024; - - /** Input stream */ - private final PeekableInputStream mIn; - - private final int mLiteralKeepInMemoryThreshold; - - /** StringBuilder used by readUntil() */ - private final StringBuilder mBufferReadUntil = new StringBuilder(); - - /** StringBuilder used by parseBareString() */ - private final StringBuilder mParseBareString = new StringBuilder(); - - /** - * We store all {@link ImapResponse} in it. {@link #destroyResponses()} must be called from - * time to time to destroy them and clear it. - */ - private final ArrayList<ImapResponse> mResponsesToDestroy = new ArrayList<ImapResponse>(); - - /** - * Exception thrown when we receive BYE. It derives from IOException, so it'll be treated - * in the same way EOF does. - */ - public static class ByeException extends IOException { - public static final String MESSAGE = "Received BYE"; - public ByeException() { - super(MESSAGE); - } - } - - /** - * Public constructor for normal use. - */ - public ImapResponseParser(InputStream in) { - this(in, LITERAL_KEEP_IN_MEMORY_THRESHOLD); - } - - /** - * Constructor for testing to override the literal size threshold. - */ - /* package for test */ ImapResponseParser(InputStream in, int literalKeepInMemoryThreshold) { - mIn = new PeekableInputStream(in); - mLiteralKeepInMemoryThreshold = literalKeepInMemoryThreshold; - } - - private static IOException newEOSException() { - final String message = "End of stream reached"; - VvmLog.d(TAG, message); - return new IOException(message); - } - - /** - * Peek next one byte. - * - * Throws IOException() if reaches EOF. As long as logical response lines end with \r\n, - * we shouldn't see EOF during parsing. - */ - private int peek() throws IOException { - final int next = mIn.peek(); - if (next == -1) { - throw newEOSException(); - } - return next; - } - - /** - * Read and return one byte from {@link #mIn}, and put it in {@link #mDiscourseLogger}. - * - * Throws IOException() if reaches EOF. As long as logical response lines end with \r\n, - * we shouldn't see EOF during parsing. - */ - private int readByte() throws IOException { - int next = mIn.read(); - if (next == -1) { - throw newEOSException(); - } - return next; - } - - /** - * Destroy all the {@link ImapResponse}s stored in the internal storage and clear it. - * - * @see #readResponse() - */ - public void destroyResponses() { - for (ImapResponse r : mResponsesToDestroy) { - r.destroy(); - } - mResponsesToDestroy.clear(); - } - - /** - * Reads the next response available on the stream and returns an - * {@link ImapResponse} object that represents it. - * - * <p>When this method successfully returns an {@link ImapResponse}, the {@link ImapResponse} - * is stored in the internal storage. When the {@link ImapResponse} is no longer used - * {@link #destroyResponses} should be called to destroy all the responses in the array. - * - * @param byeExpected is a untagged BYE response expected? If not proper cleanup will be done - * and {@link ByeException} will be thrown. - * @return the parsed {@link ImapResponse} object. - * @exception ByeException when detects BYE and <code>byeExpected</code> is false. - */ - public ImapResponse readResponse(boolean byeExpected) throws IOException, MessagingException { - ImapResponse response = null; - try { - response = parseResponse(); - } catch (RuntimeException e) { - // Parser crash -- log network activities. - onParseError(e); - throw e; - } catch (IOException e) { - // Network error, or received an unexpected char. - onParseError(e); - throw e; - } - - // Handle this outside of try-catch. We don't have to dump protocol log when getting BYE. - if (!byeExpected && response.is(0, ImapConstants.BYE)) { - Log.w(TAG, ByeException.MESSAGE); - response.destroy(); - throw new ByeException(); - } - mResponsesToDestroy.add(response); - return response; - } - - private void onParseError(Exception e) { - // Read a few more bytes, so that the log will contain some more context, even if the parser - // crashes in the middle of a response. - // This also makes sure the byte in question will be logged, no matter where it crashes. - // e.g. when parseAtom() peeks and finds at an unexpected char, it throws an exception - // before actually reading it. - // However, we don't want to read too much, because then it may get into an email message. - try { - for (int i = 0; i < 4; i++) { - int b = readByte(); - if (b == -1 || b == '\n') { - break; - } - } - } catch (IOException ignore) { - } - VvmLog.w(TAG, "Exception detected: " + e.getMessage()); - } - - /** - * Read next byte from stream and throw it away. If the byte is different from {@code expected} - * throw {@link MessagingException}. - */ - /* package for test */ void expect(char expected) throws IOException { - final int next = readByte(); - if (expected != next) { - throw new IOException(String.format("Expected %04x (%c) but got %04x (%c)", - (int) expected, expected, next, (char) next)); - } - } - - /** - * Read bytes until we find {@code end}, and return all as string. - * The {@code end} will be read (rather than peeked) and won't be included in the result. - */ - /* package for test */ String readUntil(char end) throws IOException { - mBufferReadUntil.setLength(0); - for (;;) { - final int ch = readByte(); - if (ch != end) { - mBufferReadUntil.append((char) ch); - } else { - return mBufferReadUntil.toString(); - } - } - } - - /** - * Read all bytes until \r\n. - */ - /* package */ String readUntilEol() throws IOException { - String ret = readUntil('\r'); - expect('\n'); // TODO Should this really be error? - return ret; - } - - /** - * Parse and return the response line. - */ - private ImapResponse parseResponse() throws IOException, MessagingException { - // We need to destroy the response if we get an exception. - // So, we first store the response that's being built in responseToDestroy, until it's - // completely built, at which point we copy it into responseToReturn and null out - // responseToDestroyt. - // If responseToDestroy is not null in finally, we destroy it because that means - // we got an exception somewhere. - ImapResponse responseToDestroy = null; - final ImapResponse responseToReturn; - - try { - final int ch = peek(); - if (ch == '+') { // Continuation request - readByte(); // skip + - expect(' '); - responseToDestroy = new ImapResponse(null, true); - - // If it's continuation request, we don't really care what's in it. - responseToDestroy.add(new ImapSimpleString(readUntilEol())); - - // Response has successfully been built. Let's return it. - responseToReturn = responseToDestroy; - responseToDestroy = null; - } else { - // Status response or response data - final String tag; - if (ch == '*') { - tag = null; - readByte(); // skip * - expect(' '); - } else { - tag = readUntil(' '); - } - responseToDestroy = new ImapResponse(tag, false); - - final ImapString firstString = parseBareString(); - responseToDestroy.add(firstString); - - // parseBareString won't eat a space after the string, so we need to skip it, - // if exists. - // If the next char is not ' ', it should be EOL. - if (peek() == ' ') { - readByte(); // skip ' ' - - if (responseToDestroy.isStatusResponse()) { // It's a status response - - // Is there a response code? - final int next = peek(); - if (next == '[') { - responseToDestroy.add(parseList('[', ']')); - if (peek() == ' ') { // Skip following space - readByte(); - } - } - - String rest = readUntilEol(); - if (!TextUtils.isEmpty(rest)) { - // The rest is free-form text. - responseToDestroy.add(new ImapSimpleString(rest)); - } - } else { // It's a response data. - parseElements(responseToDestroy, '\0'); - } - } else { - expect('\r'); - expect('\n'); - } - - // Response has successfully been built. Let's return it. - responseToReturn = responseToDestroy; - responseToDestroy = null; - } - } finally { - if (responseToDestroy != null) { - // We get an exception. - responseToDestroy.destroy(); - } - } - - return responseToReturn; - } - - private ImapElement parseElement() throws IOException, MessagingException { - final int next = peek(); - switch (next) { - case '(': - return parseList('(', ')'); - case '[': - return parseList('[', ']'); - case '"': - readByte(); // Skip " - return new ImapSimpleString(readUntil('"')); - case '{': - return parseLiteral(); - case '\r': // CR - readByte(); // Consume \r - expect('\n'); // Should be followed by LF. - return null; - case '\n': // LF // There shouldn't be a bare LF, but just in case. - readByte(); // Consume \n - return null; - default: - return parseBareString(); - } - } - - /** - * Parses an atom. - * - * Special case: If an atom contains '[', everything until the next ']' will be considered - * a part of the atom. - * (e.g. "BODY[HEADER.FIELDS ("DATE" ...)]" will become a single ImapString) - * - * If the value is "NIL", returns an empty string. - */ - private ImapString parseBareString() throws IOException, MessagingException { - mParseBareString.setLength(0); - for (;;) { - final int ch = peek(); - - // TODO Can we clean this up? (This condition is from the old parser.) - if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' || - // ']' is not part of atom (it's in resp-specials) - ch == ']' || - // docs claim that flags are \ atom but atom isn't supposed to - // contain - // * and some flags contain * - // ch == '%' || ch == '*' || - ch == '%' || - // TODO probably should not allow \ and should recognize - // it as a flag instead - // ch == '"' || ch == '\' || - ch == '"' || (0x00 <= ch && ch <= 0x1f) || ch == 0x7f) { - if (mParseBareString.length() == 0) { - throw new MessagingException("Expected string, none found."); - } - String s = mParseBareString.toString(); - - // NIL will be always converted into the empty string. - if (ImapConstants.NIL.equalsIgnoreCase(s)) { - return ImapString.EMPTY; - } - return new ImapSimpleString(s); - } else if (ch == '[') { - // Eat all until next ']' - mParseBareString.append((char) readByte()); - mParseBareString.append(readUntil(']')); - mParseBareString.append(']'); // readUntil won't include the end char. - } else { - mParseBareString.append((char) readByte()); - } - } - } - - private void parseElements(ImapList list, char end) - throws IOException, MessagingException { - for (;;) { - for (;;) { - final int next = peek(); - if (next == end) { - return; - } - if (next != ' ') { - break; - } - // Skip space - readByte(); - } - final ImapElement el = parseElement(); - if (el == null) { // EOL - return; - } - list.add(el); - } - } - - private ImapList parseList(char opening, char closing) - throws IOException, MessagingException { - expect(opening); - final ImapList list = new ImapList(); - parseElements(list, closing); - expect(closing); - return list; - } - - private ImapString parseLiteral() throws IOException, MessagingException { - expect('{'); - final int size; - try { - size = Integer.parseInt(readUntil('}')); - } catch (NumberFormatException nfe) { - throw new MessagingException("Invalid length in literal"); - } - if (size < 0) { - throw new MessagingException("Invalid negative length in literal"); - } - expect('\r'); - expect('\n'); - FixedLengthInputStream in = new FixedLengthInputStream(mIn, size); - if (size > mLiteralKeepInMemoryThreshold) { - return new ImapTempFileLiteral(in); - } else { - return new ImapMemoryLiteral(in); - } - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapSimpleString.java b/java/com/android/voicemailomtp/mail/store/imap/ImapSimpleString.java deleted file mode 100644 index 22d8141a0..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapSimpleString.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.VvmLog; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; - -/** - * Subclass of {@link ImapString} used for non literals. - */ -public class ImapSimpleString extends ImapString { - private final String TAG = "ImapSimpleString"; - private String mString; - - /* package */ ImapSimpleString(String string) { - mString = (string != null) ? string : ""; - } - - @Override - public void destroy() { - mString = null; - super.destroy(); - } - - @Override - public String getString() { - return mString; - } - - @Override - public InputStream getAsStream() { - try { - return new ByteArrayInputStream(mString.getBytes("US-ASCII")); - } catch (UnsupportedEncodingException e) { - VvmLog.e(TAG, "Unsupported encoding: ", e); - } - return null; - } - - @Override - public String toString() { - // Purposefully not return just mString, in order to prevent using it instead of getString. - return "\"" + mString + "\""; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapString.java b/java/com/android/voicemailomtp/mail/store/imap/ImapString.java deleted file mode 100644 index 83efb6479..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapString.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.VvmLog; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Class represents an IMAP "element" that is not a list. - * - * An atom, quoted string, literal, are all represented by this. Values like OK, STATUS are too. - * Also, this class class may contain more arbitrary value like "BODY[HEADER.FIELDS ("DATE")]". - * See {@link ImapResponseParser}. - */ -public abstract class ImapString extends ImapElement { - private static final byte[] EMPTY_BYTES = new byte[0]; - - public static final ImapString EMPTY = new ImapString() { - @Override public void destroy() { - // Don't call super.destroy(). - // It's a shared object. We don't want the mDestroyed to be set on this. - } - - @Override public String getString() { - return ""; - } - - @Override public InputStream getAsStream() { - return new ByteArrayInputStream(EMPTY_BYTES); - } - - @Override public String toString() { - return ""; - } - }; - - // This is used only for parsing IMAP's FETCH ENVELOPE command, in which - // en_US-like date format is used like "01-Jan-2009 11:20:39 -0800", so this should be - // handled by Locale.US - private final static SimpleDateFormat DATE_TIME_FORMAT = - new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US); - - private boolean mIsInteger; - private int mParsedInteger; - private Date mParsedDate; - - @Override - public final boolean isList() { - return false; - } - - @Override - public final boolean isString() { - return true; - } - - /** - * @return true if and only if the length of the string is larger than 0. - * - * Note: IMAP NIL is considered an empty string. See {@link ImapResponseParser - * #parseBareString}. - * On the other hand, a quoted/literal string with value NIL (i.e. "NIL" and {3}\r\nNIL) is - * treated literally. - */ - public final boolean isEmpty() { - return getString().length() == 0; - } - - public abstract String getString(); - - public abstract InputStream getAsStream(); - - /** - * @return whether it can be parsed as a number. - */ - public final boolean isNumber() { - if (mIsInteger) { - return true; - } - try { - mParsedInteger = Integer.parseInt(getString()); - mIsInteger = true; - return true; - } catch (NumberFormatException e) { - return false; - } - } - - /** - * @return value parsed as a number, or 0 if the string is not a number. - */ - public final int getNumberOrZero() { - return getNumber(0); - } - - /** - * @return value parsed as a number, or {@code defaultValue} if the string is not a number. - */ - public final int getNumber(int defaultValue) { - if (!isNumber()) { - return defaultValue; - } - return mParsedInteger; - } - - /** - * @return whether it can be parsed as a date using {@link #DATE_TIME_FORMAT}. - */ - public final boolean isDate() { - if (mParsedDate != null) { - return true; - } - if (isEmpty()) { - return false; - } - try { - mParsedDate = DATE_TIME_FORMAT.parse(getString()); - return true; - } catch (ParseException e) { - VvmLog.w("ImapString", getString() + " can't be parsed as a date."); - return false; - } - } - - /** - * @return value it can be parsed as a {@link Date}, or null otherwise. - */ - public final Date getDateOrNull() { - if (!isDate()) { - return null; - } - return mParsedDate; - } - - /** - * @return whether the value case-insensitively equals to {@code s}. - */ - public final boolean is(String s) { - if (s == null) { - return false; - } - return getString().equalsIgnoreCase(s); - } - - - /** - * @return whether the value case-insensitively starts with {@code s}. - */ - public final boolean startsWith(String prefix) { - if (prefix == null) { - return false; - } - final String me = this.getString(); - if (me.length() < prefix.length()) { - return false; - } - return me.substring(0, prefix.length()).equalsIgnoreCase(prefix); - } - - // To force subclasses to implement it. - @Override - public abstract String toString(); - - @Override - public final boolean equalsForTest(ImapElement that) { - if (!super.equalsForTest(that)) { - return false; - } - ImapString thatString = (ImapString) that; - return getString().equals(thatString.getString()); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapTempFileLiteral.java b/java/com/android/voicemailomtp/mail/store/imap/ImapTempFileLiteral.java deleted file mode 100644 index efe5c3848..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapTempFileLiteral.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.mail.FixedLengthInputStream; -import com.android.voicemailomtp.mail.TempDirectory; -import com.android.voicemailomtp.mail.utils.Utility; -import com.android.voicemailomtp.mail.utils.LogUtils; - -import org.apache.commons.io.IOUtils; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Subclass of {@link ImapString} used for literals backed by a temp file. - */ -public class ImapTempFileLiteral extends ImapString { - private final String TAG = "ImapTempFileLiteral"; - - /* package for test */ final File mFile; - - /** Size is purely for toString() */ - private final int mSize; - - /* package */ ImapTempFileLiteral(FixedLengthInputStream stream) throws IOException { - mSize = stream.getLength(); - mFile = File.createTempFile("imap", ".tmp", TempDirectory.getTempDirectory()); - - // Unfortunately, we can't really use deleteOnExit(), because temp filenames are random - // so it'd simply cause a memory leak. - // deleteOnExit() simply adds filenames to a static list and the list will never shrink. - // mFile.deleteOnExit(); - OutputStream out = new FileOutputStream(mFile); - IOUtils.copy(stream, out); - out.close(); - } - - /** - * Make sure we delete the temp file. - * - * We should always be calling {@link ImapResponse#destroy()}, but it's here as a last resort. - */ - @Override - protected void finalize() throws Throwable { - try { - destroy(); - } finally { - super.finalize(); - } - } - - @Override - public InputStream getAsStream() { - checkNotDestroyed(); - try { - return new FileInputStream(mFile); - } catch (FileNotFoundException e) { - // It's probably possible if we're low on storage and the system clears the cache dir. - LogUtils.w(TAG, "ImapTempFileLiteral: Temp file not found"); - - // Return 0 byte stream as a dummy... - return new ByteArrayInputStream(new byte[0]); - } - } - - @Override - public String getString() { - checkNotDestroyed(); - try { - byte[] bytes = IOUtils.toByteArray(getAsStream()); - // Prevent crash from OOM; we've seen this, but only rarely and not reproducibly - if (bytes.length > ImapResponseParser.LITERAL_KEEP_IN_MEMORY_THRESHOLD) { - throw new IOException(); - } - return Utility.fromAscii(bytes); - } catch (IOException e) { - LogUtils.w(TAG, "ImapTempFileLiteral: Error while reading temp file", e); - return ""; - } - } - - @Override - public void destroy() { - try { - if (!isDestroyed() && mFile.exists()) { - mFile.delete(); - } - } catch (RuntimeException re) { - // Just log and ignore. - LogUtils.w(TAG, "Failed to remove temp file: " + re.getMessage()); - } - super.destroy(); - } - - @Override - public String toString() { - return String.format("{%d byte literal(file)}", mSize); - } - - public boolean tempFileExistsForTest() { - return mFile.exists(); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/store/imap/ImapUtility.java b/java/com/android/voicemailomtp/mail/store/imap/ImapUtility.java deleted file mode 100644 index b045eb32f..000000000 --- a/java/com/android/voicemailomtp/mail/store/imap/ImapUtility.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.store.imap; - -import com.android.voicemailomtp.mail.utils.LogUtils; - -import java.util.ArrayList; - -/** - * Utility methods for use with IMAP. - */ -public class ImapUtility { - public static final String TAG = "ImapUtility"; - /** - * Apply quoting rules per IMAP RFC, - * quoted = DQUOTE *QUOTED-CHAR DQUOTE - * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials - * quoted-specials = DQUOTE / "\" - * - * This is used primarily for IMAP login, but might be useful elsewhere. - * - * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check - * for trouble chars before calling the replace functions. - * - * @param s The string to be quoted. - * @return A copy of the string, having undergone quoting as described above - */ - public static String imapQuoted(String s) { - - // First, quote any backslashes by replacing \ with \\ - // regex Pattern: \\ (Java string const = \\\\) - // Substitute: \\\\ (Java string const = \\\\\\\\) - String result = s.replaceAll("\\\\", "\\\\\\\\"); - - // Then, quote any double-quotes by replacing " with \" - // regex Pattern: " (Java string const = \") - // Substitute: \\" (Java string const = \\\\\") - result = result.replaceAll("\"", "\\\\\""); - - // return string with quotes around it - return "\"" + result + "\""; - } - - /** - * Gets all of the values in a sequence set per RFC 3501. Any ranges are expanded into a - * list of individual numbers. If the set is invalid, an empty array is returned. - * <pre> - * sequence-number = nz-number / "*" - * sequence-range = sequence-number ":" sequence-number - * sequence-set = (sequence-number / sequence-range) *("," sequence-set) - * </pre> - */ - public static String[] getImapSequenceValues(String set) { - ArrayList<String> list = new ArrayList<String>(); - if (set != null) { - String[] setItems = set.split(","); - for (String item : setItems) { - if (item.indexOf(':') == -1) { - // simple item - try { - Integer.parseInt(item); // Don't need the value; just ensure it's valid - list.add(item); - } catch (NumberFormatException e) { - LogUtils.d(TAG, "Invalid UID value", e); - } - } else { - // range - for (String rangeItem : getImapRangeValues(item)) { - list.add(rangeItem); - } - } - } - } - String[] stringList = new String[list.size()]; - return list.toArray(stringList); - } - - /** - * Expand the given number range into a list of individual numbers. If the range is not valid, - * an empty array is returned. - * <pre> - * sequence-number = nz-number / "*" - * sequence-range = sequence-number ":" sequence-number - * sequence-set = (sequence-number / sequence-range) *("," sequence-set) - * </pre> - */ - public static String[] getImapRangeValues(String range) { - ArrayList<String> list = new ArrayList<String>(); - try { - if (range != null) { - int colonPos = range.indexOf(':'); - if (colonPos > 0) { - int first = Integer.parseInt(range.substring(0, colonPos)); - int second = Integer.parseInt(range.substring(colonPos + 1)); - if (first < second) { - for (int i = first; i <= second; i++) { - list.add(Integer.toString(i)); - } - } else { - for (int i = first; i >= second; i--) { - list.add(Integer.toString(i)); - } - } - } - } - } catch (NumberFormatException e) { - LogUtils.d(TAG, "Invalid range value", e); - } - String[] stringList = new String[list.size()]; - return list.toArray(stringList); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/utility/CountingOutputStream.java b/java/com/android/voicemailomtp/mail/utility/CountingOutputStream.java deleted file mode 100644 index fdf81d44a..000000000 --- a/java/com/android/voicemailomtp/mail/utility/CountingOutputStream.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.utility; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * A simple pass-thru OutputStream that also counts how many bytes are written to it and - * makes that count available to callers. - */ -public class CountingOutputStream extends OutputStream { - private long mCount; - private final OutputStream mOutputStream; - - public CountingOutputStream(OutputStream outputStream) { - mOutputStream = outputStream; - } - - public long getCount() { - return mCount; - } - - @Override - public void write(byte[] buffer, int offset, int count) throws IOException { - mOutputStream.write(buffer, offset, count); - mCount += count; - } - - @Override - public void write(int oneByte) throws IOException { - mOutputStream.write(oneByte); - mCount++; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/utility/EOLConvertingOutputStream.java b/java/com/android/voicemailomtp/mail/utility/EOLConvertingOutputStream.java deleted file mode 100644 index 5b93a92ab..000000000 --- a/java/com/android/voicemailomtp/mail/utility/EOLConvertingOutputStream.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.utility; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -public class EOLConvertingOutputStream extends FilterOutputStream { - int lastChar; - - public EOLConvertingOutputStream(OutputStream out) { - super(out); - } - - @Override - public void write(int oneByte) throws IOException { - if (oneByte == '\n') { - if (lastChar != '\r') { - super.write('\r'); - } - } - super.write(oneByte); - lastChar = oneByte; - } - - @Override - public void flush() throws IOException { - if (lastChar == '\r') { - super.write('\n'); - lastChar = '\n'; - } - super.flush(); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/mail/utils/LogUtils.java b/java/com/android/voicemailomtp/mail/utils/LogUtils.java deleted file mode 100644 index a213a835e..000000000 --- a/java/com/android/voicemailomtp/mail/utils/LogUtils.java +++ /dev/null @@ -1,413 +0,0 @@ -/** - * Copyright (c) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.utils; - -import android.net.Uri; -import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; -import android.util.Log; -import com.android.voicemailomtp.VvmLog; -import java.util.List; -import java.util.regex.Pattern; - -public class LogUtils { - public static final String TAG = "Email Log"; - - // "GMT" + "+" or "-" + 4 digits - private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE = - Pattern.compile("GMT([-+]\\d{4})$"); - - private static final String ACCOUNT_PREFIX = "account:"; - - /** - * Priority constant for the println method; use LogUtils.v. - */ - public static final int VERBOSE = Log.VERBOSE; - - /** - * Priority constant for the println method; use LogUtils.d. - */ - public static final int DEBUG = Log.DEBUG; - - /** - * Priority constant for the println method; use LogUtils.i. - */ - public static final int INFO = Log.INFO; - - /** - * Priority constant for the println method; use LogUtils.w. - */ - public static final int WARN = Log.WARN; - - /** - * Priority constant for the println method; use LogUtils.e. - */ - public static final int ERROR = Log.ERROR; - - /** - * Used to enable/disable logging that we don't want included in production releases. This should - * be set to DEBUG for production releases, and VERBOSE for internal builds. - */ - private static final int MAX_ENABLED_LOG_LEVEL = DEBUG; - - private static Boolean sDebugLoggingEnabledForTests = null; - - /** - * Enable debug logging for unit tests. - */ - @VisibleForTesting - public static void setDebugLoggingEnabledForTests(boolean enabled) { - setDebugLoggingEnabledForTestsInternal(enabled); - } - - protected static void setDebugLoggingEnabledForTestsInternal(boolean enabled) { - sDebugLoggingEnabledForTests = Boolean.valueOf(enabled); - } - - /** - * Returns true if the build configuration prevents debug logging. - */ - @VisibleForTesting - public static boolean buildPreventsDebugLogging() { - return MAX_ENABLED_LOG_LEVEL > VERBOSE; - } - - /** - * Returns a boolean indicating whether debug logging is enabled. - */ - protected static boolean isDebugLoggingEnabled(String tag) { - if (buildPreventsDebugLogging()) { - return false; - } - if (sDebugLoggingEnabledForTests != null) { - return sDebugLoggingEnabledForTests.booleanValue(); - } - return Log.isLoggable(tag, Log.DEBUG) || Log.isLoggable(TAG, Log.DEBUG); - } - - /** - * Returns a String for the specified content provider uri. This will do - * sanitation of the uri to remove PII if debug logging is not enabled. - */ - public static String contentUriToString(final Uri uri) { - return contentUriToString(TAG, uri); - } - - /** - * Returns a String for the specified content provider uri. This will do - * sanitation of the uri to remove PII if debug logging is not enabled. - */ - public static String contentUriToString(String tag, Uri uri) { - if (isDebugLoggingEnabled(tag)) { - // Debug logging has been enabled, so log the uri as is - return uri.toString(); - } else { - // Debug logging is not enabled, we want to remove the email address from the uri. - List<String> pathSegments = uri.getPathSegments(); - - Uri.Builder builder = new Uri.Builder() - .scheme(uri.getScheme()) - .authority(uri.getAuthority()) - .query(uri.getQuery()) - .fragment(uri.getFragment()); - - // This assumes that the first path segment is the account - final String account = pathSegments.get(0); - - builder = builder.appendPath(sanitizeAccountName(account)); - for (int i = 1; i < pathSegments.size(); i++) { - builder.appendPath(pathSegments.get(i)); - } - return builder.toString(); - } - } - - /** - * Sanitizes an account name. If debug logging is not enabled, a sanitized name - * is returned. - */ - public static String sanitizeAccountName(String accountName) { - if (TextUtils.isEmpty(accountName)) { - return ""; - } - - return ACCOUNT_PREFIX + sanitizeName(TAG, accountName); - } - - public static String sanitizeName(final String tag, final String name) { - if (TextUtils.isEmpty(name)) { - return ""; - } - - if (isDebugLoggingEnabled(tag)) { - return name; - } - - return String.valueOf(name.hashCode()); - } - - /** - * Checks to see whether or not a log for the specified tag is loggable at the specified level. - */ - public static boolean isLoggable(String tag, int level) { - if (MAX_ENABLED_LOG_LEVEL > level) { - return false; - } - return Log.isLoggable(tag, level) || Log.isLoggable(TAG, level); - } - - /** - * Send a {@link #VERBOSE} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int v(String tag, String format, Object... args) { - if (isLoggable(tag, VERBOSE)) { - return VvmLog.v(tag, String.format(format, args)); - } - return 0; - } - - /** - * Send a {@link #VERBOSE} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int v(String tag, Throwable tr, String format, Object... args) { - if (isLoggable(tag, VERBOSE)) { - return VvmLog.v(tag, String.format(format, args), tr); - } - return 0; - } - - /** - * Send a {@link #DEBUG} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int d(String tag, String format, Object... args) { - if (isLoggable(tag, DEBUG)) { - return VvmLog.d(tag, String.format(format, args)); - } - return 0; - } - - /** - * Send a {@link #DEBUG} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int d(String tag, Throwable tr, String format, Object... args) { - if (isLoggable(tag, DEBUG)) { - return VvmLog.d(tag, String.format(format, args), tr); - } - return 0; - } - - /** - * Send a {@link #INFO} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int i(String tag, String format, Object... args) { - if (isLoggable(tag, INFO)) { - return VvmLog.i(tag, String.format(format, args)); - } - return 0; - } - - /** - * Send a {@link #INFO} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int i(String tag, Throwable tr, String format, Object... args) { - if (isLoggable(tag, INFO)) { - return VvmLog.i(tag, String.format(format, args), tr); - } - return 0; - } - - /** - * Send a {@link #WARN} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int w(String tag, String format, Object... args) { - if (isLoggable(tag, WARN)) { - return VvmLog.w(tag, String.format(format, args)); - } - return 0; - } - - /** - * Send a {@link #WARN} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int w(String tag, Throwable tr, String format, Object... args) { - if (isLoggable(tag, WARN)) { - return VvmLog.w(tag, String.format(format, args), tr); - } - return 0; - } - - /** - * Send a {@link #ERROR} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int e(String tag, String format, Object... args) { - if (isLoggable(tag, ERROR)) { - return VvmLog.e(tag, String.format(format, args)); - } - return 0; - } - - /** - * Send a {@link #ERROR} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int e(String tag, Throwable tr, String format, Object... args) { - if (isLoggable(tag, ERROR)) { - return VvmLog.e(tag, String.format(format, args), tr); - } - return 0; - } - - /** - * What a Terrible Failure: Report a condition that should never happen. - * The error will always be logged at level ASSERT with the call stack. - * Depending on system configuration, a report may be added to the - * {@link android.os.DropBoxManager} and/or the process may be terminated - * immediately with an error dialog. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int wtf(String tag, String format, Object... args) { - return VvmLog.wtf(tag, String.format(format, args), new Error()); - } - - /** - * What a Terrible Failure: Report a condition that should never happen. - * The error will always be logged at level ASSERT with the call stack. - * Depending on system configuration, a report may be added to the - * {@link android.os.DropBoxManager} and/or the process may be terminated - * immediately with an error dialog. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - * @param format the format string (see {@link java.util.Formatter#format}) - * @param args - * the list of arguments passed to the formatter. If there are - * more arguments than required by {@code format}, - * additional arguments are ignored. - */ - public static int wtf(String tag, Throwable tr, String format, Object... args) { - return VvmLog.wtf(tag, String.format(format, args), tr); - } - - - /** - * Try to make a date MIME(RFC 2822/5322)-compliant. - * - * It fixes: - * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700" - * (4 digit zone value can't be preceded by "GMT") - * We got a report saying eBay sends a date in this format - */ - public static String cleanUpMimeDate(String date) { - if (TextUtils.isEmpty(date)) { - return date; - } - date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1"); - return date; - } - - - public static String byteToHex(int b) { - return byteToHex(new StringBuilder(), b).toString(); - } - - public static StringBuilder byteToHex(StringBuilder sb, int b) { - b &= 0xFF; - sb.append("0123456789ABCDEF".charAt(b >> 4)); - sb.append("0123456789ABCDEF".charAt(b & 0xF)); - return sb; - } - -} diff --git a/java/com/android/voicemailomtp/mail/utils/Utility.java b/java/com/android/voicemailomtp/mail/utils/Utility.java deleted file mode 100644 index c7286fa64..000000000 --- a/java/com/android/voicemailomtp/mail/utils/Utility.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.voicemailomtp.mail.utils; - -import java.io.ByteArrayInputStream; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; - -/** - * Simple utility methods used in email functions. - */ -public class Utility { - public static final Charset ASCII = Charset.forName("US-ASCII"); - - public static final String[] EMPTY_STRINGS = new String[0]; - - /** - * Returns a concatenated string containing the output of every Object's - * toString() method, each separated by the given separator character. - */ - public static String combine(Object[] parts, char separator) { - if (parts == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < parts.length; i++) { - sb.append(parts[i].toString()); - if (i < parts.length - 1) { - sb.append(separator); - } - } - return sb.toString(); - } - - /** Converts a String to ASCII bytes */ - public static byte[] toAscii(String s) { - return encode(ASCII, s); - } - - /** Builds a String from ASCII bytes */ - public static String fromAscii(byte[] b) { - return decode(ASCII, b); - } - - private static byte[] encode(Charset charset, String s) { - if (s == null) { - return null; - } - final ByteBuffer buffer = charset.encode(CharBuffer.wrap(s)); - final byte[] bytes = new byte[buffer.limit()]; - buffer.get(bytes); - return bytes; - } - - private static String decode(Charset charset, byte[] b) { - if (b == null) { - return null; - } - final CharBuffer cb = charset.decode(ByteBuffer.wrap(b)); - return new String(cb.array(), 0, cb.length()); - } - - public static ByteArrayInputStream streamFromAsciiString(String ascii) { - return new ByteArrayInputStream(toAscii(ascii)); - } -} diff --git a/java/com/android/voicemailomtp/permissions.xml b/java/com/android/voicemailomtp/permissions.xml deleted file mode 100644 index 9326d803a..000000000 --- a/java/com/android/voicemailomtp/permissions.xml +++ /dev/null @@ -1,21 +0,0 @@ -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.voicemailomtp"> - - <uses-sdk - android:minSdkVersion="23" - android:targetSdkVersion="25"/> - - <!-- Applications using this module should merge these permissions using android_manifest_merge --> - - <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> - <uses-permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL" /> - <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" /> - <uses-permission android:name="android.permission.WAKE_LOCK"/> - <uses-permission android:name="android.permission.READ_PHONE_STATE"/> - <uses-permission android:name="android.permission.SEND_SMS"/> - <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> - <uses-permission android:name="android.permission.INTERNET"/> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> - - <application/> -</manifest> diff --git a/java/com/android/voicemailomtp/protocol/CvvmProtocol.java b/java/com/android/voicemailomtp/protocol/CvvmProtocol.java deleted file mode 100644 index 48ed99709..000000000 --- a/java/com/android/voicemailomtp/protocol/CvvmProtocol.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; - -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.sms.OmtpCvvmMessageSender; -import com.android.voicemailomtp.sms.OmtpMessageSender; - -/** - * A flavor of OMTP protocol with a different mobile originated (MO) format - * - * Used by carriers such as T-Mobile - */ -public class CvvmProtocol extends VisualVoicemailProtocol { - - private static String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s"; - private static String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s"; - private static String IMAP_CLOSE_NUT = "CLOSE_NUT"; - - @Override - public OmtpMessageSender createMessageSender(Context context, - PhoneAccountHandle phoneAccountHandle, short applicationPort, - String destinationNumber) { - return new OmtpCvvmMessageSender(context, phoneAccountHandle, applicationPort, - destinationNumber); - } - - @Override - public String getCommand(String command) { - if (command == OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT) { - return IMAP_CHANGE_TUI_PWD_FORMAT; - } - if (command == OmtpConstants.IMAP_CLOSE_NUT) { - return IMAP_CLOSE_NUT; - } - if (command == OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT) { - return IMAP_CHANGE_VM_LANG_FORMAT; - } - return super.getCommand(command); - } -} diff --git a/java/com/android/voicemailomtp/protocol/OmtpProtocol.java b/java/com/android/voicemailomtp/protocol/OmtpProtocol.java deleted file mode 100644 index d88a23285..000000000 --- a/java/com/android/voicemailomtp/protocol/OmtpProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; - -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.sms.OmtpMessageSender; -import com.android.voicemailomtp.sms.OmtpStandardMessageSender; - -public class OmtpProtocol extends VisualVoicemailProtocol { - - @Override - public OmtpMessageSender createMessageSender(Context context, - PhoneAccountHandle phoneAccountHandle, short applicationPort, - String destinationNumber) { - return new OmtpStandardMessageSender(context, phoneAccountHandle, applicationPort, - destinationNumber, - null, OmtpConstants.PROTOCOL_VERSION1_1, null); - } -} diff --git a/java/com/android/voicemailomtp/protocol/ProtocolHelper.java b/java/com/android/voicemailomtp/protocol/ProtocolHelper.java deleted file mode 100644 index 4fca199bf..000000000 --- a/java/com/android/voicemailomtp/protocol/ProtocolHelper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.telephony.SmsManager; -import android.text.TextUtils; - -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.sms.OmtpMessageSender; - -public class ProtocolHelper { - - private static final String TAG = "ProtocolHelper"; - - public static OmtpMessageSender getMessageSender(VisualVoicemailProtocol protocol, - OmtpVvmCarrierConfigHelper config) { - - int applicationPort = config.getApplicationPort(); - String destinationNumber = config.getDestinationNumber(); - if (TextUtils.isEmpty(destinationNumber)) { - VvmLog.w(TAG, "No destination number for this carrier."); - return null; - } - - return protocol.createMessageSender(config.getContext(), config.getPhoneAccountHandle(), - (short) applicationPort, destinationNumber); - } -} diff --git a/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocol.java b/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocol.java deleted file mode 100644 index 9ff2ed167..000000000 --- a/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocol.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.app.PendingIntent; -import android.content.Context; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.DefaultOmtpEventHandler; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.sms.OmtpMessageSender; -import com.android.voicemailomtp.sms.StatusMessage; - -public abstract class VisualVoicemailProtocol { - - /** - * Activation should cause the carrier to respond with a STATUS SMS. - */ - public void startActivation(OmtpVvmCarrierConfigHelper config, PendingIntent sentIntent) { - OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config); - if (messageSender != null) { - messageSender.requestVvmActivation(sentIntent); - } - } - - public void startDeactivation(OmtpVvmCarrierConfigHelper config) { - OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config); - if (messageSender != null) { - messageSender.requestVvmDeactivation(null); - } - } - - public boolean supportsProvisioning() { - return false; - } - - public void startProvisioning(ActivationTask task, PhoneAccountHandle handle, - OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor editor, StatusMessage message, - Bundle data) { - // Do nothing - } - - public void requestStatus(OmtpVvmCarrierConfigHelper config, - @Nullable PendingIntent sentIntent) { - OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config); - if (messageSender != null) { - messageSender.requestVvmStatus(sentIntent); - } - } - - public abstract OmtpMessageSender createMessageSender(Context context, - PhoneAccountHandle phoneAccountHandle, - short applicationPort, String destinationNumber); - - /** - * Translate an OMTP IMAP command to the protocol specific one. For example, changing the TUI - * password on OMTP is XCHANGE_TUI_PWD, but on CVVM and VVM3 it is CHANGE_TUI_PWD. - * - * @param command A String command in {@link com.android.voicemailomtp.OmtpConstants}, the exact - * instance should be used instead of its' value. - * @returns Translated command, or {@code null} if not available in this protocol - */ - public String getCommand(String command) { - return command; - } - - public void handleEvent(Context context, OmtpVvmCarrierConfigHelper config, - VoicemailStatus.Editor status, OmtpEvents event) { - DefaultOmtpEventHandler.handleEvent(context, config, status, event); - } - - /** - * Given an VVM SMS with an unknown {@code event}, let the protocol attempt to translate it into - * an equivalent STATUS SMS. Returns {@code null} if it cannot be translated. - */ - @Nullable - public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event, - Bundle data) { - return null; - } -} diff --git a/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocolFactory.java b/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocolFactory.java deleted file mode 100644 index b74f503c6..000000000 --- a/java/com/android/voicemailomtp/protocol/VisualVoicemailProtocolFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.content.res.Resources; -import android.support.annotation.Nullable; -import android.telephony.TelephonyManager; -import com.android.voicemailomtp.VvmLog; - -public class VisualVoicemailProtocolFactory { - - private static final String TAG = "VvmProtocolFactory"; - - private static final String VVM_TYPE_VVM3 = "vvm_type_vvm3"; - - @Nullable - public static VisualVoicemailProtocol create(Resources resources, String type) { - if (type == null) { - return null; - } - switch (type) { - case TelephonyManager.VVM_TYPE_OMTP: - return new OmtpProtocol(); - case TelephonyManager.VVM_TYPE_CVVM: - return new CvvmProtocol(); - case VVM_TYPE_VVM3: - return new Vvm3Protocol(); - default: - VvmLog.e(TAG, "Unexpected visual voicemail type: " + type); - } - return null; - } -} diff --git a/java/com/android/voicemailomtp/protocol/Vvm3EventHandler.java b/java/com/android/voicemailomtp/protocol/Vvm3EventHandler.java deleted file mode 100644 index 72646386c..000000000 --- a/java/com/android/voicemailomtp/protocol/Vvm3EventHandler.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.content.Context; -import android.support.annotation.IntDef; -import android.util.Log; -import com.android.voicemailomtp.DefaultOmtpEventHandler; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpEvents.Type; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.settings.VoicemailChangePinActivity; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Handles {@link OmtpEvents} when {@link Vvm3Protocol} is being used. This handler writes custom - * error codes into the voicemail status table so support on the dialer side is required. - * - * TODO(b/29577838) disable VVM3 by default so support on system dialer can be ensured. - */ -public class Vvm3EventHandler { - - private static final String TAG = "Vvm3EventHandler"; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({VMS_DNS_FAILURE, VMG_DNS_FAILURE, SPG_DNS_FAILURE, VMS_NO_CELLULAR, VMG_NO_CELLULAR, - SPG_NO_CELLULAR, VMS_TIMEOUT, VMG_TIMEOUT, STATUS_SMS_TIMEOUT, SUBSCRIBER_BLOCKED, - UNKNOWN_USER, UNKNOWN_DEVICE, INVALID_PASSWORD, MAILBOX_NOT_INITIALIZED, - SERVICE_NOT_PROVISIONED, SERVICE_NOT_ACTIVATED, USER_BLOCKED, IMAP_GETQUOTA_ERROR, - IMAP_SELECT_ERROR, IMAP_ERROR, VMG_INTERNAL_ERROR, VMG_DB_ERROR, - VMG_COMMUNICATION_ERROR, SPG_URL_NOT_FOUND, VMG_UNKNOWN_ERROR, PIN_NOT_SET}) - public @interface ErrorCode { - - } - - public static final int VMS_DNS_FAILURE = -9001; - public static final int VMG_DNS_FAILURE = -9002; - public static final int SPG_DNS_FAILURE = -9003; - public static final int VMS_NO_CELLULAR = -9004; - public static final int VMG_NO_CELLULAR = -9005; - public static final int SPG_NO_CELLULAR = -9006; - public static final int VMS_TIMEOUT = -9007; - public static final int VMG_TIMEOUT = -9008; - public static final int STATUS_SMS_TIMEOUT = -9009; - - public static final int SUBSCRIBER_BLOCKED = -9990; - public static final int UNKNOWN_USER = -9991; - public static final int UNKNOWN_DEVICE = -9992; - public static final int INVALID_PASSWORD = -9993; - public static final int MAILBOX_NOT_INITIALIZED = -9994; - public static final int SERVICE_NOT_PROVISIONED = -9995; - public static final int SERVICE_NOT_ACTIVATED = -9996; - public static final int USER_BLOCKED = -9998; - public static final int IMAP_GETQUOTA_ERROR = -9997; - public static final int IMAP_SELECT_ERROR = -9989; - public static final int IMAP_ERROR = -9999; - - public static final int VMG_INTERNAL_ERROR = -101; - public static final int VMG_DB_ERROR = -102; - public static final int VMG_COMMUNICATION_ERROR = -103; - public static final int SPG_URL_NOT_FOUND = -301; - - // Non VVM3 codes: - public static final int VMG_UNKNOWN_ERROR = -1; - public static final int PIN_NOT_SET = -100; - // STATUS SMS returned st=U and rc!=2. The user cannot be provisioned and must contact customer - // support. - public static final int SUBSCRIBER_UNKNOWN = -99; - - - public static void handleEvent(Context context, OmtpVvmCarrierConfigHelper config, - VoicemailStatus.Editor status, OmtpEvents event) { - boolean handled = false; - switch (event.getType()) { - case Type.CONFIGURATION: - handled = handleConfigurationEvent(context, status, event); - break; - case Type.DATA_CHANNEL: - handled = handleDataChannelEvent(status, event); - break; - case Type.NOTIFICATION_CHANNEL: - handled = handleNotificationChannelEvent(status, event); - break; - case Type.OTHER: - handled = handleOtherEvent(status, event); - break; - default: - Log.wtf(TAG, "invalid event type " + event.getType() + " for " + event); - } - if (!handled) { - DefaultOmtpEventHandler.handleEvent(context, config, status, event); - } - } - - private static boolean handleConfigurationEvent(Context context, VoicemailStatus.Editor status, - OmtpEvents event) { - switch (event) { - case CONFIG_REQUEST_STATUS_SUCCESS: - if (status.getPhoneAccountHandle() == null) { - // This should never happen. - Log.e(TAG, "status editor has null phone account handle"); - return true; - } - - if (!VoicemailChangePinActivity - .isDefaultOldPinSet(context, status.getPhoneAccountHandle())) { - return false; - } else { - postError(status, PIN_NOT_SET); - } - break; - case CONFIG_DEFAULT_PIN_REPLACED: - postError(status, PIN_NOT_SET); - break; - case CONFIG_STATUS_SMS_TIME_OUT: - postError(status, STATUS_SMS_TIMEOUT); - break; - default: - return false; - } - return true; - } - - private static boolean handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event) { - switch (event) { - case DATA_NO_CONNECTION: - case DATA_NO_CONNECTION_CELLULAR_REQUIRED: - case DATA_ALL_SOCKET_CONNECTION_FAILED: - postError(status, VMS_NO_CELLULAR); - break; - case DATA_SSL_INVALID_HOST_NAME: - case DATA_CANNOT_ESTABLISH_SSL_SESSION: - case DATA_IOE_ON_OPEN: - postError(status, VMS_TIMEOUT); - break; - case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK: - postError(status, VMS_DNS_FAILURE); - break; - case DATA_BAD_IMAP_CREDENTIAL: - postError(status, IMAP_ERROR); - break; - case DATA_AUTH_UNKNOWN_USER: - postError(status, UNKNOWN_USER); - break; - case DATA_AUTH_UNKNOWN_DEVICE: - postError(status, UNKNOWN_DEVICE); - break; - case DATA_AUTH_INVALID_PASSWORD: - postError(status, INVALID_PASSWORD); - break; - case DATA_AUTH_MAILBOX_NOT_INITIALIZED: - postError(status, MAILBOX_NOT_INITIALIZED); - break; - case DATA_AUTH_SERVICE_NOT_PROVISIONED: - postError(status, SERVICE_NOT_PROVISIONED); - break; - case DATA_AUTH_SERVICE_NOT_ACTIVATED: - postError(status, SERVICE_NOT_ACTIVATED); - break; - case DATA_AUTH_USER_IS_BLOCKED: - postError(status, USER_BLOCKED); - break; - case DATA_REJECTED_SERVER_RESPONSE: - case DATA_INVALID_INITIAL_SERVER_RESPONSE: - case DATA_SSL_EXCEPTION: - postError(status, IMAP_ERROR); - break; - default: - return false; - } - return true; - } - - private static boolean handleNotificationChannelEvent(VoicemailStatus.Editor status, - OmtpEvents event) { - return false; - } - - private static boolean handleOtherEvent(VoicemailStatus.Editor status, - OmtpEvents event) { - switch (event) { - case VVM3_NEW_USER_SETUP_FAILED: - postError(status, MAILBOX_NOT_INITIALIZED); - break; - case VVM3_VMG_DNS_FAILURE: - postError(status, VMG_DNS_FAILURE); - break; - case VVM3_SPG_DNS_FAILURE: - postError(status, SPG_DNS_FAILURE); - break; - case VVM3_VMG_CONNECTION_FAILED: - postError(status, VMG_NO_CELLULAR); - break; - case VVM3_SPG_CONNECTION_FAILED: - postError(status, SPG_NO_CELLULAR); - break; - case VVM3_VMG_TIMEOUT: - postError(status, VMG_TIMEOUT); - break; - case VVM3_SUBSCRIBER_PROVISIONED: - postError(status, SERVICE_NOT_ACTIVATED); - break; - case VVM3_SUBSCRIBER_BLOCKED: - postError(status, SUBSCRIBER_BLOCKED); - break; - case VVM3_SUBSCRIBER_UNKNOWN: - postError(status, SUBSCRIBER_UNKNOWN); - break; - default: - return false; - } - return true; - } - - private static void postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode) { - switch (errorCode) { - case VMG_DNS_FAILURE: - case SPG_DNS_FAILURE: - case VMG_NO_CELLULAR: - case SPG_NO_CELLULAR: - case VMG_TIMEOUT: - case SUBSCRIBER_BLOCKED: - case UNKNOWN_USER: - case UNKNOWN_DEVICE: - case INVALID_PASSWORD: - case MAILBOX_NOT_INITIALIZED: - case SERVICE_NOT_PROVISIONED: - case SERVICE_NOT_ACTIVATED: - case USER_BLOCKED: - case VMG_UNKNOWN_ERROR: - case SPG_URL_NOT_FOUND: - case VMG_INTERNAL_ERROR: - case VMG_DB_ERROR: - case VMG_COMMUNICATION_ERROR: - case PIN_NOT_SET: - case SUBSCRIBER_UNKNOWN: - editor.setConfigurationState(errorCode); - break; - case VMS_NO_CELLULAR: - case VMS_DNS_FAILURE: - case VMS_TIMEOUT: - case IMAP_GETQUOTA_ERROR: - case IMAP_SELECT_ERROR: - case IMAP_ERROR: - editor.setDataChannelState(errorCode); - break; - case STATUS_SMS_TIMEOUT: - editor.setNotificationChannelState(errorCode); - break; - default: - Log.wtf(TAG, "unknown error code: " + errorCode); - } - editor.apply(); - } -} diff --git a/java/com/android/voicemailomtp/protocol/Vvm3Protocol.java b/java/com/android/voicemailomtp/protocol/Vvm3Protocol.java deleted file mode 100644 index 652d1010a..000000000 --- a/java/com/android/voicemailomtp/protocol/Vvm3Protocol.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.Context; -import android.net.Network; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.text.TextUtils; -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VisualVoicemailPreferences; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.imap.ImapHelper.InitializingException; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.settings.VisualVoicemailSettingsUtil; -import com.android.voicemailomtp.settings.VoicemailChangePinActivity; -import com.android.voicemailomtp.sms.OmtpMessageSender; -import com.android.voicemailomtp.sms.StatusMessage; -import com.android.voicemailomtp.sms.Vvm3MessageSender; -import com.android.voicemailomtp.sync.VvmNetworkRequest; -import com.android.voicemailomtp.sync.VvmNetworkRequest.NetworkWrapper; -import com.android.voicemailomtp.sync.VvmNetworkRequest.RequestFailedException; -import java.io.IOException; -import java.security.SecureRandom; -import java.util.Locale; - -/** - * A flavor of OMTP protocol with a different provisioning process - * - * <p>Used by carriers such as Verizon Wireless - */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class Vvm3Protocol extends VisualVoicemailProtocol { - - private static final String TAG = "Vvm3Protocol"; - - private static final String SMS_EVENT_UNRECOGNIZED = "UNRECOGNIZED"; - private static final String SMS_EVENT_UNRECOGNIZED_CMD = "cmd"; - private static final String SMS_EVENT_UNRECOGNIZED_STATUS = "STATUS"; - private static final String DEFAULT_VMG_URL_KEY = "default_vmg_url"; - - private static final String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s"; - private static final String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s"; - private static final String IMAP_CLOSE_NUT = "CLOSE_NUT"; - - private static final String ISO639_Spanish = "es"; - - /** - * For VVM3, if the STATUS SMS returns {@link StatusMessage#getProvisioningStatus()} of {@link - * OmtpConstants#SUBSCRIBER_UNKNOWN} and {@link StatusMessage#getReturnCode()} of this value, - * the user can self-provision visual voicemail service. For other response codes, the user must - * contact customer support to resolve the issue. - */ - private static final String VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE = "2"; - - // Default prompt level when using the telephone user interface. - // Standard prompt when the user call into the voicemail, and no prompts when someone else is - // leaving a voicemail. - private static final String VVM3_VM_LANGUAGE_ENGLISH_STANDARD_NO_GUEST_PROMPTS = "5"; - private static final String VVM3_VM_LANGUAGE_SPANISH_STANDARD_NO_GUEST_PROMPTS = "6"; - - private static final int DEFAULT_PIN_LENGTH = 6; - - @Override - public void startActivation(OmtpVvmCarrierConfigHelper config, - @Nullable PendingIntent sentIntent) { - // VVM3 does not support activation SMS. - // Send a status request which will start the provisioning process if the user is not - // provisioned. - VvmLog.i(TAG, "Activating"); - config.requestStatus(sentIntent); - } - - @Override - public void startDeactivation(OmtpVvmCarrierConfigHelper config) { - // VVM3 does not support deactivation. - // do nothing. - } - - @Override - public boolean supportsProvisioning() { - return true; - } - - @Override - public void startProvisioning(ActivationTask task, PhoneAccountHandle phoneAccountHandle, - OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, StatusMessage message, - Bundle data) { - VvmLog.i(TAG, "start vvm3 provisioning"); - if (OmtpConstants.SUBSCRIBER_UNKNOWN.equals(message.getProvisioningStatus())) { - VvmLog.i(TAG, "Provisioning status: Unknown"); - if (VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE - .equals(message.getReturnCode())) { - VvmLog.i(TAG, "Self provisioning available, subscribing"); - new Vvm3Subscriber(task, phoneAccountHandle, config, status, data).subscribe(); - } else { - config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_UNKNOWN); - } - } else if (OmtpConstants.SUBSCRIBER_NEW.equals(message.getProvisioningStatus())) { - VvmLog.i(TAG, "setting up new user"); - // Save the IMAP credentials in preferences so they are persistent and can be retrieved. - VisualVoicemailPreferences prefs = - new VisualVoicemailPreferences(config.getContext(), phoneAccountHandle); - message.putStatus(prefs.edit()).apply(); - - startProvisionNewUser(task, phoneAccountHandle, config, status, message); - } else if (OmtpConstants.SUBSCRIBER_PROVISIONED.equals(message.getProvisioningStatus())) { - VvmLog.i(TAG, "User provisioned but not activated, disabling VVM"); - VisualVoicemailSettingsUtil - .setEnabled(config.getContext(), phoneAccountHandle, false); - } else if (OmtpConstants.SUBSCRIBER_BLOCKED.equals(message.getProvisioningStatus())) { - VvmLog.i(TAG, "User blocked"); - config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_BLOCKED); - } - } - - @Override - public OmtpMessageSender createMessageSender(Context context, - PhoneAccountHandle phoneAccountHandle, short applicationPort, - String destinationNumber) { - return new Vvm3MessageSender(context, phoneAccountHandle, applicationPort, - destinationNumber); - } - - @Override - public void handleEvent(Context context, OmtpVvmCarrierConfigHelper config, - VoicemailStatus.Editor status, OmtpEvents event) { - Vvm3EventHandler.handleEvent(context, config, status, event); - } - - @Override - public String getCommand(String command) { - if (command == OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT) { - return IMAP_CHANGE_TUI_PWD_FORMAT; - } - if (command == OmtpConstants.IMAP_CLOSE_NUT) { - return IMAP_CLOSE_NUT; - } - if (command == OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT) { - return IMAP_CHANGE_VM_LANG_FORMAT; - } - return super.getCommand(command); - } - - @Override - public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event, - Bundle data) { - // UNRECOGNIZED?cmd=STATUS is the response of a STATUS request when the user is provisioned - // with iPhone visual voicemail without VoLTE. Translate it into an unprovisioned status - // so provisioning can be done. - if (!SMS_EVENT_UNRECOGNIZED.equals(event)) { - return null; - } - if (!SMS_EVENT_UNRECOGNIZED_STATUS.equals(data.getString(SMS_EVENT_UNRECOGNIZED_CMD))) { - return null; - } - Bundle bundle = new Bundle(); - bundle.putString(OmtpConstants.PROVISIONING_STATUS, OmtpConstants.SUBSCRIBER_UNKNOWN); - bundle.putString(OmtpConstants.RETURN_CODE, - VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE); - String vmgUrl = config.getString(DEFAULT_VMG_URL_KEY); - if (TextUtils.isEmpty(vmgUrl)) { - VvmLog.e(TAG, "Unable to translate STATUS SMS: VMG URL is not set in config"); - return null; - } - bundle.putString(Vvm3Subscriber.VMG_URL_KEY, vmgUrl); - VvmLog.i(TAG, "UNRECOGNIZED?cmd=STATUS translated into unprovisioned STATUS SMS"); - return bundle; - } - - private void startProvisionNewUser(ActivationTask task, PhoneAccountHandle phoneAccountHandle, - OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, - StatusMessage message) { - try (NetworkWrapper wrapper = VvmNetworkRequest - .getNetwork(config, phoneAccountHandle, status)) { - Network network = wrapper.get(); - - VvmLog.i(TAG, "new user: network available"); - try (ImapHelper helper = new ImapHelper(config.getContext(), phoneAccountHandle, - network, status)) { - // VVM3 has inconsistent error language code to OMTP. Just issue a raw command - // here. - // TODO(b/29082671): use LocaleList - if (Locale.getDefault().getLanguage() - .equals(new Locale(ISO639_Spanish).getLanguage())) { - // Spanish - helper.changeVoicemailTuiLanguage( - VVM3_VM_LANGUAGE_SPANISH_STANDARD_NO_GUEST_PROMPTS); - } else { - // English - helper.changeVoicemailTuiLanguage( - VVM3_VM_LANGUAGE_ENGLISH_STANDARD_NO_GUEST_PROMPTS); - } - VvmLog.i(TAG, "new user: language set"); - - if (setPin(config.getContext(), phoneAccountHandle, helper, message)) { - // Only close new user tutorial if the PIN has been changed. - helper.closeNewUserTutorial(); - VvmLog.i(TAG, "new user: NUT closed"); - - config.requestStatus(null); - } - } catch (InitializingException | MessagingException | IOException e) { - config.handleEvent(status, OmtpEvents.VVM3_NEW_USER_SETUP_FAILED); - task.fail(); - VvmLog.e(TAG, e.toString()); - } - } catch (RequestFailedException e) { - config.handleEvent(status, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED); - task.fail(); - } - - } - - - private static boolean setPin(Context context, PhoneAccountHandle phoneAccountHandle, - ImapHelper helper, StatusMessage message) - throws IOException, MessagingException { - String defaultPin = getDefaultPin(message); - if (defaultPin == null) { - VvmLog.i(TAG, "cannot generate default PIN"); - return false; - } - - if (VoicemailChangePinActivity.isDefaultOldPinSet(context, phoneAccountHandle)) { - // The pin was already set - VvmLog.i(TAG, "PIN already set"); - return true; - } - String newPin = generatePin(getMinimumPinLength(context, phoneAccountHandle)); - if (helper.changePin(defaultPin, newPin) == OmtpConstants.CHANGE_PIN_SUCCESS) { - VoicemailChangePinActivity.setDefaultOldPIN(context, phoneAccountHandle, newPin); - helper.handleEvent(OmtpEvents.CONFIG_DEFAULT_PIN_REPLACED); - } - VvmLog.i(TAG, "new user: PIN set"); - return true; - } - - @Nullable - private static String getDefaultPin(StatusMessage message) { - // The IMAP username is [phone number]@example.com - String username = message.getImapUserName(); - try { - String number = username.substring(0, username.indexOf('@')); - if (number.length() < 4) { - VvmLog.e(TAG, "unable to extract number from IMAP username"); - return null; - } - return "1" + number.substring(number.length() - 4); - } catch (StringIndexOutOfBoundsException e) { - VvmLog.e(TAG, "unable to extract number from IMAP username"); - return null; - } - - } - - private static int getMinimumPinLength(Context context, PhoneAccountHandle phoneAccountHandle) { - VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(context, - phoneAccountHandle); - // The OMTP pin length format is {min}-{max} - String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-"); - if (lengths.length == 2) { - try { - return Integer.parseInt(lengths[0]); - } catch (NumberFormatException e) { - return DEFAULT_PIN_LENGTH; - } - } - return DEFAULT_PIN_LENGTH; - } - - private static String generatePin(int length) { - SecureRandom random = new SecureRandom(); - return String.format(Locale.US, "%010d", Math.abs(random.nextLong())) - .substring(0, length); - - } -} diff --git a/java/com/android/voicemailomtp/protocol/Vvm3Subscriber.java b/java/com/android/voicemailomtp/protocol/Vvm3Subscriber.java deleted file mode 100644 index 0a4d792b2..000000000 --- a/java/com/android/voicemailomtp/protocol/Vvm3Subscriber.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.protocol; - -import android.annotation.TargetApi; -import android.net.Network; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.support.annotation.WorkerThread; -import android.telecom.PhoneAccountHandle; -import android.telephony.TelephonyManager; -import android.text.Html; -import android.text.Spanned; -import android.text.style.URLSpan; -import android.util.ArrayMap; -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.Assert; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.sync.VvmNetworkRequest; -import com.android.voicemailomtp.sync.VvmNetworkRequest.NetworkWrapper; -import com.android.voicemailomtp.sync.VvmNetworkRequest.RequestFailedException; -import com.android.volley.AuthFailureError; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.HurlStack; -import com.android.volley.toolbox.RequestFuture; -import com.android.volley.toolbox.StringRequest; -import com.android.volley.toolbox.Volley; -import java.io.IOException; -import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Locale; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Class to subscribe to basic VVM3 visual voicemail, for example, Verizon. Subscription is required - * when the user is unprovisioned. This could happen when the user is on a legacy service, or - * switched over from devices that used other type of visual voicemail. - * - * <p>The STATUS SMS will come with a URL to the voicemail management gateway. From it we can find - * the self provisioning gateway URL that we can modify voicemail services. - * - * <p>A request to the self provisioning gateway to activate basic visual voicemail will return us - * with a web page. If the user hasn't subscribe to it yet it will contain a link to confirm the - * subscription. This link should be clicked through cellular network, and have cookies enabled. - * - * <p>After the process is completed, the carrier should send us another STATUS SMS with a new or - * ready user. - */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class Vvm3Subscriber { - - private static final String TAG = "Vvm3Subscriber"; - - private static final String OPERATION_GET_SPG_URL = "retrieveSPGURL"; - private static final String SPG_URL_TAG = "spgurl"; - private static final String TRANSACTION_ID_TAG = "transactionid"; - //language=XML - private static final String VMG_XML_REQUEST_FORMAT = "" - + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<VMGVVMRequest>" - + " <MessageHeader>" - + " <transactionid>%1$s</transactionid>" - + " </MessageHeader>" - + " <MessageBody>" - + " <mdn>%2$s</mdn>" - + " <operation>%3$s</operation>" - + " <source>Device</source>" - + " <devicemodel>%4$s</devicemodel>" - + " </MessageBody>" - + "</VMGVVMRequest>"; - - static final String VMG_URL_KEY = "vmg_url"; - - // Self provisioning POST key/values. VVM3 API 2.1.0 12.3 - private static final String SPG_VZW_MDN_PARAM = "VZW_MDN"; - private static final String SPG_VZW_SERVICE_PARAM = "VZW_SERVICE"; - private static final String SPG_VZW_SERVICE_BASIC = "BVVM"; - private static final String SPG_DEVICE_MODEL_PARAM = "DEVICE_MODEL"; - // Value for all android device - private static final String SPG_DEVICE_MODEL_ANDROID = "DROID_4G"; - private static final String SPG_APP_TOKEN_PARAM = "APP_TOKEN"; - private static final String SPG_APP_TOKEN = "q8e3t5u2o1"; - private static final String SPG_LANGUAGE_PARAM = "SPG_LANGUAGE_PARAM"; - private static final String SPG_LANGUAGE_EN = "ENGLISH"; - - private static final String BASIC_SUBSCRIBE_LINK_TEXT = "Subscribe to Basic Visual Voice Mail"; - - private static final int REQUEST_TIMEOUT_SECONDS = 30; - - private final ActivationTask mTask; - private final PhoneAccountHandle mHandle; - private final OmtpVvmCarrierConfigHelper mHelper; - private final VoicemailStatus.Editor mStatus; - private final Bundle mData; - - private final String mNumber; - - private RequestQueue mRequestQueue; - - private static class ProvisioningException extends Exception { - - public ProvisioningException(String message) { - super(message); - } - } - - static { - // Set the default cookie handler to retain session data for the self provisioning gateway. - // Note; this is not ideal as it is application-wide, and can easily get clobbered. - // But it seems to be the preferred way to manage cookie for HttpURLConnection, and manually - // managing cookies will greatly increase complexity. - CookieManager cookieManager = new CookieManager(); - CookieHandler.setDefault(cookieManager); - } - - @WorkerThread - public Vvm3Subscriber(ActivationTask task, PhoneAccountHandle handle, - OmtpVvmCarrierConfigHelper helper, VoicemailStatus.Editor status, Bundle data) { - Assert.isNotMainThread(); - mTask = task; - mHandle = handle; - mHelper = helper; - mStatus = status; - mData = data; - - // Assuming getLine1Number() will work with VVM3. For unprovisioned users the IMAP username - // is not included in the status SMS, thus no other way to get the current phone number. - mNumber = mHelper.getContext().getSystemService(TelephonyManager.class) - .createForPhoneAccountHandle(mHandle).getLine1Number(); - } - - @WorkerThread - public void subscribe() { - Assert.isNotMainThread(); - // Cellular data is required to subscribe. - // processSubscription() is called after network is available. - VvmLog.i(TAG, "Subscribing"); - - try (NetworkWrapper wrapper = VvmNetworkRequest.getNetwork(mHelper, mHandle, mStatus)) { - Network network = wrapper.get(); - VvmLog.d(TAG, "provisioning: network available"); - mRequestQueue = Volley - .newRequestQueue(mHelper.getContext(), new NetworkSpecifiedHurlStack(network)); - processSubscription(); - } catch (RequestFailedException e) { - mHelper.handleEvent(mStatus, OmtpEvents.VVM3_VMG_CONNECTION_FAILED); - mTask.fail(); - } - } - - private void processSubscription() { - try { - String gatewayUrl = getSelfProvisioningGateway(); - String selfProvisionResponse = getSelfProvisionResponse(gatewayUrl); - String subscribeLink = findSubscribeLink(selfProvisionResponse); - clickSubscribeLink(subscribeLink); - } catch (ProvisioningException e) { - VvmLog.e(TAG, e.toString()); - mTask.fail(); - } - } - - /** - * Get the URL to perform self-provisioning from the voicemail management gateway. - */ - private String getSelfProvisioningGateway() throws ProvisioningException { - VvmLog.i(TAG, "retrieving SPG URL"); - String response = vvm3XmlRequest(OPERATION_GET_SPG_URL); - return extractText(response, SPG_URL_TAG); - } - - /** - * Sent a request to the self-provisioning gateway, which will return us with a webpage. The - * page might contain a "Subscribe to Basic Visual Voice Mail" link to complete the - * subscription. The cookie from this response and cellular data is required to click the link. - */ - private String getSelfProvisionResponse(String url) throws ProvisioningException { - VvmLog.i(TAG, "Retrieving self provisioning response"); - - RequestFuture<String> future = RequestFuture.newFuture(); - - StringRequest stringRequest = new StringRequest(Request.Method.POST, url, future, future) { - @Override - protected Map<String, String> getParams() { - Map<String, String> params = new ArrayMap<>(); - params.put(SPG_VZW_MDN_PARAM, mNumber); - params.put(SPG_VZW_SERVICE_PARAM, SPG_VZW_SERVICE_BASIC); - params.put(SPG_DEVICE_MODEL_PARAM, SPG_DEVICE_MODEL_ANDROID); - params.put(SPG_APP_TOKEN_PARAM, SPG_APP_TOKEN); - // Language to display the subscription page. The page is never shown to the user - // so just use English. - params.put(SPG_LANGUAGE_PARAM, SPG_LANGUAGE_EN); - return params; - } - }; - - mRequestQueue.add(stringRequest); - try { - return future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - mHelper.handleEvent(mStatus, OmtpEvents.VVM3_SPG_CONNECTION_FAILED); - throw new ProvisioningException(e.toString()); - } - } - - private void clickSubscribeLink(String subscribeLink) throws ProvisioningException { - VvmLog.i(TAG, "Clicking subscribe link"); - RequestFuture<String> future = RequestFuture.newFuture(); - - StringRequest stringRequest = new StringRequest(Request.Method.POST, - subscribeLink, future, future); - mRequestQueue.add(stringRequest); - try { - // A new STATUS SMS will be sent after this request. - future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (TimeoutException | ExecutionException | InterruptedException e) { - mHelper.handleEvent(mStatus, OmtpEvents.VVM3_SPG_CONNECTION_FAILED); - throw new ProvisioningException(e.toString()); - } - // It could take very long for the STATUS SMS to return. Waiting for it is unreliable. - // Just leave the CONFIG STATUS as CONFIGURING and end the task. The user can always - // manually retry if it took too long. - } - - private String vvm3XmlRequest(String operation) throws ProvisioningException { - VvmLog.d(TAG, "Sending vvm3XmlRequest for " + operation); - String voicemailManagementGateway = mData.getString(VMG_URL_KEY); - if (voicemailManagementGateway == null) { - VvmLog.e(TAG, "voicemailManagementGateway url unknown"); - return null; - } - String transactionId = createTransactionId(); - String body = String.format(Locale.US, VMG_XML_REQUEST_FORMAT, - transactionId, mNumber, operation, Build.MODEL); - - RequestFuture<String> future = RequestFuture.newFuture(); - StringRequest stringRequest = new StringRequest(Request.Method.POST, - voicemailManagementGateway, future, future) { - @Override - public byte[] getBody() throws AuthFailureError { - return body.getBytes(); - } - }; - mRequestQueue.add(stringRequest); - - try { - String response = future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); - if (!transactionId.equals(extractText(response, TRANSACTION_ID_TAG))) { - throw new ProvisioningException("transactionId mismatch"); - } - return response; - } catch (InterruptedException | ExecutionException | TimeoutException e) { - mHelper.handleEvent(mStatus, OmtpEvents.VVM3_VMG_CONNECTION_FAILED); - throw new ProvisioningException(e.toString()); - } - } - - private String findSubscribeLink(String response) throws ProvisioningException { - Spanned doc = Html.fromHtml(response, Html.FROM_HTML_MODE_LEGACY); - URLSpan[] spans = doc.getSpans(0, doc.length(), URLSpan.class); - StringBuilder fulltext = new StringBuilder(); - for (URLSpan span : spans) { - String text = doc.subSequence(doc.getSpanStart(span), doc.getSpanEnd(span)).toString(); - if (BASIC_SUBSCRIBE_LINK_TEXT.equals(text)) { - return span.getURL(); - } - fulltext.append(text); - } - throw new ProvisioningException("Subscribe link not found: " + fulltext); - } - - private String createTransactionId() { - return String.valueOf(Math.abs(new Random().nextLong())); - } - - private String extractText(String xml, String tag) throws ProvisioningException { - Pattern pattern = Pattern.compile("<" + tag + ">(.*)<\\/" + tag + ">"); - Matcher matcher = pattern.matcher(xml); - if (matcher.find()) { - return matcher.group(1); - } - throw new ProvisioningException("Tag " + tag + " not found in xml response"); - } - - private static class NetworkSpecifiedHurlStack extends HurlStack { - - private final Network mNetwork; - - public NetworkSpecifiedHurlStack(Network network) { - mNetwork = network; - } - - @Override - protected HttpURLConnection createConnection(URL url) throws IOException { - return (HttpURLConnection) mNetwork.openConnection(url); - } - - } -} diff --git a/java/com/android/voicemailomtp/res/layout/voicemail_change_pin.xml b/java/com/android/voicemailomtp/res/layout/voicemail_change_pin.xml deleted file mode 100644 index b0db64b12..000000000 --- a/java/com/android/voicemailomtp/res/layout/voicemail_change_pin.xml +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 2014, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center_horizontal" - android:orientation="vertical"> - <!-- header text ('Enter Pin') --> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:orientation="vertical" - android:paddingTop="48dp" - android:paddingStart="48dp" - android:paddingEnd="48dp"> - <TextView - android:id="@+id/headerText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:lines="2" - android:textAppearance="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" - android:accessibilityLiveRegion="polite"/> - - <!-- hint text ('PIN too short') --> - <TextView - android:id="@+id/hintText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:lines="2" /> - - <!-- error text ('PIN too short') --> - <TextView - android:id="@+id/errorText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:lines="2" - android:textColor="@android:color/holo_red_dark"/> - - <!-- Password entry field --> - <EditText - android:id="@+id/pin_entry" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:imeOptions="actionNext|flagNoExtractUi" - android:inputType="numberPassword" - android:textSize="24sp"/> - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clipChildren="false" - android:clipToPadding="false" - android:gravity="end" - android:orientation="horizontal"> - - <!-- left : cancel --> - <Button - android:id="@+id/cancel_button" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="wrap_content" - android:text="@string/change_pin_cancel_label"/> - - <!-- right : continue --> - <Button - android:id="@+id/next_button" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="wrap_content" - android:text="@string/change_pin_continue_label"/> - - </LinearLayout> -</LinearLayout> diff --git a/java/com/android/voicemailomtp/res/values/arrays.xml b/java/com/android/voicemailomtp/res/values/arrays.xml deleted file mode 100644 index 95714cf4d..000000000 --- a/java/com/android/voicemailomtp/res/values/arrays.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<resources> - -</resources> diff --git a/java/com/android/voicemailomtp/res/values/attrs.xml b/java/com/android/voicemailomtp/res/values/attrs.xml deleted file mode 100644 index d1c7329d5..000000000 --- a/java/com/android/voicemailomtp/res/values/attrs.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2006 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - - <attr name="preferenceBackgroundColor" format="color" /> -</resources> diff --git a/java/com/android/voicemailomtp/res/values/colors.xml b/java/com/android/voicemailomtp/res/values/colors.xml deleted file mode 100644 index 8a897ab94..000000000 --- a/java/com/android/voicemailomtp/res/values/colors.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2007 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - -</resources> diff --git a/java/com/android/voicemailomtp/res/values/config.xml b/java/com/android/voicemailomtp/res/values/config.xml deleted file mode 100644 index 2f5603083..000000000 --- a/java/com/android/voicemailomtp/res/values/config.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - -</resources> diff --git a/java/com/android/voicemailomtp/res/values/dimens.xml b/java/com/android/voicemailomtp/res/values/dimens.xml deleted file mode 100644 index e66ca0921..000000000 --- a/java/com/android/voicemailomtp/res/values/dimens.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - -</resources> diff --git a/java/com/android/voicemailomtp/res/values/ids.xml b/java/com/android/voicemailomtp/res/values/ids.xml deleted file mode 100644 index 84c685a14..000000000 --- a/java/com/android/voicemailomtp/res/values/ids.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2015 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<resources> - -</resources>
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/res/values/strings.xml b/java/com/android/voicemailomtp/res/values/strings.xml deleted file mode 100644 index 7a1407371..000000000 --- a/java/com/android/voicemailomtp/res/values/strings.xml +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2007 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - - <!-- Title of the "Voicemail" settings screen, with a text label identifying which SIM the settings are for. --> - <string translatable="false" name="voicemail_settings_with_label">Voicemail (<xliff:g id="subscriptionlabel" example="Mock Carrier">%s</xliff:g>)</string> - - <!-- Call settings screen, setting option name --> - <string translatable="false" name="voicemail_settings_label">Voicemail</string> - - <!-- DO NOT TRANSLATE. Internal key for a visual voicemail preference. --> - <string translatable="false" name="voicemail_visual_voicemail_key"> - voicemail_visual_voicemail_key - </string> - <!-- DO NOT TRANSLATE. Internal key for a voicemail change pin preference. --> - <string translatable="false" name="voicemail_change_pin_key">voicemail_change_pin_key</string> - - <!-- Visual voicemail on/off title [CHAR LIMIT=40] --> - <string translatable="false" name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string> - - <!-- Voicemail change PIN dialog title [CHAR LIMIT=40] --> - <string translatable="false" name="voicemail_set_pin_dialog_title">Set PIN</string> - <!-- Voicemail change PIN dialog title [CHAR LIMIT=40] --> - <string translatable="false" name="voicemail_change_pin_dialog_title">Change PIN</string> - - <!-- Hint for the old PIN field in the change vociemail PIN dialog --> - <string translatable="false" name="vm_change_pin_old_pin">Old PIN</string> - <!-- Hint for the new PIN field in the change vociemail PIN dialog --> - <string translatable="false" name="vm_change_pin_new_pin">New PIN</string> - - <!-- Message on the dialog when PIN changing is in progress --> - <string translatable="false" name="vm_change_pin_progress_message">Please wait.</string> - <!-- Error message for the voicemail PIN change if the PIN is too short --> - <string translatable="false" name="vm_change_pin_error_too_short">The new PIN is too short.</string> - <!-- Error message for the voicemail PIN change if the PIN is too long --> - <string translatable="false" name="vm_change_pin_error_too_long">The new PIN is too long.</string> - <!-- Error message for the voicemail PIN change if the PIN is too weak --> - <string translatable="false" name="vm_change_pin_error_too_weak">The new PIN is too weak. A strong password should not have continuous sequence or repeated digits.</string> - <!-- Error message for the voicemail PIN change if the old PIN entered doesn't match --> - <string translatable="false" name="vm_change_pin_error_mismatch">The old PIN does not match.</string> - <!-- Error message for the voicemail PIN change if the new PIN contains invalid character --> - <string translatable="false" name="vm_change_pin_error_invalid">The new PIN contains invalid characters.</string> - <!-- Error message for the voicemail PIN change if operation has failed --> - <string translatable="false" name="vm_change_pin_error_system_error">Unable to change PIN</string> - <!-- Message to replace the transcription if a visual voicemail message is not supported--> - <string translatable="false" name="vvm_unsupported_message_format">Unsupported message type, call <xliff:g id="number" example="*86">%s</xliff:g> to listen.</string> - - <!-- The title for the change voicemail PIN activity --> - <string translatable="false" name="change_pin_title">Change Voicemail PIN</string> - <!-- The label for the continue button in change voicemail PIN activity --> - <string translatable="false" name="change_pin_continue_label">Continue</string> - <!-- The label for the cancel button in change voicemail PIN activity --> - <string translatable="false" name="change_pin_cancel_label">Cancel</string> - <!-- The label for the ok button in change voicemail PIN activity --> - <string translatable="false" name="change_pin_ok_label">Ok</string> - <!-- The title for the enter old pin step in change voicemail PIN activity --> - <string translatable="false" name="change_pin_enter_old_pin_header">Confirm your old PIN</string> - <!-- The hint for the enter old pin step in change voicemail PIN activity --> - <string translatable="false" name="change_pin_enter_old_pin_hint">Enter your voicemail PIN to continue.</string> - <!-- The title for the enter new pin step in change voicemail PIN activity --> - <string translatable="false" name="change_pin_enter_new_pin_header">Set a new PIN</string> - <!-- The hint for the enter new pin step in change voicemail PIN activity --> - <string translatable="false" name="change_pin_enter_new_pin_hint">PIN must be <xliff:g id="min" example="4">%1$d</xliff:g>-<xliff:g id="max" example="7">%2$d</xliff:g> digits.</string> - <!-- The title for the confirm new pin step in change voicemail PIN activity --> - <string translatable="false" name="change_pin_confirm_pin_header">Confirm your PIN</string> - <!-- The error message for th confirm new pin step in change voicemail PIN activity, if the pin doen't match the one previously entered --> - <string translatable="false" name="change_pin_confirm_pins_dont_match">PINs don\'t match</string> - <!-- The toast to show after the voicemail PIN has been successfully changed --> - <string translatable="false" name="change_pin_succeeded">Voicemail PIN updated</string> - <!-- The error message to show if the server reported an error while attempting to change the voicemail PIN --> - <string translatable="false" name="change_pin_system_error">Unable to set PIN</string> -</resources> diff --git a/java/com/android/voicemailomtp/res/values/styles.xml b/java/com/android/voicemailomtp/res/values/styles.xml deleted file mode 100644 index 8a897ab94..000000000 --- a/java/com/android/voicemailomtp/res/values/styles.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2007 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - -</resources> diff --git a/java/com/android/voicemailomtp/res/xml/voicemail_settings.xml b/java/com/android/voicemailomtp/res/xml/voicemail_settings.xml deleted file mode 100644 index 03bc34efc..000000000 --- a/java/com/android/voicemailomtp/res/xml/voicemail_settings.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/voicemail_settings_label"> - - <SwitchPreference - android:key="@string/voicemail_visual_voicemail_key" - android:title="@string/voicemail_visual_voicemail_switch_title"/>" - - <Preference - android:key="@string/voicemail_change_pin_key" - android:title="@string/voicemail_change_pin_dialog_title"/> -</PreferenceScreen> diff --git a/java/com/android/voicemailomtp/res/xml/vvm_config.xml b/java/com/android/voicemailomtp/res/xml/vvm_config.xml deleted file mode 100644 index 19c667e13..000000000 --- a/java/com/android/voicemailomtp/res/xml/vvm_config.xml +++ /dev/null @@ -1,134 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<list name="carrier_config_list"> - <pbundle_as_map> - <!-- Test --> - <string-array name="mccmnc"> - <item value="TEST"/> - </string-array> - </pbundle_as_map> - - <pbundle_as_map> - <!-- Orange France --> - <string-array name="mccmnc"> - <item value="20801"/> - <item value="20802"/> - </string-array> - - <int name="vvm_port_number_int" value="20481"/> - <string name="vvm_destination_number_string">21101</string> - <string-array name="carrier_vvm_package_name_string_array"> - <item value="com.orange.vvm"/> - </string-array> - <string name="vvm_type_string">vvm_type_omtp</string> - <boolean name="vvm_cellular_data_required_bool" value="true"/> - <string-array name="vvm_disabled_capabilities_string_array"> - <!-- b/32365569 --> - <item value="STARTTLS"/> - </string-array> - </pbundle_as_map> - - <pbundle_as_map> - <!-- T-Mobile USA--> - <string-array name="mccmnc"> - <item value="310160"/> - <item value="310200"/> - <item value="310210"/> - <item value="310220"/> - <item value="310230"/> - <item value="310240"/> - <item value="310250"/> - <item value="310260"/> - <item value="310270"/> - <item value="310300"/> - <item value="310310"/> - <item value="310490"/> - <item value="310530"/> - <item value="310590"/> - <item value="310640"/> - <item value="310660"/> - <item value="310800"/> - </string-array> - - <int name="vvm_port_number_int" value="1808"/> - <int name="vvm_ssl_port_number_int" value="993"/> - <string name="vvm_destination_number_string">122</string> - <string-array name="carrier_vvm_package_name_string_array"> - <item value="com.tmobile.vvm.application"/> - </string-array> - <string name="vvm_type_string">vvm_type_cvvm</string>> - <string-array name="vvm_disabled_capabilities_string_array"> - <!-- b/28717550 --> - <item value="AUTH=DIGEST-MD5"/> - </string-array> - </pbundle_as_map> - - <pbundle_as_map> - <!-- Verizon USA --> - <string-array name="mccmnc"> - <item value="310004"/> - <item value="310010"/> - <item value="310012"/> - <item value="310013"/> - <item value="310590"/> - <item value="310890"/> - <item value="310910"/> - <item value="311110"/> - <item value="311270"/> - <item value="311271"/> - <item value="311272"/> - <item value="311273"/> - <item value="311274"/> - <item value="311275"/> - <item value="311276"/> - <item value="311277"/> - <item value="311278"/> - <item value="311279"/> - <item value="311280"/> - <item value="311281"/> - <item value="311282"/> - <item value="311283"/> - <item value="311284"/> - <item value="311285"/> - <item value="311286"/> - <item value="311287"/> - <item value="311288"/> - <item value="311289"/> - <item value="311390"/> - <item value="311480"/> - <item value="311481"/> - <item value="311482"/> - <item value="311483"/> - <item value="311484"/> - <item value="311485"/> - <item value="311486"/> - <item value="311487"/> - <item value="311488"/> - <item value="311489"/> - </string-array> - - <int name="vvm_port_number_int" value="0"/> - <string name="vvm_destination_number_string">900080006200</string> - <string name="vvm_type_string">vvm_type_vvm3</string> - <string name="vvm_client_prefix_string">//VZWVVM</string> - <boolean name="vvm_cellular_data_required_bool" value="true"/> - <boolean name="vvm_legacy_mode_enabled_bool" value="true"/> - <!-- VVM3 specific value for the voicemail management gateway to use if the SMS didn't provide - one --> - <string name="default_vmg_url">https://mobile.vzw.com/VMGIMS/VMServices</string> - </pbundle_as_map> -</list> diff --git a/java/com/android/voicemailomtp/scheduling/BaseTask.java b/java/com/android/voicemailomtp/scheduling/BaseTask.java deleted file mode 100644 index 8097bb4dc..000000000 --- a/java/com/android/voicemailomtp/scheduling/BaseTask.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Context; -import android.content.Intent; -import android.os.SystemClock; -import android.support.annotation.CallSuper; -import android.support.annotation.MainThread; -import android.support.annotation.NonNull; -import android.support.annotation.WorkerThread; -import android.telecom.PhoneAccountHandle; -import android.telephony.SubscriptionManager; -import com.android.voicemailomtp.Assert; -import com.android.voicemailomtp.NeededForTesting; -import java.util.ArrayList; -import java.util.List; - -/** - * Provides common utilities for task implementations, such as execution time and managing {@link - * Policy} - */ -public abstract class BaseTask implements Task { - - private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; - - private Context mContext; - - private int mId; - private PhoneAccountHandle mPhoneAccountHandle; - - private boolean mHasStarted; - private volatile boolean mHasFailed; - - @NonNull - private final List<Policy> mPolicies = new ArrayList<>(); - - private long mExecutionTime; - - private static Clock sClock = new Clock(); - - protected BaseTask(int id) { - mId = id; - mExecutionTime = getTimeMillis(); - } - - /** - * Modify the task ID to prevent arbitrary task from executing. Can only be called before {@link - * #onCreate(Context, Intent, int, int)} returns. - */ - @MainThread - public void setId(int id) { - Assert.isMainThread(); - mId = id; - } - - @MainThread - public boolean hasStarted() { - Assert.isMainThread(); - return mHasStarted; - } - - @MainThread - public boolean hasFailed() { - Assert.isMainThread(); - return mHasFailed; - } - - public Context getContext() { - return mContext; - } - - public PhoneAccountHandle getPhoneAccountHandle() { - return mPhoneAccountHandle; - } - /** - * Should be call in the constructor or {@link Policy#onCreate(BaseTask, Intent, int, int)} will - * be missed. - */ - @MainThread - public BaseTask addPolicy(Policy policy) { - Assert.isMainThread(); - mPolicies.add(policy); - return this; - } - - /** - * Indicate the task has failed. {@link Policy#onFail()} will be triggered once the execution - * ends. This mechanism is used by policies for actions such as determining whether to schedule - * a retry. Must be call inside {@link #onExecuteInBackgroundThread()} - */ - @WorkerThread - public void fail() { - Assert.isNotMainThread(); - mHasFailed = true; - } - - @MainThread - public void setExecutionTime(long timeMillis) { - Assert.isMainThread(); - mExecutionTime = timeMillis; - } - - public long getTimeMillis() { - return sClock.getTimeMillis(); - } - - /** - * Creates an intent that can be used to restart the current task. Derived class should build - * their intent upon this. - */ - public Intent createRestartIntent() { - return createIntent(getContext(), this.getClass(), mPhoneAccountHandle); - } - - /** - * Creates an intent that can be used to start the {@link TaskSchedulerService}. Derived class - * should build their intent upon this. - */ - public static Intent createIntent(Context context, Class<? extends BaseTask> task, - PhoneAccountHandle phoneAccountHandle) { - Intent intent = TaskSchedulerService.createIntent(context, task); - intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); - return intent; - } - - @Override - public TaskId getId() { - return new TaskId(mId, mPhoneAccountHandle); - } - - @Override - @CallSuper - public void onCreate(Context context, Intent intent, int flags, int startId) { - mContext = context; - mPhoneAccountHandle = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - for (Policy policy : mPolicies) { - policy.onCreate(this, intent, flags, startId); - } - } - - @Override - public long getReadyInMilliSeconds() { - return mExecutionTime - getTimeMillis(); - } - - @Override - @CallSuper - public void onBeforeExecute() { - for (Policy policy : mPolicies) { - policy.onBeforeExecute(); - } - mHasStarted = true; - } - - @Override - @CallSuper - public void onCompleted() { - if (mHasFailed) { - for (Policy policy : mPolicies) { - policy.onFail(); - } - } - - for (Policy policy : mPolicies) { - policy.onCompleted(); - } - } - - @Override - public void onDuplicatedTaskAdded(Task task) { - for (Policy policy : mPolicies) { - policy.onDuplicatedTaskAdded(); - } - } - - @NeededForTesting - static class Clock { - - public long getTimeMillis() { - return SystemClock.elapsedRealtime(); - } - } - - /** - * Used to replace the clock with an deterministic clock - */ - @NeededForTesting - static void setClockForTesting(Clock clock) { - sClock = clock; - } -} diff --git a/java/com/android/voicemailomtp/scheduling/BlockerTask.java b/java/com/android/voicemailomtp/scheduling/BlockerTask.java deleted file mode 100644 index 55ad9a7fd..000000000 --- a/java/com/android/voicemailomtp/scheduling/BlockerTask.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Context; -import android.content.Intent; - -import com.android.voicemailomtp.VvmLog; - -/** - * Task to block another task of the same ID from being queued for a certain amount of time. - */ -public class BlockerTask extends BaseTask { - - private static final String TAG = "BlockerTask"; - - public static final String EXTRA_TASK_ID = "extra_task_id"; - public static final String EXTRA_BLOCK_FOR_MILLIS = "extra_block_for_millis"; - - public BlockerTask() { - super(TASK_INVALID); - } - - @Override - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - setId(intent.getIntExtra(EXTRA_TASK_ID, TASK_INVALID)); - setExecutionTime(getTimeMillis() + intent.getIntExtra(EXTRA_BLOCK_FOR_MILLIS, 0)); - } - - @Override - public void onExecuteInBackgroundThread() { - // Do nothing. - } - - @Override - public void onDuplicatedTaskAdded(Task task) { - VvmLog - .v(TAG, task.toString() + "blocked, " + getReadyInMilliSeconds() + "millis remaining"); - } -} diff --git a/java/com/android/voicemailomtp/scheduling/MinimalIntervalPolicy.java b/java/com/android/voicemailomtp/scheduling/MinimalIntervalPolicy.java deleted file mode 100644 index bef449b30..000000000 --- a/java/com/android/voicemailomtp/scheduling/MinimalIntervalPolicy.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Intent; - -import com.android.voicemailomtp.scheduling.Task.TaskId; - -/** - * If a task with this policy succeeds, a {@link BlockerTask} with the same {@link TaskId} of the - * task will be queued immediately, preventing the same task from running for a certain amount of - * time. - */ -public class MinimalIntervalPolicy implements Policy { - - BaseTask mTask; - TaskId mId; - int mBlockForMillis; - - public MinimalIntervalPolicy(int blockForMillis) { - mBlockForMillis = blockForMillis; - } - - @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { - mTask = task; - mId = mTask.getId(); - } - - @Override - public void onBeforeExecute() { - - } - - @Override - public void onCompleted() { - if (!mTask.hasFailed()) { - Intent intent = mTask - .createIntent(mTask.getContext(), BlockerTask.class, mId.phoneAccountHandle); - intent.putExtra(BlockerTask.EXTRA_TASK_ID, mId.id); - intent.putExtra(BlockerTask.EXTRA_BLOCK_FOR_MILLIS, mBlockForMillis); - mTask.getContext().startService(intent); - } - } - - @Override - public void onFail() { - - } - - @Override - public void onDuplicatedTaskAdded() { - - } -} diff --git a/java/com/android/voicemailomtp/scheduling/Policy.java b/java/com/android/voicemailomtp/scheduling/Policy.java deleted file mode 100644 index 4a475d2ed..000000000 --- a/java/com/android/voicemailomtp/scheduling/Policy.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Intent; - -/** - * A set of listeners managed by {@link BaseTask} for common behaviors such as retrying. Call {@link - * BaseTask#addPolicy(Policy)} to add a policy. - */ -public interface Policy { - - void onCreate(BaseTask task, Intent intent, int flags, int startId); - - void onBeforeExecute(); - - void onCompleted(); - - void onFail(); - - void onDuplicatedTaskAdded(); -} diff --git a/java/com/android/voicemailomtp/scheduling/PostponePolicy.java b/java/com/android/voicemailomtp/scheduling/PostponePolicy.java deleted file mode 100644 index 27a82f0ef..000000000 --- a/java/com/android/voicemailomtp/scheduling/PostponePolicy.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Intent; - -import com.android.voicemailomtp.VvmLog; - -/** - * A task with Postpone policy will not be executed immediately. It will wait for a while and if a - * duplicated task is queued during the duration, the task will be postponed further. The task will - * only be executed if no new task was added in postponeMillis. Useful to batch small tasks in quick - * succession together. - */ -public class PostponePolicy implements Policy { - - private static final String TAG = "PostponePolicy"; - - private final int mPostponeMillis; - private BaseTask mTask; - - public PostponePolicy(int postponeMillis) { - mPostponeMillis = postponeMillis; - } - - @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { - mTask = task; - mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis); - } - - @Override - public void onBeforeExecute() { - // Do nothing - } - - @Override - public void onCompleted() { - // Do nothing - } - - @Override - public void onFail() { - // Do nothing - } - - @Override - public void onDuplicatedTaskAdded() { - if (mTask.hasStarted()) { - return; - } - VvmLog.d(TAG, "postponing " + mTask); - mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis); - } -} diff --git a/java/com/android/voicemailomtp/scheduling/RetryPolicy.java b/java/com/android/voicemailomtp/scheduling/RetryPolicy.java deleted file mode 100644 index 463657483..000000000 --- a/java/com/android/voicemailomtp/scheduling/RetryPolicy.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Intent; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; - -/** - * A task with this policy will automatically re-queue itself if {@link BaseTask#fail()} has been - * called during {@link BaseTask#onExecuteInBackgroundThread()}. A task will be retried at most - * <code>retryLimit</code> times and with a <code>retryDelayMillis</code> interval in between. - */ -public class RetryPolicy implements Policy { - - private static final String TAG = "RetryPolicy"; - private static final String EXTRA_RETRY_COUNT = "extra_retry_count"; - - private final int mRetryLimit; - private final int mRetryDelayMillis; - - private BaseTask mTask; - - private int mRetryCount; - private boolean mFailed; - - private VoicemailStatus.DeferredEditor mVoicemailStatusEditor; - - public RetryPolicy(int retryLimit, int retryDelayMillis) { - mRetryLimit = retryLimit; - mRetryDelayMillis = retryDelayMillis; - } - - private boolean hasMoreRetries() { - return mRetryCount < mRetryLimit; - } - - /** - * Error status should only be set if retries has exhausted or the task is successful. Status - * writes to this editor will be deferred until the task has ended, and will only be committed - * if the task is successful or there are no retries left. - */ - public VoicemailStatus.Editor getVoicemailStatusEditor() { - return mVoicemailStatusEditor; - } - - @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { - mTask = task; - mRetryCount = intent.getIntExtra(EXTRA_RETRY_COUNT, 0); - if (mRetryCount > 0) { - VvmLog.d(TAG, "retry #" + mRetryCount + " for " + mTask + " queued, executing in " - + mRetryDelayMillis); - mTask.setExecutionTime(mTask.getTimeMillis() + mRetryDelayMillis); - } - PhoneAccountHandle phoneAccountHandle = task.getPhoneAccountHandle(); - if (phoneAccountHandle == null) { - VvmLog.e(TAG, - "null phone account for phoneAccountHandle " + task.getPhoneAccountHandle()); - // This should never happen, but continue on if it does. The status write will be - // discarded. - } - mVoicemailStatusEditor = VoicemailStatus - .deferredEdit(task.getContext(), phoneAccountHandle); - } - - @Override - public void onBeforeExecute() { - - } - - @Override - public void onCompleted() { - if (!mFailed || !hasMoreRetries()) { - if (!mFailed) { - VvmLog.d(TAG, mTask.toString() + " completed successfully"); - } - if (!hasMoreRetries()) { - VvmLog.d(TAG, "Retry limit for " + mTask + " reached"); - } - VvmLog.i(TAG, "committing deferred status: " + mVoicemailStatusEditor.getValues()); - mVoicemailStatusEditor.deferredApply(); - return; - } - VvmLog.i(TAG, "discarding deferred status: " + mVoicemailStatusEditor.getValues()); - Intent intent = mTask.createRestartIntent(); - intent.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1); - - mTask.getContext().startService(intent); - } - - @Override - public void onFail() { - mFailed = true; - } - - @Override - public void onDuplicatedTaskAdded() { - - } -} diff --git a/java/com/android/voicemailomtp/scheduling/Task.java b/java/com/android/voicemailomtp/scheduling/Task.java deleted file mode 100644 index 61c35396b..000000000 --- a/java/com/android/voicemailomtp/scheduling/Task.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.content.Context; -import android.content.Intent; -import android.support.annotation.MainThread; -import android.support.annotation.WorkerThread; -import android.telecom.PhoneAccountHandle; - -import java.util.Objects; - -/** - * A task for {@link TaskSchedulerService} to execute. Since the task is sent through a intent to - * the scheduler, The task must be constructable with the intent. Specifically, It must have a - * constructor with zero arguments, and have all relevant data packed inside the intent. Use {@link - * TaskSchedulerService#createIntent(Context, Class)} to create a intent that will construct the - * Task. - * - * <p>Only {@link #onExecuteInBackgroundThread()} is run on the worker thread. - */ -public interface Task { - - /** - * TaskId to indicate it has not be set. If a task does not provide a default TaskId it should - * be set before {@link Task#onCreate(Context, Intent, int, int) returns} - */ - int TASK_INVALID = -1; - - /** - * TaskId to indicate it should always be queued regardless of duplicates. {@link - * Task#onDuplicatedTaskAdded(Task)} will never be called on tasks with this TaskId. - */ - int TASK_ALLOW_DUPLICATES = -2; - - int TASK_UPLOAD = 1; - int TASK_SYNC = 2; - int TASK_ACTIVATION = 3; - - /** - * Used to differentiate between types of tasks. If a task with the same TaskId is already in - * the queue the new task will be rejected. - */ - class TaskId { - - /** - * Indicates the operation type of the task. - */ - public final int id; - /** - * Same operation for a different phoneAccountHandle is allowed. phoneAccountHandle is used - * to differentiate phone accounts in multi-SIM scenario. For example, each SIM can queue a - * sync task for their own. - */ - public final PhoneAccountHandle phoneAccountHandle; - - public TaskId(int id, PhoneAccountHandle phoneAccountHandle) { - this.id = id; - this.phoneAccountHandle = phoneAccountHandle; - } - - @Override - public boolean equals(Object object) { - if (!(object instanceof TaskId)) { - return false; - } - TaskId other = (TaskId) object; - return id == other.id && phoneAccountHandle.equals(other.phoneAccountHandle); - } - - @Override - public int hashCode() { - return Objects.hash(id, phoneAccountHandle); - } - } - - TaskId getId(); - - @MainThread - void onCreate(Context context, Intent intent, int flags, int startId); - - /** - * @return number of milliSeconds the scheduler should wait before running this task. A value - * less than {@link TaskSchedulerService#READY_TOLERANCE_MILLISECONDS} will be considered ready. - * If no tasks are ready, the scheduler will sleep for this amount of time before doing another - * check (it will still wake if a new task is added). The first task in the queue that is ready - * will be executed. - */ - @MainThread - long getReadyInMilliSeconds(); - - /** - * Called on the main thread when the scheduler is about to send the task into the worker - * thread, calling {@link #onExecuteInBackgroundThread()} - */ - @MainThread - void onBeforeExecute(); - - /** - * The actual payload of the task, executed on the worker thread. - */ - @WorkerThread - void onExecuteInBackgroundThread(); - - /** - * Called on the main thread when {@link #onExecuteInBackgroundThread()} has finished or thrown - * an uncaught exception. The task is already removed from the queue at this point, and a same - * task can be queued again. - */ - @MainThread - void onCompleted(); - - /** - * Another task with the same TaskId has been added. Necessary data can be retrieved from the - * other task, and after this returns the task will be discarded. - */ - @MainThread - void onDuplicatedTaskAdded(Task task); -} diff --git a/java/com/android/voicemailomtp/scheduling/TaskSchedulerService.java b/java/com/android/voicemailomtp/scheduling/TaskSchedulerService.java deleted file mode 100644 index 90b50e913..000000000 --- a/java/com/android/voicemailomtp/scheduling/TaskSchedulerService.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.scheduling; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.SystemClock; -import android.support.annotation.MainThread; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.support.annotation.WorkerThread; -import com.android.voicemailomtp.Assert; -import com.android.voicemailomtp.NeededForTesting; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.scheduling.Task.TaskId; -import java.util.ArrayDeque; -import java.util.Queue; - -/** - * A service to queue and run {@link Task} on a worker thread. Only one task will be ran at a time, - * and same task cannot exist in the queue at the same time. The service will be started when a - * intent is received, and stopped when there are no more tasks in the queue. - */ -public class TaskSchedulerService extends Service { - - private static final String TAG = "VvmTaskScheduler"; - - private static final String ACTION_WAKEUP = "action_wakeup"; - - private static final int READY_TOLERANCE_MILLISECONDS = 100; - - /** - * Threshold to determine whether to do a short or long sleep when a task is scheduled in the - * future. - * - * <p>A short sleep will continue to held the wake lock and use {@link - * Handler#postDelayed(Runnable, long)} to wait for the next task. - * - * <p>A long sleep will release the wake lock and set a {@link AlarmManager} alarm. The alarm is - * exact and will wake up the device. Note: as this service is run in the telephony process it - * does not seem to be restricted by doze or sleep, it will fire exactly at the moment. The - * unbundled version should take doze into account. - */ - private static final int SHORT_SLEEP_THRESHOLD_MILLISECONDS = 60_000; - /** - * When there are no more tasks to be run the service should be stopped. But when all tasks has - * finished there might still be more tasks in the message queue waiting to be processed, - * especially the ones submitted in {@link Task#onCompleted()}. Wait for a while before stopping - * the service to make sure there are no pending messages. - */ - private static final int STOP_DELAY_MILLISECONDS = 5_000; - private static final String EXTRA_CLASS_NAME = "extra_class_name"; - - private static final String WAKE_LOCK_TAG = "TaskSchedulerService_wakelock"; - - // The thread to run tasks on - private volatile WorkerThreadHandler mWorkerThreadHandler; - - private Context mContext = this; - /** - * Used by tests to turn task handling into a single threaded process by calling {@link - * Handler#handleMessage(Message)} directly - */ - private MessageSender mMessageSender = new MessageSender(); - - private MainThreadHandler mMainThreadHandler; - - private WakeLock mWakeLock; - - /** - * Main thread only, access through {@link #getTasks()} - */ - private final Queue<Task> mTasks = new ArrayDeque<>(); - private boolean mWorkerThreadIsBusy = false; - - private final Runnable mStopServiceWithDelay = new Runnable() { - @Override - public void run() { - VvmLog.d(TAG, "Stopping service"); - stopSelf(); - } - }; - /** - * Should attempt to run the next task when a task has finished or been added. - */ - private boolean mTaskAutoRunDisabledForTesting = false; - - @VisibleForTesting - final class WorkerThreadHandler extends Handler { - - public WorkerThreadHandler(Looper looper) { - super(looper); - } - - @Override - @WorkerThread - public void handleMessage(Message msg) { - Assert.isNotMainThread(); - Task task = (Task) msg.obj; - try { - VvmLog.v(TAG, "executing task " + task); - task.onExecuteInBackgroundThread(); - } catch (Throwable throwable) { - VvmLog.e(TAG, "Exception while executing task " + task + ":", throwable); - } - - Message schedulerMessage = mMainThreadHandler.obtainMessage(); - schedulerMessage.obj = task; - mMessageSender.send(schedulerMessage); - } - } - - @VisibleForTesting - final class MainThreadHandler extends Handler { - - public MainThreadHandler(Looper looper) { - super(looper); - } - - @Override - @MainThread - public void handleMessage(Message msg) { - Assert.isMainThread(); - Task task = (Task) msg.obj; - getTasks().remove(task); - task.onCompleted(); - mWorkerThreadIsBusy = false; - maybeRunNextTask(); - } - } - - @Override - @MainThread - public void onCreate() { - super.onCreate(); - mWakeLock = getSystemService(PowerManager.class) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG); - mWakeLock.setReferenceCounted(false); - HandlerThread thread = new HandlerThread("VvmTaskSchedulerService"); - thread.start(); - - mWorkerThreadHandler = new WorkerThreadHandler(thread.getLooper()); - mMainThreadHandler = new MainThreadHandler(Looper.getMainLooper()); - } - - @Override - public void onDestroy() { - mWorkerThreadHandler.getLooper().quit(); - mWakeLock.release(); - } - - @Override - @MainThread - public int onStartCommand(@Nullable Intent intent, int flags, int startId) { - Assert.isMainThread(); - // maybeRunNextTask() will release the wakelock either by entering a long sleep or stopping - // the service. - mWakeLock.acquire(); - if (ACTION_WAKEUP.equals(intent.getAction())) { - VvmLog.d(TAG, "woke up by AlarmManager"); - } else { - Task task = createTask(intent, flags, startId); - if (task == null) { - VvmLog.e(TAG, "cannot create task form intent"); - } else { - addTask(task); - } - } - maybeRunNextTask(); - // STICKY means the service will be automatically restarted will the last intent if it is - // killed. - return START_NOT_STICKY; - } - - @MainThread - @VisibleForTesting - void addTask(Task task) { - Assert.isMainThread(); - if (task.getId().id == Task.TASK_INVALID) { - throw new AssertionError("Task id was not set to a valid value before adding."); - } - if (task.getId().id != Task.TASK_ALLOW_DUPLICATES) { - Task oldTask = getTask(task.getId()); - if (oldTask != null) { - oldTask.onDuplicatedTaskAdded(task); - return; - } - } - mMainThreadHandler.removeCallbacks(mStopServiceWithDelay); - getTasks().add(task); - maybeRunNextTask(); - } - - @MainThread - @Nullable - private Task getTask(TaskId taskId) { - Assert.isMainThread(); - for (Task task : getTasks()) { - if (task.getId().equals(taskId)) { - return task; - } - } - return null; - } - - @MainThread - private Queue<Task> getTasks() { - Assert.isMainThread(); - return mTasks; - } - - /** - * Create an intent that will queue the <code>task</code> - */ - public static Intent createIntent(Context context, Class<? extends Task> task) { - Intent intent = new Intent(context, TaskSchedulerService.class); - intent.putExtra(EXTRA_CLASS_NAME, task.getName()); - return intent; - } - - @VisibleForTesting - @MainThread - @Nullable - Task createTask(@Nullable Intent intent, int flags, int startId) { - Assert.isMainThread(); - if (intent == null) { - return null; - } - String className = intent.getStringExtra(EXTRA_CLASS_NAME); - VvmLog.d(TAG, "create task:" + className); - if (className == null) { - throw new IllegalArgumentException("EXTRA_CLASS_NAME expected"); - } - try { - Task task = (Task) Class.forName(className).newInstance(); - task.onCreate(mContext, intent, flags, startId); - return task; - } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { - throw new IllegalArgumentException(e); - } - } - - @MainThread - private void maybeRunNextTask() { - Assert.isMainThread(); - if (mWorkerThreadIsBusy) { - return; - } - if (mTaskAutoRunDisabledForTesting) { - // If mTaskAutoRunDisabledForTesting is true, runNextTask() must be explicitly called - // to run the next task. - return; - } - - runNextTask(); - } - - @VisibleForTesting - @MainThread - void runNextTask() { - Assert.isMainThread(); - // The current alarm is no longer valid, a new one will be set up if required. - getSystemService(AlarmManager.class).cancel(getWakeupIntent()); - if (getTasks().isEmpty()) { - prepareStop(); - return; - } - Long minimalWaitTime = null; - for (Task task : getTasks()) { - long waitTime = task.getReadyInMilliSeconds(); - if (waitTime < READY_TOLERANCE_MILLISECONDS) { - task.onBeforeExecute(); - Message message = mWorkerThreadHandler.obtainMessage(); - message.obj = task; - mWorkerThreadIsBusy = true; - mMessageSender.send(message); - return; - } else { - if (minimalWaitTime == null || waitTime < minimalWaitTime) { - minimalWaitTime = waitTime; - } - } - } - VvmLog.d(TAG, "minimal wait time:" + minimalWaitTime); - if (!mTaskAutoRunDisabledForTesting && minimalWaitTime != null) { - // No tasks are currently ready. Sleep until the next one should be. - // If a new task is added during the sleep the service will wake immediately. - sleep(minimalWaitTime); - } - } - - private void sleep(long timeMillis) { - if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) { - mMainThreadHandler.postDelayed(new Runnable() { - @Override - public void run() { - maybeRunNextTask(); - } - }, timeMillis); - return; - } - - // Tasks does not have a strict timing requirement, use AlarmManager.set() so the OS could - // optimize the battery usage. As this service currently run in the telephony process the - // OS give it privileges to behave the same as setExact(), but set() is the targeted - // behavior once this is unbundled. - getSystemService(AlarmManager.class).set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + timeMillis, - getWakeupIntent()); - mWakeLock.release(); - VvmLog.d(TAG, "Long sleep for " + timeMillis + " millis"); - } - - private PendingIntent getWakeupIntent() { - Intent intent = new Intent(ACTION_WAKEUP, null, this, getClass()); - return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); - } - - private void prepareStop() { - VvmLog.d(TAG, - "No more tasks, stopping service if no task are added in " - + STOP_DELAY_MILLISECONDS + " millis"); - mMainThreadHandler.postDelayed(mStopServiceWithDelay, STOP_DELAY_MILLISECONDS); - } - - static class MessageSender { - - public void send(Message message) { - message.sendToTarget(); - } - } - - @NeededForTesting - void setContextForTest(Context context) { - mContext = context; - } - - @NeededForTesting - void setTaskAutoRunDisabledForTest(boolean value) { - mTaskAutoRunDisabledForTesting = value; - } - - @NeededForTesting - void setMessageSenderForTest(MessageSender sender) { - mMessageSender = sender; - } - - @NeededForTesting - void clearTasksForTest() { - mTasks.clear(); - } - - @Override - @Nullable - public IBinder onBind(Intent intent) { - return new LocalBinder(); - } - - @NeededForTesting - class LocalBinder extends Binder { - - @NeededForTesting - public TaskSchedulerService getService() { - return TaskSchedulerService.this; - } - } -} diff --git a/java/com/android/voicemailomtp/settings/VisualVoicemailSettingsUtil.java b/java/com/android/voicemailomtp/settings/VisualVoicemailSettingsUtil.java deleted file mode 100644 index 5cec52842..000000000 --- a/java/com/android/voicemailomtp/settings/VisualVoicemailSettingsUtil.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.settings; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VisualVoicemailPreferences; -import com.android.voicemailomtp.sync.OmtpVvmSourceManager; - -/** - * Save whether or not a particular account is enabled in shared to be retrieved later. - */ -public class VisualVoicemailSettingsUtil { - - private static final String IS_ENABLED_KEY = "is_enabled"; - - - public static void setEnabled(Context context, PhoneAccountHandle phoneAccount, - boolean isEnabled) { - new VisualVoicemailPreferences(context, phoneAccount).edit() - .putBoolean(IS_ENABLED_KEY, isEnabled) - .apply(); - OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, phoneAccount); - if (isEnabled) { - OmtpVvmSourceManager.getInstance(context).addPhoneStateListener(phoneAccount); - config.startActivation(); - } else { - OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount); - config.startDeactivation(); - } - } - - public static boolean isEnabled(Context context, - PhoneAccountHandle phoneAccount) { - if (phoneAccount == null) { - return false; - } - - VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount); - if (prefs.contains(IS_ENABLED_KEY)) { - // isEnableByDefault is a bit expensive, so don't use it as default value of - // getBoolean(). The "false" here should never be actually used. - return prefs.getBoolean(IS_ENABLED_KEY, false); - } - return new OmtpVvmCarrierConfigHelper(context, phoneAccount).isEnabledByDefault(); - } - - /** - * Whether the client enabled status is explicitly set by user or by default(Whether carrier VVM - * app is installed). This is used to determine whether to disable the client when the carrier - * VVM app is installed. If the carrier VVM app is installed the client should give priority to - * it if the settings are not touched. - */ - public static boolean isEnabledUserSet(Context context, - PhoneAccountHandle phoneAccount) { - if (phoneAccount == null) { - return false; - } - VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount); - return prefs.contains(IS_ENABLED_KEY); - } -} diff --git a/java/com/android/voicemailomtp/settings/VoicemailChangePinActivity.java b/java/com/android/voicemailomtp/settings/VoicemailChangePinActivity.java deleted file mode 100644 index e679e9970..000000000 --- a/java/com/android/voicemailomtp/settings/VoicemailChangePinActivity.java +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.settings; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; -import android.net.Network; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.text.Editable; -import android.text.InputFilter; -import android.text.InputFilter.LengthFilter; -import android.text.TextWatcher; -import android.view.KeyEvent; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.WindowManager; -import android.view.inputmethod.EditorInfo; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; -import android.widget.Toast; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpConstants.ChangePinResult; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.R; -import com.android.voicemailomtp.VisualVoicemailPreferences; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.imap.ImapHelper.InitializingException; -import com.android.voicemailomtp.mail.MessagingException; -import com.android.voicemailomtp.sync.VvmNetworkRequestCallback; - -/** - * Dialog to change the voicemail PIN. The TUI (Telephony User Interface) PIN is used when accessing - * traditional voicemail through phone call. The intent to launch this activity must contain {@link - * #EXTRA_PHONE_ACCOUNT_HANDLE} - */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class VoicemailChangePinActivity extends Activity - implements OnClickListener, OnEditorActionListener, TextWatcher { - - private static final String TAG = "VmChangePinActivity"; - - public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; - - private static final String KEY_DEFAULT_OLD_PIN = "default_old_pin"; - - private static final int MESSAGE_HANDLE_RESULT = 1; - - private PhoneAccountHandle mPhoneAccountHandle; - private OmtpVvmCarrierConfigHelper mConfig; - - private int mPinMinLength; - private int mPinMaxLength; - - private State mUiState = State.Initial; - private String mOldPin; - private String mFirstPin; - - private ProgressDialog mProgressDialog; - - private TextView mHeaderText; - private TextView mHintText; - private TextView mErrorText; - private EditText mPinEntry; - private Button mCancelButton; - private Button mNextButton; - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == MESSAGE_HANDLE_RESULT) { - mUiState.handleResult(VoicemailChangePinActivity.this, message.arg1); - } - } - }; - - private enum State { - /** - * Empty state to handle initial state transition. Will immediately switch into {@link - * #VerifyOldPin} if a default PIN has been set by the OMTP client, or {@link #EnterOldPin} - * if not. - */ - Initial, - /** - * Prompt the user to enter old PIN. The PIN will be verified with the server before - * proceeding to {@link #EnterNewPin}. - */ - EnterOldPin { - @Override - public void onEnter(VoicemailChangePinActivity activity) { - activity.setHeader(R.string.change_pin_enter_old_pin_header); - activity.mHintText.setText(R.string.change_pin_enter_old_pin_hint); - activity.mNextButton.setText(R.string.change_pin_continue_label); - activity.mErrorText.setText(null); - } - - @Override - public void onInputChanged(VoicemailChangePinActivity activity) { - activity.setNextEnabled(activity.getCurrentPasswordInput().length() > 0); - } - - - @Override - public void handleNext(VoicemailChangePinActivity activity) { - activity.mOldPin = activity.getCurrentPasswordInput(); - activity.verifyOldPin(); - } - - @Override - public void handleResult(VoicemailChangePinActivity activity, - @ChangePinResult int result) { - if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { - activity.updateState(State.EnterNewPin); - } else { - CharSequence message = activity.getChangePinResultMessage(result); - activity.showError(message); - activity.mPinEntry.setText(""); - } - } - }, - /** - * The default old PIN is found. Show a blank screen while verifying with the server to make - * sure the PIN is still valid. If the PIN is still valid, proceed to {@link #EnterNewPin}. - * If not, the user probably changed the PIN through other means, proceed to {@link - * #EnterOldPin}. If any other issue caused the verifying to fail, show an error and exit. - */ - VerifyOldPin { - @Override - public void onEnter(VoicemailChangePinActivity activity) { - activity.findViewById(android.R.id.content).setVisibility(View.INVISIBLE); - activity.verifyOldPin(); - } - - @Override - public void handleResult(final VoicemailChangePinActivity activity, - @ChangePinResult int result) { - if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { - activity.updateState(State.EnterNewPin); - } else if (result == OmtpConstants.CHANGE_PIN_SYSTEM_ERROR) { - activity.getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - activity.showError(activity.getString(R.string.change_pin_system_error), - new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - activity.finish(); - } - }); - } else { - VvmLog.e(TAG, "invalid default old PIN: " + activity - .getChangePinResultMessage(result)); - // If the default old PIN is rejected by the server, the PIN is probably changed - // through other means, or the generated pin is invalid - // Wipe the default old PIN so the old PIN input box will be shown to the user - // on the next time. - setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null); - activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET); - activity.updateState(State.EnterOldPin); - } - } - - @Override - public void onLeave(VoicemailChangePinActivity activity) { - activity.findViewById(android.R.id.content).setVisibility(View.VISIBLE); - } - }, - /** - * Let the user enter the new PIN and validate the format. Only length is enforced, PIN - * strength check relies on the server. After a valid PIN is entered, proceed to {@link - * #ConfirmNewPin} - */ - EnterNewPin { - @Override - public void onEnter(VoicemailChangePinActivity activity) { - activity.mHeaderText.setText(R.string.change_pin_enter_new_pin_header); - activity.mNextButton.setText(R.string.change_pin_continue_label); - activity.mHintText.setText( - activity.getString(R.string.change_pin_enter_new_pin_hint, - activity.mPinMinLength, activity.mPinMaxLength)); - } - - @Override - public void onInputChanged(VoicemailChangePinActivity activity) { - String password = activity.getCurrentPasswordInput(); - if (password.length() == 0) { - activity.setNextEnabled(false); - return; - } - CharSequence error = activity.validatePassword(password); - if (error != null) { - activity.mErrorText.setText(error); - activity.setNextEnabled(false); - } else { - activity.mErrorText.setText(null); - activity.setNextEnabled(true); - } - } - - @Override - public void handleNext(VoicemailChangePinActivity activity) { - CharSequence errorMsg; - errorMsg = activity.validatePassword(activity.getCurrentPasswordInput()); - if (errorMsg != null) { - activity.showError(errorMsg); - return; - } - activity.mFirstPin = activity.getCurrentPasswordInput(); - activity.updateState(State.ConfirmNewPin); - } - }, - /** - * Let the user type in the same PIN again to avoid typos. If the PIN matches then perform a - * PIN change to the server. Finish the activity if succeeded. Return to {@link - * #EnterOldPin} if the old PIN is rejected, {@link #EnterNewPin} for other failure. - */ - ConfirmNewPin { - @Override - public void onEnter(VoicemailChangePinActivity activity) { - activity.mHeaderText.setText(R.string.change_pin_confirm_pin_header); - activity.mHintText.setText(null); - activity.mNextButton.setText(R.string.change_pin_ok_label); - } - - @Override - public void onInputChanged(VoicemailChangePinActivity activity) { - if (activity.getCurrentPasswordInput().length() == 0) { - activity.setNextEnabled(false); - return; - } - if (activity.getCurrentPasswordInput().equals(activity.mFirstPin)) { - activity.setNextEnabled(true); - activity.mErrorText.setText(null); - } else { - activity.setNextEnabled(false); - activity.mErrorText.setText(R.string.change_pin_confirm_pins_dont_match); - } - } - - @Override - public void handleResult(VoicemailChangePinActivity activity, - @ChangePinResult int result) { - if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { - // If the PIN change succeeded we no longer know what the old (current) PIN is. - // Wipe the default old PIN so the old PIN input box will be shown to the user - // on the next time. - setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null); - activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET); - - activity.finish(); - - Toast.makeText(activity, activity.getString(R.string.change_pin_succeeded), - Toast.LENGTH_SHORT).show(); - } else { - CharSequence message = activity.getChangePinResultMessage(result); - VvmLog.i(TAG, "Change PIN failed: " + message); - activity.showError(message); - if (result == OmtpConstants.CHANGE_PIN_MISMATCH) { - // Somehow the PIN has changed, prompt to enter the old PIN again. - activity.updateState(State.EnterOldPin); - } else { - // The new PIN failed to fulfil other restrictions imposed by the server. - activity.updateState(State.EnterNewPin); - } - - } - - } - - @Override - public void handleNext(VoicemailChangePinActivity activity) { - activity.processPinChange(activity.mOldPin, activity.mFirstPin); - } - }; - - /** - * The activity has switched from another state to this one. - */ - public void onEnter(VoicemailChangePinActivity activity) { - // Do nothing - } - - /** - * The user has typed something into the PIN input field. Also called after {@link - * #onEnter(VoicemailChangePinActivity)} - */ - public void onInputChanged(VoicemailChangePinActivity activity) { - // Do nothing - } - - /** - * The asynchronous call to change the PIN on the server has returned. - */ - public void handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result) { - // Do nothing - } - - /** - * The user has pressed the "next" button. - */ - public void handleNext(VoicemailChangePinActivity activity) { - // Do nothing - } - - /** - * The activity has switched from this state to another one. - */ - public void onLeave(VoicemailChangePinActivity activity) { - // Do nothing - } - - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mPhoneAccountHandle = getIntent().getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - mConfig = new OmtpVvmCarrierConfigHelper(this, mPhoneAccountHandle); - setContentView(R.layout.voicemail_change_pin); - setTitle(R.string.change_pin_title); - - readPinLength(); - - View view = findViewById(android.R.id.content); - - mCancelButton = (Button) view.findViewById(R.id.cancel_button); - mCancelButton.setOnClickListener(this); - mNextButton = (Button) view.findViewById(R.id.next_button); - mNextButton.setOnClickListener(this); - - mPinEntry = (EditText) view.findViewById(R.id.pin_entry); - mPinEntry.setOnEditorActionListener(this); - mPinEntry.addTextChangedListener(this); - if (mPinMaxLength != 0) { - mPinEntry.setFilters(new InputFilter[]{new LengthFilter(mPinMaxLength)}); - } - - - mHeaderText = (TextView) view.findViewById(R.id.headerText); - mHintText = (TextView) view.findViewById(R.id.hintText); - mErrorText = (TextView) view.findViewById(R.id.errorText); - - if (isDefaultOldPinSet(this, mPhoneAccountHandle)) { - mOldPin = getDefaultOldPin(this, mPhoneAccountHandle); - updateState(State.VerifyOldPin); - } else { - updateState(State.EnterOldPin); - } - } - - private void handleOmtpEvent(OmtpEvents event) { - mConfig.handleEvent(getVoicemailStatusEditor(), event); - } - - private VoicemailStatus.Editor getVoicemailStatusEditor() { - // This activity does not have any automatic retry mechanism, errors should be written right - // away. - return VoicemailStatus.edit(this, mPhoneAccountHandle); - } - - /** - * Extracts the pin length requirement sent by the server with a STATUS SMS. - */ - private void readPinLength() { - VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this, - mPhoneAccountHandle); - // The OMTP pin length format is {min}-{max} - String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-"); - if (lengths.length == 2) { - try { - mPinMinLength = Integer.parseInt(lengths[0]); - mPinMaxLength = Integer.parseInt(lengths[1]); - } catch (NumberFormatException e) { - mPinMinLength = 0; - mPinMaxLength = 0; - } - } else { - mPinMinLength = 0; - mPinMaxLength = 0; - } - } - - @Override - public void onResume() { - super.onResume(); - updateState(mUiState); - - } - - public void handleNext() { - if (mPinEntry.length() == 0) { - return; - } - mUiState.handleNext(this); - } - - public void onClick(View v) { - if (v.getId() == R.id.next_button) { - handleNext(); - } else if (v.getId() == R.id.cancel_button) { - finish(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (!mNextButton.isEnabled()) { - return true; - } - // Check if this was the result of hitting the enter or "done" key - if (actionId == EditorInfo.IME_NULL - || actionId == EditorInfo.IME_ACTION_DONE - || actionId == EditorInfo.IME_ACTION_NEXT) { - handleNext(); - return true; - } - return false; - } - - public void afterTextChanged(Editable s) { - mUiState.onInputChanged(this); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // Do nothing - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - // Do nothing - } - - /** - * After replacing the default PIN with a random PIN, call this to store the random PIN. The - * stored PIN will be automatically entered when the user attempts to change the PIN. - */ - public static void setDefaultOldPIN(Context context, PhoneAccountHandle phoneAccountHandle, - String pin) { - new VisualVoicemailPreferences(context, phoneAccountHandle) - .edit().putString(KEY_DEFAULT_OLD_PIN, pin).apply(); - } - - public static boolean isDefaultOldPinSet(Context context, - PhoneAccountHandle phoneAccountHandle) { - return getDefaultOldPin(context, phoneAccountHandle) != null; - } - - private static String getDefaultOldPin(Context context, PhoneAccountHandle phoneAccountHandle) { - return new VisualVoicemailPreferences(context, phoneAccountHandle) - .getString(KEY_DEFAULT_OLD_PIN); - } - - private String getCurrentPasswordInput() { - return mPinEntry.getText().toString(); - } - - private void updateState(State state) { - State previousState = mUiState; - mUiState = state; - if (previousState != state) { - previousState.onLeave(this); - mPinEntry.setText(""); - mUiState.onEnter(this); - } - mUiState.onInputChanged(this); - } - - /** - * Validates PIN and returns a message to display if PIN fails test. - * - * @param password the raw password the user typed in - * @return error message to show to user or null if password is OK - */ - private CharSequence validatePassword(String password) { - if (mPinMinLength == 0 && mPinMaxLength == 0) { - // Invalid length requirement is sent by the server, just accept anything and let the - // server decide. - return null; - } - - if (password.length() < mPinMinLength) { - return getString(R.string.vm_change_pin_error_too_short); - } - return null; - } - - private void setHeader(int text) { - mHeaderText.setText(text); - mPinEntry.setContentDescription(mHeaderText.getText()); - } - - /** - * Get the corresponding message for the {@link ChangePinResult}.<code>result</code> must not - * {@link OmtpConstants#CHANGE_PIN_SUCCESS} - */ - private CharSequence getChangePinResultMessage(@ChangePinResult int result) { - switch (result) { - case OmtpConstants.CHANGE_PIN_TOO_SHORT: - return getString(R.string.vm_change_pin_error_too_short); - case OmtpConstants.CHANGE_PIN_TOO_LONG: - return getString(R.string.vm_change_pin_error_too_long); - case OmtpConstants.CHANGE_PIN_TOO_WEAK: - return getString(R.string.vm_change_pin_error_too_weak); - case OmtpConstants.CHANGE_PIN_INVALID_CHARACTER: - return getString(R.string.vm_change_pin_error_invalid); - case OmtpConstants.CHANGE_PIN_MISMATCH: - return getString(R.string.vm_change_pin_error_mismatch); - case OmtpConstants.CHANGE_PIN_SYSTEM_ERROR: - return getString(R.string.vm_change_pin_error_system_error); - default: - VvmLog.wtf(TAG, "Unexpected ChangePinResult " + result); - return null; - } - } - - private void verifyOldPin() { - processPinChange(mOldPin, mOldPin); - } - - private void setNextEnabled(boolean enabled) { - mNextButton.setEnabled(enabled); - } - - - private void showError(CharSequence message) { - showError(message, null); - } - - private void showError(CharSequence message, @Nullable OnDismissListener callback) { - new AlertDialog.Builder(this) - .setMessage(message) - .setPositiveButton(android.R.string.ok, null) - .setOnDismissListener(callback) - .show(); - } - - /** - * Asynchronous call to change the PIN on the server. - */ - private void processPinChange(String oldPin, String newPin) { - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setCancelable(false); - mProgressDialog.setMessage(getString(R.string.vm_change_pin_progress_message)); - mProgressDialog.show(); - - ChangePinNetworkRequestCallback callback = new ChangePinNetworkRequestCallback(oldPin, - newPin); - callback.requestNetwork(); - } - - private class ChangePinNetworkRequestCallback extends VvmNetworkRequestCallback { - - private final String mOldPin; - private final String mNewPin; - - public ChangePinNetworkRequestCallback(String oldPin, String newPin) { - super(mConfig, mPhoneAccountHandle, - VoicemailChangePinActivity.this.getVoicemailStatusEditor()); - mOldPin = oldPin; - mNewPin = newPin; - } - - @Override - public void onAvailable(Network network) { - super.onAvailable(network); - try (ImapHelper helper = - new ImapHelper(VoicemailChangePinActivity.this, mPhoneAccountHandle, network, - getVoicemailStatusEditor())) { - - @ChangePinResult int result = - helper.changePin(mOldPin, mNewPin); - sendResult(result); - } catch (InitializingException | MessagingException e) { - VvmLog.e(TAG, "ChangePinNetworkRequestCallback: onAvailable: ", e); - sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR); - } - } - - @Override - public void onFailed(String reason) { - super.onFailed(reason); - sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR); - } - - private void sendResult(@ChangePinResult int result) { - VvmLog.i(TAG, "Change PIN result: " + result); - if (mProgressDialog.isShowing() && !VoicemailChangePinActivity.this.isDestroyed() && - !VoicemailChangePinActivity.this.isFinishing()) { - mProgressDialog.dismiss(); - } else { - VvmLog.i(TAG, "Dialog not visible, not dismissing"); - } - mHandler.obtainMessage(MESSAGE_HANDLE_RESULT, result, 0).sendToTarget(); - releaseNetwork(); - } - } - -} diff --git a/java/com/android/voicemailomtp/settings/VoicemailSettingsActivity.java b/java/com/android/voicemailomtp/settings/VoicemailSettingsActivity.java deleted file mode 100644 index ac0df6fab..000000000 --- a/java/com/android/voicemailomtp/settings/VoicemailSettingsActivity.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.settings; - -import android.content.Intent; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceScreen; -import android.preference.SwitchPreference; -import android.telecom.PhoneAccountHandle; -import android.text.TextUtils; -import android.util.Log; -import android.view.MenuItem; - -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.R; -import com.android.voicemailomtp.SubscriptionInfoHelper; -import com.android.voicemailomtp.VisualVoicemailPreferences; - -public class VoicemailSettingsActivity extends PreferenceActivity implements - Preference.OnPreferenceChangeListener { - private static final String LOG_TAG = VoicemailSettingsActivity.class.getSimpleName(); - private static final boolean DBG = true; - - /** - * Intent action to bring up Voicemail Provider settings - * DO NOT RENAME. There are existing apps which use this intent value. - */ - public static final String ACTION_ADD_VOICEMAIL = - "com.android.voicemailomtp.CallFeaturesSetting.ADD_VOICEMAIL"; - - /** - * Intent action to bring up the {@code VoicemailSettingsActivity}. - * DO NOT RENAME. There are existing apps which use this intent value. - */ - public static final String ACTION_CONFIGURE_VOICEMAIL = - "com.android.voicemailomtp.CallFeaturesSetting.CONFIGURE_VOICEMAIL"; - - // Extra put in the return from VM provider config containing voicemail number to set - public static final String VM_NUMBER_EXTRA = "com.android.voicemailomtp.VoicemailNumber"; - // Extra put in the return from VM provider config containing call forwarding number to set - public static final String FWD_NUMBER_EXTRA = "com.android.voicemailomtp.ForwardingNumber"; - // Extra put in the return from VM provider config containing call forwarding number to set - public static final String FWD_NUMBER_TIME_EXTRA = "com.android.voicemailomtp.ForwardingNumberTime"; - // If the VM provider returns non null value in this extra we will force the user to - // choose another VM provider - public static final String SIGNOUT_EXTRA = "com.android.voicemailomtp.Signout"; - - /** - * String Extra put into ACTION_ADD_VOICEMAIL call to indicate which provider should be hidden - * in the list of providers presented to the user. This allows a provider which is being - * disabled (e.g. GV user logging out) to force the user to pick some other provider. - */ - public static final String IGNORE_PROVIDER_EXTRA = "com.android.voicemailomtp.ProviderToIgnore"; - - /** - * String Extra put into ACTION_ADD_VOICEMAIL to indicate that the voicemail setup screen should - * be opened. - */ - public static final String SETUP_VOICEMAIL_EXTRA = "com.android.voicemailomtp.SetupVoicemail"; - - /** Event for Async voicemail change call */ - private static final int EVENT_VOICEMAIL_CHANGED = 500; - private static final int EVENT_FORWARDING_CHANGED = 501; - private static final int EVENT_FORWARDING_GET_COMPLETED = 502; - - /** Handle to voicemail pref */ - private static final int VOICEMAIL_PREF_ID = 1; - private static final int VOICEMAIL_PROVIDER_CFG_ID = 2; - - /** - * Used to indicate that the voicemail preference should be shown. - */ - private boolean mShowVoicemailPreference = false; - - private int mSubId; - private PhoneAccountHandle mPhoneAccountHandle; - private SubscriptionInfoHelper mSubscriptionInfoHelper; - private OmtpVvmCarrierConfigHelper mOmtpVvmCarrierConfigHelper; - - private SwitchPreference mVoicemailVisualVoicemail; - private Preference mVoicemailChangePinPreference; - - //********************************************************************************************* - // Preference Activity Methods - //********************************************************************************************* - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Show the voicemail preference in onResume if the calling intent specifies the - // ACTION_ADD_VOICEMAIL action. - mShowVoicemailPreference = (icicle == null) && - TextUtils.equals(getIntent().getAction(), ACTION_ADD_VOICEMAIL); - - mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent()); - mSubscriptionInfoHelper.setActionBarTitle( - getActionBar(), getResources(), R.string.voicemail_settings_with_label); - mSubId = mSubscriptionInfoHelper.getSubId(); - // TODO: scrap this activity. - /* - mPhoneAccountHandle = PhoneAccountHandleConverter - .fromSubId(this, mSubId); - - mOmtpVvmCarrierConfigHelper = new OmtpVvmCarrierConfigHelper( - this, mSubId); - */ - } - - @Override - protected void onResume() { - super.onResume(); - - PreferenceScreen preferenceScreen = getPreferenceScreen(); - if (preferenceScreen != null) { - preferenceScreen.removeAll(); - } - - addPreferencesFromResource(R.xml.voicemail_settings); - - PreferenceScreen prefSet = getPreferenceScreen(); - - mVoicemailVisualVoicemail = (SwitchPreference) findPreference( - getResources().getString(R.string.voicemail_visual_voicemail_key)); - - mVoicemailChangePinPreference = findPreference( - getResources().getString(R.string.voicemail_change_pin_key)); - Intent changePinIntent = new Intent(new Intent(this, VoicemailChangePinActivity.class)); - changePinIntent.putExtra(VoicemailChangePinActivity.EXTRA_PHONE_ACCOUNT_HANDLE, - mPhoneAccountHandle); - - mVoicemailChangePinPreference.setIntent(changePinIntent); - if (VoicemailChangePinActivity.isDefaultOldPinSet(this, mPhoneAccountHandle)) { - mVoicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_dialog_title); - } else { - mVoicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_dialog_title); - } - - if (mOmtpVvmCarrierConfigHelper.isValid()) { - mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this); - mVoicemailVisualVoicemail.setChecked( - VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle)); - if (!isVisualVoicemailActivated()) { - prefSet.removePreference(mVoicemailChangePinPreference); - } - } else { - prefSet.removePreference(mVoicemailVisualVoicemail); - prefSet.removePreference(mVoicemailChangePinPreference); - } - } - - @Override - public void onPause() { - super.onPause(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - /** - * Implemented to support onPreferenceChangeListener to look for preference changes. - * - * @param preference is the preference to be changed - * @param objValue should be the value of the selection, NOT its localized - * display value. - */ - @Override - public boolean onPreferenceChange(Preference preference, Object objValue) { - if (DBG) log("onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\""); - if (preference.getKey().equals(mVoicemailVisualVoicemail.getKey())) { - boolean isEnabled = (boolean) objValue; - VisualVoicemailSettingsUtil - .setEnabled(this, mPhoneAccountHandle, isEnabled); - PreferenceScreen prefSet = getPreferenceScreen(); - if (isVisualVoicemailActivated()) { - prefSet.addPreference(mVoicemailChangePinPreference); - } else { - prefSet.removePreference(mVoicemailChangePinPreference); - } - } - - // Always let the preference setting proceed. - return true; - } - - private boolean isVisualVoicemailActivated() { - if (!VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle)) { - return false; - } - VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this, - mPhoneAccountHandle); - return preferences.getString(OmtpConstants.SERVER_ADDRESS, null) != null; - - } - - private static void log(String msg) { - Log.d(LOG_TAG, msg); - } -} diff --git a/java/com/android/voicemailomtp/sms/LegacyModeSmsHandler.java b/java/com/android/voicemailomtp/sms/LegacyModeSmsHandler.java deleted file mode 100644 index bb722bffc..000000000 --- a/java/com/android/voicemailomtp/sms/LegacyModeSmsHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sms; - -import android.content.Context; -import android.os.Bundle; -import android.telecom.PhoneAccountHandle; -import android.telephony.VisualVoicemailSms; - -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.TelephonyManagerStub; -import com.android.voicemailomtp.VvmLog; - -/** - * Class ot handle voicemail SMS under legacy mode - * - * @see OmtpVvmCarrierConfigHelper#isLegacyModeEnabled() - */ -public class LegacyModeSmsHandler { - - private static final String TAG = "LegacyModeSmsHandler"; - - public static void handle(Context context, VisualVoicemailSms sms) { - VvmLog.v(TAG, "processing VVM SMS on legacy mode"); - String eventType = sms.getPrefix(); - Bundle data = sms.getFields(); - PhoneAccountHandle handle = sms.getPhoneAccountHandle(); - - if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) { - SyncMessage message = new SyncMessage(data); - VvmLog.v(TAG, "Received SYNC sms for " + handle + - " with event " + message.getSyncTriggerEvent()); - - switch (message.getSyncTriggerEvent()) { - case OmtpConstants.NEW_MESSAGE: - case OmtpConstants.MAILBOX_UPDATE: - // The user has called into the voicemail and the new message count could - // change. - // For some carriers new message count could be set to 0 even if there are still - // unread messages, to clear the message waiting indicator. - VvmLog.v(TAG, "updating MWI"); - - // Setting voicemail message count to non-zero will show the telephony voicemail - // notification, and zero will clear it. - TelephonyManagerStub.showVoicemailNotification(message.getNewMessageCount()); - break; - default: - break; - } - } - } -} diff --git a/java/com/android/voicemailomtp/sms/OmtpCvvmMessageSender.java b/java/com/android/voicemailomtp/sms/OmtpCvvmMessageSender.java deleted file mode 100644 index 63af2c13d..000000000 --- a/java/com/android/voicemailomtp/sms/OmtpCvvmMessageSender.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.app.PendingIntent; -import android.content.Context; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; -import com.android.voicemailomtp.OmtpConstants; - -/** - * An implementation of the OmtpMessageSender for T-Mobile. - */ -public class OmtpCvvmMessageSender extends OmtpMessageSender { - public OmtpCvvmMessageSender(Context context, PhoneAccountHandle phoneAccountHandle, - short applicationPort, String destinationNumber) { - super(context, phoneAccountHandle, applicationPort, destinationNumber); - } - - @Override - public void requestVvmActivation(@Nullable PendingIntent sentIntent) { - sendCvvmMessage(OmtpConstants.ACTIVATE_REQUEST, sentIntent); - } - - @Override - public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) { - sendCvvmMessage(OmtpConstants.DEACTIVATE_REQUEST, sentIntent); - } - - @Override - public void requestVvmStatus(@Nullable PendingIntent sentIntent) { - sendCvvmMessage(OmtpConstants.STATUS_REQUEST, sentIntent); - } - - private void sendCvvmMessage(String request, PendingIntent sentIntent) { - StringBuilder sb = new StringBuilder().append(request); - sb.append(OmtpConstants.SMS_PREFIX_SEPARATOR); - appendField(sb, "dt", "15"); - sendSms(sb.toString(), sentIntent); - } -} diff --git a/java/com/android/voicemailomtp/sms/OmtpMessageReceiver.java b/java/com/android/voicemailomtp/sms/OmtpMessageReceiver.java deleted file mode 100644 index c4ad2085f..000000000 --- a/java/com/android/voicemailomtp/sms/OmtpMessageReceiver.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.annotation.TargetApi; -import android.content.BroadcastReceiver; -import android.content.ContentUris; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.os.UserManager; -import android.telecom.PhoneAccountHandle; -import android.telephony.VisualVoicemailSms; -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpService; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.Voicemail; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.protocol.VisualVoicemailProtocol; -import com.android.voicemailomtp.settings.VisualVoicemailSettingsUtil; -import com.android.voicemailomtp.sync.OmtpVvmSyncService; -import com.android.voicemailomtp.sync.SyncOneTask; -import com.android.voicemailomtp.sync.SyncTask; -import com.android.voicemailomtp.sync.VoicemailsQueryHelper; -import com.android.voicemailomtp.utils.VoicemailDatabaseUtil; - -/** Receive SMS messages and send for processing by the OMTP visual voicemail source. */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class OmtpMessageReceiver extends BroadcastReceiver { - - private static final String TAG = "OmtpMessageReceiver"; - - private Context mContext; - - @Override - public void onReceive(Context context, Intent intent) { - mContext = context; - VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpService.EXTRA_VOICEMAIL_SMS); - PhoneAccountHandle phone = sms.getPhoneAccountHandle(); - - if (phone == null) { - // This should never happen - VvmLog.i(TAG, "Received message for null phone account"); - return; - } - - if (!context.getSystemService(UserManager.class).isUserUnlocked()) { - VvmLog.i(TAG, "Received message on locked device"); - // LegacyModeSmsHandler can handle new message notifications without storage access - LegacyModeSmsHandler.handle(context, sms); - // A full sync will happen after the device is unlocked, so nothing else need to be - // done. - return; - } - - OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext, phone); - if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phone)) { - if (helper.isLegacyModeEnabled()) { - LegacyModeSmsHandler.handle(context, sms); - } else { - VvmLog.i(TAG, "Received vvm message for disabled vvm source."); - } - return; - } - - String eventType = sms.getPrefix(); - Bundle data = sms.getFields(); - - if (eventType == null || data == null) { - VvmLog.e(TAG, "Unparsable VVM SMS received, ignoring"); - return; - } - - if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) { - SyncMessage message = new SyncMessage(data); - - VvmLog.v(TAG, "Received SYNC sms for " + phone + - " with event " + message.getSyncTriggerEvent()); - processSync(phone, message); - } else if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) { - VvmLog.v(TAG, "Received Status sms for " + phone); - // If the STATUS SMS is initiated by ActivationTask the TaskSchedulerService will reject - // the follow request. Providing the data will also prevent ActivationTask from - // requesting another STATUS SMS. The following task will only run if the carrier - // spontaneous send a STATUS SMS, in that case, the VVM service should be reactivated. - ActivationTask.start(context, phone, data); - } else { - VvmLog.w(TAG, "Unknown prefix: " + eventType); - VisualVoicemailProtocol protocol = helper.getProtocol(); - if (protocol == null) { - return; - } - Bundle statusData = helper.getProtocol() - .translateStatusSmsBundle(helper, eventType, data); - if (statusData != null) { - VvmLog.i(TAG, "Protocol recognized the SMS as STATUS, activating"); - ActivationTask.start(context, phone, data); - } - } - } - - /** - * A sync message has two purposes: to signal a new voicemail message, and to indicate the - * voicemails on the server have changed remotely (usually through the TUI). Save the new - * message to the voicemail provider if it is the former case and perform a full sync in the - * latter case. - * - * @param message The sync message to extract data from. - */ - private void processSync(PhoneAccountHandle phone, SyncMessage message) { - switch (message.getSyncTriggerEvent()) { - case OmtpConstants.NEW_MESSAGE: - if (!OmtpConstants.VOICE.equals(message.getContentType())) { - VvmLog.i(TAG, "Non-voice message of type '" + message.getContentType() - + "' received, ignoring"); - return; - } - - Voicemail.Builder builder = Voicemail.createForInsertion( - message.getTimestampMillis(), message.getSender()) - .setPhoneAccount(phone) - .setSourceData(message.getId()) - .setDuration(message.getLength()) - .setSourcePackage(mContext.getPackageName()); - Voicemail voicemail = builder.build(); - - VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext); - if (queryHelper.isVoicemailUnique(voicemail)) { - Uri uri = VoicemailDatabaseUtil.insert(mContext, voicemail); - voicemail = builder.setId(ContentUris.parseId(uri)).setUri(uri).build(); - SyncOneTask.start(mContext, phone, voicemail); - } - break; - case OmtpConstants.MAILBOX_UPDATE: - SyncTask.start(mContext, phone, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY); - break; - case OmtpConstants.GREETINGS_UPDATE: - // Not implemented in V1 - break; - default: - VvmLog.e(TAG, - "Unrecognized sync trigger event: " + message.getSyncTriggerEvent()); - break; - } - } -} diff --git a/java/com/android/voicemailomtp/sms/OmtpMessageSender.java b/java/com/android/voicemailomtp/sms/OmtpMessageSender.java deleted file mode 100644 index 2323e4bcf..000000000 --- a/java/com/android/voicemailomtp/sms/OmtpMessageSender.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.app.PendingIntent; -import android.content.Context; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; -import android.telephony.VisualVoicemailService; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.TelephonyManagerStub; -import com.android.voicemailomtp.VvmLog; -import java.io.UnsupportedEncodingException; -import java.util.Locale; - -/** - * Send client originated OMTP messages to the OMTP server. - * <p> - * Uses {@link PendingIntent} instead of a call back to notify when the message is - * sent. This is primarily to keep the implementation simple and reuse what the underlying - * {@link SmsManager} interface provides. - * <p> - * Provides simple APIs to send different types of mobile originated OMTP SMS to the VVM server. - */ -public abstract class OmtpMessageSender { - protected static final String TAG = "OmtpMessageSender"; - protected final Context mContext; - protected final PhoneAccountHandle mPhoneAccountHandle; - protected final short mApplicationPort; - protected final String mDestinationNumber; - - - public OmtpMessageSender(Context context, PhoneAccountHandle phoneAccountHandle, - short applicationPort, - String destinationNumber) { - mContext = context; - mPhoneAccountHandle = phoneAccountHandle; - mApplicationPort = applicationPort; - mDestinationNumber = destinationNumber; - } - - /** - * Sends a request to the VVM server to activate VVM for the current subscriber. - * - * @param sentIntent If not NULL this PendingIntent is broadcast when the message is - * successfully sent, or failed. - */ - public void requestVvmActivation(@Nullable PendingIntent sentIntent) {} - - /** - * Sends a request to the VVM server to deactivate VVM for the current subscriber. - * - * @param sentIntent If not NULL this PendingIntent is broadcast when the message is - * successfully sent, or failed. - */ - public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) {} - - /** - * Send a request to the VVM server to get account status of the current subscriber. - * - * @param sentIntent If not NULL this PendingIntent is broadcast when the message is - * successfully sent, or failed. - */ - public void requestVvmStatus(@Nullable PendingIntent sentIntent) {} - - protected void sendSms(String text, PendingIntent sentIntent) { - VisualVoicemailService - .sendVisualVoicemailSms(mContext, mPhoneAccountHandle, mDestinationNumber, - mApplicationPort, text, sentIntent); - } - - protected void appendField(StringBuilder sb, String field, Object value) { - sb.append(field).append(OmtpConstants.SMS_KEY_VALUE_SEPARATOR).append(value); - } -} diff --git a/java/com/android/voicemailomtp/sms/OmtpStandardMessageSender.java b/java/com/android/voicemailomtp/sms/OmtpStandardMessageSender.java deleted file mode 100644 index aa8374781..000000000 --- a/java/com/android/voicemailomtp/sms/OmtpStandardMessageSender.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.app.PendingIntent; -import android.content.Context; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; -import android.text.TextUtils; -import com.android.voicemailomtp.OmtpConstants; - -/** - * A implementation of the OmtpMessageSender using the standard OMTP sms protocol. - */ -public class OmtpStandardMessageSender extends OmtpMessageSender { - private final String mClientType; - private final String mProtocolVersion; - private final String mClientPrefix; - - /** - * Creates a new instance of OmtpStandardMessageSender. - * - * @param applicationPort If set to a value > 0 then a binary sms is sent to this port number. - * Otherwise, a standard text SMS is sent. - * @param destinationNumber Destination number to be used. - * @param clientType The "ct" field to be set in the MO message. This is the value used by the - * VVM server to identify the client. Certain VVM servers require a specific agreed - * value for this field. - * @param protocolVersion OMTP protocol version. - * @param clientPrefix The client prefix requested to be used by the server in its MT messages. - */ - public OmtpStandardMessageSender(Context context, PhoneAccountHandle phoneAccountHandle, - short applicationPort, - String destinationNumber, String clientType, String protocolVersion, - String clientPrefix) { - super(context, phoneAccountHandle, applicationPort, destinationNumber); - mClientType = clientType; - mProtocolVersion = protocolVersion; - mClientPrefix = clientPrefix; - } - - // Activate message: - // V1.1: Activate:pv=<value>;ct=<value> - // V1.2: Activate:pv=<value>;ct=<value>;pt=<value>;<Clientprefix> - // V1.3: Activate:pv=<value>;ct=<value>;pt=<value>;<Clientprefix> - @Override - public void requestVvmActivation(@Nullable PendingIntent sentIntent) { - StringBuilder sb = new StringBuilder().append(OmtpConstants.ACTIVATE_REQUEST); - - appendProtocolVersionAndClientType(sb); - if (TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_2) || - TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_3)) { - appendApplicationPort(sb); - appendClientPrefix(sb); - } - - sendSms(sb.toString(), sentIntent); - } - - // Deactivate message: - // V1.1: Deactivate:pv=<value>;ct=<string> - // V1.2: Deactivate:pv=<value>;ct=<string> - // V1.3: Deactivate:pv=<value>;ct=<string> - @Override - public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) { - StringBuilder sb = new StringBuilder().append(OmtpConstants.DEACTIVATE_REQUEST); - appendProtocolVersionAndClientType(sb); - - sendSms(sb.toString(), sentIntent); - } - - // Status message: - // V1.1: STATUS - // V1.2: STATUS - // V1.3: STATUS:pv=<value>;ct=<value>;pt=<value>;<Clientprefix> - @Override - public void requestVvmStatus(@Nullable PendingIntent sentIntent) { - StringBuilder sb = new StringBuilder().append(OmtpConstants.STATUS_REQUEST); - - if (TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_3)) { - appendProtocolVersionAndClientType(sb); - appendApplicationPort(sb); - appendClientPrefix(sb); - } - - sendSms(sb.toString(), sentIntent); - } - - private void appendProtocolVersionAndClientType(StringBuilder sb) { - sb.append(OmtpConstants.SMS_PREFIX_SEPARATOR); - appendField(sb, OmtpConstants.PROTOCOL_VERSION, mProtocolVersion); - sb.append(OmtpConstants.SMS_FIELD_SEPARATOR); - appendField(sb, OmtpConstants.CLIENT_TYPE, mClientType); - } - - private void appendApplicationPort(StringBuilder sb) { - sb.append(OmtpConstants.SMS_FIELD_SEPARATOR); - appendField(sb, OmtpConstants.APPLICATION_PORT, mApplicationPort); - } - - private void appendClientPrefix(StringBuilder sb) { - sb.append(OmtpConstants.SMS_FIELD_SEPARATOR); - sb.append(mClientPrefix); - } -} diff --git a/java/com/android/voicemailomtp/sms/StatusMessage.java b/java/com/android/voicemailomtp/sms/StatusMessage.java deleted file mode 100644 index 3dfd4973e..000000000 --- a/java/com/android/voicemailomtp/sms/StatusMessage.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.os.Bundle; -import com.android.voicemailomtp.NeededForTesting; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.VisualVoicemailPreferences; -import com.android.voicemailomtp.VvmLog; - -/** - * Structured data representation of OMTP STATUS message. - * - * The getters will return null if the field was not set in the message body or it could not be - * parsed. - */ -public class StatusMessage { - // NOTE: Following Status SMS fields are not yet parsed, as they do not seem - // to be useful for initial omtp source implementation. - // lang, g_len, vs_len, pw_len, pm, gm, vtc, vt - - private final String mProvisioningStatus; - private final String mStatusReturnCode; - private final String mSubscriptionUrl; - private final String mServerAddress; - private final String mTuiAccessNumber; - private final String mClientSmsDestinationNumber; - private final String mImapPort; - private final String mImapUserName; - private final String mImapPassword; - private final String mSmtpPort; - private final String mSmtpUserName; - private final String mSmtpPassword; - private final String mTuiPasswordLength; - - @Override - public String toString() { - return "StatusMessage [mProvisioningStatus=" + mProvisioningStatus - + ", mStatusReturnCode=" + mStatusReturnCode - + ", mSubscriptionUrl=" + mSubscriptionUrl - + ", mServerAddress=" + mServerAddress - + ", mTuiAccessNumber=" + mTuiAccessNumber - + ", mClientSmsDestinationNumber=" + mClientSmsDestinationNumber - + ", mImapPort=" + mImapPort - + ", mImapUserName=" + mImapUserName - + ", mImapPassword=" + VvmLog.pii(mImapPassword) - + ", mSmtpPort=" + mSmtpPort - + ", mSmtpUserName=" + mSmtpUserName - + ", mSmtpPassword=" + VvmLog.pii(mSmtpPassword) - + ", mTuiPasswordLength=" + mTuiPasswordLength + "]"; - } - - public StatusMessage(Bundle wrappedData) { - mProvisioningStatus = unquote(getString(wrappedData, OmtpConstants.PROVISIONING_STATUS)); - mStatusReturnCode = getString(wrappedData, OmtpConstants.RETURN_CODE); - mSubscriptionUrl = getString(wrappedData, OmtpConstants.SUBSCRIPTION_URL); - mServerAddress = getString(wrappedData, OmtpConstants.SERVER_ADDRESS); - mTuiAccessNumber = getString(wrappedData, OmtpConstants.TUI_ACCESS_NUMBER); - mClientSmsDestinationNumber = getString(wrappedData, - OmtpConstants.CLIENT_SMS_DESTINATION_NUMBER); - mImapPort = getString(wrappedData, OmtpConstants.IMAP_PORT); - mImapUserName = getString(wrappedData, OmtpConstants.IMAP_USER_NAME); - mImapPassword = getString(wrappedData, OmtpConstants.IMAP_PASSWORD); - mSmtpPort = getString(wrappedData, OmtpConstants.SMTP_PORT); - mSmtpUserName = getString(wrappedData, OmtpConstants.SMTP_USER_NAME); - mSmtpPassword = getString(wrappedData, OmtpConstants.SMTP_PASSWORD); - mTuiPasswordLength = getString(wrappedData, OmtpConstants.TUI_PASSWORD_LENGTH); - } - - private static String unquote(String string) { - if (string.length() < 2) { - return string; - } - if (string.startsWith("\"") && string.endsWith("\"")) { - return string.substring(1, string.length() - 1); - } - return string; - } - - /** - * @return the subscriber's VVM provisioning status. - */ - public String getProvisioningStatus() { - return mProvisioningStatus; - } - - /** - * @return the return-code of the status SMS. - */ - public String getReturnCode() { - return mStatusReturnCode; - } - - /** - * @return the URL of the voicemail server. This is the URL to send the users to for subscribing - * to the visual voicemail service. - */ - @NeededForTesting - public String getSubscriptionUrl() { - return mSubscriptionUrl; - } - - /** - * @return the voicemail server address. Either server IP address or fully qualified domain - * name. - */ - public String getServerAddress() { - return mServerAddress; - } - - /** - * @return the Telephony User Interface number to call to access voicemails directly from the - * IVR. - */ - @NeededForTesting - public String getTuiAccessNumber() { - return mTuiAccessNumber; - } - - /** - * @return the number to which client originated SMSes should be sent to. - */ - @NeededForTesting - public String getClientSmsDestinationNumber() { - return mClientSmsDestinationNumber; - } - - /** - * @return the IMAP server port to talk to. - */ - public String getImapPort() { - return mImapPort; - } - - /** - * @return the IMAP user name to be used for authentication. - */ - public String getImapUserName() { - return mImapUserName; - } - - /** - * @return the IMAP password to be used for authentication. - */ - public String getImapPassword() { - return mImapPassword; - } - - /** - * @return the SMTP server port to talk to. - */ - @NeededForTesting - public String getSmtpPort() { - return mSmtpPort; - } - - /** - * @return the SMTP user name to be used for SMTP authentication. - */ - @NeededForTesting - public String getSmtpUserName() { - return mSmtpUserName; - } - - /** - * @return the SMTP password to be used for SMTP authentication. - */ - @NeededForTesting - public String getSmtpPassword() { - return mSmtpPassword; - } - - public String getTuiPasswordLength() { - return mTuiPasswordLength; - } - - private static String getString(Bundle bundle, String key) { - String value = bundle.getString(key); - if (value == null) { - return ""; - } - return value; - } - - /** - * Saves a StatusMessage to the {@link VisualVoicemailPreferences}. Not all fields are saved. - */ - public VisualVoicemailPreferences.Editor putStatus(VisualVoicemailPreferences.Editor editor) { - return editor - .putString(OmtpConstants.IMAP_PORT, getImapPort()) - .putString(OmtpConstants.SERVER_ADDRESS, getServerAddress()) - .putString(OmtpConstants.IMAP_USER_NAME, getImapUserName()) - .putString(OmtpConstants.IMAP_PASSWORD, getImapPassword()) - .putString(OmtpConstants.TUI_PASSWORD_LENGTH, getTuiPasswordLength()); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/sms/StatusSmsFetcher.java b/java/com/android/voicemailomtp/sms/StatusSmsFetcher.java deleted file mode 100644 index 4e10c0e43..000000000 --- a/java/com/android/voicemailomtp/sms/StatusSmsFetcher.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sms; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.support.annotation.MainThread; -import android.support.annotation.Nullable; -import android.support.annotation.WorkerThread; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; -import android.telephony.VisualVoicemailSms; -import com.android.voicemailomtp.Assert; -import com.android.voicemailomtp.OmtpConstants; -import com.android.voicemailomtp.OmtpService; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.protocol.VisualVoicemailProtocol; -import java.io.Closeable; -import java.io.IOException; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** Intercepts a incoming STATUS SMS with a blocking call. */ -@SuppressWarnings("AndroidApiChecker") /* CompletableFuture is java8*/ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class StatusSmsFetcher extends BroadcastReceiver implements Closeable { - - private static final String TAG = "VvmStatusSmsFetcher"; - - private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000; - - private static final String ACTION_REQUEST_SENT_INTENT - = "com.android.voicemailomtp.sms.REQUEST_SENT"; - private static final int ACTION_REQUEST_SENT_REQUEST_CODE = 0; - - private CompletableFuture<Bundle> mFuture = new CompletableFuture<>(); - - private final Context mContext; - private final PhoneAccountHandle mPhoneAccountHandle; - - public StatusSmsFetcher(Context context, PhoneAccountHandle phoneAccountHandle) { - mContext = context; - mPhoneAccountHandle = phoneAccountHandle; - IntentFilter filter = new IntentFilter(ACTION_REQUEST_SENT_INTENT); - filter.addAction(OmtpService.ACTION_SMS_RECEIVED); - context.registerReceiver(this, filter); - } - - @Override - public void close() throws IOException { - mContext.unregisterReceiver(this); - } - - @WorkerThread - @Nullable - public Bundle get() throws InterruptedException, ExecutionException, TimeoutException, - CancellationException { - Assert.isNotMainThread(); - return mFuture.get(STATUS_SMS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - } - - public PendingIntent getSentIntent() { - Intent intent = new Intent(ACTION_REQUEST_SENT_INTENT); - intent.setPackage(mContext.getPackageName()); - // Because the receiver is registered dynamically, implicit intent must be used. - // There should only be a single status SMS request at a time. - return PendingIntent.getBroadcast(mContext, ACTION_REQUEST_SENT_REQUEST_CODE, intent, - PendingIntent.FLAG_CANCEL_CURRENT); - } - - @Override - @MainThread - public void onReceive(Context context, Intent intent) { - Assert.isMainThread(); - if (ACTION_REQUEST_SENT_INTENT.equals(intent.getAction())) { - int resultCode = getResultCode(); - - if (resultCode == Activity.RESULT_OK) { - VvmLog.d(TAG, "Request SMS successfully sent"); - return; - } - - VvmLog.e(TAG, "Request SMS send failed: " + sentSmsResultToString(resultCode)); - mFuture.cancel(true); - return; - } - - VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpService.EXTRA_VOICEMAIL_SMS); - - if (!mPhoneAccountHandle.equals(sms.getPhoneAccountHandle())) { - return; - } - String eventType = sms.getPrefix(); - - if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) { - mFuture.complete(sms.getFields()); - return; - } - - if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) { - return; - } - - VvmLog.i(TAG, "VVM SMS with event " + eventType - + " received, attempting to translate to STATUS SMS"); - OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, - mPhoneAccountHandle); - VisualVoicemailProtocol protocol = helper.getProtocol(); - if (protocol == null) { - return; - } - Bundle translatedBundle = protocol.translateStatusSmsBundle(helper, eventType, - sms.getFields()); - - if (translatedBundle != null) { - VvmLog.i(TAG, "Translated to STATUS SMS"); - mFuture.complete(translatedBundle); - } - } - - private static String sentSmsResultToString(int resultCode) { - switch (resultCode) { - case Activity.RESULT_OK: - return "OK"; - case SmsManager.RESULT_ERROR_GENERIC_FAILURE: - return "RESULT_ERROR_GENERIC_FAILURE"; - case SmsManager.RESULT_ERROR_NO_SERVICE: - return "RESULT_ERROR_GENERIC_FAILURE"; - case SmsManager.RESULT_ERROR_NULL_PDU: - return "RESULT_ERROR_GENERIC_FAILURE"; - case SmsManager.RESULT_ERROR_RADIO_OFF: - return "RESULT_ERROR_GENERIC_FAILURE"; - default: - return "UNKNOWN CODE: " + resultCode; - } - } -} diff --git a/java/com/android/voicemailomtp/sms/SyncMessage.java b/java/com/android/voicemailomtp/sms/SyncMessage.java deleted file mode 100644 index 89cfc0f19..000000000 --- a/java/com/android/voicemailomtp/sms/SyncMessage.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import com.android.voicemailomtp.NeededForTesting; -import com.android.voicemailomtp.OmtpConstants; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Locale; - -/** - * Structured data representation of an OMTP SYNC message. - * - * Getters will return null if the field was not set in the message body or it could not be parsed. - */ -public class SyncMessage { - // Sync event that triggered this message. - private final String mSyncTriggerEvent; - // Total number of new messages on the server. - private final int mNewMessageCount; - // UID of the new message. - private final String mMessageId; - // Length of the message. - private final int mMessageLength; - // Content type (voice, video, fax...) of the new message. - private final String mContentType; - // Sender of the new message. - private final String mSender; - // Timestamp (in millis) of the new message. - private final long mMsgTimeMillis; - - @Override - public String toString() { - return "SyncMessage [mSyncTriggerEvent=" + mSyncTriggerEvent - + ", mNewMessageCount=" + mNewMessageCount - + ", mMessageId=" + mMessageId - + ", mMessageLength=" + mMessageLength - + ", mContentType=" + mContentType - + ", mSender=" + mSender - + ", mMsgTimeMillis=" + mMsgTimeMillis + "]"; - } - - public SyncMessage(Bundle wrappedData) { - mSyncTriggerEvent = getString(wrappedData, OmtpConstants.SYNC_TRIGGER_EVENT); - mMessageId = getString(wrappedData, OmtpConstants.MESSAGE_UID); - mMessageLength = getInt(wrappedData, OmtpConstants.MESSAGE_LENGTH); - mContentType = getString(wrappedData, OmtpConstants.CONTENT_TYPE); - mSender = getString(wrappedData, OmtpConstants.SENDER); - mNewMessageCount = getInt(wrappedData, OmtpConstants.NUM_MESSAGE_COUNT); - mMsgTimeMillis = parseTime(wrappedData.getString(OmtpConstants.TIME)); - } - - private static long parseTime(@Nullable String value) { - if (value == null) { - return 0L; - } - try { - return new SimpleDateFormat( - OmtpConstants.DATE_TIME_FORMAT, Locale.US) - .parse(value).getTime(); - } catch (ParseException e) { - return 0L; - } - } - /** - * @return the event that triggered the sync message. This is a mandatory field and must always - * be set. - */ - public String getSyncTriggerEvent() { - return mSyncTriggerEvent; - } - - /** - * @return the number of new messages stored on the voicemail server. - */ - @NeededForTesting - public int getNewMessageCount() { - return mNewMessageCount; - } - - /** - * @return the message ID of the new message. - * <p> - * Expected to be set only for - * {@link com.android.voicemailomtp.OmtpConstants#NEW_MESSAGE} - */ - public String getId() { - return mMessageId; - } - - /** - * @return the content type of the new message. - * <p> - * Expected to be set only for - * {@link com.android.voicemailomtp.OmtpConstants#NEW_MESSAGE} - */ - @NeededForTesting - public String getContentType() { - return mContentType; - } - - /** - * @return the message length of the new message. - * <p> - * Expected to be set only for - * {@link com.android.voicemailomtp.OmtpConstants#NEW_MESSAGE} - */ - public int getLength() { - return mMessageLength; - } - - /** - * @return the sender's phone number of the new message specified as MSISDN. - * <p> - * Expected to be set only for - * {@link com.android.voicemailomtp.OmtpConstants#NEW_MESSAGE} - */ - public String getSender() { - return mSender; - } - - /** - * @return the timestamp as milliseconds for the new message. - * <p> - * Expected to be set only for - * {@link com.android.voicemailomtp.OmtpConstants#NEW_MESSAGE} - */ - public long getTimestampMillis() { - return mMsgTimeMillis; - } - - private static int getInt(Bundle wrappedData, String key) { - String value = wrappedData.getString(key); - if (value == null) { - return 0; - } - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return 0; - } - } - - private static String getString(Bundle wrappedData, String key) { - String value = wrappedData.getString(key); - if (value == null) { - return ""; - } - return value; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/sms/Vvm3MessageSender.java b/java/com/android/voicemailomtp/sms/Vvm3MessageSender.java deleted file mode 100644 index 02e465967..000000000 --- a/java/com/android/voicemailomtp/sms/Vvm3MessageSender.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sms; - -import android.app.PendingIntent; -import android.content.Context; -import android.support.annotation.Nullable; -import android.telecom.PhoneAccountHandle; -import android.telephony.SmsManager; - -public class Vvm3MessageSender extends OmtpMessageSender { - - /** - * Creates a new instance of Vvm3MessageSender. - * - * @param applicationPort If set to a value > 0 then a binary sms is sent to this port number. - * Otherwise, a standard text SMS is sent. - */ - public Vvm3MessageSender(Context context, PhoneAccountHandle phoneAccountHandle, - short applicationPort, String destinationNumber) { - super(context, phoneAccountHandle, applicationPort, destinationNumber); - } - - @Override - public void requestVvmActivation(@Nullable PendingIntent sentIntent) { - // Activation not supported for VVM3, send a status request instead. - requestVvmStatus(sentIntent); - } - - @Override - public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) { - // Deactivation not supported for VVM3, do nothing - } - - - @Override - public void requestVvmStatus(@Nullable PendingIntent sentIntent) { - // Status message: - // STATUS - StringBuilder sb = new StringBuilder().append("STATUS"); - sendSms(sb.toString(), sentIntent); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/commons/io/IOUtils.java b/java/com/android/voicemailomtp/src/org/apache/commons/io/IOUtils.java deleted file mode 100644 index b41450790..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/commons/io/IOUtils.java +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -/** - * General IO stream manipulation utilities. - * <p> - * This class provides static utility methods for input/output operations. - * <ul> - * <li>closeQuietly - these methods close a stream ignoring nulls and exceptions - * <li>toXxx/read - these methods read data from a stream - * <li>write - these methods write data to a stream - * <li>copy - these methods copy all the data from one stream to another - * <li>contentEquals - these methods compare the content of two streams - * </ul> - * <p> - * The byte-to-char methods and char-to-byte methods involve a conversion step. - * Two methods are provided in each case, one that uses the platform default - * encoding and the other which allows you to specify an encoding. You are - * encouraged to always specify an encoding because relying on the platform - * default can lead to unexpected results, for example when moving from - * development to production. - * <p> - * All the methods in this class that read a stream are buffered internally. - * This means that there is no cause to use a <code>BufferedInputStream</code> - * or <code>BufferedReader</code>. The default buffer size of 4K has been shown - * to be efficient in tests. - * <p> - * Wherever possible, the methods in this class do <em>not</em> flush or close - * the stream. This is to avoid making non-portable assumptions about the - * streams' origin and further use. Thus the caller is still responsible for - * closing streams after use. - * <p> - * Origin of code: Excalibur. - * - * @author Peter Donald - * @author Jeff Turner - * @author Matthew Hawthorne - * @author Stephen Colebourne - * @author Gareth Davis - * @author Ian Springer - * @author Niall Pemberton - * @author Sandy McArthur - * @version $Id: IOUtils.java 481854 2006-12-03 18:30:07Z scolebourne $ - */ -public class IOUtils { - // NOTE: This class is focussed on InputStream, OutputStream, Reader and - // Writer. Each method should take at least one of these as a parameter, - // or return one of them. - - /** - * The Unix directory separator character. - */ - public static final char DIR_SEPARATOR_UNIX = '/'; - /** - * The Windows directory separator character. - */ - public static final char DIR_SEPARATOR_WINDOWS = '\\'; - /** - * The system directory separator character. - */ - public static final char DIR_SEPARATOR = File.separatorChar; - /** - * The Unix line separator string. - */ - public static final String LINE_SEPARATOR_UNIX = "\n"; - /** - * The Windows line separator string. - */ - public static final String LINE_SEPARATOR_WINDOWS = "\r\n"; - /** - * The system line separator string. - */ - public static final String LINE_SEPARATOR; - static { - // avoid security issues - StringWriter buf = new StringWriter(4); - PrintWriter out = new PrintWriter(buf); - out.println(); - LINE_SEPARATOR = buf.toString(); - } - - /** - * The default buffer size to use. - */ - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - /** - * Instances should NOT be constructed in standard programming. - */ - public IOUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - * Unconditionally close an <code>Reader</code>. - * <p> - * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param input the Reader to close, may be null or already closed - */ - public static void closeQuietly(Reader input) { - try { - if (input != null) { - input.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close a <code>Writer</code>. - * <p> - * Equivalent to {@link Writer#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param output the Writer to close, may be null or already closed - */ - public static void closeQuietly(Writer output) { - try { - if (output != null) { - output.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close an <code>InputStream</code>. - * <p> - * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param input the InputStream to close, may be null or already closed - */ - public static void closeQuietly(InputStream input) { - try { - if (input != null) { - input.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close an <code>OutputStream</code>. - * <p> - * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param output the OutputStream to close, may be null or already closed - */ - public static void closeQuietly(OutputStream output) { - try { - if (output != null) { - output.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - // read toByteArray - //----------------------------------------------------------------------- - /** - * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static byte[] toByteArray(InputStream input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - /** - * Get the contents of a <code>Reader</code> as a <code>byte[]</code> - * using the default character encoding of the platform. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static byte[] toByteArray(Reader input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - /** - * Get the contents of a <code>Reader</code> as a <code>byte[]</code> - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from - * @param encoding the encoding to use, null means platform default - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static byte[] toByteArray(Reader input, String encoding) - throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output, encoding); - return output.toByteArray(); - } - - /** - * Get the contents of a <code>String</code> as a <code>byte[]</code> - * using the default character encoding of the platform. - * <p> - * This is the same as {@link String#getBytes()}. - * - * @param input the <code>String</code> to convert - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#getBytes()} - */ - @Deprecated - public static byte[] toByteArray(String input) throws IOException { - return input.getBytes(); - } - - // read char[] - //----------------------------------------------------------------------- - /** - * Get the contents of an <code>InputStream</code> as a character array - * using the default character encoding of the platform. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param is the <code>InputStream</code> to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(InputStream is) throws IOException { - CharArrayWriter output = new CharArrayWriter(); - copy(is, output); - return output.toCharArray(); - } - - /** - * Get the contents of an <code>InputStream</code> as a character array - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param is the <code>InputStream</code> to read from - * @param encoding the encoding to use, null means platform default - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(InputStream is, String encoding) - throws IOException { - CharArrayWriter output = new CharArrayWriter(); - copy(is, output, encoding); - return output.toCharArray(); - } - - /** - * Get the contents of a <code>Reader</code> as a character array. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(Reader input) throws IOException { - CharArrayWriter sw = new CharArrayWriter(); - copy(input, sw); - return sw.toCharArray(); - } - - // read toString - //----------------------------------------------------------------------- - /** - * Get the contents of an <code>InputStream</code> as a String - * using the default character encoding of the platform. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(InputStream input) throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw); - return sw.toString(); - } - - /** - * Get the contents of an <code>InputStream</code> as a String - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from - * @param encoding the encoding to use, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(InputStream input, String encoding) - throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw, encoding); - return sw.toString(); - } - - /** - * Get the contents of a <code>Reader</code> as a String. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(Reader input) throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw); - return sw.toString(); - } - - /** - * Get the contents of a <code>byte[]</code> as a String - * using the default character encoding of the platform. - * - * @param input the byte array to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#String(byte[])} - */ - @Deprecated - public static String toString(byte[] input) throws IOException { - return new String(input); - } - - /** - * Get the contents of a <code>byte[]</code> as a String - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * - * @param input the byte array to read from - * @param encoding the encoding to use, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#String(byte[],String)} - */ - @Deprecated - public static String toString(byte[] input, String encoding) - throws IOException { - if (encoding == null) { - return new String(input); - } else { - return new String(input, encoding); - } - } - - // readLines - //----------------------------------------------------------------------- - /** - * Get the contents of an <code>InputStream</code> as a list of Strings, - * one entry per line, using the default character encoding of the platform. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List<String> readLines(InputStream input) throws IOException { - InputStreamReader reader = new InputStreamReader(input); - return readLines(reader); - } - - /** - * Get the contents of an <code>InputStream</code> as a list of Strings, - * one entry per line, using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from, not null - * @param encoding the encoding to use, null means platform default - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List<String> readLines(InputStream input, String encoding) throws IOException { - if (encoding == null) { - return readLines(input); - } else { - InputStreamReader reader = new InputStreamReader(input, encoding); - return readLines(reader); - } - } - - /** - * Get the contents of a <code>Reader</code> as a list of Strings, - * one entry per line. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List<String> readLines(Reader input) throws IOException { - BufferedReader reader = new BufferedReader(input); - List<String> list = new ArrayList<String>(); - String line = reader.readLine(); - while (line != null) { - list.add(line); - line = reader.readLine(); - } - return list; - } - - //----------------------------------------------------------------------- - /** - * Convert the specified string to an input stream, encoded as bytes - * using the default character encoding of the platform. - * - * @param input the string to convert - * @return an input stream - * @since Commons IO 1.1 - */ - public static InputStream toInputStream(String input) { - byte[] bytes = input.getBytes(); - return new ByteArrayInputStream(bytes); - } - - /** - * Convert the specified string to an input stream, encoded as bytes - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * - * @param input the string to convert - * @param encoding the encoding to use, null means platform default - * @throws IOException if the encoding is invalid - * @return an input stream - * @since Commons IO 1.1 - */ - public static InputStream toInputStream(String input, String encoding) throws IOException { - byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes(); - return new ByteArrayInputStream(bytes); - } - - // write byte[] - //----------------------------------------------------------------------- - /** - * Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the <code>OutputStream</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code> - * using the default character encoding of the platform. - * <p> - * This method uses {@link String#String(byte[])}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the <code>Writer</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, Writer output) throws IOException { - if (data != null) { - output.write(new String(data)); - } - } - - /** - * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code> - * using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method uses {@link String#String(byte[], String)}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the <code>Writer</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, Writer output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(new String(data, encoding)); - } - } - } - - // write char[] - //----------------------------------------------------------------------- - /** - * Writes chars from a <code>char[]</code> to a <code>Writer</code> - * using the default character encoding of the platform. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the <code>Writer</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, Writer output) throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes chars from a <code>char[]</code> to bytes on an - * <code>OutputStream</code>. - * <p> - * This method uses {@link String#String(char[])} and - * {@link String#getBytes()}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the <code>OutputStream</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, OutputStream output) - throws IOException { - if (data != null) { - output.write(new String(data).getBytes()); - } - } - - /** - * Writes chars from a <code>char[]</code> to bytes on an - * <code>OutputStream</code> using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method uses {@link String#String(char[])} and - * {@link String#getBytes(String)}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the <code>OutputStream</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, OutputStream output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(new String(data).getBytes(encoding)); - } - } - } - - // write String - //----------------------------------------------------------------------- - /** - * Writes chars from a <code>String</code> to a <code>Writer</code>. - * - * @param data the <code>String</code> to write, null ignored - * @param output the <code>Writer</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, Writer output) throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes chars from a <code>String</code> to bytes on an - * <code>OutputStream</code> using the default character encoding of the - * platform. - * <p> - * This method uses {@link String#getBytes()}. - * - * @param data the <code>String</code> to write, null ignored - * @param output the <code>OutputStream</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data.getBytes()); - } - } - - /** - * Writes chars from a <code>String</code> to bytes on an - * <code>OutputStream</code> using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method uses {@link String#getBytes(String)}. - * - * @param data the <code>String</code> to write, null ignored - * @param output the <code>OutputStream</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, OutputStream output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(data.getBytes(encoding)); - } - } - } - - // write StringBuffer - //----------------------------------------------------------------------- - /** - * Writes chars from a <code>StringBuffer</code> to a <code>Writer</code>. - * - * @param data the <code>StringBuffer</code> to write, null ignored - * @param output the <code>Writer</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, Writer output) - throws IOException { - if (data != null) { - output.write(data.toString()); - } - } - - /** - * Writes chars from a <code>StringBuffer</code> to bytes on an - * <code>OutputStream</code> using the default character encoding of the - * platform. - * <p> - * This method uses {@link String#getBytes()}. - * - * @param data the <code>StringBuffer</code> to write, null ignored - * @param output the <code>OutputStream</code> to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data.toString().getBytes()); - } - } - - /** - * Writes chars from a <code>StringBuffer</code> to bytes on an - * <code>OutputStream</code> using the specified character encoding. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method uses {@link String#getBytes(String)}. - * - * @param data the <code>StringBuffer</code> to write, null ignored - * @param output the <code>OutputStream</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, OutputStream output, - String encoding) throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(data.toString().getBytes(encoding)); - } - } - } - - // writeLines - //----------------------------------------------------------------------- - /** - * Writes the <code>toString()</code> value of each item in a collection to - * an <code>OutputStream</code> line by line, using the default character - * encoding of the platform and the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the <code>OutputStream</code> to write to, not null, not closed - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection<Object> lines, String lineEnding, - OutputStream output) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - output.write(line.toString().getBytes()); - } - output.write(lineEnding.getBytes()); - } - } - - /** - * Writes the <code>toString()</code> value of each item in a collection to - * an <code>OutputStream</code> line by line, using the specified character - * encoding and the specified line ending. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the <code>OutputStream</code> to write to, not null, not closed - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection<Object> lines, String lineEnding, - OutputStream output, String encoding) throws IOException { - if (encoding == null) { - writeLines(lines, lineEnding, output); - } else { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - output.write(line.toString().getBytes(encoding)); - } - output.write(lineEnding.getBytes(encoding)); - } - } - } - - /** - * Writes the <code>toString()</code> value of each item in a collection to - * a <code>Writer</code> line by line, using the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param writer the <code>Writer</code> to write to, not null, not closed - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection<Object> lines, String lineEnding, - Writer writer) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - writer.write(line.toString()); - } - writer.write(lineEnding); - } - } - - // copy from InputStream - //----------------------------------------------------------------------- - /** - * Copy bytes from an <code>InputStream</code> to an - * <code>OutputStream</code>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * <p> - * Large streams (over 2GB) will return a bytes copied value of - * <code>-1</code> after the copy has completed since the correct - * number of bytes cannot be returned as an int. For large streams - * use the <code>copyLarge(InputStream, OutputStream)</code> method. - * - * @param input the <code>InputStream</code> to read from - * @param output the <code>OutputStream</code> to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws ArithmeticException if the byte count is too large - * @since Commons IO 1.1 - */ - public static int copy(InputStream input, OutputStream output) throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copy bytes from a large (over 2GB) <code>InputStream</code> to an - * <code>OutputStream</code>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * - * @param input the <code>InputStream</code> to read from - * @param output the <code>OutputStream</code> to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.3 - */ - public static long copyLarge(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copy bytes from an <code>InputStream</code> to chars on a - * <code>Writer</code> using the default character encoding of the platform. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * <p> - * This method uses {@link InputStreamReader}. - * - * @param input the <code>InputStream</code> to read from - * @param output the <code>Writer</code> to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(InputStream input, Writer output) - throws IOException { - InputStreamReader in = new InputStreamReader(input); - copy(in, output); - } - - /** - * Copy bytes from an <code>InputStream</code> to chars on a - * <code>Writer</code> using the specified character encoding. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedInputStream</code>. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * This method uses {@link InputStreamReader}. - * - * @param input the <code>InputStream</code> to read from - * @param output the <code>Writer</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(InputStream input, Writer output, String encoding) - throws IOException { - if (encoding == null) { - copy(input, output); - } else { - InputStreamReader in = new InputStreamReader(input, encoding); - copy(in, output); - } - } - - // copy from Reader - //----------------------------------------------------------------------- - /** - * Copy chars from a <code>Reader</code> to a <code>Writer</code>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * <p> - * Large streams (over 2GB) will return a chars copied value of - * <code>-1</code> after the copy has completed since the correct - * number of chars cannot be returned as an int. For large streams - * use the <code>copyLarge(Reader, Writer)</code> method. - * - * @param input the <code>Reader</code> to read from - * @param output the <code>Writer</code> to write to - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws ArithmeticException if the character count is too large - * @since Commons IO 1.1 - */ - public static int copy(Reader input, Writer output) throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copy chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * - * @param input the <code>Reader</code> to read from - * @param output the <code>Writer</code> to write to - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.3 - */ - public static long copyLarge(Reader input, Writer output) throws IOException { - char[] buffer = new char[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copy chars from a <code>Reader</code> to bytes on an - * <code>OutputStream</code> using the default character encoding of the - * platform, and calling flush. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * <p> - * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - * <p> - * This method uses {@link OutputStreamWriter}. - * - * @param input the <code>Reader</code> to read from - * @param output the <code>OutputStream</code> to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(Reader input, OutputStream output) - throws IOException { - OutputStreamWriter out = new OutputStreamWriter(output); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - /** - * Copy chars from a <code>Reader</code> to bytes on an - * <code>OutputStream</code> using the specified character encoding, and - * calling flush. - * <p> - * This method buffers the input internally, so there is no need to use a - * <code>BufferedReader</code>. - * <p> - * Character encoding names can be found at - * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. - * <p> - * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - * <p> - * This method uses {@link OutputStreamWriter}. - * - * @param input the <code>Reader</code> to read from - * @param output the <code>OutputStream</code> to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(Reader input, OutputStream output, String encoding) - throws IOException { - if (encoding == null) { - copy(input, output); - } else { - OutputStreamWriter out = new OutputStreamWriter(output, encoding); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, - // we have to flush here. - out.flush(); - } - } - - // content equals - //----------------------------------------------------------------------- - /** - * Compare the contents of two Streams to determine if they are equal or - * not. - * <p> - * This method buffers the input internally using - * <code>BufferedInputStream</code> if they are not already buffered. - * - * @param input1 the first stream - * @param input2 the second stream - * @return true if the content of the streams are equal or they both don't - * exist, false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - */ - public static boolean contentEquals(InputStream input1, InputStream input2) - throws IOException { - if (!(input1 instanceof BufferedInputStream)) { - input1 = new BufferedInputStream(input1); - } - if (!(input2 instanceof BufferedInputStream)) { - input2 = new BufferedInputStream(input2); - } - - int ch = input1.read(); - while (-1 != ch) { - int ch2 = input2.read(); - if (ch != ch2) { - return false; - } - ch = input1.read(); - } - - int ch2 = input2.read(); - return (ch2 == -1); - } - - /** - * Compare the contents of two Readers to determine if they are equal or - * not. - * <p> - * This method buffers the input internally using - * <code>BufferedReader</code> if they are not already buffered. - * - * @param input1 the first reader - * @param input2 the second reader - * @return true if the content of the readers are equal or they both don't - * exist, false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static boolean contentEquals(Reader input1, Reader input2) - throws IOException { - if (!(input1 instanceof BufferedReader)) { - input1 = new BufferedReader(input1); - } - if (!(input2 instanceof BufferedReader)) { - input2 = new BufferedReader(input2); - } - - int ch = input1.read(); - while (-1 != ch) { - int ch2 = input2.read(); - if (ch != ch2) { - return false; - } - ch = input1.read(); - } - - int ch2 = input2.read(); - return (ch2 == -1); - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/BodyDescriptor.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/BodyDescriptor.java deleted file mode 100644 index 867c43d86..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/BodyDescriptor.java +++ /dev/null @@ -1,392 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.util.HashMap; -import java.util.Map; - -/** - * Encapsulates the values of the MIME-specific header fields - * (which starts with <code>Content-</code>). - * - * - * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $ - */ -public class BodyDescriptor { - private static Log log = LogFactory.getLog(BodyDescriptor.class); - - private String mimeType = "text/plain"; - private String boundary = null; - private String charset = "us-ascii"; - private String transferEncoding = "7bit"; - private Map<String, String> parameters = new HashMap<String, String>(); - private boolean contentTypeSet = false; - private boolean contentTransferEncSet = false; - - /** - * Creates a new root <code>BodyDescriptor</code> instance. - */ - public BodyDescriptor() { - this(null); - } - - /** - * Creates a new <code>BodyDescriptor</code> instance. - * - * @param parent the descriptor of the parent or <code>null</code> if this - * is the root descriptor. - */ - public BodyDescriptor(BodyDescriptor parent) { - if (parent != null && parent.isMimeType("multipart/digest")) { - mimeType = "message/rfc822"; - } else { - mimeType = "text/plain"; - } - } - - /** - * Should be called for each <code>Content-</code> header field of - * a MIME message or part. - * - * @param name the field name. - * @param value the field value. - */ - public void addField(String name, String value) { - - name = name.trim().toLowerCase(); - - if (name.equals("content-transfer-encoding") && !contentTransferEncSet) { - contentTransferEncSet = true; - - value = value.trim().toLowerCase(); - if (value.length() > 0) { - transferEncoding = value; - } - - } else if (name.equals("content-type") && !contentTypeSet) { - contentTypeSet = true; - - value = value.trim(); - - /* - * Unfold Content-Type value - */ - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (c == '\r' || c == '\n') { - continue; - } - sb.append(c); - } - - Map<String, String> params = getHeaderParams(sb.toString()); - - String main = params.get(""); - if (main != null) { - main = main.toLowerCase().trim(); - int index = main.indexOf('/'); - boolean valid = false; - if (index != -1) { - String type = main.substring(0, index).trim(); - String subtype = main.substring(index + 1).trim(); - if (type.length() > 0 && subtype.length() > 0) { - main = type + "/" + subtype; - valid = true; - } - } - - if (!valid) { - main = null; - } - } - String b = params.get("boundary"); - - if (main != null - && ((main.startsWith("multipart/") && b != null) - || !main.startsWith("multipart/"))) { - - mimeType = main; - } - - if (isMultipart()) { - boundary = b; - } - - String c = params.get("charset"); - if (c != null) { - c = c.trim(); - if (c.length() > 0) { - charset = c.toLowerCase(); - } - } - - /* - * Add all other parameters to parameters. - */ - parameters.putAll(params); - parameters.remove(""); - parameters.remove("boundary"); - parameters.remove("charset"); - } - } - - private Map<String, String> getHeaderParams(String headerValue) { - Map<String, String> result = new HashMap<String, String>(); - - // split main value and parameters - String main; - String rest; - if (headerValue.indexOf(";") == -1) { - main = headerValue; - rest = null; - } else { - main = headerValue.substring(0, headerValue.indexOf(";")); - rest = headerValue.substring(main.length() + 1); - } - - result.put("", main); - if (rest != null) { - char[] chars = rest.toCharArray(); - StringBuffer paramName = new StringBuffer(); - StringBuffer paramValue = new StringBuffer(); - - final byte READY_FOR_NAME = 0; - final byte IN_NAME = 1; - final byte READY_FOR_VALUE = 2; - final byte IN_VALUE = 3; - final byte IN_QUOTED_VALUE = 4; - final byte VALUE_DONE = 5; - final byte ERROR = 99; - - byte state = READY_FOR_NAME; - boolean escaped = false; - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - - switch (state) { - case ERROR: - if (c == ';') - state = READY_FOR_NAME; - break; - - case READY_FOR_NAME: - if (c == '=') { - log.error("Expected header param name, got '='"); - state = ERROR; - break; - } - - paramName = new StringBuffer(); - paramValue = new StringBuffer(); - - state = IN_NAME; - // $FALL-THROUGH$ - - case IN_NAME: - if (c == '=') { - if (paramName.length() == 0) - state = ERROR; - else - state = READY_FOR_VALUE; - break; - } - - // not '='... just add to name - paramName.append(c); - break; - - case READY_FOR_VALUE: - boolean fallThrough = false; - switch (c) { - case ' ': - case '\t': - break; // ignore spaces, especially before '"' - - case '"': - state = IN_QUOTED_VALUE; - break; - - default: - state = IN_VALUE; - fallThrough = true; - break; - } - if (!fallThrough) - break; - - // $FALL-THROUGH$ - - case IN_VALUE: - fallThrough = false; - switch (c) { - case ';': - case ' ': - case '\t': - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString().trim()); - state = VALUE_DONE; - fallThrough = true; - break; - default: - paramValue.append(c); - break; - } - if (!fallThrough) - break; - - // $FALL-THROUGH$ - - case VALUE_DONE: - switch (c) { - case ';': - state = READY_FOR_NAME; - break; - - case ' ': - case '\t': - break; - - default: - state = ERROR; - break; - } - break; - - case IN_QUOTED_VALUE: - switch (c) { - case '"': - if (!escaped) { - // don't trim quoted strings; the spaces could be intentional. - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString()); - state = VALUE_DONE; - } else { - escaped = false; - paramValue.append(c); - } - break; - - case '\\': - if (escaped) { - paramValue.append('\\'); - } - escaped = !escaped; - break; - - default: - if (escaped) { - paramValue.append('\\'); - } - escaped = false; - paramValue.append(c); - break; - } - break; - - } - } - - // done looping. check if anything is left over. - if (state == IN_VALUE) { - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString().trim()); - } - } - - return result; - } - - - public boolean isMimeType(String mimeType) { - return this.mimeType.equals(mimeType.toLowerCase()); - } - - /** - * Return true if the BodyDescriptor belongs to a message - */ - public boolean isMessage() { - return mimeType.equals("message/rfc822"); - } - - /** - * Return true if the BodyDescripotro belongs to a multipart - */ - public boolean isMultipart() { - return mimeType.startsWith("multipart/"); - } - - /** - * Return the MimeType - */ - public String getMimeType() { - return mimeType; - } - - /** - * Return the boundary - */ - public String getBoundary() { - return boundary; - } - - /** - * Return the charset - */ - public String getCharset() { - return charset; - } - - /** - * Return all parameters for the BodyDescriptor - */ - public Map<String, String> getParameters() { - return parameters; - } - - /** - * Return the TransferEncoding - */ - public String getTransferEncoding() { - return transferEncoding; - } - - /** - * Return true if it's base64 encoded - */ - public boolean isBase64Encoded() { - return "base64".equals(transferEncoding); - } - - /** - * Return true if it's quoted-printable - */ - public boolean isQuotedPrintableEncoded() { - return "quoted-printable".equals(transferEncoding); - } - - @Override - public String toString() { - return mimeType; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/CloseShieldInputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/CloseShieldInputStream.java deleted file mode 100644 index d9f3b078a..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/CloseShieldInputStream.java +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.InputStream; -import java.io.IOException; - -/** - * InputStream that shields its underlying input stream from - * being closed. - * - * - * @version $Id: CloseShieldInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $ - */ -public class CloseShieldInputStream extends InputStream { - - /** - * Underlying InputStream - */ - private InputStream is; - - public CloseShieldInputStream(InputStream is) { - this.is = is; - } - - public InputStream getUnderlyingStream() { - return is; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - checkIfClosed(); - return is.read(); - } - - /** - * @see java.io.InputStream#available() - */ - public int available() throws IOException { - checkIfClosed(); - return is.available(); - } - - - /** - * Set the underlying InputStream to null - */ - public void close() throws IOException { - is = null; - } - - /** - * @see java.io.FilterInputStream#reset() - */ - public synchronized void reset() throws IOException { - checkIfClosed(); - is.reset(); - } - - /** - * @see java.io.FilterInputStream#markSupported() - */ - public boolean markSupported() { - if (is == null) - return false; - return is.markSupported(); - } - - /** - * @see java.io.FilterInputStream#mark(int) - */ - public synchronized void mark(int readlimit) { - if (is != null) - is.mark(readlimit); - } - - /** - * @see java.io.FilterInputStream#skip(long) - */ - public long skip(long n) throws IOException { - checkIfClosed(); - return is.skip(n); - } - - /** - * @see java.io.FilterInputStream#read(byte[]) - */ - public int read(byte b[]) throws IOException { - checkIfClosed(); - return is.read(b); - } - - /** - * @see java.io.FilterInputStream#read(byte[], int, int) - */ - public int read(byte b[], int off, int len) throws IOException { - checkIfClosed(); - return is.read(b, off, len); - } - - /** - * Check if the underlying InputStream is null. If so throw an Exception - * - * @throws IOException if the underlying InputStream is null - */ - private void checkIfClosed() throws IOException { - if (is == null) - throw new IOException("Stream is closed"); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/ContentHandler.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/ContentHandler.java deleted file mode 100644 index b437e739e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/ContentHandler.java +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; - -/** - * <p> - * Receives notifications of the content of a plain RFC822 or MIME message. - * Implement this interface and register an instance of that implementation - * with a <code>MimeStreamParser</code> instance using its - * {@link org.apache.james.mime4j.MimeStreamParser#setContentHandler(ContentHandler)} - * method. The parser uses the <code>ContentHandler</code> instance to report - * basic message-related events like the start and end of the body of a - * part in a multipart MIME entity. - * </p> - * <p> - * Events will be generated in the order the corresponding elements occur in - * the message stream parsed by the parser. E.g.: - * <pre> - * startMessage() - * startHeader() - * field(...) - * field(...) - * ... - * endHeader() - * startMultipart() - * preamble(...) - * startBodyPart() - * startHeader() - * field(...) - * field(...) - * ... - * endHeader() - * body() - * endBodyPart() - * startBodyPart() - * startHeader() - * field(...) - * field(...) - * ... - * endHeader() - * body() - * endBodyPart() - * epilogue(...) - * endMultipart() - * endMessage() - * </pre> - * The above shows an example of a MIME message consisting of a multipart - * body containing two body parts. - * </p> - * <p> - * See MIME RFCs 2045-2049 for more information on the structure of MIME - * messages and RFC 822 and 2822 for the general structure of Internet mail - * messages. - * </p> - * - * - * @version $Id: ContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $ - */ -public interface ContentHandler { - /** - * Called when a new message starts (a top level message or an embedded - * rfc822 message). - */ - void startMessage(); - - /** - * Called when a message ends. - */ - void endMessage(); - - /** - * Called when a new body part starts inside a - * <code>multipart/*</code> entity. - */ - void startBodyPart(); - - /** - * Called when a body part ends. - */ - void endBodyPart(); - - /** - * Called when a header (of a message or body part) is about to be parsed. - */ - void startHeader(); - - /** - * Called for each field of a header. - * - * @param fieldData the raw contents of the field - * (<code>Field-Name: field value</code>). The value will not be - * unfolded. - */ - void field(String fieldData); - - /** - * Called when there are no more header fields in a message or body part. - */ - void endHeader(); - - /** - * Called for the preamble (whatever comes before the first body part) - * of a <code>multipart/*</code> entity. - * - * @param is used to get the contents of the preamble. - * @throws IOException should be thrown on I/O errors. - */ - void preamble(InputStream is) throws IOException; - - /** - * Called for the epilogue (whatever comes after the final body part) - * of a <code>multipart/*</code> entity. - * - * @param is used to get the contents of the epilogue. - * @throws IOException should be thrown on I/O errors. - */ - void epilogue(InputStream is) throws IOException; - - /** - * Called when the body of a multipart entity is about to be parsed. - * - * @param bd encapsulates the values (either read from the - * message stream or, if not present, determined implictly - * as described in the - * MIME rfc:s) of the <code>Content-Type</code> and - * <code>Content-Transfer-Encoding</code> header fields. - */ - void startMultipart(BodyDescriptor bd); - - /** - * Called when the body of an entity has been parsed. - */ - void endMultipart(); - - /** - * Called when the body of a discrete (non-multipart) entity is about to - * be parsed. - * - * @param bd see {@link #startMultipart(BodyDescriptor)} - * @param is the contents of the body. NOTE: this is the raw body contents - * - it will not be decoded if encoded. The <code>bd</code> - * parameter should be used to determine how the stream data - * should be decoded. - * @throws IOException should be thrown on I/O errors. - */ - void body(BodyDescriptor bd, InputStream is) throws IOException; - - /** - * Called when a new entity (message or body part) starts and the - * parser is in <code>raw</code> mode. - * - * @param is the raw contents of the entity. - * @throws IOException should be thrown on I/O errors. - * @see MimeStreamParser#setRaw(boolean) - */ - void raw(InputStream is) throws IOException; -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/EOLConvertingInputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/EOLConvertingInputStream.java deleted file mode 100644 index d6ef706b2..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/EOLConvertingInputStream.java +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; - -/** - * InputStream which converts <code>\r</code> - * bytes not followed by <code>\n</code> and <code>\n</code> not - * preceded by <code>\r</code> to <code>\r\n</code>. - * - * - * @version $Id: EOLConvertingInputStream.java,v 1.4 2004/11/29 13:15:42 ntherning Exp $ - */ -public class EOLConvertingInputStream extends InputStream { - /** Converts single '\r' to '\r\n' */ - public static final int CONVERT_CR = 1; - /** Converts single '\n' to '\r\n' */ - public static final int CONVERT_LF = 2; - /** Converts single '\r' and '\n' to '\r\n' */ - public static final int CONVERT_BOTH = 3; - - private PushbackInputStream in = null; - private int previous = 0; - private int flags = CONVERT_BOTH; - private int size = 0; - private int pos = 0; - private int nextTenPctPos; - private int tenPctSize; - private Callback callback; - - public interface Callback { - public void report(int bytesRead); - } - - /** - * Creates a new <code>EOLConvertingInputStream</code> - * instance converting bytes in the given <code>InputStream</code>. - * The flag <code>CONVERT_BOTH</code> is the default. - * - * @param in the <code>InputStream</code> to read from. - */ - public EOLConvertingInputStream(InputStream _in) { - super(); - in = new PushbackInputStream(_in, 2); - } - - /** - * Creates a new <code>EOLConvertingInputStream</code> - * instance converting bytes in the given <code>InputStream</code>. - * - * @param _in the <code>InputStream</code> to read from. - * @param _size the size of the input stream (need not be exact) - * @param _callback a callback reporting when each 10% of stream's size is reached - */ - public EOLConvertingInputStream(InputStream _in, int _size, Callback _callback) { - this(_in); - size = _size; - tenPctSize = size / 10; - nextTenPctPos = tenPctSize; - callback = _callback; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - in.close(); - } - - private int readByte() throws IOException { - int b = in.read(); - if (b != -1) { - if (callback != null && pos++ == nextTenPctPos) { - nextTenPctPos += tenPctSize; - if (callback != null) { - callback.report(pos); - } - } - } - return b; - } - - private void unreadByte(int c) throws IOException { - in.unread(c); - pos--; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - int b = readByte(); - - if (b == -1) { - pos = size; - return -1; - } - - if ((flags & CONVERT_CR) != 0 && b == '\r') { - int c = readByte(); - if (c != -1) { - unreadByte(c); - } - if (c != '\n') { - unreadByte('\n'); - } - } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') { - b = '\r'; - unreadByte('\n'); - } - - previous = b; - - return b; - } - -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/Log.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/Log.java deleted file mode 100644 index 5eeead5f3..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/Log.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.james.mime4j; - -/** - * Empty stub for the apache logging library. - */ -public class Log { - private static final String LOG_TAG = "Email Log"; - - public Log(Class mClazz) { - } - - public boolean isDebugEnabled() { - return false; - } - - public boolean isErrorEnabled() { - return true; - } - - public boolean isFatalEnabled() { - return true; - } - - public boolean isInfoEnabled() { - return false; - } - - public boolean isTraceEnabled() { - return false; - } - - public boolean isWarnEnabled() { - return true; - } - - public void trace(Object message) { - if (!isTraceEnabled()) return; - android.util.Log.v(LOG_TAG, toString(message, null)); - } - - public void trace(Object message, Throwable t) { - if (!isTraceEnabled()) return; - android.util.Log.v(LOG_TAG, toString(message, t)); - } - - public void debug(Object message) { - if (!isDebugEnabled()) return; - android.util.Log.d(LOG_TAG, toString(message, null)); - } - - public void debug(Object message, Throwable t) { - if (!isDebugEnabled()) return; - android.util.Log.d(LOG_TAG, toString(message, t)); - } - - public void info(Object message) { - if (!isInfoEnabled()) return; - android.util.Log.i(LOG_TAG, toString(message, null)); - } - - public void info(Object message, Throwable t) { - if (!isInfoEnabled()) return; - android.util.Log.i(LOG_TAG, toString(message, t)); - } - - public void warn(Object message) { - android.util.Log.w(LOG_TAG, toString(message, null)); - } - - public void warn(Object message, Throwable t) { - android.util.Log.w(LOG_TAG, toString(message, t)); - } - - public void error(Object message) { - android.util.Log.e(LOG_TAG, toString(message, null)); - } - - public void error(Object message, Throwable t) { - android.util.Log.e(LOG_TAG, toString(message, t)); - } - - public void fatal(Object message) { - android.util.Log.e(LOG_TAG, toString(message, null)); - } - - public void fatal(Object message, Throwable t) { - android.util.Log.e(LOG_TAG, toString(message, t)); - } - - private static String toString(Object o, Throwable t) { - String m = (o == null) ? "(null)" : o.toString(); - if (t == null) { - return m; - } else { - return m + " " + t.getMessage(); - } - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/LogFactory.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/LogFactory.java deleted file mode 100644 index ed6e3de3d..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/LogFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.james.mime4j; - -/** - * Empty stub for the apache logging library. - */ -public final class LogFactory { - private LogFactory() { - } - - public static Log getLog(Class clazz) { - return new Log(clazz); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeBoundaryInputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeBoundaryInputStream.java deleted file mode 100644 index c6d6f248a..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeBoundaryInputStream.java +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; - -/** - * Stream that constrains itself to a single MIME body part. - * After the stream ends (i.e. read() returns -1) {@link #hasMoreParts()} - * can be used to determine if a final boundary has been seen or not. - * If {@link #parentEOF()} is <code>true</code> an unexpected end of stream - * has been detected in the parent stream. - * - * - * - * @version $Id: MimeBoundaryInputStream.java,v 1.2 2004/11/29 13:15:42 ntherning Exp $ - */ -public class MimeBoundaryInputStream extends InputStream { - - private PushbackInputStream s = null; - private byte[] boundary = null; - private boolean first = true; - private boolean eof = false; - private boolean parenteof = false; - private boolean moreParts = true; - - /** - * Creates a new MimeBoundaryInputStream. - * @param s The underlying stream. - * @param boundary Boundary string (not including leading hyphens). - */ - public MimeBoundaryInputStream(InputStream s, String boundary) - throws IOException { - - this.s = new PushbackInputStream(s, boundary.length() + 4); - - boundary = "--" + boundary; - this.boundary = new byte[boundary.length()]; - for (int i = 0; i < this.boundary.length; i++) { - this.boundary[i] = (byte) boundary.charAt(i); - } - - /* - * By reading one byte we will update moreParts to be as expected - * before any bytes have been read. - */ - int b = read(); - if (b != -1) { - this.s.unread(b); - } - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - s.close(); - } - - /** - * Determines if the underlying stream has more parts (this stream has - * not seen an end boundary). - * - * @return <code>true</code> if there are more parts in the underlying - * stream, <code>false</code> otherwise. - */ - public boolean hasMoreParts() { - return moreParts; - } - - /** - * Determines if the parent stream has reached EOF - * - * @return <code>true</code> if EOF has been reached for the parent stream, - * <code>false</code> otherwise. - */ - public boolean parentEOF() { - return parenteof; - } - - /** - * Consumes all unread bytes of this stream. After a call to this method - * this stream will have reached EOF. - * - * @throws IOException on I/O errors. - */ - public void consume() throws IOException { - while (read() != -1) { - } - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - if (eof) { - return -1; - } - - if (first) { - first = false; - if (matchBoundary()) { - return -1; - } - } - - int b1 = s.read(); - int b2 = s.read(); - - if (b1 == '\r' && b2 == '\n') { - if (matchBoundary()) { - return -1; - } - } - - if (b2 != -1) { - s.unread(b2); - } - - parenteof = b1 == -1; - eof = parenteof; - - return b1; - } - - private boolean matchBoundary() throws IOException { - - for (int i = 0; i < boundary.length; i++) { - int b = s.read(); - if (b != boundary[i]) { - if (b != -1) { - s.unread(b); - } - for (int j = i - 1; j >= 0; j--) { - s.unread(boundary[j]); - } - return false; - } - } - - /* - * We have a match. Is it an end boundary? - */ - int prev = s.read(); - int curr = s.read(); - moreParts = !(prev == '-' && curr == '-'); - do { - if (curr == '\n' && prev == '\r') { - break; - } - prev = curr; - } while ((curr = s.read()) != -1); - - if (curr == -1) { - moreParts = false; - parenteof = true; - } - - eof = true; - - return true; - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeStreamParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeStreamParser.java deleted file mode 100644 index a8aad5a38..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/MimeStreamParser.java +++ /dev/null @@ -1,324 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import org.apache.james.mime4j.decoder.Base64InputStream; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.util.BitSet; -import java.util.LinkedList; - -/** - * <p> - * Parses MIME (or RFC822) message streams of bytes or characters and reports - * parsing events to a <code>ContentHandler</code> instance. - * </p> - * <p> - * Typical usage:<br/> - * <pre> - * ContentHandler handler = new MyHandler(); - * MimeStreamParser parser = new MimeStreamParser(); - * parser.setContentHandler(handler); - * parser.parse(new BufferedInputStream(new FileInputStream("mime.msg"))); - * </pre> - * <strong>NOTE:</strong> All lines must end with CRLF - * (<code>\r\n</code>). If you are unsure of the line endings in your stream - * you should wrap it in a {@link org.apache.james.mime4j.EOLConvertingInputStream} instance. - * - * - * @version $Id: MimeStreamParser.java,v 1.8 2005/02/11 10:12:02 ntherning Exp $ - */ -public class MimeStreamParser { - private static final Log log = LogFactory.getLog(MimeStreamParser.class); - - private static BitSet fieldChars = null; - - private RootInputStream rootStream = null; - private LinkedList<BodyDescriptor> bodyDescriptors = new LinkedList<BodyDescriptor>(); - private ContentHandler handler = null; - private boolean raw = false; - private boolean prematureEof = false; - - static { - fieldChars = new BitSet(); - for (int i = 0x21; i <= 0x39; i++) { - fieldChars.set(i); - } - for (int i = 0x3b; i <= 0x7e; i++) { - fieldChars.set(i); - } - } - - /** - * Creates a new <code>MimeStreamParser</code> instance. - */ - public MimeStreamParser() { - } - - /** - * Parses a stream of bytes containing a MIME message. - * - * @param is the stream to parse. - * @throws IOException on I/O errors. - */ - public void parse(InputStream is) throws IOException { - rootStream = new RootInputStream(is); - parseMessage(rootStream); - } - - /** - * Determines if this parser is currently in raw mode. - * - * @return <code>true</code> if in raw mode, <code>false</code> - * otherwise. - * @see #setRaw(boolean) - */ - public boolean isRaw() { - return raw; - } - - /** - * Enables or disables raw mode. In raw mode all future entities - * (messages or body parts) in the stream will be reported to the - * {@link ContentHandler#raw(InputStream)} handler method only. - * The stream will contain the entire unparsed entity contents - * including header fields and whatever is in the body. - * - * @param raw <code>true</code> enables raw mode, <code>false</code> - * disables it. - */ - public void setRaw(boolean raw) { - this.raw = raw; - } - - /** - * Finishes the parsing and stops reading lines. - * NOTE: No more lines will be parsed but the parser - * will still call - * {@link ContentHandler#endMultipart()}, - * {@link ContentHandler#endBodyPart()}, - * {@link ContentHandler#endMessage()}, etc to match previous calls - * to - * {@link ContentHandler#startMultipart(BodyDescriptor)}, - * {@link ContentHandler#startBodyPart()}, - * {@link ContentHandler#startMessage()}, etc. - */ - public void stop() { - rootStream.truncate(); - } - - /** - * Parses an entity which consists of a header followed by a body containing - * arbitrary data, body parts or an embedded message. - * - * @param is the stream to parse. - * @throws IOException on I/O errors. - */ - private void parseEntity(InputStream is) throws IOException { - BodyDescriptor bd = parseHeader(is); - - if (bd.isMultipart()) { - bodyDescriptors.addFirst(bd); - - handler.startMultipart(bd); - - MimeBoundaryInputStream tempIs = - new MimeBoundaryInputStream(is, bd.getBoundary()); - handler.preamble(new CloseShieldInputStream(tempIs)); - tempIs.consume(); - - while (tempIs.hasMoreParts()) { - tempIs = new MimeBoundaryInputStream(is, bd.getBoundary()); - parseBodyPart(tempIs); - tempIs.consume(); - if (tempIs.parentEOF()) { - prematureEof = true; -// if (log.isWarnEnabled()) { -// log.warn("Line " + rootStream.getLineNumber() -// + ": Body part ended prematurely. " -// + "Higher level boundary detected or " -// + "EOF reached."); -// } - break; - } - } - - handler.epilogue(new CloseShieldInputStream(is)); - - handler.endMultipart(); - - bodyDescriptors.removeFirst(); - - } else if (bd.isMessage()) { - if (bd.isBase64Encoded()) { - log.warn("base64 encoded message/rfc822 detected"); - is = new EOLConvertingInputStream( - new Base64InputStream(is)); - } else if (bd.isQuotedPrintableEncoded()) { - log.warn("quoted-printable encoded message/rfc822 detected"); - is = new EOLConvertingInputStream( - new QuotedPrintableInputStream(is)); - } - bodyDescriptors.addFirst(bd); - parseMessage(is); - bodyDescriptors.removeFirst(); - } else { - handler.body(bd, new CloseShieldInputStream(is)); - } - - /* - * Make sure the stream has been consumed. - */ - while (is.read() != -1) { - } - } - - private void parseMessage(InputStream is) throws IOException { - if (raw) { - handler.raw(new CloseShieldInputStream(is)); - } else { - handler.startMessage(); - parseEntity(is); - handler.endMessage(); - } - } - - public boolean getPrematureEof() { - return prematureEof; - } - - private void parseBodyPart(InputStream is) throws IOException { - if (raw) { - handler.raw(new CloseShieldInputStream(is)); - } else { - handler.startBodyPart(); - parseEntity(is); - handler.endBodyPart(); - } - } - - /** - * Parses a header. - * - * @param is the stream to parse. - * @return a <code>BodyDescriptor</code> describing the body following - * the header. - */ - private BodyDescriptor parseHeader(InputStream is) throws IOException { - BodyDescriptor bd = new BodyDescriptor(bodyDescriptors.isEmpty() - ? null : (BodyDescriptor) bodyDescriptors.getFirst()); - - handler.startHeader(); - - int lineNumber = rootStream.getLineNumber(); - - StringBuffer sb = new StringBuffer(); - int curr = 0; - int prev = 0; - while ((curr = is.read()) != -1) { - if (curr == '\n' && (prev == '\n' || prev == 0)) { - /* - * [\r]\n[\r]\n or an immediate \r\n have been seen. - */ - sb.deleteCharAt(sb.length() - 1); - break; - } - sb.append((char) curr); - prev = curr == '\r' ? prev : curr; - } - -// if (curr == -1 && log.isWarnEnabled()) { -// log.warn("Line " + rootStream.getLineNumber() -// + ": Unexpected end of headers detected. " -// + "Boundary detected in header or EOF reached."); -// } - - int start = 0; - int pos = 0; - int startLineNumber = lineNumber; - while (pos < sb.length()) { - while (pos < sb.length() && sb.charAt(pos) != '\r') { - pos++; - } - if (pos < sb.length() - 1 && sb.charAt(pos + 1) != '\n') { - pos++; - continue; - } - - if (pos >= sb.length() - 2 || fieldChars.get(sb.charAt(pos + 2))) { - - /* - * field should be the complete field data excluding the - * trailing \r\n. - */ - String field = sb.substring(start, pos); - start = pos + 2; - - /* - * Check for a valid field. - */ - int index = field.indexOf(':'); - boolean valid = false; - if (index != -1 && fieldChars.get(field.charAt(0))) { - valid = true; - String fieldName = field.substring(0, index).trim(); - for (int i = 0; i < fieldName.length(); i++) { - if (!fieldChars.get(fieldName.charAt(i))) { - valid = false; - break; - } - } - - if (valid) { - handler.field(field); - bd.addField(fieldName, field.substring(index + 1)); - } - } - - if (!valid && log.isWarnEnabled()) { - log.warn("Line " + startLineNumber - + ": Ignoring invalid field: '" + field.trim() + "'"); - } - - startLineNumber = lineNumber; - } - - pos += 2; - lineNumber++; - } - - handler.endHeader(); - - return bd; - } - - /** - * Sets the <code>ContentHandler</code> to use when reporting - * parsing events. - * - * @param h the <code>ContentHandler</code>. - */ - public void setContentHandler(ContentHandler h) { - this.handler = h; - } - -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/RootInputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/RootInputStream.java deleted file mode 100644 index cc8b2411c..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/RootInputStream.java +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; - -/** - * <code>InputStream</code> used by the parser to wrap the original user - * supplied stream. This stream keeps track of the current line number and - * can also be truncated. When truncated the stream will appear to have - * reached end of file. This is used by the parser's - * {@link org.apache.james.mime4j.MimeStreamParser#stop()} method. - * - * - * @version $Id: RootInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $ - */ -class RootInputStream extends InputStream { - private InputStream is = null; - private int lineNumber = 1; - private int prev = -1; - private boolean truncated = false; - - /** - * Creates a new <code>RootInputStream</code>. - * - * @param in the stream to read from. - */ - public RootInputStream(InputStream is) { - this.is = is; - } - - /** - * Gets the current line number starting at 1 - * (the number of <code>\r\n</code> read so far plus 1). - * - * @return the current line number. - */ - public int getLineNumber() { - return lineNumber; - } - - /** - * Truncates this <code>InputStream</code>. After this call any - * call to {@link #read()}, {@link #read(byte[]) or - * {@link #read(byte[], int, int)} will return - * -1 as if end-of-file had been reached. - */ - public void truncate() { - this.truncated = true; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - if (truncated) { - return -1; - } - - int b = is.read(); - if (prev == '\r' && b == '\n') { - lineNumber++; - } - prev = b; - return b; - } - - /** - * - * @see java.io.InputStream#read(byte[], int, int) - */ - public int read(byte[] b, int off, int len) throws IOException { - if (truncated) { - return -1; - } - - int n = is.read(b, off, len); - for (int i = off; i < off + n; i++) { - if (prev == '\r' && b[i] == '\n') { - lineNumber++; - } - prev = b[i]; - } - return n; - } - - /** - * @see java.io.InputStream#read(byte[]) - */ - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/codec/EncoderUtil.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/codec/EncoderUtil.java deleted file mode 100644 index 6841bc998..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/codec/EncoderUtil.java +++ /dev/null @@ -1,630 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.codec; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.BitSet; -import java.util.Locale; - -import org.apache.james.mime4j.util.CharsetUtil; - -/** - * ANDROID: THIS CLASS IS COPIED FROM A NEWER VERSION OF MIME4J - */ - -/** - * Static methods for encoding header field values. This includes encoded-words - * as defined in <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a> - * or display-names of an e-mail address, for example. - * - */ -public class EncoderUtil { - - // This array is a lookup table that translates 6-bit positive integer index - // values into their "Base64 Alphabet" equivalents as specified in Table 1 - // of RFC 2045. - // ANDROID: THIS TABLE IS COPIED FROM BASE64OUTPUTSTREAM - static final byte[] BASE64_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', '+', '/' }; - - // Byte used to pad output. - private static final byte BASE64_PAD = '='; - - private static final BitSet Q_REGULAR_CHARS = initChars("=_?"); - - private static final BitSet Q_RESTRICTED_CHARS = initChars("=_?\"#$%&'(),.:;<>@[\\]^`{|}~"); - - private static final int MAX_USED_CHARACTERS = 50; - - private static final String ENC_WORD_PREFIX = "=?"; - private static final String ENC_WORD_SUFFIX = "?="; - - private static final int ENCODED_WORD_MAX_LENGTH = 75; // RFC 2047 - - private static final BitSet TOKEN_CHARS = initChars("()<>@,;:\\\"/[]?="); - - private static final BitSet ATEXT_CHARS = initChars("()<>@.,;:\\\"[]"); - - private static BitSet initChars(String specials) { - BitSet bs = new BitSet(128); - for (char ch = 33; ch < 127; ch++) { - if (specials.indexOf(ch) == -1) { - bs.set(ch); - } - } - return bs; - } - - /** - * Selects one of the two encodings specified in RFC 2047. - */ - public enum Encoding { - /** The B encoding (identical to base64 defined in RFC 2045). */ - B, - /** The Q encoding (similar to quoted-printable defined in RFC 2045). */ - Q - } - - /** - * Indicates the intended usage of an encoded word. - */ - public enum Usage { - /** - * Encoded word is used to replace a 'text' token in any Subject or - * Comments header field. - */ - TEXT_TOKEN, - /** - * Encoded word is used to replace a 'word' entity within a 'phrase', - * for example, one that precedes an address in a From, To, or Cc - * header. - */ - WORD_ENTITY - } - - private EncoderUtil() { - } - - /** - * Encodes the display-name portion of an address. See <a - * href='http://www.faqs.org/rfcs/rfc5322.html'>RFC 5322</a> section 3.4 - * and <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a> section - * 5.3. The specified string should not be folded. - * - * @param displayName - * display-name to encode. - * @return encoded display-name. - */ - public static String encodeAddressDisplayName(String displayName) { - // display-name = phrase - // phrase = 1*( encoded-word / word ) - // word = atom / quoted-string - // atom = [CFWS] 1*atext [CFWS] - // CFWS = comment or folding white space - - if (isAtomPhrase(displayName)) { - return displayName; - } else if (hasToBeEncoded(displayName, 0)) { - return encodeEncodedWord(displayName, Usage.WORD_ENTITY); - } else { - return quote(displayName); - } - } - - /** - * Encodes the local part of an address specification as described in RFC - * 5322 section 3.4.1. Leading and trailing CFWS should have been removed - * before calling this method. The specified string should not contain any - * illegal (control or non-ASCII) characters. - * - * @param localPart - * the local part to encode - * @return the encoded local part. - */ - public static String encodeAddressLocalPart(String localPart) { - // local-part = dot-atom / quoted-string - // dot-atom = [CFWS] dot-atom-text [CFWS] - // CFWS = comment or folding white space - - if (isDotAtomText(localPart)) { - return localPart; - } else { - return quote(localPart); - } - } - - /** - * Encodes the specified strings into a header parameter as described in RFC - * 2045 section 5.1 and RFC 2183 section 2. The specified strings should not - * contain any illegal (control or non-ASCII) characters. - * - * @param name - * parameter name. - * @param value - * parameter value. - * @return encoded result. - */ - public static String encodeHeaderParameter(String name, String value) { - name = name.toLowerCase(Locale.US); - - // value := token / quoted-string - if (isToken(value)) { - return name + "=" + value; - } else { - return name + "=" + quote(value); - } - } - - /** - * Shortcut method that encodes the specified text into an encoded-word if - * the text has to be encoded. - * - * @param text - * text to encode. - * @param usage - * whether the encoded-word is to be used to replace a text token - * or a word entity (see RFC 822). - * @param usedCharacters - * number of characters already used up (<code>0 <= usedCharacters <= 50</code>). - * @return the specified text if encoding is not necessary or an encoded - * word or a sequence of encoded words otherwise. - */ - public static String encodeIfNecessary(String text, Usage usage, - int usedCharacters) { - if (hasToBeEncoded(text, usedCharacters)) - return encodeEncodedWord(text, usage, usedCharacters); - else - return text; - } - - /** - * Determines if the specified string has to encoded into an encoded-word. - * Returns <code>true</code> if the text contains characters that don't - * fall into the printable ASCII character set or if the text contains a - * 'word' (sequence of non-whitespace characters) longer than 77 characters - * (including characters already used up in the line). - * - * @param text - * text to analyze. - * @param usedCharacters - * number of characters already used up (<code>0 <= usedCharacters <= 50</code>). - * @return <code>true</code> if the specified text has to be encoded into - * an encoded-word, <code>false</code> otherwise. - */ - public static boolean hasToBeEncoded(String text, int usedCharacters) { - if (text == null) - throw new IllegalArgumentException(); - if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS) - throw new IllegalArgumentException(); - - int nonWhiteSpaceCount = usedCharacters; - - for (int idx = 0; idx < text.length(); idx++) { - char ch = text.charAt(idx); - if (ch == '\t' || ch == ' ') { - nonWhiteSpaceCount = 0; - } else { - nonWhiteSpaceCount++; - if (nonWhiteSpaceCount > 77) { - // Line cannot be folded into multiple lines with no more - // than 78 characters each. Encoding as encoded-words makes - // that possible. One character has to be reserved for - // folding white space; that leaves 77 characters. - return true; - } - - if (ch < 32 || ch >= 127) { - // non-printable ascii character has to be encoded - return true; - } - } - } - - return false; - } - - /** - * Encodes the specified text into an encoded word or a sequence of encoded - * words separated by space. The text is separated into a sequence of - * encoded words if it does not fit in a single one. - * <p> - * The charset to encode the specified text into a byte array and the - * encoding to use for the encoded-word are detected automatically. - * <p> - * This method assumes that zero characters have already been used up in the - * current line. - * - * @param text - * text to encode. - * @param usage - * whether the encoded-word is to be used to replace a text token - * or a word entity (see RFC 822). - * @return the encoded word (or sequence of encoded words if the given text - * does not fit in a single encoded word). - * @see #hasToBeEncoded(String, int) - */ - public static String encodeEncodedWord(String text, Usage usage) { - return encodeEncodedWord(text, usage, 0, null, null); - } - - /** - * Encodes the specified text into an encoded word or a sequence of encoded - * words separated by space. The text is separated into a sequence of - * encoded words if it does not fit in a single one. - * <p> - * The charset to encode the specified text into a byte array and the - * encoding to use for the encoded-word are detected automatically. - * - * @param text - * text to encode. - * @param usage - * whether the encoded-word is to be used to replace a text token - * or a word entity (see RFC 822). - * @param usedCharacters - * number of characters already used up (<code>0 <= usedCharacters <= 50</code>). - * @return the encoded word (or sequence of encoded words if the given text - * does not fit in a single encoded word). - * @see #hasToBeEncoded(String, int) - */ - public static String encodeEncodedWord(String text, Usage usage, - int usedCharacters) { - return encodeEncodedWord(text, usage, usedCharacters, null, null); - } - - /** - * Encodes the specified text into an encoded word or a sequence of encoded - * words separated by space. The text is separated into a sequence of - * encoded words if it does not fit in a single one. - * - * @param text - * text to encode. - * @param usage - * whether the encoded-word is to be used to replace a text token - * or a word entity (see RFC 822). - * @param usedCharacters - * number of characters already used up (<code>0 <= usedCharacters <= 50</code>). - * @param charset - * the Java charset that should be used to encode the specified - * string into a byte array. A suitable charset is detected - * automatically if this parameter is <code>null</code>. - * @param encoding - * the encoding to use for the encoded-word (either B or Q). A - * suitable encoding is automatically chosen if this parameter is - * <code>null</code>. - * @return the encoded word (or sequence of encoded words if the given text - * does not fit in a single encoded word). - * @see #hasToBeEncoded(String, int) - */ - public static String encodeEncodedWord(String text, Usage usage, - int usedCharacters, Charset charset, Encoding encoding) { - if (text == null) - throw new IllegalArgumentException(); - if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS) - throw new IllegalArgumentException(); - - if (charset == null) - charset = determineCharset(text); - - String mimeCharset = CharsetUtil.toMimeCharset(charset.name()); - if (mimeCharset == null) { - // cannot happen if charset was originally null - throw new IllegalArgumentException("Unsupported charset"); - } - - byte[] bytes = encode(text, charset); - - if (encoding == null) - encoding = determineEncoding(bytes, usage); - - if (encoding == Encoding.B) { - String prefix = ENC_WORD_PREFIX + mimeCharset + "?B?"; - return encodeB(prefix, text, usedCharacters, charset, bytes); - } else { - String prefix = ENC_WORD_PREFIX + mimeCharset + "?Q?"; - return encodeQ(prefix, text, usage, usedCharacters, charset, bytes); - } - } - - /** - * Encodes the specified byte array using the B encoding defined in RFC - * 2047. - * - * @param bytes - * byte array to encode. - * @return encoded string. - */ - public static String encodeB(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - - int idx = 0; - final int end = bytes.length; - for (; idx < end - 2; idx += 3) { - int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8 - | bytes[idx + 2] & 0xff; - sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]); - sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]); - sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]); - sb.append((char) BASE64_TABLE[data & 0x3f]); - } - - if (idx == end - 2) { - int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8; - sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]); - sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]); - sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]); - sb.append((char) BASE64_PAD); - - } else if (idx == end - 1) { - int data = (bytes[idx] & 0xff) << 16; - sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]); - sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]); - sb.append((char) BASE64_PAD); - sb.append((char) BASE64_PAD); - } - - return sb.toString(); - } - - /** - * Encodes the specified byte array using the Q encoding defined in RFC - * 2047. - * - * @param bytes - * byte array to encode. - * @param usage - * whether the encoded-word is to be used to replace a text token - * or a word entity (see RFC 822). - * @return encoded string. - */ - public static String encodeQ(byte[] bytes, Usage usage) { - BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS - : Q_RESTRICTED_CHARS; - - StringBuilder sb = new StringBuilder(); - - final int end = bytes.length; - for (int idx = 0; idx < end; idx++) { - int v = bytes[idx] & 0xff; - if (v == 32) { - sb.append('_'); - } else if (!qChars.get(v)) { - sb.append('='); - sb.append(hexDigit(v >>> 4)); - sb.append(hexDigit(v & 0xf)); - } else { - sb.append((char) v); - } - } - - return sb.toString(); - } - - /** - * Tests whether the specified string is a token as defined in RFC 2045 - * section 5.1. - * - * @param str - * string to test. - * @return <code>true</code> if the specified string is a RFC 2045 token, - * <code>false</code> otherwise. - */ - public static boolean isToken(String str) { - // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials> - // tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / - // <"> / "/" / "[" / "]" / "?" / "=" - // CTL := 0.- 31., 127. - - final int length = str.length(); - if (length == 0) - return false; - - for (int idx = 0; idx < length; idx++) { - char ch = str.charAt(idx); - if (!TOKEN_CHARS.get(ch)) - return false; - } - - return true; - } - - private static boolean isAtomPhrase(String str) { - // atom = [CFWS] 1*atext [CFWS] - - boolean containsAText = false; - - final int length = str.length(); - for (int idx = 0; idx < length; idx++) { - char ch = str.charAt(idx); - if (ATEXT_CHARS.get(ch)) { - containsAText = true; - } else if (!CharsetUtil.isWhitespace(ch)) { - return false; - } - } - - return containsAText; - } - - // RFC 5322 section 3.2.3 - private static boolean isDotAtomText(String str) { - // dot-atom-text = 1*atext *("." 1*atext) - // atext = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / - // "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" - - char prev = '.'; - - final int length = str.length(); - if (length == 0) - return false; - - for (int idx = 0; idx < length; idx++) { - char ch = str.charAt(idx); - - if (ch == '.') { - if (prev == '.' || idx == length - 1) - return false; - } else { - if (!ATEXT_CHARS.get(ch)) - return false; - } - - prev = ch; - } - - return true; - } - - // RFC 5322 section 3.2.4 - private static String quote(String str) { - // quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS] - // qcontent = qtext / quoted-pair - // qtext = %d33 / %d35-91 / %d93-126 - // quoted-pair = ("\" (VCHAR / WSP)) - // VCHAR = %x21-7E - // DQUOTE = %x22 - - String escaped = str.replaceAll("[\\\\\"]", "\\\\$0"); - return "\"" + escaped + "\""; - } - - private static String encodeB(String prefix, String text, - int usedCharacters, Charset charset, byte[] bytes) { - int encodedLength = bEncodedLength(bytes); - - int totalLength = prefix.length() + encodedLength - + ENC_WORD_SUFFIX.length(); - if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) { - return prefix + encodeB(bytes) + ENC_WORD_SUFFIX; - } else { - int splitOffset = text.offsetByCodePoints(text.length() / 2, -1); - - String part1 = text.substring(0, splitOffset); - byte[] bytes1 = encode(part1, charset); - String word1 = encodeB(prefix, part1, usedCharacters, charset, - bytes1); - - String part2 = text.substring(splitOffset); - byte[] bytes2 = encode(part2, charset); - String word2 = encodeB(prefix, part2, 0, charset, bytes2); - - return word1 + " " + word2; - } - } - - private static int bEncodedLength(byte[] bytes) { - return (bytes.length + 2) / 3 * 4; - } - - private static String encodeQ(String prefix, String text, Usage usage, - int usedCharacters, Charset charset, byte[] bytes) { - int encodedLength = qEncodedLength(bytes, usage); - - int totalLength = prefix.length() + encodedLength - + ENC_WORD_SUFFIX.length(); - if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) { - return prefix + encodeQ(bytes, usage) + ENC_WORD_SUFFIX; - } else { - int splitOffset = text.offsetByCodePoints(text.length() / 2, -1); - - String part1 = text.substring(0, splitOffset); - byte[] bytes1 = encode(part1, charset); - String word1 = encodeQ(prefix, part1, usage, usedCharacters, - charset, bytes1); - - String part2 = text.substring(splitOffset); - byte[] bytes2 = encode(part2, charset); - String word2 = encodeQ(prefix, part2, usage, 0, charset, bytes2); - - return word1 + " " + word2; - } - } - - private static int qEncodedLength(byte[] bytes, Usage usage) { - BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS - : Q_RESTRICTED_CHARS; - - int count = 0; - - for (int idx = 0; idx < bytes.length; idx++) { - int v = bytes[idx] & 0xff; - if (v == 32) { - count++; - } else if (!qChars.get(v)) { - count += 3; - } else { - count++; - } - } - - return count; - } - - private static byte[] encode(String text, Charset charset) { - ByteBuffer buffer = charset.encode(text); - byte[] bytes = new byte[buffer.limit()]; - buffer.get(bytes); - return bytes; - } - - private static Charset determineCharset(String text) { - // it is an important property of iso-8859-1 that it directly maps - // unicode code points 0000 to 00ff to byte values 00 to ff. - boolean ascii = true; - final int len = text.length(); - for (int index = 0; index < len; index++) { - char ch = text.charAt(index); - if (ch > 0xff) { - return CharsetUtil.UTF_8; - } - if (ch > 0x7f) { - ascii = false; - } - } - return ascii ? CharsetUtil.US_ASCII : CharsetUtil.ISO_8859_1; - } - - private static Encoding determineEncoding(byte[] bytes, Usage usage) { - if (bytes.length == 0) - return Encoding.Q; - - BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS - : Q_RESTRICTED_CHARS; - - int qEncoded = 0; - for (int i = 0; i < bytes.length; i++) { - int v = bytes[i] & 0xff; - if (v != 32 && !qChars.get(v)) { - qEncoded++; - } - } - - int percentage = qEncoded * 100 / bytes.length; - return percentage > 30 ? Encoding.B : Encoding.Q; - } - - private static char hexDigit(int i) { - return i < 10 ? (char) (i + '0') : (char) (i - 10 + 'A'); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/Base64InputStream.java deleted file mode 100644 index 77f5d7d4a..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/Base64InputStream.java +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -/** - * Modified to improve efficiency by Android 21-Aug-2009 - */ - -package org.apache.james.mime4j.decoder; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Performs Base-64 decoding on an underlying stream. - * - * - * @version $Id: Base64InputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $ - */ -public class Base64InputStream extends InputStream { - private final InputStream s; - private int outCount = 0; - private int outIndex = 0; - private final int[] outputBuffer = new int[3]; - private final byte[] inputBuffer = new byte[4]; - private boolean done = false; - - public Base64InputStream(InputStream s) { - this.s = s; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - @Override - public void close() throws IOException { - s.close(); - } - - @Override - public int read() throws IOException { - if (outIndex == outCount) { - fillBuffer(); - if (outIndex == outCount) { - return -1; - } - } - - return outputBuffer[outIndex++]; - } - - /** - * Retrieve data from the underlying stream, decode it, - * and put the results in the byteq. - * @throws IOException - */ - private void fillBuffer() throws IOException { - outCount = 0; - outIndex = 0; - int inCount = 0; - - int i; - // "done" is needed for the two successive '=' at the end - while (!done) { - switch (i = s.read()) { - case -1: - // No more input - just return, let outputBuffer drain out, and be done - return; - case '=': - // once we meet the first '=', avoid reading the second '=' - done = true; - decodeAndEnqueue(inCount); - return; - default: - byte sX = TRANSLATION[i]; - if (sX < 0) continue; - inputBuffer[inCount++] = sX; - if (inCount == 4) { - decodeAndEnqueue(inCount); - return; - } - break; - } - } - } - - private void decodeAndEnqueue(int len) { - int accum = 0; - accum |= inputBuffer[0] << 18; - accum |= inputBuffer[1] << 12; - accum |= inputBuffer[2] << 6; - accum |= inputBuffer[3]; - - // There's a bit of duplicated code here because we want to have straight-through operation - // for the most common case of len==4 - if (len == 4) { - outputBuffer[0] = (accum >> 16) & 0xFF; - outputBuffer[1] = (accum >> 8) & 0xFF; - outputBuffer[2] = (accum) & 0xFF; - outCount = 3; - return; - } else if (len == 3) { - outputBuffer[0] = (accum >> 16) & 0xFF; - outputBuffer[1] = (accum >> 8) & 0xFF; - outCount = 2; - return; - } else { // len == 2 - outputBuffer[0] = (accum >> 16) & 0xFF; - outCount = 1; - return; - } - } - - private static byte[] TRANSLATION = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xF0 */ - }; - - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/ByteQueue.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/ByteQueue.java deleted file mode 100644 index 6d7ccef52..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/ByteQueue.java +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.util.Iterator; - -public class ByteQueue { - - private UnboundedFifoByteBuffer buf; - private int initialCapacity = -1; - - public ByteQueue() { - buf = new UnboundedFifoByteBuffer(); - } - - public ByteQueue(int initialCapacity) { - buf = new UnboundedFifoByteBuffer(initialCapacity); - this.initialCapacity = initialCapacity; - } - - public void enqueue(byte b) { - buf.add(b); - } - - public byte dequeue() { - return buf.remove(); - } - - public int count() { - return buf.size(); - } - - public void clear() { - if (initialCapacity != -1) - buf = new UnboundedFifoByteBuffer(initialCapacity); - else - buf = new UnboundedFifoByteBuffer(); - } - - public Iterator iterator() { - return buf.iterator(); - } - - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/DecoderUtil.java deleted file mode 100644 index 48fe07dee..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/DecoderUtil.java +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed -import org.apache.james.mime4j.util.CharsetUtil; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -/** - * Static methods for decoding strings, byte arrays and encoded words. - * - * - * @version $Id: DecoderUtil.java,v 1.3 2005/02/07 15:33:59 ntherning Exp $ - */ -public class DecoderUtil { - private static Log log = LogFactory.getLog(DecoderUtil.class); - - /** - * Decodes a string containing quoted-printable encoded data. - * - * @param s the string to decode. - * @return the decoded bytes. - */ - public static byte[] decodeBaseQuotedPrintable(String s) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - try { - byte[] bytes = s.getBytes("US-ASCII"); - - QuotedPrintableInputStream is = new QuotedPrintableInputStream( - new ByteArrayInputStream(bytes)); - - int b = 0; - while ((b = is.read()) != -1) { - baos.write(b); - } - } catch (IOException e) { - /* - * This should never happen! - */ - log.error(e); - } - - return baos.toByteArray(); - } - - /** - * Decodes a string containing base64 encoded data. - * - * @param s the string to decode. - * @return the decoded bytes. - */ - public static byte[] decodeBase64(String s) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - try { - byte[] bytes = s.getBytes("US-ASCII"); - - Base64InputStream is = new Base64InputStream( - new ByteArrayInputStream(bytes)); - - int b = 0; - while ((b = is.read()) != -1) { - baos.write(b); - } - } catch (IOException e) { - /* - * This should never happen! - */ - log.error(e); - } - - return baos.toByteArray(); - } - - /** - * Decodes an encoded word encoded with the 'B' encoding (described in - * RFC 2047) found in a header field body. - * - * @param encodedWord the encoded word to decode. - * @param charset the Java charset to use. - * @return the decoded string. - * @throws UnsupportedEncodingException if the given Java charset isn't - * supported. - */ - public static String decodeB(String encodedWord, String charset) - throws UnsupportedEncodingException { - - return new String(decodeBase64(encodedWord), charset); - } - - /** - * Decodes an encoded word encoded with the 'Q' encoding (described in - * RFC 2047) found in a header field body. - * - * @param encodedWord the encoded word to decode. - * @param charset the Java charset to use. - * @return the decoded string. - * @throws UnsupportedEncodingException if the given Java charset isn't - * supported. - */ - public static String decodeQ(String encodedWord, String charset) - throws UnsupportedEncodingException { - - /* - * Replace _ with =20 - */ - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < encodedWord.length(); i++) { - char c = encodedWord.charAt(i); - if (c == '_') { - sb.append("=20"); - } else { - sb.append(c); - } - } - - return new String(decodeBaseQuotedPrintable(sb.toString()), charset); - } - - /** - * Decodes a string containing encoded words as defined by RFC 2047. - * Encoded words in have the form - * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for - * quoted-printable and 'B' or 'b' for Base64. - * - * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J - * - * @param body the string to decode. - * @return the decoded string. - */ - public static String decodeEncodedWords(String body) { - - // ANDROID: Most strings will not include "=?" so a quick test can prevent unneeded - // object creation. This could also be handled via lazy creation of the StringBuilder. - if (body.indexOf("=?") == -1) { - return body; - } - - int previousEnd = 0; - boolean previousWasEncoded = false; - - StringBuilder sb = new StringBuilder(); - - while (true) { - int begin = body.indexOf("=?", previousEnd); - - // ANDROID: The mime4j original version has an error here. It gets confused if - // the encoded string begins with an '=' (just after "?Q?"). This patch seeks forward - // to find the two '?' in the "header", before looking for the final "?=". - if (begin == -1) { - break; - } - int qm1 = body.indexOf('?', begin + 2); - if (qm1 == -1) { - break; - } - int qm2 = body.indexOf('?', qm1 + 1); - if (qm2 == -1) { - break; - } - int end = body.indexOf("?=", qm2 + 1); - if (end == -1) { - break; - } - end += 2; - - String sep = body.substring(previousEnd, begin); - - String decoded = decodeEncodedWord(body, begin, end); - if (decoded == null) { - sb.append(sep); - sb.append(body.substring(begin, end)); - } else { - if (!previousWasEncoded || !CharsetUtil.isWhitespace(sep)) { - sb.append(sep); - } - sb.append(decoded); - } - - previousEnd = end; - previousWasEncoded = decoded != null; - } - - if (previousEnd == 0) - return body; - - sb.append(body.substring(previousEnd)); - return sb.toString(); - } - - // return null on error. Begin is index of '=?' in body. - public static String decodeEncodedWord(String body, int begin, int end) { - // Skip the '?=' chars in body and scan forward from there for next '?' - int qm1 = body.indexOf('?', begin + 2); - if (qm1 == -1 || qm1 == end - 2) - return null; - - int qm2 = body.indexOf('?', qm1 + 1); - if (qm2 == -1 || qm2 == end - 2) - return null; - - String mimeCharset = body.substring(begin + 2, qm1); - String encoding = body.substring(qm1 + 1, qm2); - String encodedText = body.substring(qm2 + 1, end - 2); - - String charset = CharsetUtil.toJavaCharset(mimeCharset); - if (charset == null) { - if (log.isWarnEnabled()) { - log.warn("MIME charset '" + mimeCharset + "' in encoded word '" - + body.substring(begin, end) + "' doesn't have a " - + "corresponding Java charset"); - } - return null; - } else if (!CharsetUtil.isDecodingSupported(charset)) { - if (log.isWarnEnabled()) { - log.warn("Current JDK doesn't support decoding of charset '" - + charset + "' (MIME charset '" + mimeCharset - + "' in encoded word '" + body.substring(begin, end) - + "')"); - } - return null; - } - - if (encodedText.length() == 0) { - if (log.isWarnEnabled()) { - log.warn("Missing encoded text in encoded word: '" - + body.substring(begin, end) + "'"); - } - return null; - } - - try { - if (encoding.equalsIgnoreCase("Q")) { - return DecoderUtil.decodeQ(encodedText, charset); - } else if (encoding.equalsIgnoreCase("B")) { - return DecoderUtil.decodeB(encodedText, charset); - } else { - if (log.isWarnEnabled()) { - log.warn("Warning: Unknown encoding in encoded word '" - + body.substring(begin, end) + "'"); - } - return null; - } - } catch (UnsupportedEncodingException e) { - // should not happen because of isDecodingSupported check above - if (log.isWarnEnabled()) { - log.warn("Unsupported encoding in encoded word '" - + body.substring(begin, end) + "'", e); - } - return null; - } catch (RuntimeException e) { - if (log.isWarnEnabled()) { - log.warn("Could not decode encoded word '" - + body.substring(begin, end) + "'", e); - } - return null; - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java deleted file mode 100644 index e43f398f9..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.io.IOException; -import java.io.InputStream; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed - -/** - * Performs Quoted-Printable decoding on an underlying stream. - * - * - * - * @version $Id: QuotedPrintableInputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $ - */ -public class QuotedPrintableInputStream extends InputStream { - private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class); - - private InputStream stream; - ByteQueue byteq = new ByteQueue(); - ByteQueue pushbackq = new ByteQueue(); - private byte state = 0; - - public QuotedPrintableInputStream(InputStream stream) { - this.stream = stream; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - stream.close(); - } - - public int read() throws IOException { - fillBuffer(); - if (byteq.count() == 0) - return -1; - else { - byte val = byteq.dequeue(); - if (val >= 0) - return val; - else - return val & 0xFF; - } - } - - /** - * Pulls bytes out of the underlying stream and places them in the - * pushback queue. This is necessary (vs. reading from the - * underlying stream directly) to detect and filter out "transport - * padding" whitespace, i.e., all whitespace that appears immediately - * before a CRLF. - * - * @throws IOException Underlying stream threw IOException. - */ - private void populatePushbackQueue() throws IOException { - //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!"); - - if (pushbackq.count() != 0) - return; - - while (true) { - int i = stream.read(); - switch (i) { - case -1: - // stream is done - pushbackq.clear(); // discard any whitespace preceding EOF - return; - case ' ': - case '\t': - pushbackq.enqueue((byte)i); - break; - case '\r': - case '\n': - pushbackq.clear(); // discard any whitespace preceding EOL - pushbackq.enqueue((byte)i); - return; - default: - pushbackq.enqueue((byte)i); - return; - } - } - } - - /** - * Causes the pushback queue to get populated if it is empty, then - * consumes and decodes bytes out of it until one or more bytes are - * in the byte queue. This decoding step performs the actual QP - * decoding. - * - * @throws IOException Underlying stream threw IOException. - */ - private void fillBuffer() throws IOException { - byte msdChar = 0; // first digit of escaped num - while (byteq.count() == 0) { - if (pushbackq.count() == 0) { - populatePushbackQueue(); - if (pushbackq.count() == 0) - return; - } - - byte b = (byte)pushbackq.dequeue(); - - switch (state) { - case 0: // start state, no bytes pending - if (b != '=') { - byteq.enqueue(b); - break; // state remains 0 - } else { - state = 1; - break; - } - case 1: // encountered "=" so far - if (b == '\r') { - state = 2; - break; - } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) { - state = 3; - msdChar = b; // save until next digit encountered - break; - } else if (b == '=') { - /* - * Special case when == is encountered. - * Emit one = and stay in this state. - */ - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; got =="); - } - byteq.enqueue((byte)'='); - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected \\r or " - + "[0-9A-Z], got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue(b); - break; - } - case 2: // encountered "=\r" so far - if (b == '\n') { - state = 0; - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected " - + (int)'\n' + ", got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue((byte)'\r'); - byteq.enqueue(b); - break; - } - case 3: // encountered =<digit> so far; expecting another <digit> to complete the octet - if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) { - byte msd = asciiCharToNumericValue(msdChar); - byte low = asciiCharToNumericValue(b); - state = 0; - byteq.enqueue((byte)((msd << 4) | low)); - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected " - + "[0-9A-Z], got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue(msdChar); - byteq.enqueue(b); - break; - } - default: // should never happen - log.error("Illegal state: " + state); - state = 0; - byteq.enqueue(b); - break; - } - } - } - - /** - * Converts '0' => 0, 'A' => 10, etc. - * @param c ASCII character value. - * @return Numeric value of hexadecimal character. - */ - private byte asciiCharToNumericValue(byte c) { - if (c >= '0' && c <= '9') { - return (byte)(c - '0'); - } else if (c >= 'A' && c <= 'Z') { - return (byte)(0xA + (c - 'A')); - } else if (c >= 'a' && c <= 'z') { - return (byte)(0xA + (c - 'a')); - } else { - /* - * This should never happen since all calls to this method - * are preceded by a check that c is in [0-9A-Za-z] - */ - throw new IllegalArgumentException((char) c - + " is not a hexadecimal digit"); - } - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java deleted file mode 100644 index f01194fd1..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java +++ /dev/null @@ -1,272 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * UnboundedFifoByteBuffer is a very efficient buffer implementation. - * According to performance testing, it exhibits a constant access time, but it - * also outperforms ArrayList when used for the same purpose. - * <p> - * The removal order of an <code>UnboundedFifoByteBuffer</code> is based on the insertion - * order; elements are removed in the same order in which they were added. - * The iteration order is the same as the removal order. - * <p> - * The {@link #remove()} and {@link #get()} operations perform in constant time. - * The {@link #add(Object)} operation performs in amortized constant time. All - * other operations perform in linear time or worse. - * <p> - * Note that this implementation is not synchronized. The following can be - * used to provide synchronized access to your <code>UnboundedFifoByteBuffer</code>: - * <pre> - * Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer()); - * </pre> - * <p> - * This buffer prevents null objects from being added. - * - * @since Commons Collections 3.0 (previously in main package v2.1) - * @version $Revision: 1.1 $ $Date: 2004/08/24 06:52:02 $ - * - * - * - * - * - * - */ -class UnboundedFifoByteBuffer { - - protected byte[] buffer; - protected int head; - protected int tail; - - /** - * Constructs an UnboundedFifoByteBuffer with the default number of elements. - * It is exactly the same as performing the following: - * - * <pre> - * new UnboundedFifoByteBuffer(32); - * </pre> - */ - public UnboundedFifoByteBuffer() { - this(32); - } - - /** - * Constructs an UnboundedFifoByteBuffer with the specified number of elements. - * The integer must be a positive integer. - * - * @param initialSize the initial size of the buffer - * @throws IllegalArgumentException if the size is less than 1 - */ - public UnboundedFifoByteBuffer(int initialSize) { - if (initialSize <= 0) { - throw new IllegalArgumentException("The size must be greater than 0"); - } - buffer = new byte[initialSize + 1]; - head = 0; - tail = 0; - } - - /** - * Returns the number of elements stored in the buffer. - * - * @return this buffer's size - */ - public int size() { - int size = 0; - - if (tail < head) { - size = buffer.length - head + tail; - } else { - size = tail - head; - } - - return size; - } - - /** - * Returns true if this buffer is empty; false otherwise. - * - * @return true if this buffer is empty - */ - public boolean isEmpty() { - return (size() == 0); - } - - /** - * Adds the given element to this buffer. - * - * @param b the byte to add - * @return true, always - */ - public boolean add(final byte b) { - - if (size() + 1 >= buffer.length) { - byte[] tmp = new byte[((buffer.length - 1) * 2) + 1]; - - int j = 0; - for (int i = head; i != tail;) { - tmp[j] = buffer[i]; - buffer[i] = 0; - - j++; - i++; - if (i == buffer.length) { - i = 0; - } - } - - buffer = tmp; - head = 0; - tail = j; - } - - buffer[tail] = b; - tail++; - if (tail >= buffer.length) { - tail = 0; - } - return true; - } - - /** - * Returns the next object in the buffer. - * - * @return the next object in the buffer - * @throws BufferUnderflowException if this buffer is empty - */ - public byte get() { - if (isEmpty()) { - throw new IllegalStateException("The buffer is already empty"); - } - - return buffer[head]; - } - - /** - * Removes the next object from the buffer - * - * @return the removed object - * @throws BufferUnderflowException if this buffer is empty - */ - public byte remove() { - if (isEmpty()) { - throw new IllegalStateException("The buffer is already empty"); - } - - byte element = buffer[head]; - - head++; - if (head >= buffer.length) { - head = 0; - } - - return element; - } - - /** - * Increments the internal index. - * - * @param index the index to increment - * @return the updated index - */ - private int increment(int index) { - index++; - if (index >= buffer.length) { - index = 0; - } - return index; - } - - /** - * Decrements the internal index. - * - * @param index the index to decrement - * @return the updated index - */ - private int decrement(int index) { - index--; - if (index < 0) { - index = buffer.length - 1; - } - return index; - } - - /** - * Returns an iterator over this buffer's elements. - * - * @return an iterator over this buffer's elements - */ - public Iterator iterator() { - return new Iterator() { - - private int index = head; - private int lastReturnedIndex = -1; - - public boolean hasNext() { - return index != tail; - - } - - public Object next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - lastReturnedIndex = index; - index = increment(index); - return new Byte(buffer[lastReturnedIndex]); - } - - public void remove() { - if (lastReturnedIndex == -1) { - throw new IllegalStateException(); - } - - // First element can be removed quickly - if (lastReturnedIndex == head) { - UnboundedFifoByteBuffer.this.remove(); - lastReturnedIndex = -1; - return; - } - - // Other elements require us to shift the subsequent elements - int i = lastReturnedIndex + 1; - while (i != tail) { - if (i >= buffer.length) { - buffer[i - 1] = buffer[0]; - i = 0; - } else { - buffer[i - 1] = buffer[i]; - i++; - } - } - - lastReturnedIndex = -1; - tail = decrement(tail); - buffer[tail] = 0; - index = decrement(index); - } - - }; - } - -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/AddressListField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/AddressListField.java deleted file mode 100644 index df9f39835..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/AddressListField.java +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class AddressListField extends Field { - private AddressList addressList; - private ParseException parseException; - - protected AddressListField(String name, String body, String raw, AddressList addressList, ParseException parseException) { - super(name, body, raw); - this.addressList = addressList; - this.parseException = parseException; - } - - public AddressList getAddressList() { - return addressList; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - AddressList addressList = null; - ParseException parseException = null; - try { - addressList = AddressList.parse(body); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new AddressListField(name, body, raw, addressList, parseException); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java deleted file mode 100644 index 73d8d2339..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - - - -/** - * Represents a <code>Content-Transfer-Encoding</code> field. - * - * - * @version $Id: ContentTransferEncodingField.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public class ContentTransferEncodingField extends Field { - /** - * The <code>7bit</code> encoding. - */ - public static final String ENC_7BIT = "7bit"; - /** - * The <code>8bit</code> encoding. - */ - public static final String ENC_8BIT = "8bit"; - /** - * The <code>binary</code> encoding. - */ - public static final String ENC_BINARY = "binary"; - /** - * The <code>quoted-printable</code> encoding. - */ - public static final String ENC_QUOTED_PRINTABLE = "quoted-printable"; - /** - * The <code>base64</code> encoding. - */ - public static final String ENC_BASE64 = "base64"; - - private String encoding; - - protected ContentTransferEncodingField(String name, String body, String raw, String encoding) { - super(name, body, raw); - this.encoding = encoding; - } - - /** - * Gets the encoding defined in this field. - * - * @return the encoding or an empty string if not set. - */ - public String getEncoding() { - return encoding; - } - - /** - * Gets the encoding of the given field if. Returns the default - * <code>7bit</code> if not set or if - * <code>f</code> is <code>null</code>. - * - * @return the encoding. - */ - public static String getEncoding(ContentTransferEncodingField f) { - if (f != null && f.getEncoding().length() != 0) { - return f.getEncoding(); - } - return ENC_7BIT; - } - - public static class Parser implements FieldParser { - public Field parse(final String name, final String body, final String raw) { - final String encoding = body.trim().toLowerCase(); - return new ContentTransferEncodingField(name, body, raw, encoding); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTypeField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTypeField.java deleted file mode 100644 index ad9f7f9ac..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/ContentTypeField.java +++ /dev/null @@ -1,259 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed -import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser; -import org.apache.james.mime4j.field.contenttype.parser.ParseException; -import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError; - -/** - * Represents a <code>Content-Type</code> field. - * - * <p>TODO: Remove dependency on Java 1.4 regexps</p> - * - * - * @version $Id: ContentTypeField.java,v 1.6 2005/01/27 14:16:31 ntherning Exp $ - */ -public class ContentTypeField extends Field { - - /** - * The prefix of all <code>multipart</code> MIME types. - */ - public static final String TYPE_MULTIPART_PREFIX = "multipart/"; - /** - * The <code>multipart/digest</code> MIME type. - */ - public static final String TYPE_MULTIPART_DIGEST = "multipart/digest"; - /** - * The <code>text/plain</code> MIME type. - */ - public static final String TYPE_TEXT_PLAIN = "text/plain"; - /** - * The <code>message/rfc822</code> MIME type. - */ - public static final String TYPE_MESSAGE_RFC822 = "message/rfc822"; - /** - * The name of the <code>boundary</code> parameter. - */ - public static final String PARAM_BOUNDARY = "boundary"; - /** - * The name of the <code>charset</code> parameter. - */ - public static final String PARAM_CHARSET = "charset"; - - private String mimeType = ""; - private Map<String, String> parameters = null; - private ParseException parseException; - - protected ContentTypeField(String name, String body, String raw, String mimeType, Map<String, String> parameters, ParseException parseException) { - super(name, body, raw); - this.mimeType = mimeType; - this.parameters = parameters; - this.parseException = parseException; - } - - /** - * Gets the exception that was raised during parsing of - * the field value, if any; otherwise, null. - */ - public ParseException getParseException() { - return parseException; - } - - /** - * Gets the MIME type defined in this Content-Type field. - * - * @return the MIME type or an empty string if not set. - */ - public String getMimeType() { - return mimeType; - } - - /** - * Gets the MIME type defined in the child's - * Content-Type field or derives a MIME type from the parent - * if child is <code>null</code> or hasn't got a MIME type value set. - * If child's MIME type is multipart but no boundary - * has been set the MIME type of child will be derived from - * the parent. - * - * @param child the child. - * @param parent the parent. - * @return the MIME type. - */ - public static String getMimeType(ContentTypeField child, - ContentTypeField parent) { - - if (child == null || child.getMimeType().length() == 0 - || child.isMultipart() && child.getBoundary() == null) { - - if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) { - return TYPE_MESSAGE_RFC822; - } else { - return TYPE_TEXT_PLAIN; - } - } - - return child.getMimeType(); - } - - /** - * Gets the value of a parameter. Parameter names are case-insensitive. - * - * @param name the name of the parameter to get. - * @return the parameter value or <code>null</code> if not set. - */ - public String getParameter(String name) { - return parameters != null - ? parameters.get(name.toLowerCase()) - : null; - } - - /** - * Gets all parameters. - * - * @return the parameters. - */ - public Map<String, String> getParameters() { - if (parameters != null) { - return Collections.unmodifiableMap(parameters); - } - return Collections.emptyMap(); - } - - /** - * Gets the value of the <code>boundary</code> parameter if set. - * - * @return the <code>boundary</code> parameter value or <code>null</code> - * if not set. - */ - public String getBoundary() { - return getParameter(PARAM_BOUNDARY); - } - - /** - * Gets the value of the <code>charset</code> parameter if set. - * - * @return the <code>charset</code> parameter value or <code>null</code> - * if not set. - */ - public String getCharset() { - return getParameter(PARAM_CHARSET); - } - - /** - * Gets the value of the <code>charset</code> parameter if set for the - * given field. Returns the default <code>us-ascii</code> if not set or if - * <code>f</code> is <code>null</code>. - * - * @return the <code>charset</code> parameter value. - */ - public static String getCharset(ContentTypeField f) { - if (f != null) { - if (f.getCharset() != null && f.getCharset().length() > 0) { - return f.getCharset(); - } - } - return "us-ascii"; - } - - /** - * Determines if the MIME type of this field matches the given one. - * - * @param mimeType the MIME type to match against. - * @return <code>true</code> if the MIME type of this field matches, - * <code>false</code> otherwise. - */ - public boolean isMimeType(String mimeType) { - return this.mimeType.equalsIgnoreCase(mimeType); - } - - /** - * Determines if the MIME type of this field is <code>multipart/*</code>. - * - * @return <code>true</code> if this field is has a <code>multipart/*</code> - * MIME type, <code>false</code> otherwise. - */ - public boolean isMultipart() { - return mimeType.startsWith(TYPE_MULTIPART_PREFIX); - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - ParseException parseException = null; - String mimeType = ""; - Map<String, String> parameters = null; - - ContentTypeParser parser = new ContentTypeParser(new StringReader(body)); - try { - parser.parseAll(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - catch (TokenMgrError e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = new ParseException(e.getMessage()); - } - - try { - final String type = parser.getType(); - final String subType = parser.getSubType(); - - if (type != null && subType != null) { - mimeType = (type + "/" + parser.getSubType()).toLowerCase(); - - ArrayList<String> paramNames = parser.getParamNames(); - ArrayList<String> paramValues = parser.getParamValues(); - - if (paramNames != null && paramValues != null) { - for (int i = 0; i < paramNames.size() && i < paramValues.size(); i++) { - if (parameters == null) - parameters = new HashMap<String, String>((int)(paramNames.size() * 1.3 + 1)); - String paramName = paramNames.get(i).toLowerCase(); - String paramValue = paramValues.get(i); - parameters.put(paramName, paramValue); - } - } - } - } - catch (NullPointerException npe) { - } - return new ContentTypeField(name, body, raw, mimeType, parameters, parseException); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DateTimeField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DateTimeField.java deleted file mode 100644 index 1e6c8e250..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DateTimeField.java +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -//BEGIN android-changed: Stubbing out logging - -import com.android.voicemailomtp.mail.utils.LogUtils; - -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END -import org.apache.james.mime4j.field.datetime.DateTime; -import org.apache.james.mime4j.field.datetime.parser.ParseException; - -import java.util.Date; - -public class DateTimeField extends Field { - private Date date; - private ParseException parseException; - - protected DateTimeField(String name, String body, String raw, Date date, ParseException parseException) { - super(name, body, raw); - this.date = date; - this.parseException = parseException; - } - - public Date getDate() { - return date; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, String body, final String raw) { - Date date = null; - ParseException parseException = null; - //BEGIN android-changed - body = LogUtils.cleanUpMimeDate(body); - //END android-changed - try { - date = DateTime.parse(body).getDate(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new DateTimeField(name, body, raw, date, parseException); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DefaultFieldParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DefaultFieldParser.java deleted file mode 100644 index 3695afe3e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DefaultFieldParser.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -public class DefaultFieldParser extends DelegatingFieldParser { - - public DefaultFieldParser() { - setFieldParser(Field.CONTENT_TRANSFER_ENCODING, new ContentTransferEncodingField.Parser()); - setFieldParser(Field.CONTENT_TYPE, new ContentTypeField.Parser()); - - final DateTimeField.Parser dateTimeParser = new DateTimeField.Parser(); - setFieldParser(Field.DATE, dateTimeParser); - setFieldParser(Field.RESENT_DATE, dateTimeParser); - - final MailboxListField.Parser mailboxListParser = new MailboxListField.Parser(); - setFieldParser(Field.FROM, mailboxListParser); - setFieldParser(Field.RESENT_FROM, mailboxListParser); - - final MailboxField.Parser mailboxParser = new MailboxField.Parser(); - setFieldParser(Field.SENDER, mailboxParser); - setFieldParser(Field.RESENT_SENDER, mailboxParser); - - final AddressListField.Parser addressListParser = new AddressListField.Parser(); - setFieldParser(Field.TO, addressListParser); - setFieldParser(Field.RESENT_TO, addressListParser); - setFieldParser(Field.CC, addressListParser); - setFieldParser(Field.RESENT_CC, addressListParser); - setFieldParser(Field.BCC, addressListParser); - setFieldParser(Field.RESENT_BCC, addressListParser); - setFieldParser(Field.REPLY_TO, addressListParser); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DelegatingFieldParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DelegatingFieldParser.java deleted file mode 100644 index 32b69ec13..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/DelegatingFieldParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -import java.util.HashMap; -import java.util.Map; - -public class DelegatingFieldParser implements FieldParser { - - private Map<String, FieldParser> parsers = new HashMap<String, FieldParser>(); - private FieldParser defaultParser = new UnstructuredField.Parser(); - - /** - * Sets the parser used for the field named <code>name</code>. - * @param name the name of the field - * @param parser the parser for fields named <code>name</code> - */ - public void setFieldParser(final String name, final FieldParser parser) { - parsers.put(name.toLowerCase(), parser); - } - - public FieldParser getParser(final String name) { - final FieldParser field = parsers.get(name.toLowerCase()); - if(field==null) { - return defaultParser; - } - return field; - } - - public Field parse(final String name, final String body, final String raw) { - final FieldParser parser = getParser(name); - return parser.parse(name, body, raw); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/Field.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/Field.java deleted file mode 100644 index 4dea5c5cf..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/Field.java +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The base class of all field classes. - * - * - * @version $Id: Field.java,v 1.6 2004/10/25 07:26:46 ntherning Exp $ - */ -public abstract class Field { - public static final String SENDER = "Sender"; - public static final String FROM = "From"; - public static final String TO = "To"; - public static final String CC = "Cc"; - public static final String BCC = "Bcc"; - public static final String REPLY_TO = "Reply-To"; - public static final String RESENT_SENDER = "Resent-Sender"; - public static final String RESENT_FROM = "Resent-From"; - public static final String RESENT_TO = "Resent-To"; - public static final String RESENT_CC = "Resent-Cc"; - public static final String RESENT_BCC = "Resent-Bcc"; - - public static final String DATE = "Date"; - public static final String RESENT_DATE = "Resent-Date"; - - public static final String SUBJECT = "Subject"; - public static final String CONTENT_TYPE = "Content-Type"; - public static final String CONTENT_TRANSFER_ENCODING = - "Content-Transfer-Encoding"; - - private static final String FIELD_NAME_PATTERN = - "^([\\x21-\\x39\\x3b-\\x7e]+)[ \t]*:"; - private static final Pattern fieldNamePattern = - Pattern.compile(FIELD_NAME_PATTERN); - - private static final DefaultFieldParser parser = new DefaultFieldParser(); - - private final String name; - private final String body; - private final String raw; - - protected Field(final String name, final String body, final String raw) { - this.name = name; - this.body = body; - this.raw = raw; - } - - /** - * Parses the given string and returns an instance of the - * <code>Field</code> class. The type of the class returned depends on - * the field name: - * <table> - * <tr> - * <td><em>Field name</em></td><td><em>Class returned</em></td> - * <td>Content-Type</td><td>org.apache.james.mime4j.field.ContentTypeField</td> - * <td>other</td><td>org.apache.james.mime4j.field.UnstructuredField</td> - * </tr> - * </table> - * - * @param s the string to parse. - * @return a <code>Field</code> instance. - * @throws IllegalArgumentException on parse errors. - */ - public static Field parse(final String raw) { - - /* - * Unfold the field. - */ - final String unfolded = raw.replaceAll("\r|\n", ""); - - /* - * Split into name and value. - */ - final Matcher fieldMatcher = fieldNamePattern.matcher(unfolded); - if (!fieldMatcher.find()) { - throw new IllegalArgumentException("Invalid field in string"); - } - final String name = fieldMatcher.group(1); - - String body = unfolded.substring(fieldMatcher.end()); - if (body.length() > 0 && body.charAt(0) == ' ') { - body = body.substring(1); - } - - return parser.parse(name, body, raw); - } - - /** - * Gets the default parser used to parse fields. - * @return the default field parser - */ - public static DefaultFieldParser getParser() { - return parser; - } - - /** - * Gets the name of the field (<code>Subject</code>, - * <code>From</code>, etc). - * - * @return the field name. - */ - public String getName() { - return name; - } - - /** - * Gets the original raw field string. - * - * @return the original raw field string. - */ - public String getRaw() { - return raw; - } - - /** - * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field - * body string. - * - * @return the unfolded unparsed field body string. - */ - public String getBody() { - return body; - } - - /** - * Determines if this is a <code>Content-Type</code> field. - * - * @return <code>true</code> if this is a <code>Content-Type</code> field, - * <code>false</code> otherwise. - */ - public boolean isContentType() { - return CONTENT_TYPE.equalsIgnoreCase(name); - } - - /** - * Determines if this is a <code>Subject</code> field. - * - * @return <code>true</code> if this is a <code>Subject</code> field, - * <code>false</code> otherwise. - */ - public boolean isSubject() { - return SUBJECT.equalsIgnoreCase(name); - } - - /** - * Determines if this is a <code>From</code> field. - * - * @return <code>true</code> if this is a <code>From</code> field, - * <code>false</code> otherwise. - */ - public boolean isFrom() { - return FROM.equalsIgnoreCase(name); - } - - /** - * Determines if this is a <code>To</code> field. - * - * @return <code>true</code> if this is a <code>To</code> field, - * <code>false</code> otherwise. - */ - public boolean isTo() { - return TO.equalsIgnoreCase(name); - } - - /** - * @see #getRaw() - */ - public String toString() { - return raw; - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/FieldParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/FieldParser.java deleted file mode 100644 index 78aaf1334..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/FieldParser.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -public interface FieldParser { - - Field parse(final String name, final String body, final String raw); -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxField.java deleted file mode 100644 index f15980055..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxField.java +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.Mailbox; -import org.apache.james.mime4j.field.address.MailboxList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class MailboxField extends Field { - private final Mailbox mailbox; - private final ParseException parseException; - - protected MailboxField(final String name, final String body, final String raw, final Mailbox mailbox, final ParseException parseException) { - super(name, body, raw); - this.mailbox = mailbox; - this.parseException = parseException; - } - - public Mailbox getMailbox() { - return mailbox; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - Mailbox mailbox = null; - ParseException parseException = null; - try { - MailboxList mailboxList = AddressList.parse(body).flatten(); - if (mailboxList.size() > 0) { - mailbox = mailboxList.get(0); - } - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new MailboxField(name, body, raw, mailbox, parseException); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxListField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxListField.java deleted file mode 100644 index 23378d4fa..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/MailboxListField.java +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.MailboxList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class MailboxListField extends Field { - - private MailboxList mailboxList; - private ParseException parseException; - - protected MailboxListField(final String name, final String body, final String raw, final MailboxList mailboxList, final ParseException parseException) { - super(name, body, raw); - this.mailboxList = mailboxList; - this.parseException = parseException; - } - - public MailboxList getMailboxList() { - return mailboxList; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - MailboxList mailboxList = null; - ParseException parseException = null; - try { - mailboxList = AddressList.parse(body).flatten(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new MailboxListField(name, body, raw, mailboxList, parseException); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/UnstructuredField.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/UnstructuredField.java deleted file mode 100644 index 6084e4435..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/UnstructuredField.java +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.james.mime4j.decoder.DecoderUtil; - - -/** - * Simple unstructured field such as <code>Subject</code>. - * - * - * @version $Id: UnstructuredField.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $ - */ -public class UnstructuredField extends Field { - private String value; - - protected UnstructuredField(String name, String body, String raw, String value) { - super(name, body, raw); - this.value = value; - } - - public String getValue() { - return value; - } - - public static class Parser implements FieldParser { - public Field parse(final String name, final String body, final String raw) { - final String value = DecoderUtil.decodeEncodedWords(body); - return new UnstructuredField(name, body, raw, value); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Address.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Address.java deleted file mode 100644 index 3e24e91aa..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Address.java +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * The abstract base for classes that represent RFC2822 addresses. - * This includes groups and mailboxes. - * - * Currently, no public methods are introduced on this class. - * - * - */ -public abstract class Address { - - /** - * Adds any mailboxes represented by this address - * into the given ArrayList. Note that this method - * has default (package) access, so a doAddMailboxesTo - * method is needed to allow the behavior to be - * overridden by subclasses. - */ - final void addMailboxesTo(ArrayList<Address> results) { - doAddMailboxesTo(results); - } - - /** - * Adds any mailboxes represented by this address - * into the given ArrayList. Must be overridden by - * concrete subclasses. - */ - protected abstract void doAddMailboxesTo(ArrayList<Address> results); - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/AddressList.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/AddressList.java deleted file mode 100644 index 1829e79aa..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/AddressList.java +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import org.apache.james.mime4j.field.address.parser.AddressListParser; -import org.apache.james.mime4j.field.address.parser.ParseException; - -import java.io.StringReader; -import java.util.ArrayList; - -/** - * An immutable, random-access list of Address objects. - * - * - */ -public class AddressList { - - private ArrayList<Address> addresses; - - /** - * @param addresses An ArrayList that contains only Address objects. - * @param dontCopy true iff it is not possible for the addresses ArrayList to be modified by someone else. - */ - public AddressList(ArrayList<Address> addresses, boolean dontCopy) { - if (addresses != null) - this.addresses = (dontCopy ? addresses : new ArrayList<Address>(addresses)); - else - this.addresses = new ArrayList<Address>(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return addresses.size(); - } - - /** - * Gets an address. - */ - public Address get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return addresses.get(index); - } - - /** - * Returns a flat list of all mailboxes represented - * in this address list. Use this if you don't care - * about grouping. - */ - public MailboxList flatten() { - // in the common case, all addresses are mailboxes - boolean groupDetected = false; - for (int i = 0; i < size(); i++) { - if (!(get(i) instanceof Mailbox)) { - groupDetected = true; - break; - } - } - - if (!groupDetected) - return new MailboxList(addresses, true); - - ArrayList<Address> results = new ArrayList<Address>(); - for (int i = 0; i < size(); i++) { - Address addr = get(i); - addr.addMailboxesTo(results); - } - - // copy-on-construct this time, because subclasses - // could have held onto a reference to the results - return new MailboxList(results, false); - } - - /** - * Dumps a representation of this address list to - * stdout, for debugging purposes. - */ - public void print() { - for (int i = 0; i < size(); i++) { - Address addr = get(i); - System.out.println(addr.toString()); - } - } - - /** - * Parse the address list string, such as the value - * of a From, To, Cc, Bcc, Sender, or Reply-To - * header. - * - * The string MUST be unfolded already. - */ - public static AddressList parse(String rawAddressList) throws ParseException { - AddressListParser parser = new AddressListParser(new StringReader(rawAddressList)); - return Builder.getInstance().buildAddressList(parser.parse()); - } - - /** - * Test console. - */ - public static void main(String[] args) throws Exception { - java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); - while (true) { - try { - System.out.print("> "); - String line = reader.readLine(); - if (line.length() == 0 || line.toLowerCase().equals("exit") || line.toLowerCase().equals("quit")) { - System.out.println("Goodbye."); - return; - } - AddressList list = parse(line); - list.print(); - } - catch(Exception e) { - e.printStackTrace(); - Thread.sleep(300); - } - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Builder.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Builder.java deleted file mode 100644 index 3bcd15b6f..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Builder.java +++ /dev/null @@ -1,243 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; -import java.util.Iterator; - -import org.apache.james.mime4j.decoder.DecoderUtil; -import org.apache.james.mime4j.field.address.parser.ASTaddr_spec; -import org.apache.james.mime4j.field.address.parser.ASTaddress; -import org.apache.james.mime4j.field.address.parser.ASTaddress_list; -import org.apache.james.mime4j.field.address.parser.ASTangle_addr; -import org.apache.james.mime4j.field.address.parser.ASTdomain; -import org.apache.james.mime4j.field.address.parser.ASTgroup_body; -import org.apache.james.mime4j.field.address.parser.ASTlocal_part; -import org.apache.james.mime4j.field.address.parser.ASTmailbox; -import org.apache.james.mime4j.field.address.parser.ASTname_addr; -import org.apache.james.mime4j.field.address.parser.ASTphrase; -import org.apache.james.mime4j.field.address.parser.ASTroute; -import org.apache.james.mime4j.field.address.parser.Node; -import org.apache.james.mime4j.field.address.parser.SimpleNode; -import org.apache.james.mime4j.field.address.parser.Token; - -/** - * Transforms the JJTree-generated abstract syntax tree - * into a graph of org.apache.james.mime4j.field.address objects. - * - * - */ -class Builder { - - private static Builder singleton = new Builder(); - - public static Builder getInstance() { - return singleton; - } - - - - public AddressList buildAddressList(ASTaddress_list node) { - ArrayList<Address> list = new ArrayList<Address>(); - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - ASTaddress childNode = (ASTaddress) node.jjtGetChild(i); - Address address = buildAddress(childNode); - list.add(address); - } - return new AddressList(list, true); - } - - private Address buildAddress(ASTaddress node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - if (n instanceof ASTaddr_spec) { - return buildAddrSpec((ASTaddr_spec)n); - } - else if (n instanceof ASTangle_addr) { - return buildAngleAddr((ASTangle_addr)n); - } - else if (n instanceof ASTphrase) { - String name = buildString((ASTphrase)n, false); - Node n2 = it.nextNode(); - if (n2 instanceof ASTgroup_body) { - return new Group(name, buildGroupBody((ASTgroup_body)n2)); - } - else if (n2 instanceof ASTangle_addr) { - name = DecoderUtil.decodeEncodedWords(name); - return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2)); - } - else { - throw new IllegalStateException(); - } - } - else { - throw new IllegalStateException(); - } - } - - - - private MailboxList buildGroupBody(ASTgroup_body node) { - ArrayList<Address> results = new ArrayList<Address>(); - ChildNodeIterator it = new ChildNodeIterator(node); - while (it.hasNext()) { - Node n = it.nextNode(); - if (n instanceof ASTmailbox) - results.add(buildMailbox((ASTmailbox)n)); - else - throw new IllegalStateException(); - } - return new MailboxList(results, true); - } - - private Mailbox buildMailbox(ASTmailbox node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - if (n instanceof ASTaddr_spec) { - return buildAddrSpec((ASTaddr_spec)n); - } - else if (n instanceof ASTangle_addr) { - return buildAngleAddr((ASTangle_addr)n); - } - else if (n instanceof ASTname_addr) { - return buildNameAddr((ASTname_addr)n); - } - else { - throw new IllegalStateException(); - } - } - - private NamedMailbox buildNameAddr(ASTname_addr node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - String name; - if (n instanceof ASTphrase) { - name = buildString((ASTphrase)n, false); - } - else { - throw new IllegalStateException(); - } - - n = it.nextNode(); - if (n instanceof ASTangle_addr) { - name = DecoderUtil.decodeEncodedWords(name); - return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n)); - } - else { - throw new IllegalStateException(); - } - } - - private Mailbox buildAngleAddr(ASTangle_addr node) { - ChildNodeIterator it = new ChildNodeIterator(node); - DomainList route = null; - Node n = it.nextNode(); - if (n instanceof ASTroute) { - route = buildRoute((ASTroute)n); - n = it.nextNode(); - } - else if (n instanceof ASTaddr_spec) - ; // do nothing - else - throw new IllegalStateException(); - - if (n instanceof ASTaddr_spec) - return buildAddrSpec(route, (ASTaddr_spec)n); - else - throw new IllegalStateException(); - } - - private DomainList buildRoute(ASTroute node) { - ArrayList<String> results = new ArrayList<String>(node.jjtGetNumChildren()); - ChildNodeIterator it = new ChildNodeIterator(node); - while (it.hasNext()) { - Node n = it.nextNode(); - if (n instanceof ASTdomain) - results.add(buildString((ASTdomain)n, true)); - else - throw new IllegalStateException(); - } - return new DomainList(results, true); - } - - private Mailbox buildAddrSpec(ASTaddr_spec node) { - return buildAddrSpec(null, node); - } - private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) { - ChildNodeIterator it = new ChildNodeIterator(node); - String localPart = buildString((ASTlocal_part)it.nextNode(), true); - String domain = buildString((ASTdomain)it.nextNode(), true); - return new Mailbox(route, localPart, domain); - } - - - private String buildString(SimpleNode node, boolean stripSpaces) { - Token head = node.firstToken; - Token tail = node.lastToken; - StringBuffer out = new StringBuffer(); - - while (head != tail) { - out.append(head.image); - head = head.next; - if (!stripSpaces) - addSpecials(out, head.specialToken); - } - out.append(tail.image); - - return out.toString(); - } - - private void addSpecials(StringBuffer out, Token specialToken) { - if (specialToken != null) { - addSpecials(out, specialToken.specialToken); - out.append(specialToken.image); - } - } - - private static class ChildNodeIterator implements Iterator<Node> { - - private SimpleNode simpleNode; - private int index; - private int len; - - public ChildNodeIterator(SimpleNode simpleNode) { - this.simpleNode = simpleNode; - this.len = simpleNode.jjtGetNumChildren(); - this.index = 0; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return index < len; - } - - public Node next() { - return nextNode(); - } - - public Node nextNode() { - return simpleNode.jjtGetChild(index++); - } - - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/DomainList.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/DomainList.java deleted file mode 100644 index 49b0f3be5..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/DomainList.java +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * An immutable, random-access list of Strings (that - * are supposedly domain names or domain literals). - * - * - */ -public class DomainList { - private ArrayList<String> domains; - - /** - * @param domains An ArrayList that contains only String objects. - * @param dontCopy true iff it is not possible for the domains ArrayList to be modified by someone else. - */ - public DomainList(ArrayList<String> domains, boolean dontCopy) { - if (domains != null) - this.domains = (dontCopy ? domains : new ArrayList<String>(domains)); - else - this.domains = new ArrayList<String>(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return domains.size(); - } - - /** - * Gets the domain name or domain literal at the - * specified index. - * @throws IndexOutOfBoundsException If index is < 0 or >= size(). - */ - public String get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return domains.get(index); - } - - /** - * Returns the list of domains formatted as a route - * string (not including the trailing ':'). - */ - public String toRouteString() { - StringBuffer out = new StringBuffer(); - for (int i = 0; i < domains.size(); i++) { - out.append("@"); - out.append(get(i)); - if (i + 1 < domains.size()) - out.append(","); - } - return out.toString(); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Group.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Group.java deleted file mode 100644 index c0ab7f724..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Group.java +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * A named group of zero or more mailboxes. - * - * - */ -public class Group extends Address { - private String name; - private MailboxList mailboxList; - - /** - * @param name The group name. - * @param mailboxes The mailboxes in this group. - */ - public Group(String name, MailboxList mailboxes) { - this.name = name; - this.mailboxList = mailboxes; - } - - /** - * Returns the group name. - */ - public String getName() { - return name; - } - - /** - * Returns the mailboxes in this group. - */ - public MailboxList getMailboxes() { - return mailboxList; - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append(name); - buf.append(":"); - for (int i = 0; i < mailboxList.size(); i++) { - buf.append(mailboxList.get(i).toString()); - if (i + 1 < mailboxList.size()) - buf.append(","); - } - buf.append(";"); - return buf.toString(); - } - - @Override - protected void doAddMailboxesTo(ArrayList<Address> results) { - for (int i = 0; i < mailboxList.size(); i++) - results.add(mailboxList.get(i)); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Mailbox.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Mailbox.java deleted file mode 100644 index 25f2548d4..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/Mailbox.java +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * Represents a single e-mail address. - * - * - */ -public class Mailbox extends Address { - private DomainList route; - private String localPart; - private String domain; - - /** - * Creates a mailbox without a route. Routes are obsolete. - * @param localPart The part of the e-mail address to the left of the "@". - * @param domain The part of the e-mail address to the right of the "@". - */ - public Mailbox(String localPart, String domain) { - this(null, localPart, domain); - } - - /** - * Creates a mailbox with a route. Routes are obsolete. - * @param route The zero or more domains that make up the route. Can be null. - * @param localPart The part of the e-mail address to the left of the "@". - * @param domain The part of the e-mail address to the right of the "@". - */ - public Mailbox(DomainList route, String localPart, String domain) { - this.route = route; - this.localPart = localPart; - this.domain = domain; - } - - /** - * Returns the route list. - */ - public DomainList getRoute() { - return route; - } - - /** - * Returns the left part of the e-mail address - * (before "@"). - */ - public String getLocalPart() { - return localPart; - } - - /** - * Returns the right part of the e-mail address - * (after "@"). - */ - public String getDomain() { - return domain; - } - - /** - * Formats the address as a string, not including - * the route. - * - * @see #getAddressString(boolean) - */ - public String getAddressString() { - return getAddressString(false); - } - - /** - * Note that this value may not be usable - * for transport purposes, only display purposes. - * - * For example, if the unparsed address was - * - * <"Joe Cheng"@joecheng.com> - * - * this method would return - * - * <Joe Cheng@joecheng.com> - * - * which is not valid for transport; the local part - * would need to be re-quoted. - * - * @param includeRoute true if the route should be included if it exists. - */ - public String getAddressString(boolean includeRoute) { - return "<" + (!includeRoute || route == null ? "" : route.toRouteString() + ":") - + localPart - + (domain == null ? "" : "@") - + domain + ">"; - } - - @Override - protected final void doAddMailboxesTo(ArrayList<Address> results) { - results.add(this); - } - - @Override - public String toString() { - return getAddressString(); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/MailboxList.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/MailboxList.java deleted file mode 100644 index 2c9efb37f..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/MailboxList.java +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * An immutable, random-access list of Mailbox objects. - * - * - */ -public class MailboxList { - - private ArrayList<Address> mailboxes; - - /** - * @param mailboxes An ArrayList that contains only Mailbox objects. - * @param dontCopy true iff it is not possible for the mailboxes ArrayList to be modified by someone else. - */ - public MailboxList(ArrayList<Address> mailboxes, boolean dontCopy) { - if (mailboxes != null) - this.mailboxes = (dontCopy ? mailboxes : new ArrayList<Address>(mailboxes)); - else - this.mailboxes = new ArrayList<Address>(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return mailboxes.size(); - } - - /** - * Gets an address. - */ - public Mailbox get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return (Mailbox)mailboxes.get(index); - } - - /** - * Dumps a representation of this mailbox list to - * stdout, for debugging purposes. - */ - public void print() { - for (int i = 0; i < size(); i++) { - Mailbox mailbox = get(i); - System.out.println(mailbox.toString()); - } - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/NamedMailbox.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/NamedMailbox.java deleted file mode 100644 index 4b8306037..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/NamedMailbox.java +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -/** - * A Mailbox that has a name/description. - * - * - */ -public class NamedMailbox extends Mailbox { - private String name; - - /** - * @see Mailbox#Mailbox(String, String) - */ - public NamedMailbox(String name, String localPart, String domain) { - super(localPart, domain); - this.name = name; - } - - /** - * @see Mailbox#Mailbox(DomainList, String, String) - */ - public NamedMailbox(String name, DomainList route, String localPart, String domain) { - super(route, localPart, domain); - this.name = name; - } - - /** - * Creates a named mailbox based on an unnamed mailbox. - */ - public NamedMailbox(String name, Mailbox baseMailbox) { - super(baseMailbox.getRoute(), baseMailbox.getLocalPart(), baseMailbox.getDomain()); - this.name = name; - } - - /** - * Returns the name of the mailbox. - */ - public String getName() { - return this.name; - } - - /** - * Same features (or problems) as Mailbox.getAddressString(boolean), - * only more so. - * - * @see Mailbox#getAddressString(boolean) - */ - @Override - public String getAddressString(boolean includeRoute) { - return (name == null ? "" : name + " ") + super.getAddressString(includeRoute); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java deleted file mode 100644 index 4d56d000b..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddr_spec.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddr_spec extends SimpleNode { - public ASTaddr_spec(int id) { - super(id); - } - - public ASTaddr_spec(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java deleted file mode 100644 index 47bdeda8e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddress.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddress extends SimpleNode { - public ASTaddress(int id) { - super(id); - } - - public ASTaddress(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java deleted file mode 100644 index 737840e38..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddress_list.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddress_list extends SimpleNode { - public ASTaddress_list(int id) { - super(id); - } - - public ASTaddress_list(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java deleted file mode 100644 index 8cb8f421f..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTangle_addr.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTangle_addr extends SimpleNode { - public ASTangle_addr(int id) { - super(id); - } - - public ASTangle_addr(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java deleted file mode 100644 index b52664386..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTdomain.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTdomain extends SimpleNode { - public ASTdomain(int id) { - super(id); - } - - public ASTdomain(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java deleted file mode 100644 index f6017b9fc..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTgroup_body.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTgroup_body extends SimpleNode { - public ASTgroup_body(int id) { - super(id); - } - - public ASTgroup_body(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java deleted file mode 100644 index 5c244fa3e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTlocal_part.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTlocal_part extends SimpleNode { - public ASTlocal_part(int id) { - super(id); - } - - public ASTlocal_part(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java deleted file mode 100644 index aeb469da1..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTmailbox.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTmailbox extends SimpleNode { - public ASTmailbox(int id) { - super(id); - } - - public ASTmailbox(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java deleted file mode 100644 index 846c73167..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTname_addr.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTname_addr extends SimpleNode { - public ASTname_addr(int id) { - super(id); - } - - public ASTname_addr(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java deleted file mode 100644 index 7d711c529..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTphrase.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTphrase extends SimpleNode { - public ASTphrase(int id) { - super(id); - } - - public ASTphrase(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTroute.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTroute.java deleted file mode 100644 index 54ea11523..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ASTroute.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTroute.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTroute extends SimpleNode { - public ASTroute(int id) { - super(id); - } - - public ASTroute(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java deleted file mode 100644 index 8094df0ad..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java +++ /dev/null @@ -1,977 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants, AddressListParserConstants {/*@bgen(jjtree)*/ - protected JJTAddressListParserState jjtree = new JJTAddressListParserState();public static void main(String args[]) throws ParseException { - while (true) { - try { - AddressListParser parser = new AddressListParser(System.in); - parser.parseLine(); - ((SimpleNode)parser.jjtree.rootNode()).dump("> "); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static void log(String msg) { - System.out.print(msg); - } - - public ASTaddress_list parse() throws ParseException { - try { - parseAll(); - return (ASTaddress_list)jjtree.rootNode(); - } catch (TokenMgrError tme) { - throw new ParseException(tme.getMessage()); - } - } - - - void jjtreeOpenNodeScope(Node n) { - ((SimpleNode)n).firstToken = getToken(1); - } - - void jjtreeCloseNodeScope(Node n) { - ((SimpleNode)n).lastToken = getToken(0); - } - - final public void parseLine() throws ParseException { - address_list(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - } - - final public void parseAll() throws ParseException { - address_list(); - jj_consume_token(0); - } - - final public void address_list() throws ParseException { - /*@bgen(jjtree) address_list */ - ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - address(); - break; - default: - jj_la1[1] = jj_gen; - ; - } - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[2] = jj_gen; - break label_1; - } - jj_consume_token(3); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - address(); - break; - default: - jj_la1[3] = jj_gen; - ; - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void address() throws ParseException { - /*@bgen(jjtree) address */ - ASTaddress jjtn000 = new ASTaddress(JJTADDRESS); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - if (jj_2_1(2147483647)) { - addr_spec(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - angle_addr(); - break; - case DOTATOM: - case QUOTEDSTRING: - phrase(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - group_body(); - break; - case 6: - angle_addr(); - break; - default: - jj_la1[4] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void mailbox() throws ParseException { - /*@bgen(jjtree) mailbox */ - ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - if (jj_2_2(2147483647)) { - addr_spec(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - angle_addr(); - break; - case DOTATOM: - case QUOTEDSTRING: - name_addr(); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void name_addr() throws ParseException { - /*@bgen(jjtree) name_addr */ - ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - phrase(); - angle_addr(); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void group_body() throws ParseException { - /*@bgen(jjtree) group_body */ - ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(4); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - mailbox(); - break; - default: - jj_la1[7] = jj_gen; - ; - } - label_2: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[8] = jj_gen; - break label_2; - } - jj_consume_token(3); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - mailbox(); - break; - default: - jj_la1[9] = jj_gen; - ; - } - } - jj_consume_token(5); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void angle_addr() throws ParseException { - /*@bgen(jjtree) angle_addr */ - ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(6); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 8: - route(); - break; - default: - jj_la1[10] = jj_gen; - ; - } - addr_spec(); - jj_consume_token(7); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void route() throws ParseException { - /*@bgen(jjtree) route */ - ASTroute jjtn000 = new ASTroute(JJTROUTE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(8); - domain(); - label_3: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - case 8: - ; - break; - default: - jj_la1[11] = jj_gen; - break label_3; - } - label_4: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[12] = jj_gen; - break label_4; - } - jj_consume_token(3); - } - jj_consume_token(8); - domain(); - } - jj_consume_token(4); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void phrase() throws ParseException { - /*@bgen(jjtree) phrase */ - ASTphrase jjtn000 = new ASTphrase(JJTPHRASE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - label_5: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[13] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - case QUOTEDSTRING: - ; - break; - default: - jj_la1[14] = jj_gen; - break label_5; - } - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void addr_spec() throws ParseException { - /*@bgen(jjtree) addr_spec */ - ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - local_part(); - jj_consume_token(8); - domain(); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void local_part() throws ParseException { - /*@bgen(jjtree) local_part */ - ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000);Token t; - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[15] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - label_6: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - case DOTATOM: - case QUOTEDSTRING: - ; - break; - default: - jj_la1[16] = jj_gen; - break label_6; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - t = jj_consume_token(9); - break; - default: - jj_la1[17] = jj_gen; - ; - } - if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING) - {if (true) throw new ParseException("Words in local part must be separated by '.'");} - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[18] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void domain() throws ParseException { - /*@bgen(jjtree) domain */ - ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000);Token t; - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - label_7: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - case DOTATOM: - ; - break; - default: - jj_la1[19] = jj_gen; - break label_7; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - t = jj_consume_token(9); - break; - default: - jj_la1[20] = jj_gen; - ; - } - if (t.image.charAt(t.image.length() - 1) != '.') - {if (true) throw new ParseException("Atoms in domain names must be separated by '.'");} - t = jj_consume_token(DOTATOM); - } - break; - case DOMAINLITERAL: - jj_consume_token(DOMAINLITERAL); - break; - default: - jj_la1[21] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final private boolean jj_2_1(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_1(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(0, xla); } - } - - final private boolean jj_2_2(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_2(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(1, xla); } - } - - final private boolean jj_3R_11() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(9)) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_scan_token(14)) { - jj_scanpos = xsp; - if (jj_scan_token(31)) return true; - } - return false; - } - - final private boolean jj_3R_13() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(9)) jj_scanpos = xsp; - if (jj_scan_token(DOTATOM)) return true; - return false; - } - - final private boolean jj_3R_8() { - if (jj_3R_9()) return true; - if (jj_scan_token(8)) return true; - if (jj_3R_10()) return true; - return false; - } - - final private boolean jj_3_1() { - if (jj_3R_8()) return true; - return false; - } - - final private boolean jj_3R_12() { - if (jj_scan_token(DOTATOM)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_13()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_10() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_12()) { - jj_scanpos = xsp; - if (jj_scan_token(18)) return true; - } - return false; - } - - final private boolean jj_3_2() { - if (jj_3R_8()) return true; - return false; - } - - final private boolean jj_3R_9() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(14)) { - jj_scanpos = xsp; - if (jj_scan_token(31)) return true; - } - while (true) { - xsp = jj_scanpos; - if (jj_3R_11()) { jj_scanpos = xsp; break; } - } - return false; - } - - public AddressListParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private Token jj_scanpos, jj_lastpos; - private int jj_la; - public boolean lookingAhead = false; - private boolean jj_semLA; - private int jj_gen; - final private int[] jj_la1 = new int[22]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static { - jj_la1_0(); - jj_la1_1(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x80004040,0x8,0x80004040,0x50,0x80004040,0x80004040,0x80004040,0x8,0x80004040,0x100,0x108,0x8,0x80004000,0x80004000,0x80004000,0x80004200,0x200,0x80004000,0x4200,0x200,0x44000,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; - } - final private JJCalls[] jj_2_rtns = new JJCalls[2]; - private boolean jj_rescan = false; - private int jj_gc = 0; - - public AddressListParser(java.io.InputStream stream) { - this(stream, null); - } - public AddressListParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new AddressListParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public AddressListParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new AddressListParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public AddressListParser(AddressListParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(AddressListParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns.length; i++) { - JJCalls c = jj_2_rtns[i]; - while (c != null) { - if (c.gen < jj_gen) c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - static private final class LookaheadSuccess extends java.lang.Error { } - final private LookaheadSuccess jj_ls = new LookaheadSuccess(); - final private boolean jj_scan_token(int kind) { - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos.next == null) { - jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos.next; - } - } else { - jj_scanpos = jj_scanpos.next; - } - if (jj_rescan) { - int i = 0; Token tok = token; - while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } - if (tok != null) jj_add_error_token(kind, i); - } - if (jj_scanpos.kind != kind) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; - return false; - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = lookingAhead ? jj_scanpos : token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector<int[]> jj_expentries = new java.util.Vector<int[]>(); - private int[] jj_expentry; - private int jj_kind = -1; - private int[] jj_lasttokens = new int[100]; - private int jj_endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new int[jj_endpos]; - for (int i = 0; i < jj_endpos; i++) { - jj_expentry[i] = jj_lasttokens[i]; - } - boolean exists = false; - for (java.util.Enumeration<int[]> e = jj_expentries.elements(); e.hasMoreElements();) { - int[] oldentry = e.nextElement(); - if (oldentry.length == jj_expentry.length) { - exists = true; - for (int i = 0; i < jj_expentry.length; i++) { - if (oldentry[i] != jj_expentry[i]) { - exists = false; - break; - } - } - if (exists) break; - } - } - if (!exists) jj_expentries.addElement(jj_expentry); - if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } - } - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[34]; - for (int i = 0; i < 34; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 22; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<<j)) != 0) { - la1tokens[j] = true; - } - if ((jj_la1_1[i] & (1<<j)) != 0) { - la1tokens[32+j] = true; - } - } - } - } - for (int i = 0; i < 34; i++) { - if (la1tokens[i]) { - jj_expentry = new int[1]; - jj_expentry[0] = i; - jj_expentries.addElement(jj_expentry); - } - } - jj_endpos = 0; - jj_rescan_token(); - jj_add_error_token(0, 0); - int[][] exptokseq = new int[jj_expentries.size()][]; - for (int i = 0; i < jj_expentries.size(); i++) { - exptokseq[i] = jj_expentries.elementAt(i); - } - return new ParseException(token, exptokseq, tokenImage); - } - - final public void enable_tracing() { - } - - final public void disable_tracing() { - } - - final private void jj_rescan_token() { - jj_rescan = true; - for (int i = 0; i < 2; i++) { - try { - JJCalls p = jj_2_rtns[i]; - do { - if (p.gen > jj_gen) { - jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; - switch (i) { - case 0: jj_3_1(); break; - case 1: jj_3_2(); break; - } - } - p = p.next; - } while (p != null); - } catch(LookaheadSuccess ls) { } - } - jj_rescan = false; - } - - final private void jj_save(int index, int xla) { - JJCalls p = jj_2_rtns[index]; - while (p.gen > jj_gen) { - if (p.next == null) { p = p.next = new JJCalls(); break; } - p = p.next; - } - p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; - } - - static final class JJCalls { - int gen; - Token first; - int arg; - JJCalls next; - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj deleted file mode 100644 index c14277bc6..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj +++ /dev/null @@ -1,595 +0,0 @@ -/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParser.jj */ -/*@egen*//**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - - -/** - * RFC2822 address list parser. - * - * Created 9/17/2004 - * by Joe Cheng <code@joecheng.com> - */ - -options { - STATIC=false; - LOOKAHEAD=1; - //DEBUG_PARSER=true; - //DEBUG_TOKEN_MANAGER=true; -} - -PARSER_BEGIN(AddressListParser) -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants/*@egen*/ {/*@bgen(jjtree)*/ - protected JJTAddressListParserState jjtree = new JJTAddressListParserState(); - -/*@egen*/ - public static void main(String args[]) throws ParseException { - while (true) { - try { - AddressListParser parser = new AddressListParser(System.in); - parser.parseLine(); - ((SimpleNode)parser.jjtree.rootNode()).dump("> "); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static void log(String msg) { - System.out.print(msg); - } - - public ASTaddress_list parse() throws ParseException { - try { - parseAll(); - return (ASTaddress_list)jjtree.rootNode(); - } catch (TokenMgrError tme) { - throw new ParseException(tme.getMessage()); - } - } - - - void jjtreeOpenNodeScope(Node n) { - ((SimpleNode)n).firstToken = getToken(1); - } - - void jjtreeCloseNodeScope(Node n) { - ((SimpleNode)n).lastToken = getToken(0); - } -} - -PARSER_END(AddressListParser) - -void parseLine() : -{} -{ - address_list() ["\r"] "\n" -} - -void parseAll() : -{} -{ - address_list() <EOF> -} - -void address_list() : -{/*@bgen(jjtree) address_list */ - ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) address_list */ - try { -/*@egen*/ - [ address() ] - ( - "," - [ address() ] - )*/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void address() : -{/*@bgen(jjtree) address */ - ASTaddress jjtn000 = new ASTaddress(JJTADDRESS); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) address */ - try { -/*@egen*/ - LOOKAHEAD(2147483647) - addr_spec() -| angle_addr() -| ( phrase() (group_body() | angle_addr()) )/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void mailbox() : -{/*@bgen(jjtree) mailbox */ - ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) mailbox */ - try { -/*@egen*/ - LOOKAHEAD(2147483647) - addr_spec() -| angle_addr() -| name_addr()/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void name_addr() : -{/*@bgen(jjtree) name_addr */ - ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) name_addr */ - try { -/*@egen*/ - phrase() angle_addr()/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void group_body() : -{/*@bgen(jjtree) group_body */ - ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) group_body */ - try { -/*@egen*/ - ":" - [ mailbox() ] - ( - "," - [ mailbox() ] - )* - ";"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void angle_addr() : -{/*@bgen(jjtree) angle_addr */ - ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) angle_addr */ - try { -/*@egen*/ - "<" [ route() ] addr_spec() ">"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void route() : -{/*@bgen(jjtree) route */ - ASTroute jjtn000 = new ASTroute(JJTROUTE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) route */ - try { -/*@egen*/ - "@" domain() ( (",")* "@" domain() )* ":"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void phrase() : -{/*@bgen(jjtree) phrase */ - ASTphrase jjtn000 = new ASTphrase(JJTPHRASE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) phrase */ -try { -/*@egen*/ -( <DOTATOM> -| <QUOTEDSTRING> -)+/*@bgen(jjtree)*/ -} finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } -} -/*@egen*/ -} - -void addr_spec() : -{/*@bgen(jjtree) addr_spec */ - ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) addr_spec */ - try { -/*@egen*/ - ( local_part() "@" domain() )/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void local_part() : -{/*@bgen(jjtree) local_part */ - ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/ Token t; } -{/*@bgen(jjtree) local_part */ - try { -/*@egen*/ - ( t=<DOTATOM> | t=<QUOTEDSTRING> ) - ( [t="."] - { - if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING) - throw new ParseException("Words in local part must be separated by '.'"); - } - ( t=<DOTATOM> | t=<QUOTEDSTRING> ) - )*/*@bgen(jjtree)*/ - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void domain() : -{/*@bgen(jjtree) domain */ - ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/ Token t; } -{/*@bgen(jjtree) domain */ - try { -/*@egen*/ - ( t=<DOTATOM> - ( [t="."] - { - if (t.image.charAt(t.image.length() - 1) != '.') - throw new ParseException("Atoms in domain names must be separated by '.'"); - } - t=<DOTATOM> - )* - ) -| <DOMAINLITERAL>/*@bgen(jjtree)*/ - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -SPECIAL_TOKEN : -{ - < WS: ( [" ", "\t"] )+ > -} - -TOKEN : -{ - < #ALPHA: ["a" - "z", "A" - "Z"] > -| < #DIGIT: ["0" - "9"] > -| < #ATEXT: ( <ALPHA> | <DIGIT> - | "!" | "#" | "$" | "%" - | "&" | "'" | "*" | "+" - | "-" | "/" | "=" | "?" - | "^" | "_" | "`" | "{" - | "|" | "}" | "~" - )> -| < DOTATOM: <ATEXT> ( <ATEXT> | "." )* > -} - -TOKEN_MGR_DECLS : -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; -} - -MORE : -{ - // domain literal - "[" : INDOMAINLITERAL -} - -<INDOMAINLITERAL> -MORE : -{ - < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); } -| < ~["[", "]", "\\"] > -} - -<INDOMAINLITERAL> -TOKEN : -{ - < DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT -} - -MORE : -{ - // starts a comment - "(" : INCOMMENT -} - -<INCOMMENT> -SKIP : -{ - // ends a comment - < COMMENT: ")" > : DEFAULT - // if this is ever changed to not be a SKIP, need - // to make sure matchedToken.token = token.toString() - // is called. -} - -<INCOMMENT> -MORE : -{ - < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); } -| "(" { commentNest = 1; } : NESTED_COMMENT -| < <ANY>> -} - -<NESTED_COMMENT> -MORE : -{ - < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); } -| "(" { ++commentNest; } -| ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); } -| < <ANY>> -} - - -// QUOTED STRINGS - -MORE : -{ - "\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING -} - -<INQUOTEDSTRING> -MORE : -{ - < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); } -| < (~["\"", "\\"])+ > -} - -<INQUOTEDSTRING> -TOKEN : -{ - < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT -} - -// GLOBALS - -<*> -TOKEN : -{ - < #QUOTEDPAIR: "\\" <ANY> > -| < #ANY: ~[] > -} - -// ERROR! -/* - -<*> -TOKEN : -{ - < UNEXPECTED_CHAR: <ANY> > -} - -*/
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java deleted file mode 100644 index 006a082c1..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserConstants.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserConstants { - - int EOF = 0; - int WS = 10; - int ALPHA = 11; - int DIGIT = 12; - int ATEXT = 13; - int DOTATOM = 14; - int DOMAINLITERAL = 18; - int COMMENT = 20; - int QUOTEDSTRING = 31; - int QUOTEDPAIR = 32; - int ANY = 33; - - int DEFAULT = 0; - int INDOMAINLITERAL = 1; - int INCOMMENT = 2; - int NESTED_COMMENT = 3; - int INQUOTEDSTRING = 4; - - String[] tokenImage = { - "<EOF>", - "\"\\r\"", - "\"\\n\"", - "\",\"", - "\":\"", - "\";\"", - "\"<\"", - "\">\"", - "\"@\"", - "\".\"", - "<WS>", - "<ALPHA>", - "<DIGIT>", - "<ATEXT>", - "<DOTATOM>", - "\"[\"", - "<token of kind 16>", - "<token of kind 17>", - "\"]\"", - "\"(\"", - "\")\"", - "<token of kind 21>", - "\"(\"", - "<token of kind 23>", - "<token of kind 24>", - "\"(\"", - "\")\"", - "<token of kind 27>", - "\"\\\"\"", - "<token of kind 29>", - "<token of kind 30>", - "\"\\\"\"", - "<QUOTEDPAIR>", - "<ANY>", - }; - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java deleted file mode 100644 index d2dd88dd3..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java +++ /dev/null @@ -1,1009 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParserTokenManager implements AddressListParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStopAtPos(0, 2); - case 13: - return jjStopAtPos(0, 1); - case 34: - return jjStopAtPos(0, 28); - case 40: - return jjStopAtPos(0, 19); - case 44: - return jjStopAtPos(0, 3); - case 46: - return jjStopAtPos(0, 9); - case 58: - return jjStopAtPos(0, 4); - case 59: - return jjStopAtPos(0, 5); - case 60: - return jjStopAtPos(0, 6); - case 62: - return jjStopAtPos(0, 7); - case 64: - return jjStopAtPos(0, 8); - case 91: - return jjStopAtPos(0, 15); - default : - return jjMoveNfa_0(1, 0); - } -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 1: - if ((0xa3ffacfa00000000L & l) != 0L) - { - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 10) - kind = 10; - jjCheckNAdd(0); - } - break; - case 0: - if ((0x100000200L & l) == 0L) - break; - kind = 10; - jjCheckNAdd(0); - break; - case 2: - if ((0xa3ffecfa00000000L & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 1: - case 2: - if ((0x7fffffffc7fffffeL & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 22); - case 41: - return jjStopAtPos(0, 20); - default : - return jjMoveNfa_2(0, 0); - } -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 23) - kind = 23; - break; - case 1: - if (kind > 21) - kind = 21; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 23) - kind = 23; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 21) - kind = 21; - break; - case 2: - if (kind > 23) - kind = 23; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 23) - kind = 23; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 21) - kind = 21; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_4(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_4(int pos, long active0) -{ - return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_4(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_4(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_4() -{ - switch(curChar) - { - case 34: - return jjStopAtPos(0, 31); - default : - return jjMoveNfa_4(0, 0); - } -} -private final int jjMoveNfa_4(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((0xfffffffbffffffffL & l) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - case 1: - if (kind > 29) - kind = 29; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffefffffffL & l) != 0L) - { - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 29) - kind = 29; - break; - case 2: - if ((0xffffffffefffffffL & l) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 29) - kind = 29; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_3(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_3(int pos, long active0) -{ - return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_3(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_3(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_3() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 25); - case 41: - return jjStopAtPos(0, 26); - default : - return jjMoveNfa_3(0, 0); - } -} -private final int jjMoveNfa_3(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 27) - kind = 27; - break; - case 1: - if (kind > 24) - kind = 24; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 27) - kind = 27; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 24) - kind = 24; - break; - case 2: - if (kind > 27) - kind = 27; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 27) - kind = 27; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 24) - kind = 24; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 93: - return jjStopAtPos(0, 18); - default : - return jjMoveNfa_1(0, 0); - } -} -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 17) - kind = 17; - break; - case 1: - if (kind > 16) - kind = 16; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffc7ffffffL & l) != 0L) - { - if (kind > 17) - kind = 17; - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 16) - kind = 16; - break; - case 2: - if ((0xffffffffc7ffffffL & l) != 0L && kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 17) - kind = 17; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 16) - kind = 16; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\54", "\72", "\73", "\74", "\76", "\100", "\56", null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INDOMAINLITERAL", - "INCOMMENT", - "NESTED_COMMENT", - "INQUOTEDSTRING", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 2, 0, -1, 3, -1, -1, - -1, -1, -1, 4, -1, -1, 0, -1, -1, -}; -static final long[] jjtoToken = { - 0x800443ffL, -}; -static final long[] jjtoSkip = { - 0x100400L, -}; -static final long[] jjtoSpecial = { - 0x400L, -}; -static final long[] jjtoMore = { - 0x7feb8000L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[3]; -private final int[] jjstateSet = new int[6]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public AddressListParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public AddressListParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 3; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 5 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - case 3: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_3(); - break; - case 4: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_4(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - TokenLexicalActions(matchedToken); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 16 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 21 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 22 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 24 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 25 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 26 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - case 28 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 1); - break; - case 29 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - default : - break; - } -} -void TokenLexicalActions(Token matchedToken) -{ - switch(jjmatchedKind) - { - case 18 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.toString(); - break; - case 31 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.substring(0, image.length() - 1); - break; - default : - break; - } -} -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java deleted file mode 100644 index 5987f19d8..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java */ - -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserTreeConstants -{ - public int JJTVOID = 0; - public int JJTADDRESS_LIST = 1; - public int JJTADDRESS = 2; - public int JJTMAILBOX = 3; - public int JJTNAME_ADDR = 4; - public int JJTGROUP_BODY = 5; - public int JJTANGLE_ADDR = 6; - public int JJTROUTE = 7; - public int JJTPHRASE = 8; - public int JJTADDR_SPEC = 9; - public int JJTLOCAL_PART = 10; - public int JJTDOMAIN = 11; - - - public String[] jjtNodeName = { - "void", - "address_list", - "address", - "mailbox", - "name_addr", - "group_body", - "angle_addr", - "route", - "phrase", - "addr_spec", - "local_part", - "domain", - }; -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java deleted file mode 100644 index 8ec2fe7d2..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java */ - -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserVisitor -{ - public Object visit(SimpleNode node, Object data); - public Object visit(ASTaddress_list node, Object data); - public Object visit(ASTaddress node, Object data); - public Object visit(ASTmailbox node, Object data); - public Object visit(ASTname_addr node, Object data); - public Object visit(ASTgroup_body node, Object data); - public Object visit(ASTangle_addr node, Object data); - public Object visit(ASTroute node, Object data); - public Object visit(ASTphrase node, Object data); - public Object visit(ASTaddr_spec node, Object data); - public Object visit(ASTlocal_part node, Object data); - public Object visit(ASTdomain node, Object data); -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/BaseNode.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/BaseNode.java deleted file mode 100644 index 780974616..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/BaseNode.java +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address.parser; - -import org.apache.james.mime4j.field.address.parser.Node; -import org.apache.james.mime4j.field.address.parser.Token; - -public abstract class BaseNode implements Node { - - public Token firstToken; - public Token lastToken; - -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java deleted file mode 100644 index 08b5c5bef..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java +++ /dev/null @@ -1,123 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java */ - -package org.apache.james.mime4j.field.address.parser; - -class JJTAddressListParserState { - private java.util.Stack<Node> nodes; - private java.util.Stack<Integer> marks; - - private int sp; // number of nodes on stack - private int mk; // current mark - private boolean node_created; - - JJTAddressListParserState() { - nodes = new java.util.Stack<Node>(); - marks = new java.util.Stack<Integer>(); - sp = 0; - mk = 0; - } - - /* Determines whether the current node was actually closed and - pushed. This should only be called in the final user action of a - node scope. */ - boolean nodeCreated() { - return node_created; - } - - /* Call this to reinitialize the node stack. It is called - automatically by the parser's ReInit() method. */ - void reset() { - nodes.removeAllElements(); - marks.removeAllElements(); - sp = 0; - mk = 0; - } - - /* Returns the root node of the AST. It only makes sense to call - this after a successful parse. */ - Node rootNode() { - return nodes.elementAt(0); - } - - /* Pushes a node on to the stack. */ - void pushNode(Node n) { - nodes.push(n); - ++sp; - } - - /* Returns the node on the top of the stack, and remove it from the - stack. */ - Node popNode() { - if (--sp < mk) { - mk = marks.pop().intValue(); - } - return nodes.pop(); - } - - /* Returns the node currently on the top of the stack. */ - Node peekNode() { - return nodes.peek(); - } - - /* Returns the number of children on the stack in the current node - scope. */ - int nodeArity() { - return sp - mk; - } - - - void clearNodeScope(Node n) { - while (sp > mk) { - popNode(); - } - mk = marks.pop().intValue(); - } - - - void openNodeScope(Node n) { - marks.push(new Integer(mk)); - mk = sp; - n.jjtOpen(); - } - - - /* A definite node is constructed from a specified number of - children. That number of nodes are popped from the stack and - made the children of the definite node. Then the definite node - is pushed on to the stack. */ - void closeNodeScope(Node n, int num) { - mk = marks.pop().intValue(); - while (num-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, num); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } - - - /* A conditional node is constructed if its condition is true. All - the nodes that have been pushed since the node was opened are - made children of the the conditional node, which is then pushed - on to the stack. If the condition is false the node is not - constructed and they are left on the stack. */ - void closeNodeScope(Node n, boolean condition) { - if (condition) { - int a = nodeArity(); - mk = marks.pop().intValue(); - while (a-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, a); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } else { - mk = marks.pop().intValue(); - node_created = false; - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Node.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Node.java deleted file mode 100644 index 158892016..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Node.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. Node.java */ - -package org.apache.james.mime4j.field.address.parser; - -/* All AST nodes must implement this interface. It provides basic - machinery for constructing the parent and child relationships - between nodes. */ - -public interface Node { - - /** This method is called after the node has been made the current - node. It indicates that child nodes can now be added to it. */ - public void jjtOpen(); - - /** This method is called after all the child nodes have been - added. */ - public void jjtClose(); - - /** This pair of methods are used to inform the node of its - parent. */ - public void jjtSetParent(Node n); - public Node jjtGetParent(); - - /** This method tells the node to add its argument to the node's - list of children. */ - public void jjtAddChild(Node n, int i); - - /** This method returns a child node. The children are numbered - from zero, left to right. */ - public Node jjtGetChild(int i); - - /** Return the number of children the node has. */ - public int jjtGetNumChildren(); - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data); -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ParseException.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ParseException.java deleted file mode 100644 index e20146fb6..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: <result of getMessage> - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java deleted file mode 100644 index c9ba0b444..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - @Deprecated - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - @Deprecated - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java deleted file mode 100644 index 9bf537e60..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java +++ /dev/null @@ -1,87 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class SimpleNode extends org.apache.james.mime4j.field.address.parser.BaseNode implements Node { - protected Node parent; - protected Node[] children; - protected int id; - protected AddressListParser parser; - - public SimpleNode(int i) { - id = i; - } - - public SimpleNode(AddressListParser p, int i) { - this(i); - parser = p; - } - - public void jjtOpen() { - } - - public void jjtClose() { - } - - public void jjtSetParent(Node n) { parent = n; } - public Node jjtGetParent() { return parent; } - - public void jjtAddChild(Node n, int i) { - if (children == null) { - children = new Node[i + 1]; - } else if (i >= children.length) { - Node c[] = new Node[i + 1]; - System.arraycopy(children, 0, c, 0, children.length); - children = c; - } - children[i] = n; - } - - public Node jjtGetChild(int i) { - return children[i]; - } - - public int jjtGetNumChildren() { - return (children == null) ? 0 : children.length; - } - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - /** Accept the visitor. **/ - public Object childrenAccept(AddressListParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - children[i].jjtAccept(visitor, data); - } - } - return data; - } - - /* You can override these two methods in subclasses of SimpleNode to - customize the way the node appears when the tree is dumped. If - your output uses more than one line you should override - toString(String), otherwise overriding toString() is probably all - you need to do. */ - - public String toString() { return AddressListParserTreeConstants.jjtNodeName[id]; } - public String toString(String prefix) { return prefix + toString(); } - - /* Override this method if you want to customize how the node dumps - out its children. */ - - public void dump(String prefix) { - System.out.println(toString(prefix)); - if (children != null) { - for (int i = 0; i < children.length; ++i) { - SimpleNode n = (SimpleNode)children[i]; - if (n != null) { - n.dump(prefix + " "); - } - } - } - } -} - diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Token.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Token.java deleted file mode 100644 index 2382e8e92..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java deleted file mode 100644 index 0299c8523..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java deleted file mode 100644 index cacf3af21..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java +++ /dev/null @@ -1,268 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ContentTypeParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -import java.util.ArrayList; -import java.util.Vector; - -public class ContentTypeParser implements ContentTypeParserConstants { - - private String type; - private String subtype; - private ArrayList<String> paramNames = new ArrayList<String>(); - private ArrayList<String> paramValues = new ArrayList<String>(); - - public String getType() { return type; } - public String getSubType() { return subtype; } - public ArrayList<String> getParamNames() { return paramNames; } - public ArrayList<String> getParamValues() { return paramValues; } - - public static void main(String args[]) throws ParseException { - while (true) { - try { - ContentTypeParser parser = new ContentTypeParser(System.in); - parser.parseLine(); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - final public void parseLine() throws ParseException { - parse(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - } - - final public void parseAll() throws ParseException { - parse(); - jj_consume_token(0); - } - - final public void parse() throws ParseException { - Token type; - Token subtype; - type = jj_consume_token(ATOKEN); - jj_consume_token(3); - subtype = jj_consume_token(ATOKEN); - this.type = type.image; - this.subtype = subtype.image; - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - ; - break; - default: - jj_la1[1] = jj_gen; - break label_1; - } - jj_consume_token(4); - parameter(); - } - } - - final public void parameter() throws ParseException { - Token attrib; - String val; - attrib = jj_consume_token(ATOKEN); - jj_consume_token(5); - val = value(); - paramNames.add(attrib.image); - paramValues.add(val); - } - - final public String value() throws ParseException { - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ATOKEN: - t = jj_consume_token(ATOKEN); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[2] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t.image;} - throw new Error("Missing return statement in function"); - } - - public ContentTypeParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private int jj_gen; - final private int[] jj_la1 = new int[3]; - static private int[] jj_la1_0; - static { - jj_la1_0(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x10,0x280000,}; - } - - public ContentTypeParser(java.io.InputStream stream) { - this(stream, null); - } - public ContentTypeParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new ContentTypeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public ContentTypeParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new ContentTypeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public ContentTypeParser(ContentTypeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(ContentTypeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private Vector<int[]> jj_expentries = new Vector<int[]>(); - private int[] jj_expentry; - private int jj_kind = -1; - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[24]; - for (int i = 0; i < 24; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 3; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<<j)) != 0) { - la1tokens[j] = true; - } - } - } - } - for (int i = 0; i < 24; i++) { - if (la1tokens[i]) { - jj_expentry = new int[1]; - jj_expentry[0] = i; - jj_expentries.addElement(jj_expentry); - } - } - int[][] exptokseq = new int[jj_expentries.size()][]; - for (int i = 0; i < jj_expentries.size(); i++) { - exptokseq[i] = jj_expentries.elementAt(i); - } - return new ParseException(token, exptokseq, tokenImage); - } - - final public void enable_tracing() { - } - - final public void disable_tracing() { - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java deleted file mode 100644 index d933d800d..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java +++ /dev/null @@ -1,62 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ContentTypeParserConstants.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -public interface ContentTypeParserConstants { - - int EOF = 0; - int WS = 6; - int COMMENT = 8; - int QUOTEDSTRING = 19; - int DIGITS = 20; - int ATOKEN = 21; - int QUOTEDPAIR = 22; - int ANY = 23; - - int DEFAULT = 0; - int INCOMMENT = 1; - int NESTED_COMMENT = 2; - int INQUOTEDSTRING = 3; - - String[] tokenImage = { - "<EOF>", - "\"\\r\"", - "\"\\n\"", - "\"/\"", - "\";\"", - "\"=\"", - "<WS>", - "\"(\"", - "\")\"", - "<token of kind 9>", - "\"(\"", - "<token of kind 11>", - "<token of kind 12>", - "\"(\"", - "\")\"", - "<token of kind 15>", - "\"\\\"\"", - "<token of kind 17>", - "<token of kind 18>", - "\"\\\"\"", - "<DIGITS>", - "<ATOKEN>", - "<QUOTEDPAIR>", - "<ANY>", - }; - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java deleted file mode 100644 index 25b7abafa..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java +++ /dev/null @@ -1,877 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ContentTypeParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; -import java.util.ArrayList; - -public class ContentTypeParserTokenManager implements ContentTypeParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStartNfaWithStates_0(0, 2, 2); - case 13: - return jjStartNfaWithStates_0(0, 1, 2); - case 34: - return jjStopAtPos(0, 16); - case 40: - return jjStopAtPos(0, 7); - case 47: - return jjStopAtPos(0, 3); - case 59: - return jjStopAtPos(0, 4); - case 61: - return jjStopAtPos(0, 5); - default : - return jjMoveNfa_0(3, 0); - } -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - if ((0x3ff6cfafffffdffL & l) != 0L) - { - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 6) - kind = 6; - jjCheckNAdd(0); - } - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 20) - kind = 20; - jjCheckNAdd(1); - } - break; - case 0: - if ((0x100000200L & l) == 0L) - break; - kind = 6; - jjCheckNAdd(0); - break; - case 1: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(1); - break; - case 2: - if ((0x3ff6cfafffffdffL & l) == 0L) - break; - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - case 2: - if ((0xffffffffc7fffffeL & l) == 0L) - break; - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 10); - case 41: - return jjStopAtPos(0, 8); - default : - return jjMoveNfa_1(0, 0); - } -} -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 11) - kind = 11; - break; - case 1: - if (kind > 9) - kind = 9; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 11) - kind = 11; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 9) - kind = 9; - break; - case 2: - if (kind > 11) - kind = 11; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 11) - kind = 11; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 9) - kind = 9; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_3(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_3(int pos, long active0) -{ - return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_3(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_3(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_3() -{ - switch(curChar) - { - case 34: - return jjStopAtPos(0, 19); - default : - return jjMoveNfa_3(0, 0); - } -} -private final int jjMoveNfa_3(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((0xfffffffbffffffffL & l) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - case 1: - if (kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffefffffffL & l) != 0L) - { - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 17) - kind = 17; - break; - case 2: - if ((0xffffffffefffffffL & l) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 13); - case 41: - return jjStopAtPos(0, 14); - default : - return jjMoveNfa_2(0, 0); - } -} -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 15) - kind = 15; - break; - case 1: - if (kind > 12) - kind = 12; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 15) - kind = 15; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 12) - kind = 12; - break; - case 2: - if (kind > 15) - kind = 15; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 15) - kind = 15; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 12) - kind = 12; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\57", "\73", "\75", null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INCOMMENT", - "NESTED_COMMENT", - "INQUOTEDSTRING", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0x38003fL, -}; -static final long[] jjtoSkip = { - 0x140L, -}; -static final long[] jjtoSpecial = { - 0x40L, -}; -static final long[] jjtoMore = { - 0x7fe80L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[3]; -private final int[] jjstateSet = new int[6]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public ContentTypeParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public ContentTypeParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 3; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 4 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - case 3: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_3(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - TokenLexicalActions(matchedToken); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 9 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 10 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 12 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 13 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 14 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - case 16 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 1); - break; - case 17 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - default : - break; - } -} -void TokenLexicalActions(Token matchedToken) -{ - switch(jjmatchedKind) - { - case 19 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.substring(0, image.length() - 1); - break; - default : - break; - } -} -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java deleted file mode 100644 index d9b69b25c..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: <result of getMessage> - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java deleted file mode 100644 index ae035b717..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - @Deprecated - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - @Deprecated - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/Token.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/Token.java deleted file mode 100644 index 34e65eec0..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java deleted file mode 100644 index ea5a7826e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/DateTime.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/DateTime.java deleted file mode 100644 index 506ff54e5..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/DateTime.java +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.datetime; - -import org.apache.james.mime4j.field.datetime.parser.DateTimeParser; -import org.apache.james.mime4j.field.datetime.parser.ParseException; -import org.apache.james.mime4j.field.datetime.parser.TokenMgrError; - -import java.util.Date; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.GregorianCalendar; -import java.io.StringReader; - -public class DateTime { - private final Date date; - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int timeZone; - - public DateTime(String yearString, int month, int day, int hour, int minute, int second, int timeZone) { - this.year = convertToYear(yearString); - this.date = convertToDate(year, month, day, hour, minute, second, timeZone); - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.timeZone = timeZone; - } - - private int convertToYear(String yearString) { - int year = Integer.parseInt(yearString); - switch (yearString.length()) { - case 1: - case 2: - if (year >= 0 && year < 50) - return 2000 + year; - else - return 1900 + year; - case 3: - return 1900 + year; - default: - return year; - } - } - - public static Date convertToDate(int year, int month, int day, int hour, int minute, int second, int timeZone) { - Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT+0")); - c.set(year, month - 1, day, hour, minute, second); - c.set(Calendar.MILLISECOND, 0); - - if (timeZone != Integer.MIN_VALUE) { - int minutes = ((timeZone / 100) * 60) + timeZone % 100; - c.add(Calendar.MINUTE, -1 * minutes); - } - - return c.getTime(); - } - - public Date getDate() { - return date; - } - - public int getYear() { - return year; - } - - public int getMonth() { - return month; - } - - public int getDay() { - return day; - } - - public int getHour() { - return hour; - } - - public int getMinute() { - return minute; - } - - public int getSecond() { - return second; - } - - public int getTimeZone() { - return timeZone; - } - - public void print() { - System.out.println(getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone()); - } - - - public static DateTime parse(String dateString) throws ParseException { - try { - return new DateTimeParser(new StringReader(dateString)).parseAll(); - } - catch (TokenMgrError err) { - throw new ParseException(err.getMessage()); - } - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java deleted file mode 100644 index 43edebb5c..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java +++ /dev/null @@ -1,570 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. DateTimeParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -import org.apache.james.mime4j.field.datetime.DateTime; - -import java.util.Vector; - -public class DateTimeParser implements DateTimeParserConstants { - private static final boolean ignoreMilitaryZoneOffset = true; - - public static void main(String args[]) throws ParseException { - while (true) { - try { - DateTimeParser parser = new DateTimeParser(System.in); - parser.parseLine(); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static int parseDigits(Token token) { - return Integer.parseInt(token.image, 10); - } - - private static int getMilitaryZoneOffset(char c) { - if (ignoreMilitaryZoneOffset) - return 0; - - c = Character.toUpperCase(c); - - switch (c) { - case 'A': return 1; - case 'B': return 2; - case 'C': return 3; - case 'D': return 4; - case 'E': return 5; - case 'F': return 6; - case 'G': return 7; - case 'H': return 8; - case 'I': return 9; - case 'K': return 10; - case 'L': return 11; - case 'M': return 12; - - case 'N': return -1; - case 'O': return -2; - case 'P': return -3; - case 'Q': return -4; - case 'R': return -5; - case 'S': return -6; - case 'T': return -7; - case 'U': return -8; - case 'V': return -9; - case 'W': return -10; - case 'X': return -11; - case 'Y': return -12; - - case 'Z': return 0; - default: return 0; - } - } - - private static class Time { - private int hour; - private int minute; - private int second; - private int zone; - - public Time(int hour, int minute, int second, int zone) { - this.hour = hour; - this.minute = minute; - this.second = second; - this.zone = zone; - } - - public int getHour() { return hour; } - public int getMinute() { return minute; } - public int getSecond() { return second; } - public int getZone() { return zone; } - } - - private static class Date { - private String year; - private int month; - private int day; - - public Date(String year, int month, int day) { - this.year = year; - this.month = month; - this.day = day; - } - - public String getYear() { return year; } - public int getMonth() { return month; } - public int getDay() { return day; } - } - - final public DateTime parseLine() throws ParseException { - DateTime dt; - dt = date_time(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - {if (true) return dt;} - throw new Error("Missing return statement in function"); - } - - final public DateTime parseAll() throws ParseException { - DateTime dt; - dt = date_time(); - jj_consume_token(0); - {if (true) return dt;} - throw new Error("Missing return statement in function"); - } - - final public DateTime date_time() throws ParseException { - Date d; Time t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - day_of_week(); - jj_consume_token(3); - break; - default: - jj_la1[1] = jj_gen; - ; - } - d = date(); - t = time(); - {if (true) return new DateTime( - d.getYear(), - d.getMonth(), - d.getDay(), - t.getHour(), - t.getMinute(), - t.getSecond(), - t.getZone());} // time zone offset - - throw new Error("Missing return statement in function"); - } - - final public String day_of_week() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - jj_consume_token(4); - break; - case 5: - jj_consume_token(5); - break; - case 6: - jj_consume_token(6); - break; - case 7: - jj_consume_token(7); - break; - case 8: - jj_consume_token(8); - break; - case 9: - jj_consume_token(9); - break; - case 10: - jj_consume_token(10); - break; - default: - jj_la1[2] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return token.image;} - throw new Error("Missing return statement in function"); - } - - final public Date date() throws ParseException { - int d, m; String y; - d = day(); - m = month(); - y = year(); - {if (true) return new Date(y, m, d);} - throw new Error("Missing return statement in function"); - } - - final public int day() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int month() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 11: - jj_consume_token(11); - {if (true) return 1;} - break; - case 12: - jj_consume_token(12); - {if (true) return 2;} - break; - case 13: - jj_consume_token(13); - {if (true) return 3;} - break; - case 14: - jj_consume_token(14); - {if (true) return 4;} - break; - case 15: - jj_consume_token(15); - {if (true) return 5;} - break; - case 16: - jj_consume_token(16); - {if (true) return 6;} - break; - case 17: - jj_consume_token(17); - {if (true) return 7;} - break; - case 18: - jj_consume_token(18); - {if (true) return 8;} - break; - case 19: - jj_consume_token(19); - {if (true) return 9;} - break; - case 20: - jj_consume_token(20); - {if (true) return 10;} - break; - case 21: - jj_consume_token(21); - {if (true) return 11;} - break; - case 22: - jj_consume_token(22); - {if (true) return 12;} - break; - default: - jj_la1[3] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - throw new Error("Missing return statement in function"); - } - - final public String year() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return t.image;} - throw new Error("Missing return statement in function"); - } - - final public Time time() throws ParseException { - int h, m, s=0, z; - h = hour(); - jj_consume_token(23); - m = minute(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 23: - jj_consume_token(23); - s = second(); - break; - default: - jj_la1[4] = jj_gen; - ; - } - z = zone(); - {if (true) return new Time(h, m, s, z);} - throw new Error("Missing return statement in function"); - } - - final public int hour() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int minute() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int second() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int zone() throws ParseException { - Token t, u; int z; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OFFSETDIR: - t = jj_consume_token(OFFSETDIR); - u = jj_consume_token(DIGITS); - z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); - break; - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - case MILITARY_ZONE: - z = obs_zone(); - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return z;} - throw new Error("Missing return statement in function"); - } - - final public int obs_zone() throws ParseException { - Token t; int z; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 25: - jj_consume_token(25); - z=0; - break; - case 26: - jj_consume_token(26); - z=0; - break; - case 27: - jj_consume_token(27); - z=-5; - break; - case 28: - jj_consume_token(28); - z=-4; - break; - case 29: - jj_consume_token(29); - z=-6; - break; - case 30: - jj_consume_token(30); - z=-5; - break; - case 31: - jj_consume_token(31); - z=-7; - break; - case 32: - jj_consume_token(32); - z=-6; - break; - case 33: - jj_consume_token(33); - z=-8; - break; - case 34: - jj_consume_token(34); - z=-7; - break; - case MILITARY_ZONE: - t = jj_consume_token(MILITARY_ZONE); - z=getMilitaryZoneOffset(t.image.charAt(0)); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return z * 100;} - throw new Error("Missing return statement in function"); - } - - public DateTimeParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private int jj_gen; - final private int[] jj_la1 = new int[7]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static { - jj_la1_0(); - jj_la1_1(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x7f0,0x7f0,0x7ff800,0x800000,0xff000000,0xfe000000,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0xf,0xf,}; - } - - public DateTimeParser(java.io.InputStream stream) { - this(stream, null); - } - public DateTimeParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new DateTimeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public DateTimeParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new DateTimeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public DateTimeParser(DateTimeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(DateTimeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private Vector<int[]> jj_expentries = new Vector<int[]>(); - private int[] jj_expentry; - private int jj_kind = -1; - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[49]; - for (int i = 0; i < 49; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 7; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<<j)) != 0) { - la1tokens[j] = true; - } - if ((jj_la1_1[i] & (1<<j)) != 0) { - la1tokens[32+j] = true; - } - } - } - } - for (int i = 0; i < 49; i++) { - if (la1tokens[i]) { - jj_expentry = new int[1]; - jj_expentry[0] = i; - jj_expentries.addElement(jj_expentry); - } - } - int[][] exptokseq = new int[jj_expentries.size()][]; - for (int i = 0; i < jj_expentries.size(); i++) { - exptokseq[i] = jj_expentries.elementAt(i); - } - return new ParseException(token, exptokseq, tokenImage); - } - - final public void enable_tracing() { - } - - final public void disable_tracing() { - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java deleted file mode 100644 index 2c203db2e..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java +++ /dev/null @@ -1,86 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. DateTimeParserConstants.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -public interface DateTimeParserConstants { - - int EOF = 0; - int OFFSETDIR = 24; - int MILITARY_ZONE = 35; - int WS = 36; - int COMMENT = 38; - int DIGITS = 46; - int QUOTEDPAIR = 47; - int ANY = 48; - - int DEFAULT = 0; - int INCOMMENT = 1; - int NESTED_COMMENT = 2; - - String[] tokenImage = { - "<EOF>", - "\"\\r\"", - "\"\\n\"", - "\",\"", - "\"Mon\"", - "\"Tue\"", - "\"Wed\"", - "\"Thu\"", - "\"Fri\"", - "\"Sat\"", - "\"Sun\"", - "\"Jan\"", - "\"Feb\"", - "\"Mar\"", - "\"Apr\"", - "\"May\"", - "\"Jun\"", - "\"Jul\"", - "\"Aug\"", - "\"Sep\"", - "\"Oct\"", - "\"Nov\"", - "\"Dec\"", - "\":\"", - "<OFFSETDIR>", - "\"UT\"", - "\"GMT\"", - "\"EST\"", - "\"EDT\"", - "\"CST\"", - "\"CDT\"", - "\"MST\"", - "\"MDT\"", - "\"PST\"", - "\"PDT\"", - "<MILITARY_ZONE>", - "<WS>", - "\"(\"", - "\")\"", - "<token of kind 39>", - "\"(\"", - "<token of kind 41>", - "<token of kind 42>", - "\"(\"", - "\")\"", - "<token of kind 45>", - "<DIGITS>", - "<QUOTEDPAIR>", - "<ANY>", - }; - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java deleted file mode 100644 index 4b2d2fd95..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java +++ /dev/null @@ -1,882 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. DateTimeParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; -import org.apache.james.mime4j.field.datetime.DateTime; -import java.util.Calendar; - -public class DateTimeParserTokenManager implements DateTimeParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - case 0: - if ((active0 & 0x7fe7cf7f0L) != 0L) - { - jjmatchedKind = 35; - return -1; - } - return -1; - case 1: - if ((active0 & 0x7fe7cf7f0L) != 0L) - { - if (jjmatchedPos == 0) - { - jjmatchedKind = 35; - jjmatchedPos = 0; - } - return -1; - } - return -1; - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStopAtPos(0, 2); - case 13: - return jjStopAtPos(0, 1); - case 40: - return jjStopAtPos(0, 37); - case 44: - return jjStopAtPos(0, 3); - case 58: - return jjStopAtPos(0, 23); - case 65: - return jjMoveStringLiteralDfa1_0(0x44000L); - case 67: - return jjMoveStringLiteralDfa1_0(0x60000000L); - case 68: - return jjMoveStringLiteralDfa1_0(0x400000L); - case 69: - return jjMoveStringLiteralDfa1_0(0x18000000L); - case 70: - return jjMoveStringLiteralDfa1_0(0x1100L); - case 71: - return jjMoveStringLiteralDfa1_0(0x4000000L); - case 74: - return jjMoveStringLiteralDfa1_0(0x30800L); - case 77: - return jjMoveStringLiteralDfa1_0(0x18000a010L); - case 78: - return jjMoveStringLiteralDfa1_0(0x200000L); - case 79: - return jjMoveStringLiteralDfa1_0(0x100000L); - case 80: - return jjMoveStringLiteralDfa1_0(0x600000000L); - case 83: - return jjMoveStringLiteralDfa1_0(0x80600L); - case 84: - return jjMoveStringLiteralDfa1_0(0xa0L); - case 85: - return jjMoveStringLiteralDfa1_0(0x2000000L); - case 87: - return jjMoveStringLiteralDfa1_0(0x40L); - default : - return jjMoveNfa_0(0, 0); - } -} -private final int jjMoveStringLiteralDfa1_0(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(0, active0); - return 1; - } - switch(curChar) - { - case 68: - return jjMoveStringLiteralDfa2_0(active0, 0x550000000L); - case 77: - return jjMoveStringLiteralDfa2_0(active0, 0x4000000L); - case 83: - return jjMoveStringLiteralDfa2_0(active0, 0x2a8000000L); - case 84: - if ((active0 & 0x2000000L) != 0L) - return jjStopAtPos(1, 25); - break; - case 97: - return jjMoveStringLiteralDfa2_0(active0, 0xaa00L); - case 99: - return jjMoveStringLiteralDfa2_0(active0, 0x100000L); - case 101: - return jjMoveStringLiteralDfa2_0(active0, 0x481040L); - case 104: - return jjMoveStringLiteralDfa2_0(active0, 0x80L); - case 111: - return jjMoveStringLiteralDfa2_0(active0, 0x200010L); - case 112: - return jjMoveStringLiteralDfa2_0(active0, 0x4000L); - case 114: - return jjMoveStringLiteralDfa2_0(active0, 0x100L); - case 117: - return jjMoveStringLiteralDfa2_0(active0, 0x70420L); - default : - break; - } - return jjStartNfa_0(0, active0); -} -private final int jjMoveStringLiteralDfa2_0(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_0(0, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(1, active0); - return 2; - } - switch(curChar) - { - case 84: - if ((active0 & 0x4000000L) != 0L) - return jjStopAtPos(2, 26); - else if ((active0 & 0x8000000L) != 0L) - return jjStopAtPos(2, 27); - else if ((active0 & 0x10000000L) != 0L) - return jjStopAtPos(2, 28); - else if ((active0 & 0x20000000L) != 0L) - return jjStopAtPos(2, 29); - else if ((active0 & 0x40000000L) != 0L) - return jjStopAtPos(2, 30); - else if ((active0 & 0x80000000L) != 0L) - return jjStopAtPos(2, 31); - else if ((active0 & 0x100000000L) != 0L) - return jjStopAtPos(2, 32); - else if ((active0 & 0x200000000L) != 0L) - return jjStopAtPos(2, 33); - else if ((active0 & 0x400000000L) != 0L) - return jjStopAtPos(2, 34); - break; - case 98: - if ((active0 & 0x1000L) != 0L) - return jjStopAtPos(2, 12); - break; - case 99: - if ((active0 & 0x400000L) != 0L) - return jjStopAtPos(2, 22); - break; - case 100: - if ((active0 & 0x40L) != 0L) - return jjStopAtPos(2, 6); - break; - case 101: - if ((active0 & 0x20L) != 0L) - return jjStopAtPos(2, 5); - break; - case 103: - if ((active0 & 0x40000L) != 0L) - return jjStopAtPos(2, 18); - break; - case 105: - if ((active0 & 0x100L) != 0L) - return jjStopAtPos(2, 8); - break; - case 108: - if ((active0 & 0x20000L) != 0L) - return jjStopAtPos(2, 17); - break; - case 110: - if ((active0 & 0x10L) != 0L) - return jjStopAtPos(2, 4); - else if ((active0 & 0x400L) != 0L) - return jjStopAtPos(2, 10); - else if ((active0 & 0x800L) != 0L) - return jjStopAtPos(2, 11); - else if ((active0 & 0x10000L) != 0L) - return jjStopAtPos(2, 16); - break; - case 112: - if ((active0 & 0x80000L) != 0L) - return jjStopAtPos(2, 19); - break; - case 114: - if ((active0 & 0x2000L) != 0L) - return jjStopAtPos(2, 13); - else if ((active0 & 0x4000L) != 0L) - return jjStopAtPos(2, 14); - break; - case 116: - if ((active0 & 0x200L) != 0L) - return jjStopAtPos(2, 9); - else if ((active0 & 0x100000L) != 0L) - return jjStopAtPos(2, 20); - break; - case 117: - if ((active0 & 0x80L) != 0L) - return jjStopAtPos(2, 7); - break; - case 118: - if ((active0 & 0x200000L) != 0L) - return jjStopAtPos(2, 21); - break; - case 121: - if ((active0 & 0x8000L) != 0L) - return jjStopAtPos(2, 15); - break; - default : - break; - } - return jjStartNfa_0(1, active0); -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 4; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 46) - kind = 46; - jjCheckNAdd(3); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 36) - kind = 36; - jjCheckNAdd(2); - } - else if ((0x280000000000L & l) != 0L) - { - if (kind > 24) - kind = 24; - } - break; - case 2: - if ((0x100000200L & l) == 0L) - break; - kind = 36; - jjCheckNAdd(2); - break; - case 3: - if ((0x3ff000000000000L & l) == 0L) - break; - kind = 46; - jjCheckNAdd(3); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x7fffbfe07fffbfeL & l) != 0L) - kind = 35; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 40); - case 41: - return jjStopAtPos(0, 38); - default : - return jjMoveNfa_1(0, 0); - } -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 41) - kind = 41; - break; - case 1: - if (kind > 39) - kind = 39; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 41) - kind = 41; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 39) - kind = 39; - break; - case 2: - if (kind > 41) - kind = 41; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 41) - kind = 41; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 39) - kind = 39; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 43); - case 41: - return jjStopAtPos(0, 44); - default : - return jjMoveNfa_2(0, 0); - } -} -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 45) - kind = 45; - break; - case 1: - if (kind > 42) - kind = 42; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 45) - kind = 45; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 42) - kind = 42; - break; - case 2: - if (kind > 45) - kind = 45; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 45) - kind = 45; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 42) - kind = 42; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\54", "\115\157\156", "\124\165\145", "\127\145\144", -"\124\150\165", "\106\162\151", "\123\141\164", "\123\165\156", "\112\141\156", -"\106\145\142", "\115\141\162", "\101\160\162", "\115\141\171", "\112\165\156", -"\112\165\154", "\101\165\147", "\123\145\160", "\117\143\164", "\116\157\166", -"\104\145\143", "\72", null, "\125\124", "\107\115\124", "\105\123\124", "\105\104\124", -"\103\123\124", "\103\104\124", "\115\123\124", "\115\104\124", "\120\123\124", -"\120\104\124", null, null, null, null, null, null, null, null, null, null, null, null, null, -null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INCOMMENT", - "NESTED_COMMENT", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0x400fffffffffL, -}; -static final long[] jjtoSkip = { - 0x5000000000L, -}; -static final long[] jjtoSpecial = { - 0x1000000000L, -}; -static final long[] jjtoMore = { - 0x3fa000000000L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[4]; -private final int[] jjstateSet = new int[8]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public DateTimeParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public DateTimeParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 4; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 3 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 39 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 40 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 42 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 43 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 44 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - default : - break; - } -} -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java deleted file mode 100644 index 13b3ff097..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: <result of getMessage> - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java deleted file mode 100644 index 2724529f7..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - @Deprecated - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - @Deprecated - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/Token.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/Token.java deleted file mode 100644 index 0927a0921..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java deleted file mode 100644 index e7043c1b7..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/util/CharsetUtil.java b/java/com/android/voicemailomtp/src/org/apache/james/mime4j/util/CharsetUtil.java deleted file mode 100644 index 4e712fcdd..000000000 --- a/java/com/android/voicemailomtp/src/org/apache/james/mime4j/util/CharsetUtil.java +++ /dev/null @@ -1,1249 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; -import java.util.HashMap; -import java.util.Locale; -import java.util.TreeSet; - -//BEGIN android-changed: Stubbing out logging -import org.apache.james.mime4j.Log; -import org.apache.james.mime4j.LogFactory; -//END android-changed - -/** - * Utility class for working with character sets. It is somewhat similar to - * the Java 1.4 <code>java.nio.charset.Charset</code> class but knows many - * more aliases and is compatible with Java 1.3. It will use a simple detection - * mechanism to detect what character sets the current VM supports. This will - * be a sub-set of the character sets listed in the - * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html"> - * Java 1.5 (J2SE5.0) Supported Encodings</a> document. - * <p> - * The <a href="http://www.iana.org/assignments/character-sets"> - * IANA Character Sets</a> document has been used to determine the preferred - * MIME character set names and to get a list of known aliases. - * <p> - * This is a complete list of the character sets known to this class: - * <table> - * <tr> - * <td>Canonical (Java) name</td> - * <td>MIME preferred</td> - * <td>Aliases</td> - * </tr> - * <tr> - * <td>ASCII</td> - * <td>US-ASCII</td> - * <td>ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ISO646-US us IBM367 cp367 csASCII ascii7 646 iso_646.irv:1983 </td> - * </tr> - * <tr> - * <td>Big5</td> - * <td>Big5</td> - * <td>csBig5 CN-Big5 BIG-FIVE BIGFIVE </td> - * </tr> - * <tr> - * <td>Big5_HKSCS</td> - * <td>Big5-HKSCS</td> - * <td>big5hkscs </td> - * </tr> - * <tr> - * <td>Big5_Solaris</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp037</td> - * <td>IBM037</td> - * <td>ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037 </td> - * </tr> - * <tr> - * <td>Cp1006</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1025</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1026</td> - * <td>IBM1026</td> - * <td>csIBM1026 </td> - * </tr> - * <tr> - * <td>Cp1046</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1047</td> - * <td>IBM1047</td> - * <td>IBM-1047 </td> - * </tr> - * <tr> - * <td>Cp1097</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1098</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1112</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1122</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1123</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1124</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1140</td> - * <td>IBM01140</td> - * <td>CCSID01140 CP01140 ebcdic-us-37+euro </td> - * </tr> - * <tr> - * <td>Cp1141</td> - * <td>IBM01141</td> - * <td>CCSID01141 CP01141 ebcdic-de-273+euro </td> - * </tr> - * <tr> - * <td>Cp1142</td> - * <td>IBM01142</td> - * <td>CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro </td> - * </tr> - * <tr> - * <td>Cp1143</td> - * <td>IBM01143</td> - * <td>CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro </td> - * </tr> - * <tr> - * <td>Cp1144</td> - * <td>IBM01144</td> - * <td>CCSID01144 CP01144 ebcdic-it-280+euro </td> - * </tr> - * <tr> - * <td>Cp1145</td> - * <td>IBM01145</td> - * <td>CCSID01145 CP01145 ebcdic-es-284+euro </td> - * </tr> - * <tr> - * <td>Cp1146</td> - * <td>IBM01146</td> - * <td>CCSID01146 CP01146 ebcdic-gb-285+euro </td> - * </tr> - * <tr> - * <td>Cp1147</td> - * <td>IBM01147</td> - * <td>CCSID01147 CP01147 ebcdic-fr-297+euro </td> - * </tr> - * <tr> - * <td>Cp1148</td> - * <td>IBM01148</td> - * <td>CCSID01148 CP01148 ebcdic-international-500+euro </td> - * </tr> - * <tr> - * <td>Cp1149</td> - * <td>IBM01149</td> - * <td>CCSID01149 CP01149 ebcdic-is-871+euro </td> - * </tr> - * <tr> - * <td>Cp1250</td> - * <td>windows-1250</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1251</td> - * <td>windows-1251</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1252</td> - * <td>windows-1252</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1253</td> - * <td>windows-1253</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1254</td> - * <td>windows-1254</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1255</td> - * <td>windows-1255</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1256</td> - * <td>windows-1256</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1257</td> - * <td>windows-1257</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1258</td> - * <td>windows-1258</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1381</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp1383</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp273</td> - * <td>IBM273</td> - * <td>csIBM273 </td> - * </tr> - * <tr> - * <td>Cp277</td> - * <td>IBM277</td> - * <td>EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 </td> - * </tr> - * <tr> - * <td>Cp278</td> - * <td>IBM278</td> - * <td>CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 </td> - * </tr> - * <tr> - * <td>Cp280</td> - * <td>IBM280</td> - * <td>ebcdic-cp-it csIBM280 </td> - * </tr> - * <tr> - * <td>Cp284</td> - * <td>IBM284</td> - * <td>ebcdic-cp-es csIBM284 </td> - * </tr> - * <tr> - * <td>Cp285</td> - * <td>IBM285</td> - * <td>ebcdic-cp-gb csIBM285 </td> - * </tr> - * <tr> - * <td>Cp297</td> - * <td>IBM297</td> - * <td>ebcdic-cp-fr csIBM297 </td> - * </tr> - * <tr> - * <td>Cp33722</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp420</td> - * <td>IBM420</td> - * <td>ebcdic-cp-ar1 csIBM420 </td> - * </tr> - * <tr> - * <td>Cp424</td> - * <td>IBM424</td> - * <td>ebcdic-cp-he csIBM424 </td> - * </tr> - * <tr> - * <td>Cp437</td> - * <td>IBM437</td> - * <td>437 csPC8CodePage437 </td> - * </tr> - * <tr> - * <td>Cp500</td> - * <td>IBM500</td> - * <td>ebcdic-cp-be ebcdic-cp-ch csIBM500 </td> - * </tr> - * <tr> - * <td>Cp737</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp775</td> - * <td>IBM775</td> - * <td>csPC775Baltic </td> - * </tr> - * <tr> - * <td>Cp838</td> - * <td>IBM-Thai</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp850</td> - * <td>IBM850</td> - * <td>850 csPC850Multilingual </td> - * </tr> - * <tr> - * <td>Cp852</td> - * <td>IBM852</td> - * <td>852 csPCp852 </td> - * </tr> - * <tr> - * <td>Cp855</td> - * <td>IBM855</td> - * <td>855 csIBM855 </td> - * </tr> - * <tr> - * <td>Cp856</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp857</td> - * <td>IBM857</td> - * <td>857 csIBM857 </td> - * </tr> - * <tr> - * <td>Cp858</td> - * <td>IBM00858</td> - * <td>CCSID00858 CP00858 PC-Multilingual-850+euro </td> - * </tr> - * <tr> - * <td>Cp860</td> - * <td>IBM860</td> - * <td>860 csIBM860 </td> - * </tr> - * <tr> - * <td>Cp861</td> - * <td>IBM861</td> - * <td>861 cp-is csIBM861 </td> - * </tr> - * <tr> - * <td>Cp862</td> - * <td>IBM862</td> - * <td>862 csPC862LatinHebrew </td> - * </tr> - * <tr> - * <td>Cp863</td> - * <td>IBM863</td> - * <td>863 csIBM863 </td> - * </tr> - * <tr> - * <td>Cp864</td> - * <td>IBM864</td> - * <td>cp864 csIBM864 </td> - * </tr> - * <tr> - * <td>Cp865</td> - * <td>IBM865</td> - * <td>865 csIBM865 </td> - * </tr> - * <tr> - * <td>Cp866</td> - * <td>IBM866</td> - * <td>866 csIBM866 </td> - * </tr> - * <tr> - * <td>Cp868</td> - * <td>IBM868</td> - * <td>cp-ar csIBM868 </td> - * </tr> - * <tr> - * <td>Cp869</td> - * <td>IBM869</td> - * <td>cp-gr csIBM869 </td> - * </tr> - * <tr> - * <td>Cp870</td> - * <td>IBM870</td> - * <td>ebcdic-cp-roece ebcdic-cp-yu csIBM870 </td> - * </tr> - * <tr> - * <td>Cp871</td> - * <td>IBM871</td> - * <td>ebcdic-cp-is csIBM871 </td> - * </tr> - * <tr> - * <td>Cp875</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp918</td> - * <td>IBM918</td> - * <td>ebcdic-cp-ar2 csIBM918 </td> - * </tr> - * <tr> - * <td>Cp921</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp922</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp930</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp933</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp935</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp937</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp939</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp942</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp942C</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp943</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp943C</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp948</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp949</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp949C</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp950</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp964</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>Cp970</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>EUC_CN</td> - * <td>GB2312</td> - * <td>x-EUC-CN csGB2312 euccn euc-cn gb2312-80 gb2312-1980 CN-GB CN-GB-ISOIR165 </td> - * </tr> - * <tr> - * <td>EUC_JP</td> - * <td>EUC-JP</td> - * <td>csEUCPkdFmtJapanese Extended_UNIX_Code_Packed_Format_for_Japanese eucjis x-eucjp eucjp x-euc-jp </td> - * </tr> - * <tr> - * <td>EUC_JP_LINUX</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>EUC_JP_Solaris</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>EUC_KR</td> - * <td>EUC-KR</td> - * <td>csEUCKR ksc5601 5601 ksc5601_1987 ksc_5601 ksc5601-1987 ks_c_5601-1987 euckr </td> - * </tr> - * <tr> - * <td>EUC_TW</td> - * <td>EUC-TW</td> - * <td>x-EUC-TW cns11643 euctw </td> - * </tr> - * <tr> - * <td>GB18030</td> - * <td>GB18030</td> - * <td>gb18030-2000 </td> - * </tr> - * <tr> - * <td>GBK</td> - * <td>windows-936</td> - * <td>CP936 MS936 ms_936 x-mswin-936 </td> - * </tr> - * <tr> - * <td>ISCII91</td> - * <td>?</td> - * <td>x-ISCII91 iscii </td> - * </tr> - * <tr> - * <td>ISO2022CN</td> - * <td>ISO-2022-CN</td> - * <td></td> - * </tr> - * <tr> - * <td>ISO2022JP</td> - * <td>ISO-2022-JP</td> - * <td>csISO2022JP JIS jis_encoding csjisencoding </td> - * </tr> - * <tr> - * <td>ISO2022KR</td> - * <td>ISO-2022-KR</td> - * <td>csISO2022KR </td> - * </tr> - * <tr> - * <td>ISO2022_CN_CNS</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>ISO2022_CN_GB</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>ISO8859_1</td> - * <td>ISO-8859-1</td> - * <td>ISO_8859-1:1987 iso-ir-100 ISO_8859-1 latin1 l1 IBM819 CP819 csISOLatin1 8859_1 819 IBM-819 ISO8859-1 ISO_8859_1 </td> - * </tr> - * <tr> - * <td>ISO8859_13</td> - * <td>ISO-8859-13</td> - * <td></td> - * </tr> - * <tr> - * <td>ISO8859_15</td> - * <td>ISO-8859-15</td> - * <td>ISO_8859-15 Latin-9 8859_15 csISOlatin9 IBM923 cp923 923 L9 IBM-923 ISO8859-15 LATIN9 LATIN0 csISOlatin0 ISO8859_15_FDIS </td> - * </tr> - * <tr> - * <td>ISO8859_2</td> - * <td>ISO-8859-2</td> - * <td>ISO_8859-2:1987 iso-ir-101 ISO_8859-2 latin2 l2 csISOLatin2 8859_2 iso8859_2 </td> - * </tr> - * <tr> - * <td>ISO8859_3</td> - * <td>ISO-8859-3</td> - * <td>ISO_8859-3:1988 iso-ir-109 ISO_8859-3 latin3 l3 csISOLatin3 8859_3 </td> - * </tr> - * <tr> - * <td>ISO8859_4</td> - * <td>ISO-8859-4</td> - * <td>ISO_8859-4:1988 iso-ir-110 ISO_8859-4 latin4 l4 csISOLatin4 8859_4 </td> - * </tr> - * <tr> - * <td>ISO8859_5</td> - * <td>ISO-8859-5</td> - * <td>ISO_8859-5:1988 iso-ir-144 ISO_8859-5 cyrillic csISOLatinCyrillic 8859_5 </td> - * </tr> - * <tr> - * <td>ISO8859_6</td> - * <td>ISO-8859-6</td> - * <td>ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ECMA-114 ASMO-708 arabic csISOLatinArabic 8859_6 </td> - * </tr> - * <tr> - * <td>ISO8859_7</td> - * <td>ISO-8859-7</td> - * <td>ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ELOT_928 ECMA-118 greek greek8 csISOLatinGreek 8859_7 sun_eu_greek </td> - * </tr> - * <tr> - * <td>ISO8859_8</td> - * <td>ISO-8859-8</td> - * <td>ISO_8859-8:1988 iso-ir-138 ISO_8859-8 hebrew csISOLatinHebrew 8859_8 </td> - * </tr> - * <tr> - * <td>ISO8859_9</td> - * <td>ISO-8859-9</td> - * <td>ISO_8859-9:1989 iso-ir-148 ISO_8859-9 latin5 l5 csISOLatin5 8859_9 </td> - * </tr> - * <tr> - * <td>JISAutoDetect</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>JIS_C6626-1983</td> - * <td>JIS_C6626-1983</td> - * <td>x-JIS0208 JIS0208 csISO87JISX0208 x0208 JIS_X0208-1983 iso-ir-87 </td> - * </tr> - * <tr> - * <td>JIS_X0201</td> - * <td>JIS_X0201</td> - * <td>X0201 JIS0201 csHalfWidthKatakana </td> - * </tr> - * <tr> - * <td>JIS_X0212-1990</td> - * <td>JIS_X0212-1990</td> - * <td>iso-ir-159 x0212 JIS0212 csISO159JISX02121990 </td> - * </tr> - * <tr> - * <td>KOI8_R</td> - * <td>KOI8-R</td> - * <td>csKOI8R koi8 </td> - * </tr> - * <tr> - * <td>MS874</td> - * <td>windows-874</td> - * <td>cp874 </td> - * </tr> - * <tr> - * <td>MS932</td> - * <td>Windows-31J</td> - * <td>windows-932 csWindows31J x-ms-cp932 </td> - * </tr> - * <tr> - * <td>MS949</td> - * <td>windows-949</td> - * <td>windows949 ms_949 x-windows-949 </td> - * </tr> - * <tr> - * <td>MS950</td> - * <td>windows-950</td> - * <td>x-windows-950 </td> - * </tr> - * <tr> - * <td>MS950_HKSCS</td> - * <td></td> - * <td></td> - * </tr> - * <tr> - * <td>MacArabic</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacCentralEurope</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacCroatian</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacCyrillic</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacDingbat</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacGreek</td> - * <td>MacGreek</td> - * <td></td> - * </tr> - * <tr> - * <td>MacHebrew</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacIceland</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacRoman</td> - * <td>MacRoman</td> - * <td>Macintosh MAC csMacintosh </td> - * </tr> - * <tr> - * <td>MacRomania</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacSymbol</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacThai</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacTurkish</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>MacUkraine</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>SJIS</td> - * <td>Shift_JIS</td> - * <td>MS_Kanji csShiftJIS shift-jis x-sjis pck </td> - * </tr> - * <tr> - * <td>TIS620</td> - * <td>TIS-620</td> - * <td></td> - * </tr> - * <tr> - * <td>UTF-16</td> - * <td>UTF-16</td> - * <td>UTF_16 </td> - * </tr> - * <tr> - * <td>UTF8</td> - * <td>UTF-8</td> - * <td></td> - * </tr> - * <tr> - * <td>UnicodeBig</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>UnicodeBigUnmarked</td> - * <td>UTF-16BE</td> - * <td>X-UTF-16BE UTF_16BE ISO-10646-UCS-2 </td> - * </tr> - * <tr> - * <td>UnicodeLittle</td> - * <td>?</td> - * <td></td> - * </tr> - * <tr> - * <td>UnicodeLittleUnmarked</td> - * <td>UTF-16LE</td> - * <td>UTF_16LE X-UTF-16LE </td> - * </tr> - * <tr> - * <td>x-Johab</td> - * <td>johab</td> - * <td>johab cp1361 ms1361 ksc5601-1992 ksc5601_1992 </td> - * </tr> - * <tr> - * <td>x-iso-8859-11</td> - * <td>?</td> - * <td></td> - * </tr> - * </table> - * - * - * @version $Id: CharsetUtil.java,v 1.1 2004/10/25 07:26:46 ntherning Exp $ - */ -public class CharsetUtil { - private static Log log = LogFactory.getLog(CharsetUtil.class); - - private static class Charset implements Comparable<Charset> { - private String canonical = null; - private String mime = null; - private String[] aliases = null; - - private Charset(String canonical, String mime, String[] aliases) { - this.canonical = canonical; - this.mime = mime; - this.aliases = aliases; - } - - public int compareTo(Charset c) { - return this.canonical.compareTo(c.canonical); - } - } - - private static Charset[] JAVA_CHARSETS = { - new Charset("ISO8859_1", "ISO-8859-1", - new String[] {"ISO_8859-1:1987", "iso-ir-100", "ISO_8859-1", - "latin1", "l1", "IBM819", "CP819", - "csISOLatin1", "8859_1", "819", "IBM-819", - "ISO8859-1", "ISO_8859_1"}), - new Charset("ISO8859_2", "ISO-8859-2", - new String[] {"ISO_8859-2:1987", "iso-ir-101", "ISO_8859-2", - "latin2", "l2", "csISOLatin2", "8859_2", - "iso8859_2"}), - new Charset("ISO8859_3", "ISO-8859-3", new String[] {"ISO_8859-3:1988", "iso-ir-109", "ISO_8859-3", "latin3", "l3", "csISOLatin3", "8859_3"}), - new Charset("ISO8859_4", "ISO-8859-4", - new String[] {"ISO_8859-4:1988", "iso-ir-110", "ISO_8859-4", - "latin4", "l4", "csISOLatin4", "8859_4"}), - new Charset("ISO8859_5", "ISO-8859-5", - new String[] {"ISO_8859-5:1988", "iso-ir-144", "ISO_8859-5", - "cyrillic", "csISOLatinCyrillic", "8859_5"}), - new Charset("ISO8859_6", "ISO-8859-6", new String[] {"ISO_8859-6:1987", "iso-ir-127", "ISO_8859-6", "ECMA-114", "ASMO-708", "arabic", "csISOLatinArabic", "8859_6"}), - new Charset("ISO8859_7", "ISO-8859-7", - new String[] {"ISO_8859-7:1987", "iso-ir-126", "ISO_8859-7", - "ELOT_928", "ECMA-118", "greek", "greek8", - "csISOLatinGreek", "8859_7", "sun_eu_greek"}), - new Charset("ISO8859_8", "ISO-8859-8", new String[] {"ISO_8859-8:1988", "iso-ir-138", "ISO_8859-8", "hebrew", "csISOLatinHebrew", "8859_8"}), - new Charset("ISO8859_9", "ISO-8859-9", - new String[] {"ISO_8859-9:1989", "iso-ir-148", "ISO_8859-9", - "latin5", "l5", "csISOLatin5", "8859_9"}), - - new Charset("ISO8859_13", "ISO-8859-13", new String[] {}), - new Charset("ISO8859_15", "ISO-8859-15", - new String[] {"ISO_8859-15", "Latin-9", "8859_15", - "csISOlatin9", "IBM923", "cp923", "923", "L9", - "IBM-923", "ISO8859-15", "LATIN9", "LATIN0", - "csISOlatin0", "ISO8859_15_FDIS"}), - new Charset("KOI8_R", "KOI8-R", new String[] {"csKOI8R", "koi8"}), - new Charset("ASCII", "US-ASCII", - new String[] {"ANSI_X3.4-1968", "iso-ir-6", - "ANSI_X3.4-1986", "ISO_646.irv:1991", - "ISO646-US", "us", "IBM367", "cp367", - "csASCII", "ascii7", "646", "iso_646.irv:1983"}), - new Charset("UTF8", "UTF-8", new String[] {}), - new Charset("UTF-16", "UTF-16", new String[] {"UTF_16"}), - new Charset("UnicodeBigUnmarked", "UTF-16BE", new String[] {"X-UTF-16BE", "UTF_16BE", "ISO-10646-UCS-2"}), - new Charset("UnicodeLittleUnmarked", "UTF-16LE", new String[] {"UTF_16LE", "X-UTF-16LE"}), - new Charset("Big5", "Big5", new String[] {"csBig5", "CN-Big5", "BIG-FIVE", "BIGFIVE"}), - new Charset("Big5_HKSCS", "Big5-HKSCS", new String[] {"big5hkscs"}), - new Charset("EUC_JP", "EUC-JP", - new String[] {"csEUCPkdFmtJapanese", - "Extended_UNIX_Code_Packed_Format_for_Japanese", - "eucjis", "x-eucjp", "eucjp", "x-euc-jp"}), - new Charset("EUC_KR", "EUC-KR", - new String[] {"csEUCKR", "ksc5601", "5601", "ksc5601_1987", - "ksc_5601", "ksc5601-1987", "ks_c_5601-1987", - "euckr"}), - new Charset("GB18030", "GB18030", new String[] {"gb18030-2000"}), - new Charset("EUC_CN", "GB2312", new String[] {"x-EUC-CN", "csGB2312", "euccn", "euc-cn", "gb2312-80", "gb2312-1980", "CN-GB", "CN-GB-ISOIR165"}), - new Charset("GBK", "windows-936", new String[] {"CP936", "MS936", "ms_936", "x-mswin-936"}), - - new Charset("Cp037", "IBM037", new String[] {"ebcdic-cp-us", "ebcdic-cp-ca", "ebcdic-cp-wt", "ebcdic-cp-nl", "csIBM037"}), - new Charset("Cp273", "IBM273", new String[] {"csIBM273"}), - new Charset("Cp277", "IBM277", new String[] {"EBCDIC-CP-DK", "EBCDIC-CP-NO", "csIBM277"}), - new Charset("Cp278", "IBM278", new String[] {"CP278", "ebcdic-cp-fi", "ebcdic-cp-se", "csIBM278"}), - new Charset("Cp280", "IBM280", new String[] {"ebcdic-cp-it", "csIBM280"}), - new Charset("Cp284", "IBM284", new String[] {"ebcdic-cp-es", "csIBM284"}), - new Charset("Cp285", "IBM285", new String[] {"ebcdic-cp-gb", "csIBM285"}), - new Charset("Cp297", "IBM297", new String[] {"ebcdic-cp-fr", "csIBM297"}), - new Charset("Cp420", "IBM420", new String[] {"ebcdic-cp-ar1", "csIBM420"}), - new Charset("Cp424", "IBM424", new String[] {"ebcdic-cp-he", "csIBM424"}), - new Charset("Cp437", "IBM437", new String[] {"437", "csPC8CodePage437"}), - new Charset("Cp500", "IBM500", new String[] {"ebcdic-cp-be", "ebcdic-cp-ch", "csIBM500"}), - new Charset("Cp775", "IBM775", new String[] {"csPC775Baltic"}), - new Charset("Cp838", "IBM-Thai", new String[] {}), - new Charset("Cp850", "IBM850", new String[] {"850", "csPC850Multilingual"}), - new Charset("Cp852", "IBM852", new String[] {"852", "csPCp852"}), - new Charset("Cp855", "IBM855", new String[] {"855", "csIBM855"}), - new Charset("Cp857", "IBM857", new String[] {"857", "csIBM857"}), - new Charset("Cp858", "IBM00858", - new String[] {"CCSID00858", "CP00858", - "PC-Multilingual-850+euro"}), - new Charset("Cp860", "IBM860", new String[] {"860", "csIBM860"}), - new Charset("Cp861", "IBM861", new String[] {"861", "cp-is", "csIBM861"}), - new Charset("Cp862", "IBM862", new String[] {"862", "csPC862LatinHebrew"}), - new Charset("Cp863", "IBM863", new String[] {"863", "csIBM863"}), - new Charset("Cp864", "IBM864", new String[] {"cp864", "csIBM864"}), - new Charset("Cp865", "IBM865", new String[] {"865", "csIBM865"}), - new Charset("Cp866", "IBM866", new String[] {"866", "csIBM866"}), - new Charset("Cp868", "IBM868", new String[] {"cp-ar", "csIBM868"}), - new Charset("Cp869", "IBM869", new String[] {"cp-gr", "csIBM869"}), - new Charset("Cp870", "IBM870", new String[] {"ebcdic-cp-roece", "ebcdic-cp-yu", "csIBM870"}), - new Charset("Cp871", "IBM871", new String[] {"ebcdic-cp-is", "csIBM871"}), - new Charset("Cp918", "IBM918", new String[] {"ebcdic-cp-ar2", "csIBM918"}), - new Charset("Cp1026", "IBM1026", new String[] {"csIBM1026"}), - new Charset("Cp1047", "IBM1047", new String[] {"IBM-1047"}), - new Charset("Cp1140", "IBM01140", - new String[] {"CCSID01140", "CP01140", - "ebcdic-us-37+euro"}), - new Charset("Cp1141", "IBM01141", - new String[] {"CCSID01141", "CP01141", - "ebcdic-de-273+euro"}), - new Charset("Cp1142", "IBM01142", new String[] {"CCSID01142", "CP01142", "ebcdic-dk-277+euro", "ebcdic-no-277+euro"}), - new Charset("Cp1143", "IBM01143", new String[] {"CCSID01143", "CP01143", "ebcdic-fi-278+euro", "ebcdic-se-278+euro"}), - new Charset("Cp1144", "IBM01144", new String[] {"CCSID01144", "CP01144", "ebcdic-it-280+euro"}), - new Charset("Cp1145", "IBM01145", new String[] {"CCSID01145", "CP01145", "ebcdic-es-284+euro"}), - new Charset("Cp1146", "IBM01146", new String[] {"CCSID01146", "CP01146", "ebcdic-gb-285+euro"}), - new Charset("Cp1147", "IBM01147", new String[] {"CCSID01147", "CP01147", "ebcdic-fr-297+euro"}), - new Charset("Cp1148", "IBM01148", new String[] {"CCSID01148", "CP01148", "ebcdic-international-500+euro"}), - new Charset("Cp1149", "IBM01149", new String[] {"CCSID01149", "CP01149", "ebcdic-is-871+euro"}), - new Charset("Cp1250", "windows-1250", new String[] {}), - new Charset("Cp1251", "windows-1251", new String[] {}), - new Charset("Cp1252", "windows-1252", new String[] {}), - new Charset("Cp1253", "windows-1253", new String[] {}), - new Charset("Cp1254", "windows-1254", new String[] {}), - new Charset("Cp1255", "windows-1255", new String[] {}), - new Charset("Cp1256", "windows-1256", new String[] {}), - new Charset("Cp1257", "windows-1257", new String[] {}), - new Charset("Cp1258", "windows-1258", new String[] {}), - new Charset("ISO2022CN", "ISO-2022-CN", new String[] {}), - new Charset("ISO2022JP", "ISO-2022-JP", new String[] {"csISO2022JP", "JIS", "jis_encoding", "csjisencoding"}), - new Charset("ISO2022KR", "ISO-2022-KR", new String[] {"csISO2022KR"}), - new Charset("JIS_X0201", "JIS_X0201", new String[] {"X0201", "JIS0201", "csHalfWidthKatakana"}), - new Charset("JIS_X0212-1990", "JIS_X0212-1990", new String[] {"iso-ir-159", "x0212", "JIS0212", "csISO159JISX02121990"}), - new Charset("JIS_C6626-1983", "JIS_C6626-1983", new String[] {"x-JIS0208", "JIS0208", "csISO87JISX0208", "x0208", "JIS_X0208-1983", "iso-ir-87"}), - new Charset("SJIS", "Shift_JIS", new String[] {"MS_Kanji", "csShiftJIS", "shift-jis", "x-sjis", "pck"}), - new Charset("TIS620", "TIS-620", new String[] {}), - new Charset("MS932", "Windows-31J", new String[] {"windows-932", "csWindows31J", "x-ms-cp932"}), - new Charset("EUC_TW", "EUC-TW", new String[] {"x-EUC-TW", "cns11643", "euctw"}), - new Charset("x-Johab", "johab", new String[] {"johab", "cp1361", "ms1361", "ksc5601-1992", "ksc5601_1992"}), - new Charset("MS950_HKSCS", "", new String[] {}), - new Charset("MS874", "windows-874", new String[] {"cp874"}), - new Charset("MS949", "windows-949", new String[] {"windows949", "ms_949", "x-windows-949"}), - new Charset("MS950", "windows-950", new String[] {"x-windows-950"}), - - new Charset("Cp737", null, new String[] {}), - new Charset("Cp856", null, new String[] {}), - new Charset("Cp875", null, new String[] {}), - new Charset("Cp921", null, new String[] {}), - new Charset("Cp922", null, new String[] {}), - new Charset("Cp930", null, new String[] {}), - new Charset("Cp933", null, new String[] {}), - new Charset("Cp935", null, new String[] {}), - new Charset("Cp937", null, new String[] {}), - new Charset("Cp939", null, new String[] {}), - new Charset("Cp942", null, new String[] {}), - new Charset("Cp942C", null, new String[] {}), - new Charset("Cp943", null, new String[] {}), - new Charset("Cp943C", null, new String[] {}), - new Charset("Cp948", null, new String[] {}), - new Charset("Cp949", null, new String[] {}), - new Charset("Cp949C", null, new String[] {}), - new Charset("Cp950", null, new String[] {}), - new Charset("Cp964", null, new String[] {}), - new Charset("Cp970", null, new String[] {}), - new Charset("Cp1006", null, new String[] {}), - new Charset("Cp1025", null, new String[] {}), - new Charset("Cp1046", null, new String[] {}), - new Charset("Cp1097", null, new String[] {}), - new Charset("Cp1098", null, new String[] {}), - new Charset("Cp1112", null, new String[] {}), - new Charset("Cp1122", null, new String[] {}), - new Charset("Cp1123", null, new String[] {}), - new Charset("Cp1124", null, new String[] {}), - new Charset("Cp1381", null, new String[] {}), - new Charset("Cp1383", null, new String[] {}), - new Charset("Cp33722", null, new String[] {}), - new Charset("Big5_Solaris", null, new String[] {}), - new Charset("EUC_JP_LINUX", null, new String[] {}), - new Charset("EUC_JP_Solaris", null, new String[] {}), - new Charset("ISCII91", null, new String[] {"x-ISCII91", "iscii"}), - new Charset("ISO2022_CN_CNS", null, new String[] {}), - new Charset("ISO2022_CN_GB", null, new String[] {}), - new Charset("x-iso-8859-11", null, new String[] {}), - new Charset("JISAutoDetect", null, new String[] {}), - new Charset("MacArabic", null, new String[] {}), - new Charset("MacCentralEurope", null, new String[] {}), - new Charset("MacCroatian", null, new String[] {}), - new Charset("MacCyrillic", null, new String[] {}), - new Charset("MacDingbat", null, new String[] {}), - new Charset("MacGreek", "MacGreek", new String[] {}), - new Charset("MacHebrew", null, new String[] {}), - new Charset("MacIceland", null, new String[] {}), - new Charset("MacRoman", "MacRoman", new String[] {"Macintosh", "MAC", "csMacintosh"}), - new Charset("MacRomania", null, new String[] {}), - new Charset("MacSymbol", null, new String[] {}), - new Charset("MacThai", null, new String[] {}), - new Charset("MacTurkish", null, new String[] {}), - new Charset("MacUkraine", null, new String[] {}), - new Charset("UnicodeBig", null, new String[] {}), - new Charset("UnicodeLittle", null, new String[] {}) - }; - - /** - * Contains the canonical names of character sets which can be used to - * decode bytes into Java chars. - */ - private static TreeSet<String> decodingSupported = null; - - /** - * Contains the canonical names of character sets which can be used to - * encode Java chars into bytes. - */ - private static TreeSet<String> encodingSupported = null; - - /** - * Maps character set names to Charset objects. All possible names of - * a charset will be mapped to the Charset. - */ - private static HashMap<String, Charset> charsetMap = null; - - static { - decodingSupported = new TreeSet<String>(); - encodingSupported = new TreeSet<String>(); - byte[] dummy = new byte[] {'d', 'u', 'm', 'm', 'y'}; - for (int i = 0; i < JAVA_CHARSETS.length; i++) { - try { - String s = new String(dummy, JAVA_CHARSETS[i].canonical); - decodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase(Locale.US)); - } catch (UnsupportedOperationException e) { - } catch (UnsupportedEncodingException e) { - } - try { - "dummy".getBytes(JAVA_CHARSETS[i].canonical); - encodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase(Locale.US)); - } catch (UnsupportedOperationException e) { - } catch (UnsupportedEncodingException e) { - } - } - - charsetMap = new HashMap<String, Charset>(); - for (int i = 0; i < JAVA_CHARSETS.length; i++) { - Charset c = JAVA_CHARSETS[i]; - charsetMap.put(c.canonical.toLowerCase(Locale.US), c); - if (c.mime != null) { - charsetMap.put(c.mime.toLowerCase(Locale.US), c); - } - if (c.aliases != null) { - for (int j = 0; j < c.aliases.length; j++) { - charsetMap.put(c.aliases[j].toLowerCase(Locale.US), c); - } - } - } - - if (log.isDebugEnabled()) { - log.debug("Character sets which support decoding: " - + decodingSupported); - log.debug("Character sets which support encoding: " - + encodingSupported); - } - } - - /** - * ANDROID: THE FOLLOWING SET OF STATIC STRINGS ARE COPIED FROM A NEWER VERSION OF MIME4J - */ - - /** carriage return - line feed sequence */ - public static final String CRLF = "\r\n"; - - /** US-ASCII CR, carriage return (13) */ - public static final int CR = '\r'; - - /** US-ASCII LF, line feed (10) */ - public static final int LF = '\n'; - - /** US-ASCII SP, space (32) */ - public static final int SP = ' '; - - /** US-ASCII HT, horizontal-tab (9)*/ - public static final int HT = '\t'; - - public static final java.nio.charset.Charset US_ASCII = java.nio.charset.Charset - .forName("US-ASCII"); - - public static final java.nio.charset.Charset ISO_8859_1 = java.nio.charset.Charset - .forName("ISO-8859-1"); - - public static final java.nio.charset.Charset UTF_8 = java.nio.charset.Charset - .forName("UTF-8"); - - /** - * Returns <code>true</code> if the specified character is a whitespace - * character (CR, LF, SP or HT). - * - * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J - * - * @param ch - * character to test. - * @return <code>true</code> if the specified character is a whitespace - * character, <code>false</code> otherwise. - */ - public static boolean isWhitespace(char ch) { - return ch == SP || ch == HT || ch == CR || ch == LF; - } - - /** - * Returns <code>true</code> if the specified string consists entirely of - * whitespace characters. - * - * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J - * - * @param s - * string to test. - * @return <code>true</code> if the specified string consists entirely of - * whitespace characters, <code>false</code> otherwise. - */ - public static boolean isWhitespace(final String s) { - if (s == null) { - throw new IllegalArgumentException("String may not be null"); - } - final int len = s.length(); - for (int i = 0; i < len; i++) { - if (!isWhitespace(s.charAt(i))) { - return false; - } - } - return true; - } - - /** - * Determines if the VM supports encoding (chars to bytes) the - * specified character set. NOTE: the given character set name may - * not be known to the VM even if this method returns <code>true</code>. - * Use {@link #toJavaCharset(String)} to get the canonical Java character - * set name. - * - * @param charsetName the characters set name. - * @return <code>true</code> if encoding is supported, <code>false</code> - * otherwise. - */ - public static boolean isEncodingSupported(String charsetName) { - return encodingSupported.contains(charsetName.toLowerCase(Locale.US)); - } - - /** - * Determines if the VM supports decoding (bytes to chars) the - * specified character set. NOTE: the given character set name may - * not be known to the VM even if this method returns <code>true</code>. - * Use {@link #toJavaCharset(String)} to get the canonical Java character - * set name. - * - * @param charsetName the characters set name. - * @return <code>true</code> if decoding is supported, <code>false</code> - * otherwise. - */ - public static boolean isDecodingSupported(String charsetName) { - return decodingSupported.contains(charsetName.toLowerCase(Locale.US)); - } - - /** - * Gets the preferred MIME character set name for the specified - * character set or <code>null</code> if not known. - * - * @param charsetName the character set name to look for. - * @return the MIME preferred name or <code>null</code> if not known. - */ - public static String toMimeCharset(String charsetName) { - Charset c = charsetMap.get(charsetName.toLowerCase(Locale.US)); - if (c != null) { - return c.mime; - } - return null; - } - - /** - * Gets the canonical Java character set name for the specified - * character set or <code>null</code> if not known. This should be - * called before doing any conversions using the Java API. NOTE: - * you must use {@link #isEncodingSupported(String)} or - * {@link #isDecodingSupported(String)} to make sure the returned - * Java character set is supported by the current VM. - * - * @param charsetName the character set name to look for. - * @return the canonical Java name or <code>null</code> if not known. - */ - public static String toJavaCharset(String charsetName) { - Charset c = charsetMap.get(charsetName.toLowerCase(Locale.US)); - if (c != null) { - return c.canonical; - } - return null; - } - - public static java.nio.charset.Charset getCharset(String charsetName) { - String defaultCharset = "ISO-8859-1"; - - // Use the default chareset if given charset is null - if(charsetName == null) charsetName = defaultCharset; - - try { - return java.nio.charset.Charset.forName(charsetName); - } catch (IllegalCharsetNameException e) { - log.info("Illegal charset " + charsetName + ", fallback to " + - defaultCharset + ": " + e); - // Use default charset on exception - return java.nio.charset.Charset.forName(defaultCharset); - } catch (UnsupportedCharsetException ex) { - log.info("Unsupported charset " + charsetName + ", fallback to " + - defaultCharset + ": " + ex); - // Use default charset on exception - return java.nio.charset.Charset.forName(defaultCharset); - } - - } - /* - * Uncomment the code below and run the main method to regenerate the - * Javadoc table above when the known charsets change. - */ - - /* - private static String dumpHtmlTable() { - LinkedList l = new LinkedList(Arrays.asList(JAVA_CHARSETS)); - Collections.sort(l); - StringBuffer sb = new StringBuffer(); - sb.append(" * <table>\n"); - sb.append(" * <tr>\n"); - sb.append(" * <td>Canonical (Java) name</td>\n"); - sb.append(" * <td>MIME preferred</td>\n"); - sb.append(" * <td>Aliases</td>\n"); - sb.append(" * </tr>\n"); - - for (Iterator it = l.iterator(); it.hasNext();) { - Charset c = (Charset) it.next(); - sb.append(" * <tr>\n"); - sb.append(" * <td>" + c.canonical + "</td>\n"); - sb.append(" * <td>" + (c.mime == null ? "?" : c.mime)+ "</td>\n"); - sb.append(" * <td>"); - for (int i = 0; c.aliases != null && i < c.aliases.length; i++) { - sb.append(c.aliases[i] + " "); - } - sb.append("</td>\n"); - sb.append(" * </tr>\n"); - } - sb.append(" * </table>\n"); - return sb.toString(); - } - - public static void main(String[] args) { - System.out.println(dumpHtmlTable()); - }*/ -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/sync/OmtpVvmSourceManager.java b/java/com/android/voicemailomtp/sync/OmtpVvmSourceManager.java deleted file mode 100644 index ad3c025cf..000000000 --- a/java/com/android/voicemailomtp/sync/OmtpVvmSourceManager.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; - -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmPhoneStateListener; - -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * A singleton class designed to remember the active OMTP visual voicemail sources. Because a - * voicemail source is tied 1:1 to a phone account, the phone account handle is used as the key - * for each voicemail source and the associated data. - */ -public class OmtpVvmSourceManager { - public static final String TAG = "OmtpVvmSourceManager"; - - private static OmtpVvmSourceManager sInstance = new OmtpVvmSourceManager(); - - private Context mContext; - private TelephonyManager mTelephonyManager; - // Each phone account is associated with a phone state listener for updates to whether the - // device is able to sync. - private Set<PhoneAccountHandle> mActiveVvmSources; - private Map<PhoneAccountHandle, PhoneStateListener> mPhoneStateListenerMap; - - /** - * Private constructor. Instance should only be acquired through getInstance(). - */ - private OmtpVvmSourceManager() {} - - public static OmtpVvmSourceManager getInstance(Context context) { - sInstance.setup(context); - return sInstance; - } - - /** - * Set the context and system services so they do not need to be retrieved every time. - * @param context The context to get the subscription and telephony manager for. - */ - private void setup(Context context) { - if (mContext == null) { - mContext = context; - mTelephonyManager = (TelephonyManager) - mContext.getSystemService(Context.TELEPHONY_SERVICE); - mActiveVvmSources = Collections.newSetFromMap( - new ConcurrentHashMap<PhoneAccountHandle, Boolean>(8, 0.9f, 1)); - mPhoneStateListenerMap = - new ConcurrentHashMap<PhoneAccountHandle, PhoneStateListener>(8, 0.9f, 1); - } - } - - public void addSource(PhoneAccountHandle phoneAccount) { - mActiveVvmSources.add(phoneAccount); - } - - public void removeSource(PhoneAccountHandle phoneAccount) { - // TODO: should use OmtpVvmCarrierConfigHelper to handle the event. But currently it - // couldn't handle events on removed SIMs - VoicemailStatus.disable(mContext, phoneAccount); - removePhoneStateListener(phoneAccount); - mActiveVvmSources.remove(phoneAccount); - } - - public void addPhoneStateListener(PhoneAccountHandle phoneAccount) { - if (!mPhoneStateListenerMap.containsKey(phoneAccount)) { - VvmPhoneStateListener phoneStateListener = new VvmPhoneStateListener(mContext, - phoneAccount); - mPhoneStateListenerMap.put(phoneAccount, phoneStateListener); - mTelephonyManager.createForPhoneAccountHandle(phoneAccount) - .listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); - } - } - - public void removePhoneStateListener(PhoneAccountHandle phoneAccount) { - PhoneStateListener phoneStateListener = - mPhoneStateListenerMap.remove(phoneAccount); - mTelephonyManager.createForPhoneAccountHandle(phoneAccount).listen(phoneStateListener, 0); - } - - public Set<PhoneAccountHandle> getOmtpVvmSources() { - return mActiveVvmSources; - } - - /** - * Check if a certain account is registered. - * - * @param phoneAccount The account to look for. - * @return {@code true} if the account is in the list of registered OMTP voicemail sources. - * {@code false} otherwise. - */ - public boolean isVvmSourceRegistered(PhoneAccountHandle phoneAccount) { - if (phoneAccount == null) { - return false; - } - - return mActiveVvmSources.contains(phoneAccount); - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/sync/OmtpVvmSyncReceiver.java b/java/com/android/voicemailomtp/sync/OmtpVvmSyncReceiver.java deleted file mode 100644 index 971a1c5a8..000000000 --- a/java/com/android/voicemailomtp/sync/OmtpVvmSyncReceiver.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sync; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.provider.VoicemailContract; -import android.telecom.PhoneAccountHandle; -import android.telecom.TelecomManager; - -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.settings.VisualVoicemailSettingsUtil; - -import java.util.List; - -public class OmtpVvmSyncReceiver extends BroadcastReceiver { - - private static final String TAG = "OmtpVvmSyncReceiver"; - - @Override - public void onReceive(final Context context, Intent intent) { - if (VoicemailContract.ACTION_SYNC_VOICEMAIL.equals(intent.getAction())) { - VvmLog.v(TAG, "Sync intent received"); - for (PhoneAccountHandle source : OmtpVvmSourceManager.getInstance(context) - .getOmtpVvmSources()) { - SyncTask.start(context, source, OmtpVvmSyncService.SYNC_FULL_SYNC); - } - activateUnactivatedAccounts(context); - } - } - - private static void activateUnactivatedAccounts(Context context) { - List<PhoneAccountHandle> accounts = - context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts(); - for (PhoneAccountHandle phoneAccount : accounts) { - if (!VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) { - continue; - } - if (!OmtpVvmSourceManager.getInstance(context).isVvmSourceRegistered(phoneAccount)) { - VvmLog.i(TAG, "Unactivated account " + phoneAccount + " found, activating"); - ActivationTask.start(context, phoneAccount, null); - } - } - } -} diff --git a/java/com/android/voicemailomtp/sync/OmtpVvmSyncService.java b/java/com/android/voicemailomtp/sync/OmtpVvmSyncService.java deleted file mode 100644 index a3418cc28..000000000 --- a/java/com/android/voicemailomtp/sync/OmtpVvmSyncService.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.annotation.TargetApi; -import android.content.Context; -import android.net.Network; -import android.net.Uri; -import android.os.Build.VERSION_CODES; -import android.telecom.PhoneAccountHandle; -import android.text.TextUtils; -import com.android.voicemailomtp.ActivationTask; -import com.android.voicemailomtp.Assert; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.Voicemail; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.fetch.VoicemailFetchedCallback; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.imap.ImapHelper.InitializingException; -import com.android.voicemailomtp.scheduling.BaseTask; -import com.android.voicemailomtp.settings.VisualVoicemailSettingsUtil; -import com.android.voicemailomtp.sync.VvmNetworkRequest.NetworkWrapper; -import com.android.voicemailomtp.sync.VvmNetworkRequest.RequestFailedException; -import com.android.voicemailomtp.utils.VoicemailDatabaseUtil; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Sync OMTP visual voicemail. */ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class OmtpVvmSyncService { - - private static final String TAG = OmtpVvmSyncService.class.getSimpleName(); - - /** - * Signifies a sync with both uploading to the server and downloading from the server. - */ - public static final String SYNC_FULL_SYNC = "full_sync"; - /** - * Only upload to the server. - */ - public static final String SYNC_UPLOAD_ONLY = "upload_only"; - /** - * Only download from the server. - */ - public static final String SYNC_DOWNLOAD_ONLY = "download_only"; - /** - * Only download single voicemail transcription. - */ - public static final String SYNC_DOWNLOAD_ONE_TRANSCRIPTION = - "download_one_transcription"; - - private final Context mContext; - - // Record the timestamp of the last full sync so that duplicate syncs can be reduced. - private static final String LAST_FULL_SYNC_TIMESTAMP = "last_full_sync_timestamp"; - // Constant indicating that there has never been a full sync. - public static final long NO_PRIOR_FULL_SYNC = -1; - - private VoicemailsQueryHelper mQueryHelper; - - public OmtpVvmSyncService(Context context) { - mContext = context; - mQueryHelper = new VoicemailsQueryHelper(mContext); - } - - public void sync(BaseTask task, String action, PhoneAccountHandle phoneAccount, - Voicemail voicemail, VoicemailStatus.Editor status) { - Assert.isTrue(phoneAccount != null); - VvmLog.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount); - setupAndSendRequest(task, phoneAccount, voicemail, action, status); - } - - private void setupAndSendRequest(BaseTask task, PhoneAccountHandle phoneAccount, - Voicemail voicemail, String action, VoicemailStatus.Editor status) { - if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phoneAccount)) { - VvmLog.v(TAG, "Sync requested for disabled account"); - return; - } - if (!OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(phoneAccount)) { - ActivationTask.start(mContext, phoneAccount, null); - return; - } - - OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(mContext, phoneAccount); - // DATA_IMAP_OPERATION_STARTED posting should not be deferred. This event clears all data - // channel errors, which should happen when the task starts, not when it ends. It is the - // "Sync in progress..." status. - config.handleEvent(VoicemailStatus.edit(mContext, phoneAccount), - OmtpEvents.DATA_IMAP_OPERATION_STARTED); - try (NetworkWrapper network = VvmNetworkRequest.getNetwork(config, phoneAccount, status)) { - if (network == null) { - VvmLog.e(TAG, "unable to acquire network"); - task.fail(); - return; - } - doSync(task, network.get(), phoneAccount, voicemail, action, status); - } catch (RequestFailedException e) { - config.handleEvent(status, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED); - task.fail(); - } - } - - private void doSync(BaseTask task, Network network, PhoneAccountHandle phoneAccount, - Voicemail voicemail, String action, VoicemailStatus.Editor status) { - try (ImapHelper imapHelper = new ImapHelper(mContext, phoneAccount, network, status)) { - boolean success; - if (voicemail == null) { - success = syncAll(action, imapHelper, phoneAccount); - } else { - success = syncOne(imapHelper, voicemail, phoneAccount); - } - if (success) { - // TODO: b/30569269 failure should interrupt all subsequent task via exceptions - imapHelper.updateQuota(); - imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED); - } else { - task.fail(); - } - } catch (InitializingException e) { - VvmLog.w(TAG, "Can't retrieve Imap credentials.", e); - return; - } - } - - private boolean syncAll(String action, ImapHelper imapHelper, PhoneAccountHandle account) { - boolean uploadSuccess = true; - boolean downloadSuccess = true; - - if (SYNC_FULL_SYNC.equals(action) || SYNC_UPLOAD_ONLY.equals(action)) { - uploadSuccess = upload(imapHelper); - } - if (SYNC_FULL_SYNC.equals(action) || SYNC_DOWNLOAD_ONLY.equals(action)) { - downloadSuccess = download(imapHelper, account); - } - - VvmLog.v(TAG, "upload succeeded: [" + String.valueOf(uploadSuccess) - + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]"); - - return uploadSuccess && downloadSuccess; - } - - private boolean syncOne(ImapHelper imapHelper, Voicemail voicemail, - PhoneAccountHandle account) { - if (shouldPerformPrefetch(account, imapHelper)) { - VoicemailFetchedCallback callback = new VoicemailFetchedCallback(mContext, - voicemail.getUri(), account); - imapHelper.fetchVoicemailPayload(callback, voicemail.getSourceData()); - } - - return imapHelper.fetchTranscription( - new TranscriptionFetchedCallback(mContext, voicemail), - voicemail.getSourceData()); - } - - private boolean upload(ImapHelper imapHelper) { - List<Voicemail> readVoicemails = mQueryHelper.getReadVoicemails(); - List<Voicemail> deletedVoicemails = mQueryHelper.getDeletedVoicemails(); - - boolean success = true; - - if (deletedVoicemails.size() > 0) { - if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) { - // We want to delete selectively instead of all the voicemails for this provider - // in case the state changed since the IMAP query was completed. - mQueryHelper.deleteFromDatabase(deletedVoicemails); - } else { - success = false; - } - } - - if (readVoicemails.size() > 0) { - if (imapHelper.markMessagesAsRead(readVoicemails)) { - mQueryHelper.markCleanInDatabase(readVoicemails); - } else { - success = false; - } - } - - return success; - } - - private boolean download(ImapHelper imapHelper, PhoneAccountHandle account) { - List<Voicemail> serverVoicemails = imapHelper.fetchAllVoicemails(); - List<Voicemail> localVoicemails = mQueryHelper.getAllVoicemails(); - - if (localVoicemails == null || serverVoicemails == null) { - // Null value means the query failed. - return false; - } - - Map<String, Voicemail> remoteMap = buildMap(serverVoicemails); - - // Go through all the local voicemails and check if they are on the server. - // They may be read or deleted on the server but not locally. Perform the - // appropriate local operation if the status differs from the server. Remove - // the messages that exist both locally and on the server to know which server - // messages to insert locally. - for (int i = 0; i < localVoicemails.size(); i++) { - Voicemail localVoicemail = localVoicemails.get(i); - Voicemail remoteVoicemail = remoteMap.remove(localVoicemail.getSourceData()); - if (remoteVoicemail == null) { - mQueryHelper.deleteFromDatabase(localVoicemail); - } else { - if (remoteVoicemail.isRead() != localVoicemail.isRead()) { - mQueryHelper.markReadInDatabase(localVoicemail); - } - - if (!TextUtils.isEmpty(remoteVoicemail.getTranscription()) && - TextUtils.isEmpty(localVoicemail.getTranscription())) { - mQueryHelper.updateWithTranscription(localVoicemail, - remoteVoicemail.getTranscription()); - } - } - } - - // The leftover messages are messages that exist on the server but not locally. - boolean prefetchEnabled = shouldPerformPrefetch(account, imapHelper); - for (Voicemail remoteVoicemail : remoteMap.values()) { - Uri uri = VoicemailDatabaseUtil.insert(mContext, remoteVoicemail); - if (prefetchEnabled) { - VoicemailFetchedCallback fetchedCallback = - new VoicemailFetchedCallback(mContext, uri, account); - imapHelper.fetchVoicemailPayload(fetchedCallback, remoteVoicemail.getSourceData()); - } - } - - return true; - } - - private boolean shouldPerformPrefetch(PhoneAccountHandle account, ImapHelper imapHelper) { - OmtpVvmCarrierConfigHelper carrierConfigHelper = - new OmtpVvmCarrierConfigHelper(mContext, account); - return carrierConfigHelper.isPrefetchEnabled() && !imapHelper.isRoaming(); - } - - /** - * Builds a map from provider data to message for the given collection of voicemails. - */ - private Map<String, Voicemail> buildMap(List<Voicemail> messages) { - Map<String, Voicemail> map = new HashMap<String, Voicemail>(); - for (Voicemail message : messages) { - map.put(message.getSourceData(), message); - } - return map; - } - - public class TranscriptionFetchedCallback { - - private Context mContext; - private Voicemail mVoicemail; - - public TranscriptionFetchedCallback(Context context, Voicemail voicemail) { - mContext = context; - mVoicemail = voicemail; - } - - public void setVoicemailTranscription(String transcription) { - VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext); - queryHelper.updateWithTranscription(mVoicemail, transcription); - } - } -} diff --git a/java/com/android/voicemailomtp/sync/SyncOneTask.java b/java/com/android/voicemailomtp/sync/SyncOneTask.java deleted file mode 100644 index 9264e6c08..000000000 --- a/java/com/android/voicemailomtp/sync/SyncOneTask.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.sync; - -import android.content.Context; -import android.content.Intent; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.Voicemail; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.scheduling.BaseTask; -import com.android.voicemailomtp.scheduling.RetryPolicy; - -/** - * Task to download a single voicemail from the server. This task is initiated by a SMS notifying - * the new voicemail arrival, and ignores the duplicated tasks constraint. - */ -public class SyncOneTask extends BaseTask { - - private static final int RETRY_TIMES = 2; - private static final int RETRY_INTERVAL_MILLIS = 5_000; - - private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; - private static final String EXTRA_SYNC_TYPE = "extra_sync_type"; - private static final String EXTRA_VOICEMAIL = "extra_voicemail"; - - private PhoneAccountHandle mPhone; - private String mSyncType; - private Voicemail mVoicemail; - - public static void start(Context context, PhoneAccountHandle phone, Voicemail voicemail) { - Intent intent = BaseTask - .createIntent(context, SyncOneTask.class, phone); - intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone); - intent.putExtra(EXTRA_SYNC_TYPE, OmtpVvmSyncService.SYNC_DOWNLOAD_ONE_TRANSCRIPTION); - intent.putExtra(EXTRA_VOICEMAIL, voicemail); - context.startService(intent); - } - - public SyncOneTask() { - super(TASK_ALLOW_DUPLICATES); - addPolicy(new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS)); - } - - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE); - mVoicemail = intent.getParcelableExtra(EXTRA_VOICEMAIL); - } - - @Override - public void onExecuteInBackgroundThread() { - OmtpVvmSyncService service = new OmtpVvmSyncService(getContext()); - service.sync(this, mSyncType, mPhone, mVoicemail, - VoicemailStatus.edit(getContext(), mPhone)); - } - - @Override - public Intent createRestartIntent() { - Intent intent = super.createRestartIntent(); - intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone); - intent.putExtra(EXTRA_SYNC_TYPE, mSyncType); - intent.putExtra(EXTRA_VOICEMAIL, mVoicemail); - return intent; - } - -} diff --git a/java/com/android/voicemailomtp/sync/SyncTask.java b/java/com/android/voicemailomtp/sync/SyncTask.java deleted file mode 100644 index 41b22f22c..000000000 --- a/java/com/android/voicemailomtp/sync/SyncTask.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sync; - -import android.content.Context; -import android.content.Intent; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.scheduling.BaseTask; -import com.android.voicemailomtp.scheduling.MinimalIntervalPolicy; -import com.android.voicemailomtp.scheduling.RetryPolicy; - -/** - * System initiated sync request. - */ -public class SyncTask extends BaseTask { - - // Try sync for a total of 5 times, should take around 5 minutes before finally giving up. - private static final int RETRY_TIMES = 4; - private static final int RETRY_INTERVAL_MILLIS = 5_000; - private static final int MINIMAL_INTERVAL_MILLIS = 60_000; - - private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; - private static final String EXTRA_SYNC_TYPE = "extra_sync_type"; - - private final RetryPolicy mRetryPolicy; - - private PhoneAccountHandle mPhone; - private String mSyncType; - - public static void start(Context context, PhoneAccountHandle phone, String syncType) { - Intent intent = BaseTask - .createIntent(context, SyncTask.class, phone); - intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone); - intent.putExtra(EXTRA_SYNC_TYPE, syncType); - context.startService(intent); - } - - public SyncTask() { - super(TASK_SYNC); - mRetryPolicy = new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS); - addPolicy(mRetryPolicy); - addPolicy(new MinimalIntervalPolicy(MINIMAL_INTERVAL_MILLIS)); - } - - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE); - } - - @Override - public void onExecuteInBackgroundThread() { - OmtpVvmSyncService service = new OmtpVvmSyncService(getContext()); - service.sync(this, mSyncType, mPhone, null, mRetryPolicy.getVoicemailStatusEditor()); - } - - @Override - public Intent createRestartIntent() { - Intent intent = super.createRestartIntent(); - intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone); - intent.putExtra(EXTRA_SYNC_TYPE, mSyncType); - return intent; - } -} diff --git a/java/com/android/voicemailomtp/sync/UploadTask.java b/java/com/android/voicemailomtp/sync/UploadTask.java deleted file mode 100644 index 30a16812b..000000000 --- a/java/com/android/voicemailomtp/sync/UploadTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sync; - -import android.content.Context; -import android.content.Intent; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import com.android.voicemailomtp.scheduling.BaseTask; -import com.android.voicemailomtp.scheduling.PostponePolicy; - -/** - * Upload task triggered by database changes. Will wait until the database has been stable for - * {@link #POSTPONE_MILLIS} to execute. - */ -public class UploadTask extends BaseTask { - - private static final String TAG = "VvmUploadTask"; - - private static final int POSTPONE_MILLIS = 5_000; - - public UploadTask() { - super(TASK_UPLOAD); - addPolicy(new PostponePolicy(POSTPONE_MILLIS)); - } - - public static void start(Context context, PhoneAccountHandle phoneAccountHandle) { - Intent intent = BaseTask - .createIntent(context, UploadTask.class, phoneAccountHandle); - context.startService(intent); - } - - @Override - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - } - - @Override - public void onExecuteInBackgroundThread() { - OmtpVvmSyncService service = new OmtpVvmSyncService(getContext()); - - PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(); - if (phoneAccountHandle == null) { - // This should never happen - VvmLog.e(TAG, "null phone account for phoneAccountHandle " + getPhoneAccountHandle()); - return; - } - service.sync(this, OmtpVvmSyncService.SYNC_UPLOAD_ONLY, - phoneAccountHandle, null, - VoicemailStatus.edit(getContext(), phoneAccountHandle)); - } -} diff --git a/java/com/android/voicemailomtp/sync/VoicemailProviderChangeReceiver.java b/java/com/android/voicemailomtp/sync/VoicemailProviderChangeReceiver.java deleted file mode 100644 index ade9ef12d..000000000 --- a/java/com/android/voicemailomtp/sync/VoicemailProviderChangeReceiver.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.provider.VoicemailContract; -import android.telecom.PhoneAccountHandle; - -/** - * Receives changes to the voicemail provider so they can be sent to the voicemail server. - */ -public class VoicemailProviderChangeReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - boolean isSelfChanged = intent.getBooleanExtra(VoicemailContract.EXTRA_SELF_CHANGE, false); - OmtpVvmSourceManager vvmSourceManager = - OmtpVvmSourceManager.getInstance(context); - if (vvmSourceManager.getOmtpVvmSources().size() > 0 && !isSelfChanged) { - for (PhoneAccountHandle source : OmtpVvmSourceManager.getInstance(context) - .getOmtpVvmSources()) { - UploadTask.start(context, source); - } - } - } -} diff --git a/java/com/android/voicemailomtp/sync/VoicemailStatusQueryHelper.java b/java/com/android/voicemailomtp/sync/VoicemailStatusQueryHelper.java deleted file mode 100644 index 89ba0b494..000000000 --- a/java/com/android/voicemailomtp/sync/VoicemailStatusQueryHelper.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.VoicemailContract; -import android.provider.VoicemailContract.Status; -import android.telecom.PhoneAccountHandle; - -/** - * Construct queries to interact with the voicemail status table. - */ -public class VoicemailStatusQueryHelper { - - final static String[] PROJECTION = new String[] { - Status._ID, // 0 - Status.CONFIGURATION_STATE, // 1 - Status.NOTIFICATION_CHANNEL_STATE, // 2 - Status.SOURCE_PACKAGE // 3 - }; - - public static final int _ID = 0; - public static final int CONFIGURATION_STATE = 1; - public static final int NOTIFICATION_CHANNEL_STATE = 2; - public static final int SOURCE_PACKAGE = 3; - - private Context mContext; - private ContentResolver mContentResolver; - private Uri mSourceUri; - - public VoicemailStatusQueryHelper(Context context) { - mContext = context; - mContentResolver = context.getContentResolver(); - mSourceUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName()); - } - - /** - * Check if the configuration state for the voicemail source is "ok", meaning that the - * source is set up. - * - * @param phoneAccount The phone account for the voicemail source to check. - * @return {@code true} if the voicemail source is configured, {@code} false otherwise, - * including if the voicemail source is not registered in the table. - */ - public boolean isVoicemailSourceConfigured(PhoneAccountHandle phoneAccount) { - return isFieldEqualTo(phoneAccount, CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK); - } - - /** - * Check if the notifications channel of a voicemail source is active. That is, when a new - * voicemail is available, if the server able to notify the device. - * - * @return {@code true} if notifications channel is active, {@code false} otherwise. - */ - public boolean isNotificationsChannelActive(PhoneAccountHandle phoneAccount) { - return isFieldEqualTo(phoneAccount, NOTIFICATION_CHANNEL_STATE, - Status.NOTIFICATION_CHANNEL_STATE_OK); - } - - /** - * Check if a field for an entry in the status table is equal to a specific value. - * - * @param phoneAccount The phone account of the voicemail source to query for. - * @param columnIndex The column index of the field in the returned query. - * @param value The value to compare against. - * @return {@code true} if the stored value is equal to the provided value. {@code false} - * otherwise. - */ - private boolean isFieldEqualTo(PhoneAccountHandle phoneAccount, int columnIndex, int value) { - Cursor cursor = null; - if (phoneAccount != null) { - String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString(); - String phoneAccountId = phoneAccount.getId(); - if (phoneAccountComponentName == null || phoneAccountId == null) { - return false; - } - try { - String whereClause = - Status.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " + - Status.PHONE_ACCOUNT_ID + "=? AND " + Status.SOURCE_PACKAGE + "=?"; - String[] whereArgs = { phoneAccountComponentName, phoneAccountId, - mContext.getPackageName()}; - cursor = mContentResolver.query( - mSourceUri, PROJECTION, whereClause, whereArgs, null); - if (cursor != null && cursor.moveToFirst()) { - return cursor.getInt(columnIndex) == value; - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - return false; - } -} diff --git a/java/com/android/voicemailomtp/sync/VoicemailsQueryHelper.java b/java/com/android/voicemailomtp/sync/VoicemailsQueryHelper.java deleted file mode 100644 index 1450e3d1b..000000000 --- a/java/com/android/voicemailomtp/sync/VoicemailsQueryHelper.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.VoicemailContract; -import android.provider.VoicemailContract.Voicemails; -import android.telecom.PhoneAccountHandle; -import com.android.voicemailomtp.Voicemail; -import java.util.ArrayList; -import java.util.List; - -/** - * Construct queries to interact with the voicemails table. - */ -public class VoicemailsQueryHelper { - final static String[] PROJECTION = new String[] { - Voicemails._ID, // 0 - Voicemails.SOURCE_DATA, // 1 - Voicemails.IS_READ, // 2 - Voicemails.DELETED, // 3 - Voicemails.TRANSCRIPTION // 4 - }; - - public static final int _ID = 0; - public static final int SOURCE_DATA = 1; - public static final int IS_READ = 2; - public static final int DELETED = 3; - public static final int TRANSCRIPTION = 4; - - final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND " - + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1"; - final static String DELETED_SELECTION = Voicemails.DELETED + "=1"; - - private Context mContext; - private ContentResolver mContentResolver; - private Uri mSourceUri; - - public VoicemailsQueryHelper(Context context) { - mContext = context; - mContentResolver = context.getContentResolver(); - mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName()); - } - - /** - * Get all the local read voicemails that have not been synced to the server. - * - * @return A list of read voicemails. - */ - public List<Voicemail> getReadVoicemails() { - return getLocalVoicemails(READ_SELECTION); - } - - /** - * Get all the locally deleted voicemails that have not been synced to the server. - * - * @return A list of deleted voicemails. - */ - public List<Voicemail> getDeletedVoicemails() { - return getLocalVoicemails(DELETED_SELECTION); - } - - /** - * Get all voicemails locally stored. - * - * @return A list of all locally stored voicemails. - */ - public List<Voicemail> getAllVoicemails() { - return getLocalVoicemails(null); - } - - /** - * Utility method to make queries to the voicemail database. - * - * @param selection A filter declaring which rows to return. {@code null} returns all rows. - * @return A list of voicemails according to the selection statement. - */ - private List<Voicemail> getLocalVoicemails(String selection) { - Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null); - if (cursor == null) { - return null; - } - try { - List<Voicemail> voicemails = new ArrayList<Voicemail>(); - while (cursor.moveToNext()) { - final long id = cursor.getLong(_ID); - final String sourceData = cursor.getString(SOURCE_DATA); - final boolean isRead = cursor.getInt(IS_READ) == 1; - final String transcription = cursor.getString(TRANSCRIPTION); - Voicemail voicemail = Voicemail - .createForUpdate(id, sourceData) - .setIsRead(isRead) - .setTranscription(transcription).build(); - voicemails.add(voicemail); - } - return voicemails; - } finally { - cursor.close(); - } - } - - /** - * Deletes a list of voicemails from the voicemail content provider. - * - * @param voicemails The list of voicemails to delete - * @return The number of voicemails deleted - */ - public int deleteFromDatabase(List<Voicemail> voicemails) { - int count = voicemails.size(); - if (count == 0) { - return 0; - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) { - if (i > 0) { - sb.append(","); - } - sb.append(voicemails.get(i).getId()); - } - - String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString()); - return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null); - } - - /** - * Utility method to delete a single voicemail. - */ - public void deleteFromDatabase(Voicemail voicemail) { - mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?", - new String[] { Long.toString(voicemail.getId()) }); - } - - public int markReadInDatabase(List<Voicemail> voicemails) { - int count = voicemails.size(); - for (int i = 0; i < count; i++) { - markReadInDatabase(voicemails.get(i)); - } - return count; - } - - /** - * Utility method to mark single message as read. - */ - public void markReadInDatabase(Voicemail voicemail) { - Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); - ContentValues contentValues = new ContentValues(); - contentValues.put(Voicemails.IS_READ, "1"); - mContentResolver.update(uri, contentValues, null, null); - } - - /** - * Sends an update command to the voicemail content provider for a list of voicemails. From the - * view of the provider, since the updater is the owner of the entry, a blank "update" means - * that the voicemail source is indicating that the server has up-to-date information on the - * voicemail. This flips the "dirty" bit to "0". - * - * @param voicemails The list of voicemails to update - * @return The number of voicemails updated - */ - public int markCleanInDatabase(List<Voicemail> voicemails) { - int count = voicemails.size(); - for (int i = 0; i < count; i++) { - markCleanInDatabase(voicemails.get(i)); - } - return count; - } - - /** - * Utility method to mark single message as clean. - */ - public void markCleanInDatabase(Voicemail voicemail) { - Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); - ContentValues contentValues = new ContentValues(); - mContentResolver.update(uri, contentValues, null, null); - } - - /** - * Utility method to add a transcription to the voicemail. - */ - public void updateWithTranscription(Voicemail voicemail, String transcription) { - Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); - ContentValues contentValues = new ContentValues(); - contentValues.put(Voicemails.TRANSCRIPTION, transcription); - mContentResolver.update(uri, contentValues, null, null); - } - - /** - * Voicemail is unique if the tuple of (phone account component name, phone account id, source - * data) is unique. If the phone account is missing, we also consider this unique since it's - * simply an "unknown" account. - * @param voicemail The voicemail to check if it is unique. - * @return {@code true} if the voicemail is unique, {@code false} otherwise. - */ - public boolean isVoicemailUnique(Voicemail voicemail) { - Cursor cursor = null; - PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount(); - if (phoneAccount != null) { - String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString(); - String phoneAccountId = phoneAccount.getId(); - String sourceData = voicemail.getSourceData(); - if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) { - return true; - } - try { - String whereClause = - Voicemails.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " + - Voicemails.PHONE_ACCOUNT_ID + "=? AND " + Voicemails.SOURCE_DATA + "=?"; - String[] whereArgs = { phoneAccountComponentName, phoneAccountId, sourceData }; - cursor = mContentResolver.query( - mSourceUri, PROJECTION, whereClause, whereArgs, null); - if (cursor.getCount() == 0) { - return true; - } else { - return false; - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - return true; - } -} diff --git a/java/com/android/voicemailomtp/sync/VvmNetworkRequest.java b/java/com/android/voicemailomtp/sync/VvmNetworkRequest.java deleted file mode 100644 index 966b940c2..000000000 --- a/java/com/android/voicemailomtp/sync/VvmNetworkRequest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.sync; - -import android.annotation.TargetApi; -import android.net.Network; -import android.os.Build.VERSION_CODES; -import android.support.annotation.NonNull; -import android.telecom.PhoneAccountHandle; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; -import java.io.Closeable; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -/** - * Class to retrieve a {@link Network} synchronously. {@link #getNetwork(OmtpVvmCarrierConfigHelper, - * PhoneAccountHandle)} will block until a suitable network is retrieved or it has failed. - */ -@SuppressWarnings("AndroidApiChecker") /* CompletableFuture is java8*/ -@TargetApi(VERSION_CODES.CUR_DEVELOPMENT) -public class VvmNetworkRequest { - - private static final String TAG = "VvmNetworkRequest"; - - /** - * A wrapper around a Network returned by a {@link VvmNetworkRequestCallback}, which should be - * closed once not needed anymore. - */ - public static class NetworkWrapper implements Closeable { - - private final Network mNetwork; - private final VvmNetworkRequestCallback mCallback; - - private NetworkWrapper(Network network, VvmNetworkRequestCallback callback) { - mNetwork = network; - mCallback = callback; - } - - public Network get() { - return mNetwork; - } - - @Override - public void close() { - mCallback.releaseNetwork(); - } - } - - public static class RequestFailedException extends Exception { - - private RequestFailedException(Throwable cause) { - super(cause); - } - } - - @NonNull - public static NetworkWrapper getNetwork(OmtpVvmCarrierConfigHelper config, - PhoneAccountHandle handle, VoicemailStatus.Editor status) throws RequestFailedException { - FutureNetworkRequestCallback callback = new FutureNetworkRequestCallback(config, handle, - status); - callback.requestNetwork(); - try { - return callback.getFuture().get(); - } catch (InterruptedException | ExecutionException e) { - callback.releaseNetwork(); - VvmLog.e(TAG, "can't get future network", e); - throw new RequestFailedException(e); - } - } - - private static class FutureNetworkRequestCallback extends VvmNetworkRequestCallback { - - /** - * {@link CompletableFuture#get()} will block until {@link CompletableFuture# - * complete(Object) } has been called on the other thread. - */ - private final CompletableFuture<NetworkWrapper> mFuture = new CompletableFuture<>(); - - public FutureNetworkRequestCallback(OmtpVvmCarrierConfigHelper config, - PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status) { - super(config, phoneAccount, status); - } - - public Future<NetworkWrapper> getFuture() { - return mFuture; - } - - @Override - public void onAvailable(Network network) { - super.onAvailable(network); - mFuture.complete(new NetworkWrapper(network, this)); - } - - @Override - public void onFailed(String reason) { - super.onFailed(reason); - mFuture.complete(null); - } - - } -} diff --git a/java/com/android/voicemailomtp/sync/VvmNetworkRequestCallback.java b/java/com/android/voicemailomtp/sync/VvmNetworkRequestCallback.java deleted file mode 100644 index 8481a9d16..000000000 --- a/java/com/android/voicemailomtp/sync/VvmNetworkRequestCallback.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ -package com.android.voicemailomtp.sync; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.CallSuper; -import android.telecom.PhoneAccountHandle; - -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.TelephonyManagerStub; -import com.android.voicemailomtp.VoicemailStatus; -import com.android.voicemailomtp.VvmLog; - -/** - * Base class for network request call backs for visual voicemail syncing with the Imap server. This - * handles retries and network requests. - */ -public abstract class VvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback { - - private static final String TAG = "VvmNetworkRequest"; - - // Timeout used to call ConnectivityManager.requestNetwork - private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000; - - public static final String NETWORK_REQUEST_FAILED_TIMEOUT = "timeout"; - public static final String NETWORK_REQUEST_FAILED_LOST = "lost"; - - protected Context mContext; - protected PhoneAccountHandle mPhoneAccount; - protected NetworkRequest mNetworkRequest; - private ConnectivityManager mConnectivityManager; - private final OmtpVvmCarrierConfigHelper mCarrierConfigHelper; - private final VoicemailStatus.Editor mStatus; - private boolean mRequestSent = false; - private boolean mResultReceived = false; - - public VvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount, - VoicemailStatus.Editor status) { - mContext = context; - mPhoneAccount = phoneAccount; - mStatus = status; - mCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(context, mPhoneAccount); - mNetworkRequest = createNetworkRequest(); - } - - public VvmNetworkRequestCallback(OmtpVvmCarrierConfigHelper config, - PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status) { - mContext = config.getContext(); - mPhoneAccount = phoneAccount; - mStatus = status; - mCarrierConfigHelper = config; - mNetworkRequest = createNetworkRequest(); - } - - public VoicemailStatus.Editor getVoicemailStatusEditor() { - return mStatus; - } - - /** - * @return NetworkRequest for a proper transport type. Use only cellular network if the carrier - * requires it. Otherwise use whatever available. - */ - private NetworkRequest createNetworkRequest() { - - NetworkRequest.Builder builder = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - - if (mCarrierConfigHelper.isCellularDataRequired()) { - VvmLog.d(TAG, "Transport type: CELLULAR"); - builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(TelephonyManagerStub - .getNetworkSpecifierForPhoneAccountHandle(mContext, mPhoneAccount)); - } else { - VvmLog.d(TAG, "Transport type: ANY"); - } - return builder.build(); - } - - public NetworkRequest getNetworkRequest() { - return mNetworkRequest; - } - - @Override - @CallSuper - public void onLost(Network network) { - VvmLog.d(TAG, "onLost"); - mResultReceived = true; - onFailed(NETWORK_REQUEST_FAILED_LOST); - } - - @Override - @CallSuper - public void onAvailable(Network network) { - super.onAvailable(network); - mResultReceived = true; - } - - @CallSuper - public void onUnavailable() { - // TODO: b/32637799 this is hidden, do we really need this? - mResultReceived = true; - onFailed(NETWORK_REQUEST_FAILED_TIMEOUT); - } - - public void requestNetwork() { - if (mRequestSent == true) { - VvmLog.e(TAG, "requestNetwork() called twice"); - return; - } - mRequestSent = true; - getConnectivityManager().requestNetwork(getNetworkRequest(), this); - /** - * Somehow requestNetwork() with timeout doesn't work, and it's a hidden method. - * Implement our own timeout mechanism instead. - */ - Handler handler = new Handler(Looper.getMainLooper()); - handler.postDelayed(new Runnable() { - @Override - public void run() { - if (mResultReceived == false) { - onFailed(NETWORK_REQUEST_FAILED_TIMEOUT); - } - } - }, NETWORK_REQUEST_TIMEOUT_MILLIS); - } - - public void releaseNetwork() { - VvmLog.d(TAG, "releaseNetwork"); - getConnectivityManager().unregisterNetworkCallback(this); - } - - public ConnectivityManager getConnectivityManager() { - if (mConnectivityManager == null) { - mConnectivityManager = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - } - return mConnectivityManager; - } - - @CallSuper - public void onFailed(String reason) { - VvmLog.d(TAG, "onFailed: " + reason); - if (mCarrierConfigHelper.isCellularDataRequired()) { - mCarrierConfigHelper - .handleEvent(mStatus, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED); - } else { - mCarrierConfigHelper.handleEvent(mStatus, OmtpEvents.DATA_NO_CONNECTION); - } - releaseNetwork(); - } -} diff --git a/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java b/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java deleted file mode 100644 index eda7c4ee3..000000000 --- a/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.utils; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.Arrays; - -/** - * Lightweight wrapper around {@link PrintWriter} that automatically indents newlines based on - * internal state. It also automatically wraps long lines based on given line length. <p> Delays - * writing indent until first actual write on a newline, enabling indent modification after - * newline. - */ -public class IndentingPrintWriter extends PrintWriter { - - private final String mSingleIndent; - private final int mWrapLength; - - /** - * Mutable version of current indent - */ - private StringBuilder mIndentBuilder = new StringBuilder(); - /** - * Cache of current {@link #mIndentBuilder} value - */ - private char[] mCurrentIndent; - /** - * Length of current line being built, excluding any indent - */ - private int mCurrentLength; - - /** - * Flag indicating if we're currently sitting on an empty line, and that next write should be - * prefixed with the current indent. - */ - private boolean mEmptyLine = true; - - private char[] mSingleChar = new char[1]; - - public IndentingPrintWriter(Writer writer, String singleIndent) { - this(writer, singleIndent, -1); - } - - public IndentingPrintWriter(Writer writer, String singleIndent, int wrapLength) { - super(writer); - mSingleIndent = singleIndent; - mWrapLength = wrapLength; - } - - public void increaseIndent() { - mIndentBuilder.append(mSingleIndent); - mCurrentIndent = null; - } - - public void decreaseIndent() { - mIndentBuilder.delete(0, mSingleIndent.length()); - mCurrentIndent = null; - } - - public void printPair(String key, Object value) { - print(key + "=" + String.valueOf(value) + " "); - } - - public void printPair(String key, Object[] value) { - print(key + "=" + Arrays.toString(value) + " "); - } - - public void printHexPair(String key, int value) { - print(key + "=0x" + Integer.toHexString(value) + " "); - } - - @Override - public void println() { - write('\n'); - } - - @Override - public void write(int c) { - mSingleChar[0] = (char) c; - write(mSingleChar, 0, 1); - } - - @Override - public void write(String s, int off, int len) { - final char[] buf = new char[len]; - s.getChars(off, len - off, buf, 0); - write(buf, 0, len); - } - - @Override - public void write(char[] buf, int offset, int count) { - final int indentLength = mIndentBuilder.length(); - final int bufferEnd = offset + count; - int lineStart = offset; - int lineEnd = offset; - - // March through incoming buffer looking for newlines - while (lineEnd < bufferEnd) { - char ch = buf[lineEnd++]; - mCurrentLength++; - if (ch == '\n') { - maybeWriteIndent(); - super.write(buf, lineStart, lineEnd - lineStart); - lineStart = lineEnd; - mEmptyLine = true; - mCurrentLength = 0; - } - - // Wrap if we've pushed beyond line length - if (mWrapLength > 0 && mCurrentLength >= mWrapLength - indentLength) { - if (!mEmptyLine) { - // Give ourselves a fresh line to work with - super.write('\n'); - mEmptyLine = true; - mCurrentLength = lineEnd - lineStart; - } else { - // We need more than a dedicated line, slice it hard - maybeWriteIndent(); - super.write(buf, lineStart, lineEnd - lineStart); - super.write('\n'); - mEmptyLine = true; - lineStart = lineEnd; - mCurrentLength = 0; - } - } - } - - if (lineStart != lineEnd) { - maybeWriteIndent(); - super.write(buf, lineStart, lineEnd - lineStart); - } - } - - private void maybeWriteIndent() { - if (mEmptyLine) { - mEmptyLine = false; - if (mIndentBuilder.length() != 0) { - if (mCurrentIndent == null) { - mCurrentIndent = mIndentBuilder.toString().toCharArray(); - } - super.write(mCurrentIndent, 0, mCurrentIndent.length); - } - } - } -}
\ No newline at end of file diff --git a/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java b/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java deleted file mode 100644 index f94070ecd..000000000 --- a/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.utils; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.net.Uri; -import android.provider.VoicemailContract.Voicemails; -import android.telecom.PhoneAccountHandle; -import com.android.voicemailomtp.Voicemail; -import java.util.List; - -public class VoicemailDatabaseUtil { - - /** - * Inserts a new voicemail into the voicemail content provider. - * - * @param context The context of the app doing the inserting - * @param voicemail Data to be inserted - * @return {@link Uri} of the newly inserted {@link Voicemail} - * @hide - */ - public static Uri insert(Context context, Voicemail voicemail) { - ContentResolver contentResolver = context.getContentResolver(); - ContentValues contentValues = getContentValues(voicemail); - return contentResolver - .insert(Voicemails.buildSourceUri(context.getPackageName()), contentValues); - } - - /** - * Inserts a list of voicemails into the voicemail content provider. - * - * @param context The context of the app doing the inserting - * @param voicemails Data to be inserted - * @return the number of voicemails inserted - * @hide - */ - public static int insert(Context context, List<Voicemail> voicemails) { - ContentResolver contentResolver = context.getContentResolver(); - int count = voicemails.size(); - for (int i = 0; i < count; i++) { - ContentValues contentValues = getContentValues(voicemails.get(i)); - contentResolver - .insert(Voicemails.buildSourceUri(context.getPackageName()), contentValues); - } - return count; - } - - - /** - * Maps structured {@link Voicemail} to {@link ContentValues} in content provider. - */ - private static ContentValues getContentValues(Voicemail voicemail) { - ContentValues contentValues = new ContentValues(); - contentValues.put(Voicemails.DATE, String.valueOf(voicemail.getTimestampMillis())); - contentValues.put(Voicemails.NUMBER, voicemail.getNumber()); - contentValues.put(Voicemails.DURATION, String.valueOf(voicemail.getDuration())); - contentValues.put(Voicemails.SOURCE_PACKAGE, voicemail.getSourcePackage()); - contentValues.put(Voicemails.SOURCE_DATA, voicemail.getSourceData()); - contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0); - - PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount(); - if (phoneAccount != null) { - contentValues.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, - phoneAccount.getComponentName().flattenToString()); - contentValues.put(Voicemails.PHONE_ACCOUNT_ID, phoneAccount.getId()); - } - - if (voicemail.getTranscription() != null) { - contentValues.put(Voicemails.TRANSCRIPTION, voicemail.getTranscription()); - } - - return contentValues; - } -} diff --git a/java/com/android/voicemailomtp/utils/VvmDumpHandler.java b/java/com/android/voicemailomtp/utils/VvmDumpHandler.java deleted file mode 100644 index 5768a9c19..000000000 --- a/java/com/android/voicemailomtp/utils/VvmDumpHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.voicemailomtp.utils; - -import android.content.Context; -import android.telecom.PhoneAccountHandle; -import android.telecom.TelecomManager; - -import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper; -import com.android.voicemailomtp.VvmLog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -public class VvmDumpHandler { - - public static void dump(Context context, FileDescriptor fd, PrintWriter writer, - String[] args) { - IndentingPrintWriter indentedWriter = new IndentingPrintWriter(writer, " "); - indentedWriter.println("******* OmtpVvm *******"); - indentedWriter.println("======= Configs ======="); - indentedWriter.increaseIndent(); - for (PhoneAccountHandle handle : context.getSystemService(TelecomManager.class) - .getCallCapablePhoneAccounts()) { - OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, handle); - indentedWriter.println(config.toString()); - } - indentedWriter.decreaseIndent(); - indentedWriter.println("======== Logs ========="); - VvmLog.dump(fd, indentedWriter, args); - } -} diff --git a/java/com/android/voicemailomtp/utils/XmlUtils.java b/java/com/android/voicemailomtp/utils/XmlUtils.java deleted file mode 100644 index 768247e27..000000000 --- a/java/com/android/voicemailomtp/utils/XmlUtils.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.voicemailomtp.utils; - -import android.util.ArrayMap; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class XmlUtils { - - public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag, - String[] name, ReadMapCallback callback) - throws XmlPullParserException, java.io.IOException { - ArrayMap<String, Object> map = new ArrayMap<>(); - - int eventType = parser.getEventType(); - do { - if (eventType == XmlPullParser.START_TAG) { - Object val = readThisValueXml(parser, name, callback, true); - map.put(name[0], val); - } else if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals(endTag)) { - return map; - } - throw new XmlPullParserException( - "Expected " + endTag + " end tag at: " + parser.getName()); - } - eventType = parser.next(); - } while (eventType != XmlPullParser.END_DOCUMENT); - - throw new XmlPullParserException( - "Document ended before " + endTag + " end tag"); - } - - /** - * Read an ArrayList object from an XmlPullParser. The XML data could previously have been - * generated by writeListXml(). The XmlPullParser must be positioned <em>after</em> the tag - * that begins the list. - * - * @param parser The XmlPullParser from which to read the list data. - * @param endTag Name of the tag that will end the list, usually "list". - * @param name An array of one string, used to return the name attribute of the list's tag. - * @return HashMap The newly generated list. - */ - public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, - String[] name, ReadMapCallback callback, boolean arrayMap) - throws XmlPullParserException, java.io.IOException { - ArrayList list = new ArrayList(); - - int eventType = parser.getEventType(); - do { - if (eventType == XmlPullParser.START_TAG) { - Object val = readThisValueXml(parser, name, callback, arrayMap); - list.add(val); - } else if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals(endTag)) { - return list; - } - throw new XmlPullParserException( - "Expected " + endTag + " end tag at: " + parser.getName()); - } - eventType = parser.next(); - } while (eventType != XmlPullParser.END_DOCUMENT); - - throw new XmlPullParserException( - "Document ended before " + endTag + " end tag"); - } - - /** - * Read a String[] object from an XmlPullParser. The XML data could previously have been - * generated by writeStringArrayXml(). The XmlPullParser must be positioned <em>after</em> the - * tag that begins the list. - * - * @param parser The XmlPullParser from which to read the list data. - * @param endTag Name of the tag that will end the list, usually "string-array". - * @param name An array of one string, used to return the name attribute of the list's tag. - * @return Returns a newly generated String[]. - */ - public static String[] readThisStringArrayXml(XmlPullParser parser, String endTag, - String[] name) throws XmlPullParserException, java.io.IOException { - - parser.next(); - - List<String> array = new ArrayList<>(); - - int eventType = parser.getEventType(); - do { - if (eventType == XmlPullParser.START_TAG) { - if (parser.getName().equals("item")) { - try { - array.add(parser.getAttributeValue(null, "value")); - } catch (NullPointerException e) { - throw new XmlPullParserException("Need value attribute in item"); - } catch (NumberFormatException e) { - throw new XmlPullParserException("Not a number in value attribute in item"); - } - } else { - throw new XmlPullParserException("Expected item tag at: " + parser.getName()); - } - } else if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals(endTag)) { - return array.toArray(new String[0]); - } else if (parser.getName().equals("item")) { - - } else { - throw new XmlPullParserException("Expected " + endTag + " end tag at: " + - parser.getName()); - } - } - eventType = parser.next(); - } while (eventType != XmlPullParser.END_DOCUMENT); - - throw new XmlPullParserException("Document ended before " + endTag + " end tag"); - } - - private static Object readThisValueXml(XmlPullParser parser, String[] name, - ReadMapCallback callback, boolean arrayMap) - throws XmlPullParserException, java.io.IOException { - final String valueName = parser.getAttributeValue(null, "name"); - final String tagName = parser.getName(); - - Object res; - - if (tagName.equals("null")) { - res = null; - } else if (tagName.equals("string")) { - String value = ""; - int eventType; - while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals("string")) { - name[0] = valueName; - return value; - } - throw new XmlPullParserException( - "Unexpected end tag in <string>: " + parser.getName()); - } else if (eventType == XmlPullParser.TEXT) { - value += parser.getText(); - } else if (eventType == XmlPullParser.START_TAG) { - throw new XmlPullParserException( - "Unexpected start tag in <string>: " + parser.getName()); - } - } - throw new XmlPullParserException( - "Unexpected end of document in <string>"); - } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { - // all work already done by readThisPrimitiveValueXml - } else if (tagName.equals("string-array")) { - res = readThisStringArrayXml(parser, "string-array", name); - name[0] = valueName; - return res; - } else if (tagName.equals("list")) { - parser.next(); - res = readThisListXml(parser, "list", name, callback, arrayMap); - name[0] = valueName; - return res; - } else if (callback != null) { - res = callback.readThisUnknownObjectXml(parser, tagName); - name[0] = valueName; - return res; - } else { - throw new XmlPullParserException("Unknown tag: " + tagName); - } - - // Skip through to end tag. - int eventType; - while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals(tagName)) { - name[0] = valueName; - return res; - } - throw new XmlPullParserException( - "Unexpected end tag in <" + tagName + ">: " + parser.getName()); - } else if (eventType == XmlPullParser.TEXT) { - throw new XmlPullParserException( - "Unexpected text in <" + tagName + ">: " + parser.getName()); - } else if (eventType == XmlPullParser.START_TAG) { - throw new XmlPullParserException( - "Unexpected start tag in <" + tagName + ">: " + parser.getName()); - } - } - throw new XmlPullParserException( - "Unexpected end of document in <" + tagName + ">"); - } - - private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName) - throws XmlPullParserException, java.io.IOException { - try { - if (tagName.equals("int")) { - return Integer.parseInt(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("long")) { - return Long.valueOf(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("float")) { - return Float.valueOf(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("double")) { - return Double.valueOf(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("boolean")) { - return Boolean.valueOf(parser.getAttributeValue(null, "value")); - } else { - return null; - } - } catch (NullPointerException e) { - throw new XmlPullParserException("Need value attribute in <" + tagName + ">"); - } catch (NumberFormatException e) { - throw new XmlPullParserException( - "Not a number in value attribute in <" + tagName + ">"); - } - } - - public interface ReadMapCallback { - - /** - * Called from readThisMapXml when a START_TAG is not recognized. The input stream is - * positioned within the start tag so that attributes can be read using in.getAttribute. - * - * @param in the XML input stream - * @param tag the START_TAG that was not recognized. - * @return the Object parsed from the stream which will be put into the map. - * @throws XmlPullParserException if the START_TAG is not recognized. - * @throws IOException on XmlPullParser serialization errors. - */ - Object readThisUnknownObjectXml(XmlPullParser in, String tag) - throws XmlPullParserException, IOException; - } -}
\ No newline at end of file |