diff options
359 files changed, 39824 insertions, 8391 deletions
diff --git a/Android.mk b/Android.mk index 54ad4844f..9686cb351 100644 --- a/Android.mk +++ b/Android.mk @@ -14,7 +14,7 @@ LOCAL_PATH := $(call my-dir) -# Build the Email application itself, along with its tests and tests for the emailcommon +# Build the Email application itself, along with its tests and the tests for the emailcommon # static library. All tests can be run via runtest email include $(CLEAR_VARS) @@ -22,21 +22,13 @@ include $(CLEAR_VARS) chips_dir := ../../../frameworks/ex/chips/res mail_common_dir := ../../../frameworks/opt/mailcommon/res res_dir := $(chips_dir) $(mail_common_dir) res -unified_email_src_dir := ../UnifiedEmail/src - -imported_unified_email_files := \ - $(unified_email_src_dir)/com/android/mail/providers/UIProviderValidator.java \ - $(unified_email_src_dir)/com/android/mail/providers/UIProvider.java \ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/email) LOCAL_SRC_FILES += $(call all-java-files-under, src/com/beetstra) -LOCAL_SRC_FILES += $(imported_unified_email_files) - LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dir)) LOCAL_AAPT_FLAGS := --auto-add-overlay -LOCAL_AAPT_FLAGS += --extra-packages com.android.ex.chips LOCAL_STATIC_JAVA_LIBRARIES := android-common com.android.emailcommon guava android-common-chips diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 470d8a8e5..8a449c3a8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -75,10 +75,9 @@ android:name="android.permission.USE_CREDENTIALS"/> <!-- Grant permission to system apps to access provider (see provider below) --> - <!-- STOPSHIP: Temporarily set protection level to "dangerous" (from "signature") --> <permission android:name="com.android.email.permission.ACCESS_PROVIDER" - android:protectionLevel="dangerous" + android:protectionLevel="signature" android:label="@string/permission_access_provider_label" android:description="@string/permission_access_provider_desc"/> <uses-permission @@ -176,7 +175,7 @@ <data android:scheme="content" android:host="ui.email.android.com" - android:pathPrefix="/settings" + android:path="/settings" /> </intent-filter> <intent-filter> @@ -227,6 +226,7 @@ <activity android:name=".activity.MessageCompose" android:label="@string/compose_title" + android:enabled="false" android:theme="@android:style/Theme.Holo.Light" > <intent-filter> @@ -263,16 +263,6 @@ <action android:name="com.android.email.intent.action.REPLY" /> </intent-filter> - <intent-filter> - <action android:name="android.intent.action.SEND" /> - <category - android:name="android.intent.category.DEFAULT" /> - <data - android:scheme="content" - android:host="ui.email.android.com" - android:pathPrefix="/compose" - /> - </intent-filter> </activity> <!-- Only used to support pre-HC shortcuts --> @@ -404,28 +394,6 @@ </intent-filter> </service> - <service - android:name=".service.ImapService" - android:enabled="true" - android:permission="com.android.email.permission.ACCESS_PROVIDER" - > - <intent-filter> - <action - android:name="com.android.email.IMAP_INTENT" /> - </intent-filter> - </service> - - <service - android:name=".service.Pop3Service" - android:enabled="true" - android:permission="com.android.email.permission.ACCESS_PROVIDER" - > - <intent-filter> - <action - android:name="com.android.email.POP3_INTENT" /> - </intent-filter> - </service> - <!--Required stanza to register the EasAuthenticatorService with AccountManager --> <service android:name=".service.EasAuthenticatorService" @@ -496,7 +464,7 @@ <!-- Email AppWidget definitions --> <activity android:name=".widget.WidgetConfiguration" - android:enabled="true" + android:enabled="false" android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge" > <intent-filter @@ -515,7 +483,8 @@ <receiver android:name=".provider.WidgetProvider" > <intent-filter> - <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> + <action + android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <intent-filter> <action android:name="com.android.email.MESSAGE_LIST_DATASET_CHANGED" /> diff --git a/emailcommon/Android.mk b/emailcommon/Android.mk index 18fdc801d..e3211a56a 100644 --- a/emailcommon/Android.mk +++ b/emailcommon/Android.mk @@ -20,24 +20,15 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -unified_email_src_dir := ../../UnifiedEmail/src -apache_src_dir := ../../UnifiedEmail/src/org - -imported_unified_email_files := \ - $(unified_email_src_dir)/com/android/mail/utils/LogUtils.java \ - $(unified_email_src_dir)/com/android/mail/utils/LoggingInputStream.java \ - $(unified_email_src_dir)/com/android/mail/providers/UIProvider.java - LOCAL_MODULE := com.android.emailcommon -LOCAL_STATIC_JAVA_LIBRARIES := guava android-common +LOCAL_STATIC_JAVA_LIBRARIES := guava LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/emailcommon) +LOCAL_SRC_FILES += $(call all-java-files-under, src/org) LOCAL_SRC_FILES += \ src/com/android/emailcommon/service/IEmailService.aidl \ src/com/android/emailcommon/service/IEmailServiceCallback.aidl \ src/com/android/emailcommon/service/IPolicyService.aidl \ src/com/android/emailcommon/service/IAccountService.aidl -LOCAL_SRC_FILES += $(call all-java-files-under, $(apache_src_dir)) -LOCAL_SRC_FILES += $(imported_unified_email_files) LOCAL_SDK_VERSION := current diff --git a/emailcommon/src/com/android/emailcommon/mail/Address.java b/emailcommon/src/com/android/emailcommon/mail/Address.java index 5245c5691..a2807c916 100644 --- a/emailcommon/src/com/android/emailcommon/mail/Address.java +++ b/emailcommon/src/com/android/emailcommon/mail/Address.java @@ -16,16 +16,16 @@ package com.android.emailcommon.mail; -import android.text.TextUtils; -import android.text.util.Rfc822Token; -import android.text.util.Rfc822Tokenizer; - import com.android.emailcommon.utility.Utility; import com.google.common.annotations.VisibleForTesting; import org.apache.james.mime4j.codec.EncoderUtil; import org.apache.james.mime4j.decoder.DecoderUtil; +import android.text.TextUtils; +import android.text.util.Rfc822Token; +import android.text.util.Rfc822Tokenizer; + import java.util.ArrayList; import java.util.regex.Pattern; @@ -192,10 +192,6 @@ public class Address { return super.equals(o); } - public int hashCode() { - return getAddress().hashCode(); - } - /** * Get human readable address string. * Do not use this for email header. @@ -356,21 +352,14 @@ public class Address { } /** - * Unpacks an address list that is either CSV of RFC822 addresses OR (for backward - * compatibility) previously packed with pack() - * @param addressList string packed with pack() or CSV of RFC822 addresses + * Unpacks an address list previously packed with pack() + * @param addressList String with packed addresses as returned by pack() * @return array of addresses resulting from unpack */ public static Address[] unpack(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-compatibile unpack ArrayList<Address> addresses = new ArrayList<Address>(); int length = addressList.length(); int pairStartIndex = 0; @@ -406,11 +395,45 @@ public class Address { } /** - * Generate a String containing RFC822 addresses separated by commas - * NOTE: We used to "pack" these addresses in an app-specific format, but no longer do so + * Packs an address list into a String that is very quick to read + * and parse. Packed lists can be unpacked with unpack(). + * The format is a series of packed addresses separated by LIST_DELIMITER_EMAIL. + * Each address is packed as + * a pair of address and personal separated by LIST_DELIMITER_PERSONAL, + * where the personal and delimiter are optional. + * E.g. "foo@x.com\1joe@x.com\2Joe Doe" + * @param addresses Array of addresses + * @return a string containing the packed addresses. */ public static String pack(Address[] addresses) { - return Address.toHeader(addresses); + // TODO: return same value for both null & empty list + if (addresses == null) { + return null; + } + final int nAddr = addresses.length; + if (nAddr == 0) { + return ""; + } + + // shortcut: one email with no displayName + if (nAddr == 1 && addresses[0].getPersonal() == null) { + return addresses[0].getAddress(); + } + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < nAddr; i++) { + if (i != 0) { + sb.append(LIST_DELIMITER_EMAIL); + } + final Address address = addresses[i]; + sb.append(address.getAddress()); + final String displayName = address.getPersonal(); + if (displayName != null) { + sb.append(LIST_DELIMITER_PERSONAL); + sb.append(displayName); + } + } + return sb.toString(); } /** diff --git a/emailcommon/src/com/android/emailcommon/provider/Account.java b/emailcommon/src/com/android/emailcommon/provider/Account.java index 3914176ed..94d858b31 100755..100644 --- a/emailcommon/src/com/android/emailcommon/provider/Account.java +++ b/emailcommon/src/com/android/emailcommon/provider/Account.java @@ -127,6 +127,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce public String mSecuritySyncKey; public String mSignature; public long mPolicyKey; + public long mNotifiedMessageId; + public int mNotifiedMessageCount; // Convenience for creating/working with an account public transient HostAuth mHostAuthRecv; @@ -153,6 +155,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce public static final int CONTENT_SECURITY_SYNC_KEY_COLUMN = 15; public static final int CONTENT_SIGNATURE_COLUMN = 16; public static final int CONTENT_POLICY_KEY = 17; + public static final int CONTENT_NOTIFIED_MESSAGE_ID = 18; + public static final int CONTENT_NOTIFIED_MESSAGE_COUNT = 19; public static final String[] CONTENT_PROJECTION = new String[] { RECORD_ID, AccountColumns.DISPLAY_NAME, @@ -162,7 +166,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce AccountColumns.COMPATIBILITY_UUID, AccountColumns.SENDER_NAME, AccountColumns.RINGTONE_URI, AccountColumns.PROTOCOL_VERSION, AccountColumns.NEW_MESSAGE_COUNT, AccountColumns.SECURITY_SYNC_KEY, - AccountColumns.SIGNATURE, AccountColumns.POLICY_KEY + AccountColumns.SIGNATURE, AccountColumns.POLICY_KEY, + AccountColumns.NOTIFIED_MESSAGE_ID, AccountColumns.NOTIFIED_MESSAGE_COUNT }; public static final int CONTENT_MAILBOX_TYPE_COLUMN = 1; @@ -267,6 +272,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce mSecuritySyncKey = cursor.getString(CONTENT_SECURITY_SYNC_KEY_COLUMN); mSignature = cursor.getString(CONTENT_SIGNATURE_COLUMN); mPolicyKey = cursor.getLong(CONTENT_POLICY_KEY); + mNotifiedMessageId = cursor.getLong(CONTENT_NOTIFIED_MESSAGE_ID); + mNotifiedMessageCount = cursor.getInt(CONTENT_NOTIFIED_MESSAGE_COUNT); } private long getId(Uri u) { @@ -710,6 +717,10 @@ public final class Account extends EmailContent implements AccountColumns, Parce */ @Override public int update(Context context, ContentValues cv) { + if (mPolicy != null && mPolicyKey <= 0) { + // If a policy is set and there's no policy, link it to the account + Policy.setAccountPolicy(context, this, mPolicy, null); + } if (cv.containsKey(AccountColumns.IS_DEFAULT) && cv.getAsBoolean(AccountColumns.IS_DEFAULT)) { ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); @@ -755,6 +766,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce int index = 0; int recvIndex = -1; int sendIndex = -1; + int policyIndex = -1; // Create operations for saving the send and recv hostAuths // Also, remember which operation in the array they represent @@ -771,6 +783,12 @@ public final class Account extends EmailContent implements AccountColumns, Parce .withValues(mHostAuthSend.toContentValues()) .build()); } + if (mPolicy != null) { + policyIndex = index++; + ops.add(ContentProviderOperation.newInsert(mPolicy.mBaseUri) + .withValues(mPolicy.toContentValues()) + .build()); + } // Create operations for making this the only default account // Note, these are always updates because they change existing accounts @@ -783,7 +801,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce // Now do the Account ContentValues cv = null; - if (recvIndex >= 0 || sendIndex >= 0) { + if (recvIndex >= 0 || sendIndex >= 0 || policyIndex >= 0) { cv = new ContentValues(); if (recvIndex >= 0) { cv.put(Account.HOST_AUTH_KEY_RECV, recvIndex); @@ -791,6 +809,9 @@ public final class Account extends EmailContent implements AccountColumns, Parce if (sendIndex >= 0) { cv.put(Account.HOST_AUTH_KEY_SEND, sendIndex); } + if (policyIndex >= 0) { + cv.put(Account.POLICY_KEY, policyIndex); + } } ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(mBaseUri); @@ -814,6 +835,11 @@ public final class Account extends EmailContent implements AccountColumns, Parce mHostAuthKeySend = newId; mHostAuthSend.mId = newId; } + if (policyIndex >= 0) { + long newId = getId(results[policyIndex].uri); + mPolicyKey = newId; + mPolicy.mId = newId; + } Uri u = results[index].uri; mId = getId(u); return u; @@ -845,6 +871,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce values.put(AccountColumns.SECURITY_SYNC_KEY, mSecuritySyncKey); values.put(AccountColumns.SIGNATURE, mSignature); values.put(AccountColumns.POLICY_KEY, mPolicyKey); + values.put(AccountColumns.NOTIFIED_MESSAGE_ID, mNotifiedMessageId); + values.put(AccountColumns.NOTIFIED_MESSAGE_COUNT, mNotifiedMessageCount); return values; } @@ -896,6 +924,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce dest.writeString(mSecuritySyncKey); dest.writeString(mSignature); dest.writeLong(mPolicyKey); + dest.writeLong(mNotifiedMessageId); + dest.writeInt(mNotifiedMessageCount); if (mHostAuthRecv != null) { dest.writeByte((byte)1); @@ -935,6 +965,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce mSecuritySyncKey = in.readString(); mSignature = in.readString(); mPolicyKey = in.readLong(); + mNotifiedMessageId = in.readLong(); + mNotifiedMessageCount = in.readInt(); mHostAuthRecv = null; if (in.readByte() == 1) { @@ -965,4 +997,5 @@ public final class Account extends EmailContent implements AccountColumns, Parce sb.append(']'); return sb.toString(); } + }
\ No newline at end of file diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java index eb229be2c..45876731b 100755..100644 --- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java +++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java @@ -32,7 +32,6 @@ import android.os.RemoteException; import com.android.emailcommon.utility.TextUtilities; import com.android.emailcommon.utility.Utility; -import com.android.mail.providers.UIProvider; import com.google.common.annotations.VisibleForTesting; import java.io.File; @@ -71,17 +70,6 @@ public abstract class EmailContent { public static final Uri CONTENT_NOTIFIER_URI = Uri.parse("content://" + NOTIFIER_AUTHORITY); - public static final Uri MAILBOX_NOTIFICATION_URI = - Uri.parse("content://" + EmailContent.AUTHORITY + "/mailboxNotification"); - public static final String[] NOTIFICATION_PROJECTION = - new String[] {MailboxColumns.ID, MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT}; - public static final int NOTIFICATION_MAILBOX_ID_COLUMN = 0; - public static final int NOTIFICATION_MAILBOX_UNREAD_COUNT_COLUMN = 1; - public static final int NOTIFICATION_MAILBOX_MESSAGE_COUNT_COLUMN = 2; - - public static final Uri MAILBOX_MOST_RECENT_MESSAGE_URI = - Uri.parse("content://" + EmailContent.AUTHORITY + "/mailboxMostRecentMessage"); - public static final String PROVIDER_PERMISSION = "com.android.email.permission.ACCESS_PROVIDER"; // All classes share this @@ -104,19 +92,6 @@ public abstract class EmailContent { public static final String ADD_COLUMN_NAME = "add"; public static final String SET_COLUMN_NAME = "set"; - public static final int SYNC_STATUS_NONE = UIProvider.SyncStatus.NO_SYNC; - public static final int SYNC_STATUS_USER = UIProvider.SyncStatus.USER_REFRESH; - public static final int SYNC_STATUS_BACKGROUND = UIProvider.SyncStatus.BACKGROUND_SYNC; - - public static final int LAST_SYNC_RESULT_SUCCESS = UIProvider.LastSyncResult.SUCCESS; - public static final int LAST_SYNC_RESULT_AUTH_ERROR = UIProvider.LastSyncResult.AUTH_ERROR; - public static final int LAST_SYNC_RESULT_SECURITY_ERROR = - UIProvider.LastSyncResult.SECURITY_ERROR; - public static final int LAST_SYNC_RESULT_CONNECTION_ERROR = - UIProvider.LastSyncResult.CONNECTION_ERROR; - public static final int LAST_SYNC_RESULT_INTERNAL_ERROR = - UIProvider.LastSyncResult.INTERNAL_ERROR; - // Newly created objects get this id public static final int NOT_SAVED = -1; // The base Uri that this piece of content came from @@ -912,20 +887,9 @@ public abstract class EmailContent { return null; } - /** - * Save or update a message - * @param ops an array of CPOs that we'll add to - */ public void addSaveOps(ArrayList<ContentProviderOperation> ops) { - boolean isNew = !isSaved(); - ContentProviderOperation.Builder b; - // First, save/update the message - if (isNew) { - b = ContentProviderOperation.newInsert(mBaseUri); - } else { - b = ContentProviderOperation.newUpdate(mBaseUri) - .withSelection(Message.RECORD_ID + "=?", new String[] {Long.toString(mId)}); - } + // First, save the message + ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(mBaseUri); // Generate the snippet here, before we create the CPO for Message if (mText != null) { mSnippet = TextUtilities.makeSnippetFromPlainText(mText); @@ -955,34 +919,19 @@ public abstract class EmailContent { cv.put(Body.INTRO_TEXT, mIntroText); } b = ContentProviderOperation.newInsert(Body.CONTENT_URI); - // Put our message id in the Body - if (!isNew) { - cv.put(Body.MESSAGE_KEY, mId); - } b.withValues(cv); - // We'll need this if we're new + ContentValues backValues = new ContentValues(); int messageBackValue = ops.size() - 1; - // If we're new, create a back value entry - if (isNew) { - ContentValues backValues = new ContentValues(); - backValues.put(Body.MESSAGE_KEY, messageBackValue); - b.withValueBackReferences(backValues); - } - // And add the Body operation - ops.add(b.build()); + backValues.put(Body.MESSAGE_KEY, messageBackValue); + ops.add(b.withValueBackReferences(backValues).build()); // Create the attaachments, if any if (mAttachments != null) { for (Attachment att: mAttachments) { - if (!isNew) { - att.mMessageKey = mId; - } - b = ContentProviderOperation.newInsert(Attachment.CONTENT_URI) - .withValues(att.toContentValues()); - if (isNew) { - b.withValueBackReference(Attachment.MESSAGE_KEY, messageBackValue); - } - ops.add(b.build()); + ops.add(ContentProviderOperation.newInsert(Attachment.CONTENT_URI) + .withValues(att.toContentValues()) + .withValueBackReference(Attachment.MESSAGE_KEY, messageBackValue) + .build()); } } } @@ -1085,12 +1034,6 @@ public abstract class EmailContent { public static final String CONTENT_BYTES = "content_bytes"; // A foreign key into the Account table (for the message owning this attachment) public static final String ACCOUNT_KEY = "accountKey"; - // The UIProvider state of the attachment - public static final String UI_STATE = "uiState"; - // The UIProvider destination of the attachment - public static final String UI_DESTINATION = "uiDestination"; - // The UIProvider downloaded size of the attachment - public static final String UI_DOWNLOADED_SIZE = "uiDownloadedSize"; } public static final class Attachment extends EmailContent @@ -1114,9 +1057,6 @@ public abstract class EmailContent { public int mFlags; public byte[] mContentBytes; public long mAccountKey; - public int mUiState; - public int mUiDestination; - public int mUiDownloadedSize; public static final int CONTENT_ID_COLUMN = 0; public static final int CONTENT_FILENAME_COLUMN = 1; @@ -1131,16 +1071,12 @@ public abstract class EmailContent { public static final int CONTENT_FLAGS_COLUMN = 10; public static final int CONTENT_CONTENT_BYTES_COLUMN = 11; public static final int CONTENT_ACCOUNT_KEY_COLUMN = 12; - public static final int CONTENT_UI_STATE_COLUMN = 13; - public static final int CONTENT_UI_DESTINATION_COLUMN = 14; - public static final int CONTENT_UI_DOWNLOADED_SIZE_COLUMN = 15; public static final String[] CONTENT_PROJECTION = new String[] { RECORD_ID, AttachmentColumns.FILENAME, AttachmentColumns.MIME_TYPE, AttachmentColumns.SIZE, AttachmentColumns.CONTENT_ID, AttachmentColumns.CONTENT_URI, AttachmentColumns.MESSAGE_KEY, AttachmentColumns.LOCATION, AttachmentColumns.ENCODING, AttachmentColumns.CONTENT, AttachmentColumns.FLAGS, AttachmentColumns.CONTENT_BYTES, - AttachmentColumns.ACCOUNT_KEY, AttachmentColumns.UI_STATE, - AttachmentColumns.UI_DESTINATION, AttachmentColumns.UI_DOWNLOADED_SIZE + AttachmentColumns.ACCOUNT_KEY }; // All attachments with an empty URI, regardless of mailbox @@ -1265,9 +1201,6 @@ public abstract class EmailContent { mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN); mContentBytes = cursor.getBlob(CONTENT_CONTENT_BYTES_COLUMN); mAccountKey = cursor.getLong(CONTENT_ACCOUNT_KEY_COLUMN); - mUiState = cursor.getInt(CONTENT_UI_STATE_COLUMN); - mUiDestination = cursor.getInt(CONTENT_UI_DESTINATION_COLUMN); - mUiDownloadedSize = cursor.getInt(CONTENT_UI_DOWNLOADED_SIZE_COLUMN); } @Override @@ -1285,9 +1218,6 @@ public abstract class EmailContent { values.put(AttachmentColumns.FLAGS, mFlags); values.put(AttachmentColumns.CONTENT_BYTES, mContentBytes); values.put(AttachmentColumns.ACCOUNT_KEY, mAccountKey); - values.put(AttachmentColumns.UI_STATE, mUiState); - values.put(AttachmentColumns.UI_DESTINATION, mUiDestination); - values.put(AttachmentColumns.UI_DOWNLOADED_SIZE, mUiDownloadedSize); return values; } @@ -1317,9 +1247,6 @@ public abstract class EmailContent { dest.writeInt(mContentBytes.length); dest.writeByteArray(mContentBytes); } - dest.writeInt(mUiState); - dest.writeInt(mUiDestination); - dest.writeInt(mUiDownloadedSize); } public Attachment(Parcel in) { @@ -1343,9 +1270,6 @@ public abstract class EmailContent { mContentBytes = new byte[contentBytesLen]; in.readByteArray(mContentBytes); } - mUiState = in.readInt(); - mUiDestination = in.readInt(); - mUiDownloadedSize = in.readInt(); } public static final Parcelable.Creator<EmailContent.Attachment> CREATOR @@ -1365,8 +1289,7 @@ public abstract class EmailContent { public String toString() { return "[" + mFileName + ", " + mMimeType + ", " + mSize + ", " + mContentId + ", " + mContentUri + ", " + mMessageKey + ", " + mLocation + ", " + mEncoding + ", " - + mFlags + ", " + mContentBytes + ", " + mAccountKey + "," + mUiState + "," - + mUiDestination + "," + mUiDownloadedSize + "]"; + + mFlags + ", " + mContentBytes + ", " + mAccountKey + "]"; } } @@ -1411,6 +1334,10 @@ public abstract class EmailContent { public static final String SIGNATURE = "signature"; // A foreign key into the Policy table public static final String POLICY_KEY = "policyKey"; + // The last notified message id + public static final String NOTIFIED_MESSAGE_ID = "notifiedMessageId"; + // The most recent notified message count + public static final String NOTIFIED_MESSAGE_COUNT = "notifiedMessageCount"; } public interface QuickResponseColumns { @@ -1456,18 +1383,10 @@ public abstract class EmailContent { public static final String SYNC_STATUS = "syncStatus"; // Number of messages in the mailbox. public static final String MESSAGE_COUNT = "messageCount"; + // Message ID of the last 'seen' message + public static final String LAST_SEEN_MESSAGE_KEY = "lastSeenMessageKey"; // The last time a message in this mailbox has been read (in millis) public static final String LAST_TOUCHED_TIME = "lastTouchedTime"; - // The UIProvider sync status - public static final String UI_SYNC_STATUS = "uiSyncStatus"; - // The UIProvider last sync result - public static final String UI_LAST_SYNC_RESULT = "uiLastSyncResult"; - // The UIProvider sync status - public static final String LAST_NOTIFIED_MESSAGE_KEY = "lastNotifiedMessageKey"; - // The UIProvider last sync result - public static final String LAST_NOTIFIED_MESSAGE_COUNT = "lastNotifiedMessageCount"; - // The total number of messages in the remote mailbox - public static final String TOTAL_COUNT = "totalCount"; } public interface HostAuthColumns { @@ -1518,8 +1437,5 @@ public abstract class EmailContent { public static final String MAX_CALENDAR_LOOKBACK = "maxCalendarLookback"; // Indicates that the server allows password recovery, not that we support it public static final String PASSWORD_RECOVERY_ENABLED = "passwordRecoveryEnabled"; - // Tokenized strings indicating protocol specific policies enforced/unsupported - public static final String PROTOCOL_POLICIES_ENFORCED = "protocolPoliciesEnforced"; - public static final String PROTOCOL_POLICIES_UNSUPPORTED = "protocolPoliciesUnsupported"; } } diff --git a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java index 4e44ad2fd..7ab5f4731 100644 --- a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java +++ b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java @@ -55,12 +55,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns public int mFlags; public int mVisibleLimit; public String mSyncStatus; + public long mLastSeenMessageKey; public long mLastTouchedTime; - public int mUiSyncStatus; - public int mUiLastSyncResult; - public long mLastNotifiedMessageKey; - public int mLastNotifiedMessageCount; - public int mTotalCount; public static final int CONTENT_ID_COLUMN = 0; public static final int CONTENT_DISPLAY_NAME_COLUMN = 1; @@ -78,12 +74,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns public static final int CONTENT_VISIBLE_LIMIT_COLUMN = 13; public static final int CONTENT_SYNC_STATUS_COLUMN = 14; public static final int CONTENT_PARENT_KEY_COLUMN = 15; - public static final int CONTENT_LAST_TOUCHED_TIME_COLUMN = 16; - public static final int CONTENT_UI_SYNC_STATUS_COLUMN = 17; - public static final int CONTENT_UI_LAST_SYNC_RESULT_COLUMN = 18; - public static final int CONTENT_LAST_NOTIFIED_MESSAGE_KEY_COLUMN = 19; - public static final int CONTENT_LAST_NOTIFIED_MESSAGE_COUNT_COLUMN = 20; - public static final int CONTENT_TOTAL_COUNT_COLUMN = 21; + public static final int CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN = 16; + public static final int CONTENT_LAST_TOUCHED_TIME_COLUMN = 17; /** * <em>NOTE</em>: If fields are added or removed, the method {@link #getHashes()} @@ -95,10 +87,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns MailboxColumns.DELIMITER, MailboxColumns.SYNC_KEY, MailboxColumns.SYNC_LOOKBACK, MailboxColumns.SYNC_INTERVAL, MailboxColumns.SYNC_TIME, MailboxColumns.FLAG_VISIBLE, MailboxColumns.FLAGS, MailboxColumns.VISIBLE_LIMIT, - MailboxColumns.SYNC_STATUS, MailboxColumns.PARENT_KEY, MailboxColumns.LAST_TOUCHED_TIME, - MailboxColumns.UI_SYNC_STATUS, MailboxColumns.UI_LAST_SYNC_RESULT, - MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT, - MailboxColumns.TOTAL_COUNT + MailboxColumns.SYNC_STATUS, MailboxColumns.PARENT_KEY, + MailboxColumns.LAST_SEEN_MESSAGE_KEY, MailboxColumns.LAST_TOUCHED_TIME, }; private static final String ACCOUNT_AND_MAILBOX_TYPE_SELECTION = @@ -191,10 +181,6 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns // A mailbox that holds Messages that are attachments public static final int TYPE_ATTACHMENT = 0x101; - // Default "touch" time for system mailboxes - public static final int DRAFTS_DEFAULT_TOUCH_TIME = 2; - public static final int SENT_DEFAULT_TOUCH_TIME = 1; - // Bit field flags; each is defined below // Warning: Do not read these flags until POP/IMAP/EAS all populate them /** No flags set */ @@ -320,12 +306,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN); mVisibleLimit = cursor.getInt(CONTENT_VISIBLE_LIMIT_COLUMN); mSyncStatus = cursor.getString(CONTENT_SYNC_STATUS_COLUMN); + mLastSeenMessageKey = cursor.getLong(CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN); mLastTouchedTime = cursor.getLong(CONTENT_LAST_TOUCHED_TIME_COLUMN); - mUiSyncStatus = cursor.getInt(CONTENT_UI_SYNC_STATUS_COLUMN); - mUiLastSyncResult = cursor.getInt(CONTENT_UI_LAST_SYNC_RESULT_COLUMN); - mLastNotifiedMessageKey = cursor.getLong(CONTENT_LAST_NOTIFIED_MESSAGE_KEY_COLUMN); - mLastNotifiedMessageCount = cursor.getInt(CONTENT_LAST_NOTIFIED_MESSAGE_COUNT_COLUMN); - mTotalCount = cursor.getInt(CONTENT_TOTAL_COUNT_COLUMN); } @Override @@ -346,12 +328,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns values.put(MailboxColumns.FLAGS, mFlags); values.put(MailboxColumns.VISIBLE_LIMIT, mVisibleLimit); values.put(MailboxColumns.SYNC_STATUS, mSyncStatus); + values.put(MailboxColumns.LAST_SEEN_MESSAGE_KEY, mLastSeenMessageKey); values.put(MailboxColumns.LAST_TOUCHED_TIME, mLastTouchedTime); - values.put(MailboxColumns.UI_SYNC_STATUS, mUiSyncStatus); - values.put(MailboxColumns.UI_LAST_SYNC_RESULT, mUiLastSyncResult); - values.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, mLastNotifiedMessageKey); - values.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT, mLastNotifiedMessageCount); - values.put(MailboxColumns.TOTAL_COUNT, mTotalCount); return values; } @@ -560,18 +538,10 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns = mSyncStatus; hash[CONTENT_PARENT_KEY_COLUMN] = mParentKey; + hash[CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN] + = mLastSeenMessageKey; hash[CONTENT_LAST_TOUCHED_TIME_COLUMN] = mLastTouchedTime; - hash[CONTENT_UI_SYNC_STATUS_COLUMN] - = mUiSyncStatus; - hash[CONTENT_UI_LAST_SYNC_RESULT_COLUMN] - = mUiLastSyncResult; - hash[CONTENT_LAST_NOTIFIED_MESSAGE_KEY_COLUMN] - = mLastNotifiedMessageKey; - hash[CONTENT_LAST_NOTIFIED_MESSAGE_COUNT_COLUMN] - = mLastNotifiedMessageCount; - hash[CONTENT_TOTAL_COUNT_COLUMN] - = mTotalCount; return hash; } @@ -601,12 +571,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns dest.writeInt(mFlags); dest.writeInt(mVisibleLimit); dest.writeString(mSyncStatus); + dest.writeLong(mLastSeenMessageKey); dest.writeLong(mLastTouchedTime); - dest.writeInt(mUiSyncStatus); - dest.writeInt(mUiLastSyncResult); - dest.writeLong(mLastNotifiedMessageKey); - dest.writeInt(mLastNotifiedMessageCount); - dest.writeInt(mTotalCount); } public Mailbox(Parcel in) { @@ -627,12 +593,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns mFlags = in.readInt(); mVisibleLimit = in.readInt(); mSyncStatus = in.readString(); + mLastSeenMessageKey = in.readLong(); mLastTouchedTime = in.readLong(); - mUiSyncStatus = in.readInt(); - mUiLastSyncResult = in.readInt(); - mLastNotifiedMessageKey = in.readLong(); - mLastNotifiedMessageCount = in.readInt(); - mTotalCount = in.readInt(); } public static final Parcelable.Creator<Mailbox> CREATOR = new Parcelable.Creator<Mailbox>() { @@ -646,8 +608,4 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns return new Mailbox[size]; } }; - - public String toString() { - return "[Mailbox " + mId + ": " + mDisplayName + "]"; - } } diff --git a/emailcommon/src/com/android/emailcommon/provider/Policy.java b/emailcommon/src/com/android/emailcommon/provider/Policy.java index d43290f9f..5c95abec8 100755..100644 --- a/emailcommon/src/com/android/emailcommon/provider/Policy.java +++ b/emailcommon/src/com/android/emailcommon/provider/Policy.java @@ -16,17 +16,21 @@ package com.android.emailcommon.provider; import android.app.admin.DevicePolicyManager; +import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.OperationApplicationException; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Log; -import com.android.emailcommon.utility.TextUtilities; import com.android.emailcommon.utility.Utility; +import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; @@ -52,8 +56,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol public static final int PASSWORD_MODE_SIMPLE = 1; public static final int PASSWORD_MODE_STRONG = 2; - public static final char POLICY_STRING_DELIMITER = '\1'; - public int mPasswordMode; public int mPasswordMinLength; public int mPasswordMaxFails; @@ -74,8 +76,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol public int mMaxEmailLookback; public int mMaxCalendarLookback; public boolean mPasswordRecoveryEnabled; - public String mProtocolPoliciesEnforced; - public String mProtocolPoliciesUnsupported; public static final int CONTENT_ID_COLUMN = 0; public static final int CONTENT_PASSWORD_MODE_COLUMN = 1; @@ -98,8 +98,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol public static final int CONTENT_MAX_EMAIL_LOOKBACK_COLUMN = 18; public static final int CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN = 19; public static final int CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN = 20; - public static final int CONTENT_PROTOCOL_POLICIES_ENFORCED_COLUMN = 21; - public static final int CONTENT_PROTOCOL_POLICIES_UNSUPPORTED_COLUMN = 22; public static final String[] CONTENT_PROJECTION = new String[] {RECORD_ID, PolicyColumns.PASSWORD_MODE, PolicyColumns.PASSWORD_MIN_LENGTH, @@ -111,8 +109,7 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol PolicyColumns.DONT_ALLOW_ATTACHMENTS, PolicyColumns.DONT_ALLOW_HTML, PolicyColumns.MAX_ATTACHMENT_SIZE, PolicyColumns.MAX_TEXT_TRUNCATION_SIZE, PolicyColumns.MAX_HTML_TRUNCATION_SIZE, PolicyColumns.MAX_EMAIL_LOOKBACK, - PolicyColumns.MAX_CALENDAR_LOOKBACK, PolicyColumns.PASSWORD_RECOVERY_ENABLED, - PolicyColumns.PROTOCOL_POLICIES_ENFORCED, PolicyColumns.PROTOCOL_POLICIES_UNSUPPORTED + PolicyColumns.MAX_CALENDAR_LOOKBACK, PolicyColumns.PASSWORD_RECOVERY_ENABLED }; public static final Policy NO_POLICY = new Policy(); @@ -142,24 +139,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol Account.ID_PROJECTION_COLUMN, Account.NO_ACCOUNT); } - public static ArrayList<String> addPolicyStringToList(String policyString, - ArrayList<String> policyList) { - if (policyString != null) { - int start = 0; - int len = policyString.length(); - while(start < len) { - int end = policyString.indexOf(POLICY_STRING_DELIMITER, start); - if (end > start) { - policyList.add(policyString.substring(start, end)); - start = end + 1; - } else { - break; - } - } - } - return policyList; - } - // We override this method to insure that we never write invalid policy data to the provider @Override public Uri save(Context context) { @@ -167,6 +146,76 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol return super.save(context); } + public static void clearAccountPolicy(Context context, Account account) { + setAccountPolicy(context, account, null, null); + } + + /** + * Convenience method for {@link #setAccountPolicy(Context, Account, Policy, String)}. + */ + @VisibleForTesting + public static void setAccountPolicy(Context context, long accountId, Policy policy, + String securitySyncKey) { + setAccountPolicy(context, Account.restoreAccountWithId(context, accountId), + policy, securitySyncKey); + } + + /** + * Set the policy for an account atomically; this also removes any other policy associated with + * the account and sets the policy key for the account. If policy is null, the policyKey is + * set to 0 and the securitySyncKey to null. Also, update the account object to reflect the + * current policyKey and securitySyncKey + * @param context the caller's context + * @param account the account whose policy is to be set + * @param policy the policy to set, or null if we're clearing the policy + * @param securitySyncKey the security sync key for this account (ignored if policy is null) + */ + public static void setAccountPolicy(Context context, Account account, Policy policy, + String securitySyncKey) { + if (DEBUG_POLICY) { + Log.d(TAG, "Set policy for account " + account.mDisplayName + ": " + + ((policy == null) ? "none" : policy.toString())); + } + ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); + + // Make sure this is a valid policy set + if (policy != null) { + policy.normalize(); + // Add the new policy (no account will yet reference this) + ops.add(ContentProviderOperation.newInsert( + Policy.CONTENT_URI).withValues(policy.toContentValues()).build()); + // Make the policyKey of the account our newly created policy, and set the sync key + ops.add(ContentProviderOperation.newUpdate( + ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) + .withValueBackReference(AccountColumns.POLICY_KEY, 0) + .withValue(AccountColumns.SECURITY_SYNC_KEY, securitySyncKey) + .build()); + } else { + ops.add(ContentProviderOperation.newUpdate( + ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) + .withValue(AccountColumns.SECURITY_SYNC_KEY, null) + .withValue(AccountColumns.POLICY_KEY, 0) + .build()); + } + + // Delete the previous policy associated with this account, if any + if (account.mPolicyKey > 0) { + ops.add(ContentProviderOperation.newDelete( + ContentUris.withAppendedId( + Policy.CONTENT_URI, account.mPolicyKey)).build()); + } + + try { + context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops); + account.refresh(context); + } catch (RemoteException e) { + // This is fatal to a remote process + throw new IllegalStateException("Exception setting account policy."); + } catch (OperationApplicationException e) { + // Can't happen; our provider doesn't throw this exception + } + } + /** * Review all attachment records for this account, and reset the "don't allow download" flag * as required by the account's new security policies @@ -237,7 +286,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol public boolean equals(Object other) { if (!(other instanceof Policy)) return false; Policy otherPolicy = (Policy)other; - // Policies here are enforced by the DPM if (mRequireEncryption != otherPolicy.mRequireEncryption) return false; if (mRequireEncryptionExternal != otherPolicy.mRequireEncryptionExternal) return false; if (mRequireRemoteWipe != otherPolicy.mRequireRemoteWipe) return false; @@ -248,13 +296,10 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol if (mPasswordMaxFails != otherPolicy.mPasswordMaxFails) return false; if (mPasswordMinLength != otherPolicy.mPasswordMinLength) return false; if (mPasswordMode != otherPolicy.mPasswordMode) return false; - if (mDontAllowCamera != otherPolicy.mDontAllowCamera) return false; - - // Policies here are enforced by the Exchange sync manager - // They should eventually be removed from Policy and replaced with some opaque data if (mRequireManualSyncWhenRoaming != otherPolicy.mRequireManualSyncWhenRoaming) { return false; } + if (mDontAllowCamera != otherPolicy.mDontAllowCamera) return false; if (mDontAllowAttachments != otherPolicy.mDontAllowAttachments) return false; if (mDontAllowHtml != otherPolicy.mDontAllowHtml) return false; if (mMaxAttachmentSize != otherPolicy.mMaxAttachmentSize) return false; @@ -263,15 +308,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol if (mMaxEmailLookback != otherPolicy.mMaxEmailLookback) return false; if (mMaxCalendarLookback != otherPolicy.mMaxCalendarLookback) return false; if (mPasswordRecoveryEnabled != otherPolicy.mPasswordRecoveryEnabled) return false; - - if (!TextUtilities.stringOrNullEquals(mProtocolPoliciesEnforced, - otherPolicy.mProtocolPoliciesEnforced)) { - return false; - } - if (!TextUtilities.stringOrNullEquals(mProtocolPoliciesUnsupported, - otherPolicy.mProtocolPoliciesUnsupported)) { - return false; - } return true; } @@ -317,9 +353,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol mMaxEmailLookback = cursor.getInt(CONTENT_MAX_EMAIL_LOOKBACK_COLUMN); mMaxCalendarLookback = cursor.getInt(CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN); mPasswordRecoveryEnabled = cursor.getInt(CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN) == 1; - mProtocolPoliciesEnforced = cursor.getString(CONTENT_PROTOCOL_POLICIES_ENFORCED_COLUMN); - mProtocolPoliciesUnsupported = - cursor.getString(CONTENT_PROTOCOL_POLICIES_UNSUPPORTED_COLUMN); } @Override @@ -345,8 +378,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol values.put(PolicyColumns.MAX_EMAIL_LOOKBACK, mMaxEmailLookback); values.put(PolicyColumns.MAX_CALENDAR_LOOKBACK, mMaxCalendarLookback); values.put(PolicyColumns.PASSWORD_RECOVERY_ENABLED, mPasswordRecoveryEnabled); - values.put(PolicyColumns.PROTOCOL_POLICIES_ENFORCED, mProtocolPoliciesEnforced); - values.put(PolicyColumns.PROTOCOL_POLICIES_UNSUPPORTED, mProtocolPoliciesUnsupported); return values; } @@ -477,8 +508,6 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol dest.writeInt(mMaxEmailLookback); dest.writeInt(mMaxCalendarLookback); dest.writeInt(mPasswordRecoveryEnabled ? 1 : 0); - dest.writeString(mProtocolPoliciesEnforced); - dest.writeString(mProtocolPoliciesUnsupported); } /** @@ -507,7 +536,5 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol mMaxEmailLookback = in.readInt(); mMaxCalendarLookback = in.readInt(); mPasswordRecoveryEnabled = in.readInt() == 1; - mProtocolPoliciesEnforced = in.readString(); - mProtocolPoliciesUnsupported = in.readString(); } }
\ No newline at end of file diff --git a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java index b2b50b799..a44734368 100644 --- a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java @@ -16,6 +16,12 @@ package com.android.emailcommon.service; +import com.android.emailcommon.Api; +import com.android.emailcommon.Device; +import com.android.emailcommon.mail.MessagingException; +import com.android.emailcommon.provider.HostAuth; +import com.android.emailcommon.provider.Policy; + import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -23,12 +29,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; -import com.android.emailcommon.Api; -import com.android.emailcommon.Device; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.provider.Policy; - import java.io.IOException; /** @@ -51,7 +51,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { // Private intent that will be used to connect to an independent Exchange service public static final String EXCHANGE_INTENT = "com.android.email.EXCHANGE_INTENT"; - public static final String IMAP_INTENT = "com.android.email.IMAP_INTENT"; public static final String AUTO_DISCOVER_BUNDLE_ERROR_CODE = "autodiscover_error_code"; public static final String AUTO_DISCOVER_BUNDLE_HOST_AUTH = "autodiscover_host_auth"; @@ -65,7 +64,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { private final IEmailServiceCallback mCallback; private Object mReturn = null; private IEmailService mService; - private final boolean isRemote; // Standard debugging public static final int DEBUG_BIT = 1; @@ -84,7 +82,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { public EmailServiceProxy(Context _context, Class<?> _class, IEmailServiceCallback _callback) { super(_context, new Intent(_context, _class)); mCallback = _callback; - isRemote = false; } // The following two constructors are used with remote services that must be referenced by @@ -96,7 +93,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { } catch (IOException e) { } mCallback = _callback; - isRemote = true; } public EmailServiceProxy(Context _context, String _action, IEmailServiceCallback _callback) { @@ -106,7 +102,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { } catch (IOException e) { } mCallback = _callback; - isRemote = true; } @Override @@ -114,10 +109,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { mService = IEmailService.Stub.asInterface(binder); } - public boolean isRemote() { - return isRemote; - } - @Override public int getApiLevel() { return Api.LEVEL; @@ -133,11 +124,9 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param background whether or not this request corresponds to a background action (i.e. * prefetch) vs a foreground action (user request) */ - @Override public void loadAttachment(final long attachmentId, final boolean background) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { try { if (mCallback != null) mService.setCallback(mCallback); @@ -164,10 +153,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param mailboxId the id of the mailbox record * @param userRequest whether or not the user specifically asked for the sync */ - @Override public void startSync(final long mailboxId, final boolean userRequest) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { if (mCallback != null) mService.setCallback(mCallback); mService.startSync(mailboxId, userRequest); @@ -183,10 +170,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param mailboxId the id of the mailbox record * @param userRequest whether or not the user specifically asked for the sync */ - @Override public void stopSync(final long mailboxId) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { if (mCallback != null) mService.setCallback(mCallback); mService.stopSync(mailboxId); @@ -204,10 +189,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param hostAuth the hostauth object to validate * @return a Bundle as described above */ - @Override public Bundle validate(final HostAuth hostAuth) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException{ if (mCallback != null) mService.setCallback(mCallback); mReturn = mService.validate(hostAuth); @@ -236,11 +219,9 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param password the user's password * @return a Bundle as described above */ - @Override public Bundle autoDiscover(final String userName, final String password) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException{ if (mCallback != null) mService.setCallback(mCallback); mReturn = mService.autoDiscover(userName, password); @@ -263,10 +244,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * * @param accoundId the id of the account whose folder list is to be updated */ - @Override public void updateFolderList(final long accountId) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { if (mCallback != null) mService.setCallback(mCallback); mService.updateFolderList(accountId); @@ -280,10 +259,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * * @param flags an integer whose bits represent logging flags as defined in DEBUG_* flags above */ - @Override public void setLogging(final int flags) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { if (mCallback != null) mService.setCallback(mCallback); mService.setLogging(flags); @@ -297,10 +274,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * * @param cb a callback object through which all service callbacks are executed */ - @Override public void setCallback(final IEmailServiceCallback cb) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { mService.setCallback(cb); } @@ -314,10 +289,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * * @param accountId the id of the account whose host information has changed */ - @Override public void hostChanged(final long accountId) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { mService.hostChanged(accountId); } @@ -330,11 +303,9 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param messageId the id of the message containing the meeting request * @param response the response code, as defined in EmailServiceConstants */ - @Override public void sendMeetingResponse(final long messageId, final int response) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { if (mCallback != null) mService.setCallback(mCallback); mService.sendMeetingResponse(messageId, response); @@ -343,19 +314,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { } /** - * Request the sync adapter to load a complete message + * Not yet used; intended to request the sync adapter to load a complete message * * @param messageId the id of the message to be loaded */ - @Override - public void loadMore(final long messageId) throws RemoteException { - setTask(new ProxyTask() { - @Override - public void run() throws RemoteException { - if (mCallback != null) mService.setCallback(mCallback); - mService.loadMore(messageId); - } - }, "startSync"); + public void loadMore(long messageId) throws RemoteException { } /** @@ -364,7 +327,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param accountId the account in which the folder is to be created * @param name the name of the folder to be created */ - @Override public boolean createFolder(long accountId, String name) throws RemoteException { return false; } @@ -375,7 +337,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param accountId the account in which the folder resides * @param name the name of the folder to be deleted */ - @Override public boolean deleteFolder(long accountId, String name) throws RemoteException { return false; } @@ -387,7 +348,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param oldName the name of the existing folder * @param newName the new name for the folder */ - @Override public boolean renameFolder(long accountId, String oldName, String newName) throws RemoteException { return false; @@ -401,10 +361,8 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * * @param accountId the account whose data is to be deleted */ - @Override public void deleteAccountPIMData(final long accountId) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException { mService.deleteAccountPIMData(accountId); } @@ -427,11 +385,9 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { * @param destMailboxId the id of the mailbox into which search results are appended * @return the total number of matches for this search (regardless of how many were requested) */ - @Override public int searchMessages(final long accountId, final SearchParams searchParams, final long destMailboxId) throws RemoteException { setTask(new ProxyTask() { - @Override public void run() throws RemoteException{ if (mCallback != null) mService.setCallback(mCallback); mReturn = mService.searchMessages(accountId, searchParams, destMailboxId); @@ -444,24 +400,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { return (Integer)mReturn; } } - - /** - * Request the service to send mail in the specified account's Outbox - * - * @param accountId the account whose outgoing mail should be sent - */ - @Override - public void sendMail(final long accountId) throws RemoteException { - setTask(new ProxyTask() { - @Override - public void run() throws RemoteException{ - if (mCallback != null) mService.setCallback(mCallback); - mService.sendMail(accountId); - } - }, "sendMail"); - } - - @Override public IBinder asBinder() { return null; } diff --git a/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl b/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl index cd5cd07c3..1c3d85946 100644 --- a/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl +++ b/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl @@ -57,6 +57,4 @@ interface IEmailService { // API level 2 int searchMessages(long accountId, in SearchParams params, long destMailboxId); - - void sendMail(long accountId); } diff --git a/emailcommon/src/com/android/emailcommon/service/IEmailServiceCallback.aidl b/emailcommon/src/com/android/emailcommon/service/IEmailServiceCallback.aidl index c713f5211..e4c6093fc 100644 --- a/emailcommon/src/com/android/emailcommon/service/IEmailServiceCallback.aidl +++ b/emailcommon/src/com/android/emailcommon/service/IEmailServiceCallback.aidl @@ -65,12 +65,4 @@ oneway interface IEmailServiceCallback { * progress = 0 for "start", 1..100 for optional progress reports */ void sendMessageStatus(long messageId, String subject, int statusCode, int progress); - - /** - * Callback to indicate that a particular message is being loaded - * messageId = the message being sent - * statusCode = 0 for OK, 1 for progress, other codes for error - * progress = 0 for "start", 1..100 for optional progress reports - */ - void loadMessageStatus(long messageId, int statusCode, int progress); } diff --git a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl index 9d4be36e4..e9bcf42dd 100755..100644 --- a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl +++ b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl @@ -19,7 +19,12 @@ import com.android.emailcommon.provider.Policy; interface IPolicyService { boolean isActive(in Policy policies); + void policiesRequired(long accountId); + void policiesUpdated(long accountId); void setAccountHoldFlag(long accountId, boolean newState); - void setAccountPolicy(long accountId, in Policy policy, String securityKey); + boolean isActiveAdmin(); + // This is about as oneway as you can get oneway void remoteWipe(); + boolean isSupported(in Policy policies); + Policy clearUnsupportedPolicies(in Policy policies); }
\ No newline at end of file diff --git a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java index 26e820dee..a3b317e26 100755..100644 --- a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java @@ -49,6 +49,24 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { } @Override + public Policy clearUnsupportedPolicies(final Policy arg0) throws RemoteException { + setTask(new ProxyTask() { + public void run() throws RemoteException { + mReturn = mService.clearUnsupportedPolicies(arg0); + } + }, "clearUnsupportedPolicies"); + waitForCompletion(); + if (DEBUG_PROXY) { + Log.v(TAG, "clearUnsupportedPolicies: " + ((mReturn == null) ? "null" : mReturn)); + } + if (mReturn == null) { + throw new ServiceUnavailableException("clearUnsupportedPolicies"); + } else { + return (Policy)mReturn; + } + } + + @Override public boolean isActive(final Policy arg0) throws RemoteException { setTask(new ProxyTask() { public void run() throws RemoteException { @@ -67,14 +85,48 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { } @Override - public void setAccountPolicy(final long accountId, final Policy policy, - final String securityKey) throws RemoteException { + public boolean isActiveAdmin() throws RemoteException { setTask(new ProxyTask() { public void run() throws RemoteException { - mService.setAccountPolicy(accountId, policy, securityKey); + mReturn = mService.isActiveAdmin(); } - }, "setAccountPolicy"); + }, "isActiveAdmin"); waitForCompletion(); + if (DEBUG_PROXY) { + Log.v(TAG, "isActiveAdmin: " + ((mReturn == null) ? "null" : mReturn)); + } + if (mReturn == null) { + throw new ServiceUnavailableException("isActiveAdmin"); + } else { + return (Boolean)mReturn; + } + } + + @Override + public boolean isSupported(final Policy arg0) throws RemoteException { + setTask(new ProxyTask() { + public void run() throws RemoteException { + mReturn = mService.isSupported(arg0); + } + }, "isSupported"); + waitForCompletion(); + if (DEBUG_PROXY) { + Log.v(TAG, "isSupported: " + ((mReturn == null) ? "null" : mReturn)); + } + if (mReturn == null) { + throw new ServiceUnavailableException("isSupported"); + } else { + return (Boolean)mReturn; + } + } + + @Override + public void policiesRequired(final long arg0) throws RemoteException { + setTask(new ProxyTask() { + public void run() throws RemoteException { + mService.policiesRequired(arg0); + } + }, "policiesRequired"); } @Override @@ -95,6 +147,15 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { }, "setAccountHoldFlag"); } + @Override + public void policiesUpdated(final long arg0) throws RemoteException { + setTask(new ProxyTask() { + public void run() throws RemoteException { + mService.policiesUpdated(arg0); + } + }, "policiesUpdated"); + } + // Static methods that encapsulate the proxy calls above public static boolean isActive(Context context, Policy policies) { try { @@ -104,6 +165,22 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { return false; } + public static void policiesRequired(Context context, long accountId) { + try { + new PolicyServiceProxy(context).policiesRequired(accountId); + } catch (RemoteException e) { + throw new IllegalStateException("PolicyService transaction failed"); + } + } + + public static void policiesUpdated(Context context, long accountId) { + try { + new PolicyServiceProxy(context).policiesUpdated(accountId); + } catch (RemoteException e) { + throw new IllegalStateException("PolicyService transaction failed"); + } + } + public static void setAccountHoldFlag(Context context, Account account, boolean newState) { try { new PolicyServiceProxy(context).setAccountHoldFlag(account.mId, newState); @@ -112,6 +189,14 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { } } + public static boolean isActiveAdmin(Context context) { + try { + return new PolicyServiceProxy(context).isActiveAdmin(); + } catch (RemoteException e) { + } + return false; + } + public static void remoteWipe(Context context) { try { new PolicyServiceProxy(context).remoteWipe(); @@ -120,11 +205,17 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { } } - public static void setAccountPolicy(Context context, long accountId, Policy policy, - String securityKey) { + public static boolean isSupported(Context context, Policy policy) { + try { + return new PolicyServiceProxy(context).isSupported(policy); + } catch (RemoteException e) { + } + return false; + } + + public static Policy clearUnsupportedPolicies(Context context, Policy policy) { try { - new PolicyServiceProxy(context).setAccountPolicy(accountId, policy, securityKey); - return; + return new PolicyServiceProxy(context).clearUnsupportedPolicies(policy); } catch (RemoteException e) { } throw new IllegalStateException("PolicyService transaction failed"); diff --git a/emailcommon/src/com/android/emailcommon/service/SearchParams.java b/emailcommon/src/com/android/emailcommon/service/SearchParams.java index eacf01df9..367cc89ab 100644 --- a/emailcommon/src/com/android/emailcommon/service/SearchParams.java +++ b/emailcommon/src/com/android/emailcommon/service/SearchParams.java @@ -40,10 +40,6 @@ public class SearchParams implements Parcelable { // If zero, specifies a "new" search; otherwise, asks for a continuation of the previous // query(ies) starting with the mOffset'th match (0 based) public int mOffset = DEFAULT_OFFSET; - // The total number of results for this search - public int mTotalCount = 0; - // The id of the "search" mailbox being used - public long mSearchMailboxId; /** * Error codes returned by the searchMessages API @@ -58,12 +54,6 @@ public class SearchParams implements Parcelable { mFilter = filter; } - public SearchParams(long mailboxId, String filter, long searchMailboxId) { - mMailboxId = mailboxId; - mFilter = filter; - mSearchMailboxId = searchMailboxId; - } - @Override public boolean equals(Object o) { if (o == this) { diff --git a/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java b/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java index 0aa919098..59f6fd2c0 100755..100644 --- a/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java +++ b/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java @@ -714,15 +714,4 @@ public class TextUtilities { return (CharSequence)sb; } - - /** - * Determine whether two Strings (either of which might be null) are the same; this is true - * when both are null or both are Strings that are equal. - */ - public static boolean stringOrNullEquals(String a, String b) { - if (a == null && b == null) return true; - if (a != null && b != null && a.equals(b)) return true; - return false; - } - } diff --git a/emailcommon/src/com/android/emailcommon/utility/Utility.java b/emailcommon/src/com/android/emailcommon/utility/Utility.java index b74d4b3e0..0a698d442 100644 --- a/emailcommon/src/com/android/emailcommon/utility/Utility.java +++ b/emailcommon/src/com/android/emailcommon/utility/Utility.java @@ -52,6 +52,7 @@ import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.EmailContent.HostAuthColumns; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.EmailContent.Message; +import com.android.emailcommon.provider.EmailContent.MessageColumns; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.provider.ProviderUnavailableException; @@ -896,27 +897,28 @@ public class Utility { * all accounts are updated. * @return an {@link EmailAsyncTask} for test only. */ - public static EmailAsyncTask<Void, Void, Void> updateLastNotifiedMessageKey( - final Context context, final long mailboxId) { + public static EmailAsyncTask<Void, Void, Void> updateLastSeenMessageKey(final Context context, + final long accountId) { return EmailAsyncTask.runAsyncParallel(new Runnable() { - private void updateLastSeenMessageKeyForMailbox(long mailboxId) { + private void updateLastSeenMessageKeyForAccount(long accountId) { ContentResolver resolver = context.getContentResolver(); - if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { + if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) { Cursor c = resolver.query( - Mailbox.CONTENT_URI, EmailContent.ID_PROJECTION, Mailbox.TYPE + "=?", - new String[] { Integer.toString(Mailbox.TYPE_INBOX) }, null); + Account.CONTENT_URI, EmailContent.ID_PROJECTION, null, null, null); if (c == null) throw new ProviderUnavailableException(); try { while (c.moveToNext()) { final long id = c.getLong(EmailContent.ID_PROJECTION_COLUMN); - updateLastSeenMessageKeyForMailbox(id); + updateLastSeenMessageKeyForAccount(id); } } finally { c.close(); } - } else if (mailboxId > 0L) { - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); - // mailbox has been removed + } else if (accountId > 0L) { + Mailbox mailbox = + Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_INBOX); + + // mailbox has been removed if (mailbox == null) { return; } @@ -925,33 +927,34 @@ public class Utility { // need a point at which we can compare against in the future. By setting this // value, we are claiming that every message before this has potentially been // seen by the user. - long mostRecentMessageId = Utility.getFirstRowLong(context, - ContentUris.withAppendedId( - EmailContent.MAILBOX_MOST_RECENT_MESSAGE_URI, mailboxId), - Message.ID_COLUMN_PROJECTION, null, null, null, - Message.ID_MAILBOX_COLUMN_ID, -1L); - long lastNotifiedMessageId = mailbox.mLastNotifiedMessageKey; + long messageId = Utility.getFirstRowLong( + context, + Message.CONTENT_URI, + EmailContent.ID_PROJECTION, + MessageColumns.MAILBOX_KEY + "=?", + new String[] { Long.toString(mailbox.mId) }, + MessageColumns.ID + " DESC", + EmailContent.ID_PROJECTION_COLUMN, 0L); + long oldLastSeenMessageId = Utility.getFirstRowLong( + context, ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailbox.mId), + new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY }, + null, null, null, 0, 0L); // Only update the db if the value has changed - if (mostRecentMessageId != lastNotifiedMessageId) { - Log.d(Logging.LOG_TAG, "Most recent = " + mostRecentMessageId + - ", last notified: " + lastNotifiedMessageId + - "; updating last notified"); + if (messageId != oldLastSeenMessageId) { ContentValues values = mailbox.toContentValues(); - values.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, mostRecentMessageId); + values.put(MailboxColumns.LAST_SEEN_MESSAGE_KEY, messageId); resolver.update( Mailbox.CONTENT_URI, values, EmailContent.ID_SELECTION, new String[] { Long.toString(mailbox.mId) }); - } else { - Log.d(Logging.LOG_TAG, "Most recent = last notified; no change"); } } } @Override public void run() { - updateLastSeenMessageKeyForMailbox(mailboxId); + updateLastSeenMessageKeyForAccount(accountId); } }); } diff --git a/emailcommon/src/org/apache/commons/io/CopyUtils.java b/emailcommon/src/org/apache/commons/io/CopyUtils.java new file mode 100644 index 000000000..eab8307e7 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/CopyUtils.java @@ -0,0 +1,332 @@ +/*
+ * 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.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+
+/**
+ * This class provides static utility methods for buffered
+ * copying between sources (<code>InputStream</code>, <code>Reader</code>,
+ * <code>String</code> and <code>byte[]</code>) and destinations
+ * (<code>OutputStream</code>, <code>Writer</code>, <code>String</code> and
+ * <code>byte[]</code>).
+ * <p>
+ * Unless otherwise noted, these <code>copy</code> methods do <em>not</em>
+ * flush or close the streams. Often doing so would require making non-portable
+ * assumptions about the streams' origin and further use. This means that both
+ * streams' <code>close()</code> methods must be called after copying. if one
+ * omits this step, then the stream resources (sockets, file descriptors) are
+ * released when the associated Stream is garbage-collected. It is not a good
+ * idea to rely on this mechanism. For a good overview of the distinction
+ * between "memory management" and "resource management", see
+ * <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
+ * UnixReview article</a>.
+ * <p>
+ * For byte-to-char methods, a <code>copy</code> variant allows the encoding
+ * to be selected (otherwise the platform default is used). We would like to
+ * encourage you to always specify the encoding because relying on the platform
+ * default can lead to unexpected results.
+ * <p
+ * We don't provide special variants for the <code>copy</code> methods that
+ * let you specify the buffer size because in modern VMs the impact on speed
+ * seems to be minimal. We're using a default buffer size of 4 KB.
+ * <p>
+ * The <code>copy</code> methods use an internal buffer when copying. It is
+ * therefore advisable <em>not</em> to deliberately wrap the stream arguments
+ * to the <code>copy</code> methods in <code>Buffered*</code> streams. For
+ * example, don't do the following:
+ * <pre>
+ * copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );
+ * </pre>
+ * The rationale is as follows:
+ * <p>
+ * Imagine that an InputStream's read() is a very expensive operation, which
+ * would usually suggest wrapping in a BufferedInputStream. The
+ * BufferedInputStream works by issuing infrequent
+ * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the
+ * underlying InputStream, to fill an internal buffer, from which further
+ * <code>read</code> requests can inexpensively get their data (until the buffer
+ * runs out).
+ * <p>
+ * However, the <code>copy</code> methods do the same thing, keeping an
+ * internal buffer, populated by
+ * {@link InputStream#read(byte[] b, int off, int len)} requests. Having two
+ * buffers (or three if the destination stream is also buffered) is pointless,
+ * and the unnecessary buffer management hurts performance slightly (about 3%,
+ * according to some simple experiments).
+ * <p>
+ * Behold, intrepid explorers; a map of this class:
+ * <pre>
+ * Method Input Output Dependency
+ * ------ ----- ------ -------
+ * 1 copy InputStream OutputStream (primitive)
+ * 2 copy Reader Writer (primitive)
+ *
+ * 3 copy InputStream Writer 2
+ *
+ * 4 copy Reader OutputStream 2
+ *
+ * 5 copy String OutputStream 2
+ * 6 copy String Writer (trivial)
+ *
+ * 7 copy byte[] Writer 3
+ * 8 copy byte[] OutputStream (trivial)
+ * </pre>
+ * <p>
+ * Note that only the first two methods shuffle bytes; the rest use these
+ * two, or (if possible) copy using native Java copy methods. As there are
+ * method variants to specify the encoding, each row may
+ * correspond to up to 2 methods.
+ * <p>
+ * Origin of code: Excalibur.
+ *
+ * @author Peter Donald
+ * @author Jeff Turner
+ * @author Matthew Hawthorne
+ * @version $Id: CopyUtils.java 437680 2006-08-28 11:57:00Z scolebourne $
+ * @deprecated Use IOUtils. Will be removed in 2.0.
+ * Methods renamed to IOUtils.write() or IOUtils.copy().
+ * Null handling behaviour changed in IOUtils (null data does not
+ * throw NullPointerException).
+ */
+public class CopyUtils {
+
+ /**
+ * The default size of the buffer.
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public CopyUtils() { }
+
+ // ----------------------------------------------------------------
+ // byte[] -> OutputStream
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
+ * @param input the byte array to read from
+ * @param output the <code>OutputStream</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(byte[] input, OutputStream output)
+ throws IOException {
+ output.write(input);
+ }
+
+ // ----------------------------------------------------------------
+ // byte[] -> Writer
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param input the byte array to read from
+ * @param output the <code>Writer</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(byte[] input, Writer output)
+ throws IOException {
+ ByteArrayInputStream in = new ByteArrayInputStream(input);
+ copy(in, output);
+ }
+
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param input the byte array to read from
+ * @param output the <code>Writer</code> to write to
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(
+ byte[] input,
+ Writer output,
+ String encoding)
+ throws IOException {
+ ByteArrayInputStream in = new ByteArrayInputStream(input);
+ copy(in, output, encoding);
+ }
+
+
+ // ----------------------------------------------------------------
+ // Core copy methods
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an
+ * <code>OutputStream</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 IOException In case of an I/O problem
+ */
+ public static int copy(
+ InputStream input,
+ OutputStream output)
+ throws IOException {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int count = 0;
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ // ----------------------------------------------------------------
+ // Reader -> Writer
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy chars from a <code>Reader</code> to a <code>Writer</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 IOException In case of an I/O problem
+ */
+ public static int copy(
+ Reader input,
+ Writer output)
+ throws IOException {
+ char[] buffer = new char[DEFAULT_BUFFER_SIZE];
+ int count = 0;
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ // ----------------------------------------------------------------
+ // InputStream -> Writer
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param input the <code>InputStream</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(
+ InputStream input,
+ Writer output)
+ throws IOException {
+ InputStreamReader in = new InputStreamReader(input);
+ copy(in, output);
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param input the <code>InputStream</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(
+ InputStream input,
+ Writer output,
+ String encoding)
+ throws IOException {
+ InputStreamReader in = new InputStreamReader(input, encoding);
+ copy(in, output);
+ }
+
+
+ // ----------------------------------------------------------------
+ // Reader -> OutputStream
+ // ----------------------------------------------------------------
+
+ /**
+ * Serialize chars from a <code>Reader</code> to bytes on an
+ * <code>OutputStream</code>, and flush the <code>OutputStream</code>.
+ * @param input the <code>Reader</code> to read from
+ * @param output the <code>OutputStream</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ 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();
+ }
+
+ // ----------------------------------------------------------------
+ // String -> OutputStream
+ // ----------------------------------------------------------------
+
+ /**
+ * Serialize chars from a <code>String</code> to bytes on an
+ * <code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ * @param input the <code>String</code> to read from
+ * @param output the <code>OutputStream</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(
+ String input,
+ OutputStream output)
+ throws IOException {
+ StringReader in = new StringReader(input);
+ OutputStreamWriter out = new OutputStreamWriter(output);
+ copy(in, out);
+ // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
+ // have to flush here.
+ out.flush();
+ }
+
+ // ----------------------------------------------------------------
+ // String -> Writer
+ // ----------------------------------------------------------------
+
+ /**
+ * Copy chars from a <code>String</code> to a <code>Writer</code>.
+ * @param input the <code>String</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public static void copy(String input, Writer output)
+ throws IOException {
+ output.write(input);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/DirectoryWalker.java b/emailcommon/src/org/apache/commons/io/DirectoryWalker.java new file mode 100644 index 000000000..9e564ae86 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/DirectoryWalker.java @@ -0,0 +1,620 @@ +/*
+ * 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.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+
+/**
+ * Abstract class that walks through a directory hierarchy and provides
+ * subclasses with convenient hooks to add specific behaviour.
+ * <p>
+ * This class operates with a {@link FileFilter} and maximum depth to
+ * limit the files and direcories visited.
+ * Commons IO supplies many common filter implementations in the
+ * <a href="filefilter/package-summary.html"> filefilter</a> package.
+ * <p>
+ * The following sections describe:
+ * <ul>
+ * <li><a href="#example">1. Example Implementation</a> - example
+ * <code>FileCleaner</code> implementation.</li>
+ * <li><a href="#filter">2. Filter Example</a> - using
+ * {@link FileFilter}(s) with <code>DirectoryWalker</code>.</li>
+ * <li><a href="#cancel">3. Cancellation</a> - how to implement cancellation
+ * behaviour.</li>
+ * </ul>
+ *
+ * <a name="example"></a>
+ * <h3>1. Example Implementation</h3>
+ *
+ * There are many possible extensions, for example, to delete all
+ * files and '.svn' directories, and return a list of deleted files:
+ * <pre>
+ * public class FileCleaner extends DirectoryWalker {
+ *
+ * public FileCleaner() {
+ * super();
+ * }
+ *
+ * public List clean(File startDirectory) {
+ * List results = new ArrayList();
+ * walk(startDirectory, results);
+ * return results;
+ * }
+ *
+ * protected boolean handleDirectory(File directory, int depth, Collection results) {
+ * // delete svn directories and then skip
+ * if (".svn".equals(directory.getName())) {
+ * directory.delete();
+ * return false;
+ * } else {
+ * return true;
+ * }
+ *
+ * }
+ *
+ * protected void handleFile(File file, int depth, Collection results) {
+ * // delete file and add to list of deleted
+ * file.delete();
+ * results.add(file);
+ * }
+ * }
+ * </pre>
+ *
+ * <a name="filter"></a>
+ * <h3>2. Filter Example</h3>
+ *
+ * Choosing which directories and files to process can be a key aspect
+ * of using this class. This information can be setup in three ways,
+ * via three different constructors.
+ * <p>
+ * The first option is to visit all directories and files.
+ * This is achieved via the no-args constructor.
+ * <p>
+ * The second constructor option is to supply a single {@link FileFilter}
+ * that describes the files and directories to visit. Care must be taken
+ * with this option as the same filter is used for both directories
+ * and files.
+ * <p>
+ * For example, if you wanted all directories which are not hidden
+ * and files which end in ".txt":
+ * <pre>
+ * public class FooDirectoryWalker extends DirectoryWalker {
+ * public FooDirectoryWalker(FileFilter filter) {
+ * super(filter, -1);
+ * }
+ * }
+ *
+ * // Build up the filters and create the walker
+ * // Create a filter for Non-hidden directories
+ * IOFileFilter fooDirFilter =
+ * FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
+ * HiddenFileFilter.VISIBLE);
+ *
+ * // Create a filter for Files ending in ".txt"
+ * IOFileFilter fooFileFilter =
+ * FileFilterUtils.andFileFilter(FileFilterUtils.fileFileFilter,
+ * FileFilterUtils.suffixFileFilter(".txt"));
+ *
+ * // Combine the directory and file filters using an OR condition
+ * java.io.FileFilter fooFilter =
+ * FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
+ *
+ * // Use the filter to construct a DirectoryWalker implementation
+ * FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
+ * </pre>
+ * <p>
+ * The third constructor option is to specify separate filters, one for
+ * directories and one for files. These are combined internally to form
+ * the correct <code>FileFilter</code>, something which is very easy to
+ * get wrong when attempted manually, particularly when trying to
+ * express constructs like 'any file in directories named docs'.
+ * <p>
+ * For example, if you wanted all directories which are not hidden
+ * and files which end in ".txt":
+ * <pre>
+ * public class FooDirectoryWalker extends DirectoryWalker {
+ * public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
+ * super(dirFilter, fileFilter, -1);
+ * }
+ * }
+ *
+ * // Use the filters to construct the walker
+ * FooDirectoryWalker walker = new FooDirectoryWalker(
+ * HiddenFileFilter.VISIBLE,
+ * FileFilterUtils.suffixFileFilter(".txt"),
+ * );
+ * </pre>
+ * This is much simpler than the previous example, and is why it is the preferred
+ * option for filtering.
+ *
+ * <a name="cancel"></a>
+ * <h3>3. Cancellation</h3>
+ *
+ * The DirectoryWalker contains some of the logic required for cancel processing.
+ * Subclasses must complete the implementation.
+ * <p>
+ * What <code>DirectoryWalker</code> does provide for cancellation is:
+ * <ul>
+ * <li>{@link CancelException} which can be thrown in any of the
+ * <i>lifecycle</i> methods to stop processing.</li>
+ * <li>The <code>walk()</code> method traps thrown {@link CancelException}
+ * and calls the <code>handleCancelled()</code> method, providing
+ * a place for custom cancel processing.</li>
+ * </ul>
+ * <p>
+ * Implementations need to provide:
+ * <ul>
+ * <li>The decision logic on whether to cancel processing or not.</li>
+ * <li>Constructing and throwing a {@link CancelException}.</li>
+ * <li>Custom cancel processing in the <code>handleCancelled()</code> method.
+ * </ul>
+ * <p>
+ * Two possible scenarios are envisaged for cancellation:
+ * <ul>
+ * <li><a href="#external">3.1 External / Mult-threaded</a> - cancellation being
+ * decided/initiated by an external process.</li>
+ * <li><a href="#internal">3.2 Internal</a> - cancellation being decided/initiated
+ * from within a DirectoryWalker implementation.</li>
+ * </ul>
+ * <p>
+ * The following sections provide example implementations for these two different
+ * scenarios.
+ *
+ * <a name="external"></a>
+ * <h4>3.1 External / Multi-threaded</h4>
+ *
+ * This example provides a public <code>cancel()</code> method that can be
+ * called by another thread to stop the processing. A typical example use-case
+ * would be a cancel button on a GUI. Calling this method sets a
+ * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930">
+ * volatile</a> flag to ensure it will work properly in a multi-threaded environment.
+ * The flag is returned by the <code>handleIsCancelled()</code> method, which
+ * will cause the walk to stop immediately. The <code>handleCancelled()</code>
+ * method will be the next, and last, callback method received once cancellation
+ * has occurred.
+ *
+ * <pre>
+ * public class FooDirectoryWalker extends DirectoryWalker {
+ *
+ * private volatile boolean cancelled = false;
+ *
+ * public void cancel() {
+ * cancelled = true;
+ * }
+ *
+ * private void handleIsCancelled(File file, int depth, Collection results) {
+ * return cancelled;
+ * }
+ *
+ * protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
+ * // implement processing required when a cancellation occurs
+ * }
+ * }
+ * </pre>
+ *
+ * <a name="internal"></a>
+ * <h4>3.2 Internal</h4>
+ *
+ * This shows an example of how internal cancellation processing could be implemented.
+ * <b>Note</b> the decision logic and throwing a {@link CancelException} could be implemented
+ * in any of the <i>lifecycle</i> methods.
+ *
+ * <pre>
+ * public class BarDirectoryWalker extends DirectoryWalker {
+ *
+ * protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
+ * // cancel if hidden directory
+ * if (directory.isHidden()) {
+ * throw new CancelException(file, depth);
+ * }
+ * return true;
+ * }
+ *
+ * protected void handleFile(File file, int depth, Collection results) throws IOException {
+ * // cancel if read-only file
+ * if (!file.canWrite()) {
+ * throw new CancelException(file, depth);
+ * }
+ * results.add(file);
+ * }
+ *
+ * protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
+ * // implement processing required when a cancellation occurs
+ * }
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 424748 $
+ */
+public abstract class DirectoryWalker {
+
+ /**
+ * The file filter to use to filter files and directories.
+ */
+ private final FileFilter filter;
+ /**
+ * The limit on the directory depth to walk.
+ */
+ private final int depthLimit;
+
+ /**
+ * Construct an instance with no filtering and unlimited <i>depth</i>.
+ */
+ protected DirectoryWalker() {
+ this(null, -1);
+ }
+
+ /**
+ * Construct an instance with a filter and limit the <i>depth</i> navigated to.
+ * <p>
+ * The filter controls which files and directories will be navigated to as
+ * part of the walk. The {@link FileFilterUtils} class is useful for combining
+ * various filters together. A <code>null</code> filter means that no
+ * filtering should occur and all files and directories will be visited.
+ *
+ * @param filter the filter to apply, null means visit all files
+ * @param depthLimit controls how <i>deep</i> the hierarchy is
+ * navigated to (less than 0 means unlimited)
+ */
+ protected DirectoryWalker(FileFilter filter, int depthLimit) {
+ this.filter = filter;
+ this.depthLimit = depthLimit;
+ }
+
+ /**
+ * Construct an instance with a directory and a file filter and an optional
+ * limit on the <i>depth</i> navigated to.
+ * <p>
+ * The filters control which files and directories will be navigated to as part
+ * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly(IOFileFilter)}
+ * and {@link FileFilterUtils#makeFileOnly(IOFileFilter)} internally to combine the filters.
+ * A <code>null</code> filter means that no filtering should occur.
+ *
+ * @param directoryFilter the filter to apply to directories, null means visit all directories
+ * @param fileFilter the filter to apply to files, null means visit all files
+ * @param depthLimit controls how <i>deep</i> the hierarchy is
+ * navigated to (less than 0 means unlimited)
+ */
+ protected DirectoryWalker(IOFileFilter directoryFilter, IOFileFilter fileFilter, int depthLimit) {
+ if (directoryFilter == null && fileFilter == null) {
+ this.filter = null;
+ } else {
+ directoryFilter = (directoryFilter != null ? directoryFilter : TrueFileFilter.TRUE);
+ fileFilter = (fileFilter != null ? fileFilter : TrueFileFilter.TRUE);
+ directoryFilter = FileFilterUtils.makeDirectoryOnly(directoryFilter);
+ fileFilter = FileFilterUtils.makeFileOnly(fileFilter);
+ this.filter = FileFilterUtils.orFileFilter(directoryFilter, fileFilter);
+ }
+ this.depthLimit = depthLimit;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Internal method that walks the directory hierarchy in a depth-first manner.
+ * <p>
+ * Users of this class do not need to call this method. This method will
+ * be called automatically by another (public) method on the specific subclass.
+ * <p>
+ * Writers of subclasses should call this method to start the directory walk.
+ * Once called, this method will emit events as it walks the hierarchy.
+ * The event methods have the prefix <code>handle</code>.
+ *
+ * @param startDirectory the directory to start from, not null
+ * @param results the collection of result objects, may be updated
+ * @throws NullPointerException if the start directory is null
+ * @throws IOException if an I/O Error occurs
+ */
+ protected final void walk(File startDirectory, Collection results) throws IOException {
+ if (startDirectory == null) {
+ throw new NullPointerException("Start Directory is null");
+ }
+ try {
+ handleStart(startDirectory, results);
+ walk(startDirectory, 0, results);
+ handleEnd(results);
+ } catch(CancelException cancel) {
+ handleCancelled(startDirectory, results, cancel);
+ }
+ }
+
+ /**
+ * Main recursive method to examine the directory hierarchy.
+ *
+ * @param directory the directory to examine, not null
+ * @param depth the directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ private void walk(File directory, int depth, Collection results) throws IOException {
+ checkIfCancelled(directory, depth, results);
+ if (handleDirectory(directory, depth, results)) {
+ handleDirectoryStart(directory, depth, results);
+ int childDepth = depth + 1;
+ if (depthLimit < 0 || childDepth <= depthLimit) {
+ checkIfCancelled(directory, depth, results);
+ File[] childFiles = (filter == null ? directory.listFiles() : directory.listFiles(filter));
+ if (childFiles == null) {
+ handleRestricted(directory, childDepth, results);
+ } else {
+ for (int i = 0; i < childFiles.length; i++) {
+ File childFile = childFiles[i];
+ if (childFile.isDirectory()) {
+ walk(childFile, childDepth, results);
+ } else {
+ checkIfCancelled(childFile, childDepth, results);
+ handleFile(childFile, childDepth, results);
+ checkIfCancelled(childFile, childDepth, results);
+ }
+ }
+ }
+ }
+ handleDirectoryEnd(directory, depth, results);
+ }
+ checkIfCancelled(directory, depth, results);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks whether the walk has been cancelled by calling {@link #handleIsCancelled},
+ * throwing a <code>CancelException</code> if it has.
+ * <p>
+ * Writers of subclasses should not normally call this method as it is called
+ * automatically by the walk of the tree. However, sometimes a single method,
+ * typically {@link #handleFile}, may take a long time to run. In that case,
+ * you may wish to check for cancellation by calling this method.
+ *
+ * @param file the current file being processed
+ * @param depth the current file level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected final void checkIfCancelled(File file, int depth, Collection results) throws IOException {
+ if (handleIsCancelled(file, depth, results)) {
+ throw new CancelException(file, depth);
+ }
+ }
+
+ /**
+ * Overridable callback method invoked to determine if the entire walk
+ * operation should be immediately cancelled.
+ * <p>
+ * This method should be implemented by those subclasses that want to
+ * provide a public <code>cancel()</code> method available from another
+ * thread. The design pattern for the subclass should be as follows:
+ * <pre>
+ * public class FooDirectoryWalker extends DirectoryWalker {
+ * private volatile boolean cancelled = false;
+ *
+ * public void cancel() {
+ * cancelled = true;
+ * }
+ * private void handleIsCancelled(File file, int depth, Collection results) {
+ * return cancelled;
+ * }
+ * protected void handleCancelled(File startDirectory,
+ * Collection results, CancelException cancel) {
+ * // implement processing required when a cancellation occurs
+ * }
+ * }
+ * </pre>
+ * <p>
+ * If this method returns true, then the directory walk is immediately
+ * cancelled. The next callback method will be {@link #handleCancelled}.
+ * <p>
+ * This implementation returns false.
+ *
+ * @param file the file or directory being processed
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @return true if the walk has been cancelled
+ * @throws IOException if an I/O Error occurs
+ */
+ protected boolean handleIsCancelled(
+ File file, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ return false; // not cancelled
+ }
+
+ /**
+ * Overridable callback method invoked when the operation is cancelled.
+ * The file being processed when the cancellation occurred can be
+ * obtained from the exception.
+ * <p>
+ * This implementation just re-throws the {@link CancelException}.
+ *
+ * @param startDirectory the directory that the walk started from
+ * @param results the collection of result objects, may be updated
+ * @param cancel the exception throw to cancel further processing
+ * containing details at the point of cancellation.
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleCancelled(File startDirectory, Collection results,
+ CancelException cancel) throws IOException {
+ // re-throw exception - overridable by subclass
+ throw cancel;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Overridable callback method invoked at the start of processing.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param startDirectory the directory to start from
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleStart(File startDirectory, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Overridable callback method invoked to determine if a directory should be processed.
+ * <p>
+ * This method returns a boolean to indicate if the directory should be examined or not.
+ * If you return false, the entire directory and any subdirectories will be skipped.
+ * Note that this functionality is in addition to the filtering by file filter.
+ * <p>
+ * This implementation does nothing and returns true.
+ *
+ * @param directory the current directory being processed
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @return true to process this directory, false to skip this directory
+ * @throws IOException if an I/O Error occurs
+ */
+ protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ return true; // process directory
+ }
+
+ /**
+ * Overridable callback method invoked at the start of processing each directory.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param directory the current directory being processed
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleDirectoryStart(File directory, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Overridable callback method invoked for each (non-directory) file.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param file the current file being processed
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleFile(File file, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Overridable callback method invoked for each restricted directory.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param directory the restricted directory
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleRestricted(File directory, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Overridable callback method invoked at the end of processing each directory.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param directory the directory being processed
+ * @param depth the current directory level (starting directory = 0)
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleDirectoryEnd(File directory, int depth, Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Overridable callback method invoked at the end of processing.
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param results the collection of result objects, may be updated
+ * @throws IOException if an I/O Error occurs
+ */
+ protected void handleEnd(Collection results) throws IOException {
+ // do nothing - overridable by subclass
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * CancelException is thrown in DirectoryWalker to cancel the current
+ * processing.
+ */
+ public static class CancelException extends IOException {
+
+ /** Serialization id. */
+ private static final long serialVersionUID = 1347339620135041008L;
+
+ /** The file being processed when the exception was thrown. */
+ private File file;
+ /** The file depth when the exception was thrown. */
+ private int depth = -1;
+
+ /**
+ * Constructs a <code>CancelException</code> with
+ * the file and depth when cancellation occurred.
+ *
+ * @param file the file when the operation was cancelled, may be null
+ * @param depth the depth when the operation was cancelled, may be null
+ */
+ public CancelException(File file, int depth) {
+ this("Operation Cancelled", file, depth);
+ }
+
+ /**
+ * Constructs a <code>CancelException</code> with
+ * an appropriate message and the file and depth when
+ * cancellation occurred.
+ *
+ * @param message the detail message
+ * @param file the file when the operation was cancelled
+ * @param depth the depth when the operation was cancelled
+ */
+ public CancelException(String message, File file, int depth) {
+ super(message);
+ this.file = file;
+ this.depth = depth;
+ }
+
+ /**
+ * Return the file when the operation was cancelled.
+ *
+ * @return the file when the operation was cancelled
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Return the depth when the operation was cancelled.
+ *
+ * @return the depth when the operation was cancelled
+ */
+ public int getDepth() {
+ return depth;
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/EndianUtils.java b/emailcommon/src/org/apache/commons/io/EndianUtils.java new file mode 100644 index 000000000..810feac04 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/EndianUtils.java @@ -0,0 +1,489 @@ +/*
+ * 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.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Utility code for dealing with different endian systems.
+ * <p>
+ * Different computer architectures adopt different conventions for
+ * byte ordering. In so-called "Little Endian" architectures (eg Intel),
+ * the low-order byte is stored in memory at the lowest address, and
+ * subsequent bytes at higher addresses. For "Big Endian" architectures
+ * (eg Motorola), the situation is reversed.
+ * This class helps you solve this incompatability.
+ * <p>
+ * Origin of code: Excalibur
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $
+ * @see org.apache.commons.io.input.SwappedDataInputStream
+ */
+public class EndianUtils {
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public EndianUtils() {
+ super();
+ }
+
+ // ========================================== Swapping routines
+
+ /**
+ * Converts a "short" value between endian systems.
+ * @param value value to convert
+ * @return the converted value
+ */
+ public static short swapShort(short value) {
+ return (short) ( ( ( ( value >> 0 ) & 0xff ) << 8 ) +
+ ( ( ( value >> 8 ) & 0xff ) << 0 ) );
+ }
+
+ /**
+ * Converts a "int" value between endian systems.
+ * @param value value to convert
+ * @return the converted value
+ */
+ public static int swapInteger(int value) {
+ return
+ ( ( ( value >> 0 ) & 0xff ) << 24 ) +
+ ( ( ( value >> 8 ) & 0xff ) << 16 ) +
+ ( ( ( value >> 16 ) & 0xff ) << 8 ) +
+ ( ( ( value >> 24 ) & 0xff ) << 0 );
+ }
+
+ /**
+ * Converts a "long" value between endian systems.
+ * @param value value to convert
+ * @return the converted value
+ */
+ public static long swapLong(long value) {
+ return
+ ( ( ( value >> 0 ) & 0xff ) << 56 ) +
+ ( ( ( value >> 8 ) & 0xff ) << 48 ) +
+ ( ( ( value >> 16 ) & 0xff ) << 40 ) +
+ ( ( ( value >> 24 ) & 0xff ) << 32 ) +
+ ( ( ( value >> 32 ) & 0xff ) << 24 ) +
+ ( ( ( value >> 40 ) & 0xff ) << 16 ) +
+ ( ( ( value >> 48 ) & 0xff ) << 8 ) +
+ ( ( ( value >> 56 ) & 0xff ) << 0 );
+ }
+
+ /**
+ * Converts a "float" value between endian systems.
+ * @param value value to convert
+ * @return the converted value
+ */
+ public static float swapFloat(float value) {
+ return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) );
+ }
+
+ /**
+ * Converts a "double" value between endian systems.
+ * @param value value to convert
+ * @return the converted value
+ */
+ public static double swapDouble(double value) {
+ return Double.longBitsToDouble( swapLong( Double.doubleToLongBits( value ) ) );
+ }
+
+ // ========================================== Swapping read/write routines
+
+ /**
+ * Writes a "short" value to a byte array at a given offset. The value is
+ * converted to the opposed endian system while writing.
+ * @param data target byte array
+ * @param offset starting offset in the byte array
+ * @param value value to write
+ */
+ public static void writeSwappedShort(byte[] data, int offset, short value) {
+ data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
+ data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
+ }
+
+ /**
+ * Reads a "short" value from a byte array at a given offset. The value is
+ * converted to the opposed endian system while reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static short readSwappedShort(byte[] data, int offset) {
+ return (short)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 1 ] & 0xff ) << 8 ) );
+ }
+
+ /**
+ * Reads an unsigned short (16-bit) value from a byte array at a given
+ * offset. The value is converted to the opposed endian system while
+ * reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static int readSwappedUnsignedShort(byte[] data, int offset) {
+ return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 1 ] & 0xff ) << 8 ) );
+ }
+
+ /**
+ * Writes a "int" value to a byte array at a given offset. The value is
+ * converted to the opposed endian system while writing.
+ * @param data target byte array
+ * @param offset starting offset in the byte array
+ * @param value value to write
+ */
+ public static void writeSwappedInteger(byte[] data, int offset, int value) {
+ data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
+ data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
+ data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
+ data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
+ }
+
+ /**
+ * Reads a "int" value from a byte array at a given offset. The value is
+ * converted to the opposed endian system while reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static int readSwappedInteger(byte[] data, int offset) {
+ return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
+ ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
+ ( ( data[ offset + 3 ] & 0xff ) << 24 ) );
+ }
+
+ /**
+ * Reads an unsigned integer (32-bit) value from a byte array at a given
+ * offset. The value is converted to the opposed endian system while
+ * reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static long readSwappedUnsignedInteger(byte[] data, int offset) {
+ long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
+ ( ( data[ offset + 2 ] & 0xff ) << 16 ) );
+
+ long high = data[ offset + 3 ] & 0xff;
+
+ return (high << 24) + (0xffffffffL & low);
+ }
+
+ /**
+ * Writes a "long" value to a byte array at a given offset. The value is
+ * converted to the opposed endian system while writing.
+ * @param data target byte array
+ * @param offset starting offset in the byte array
+ * @param value value to write
+ */
+ public static void writeSwappedLong(byte[] data, int offset, long value) {
+ data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
+ data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
+ data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
+ data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
+ data[ offset + 4 ] = (byte)( ( value >> 32 ) & 0xff );
+ data[ offset + 5 ] = (byte)( ( value >> 40 ) & 0xff );
+ data[ offset + 6 ] = (byte)( ( value >> 48 ) & 0xff );
+ data[ offset + 7 ] = (byte)( ( value >> 56 ) & 0xff );
+ }
+
+ /**
+ * Reads a "long" value from a byte array at a given offset. The value is
+ * converted to the opposed endian system while reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static long readSwappedLong(byte[] data, int offset) {
+ long low =
+ ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
+ ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
+ ( ( data[ offset + 3 ] & 0xff ) << 24 );
+ long high =
+ ( ( data[ offset + 4 ] & 0xff ) << 0 ) +
+ ( ( data[ offset + 5 ] & 0xff ) << 8 ) +
+ ( ( data[ offset + 6 ] & 0xff ) << 16 ) +
+ ( ( data[ offset + 7 ] & 0xff ) << 24 );
+ return (high << 32) + (0xffffffffL & low);
+ }
+
+ /**
+ * Writes a "float" value to a byte array at a given offset. The value is
+ * converted to the opposed endian system while writing.
+ * @param data target byte array
+ * @param offset starting offset in the byte array
+ * @param value value to write
+ */
+ public static void writeSwappedFloat(byte[] data, int offset, float value) {
+ writeSwappedInteger( data, offset, Float.floatToIntBits( value ) );
+ }
+
+ /**
+ * Reads a "float" value from a byte array at a given offset. The value is
+ * converted to the opposed endian system while reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static float readSwappedFloat(byte[] data, int offset) {
+ return Float.intBitsToFloat( readSwappedInteger( data, offset ) );
+ }
+
+ /**
+ * Writes a "double" value to a byte array at a given offset. The value is
+ * converted to the opposed endian system while writing.
+ * @param data target byte array
+ * @param offset starting offset in the byte array
+ * @param value value to write
+ */
+ public static void writeSwappedDouble(byte[] data, int offset, double value) {
+ writeSwappedLong( data, offset, Double.doubleToLongBits( value ) );
+ }
+
+ /**
+ * Reads a "double" value from a byte array at a given offset. The value is
+ * converted to the opposed endian system while reading.
+ * @param data source byte array
+ * @param offset starting offset in the byte array
+ * @return the value read
+ */
+ public static double readSwappedDouble(byte[] data, int offset) {
+ return Double.longBitsToDouble( readSwappedLong( data, offset ) );
+ }
+
+ /**
+ * Writes a "short" value to an OutputStream. The value is
+ * converted to the opposed endian system while writing.
+ * @param output target OutputStream
+ * @param value value to write
+ * @throws IOException in case of an I/O problem
+ */
+ public static void writeSwappedShort(OutputStream output, short value)
+ throws IOException
+ {
+ output.write( (byte)( ( value >> 0 ) & 0xff ) );
+ output.write( (byte)( ( value >> 8 ) & 0xff ) );
+ }
+
+ /**
+ * Reads a "short" value from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static short readSwappedShort(InputStream input)
+ throws IOException
+ {
+ return (short)( ( ( read( input ) & 0xff ) << 0 ) +
+ ( ( read( input ) & 0xff ) << 8 ) );
+ }
+
+ /**
+ * Reads a unsigned short (16-bit) from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static int readSwappedUnsignedShort(InputStream input)
+ throws IOException
+ {
+ int value1 = read( input );
+ int value2 = read( input );
+
+ return ( ( ( value1 & 0xff ) << 0 ) +
+ ( ( value2 & 0xff ) << 8 ) );
+ }
+
+ /**
+ * Writes a "int" value to an OutputStream. The value is
+ * converted to the opposed endian system while writing.
+ * @param output target OutputStream
+ * @param value value to write
+ * @throws IOException in case of an I/O problem
+ */
+ public static void writeSwappedInteger(OutputStream output, int value)
+ throws IOException
+ {
+ output.write( (byte)( ( value >> 0 ) & 0xff ) );
+ output.write( (byte)( ( value >> 8 ) & 0xff ) );
+ output.write( (byte)( ( value >> 16 ) & 0xff ) );
+ output.write( (byte)( ( value >> 24 ) & 0xff ) );
+ }
+
+ /**
+ * Reads a "int" value from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static int readSwappedInteger(InputStream input)
+ throws IOException
+ {
+ int value1 = read( input );
+ int value2 = read( input );
+ int value3 = read( input );
+ int value4 = read( input );
+
+ return ( ( value1 & 0xff ) << 0 ) +
+ ( ( value2 & 0xff ) << 8 ) +
+ ( ( value3 & 0xff ) << 16 ) +
+ ( ( value4 & 0xff ) << 24 );
+ }
+
+ /**
+ * Reads a unsigned integer (32-bit) from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static long readSwappedUnsignedInteger(InputStream input)
+ throws IOException
+ {
+ int value1 = read( input );
+ int value2 = read( input );
+ int value3 = read( input );
+ int value4 = read( input );
+
+ long low = ( ( ( value1 & 0xff ) << 0 ) +
+ ( ( value2 & 0xff ) << 8 ) +
+ ( ( value3 & 0xff ) << 16 ) );
+
+ long high = value4 & 0xff;
+
+ return (high << 24) + (0xffffffffL & low);
+ }
+
+ /**
+ * Writes a "long" value to an OutputStream. The value is
+ * converted to the opposed endian system while writing.
+ * @param output target OutputStream
+ * @param value value to write
+ * @throws IOException in case of an I/O problem
+ */
+ public static void writeSwappedLong(OutputStream output, long value)
+ throws IOException
+ {
+ output.write( (byte)( ( value >> 0 ) & 0xff ) );
+ output.write( (byte)( ( value >> 8 ) & 0xff ) );
+ output.write( (byte)( ( value >> 16 ) & 0xff ) );
+ output.write( (byte)( ( value >> 24 ) & 0xff ) );
+ output.write( (byte)( ( value >> 32 ) & 0xff ) );
+ output.write( (byte)( ( value >> 40 ) & 0xff ) );
+ output.write( (byte)( ( value >> 48 ) & 0xff ) );
+ output.write( (byte)( ( value >> 56 ) & 0xff ) );
+ }
+
+ /**
+ * Reads a "long" value from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static long readSwappedLong(InputStream input)
+ throws IOException
+ {
+ byte[] bytes = new byte[8];
+ for ( int i=0; i<8; i++ ) {
+ bytes[i] = (byte) read( input );
+ }
+ return readSwappedLong( bytes, 0 );
+ }
+
+ /**
+ * Writes a "float" value to an OutputStream. The value is
+ * converted to the opposed endian system while writing.
+ * @param output target OutputStream
+ * @param value value to write
+ * @throws IOException in case of an I/O problem
+ */
+ public static void writeSwappedFloat(OutputStream output, float value)
+ throws IOException
+ {
+ writeSwappedInteger( output, Float.floatToIntBits( value ) );
+ }
+
+ /**
+ * Reads a "float" value from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static float readSwappedFloat(InputStream input)
+ throws IOException
+ {
+ return Float.intBitsToFloat( readSwappedInteger( input ) );
+ }
+
+ /**
+ * Writes a "double" value to an OutputStream. The value is
+ * converted to the opposed endian system while writing.
+ * @param output target OutputStream
+ * @param value value to write
+ * @throws IOException in case of an I/O problem
+ */
+ public static void writeSwappedDouble(OutputStream output, double value)
+ throws IOException
+ {
+ writeSwappedLong( output, Double.doubleToLongBits( value ) );
+ }
+
+ /**
+ * Reads a "double" value from an InputStream. The value is
+ * converted to the opposed endian system while reading.
+ * @param input source InputStream
+ * @return the value just read
+ * @throws IOException in case of an I/O problem
+ */
+ public static double readSwappedDouble(InputStream input)
+ throws IOException
+ {
+ return Double.longBitsToDouble( readSwappedLong( input ) );
+ }
+
+ /**
+ * Reads the next byte from the input stream.
+ * @param input the stream
+ * @return the byte
+ * @throws IOException if the end of file is reached
+ */
+ private static int read(InputStream input)
+ throws IOException
+ {
+ int value = input.read();
+
+ if( -1 == value ) {
+ throw new EOFException( "Unexpected EOF reached" );
+ }
+
+ return value;
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/FileCleaner.java b/emailcommon/src/org/apache/commons/io/FileCleaner.java new file mode 100644 index 000000000..59c2f4109 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FileCleaner.java @@ -0,0 +1,154 @@ +/*
+ * 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.File;
+
+/**
+ * Keeps track of files awaiting deletion, and deletes them when an associated
+ * marker object is reclaimed by the garbage collector.
+ * <p>
+ * This utility creates a background thread to handle file deletion.
+ * Each file to be deleted is registered with a handler object.
+ * When the handler object is garbage collected, the file is deleted.
+ * <p>
+ * In an environment with multiple class loaders (a servlet container, for
+ * example), you should consider stopping the background thread if it is no
+ * longer needed. This is done by invoking the method
+ * {@link #exitWhenFinished}, typically in
+ * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
+ *
+ * @author Noel Bergman
+ * @author Martin Cooper
+ * @version $Id: FileCleaner.java 553012 2007-07-03 23:01:07Z ggregory $
+ * @deprecated Use {@link FileCleaningTracker}
+ */
+public class FileCleaner {
+ /**
+ * The instance to use for the deprecated, static methods.
+ */
+ static final FileCleaningTracker theInstance = new FileCleaningTracker();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the file is null
+ * @deprecated Use {@link FileCleaningTracker#track(File, Object)}.
+ */
+ public static void track(File file, Object marker) {
+ theInstance.track(file, marker);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the file is null
+ * @deprecated Use {@link FileCleaningTracker#track(File, Object, FileDeleteStrategy)}.
+ */
+ public static void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
+ theInstance.track(file, marker, deleteStrategy);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the path is null
+ * @deprecated Use {@link FileCleaningTracker#track(String, Object)}.
+ */
+ public static void track(String path, Object marker) {
+ theInstance.track(path, marker);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the path is null
+ * @deprecated Use {@link FileCleaningTracker#track(String, Object, FileDeleteStrategy)}.
+ */
+ public static void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
+ theInstance.track(path, marker, deleteStrategy);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Retrieve the number of files currently being tracked, and therefore
+ * awaiting deletion.
+ *
+ * @return the number of files being tracked
+ * @deprecated Use {@link FileCleaningTracker#getTrackCount()}.
+ */
+ public static int getTrackCount() {
+ return theInstance.getTrackCount();
+ }
+
+ /**
+ * Call this method to cause the file cleaner thread to terminate when
+ * there are no more objects being tracked for deletion.
+ * <p>
+ * In a simple environment, you don't need this method as the file cleaner
+ * thread will simply exit when the JVM exits. In a more complex environment,
+ * with multiple class loaders (such as an application server), you should be
+ * aware that the file cleaner thread will continue running even if the class
+ * loader it was started from terminates. This can consitute a memory leak.
+ * <p>
+ * For example, suppose that you have developed a web application, which
+ * contains the commons-io jar file in your WEB-INF/lib directory. In other
+ * words, the FileCleaner class is loaded through the class loader of your
+ * web application. If the web application is terminated, but the servlet
+ * container is still running, then the file cleaner thread will still exist,
+ * posing a memory leak.
+ * <p>
+ * This method allows the thread to be terminated. Simply call this method
+ * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}.
+ * One called, no new objects can be tracked by the file cleaner.
+ * @deprecated Use {@link FileCleaningTracker#exitWhenFinished()}.
+ */
+ public static synchronized void exitWhenFinished() {
+ theInstance.exitWhenFinished();
+ }
+
+ /**
+ * Returns the singleton instance, which is used by the deprecated, static methods.
+ * This is mainly useful for code, which wants to support the new
+ * {@link FileCleaningTracker} class while maintain compatibility with the
+ * deprecated {@link FileCleaner}.
+ *
+ * @return the singleton instance
+ */
+ public static FileCleaningTracker getInstance() {
+ return theInstance;
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/FileCleaningTracker.java b/emailcommon/src/org/apache/commons/io/FileCleaningTracker.java new file mode 100644 index 000000000..4074e6a76 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FileCleaningTracker.java @@ -0,0 +1,259 @@ +/*
+ * 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.File;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Collection;
+import java.util.Vector;
+
+/**
+ * Keeps track of files awaiting deletion, and deletes them when an associated
+ * marker object is reclaimed by the garbage collector.
+ * <p>
+ * This utility creates a background thread to handle file deletion.
+ * Each file to be deleted is registered with a handler object.
+ * When the handler object is garbage collected, the file is deleted.
+ * <p>
+ * In an environment with multiple class loaders (a servlet container, for
+ * example), you should consider stopping the background thread if it is no
+ * longer needed. This is done by invoking the method
+ * {@link #exitWhenFinished}, typically in
+ * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
+ *
+ * @author Noel Bergman
+ * @author Martin Cooper
+ * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $
+ */
+public class FileCleaningTracker {
+ /**
+ * Queue of <code>Tracker</code> instances being watched.
+ */
+ ReferenceQueue<Object> /* Tracker */ q = new ReferenceQueue<Object>();
+ /**
+ * Collection of <code>Tracker</code> instances in existence.
+ */
+ final Collection<Tracker> /* Tracker */ trackers = new Vector<Tracker>(); // synchronized
+ /**
+ * Whether to terminate the thread when the tracking is complete.
+ */
+ volatile boolean exitWhenFinished = false;
+ /**
+ * The thread that will clean up registered files.
+ */
+ Thread reaper;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the file is null
+ */
+ public void track(File file, Object marker) {
+ track(file, marker, (FileDeleteStrategy) null);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the file is null
+ */
+ public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
+ if (file == null) {
+ throw new NullPointerException("The file must not be null");
+ }
+ addTracker(file.getPath(), marker, deleteStrategy);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the path is null
+ */
+ public void track(String path, Object marker) {
+ track(path, marker, (FileDeleteStrategy) null);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the path is null
+ */
+ public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
+ if (path == null) {
+ throw new NullPointerException("The path must not be null");
+ }
+ addTracker(path, marker, deleteStrategy);
+ }
+
+ /**
+ * Adds a tracker to the list of trackers.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ */
+ private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) {
+ // synchronized block protects reaper
+ if (exitWhenFinished) {
+ throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
+ }
+ if (reaper == null) {
+ reaper = new Reaper();
+ reaper.start();
+ }
+ trackers.add(new Tracker(path, deleteStrategy, marker, q));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Retrieve the number of files currently being tracked, and therefore
+ * awaiting deletion.
+ *
+ * @return the number of files being tracked
+ */
+ public int getTrackCount() {
+ return trackers.size();
+ }
+
+ /**
+ * Call this method to cause the file cleaner thread to terminate when
+ * there are no more objects being tracked for deletion.
+ * <p>
+ * In a simple environment, you don't need this method as the file cleaner
+ * thread will simply exit when the JVM exits. In a more complex environment,
+ * with multiple class loaders (such as an application server), you should be
+ * aware that the file cleaner thread will continue running even if the class
+ * loader it was started from terminates. This can consitute a memory leak.
+ * <p>
+ * For example, suppose that you have developed a web application, which
+ * contains the commons-io jar file in your WEB-INF/lib directory. In other
+ * words, the FileCleaner class is loaded through the class loader of your
+ * web application. If the web application is terminated, but the servlet
+ * container is still running, then the file cleaner thread will still exist,
+ * posing a memory leak.
+ * <p>
+ * This method allows the thread to be terminated. Simply call this method
+ * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}.
+ * One called, no new objects can be tracked by the file cleaner.
+ */
+ public synchronized void exitWhenFinished() {
+ // synchronized block protects reaper
+ exitWhenFinished = true;
+ if (reaper != null) {
+ synchronized (reaper) {
+ reaper.interrupt();
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * The reaper thread.
+ */
+ private final class Reaper extends Thread {
+ /** Construct a new Reaper */
+ Reaper() {
+ super("File Reaper");
+ setPriority(Thread.MAX_PRIORITY);
+ setDaemon(true);
+ }
+
+ /**
+ * Run the reaper thread that will delete files as their associated
+ * marker objects are reclaimed by the garbage collector.
+ */
+ @Override
+ public void run() {
+ // thread exits when exitWhenFinished is true and there are no more tracked objects
+ while (exitWhenFinished == false || trackers.size() > 0) {
+ Tracker tracker = null;
+ try {
+ // Wait for a tracker to remove.
+ tracker = (Tracker) q.remove();
+ } catch (Exception e) {
+ continue;
+ }
+ if (tracker != null) {
+ tracker.delete();
+ tracker.clear();
+ trackers.remove(tracker);
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class which acts as the reference for a file pending deletion.
+ */
+ private static final class Tracker extends PhantomReference<Object> {
+
+ /**
+ * The full path to the file being tracked.
+ */
+ private final String path;
+ /**
+ * The strategy for deleting files.
+ */
+ private final FileDeleteStrategy deleteStrategy;
+
+ /**
+ * Constructs an instance of this class from the supplied parameters.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @param marker the marker object used to track the file, not null
+ * @param queue the queue on to which the tracker will be pushed, not null
+ */
+ Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue<Object> queue) {
+ super(marker, queue);
+ this.path = path;
+ this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy);
+ }
+
+ /**
+ * Deletes the file associated with this tracker instance.
+ *
+ * @return <code>true</code> if the file was deleted successfully;
+ * <code>false</code> otherwise.
+ */
+ public boolean delete() {
+ return deleteStrategy.deleteQuietly(new File(path));
+ }
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/FileDeleteStrategy.java b/emailcommon/src/org/apache/commons/io/FileDeleteStrategy.java new file mode 100644 index 000000000..8b6b4b9aa --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FileDeleteStrategy.java @@ -0,0 +1,156 @@ +/*
+ * 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.File;
+import java.io.IOException;
+
+/**
+ * Strategy for deleting files.
+ * <p>
+ * There is more than one way to delete a file.
+ * You may want to limit access to certain directories, to only delete
+ * directories if they are empty, or maybe to force deletion.
+ * <p>
+ * This class captures the strategy to use and is designed for user subclassing.
+ *
+ * @author Stephen Colebourne
+ * @version $Id: FileDeleteStrategy.java 453903 2006-10-07 13:47:06Z scolebourne $
+ * @since Commons IO 1.3
+ */
+public class FileDeleteStrategy {
+
+ /**
+ * The singleton instance for normal file deletion, which does not permit
+ * the deletion of directories that are not empty.
+ */
+ public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal");
+ /**
+ * The singleton instance for forced file deletion, which always deletes,
+ * even if the file represents a non-empty directory.
+ */
+ public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy();
+
+ /** The name of the strategy. */
+ private final String name;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Restricted constructor.
+ *
+ * @param name the name by which the strategy is known
+ */
+ protected FileDeleteStrategy(String name) {
+ this.name = name;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Deletes the file object, which may be a file or a directory.
+ * All <code>IOException</code>s are caught and false returned instead.
+ * If the file does not exist or is null, true is returned.
+ * <p>
+ * Subclass writers should override {@link #doDelete(File)}, not this method.
+ *
+ * @param fileToDelete the file to delete, null returns true
+ * @return true if the file was deleted, or there was no such file
+ */
+ public boolean deleteQuietly(File fileToDelete) {
+ if (fileToDelete == null || fileToDelete.exists() == false) {
+ return true;
+ }
+ try {
+ return doDelete(fileToDelete);
+ } catch (IOException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Deletes the file object, which may be a file or a directory.
+ * If the file does not exist, the method just returns.
+ * <p>
+ * Subclass writers should override {@link #doDelete(File)}, not this method.
+ *
+ * @param fileToDelete the file to delete, not null
+ * @throws NullPointerException if the file is null
+ * @throws IOException if an error occurs during file deletion
+ */
+ public void delete(File fileToDelete) throws IOException {
+ if (fileToDelete.exists() && doDelete(fileToDelete) == false) {
+ throw new IOException("Deletion failed: " + fileToDelete);
+ }
+ }
+
+ /**
+ * Actually deletes the file object, which may be a file or a directory.
+ * <p>
+ * This method is designed for subclasses to override.
+ * The implementation may return either false or an <code>IOException</code>
+ * when deletion fails. The {@link #delete(File)} and {@link #deleteQuietly(File)}
+ * methods will handle either response appropriately.
+ * A check has been made to ensure that the file will exist.
+ * <p>
+ * This implementation uses {@link File#delete()}.
+ *
+ * @param fileToDelete the file to delete, exists, not null
+ * @return true if the file was deleteds
+ * @throws NullPointerException if the file is null
+ * @throws IOException if an error occurs during file deletion
+ */
+ protected boolean doDelete(File fileToDelete) throws IOException {
+ return fileToDelete.delete();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets a string describing the delete strategy.
+ *
+ * @return a string describing the delete strategy
+ */
+ public String toString() {
+ return "FileDeleteStrategy[" + name + "]";
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Force file deletion strategy.
+ */
+ static class ForceFileDeleteStrategy extends FileDeleteStrategy {
+ /** Default Constructor */
+ ForceFileDeleteStrategy() {
+ super("Force");
+ }
+
+ /**
+ * Deletes the file object.
+ * <p>
+ * This implementation uses <code>FileUtils.forceDelete() <code>
+ * if the file exists.
+ *
+ * @param fileToDelete the file to delete, not null
+ * @return Always returns <code>true</code>
+ * @throws NullPointerException if the file is null
+ * @throws IOException if an error occurs during file deletion
+ */
+ protected boolean doDelete(File fileToDelete) throws IOException {
+ FileUtils.forceDelete(fileToDelete);
+ return true;
+ }
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/FileSystemUtils.java b/emailcommon/src/org/apache/commons/io/FileSystemUtils.java new file mode 100644 index 000000000..1765976c4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FileSystemUtils.java @@ -0,0 +1,457 @@ +/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * General File System utilities.
+ * <p>
+ * This class provides static utility methods for general file system
+ * functions not provided via the JDK {@link java.io.File File} class.
+ * <p>
+ * The current functions provided are:
+ * <ul>
+ * <li>Get the free space on a drive
+ * </ul>
+ *
+ * @author Frank W. Zammetti
+ * @author Stephen Colebourne
+ * @author Thomas Ledoux
+ * @author James Urie
+ * @author Magnus Grimsell
+ * @author Thomas Ledoux
+ * @version $Id: FileSystemUtils.java 453889 2006-10-07 11:56:25Z scolebourne $
+ * @since Commons IO 1.1
+ */
+public class FileSystemUtils {
+
+ /** Singleton instance, used mainly for testing. */
+ private static final FileSystemUtils INSTANCE = new FileSystemUtils();
+
+ /** Operating system state flag for error. */
+ private static final int INIT_PROBLEM = -1;
+ /** Operating system state flag for neither Unix nor Windows. */
+ private static final int OTHER = 0;
+ /** Operating system state flag for Windows. */
+ private static final int WINDOWS = 1;
+ /** Operating system state flag for Unix. */
+ private static final int UNIX = 2;
+ /** Operating system state flag for Posix flavour Unix. */
+ private static final int POSIX_UNIX = 3;
+
+ /** The operating system flag. */
+ private static final int OS;
+ static {
+ int os = OTHER;
+ try {
+ String osName = System.getProperty("os.name");
+ if (osName == null) {
+ throw new IOException("os.name not found");
+ }
+ osName = osName.toLowerCase();
+ // match
+ if (osName.indexOf("windows") != -1) {
+ os = WINDOWS;
+ } else if (osName.indexOf("linux") != -1 ||
+ osName.indexOf("sun os") != -1 ||
+ osName.indexOf("sunos") != -1 ||
+ osName.indexOf("solaris") != -1 ||
+ osName.indexOf("mpe/ix") != -1 ||
+ osName.indexOf("freebsd") != -1 ||
+ osName.indexOf("irix") != -1 ||
+ osName.indexOf("digital unix") != -1 ||
+ osName.indexOf("unix") != -1 ||
+ osName.indexOf("mac os x") != -1) {
+ os = UNIX;
+ } else if (osName.indexOf("hp-ux") != -1 ||
+ osName.indexOf("aix") != -1) {
+ os = POSIX_UNIX;
+ } else {
+ os = OTHER;
+ }
+
+ } catch (Exception ex) {
+ os = INIT_PROBLEM;
+ }
+ OS = os;
+ }
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public FileSystemUtils() {
+ super();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the free space on a drive or volume by invoking
+ * the command line.
+ * This method does not normalize the result, and typically returns
+ * bytes on Windows, 512 byte units on OS X and kilobytes on Unix.
+ * As this is not very useful, this method is deprecated in favour
+ * of {@link #freeSpaceKb(String)} which returns a result in kilobytes.
+ * <p>
+ * Note that some OS's are NOT currently supported, including OS/390,
+ * OpenVMS and and SunOS 5. (SunOS is supported by <code>freeSpaceKb</code>.)
+ * <pre>
+ * FileSystemUtils.freeSpace("C:"); // Windows
+ * FileSystemUtils.freeSpace("/volume"); // *nix
+ * </pre>
+ * The free space is calculated via the command line.
+ * It uses 'dir /-c' on Windows and 'df' on *nix.
+ *
+ * @param path the path to get free space for, not null, not empty on Unix
+ * @return the amount of free drive space on the drive or volume
+ * @throws IllegalArgumentException if the path is invalid
+ * @throws IllegalStateException if an error occurred in initialisation
+ * @throws IOException if an error occurs when finding the free space
+ * @since Commons IO 1.1, enhanced OS support in 1.2 and 1.3
+ * @deprecated Use freeSpaceKb(String)
+ * Deprecated from 1.3, may be removed in 2.0
+ */
+ public static long freeSpace(String path) throws IOException {
+ return INSTANCE.freeSpaceOS(path, OS, false);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the free space on a drive or volume in kilobytes by invoking
+ * the command line.
+ * <pre>
+ * FileSystemUtils.freeSpaceKb("C:"); // Windows
+ * FileSystemUtils.freeSpaceKb("/volume"); // *nix
+ * </pre>
+ * The free space is calculated via the command line.
+ * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix.
+ * <p>
+ * In order to work, you must be running Windows, or have a implementation of
+ * Unix df that supports GNU format when passed -k (or -kP). If you are going
+ * to rely on this code, please check that it works on your OS by running
+ * some simple tests to compare the command line with the output from this class.
+ * If your operating system isn't supported, please raise a JIRA call detailing
+ * the exact result from df -k and as much other detail as possible, thanks.
+ *
+ * @param path the path to get free space for, not null, not empty on Unix
+ * @return the amount of free drive space on the drive or volume in kilobytes
+ * @throws IllegalArgumentException if the path is invalid
+ * @throws IllegalStateException if an error occurred in initialisation
+ * @throws IOException if an error occurs when finding the free space
+ * @since Commons IO 1.2, enhanced OS support in 1.3
+ */
+ public static long freeSpaceKb(String path) throws IOException {
+ return INSTANCE.freeSpaceOS(path, OS, true);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the free space on a drive or volume in a cross-platform manner.
+ * Note that some OS's are NOT currently supported, including OS/390.
+ * <pre>
+ * FileSystemUtils.freeSpace("C:"); // Windows
+ * FileSystemUtils.freeSpace("/volume"); // *nix
+ * </pre>
+ * The free space is calculated via the command line.
+ * It uses 'dir /-c' on Windows and 'df' on *nix.
+ *
+ * @param path the path to get free space for, not null, not empty on Unix
+ * @param os the operating system code
+ * @param kb whether to normalize to kilobytes
+ * @return the amount of free drive space on the drive or volume
+ * @throws IllegalArgumentException if the path is invalid
+ * @throws IllegalStateException if an error occurred in initialisation
+ * @throws IOException if an error occurs when finding the free space
+ */
+ long freeSpaceOS(String path, int os, boolean kb) throws IOException {
+ if (path == null) {
+ throw new IllegalArgumentException("Path must not be empty");
+ }
+ switch (os) {
+ case WINDOWS:
+ return (kb ? freeSpaceWindows(path) / 1024 : freeSpaceWindows(path));
+ case UNIX:
+ return freeSpaceUnix(path, kb, false);
+ case POSIX_UNIX:
+ return freeSpaceUnix(path, kb, true);
+ case OTHER:
+ throw new IllegalStateException("Unsupported operating system");
+ default:
+ throw new IllegalStateException(
+ "Exception caught when determining operating system");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Find free space on the Windows platform using the 'dir' command.
+ *
+ * @param path the path to get free space for, including the colon
+ * @return the amount of free drive space on the drive
+ * @throws IOException if an error occurs
+ */
+ long freeSpaceWindows(String path) throws IOException {
+ path = FilenameUtils.normalize(path);
+ if (path.length() > 2 && path.charAt(1) == ':') {
+ path = path.substring(0, 2); // seems to make it work
+ }
+
+ // build and run the 'dir' command
+ String[] cmdAttribs = new String[] {"cmd.exe", "/C", "dir /-c " + path};
+
+ // read in the output of the command to an ArrayList
+ List<String> lines = performCommand(cmdAttribs, Integer.MAX_VALUE);
+
+ // now iterate over the lines we just read and find the LAST
+ // non-empty line (the free space bytes should be in the last element
+ // of the ArrayList anyway, but this will ensure it works even if it's
+ // not, still assuming it is on the last non-blank line)
+ for (int i = lines.size() - 1; i >= 0; i--) {
+ String line = lines.get(i);
+ if (line.length() > 0) {
+ return parseDir(line, path);
+ }
+ }
+ // all lines are blank
+ throw new IOException(
+ "Command line 'dir /-c' did not return any info " +
+ "for path '" + path + "'");
+ }
+
+ /**
+ * Parses the Windows dir response last line
+ *
+ * @param line the line to parse
+ * @param path the path that was sent
+ * @return the number of bytes
+ * @throws IOException if an error occurs
+ */
+ long parseDir(String line, String path) throws IOException {
+ // read from the end of the line to find the last numeric
+ // character on the line, then continue until we find the first
+ // non-numeric character, and everything between that and the last
+ // numeric character inclusive is our free space bytes count
+ int bytesStart = 0;
+ int bytesEnd = 0;
+ int j = line.length() - 1;
+ innerLoop1: while (j >= 0) {
+ char c = line.charAt(j);
+ if (Character.isDigit(c)) {
+ // found the last numeric character, this is the end of
+ // the free space bytes count
+ bytesEnd = j + 1;
+ break innerLoop1;
+ }
+ j--;
+ }
+ innerLoop2: while (j >= 0) {
+ char c = line.charAt(j);
+ if (!Character.isDigit(c) && c != ',' && c != '.') {
+ // found the next non-numeric character, this is the
+ // beginning of the free space bytes count
+ bytesStart = j + 1;
+ break innerLoop2;
+ }
+ j--;
+ }
+ if (j < 0) {
+ throw new IOException(
+ "Command line 'dir /-c' did not return valid info " +
+ "for path '" + path + "'");
+ }
+
+ // remove commas and dots in the bytes count
+ StringBuffer buf = new StringBuffer(line.substring(bytesStart, bytesEnd));
+ for (int k = 0; k < buf.length(); k++) {
+ if (buf.charAt(k) == ',' || buf.charAt(k) == '.') {
+ buf.deleteCharAt(k--);
+ }
+ }
+ return parseBytes(buf.toString(), path);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Find free space on the *nix platform using the 'df' command.
+ *
+ * @param path the path to get free space for
+ * @param kb whether to normalize to kilobytes
+ * @param posix whether to use the posix standard format flag
+ * @return the amount of free drive space on the volume
+ * @throws IOException if an error occurs
+ */
+ long freeSpaceUnix(String path, boolean kb, boolean posix) throws IOException {
+ if (path.length() == 0) {
+ throw new IllegalArgumentException("Path must not be empty");
+ }
+ path = FilenameUtils.normalize(path);
+
+ // build and run the 'dir' command
+ String flags = "-";
+ if (kb) {
+ flags += "k";
+ }
+ if (posix) {
+ flags += "P";
+ }
+ String[] cmdAttribs =
+ (flags.length() > 1 ? new String[] {"df", flags, path} : new String[] {"df", path});
+
+ // perform the command, asking for up to 3 lines (header, interesting, overflow)
+ List<String> lines = performCommand(cmdAttribs, 3);
+ if (lines.size() < 2) {
+ // unknown problem, throw exception
+ throw new IOException(
+ "Command line 'df' did not return info as expected " +
+ "for path '" + path + "'- response was " + lines);
+ }
+ String line2 = lines.get(1); // the line we're interested in
+
+ // Now, we tokenize the string. The fourth element is what we want.
+ StringTokenizer tok = new StringTokenizer(line2, " ");
+ if (tok.countTokens() < 4) {
+ // could be long Filesystem, thus data on third line
+ if (tok.countTokens() == 1 && lines.size() >= 3) {
+ String line3 = lines.get(2); // the line may be interested in
+ tok = new StringTokenizer(line3, " ");
+ } else {
+ throw new IOException(
+ "Command line 'df' did not return data as expected " +
+ "for path '" + path + "'- check path is valid");
+ }
+ } else {
+ tok.nextToken(); // Ignore Filesystem
+ }
+ tok.nextToken(); // Ignore 1K-blocks
+ tok.nextToken(); // Ignore Used
+ String freeSpace = tok.nextToken();
+ return parseBytes(freeSpace, path);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Parses the bytes from a string.
+ *
+ * @param freeSpace the free space string
+ * @param path the path
+ * @return the number of bytes
+ * @throws IOException if an error occurs
+ */
+ long parseBytes(String freeSpace, String path) throws IOException {
+ try {
+ long bytes = Long.parseLong(freeSpace);
+ if (bytes < 0) {
+ throw new IOException(
+ "Command line 'df' did not find free space in response " +
+ "for path '" + path + "'- check path is valid");
+ }
+ return bytes;
+
+ } catch (NumberFormatException ex) {
+ throw new IOException(
+ "Command line 'df' did not return numeric data as expected " +
+ "for path '" + path + "'- check path is valid");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Performs the os command.
+ *
+ * @param cmdAttribs the command line parameters
+ * @param max The maximum limit for the lines returned
+ * @return the parsed data
+ * @throws IOException if an error occurs
+ */
+ List<String> performCommand(String[] cmdAttribs, int max) throws IOException {
+ // this method does what it can to avoid the 'Too many open files' error
+ // based on trial and error and these links:
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801027
+ // http://forum.java.sun.com/thread.jspa?threadID=533029&messageID=2572018
+ // however, its still not perfect as the JDK support is so poor
+ // (see commond-exec or ant for a better multi-threaded multi-os solution)
+
+ List<String> lines = new ArrayList<String>(20);
+ Process proc = null;
+ InputStream in = null;
+ OutputStream out = null;
+ InputStream err = null;
+ BufferedReader inr = null;
+ try {
+ proc = openProcess(cmdAttribs);
+ in = proc.getInputStream();
+ out = proc.getOutputStream();
+ err = proc.getErrorStream();
+ inr = new BufferedReader(new InputStreamReader(in));
+ String line = inr.readLine();
+ while (line != null && lines.size() < max) {
+ line = line.toLowerCase().trim();
+ lines.add(line);
+ line = inr.readLine();
+ }
+
+ proc.waitFor();
+ if (proc.exitValue() != 0) {
+ // os command problem, throw exception
+ throw new IOException(
+ "Command line returned OS error code '" + proc.exitValue() +
+ "' for command " + Arrays.asList(cmdAttribs));
+ }
+ if (lines.size() == 0) {
+ // unknown problem, throw exception
+ throw new IOException(
+ "Command line did not return any info " +
+ "for command " + Arrays.asList(cmdAttribs));
+ }
+ return lines;
+
+ } catch (InterruptedException ex) {
+ throw new IOException(
+ "Command line threw an InterruptedException '" + ex.getMessage() +
+ "' for command " + Arrays.asList(cmdAttribs));
+ } finally {
+ IOUtils.closeQuietly(in);
+ IOUtils.closeQuietly(out);
+ IOUtils.closeQuietly(err);
+ IOUtils.closeQuietly(inr);
+ if (proc != null) {
+ proc.destroy();
+ }
+ }
+ }
+
+ /**
+ * Opens the process to the operating system.
+ *
+ * @param cmdAttribs the command line parameters
+ * @return the process
+ * @throws IOException if an error occurs
+ */
+ Process openProcess(String[] cmdAttribs) throws IOException {
+ return Runtime.getRuntime().exec(cmdAttribs);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/FileUtils.java b/emailcommon/src/org/apache/commons/io/FileUtils.java new file mode 100644 index 000000000..d5de771c7 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FileUtils.java @@ -0,0 +1,1890 @@ +/*
+ * 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.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
+import java.util.zip.Checksum;
+
+import org.apache.commons.io.filefilter.DirectoryFileFilter;
+import org.apache.commons.io.filefilter.FalseFileFilter;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.filefilter.SuffixFileFilter;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.apache.commons.io.output.NullOutputStream;
+
+/**
+ * General file manipulation utilities.
+ * <p>
+ * Facilities are provided in the following areas:
+ * <ul>
+ * <li>writing to a file
+ * <li>reading from a file
+ * <li>make a directory including parent directories
+ * <li>copying files and directories
+ * <li>deleting files and directories
+ * <li>converting to and from a URL
+ * <li>listing files and directories by filter and extension
+ * <li>comparing file content
+ * <li>file last changed date
+ * <li>calculating a checksum
+ * </ul>
+ * <p>
+ * Origin of code: Excalibur, Alexandria, Commons-Utils
+ *
+ * @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A>
+ * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph.Reck</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
+ * @author Matthew Hawthorne
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @author Stephen Colebourne
+ * @author Ian Springer
+ * @author Chris Eldredge
+ * @author Jim Harrington
+ * @author Niall Pemberton
+ * @author Sandy McArthur
+ * @version $Id: FileUtils.java 610810 2008-01-10 15:04:49Z niallp $
+ */
+public class FileUtils {
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public FileUtils() {
+ super();
+ }
+
+ /**
+ * The number of bytes in a kilobyte.
+ */
+ public static final long ONE_KB = 1024;
+
+ /**
+ * The number of bytes in a megabyte.
+ */
+ public static final long ONE_MB = ONE_KB * ONE_KB;
+
+ /**
+ * The number of bytes in a gigabyte.
+ */
+ public static final long ONE_GB = ONE_KB * ONE_MB;
+
+ /**
+ * An empty array of type <code>File</code>.
+ */
+ public static final File[] EMPTY_FILE_ARRAY = new File[0];
+
+ //-----------------------------------------------------------------------
+ /**
+ * Opens a {@link FileInputStream} for the specified file, providing better
+ * error messages than simply calling <code>new FileInputStream(file)</code>.
+ * <p>
+ * At the end of the method either the stream will be successfully opened,
+ * or an exception will have been thrown.
+ * <p>
+ * An exception is thrown if the file does not exist.
+ * An exception is thrown if the file object exists but is a directory.
+ * An exception is thrown if the file exists but cannot be read.
+ *
+ * @param file the file to open for input, must not be <code>null</code>
+ * @return a new {@link FileInputStream} for the specified file
+ * @throws FileNotFoundException if the file does not exist
+ * @throws IOException if the file object is a directory
+ * @throws IOException if the file cannot be read
+ * @since Commons IO 1.3
+ */
+ public static FileInputStream openInputStream(File file) throws IOException {
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ throw new IOException("File '" + file + "' exists but is a directory");
+ }
+ if (file.canRead() == false) {
+ throw new IOException("File '" + file + "' cannot be read");
+ }
+ } else {
+ throw new FileNotFoundException("File '" + file + "' does not exist");
+ }
+ return new FileInputStream(file);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Opens a {@link FileOutputStream} for the specified file, checking and
+ * creating the parent directory if it does not exist.
+ * <p>
+ * At the end of the method either the stream will be successfully opened,
+ * or an exception will have been thrown.
+ * <p>
+ * The parent directory will be created if it does not exist.
+ * The file will be created if it does not exist.
+ * An exception is thrown if the file object exists but is a directory.
+ * An exception is thrown if the file exists but cannot be written to.
+ * An exception is thrown if the parent directory cannot be created.
+ *
+ * @param file the file to open for output, must not be <code>null</code>
+ * @return a new {@link FileOutputStream} for the specified file
+ * @throws IOException if the file object is a directory
+ * @throws IOException if the file cannot be written to
+ * @throws IOException if a parent directory needs creating but that fails
+ * @since Commons IO 1.3
+ */
+ public static FileOutputStream openOutputStream(File file) throws IOException {
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ throw new IOException("File '" + file + "' exists but is a directory");
+ }
+ if (file.canWrite() == false) {
+ throw new IOException("File '" + file + "' cannot be written to");
+ }
+ } else {
+ File parent = file.getParentFile();
+ if (parent != null && parent.exists() == false) {
+ if (parent.mkdirs() == false) {
+ throw new IOException("File '" + file + "' could not be created");
+ }
+ }
+ }
+ return new FileOutputStream(file);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a human-readable version of the file size, where the input
+ * represents a specific number of bytes.
+ *
+ * @param size the number of bytes
+ * @return a human-readable display value (includes units)
+ */
+ public static String byteCountToDisplaySize(long size) {
+ String displaySize;
+
+ if (size / ONE_GB > 0) {
+ displaySize = String.valueOf(size / ONE_GB) + " GB";
+ } else if (size / ONE_MB > 0) {
+ displaySize = String.valueOf(size / ONE_MB) + " MB";
+ } else if (size / ONE_KB > 0) {
+ displaySize = String.valueOf(size / ONE_KB) + " KB";
+ } else {
+ displaySize = String.valueOf(size) + " bytes";
+ }
+ return displaySize;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Implements the same behaviour as the "touch" utility on Unix. It creates
+ * a new file with size 0 or, if the file exists already, it is opened and
+ * closed without modifying it, but updating the file date and time.
+ * <p>
+ * NOTE: As from v1.3, this method throws an IOException if the last
+ * modified date of the file cannot be set. Also, as from v1.3 this method
+ * creates parent directories if they do not exist.
+ *
+ * @param file the File to touch
+ * @throws IOException If an I/O problem occurs
+ */
+ public static void touch(File file) throws IOException {
+ if (!file.exists()) {
+ OutputStream out = openOutputStream(file);
+ IOUtils.closeQuietly(out);
+ }
+ boolean success = file.setLastModified(System.currentTimeMillis());
+ if (!success) {
+ throw new IOException("Unable to set the last modification time for " + file);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts a Collection containing java.io.File instanced into array
+ * representation. This is to account for the difference between
+ * File.listFiles() and FileUtils.listFiles().
+ *
+ * @param files a Collection containing java.io.File instances
+ * @return an array of java.io.File
+ */
+ public static File[] convertFileCollectionToFileArray(Collection<File> files) {
+ return files.toArray(new File[files.size()]);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Finds files within a given directory (and optionally its
+ * subdirectories). All files found are filtered by an IOFileFilter.
+ *
+ * @param files the collection of files found.
+ * @param directory the directory to search in.
+ * @param filter the filter to apply to files and directories.
+ */
+ private static void innerListFiles(Collection<File> files, File directory,
+ IOFileFilter filter) {
+ File[] found = directory.listFiles((FileFilter) filter);
+ if (found != null) {
+ for (int i = 0; i < found.length; i++) {
+ if (found[i].isDirectory()) {
+ innerListFiles(files, found[i], filter);
+ } else {
+ files.add(found[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds files within a given directory (and optionally its
+ * subdirectories). All files found are filtered by an IOFileFilter.
+ * <p>
+ * If your search should recurse into subdirectories you can pass in
+ * an IOFileFilter for directories. You don't need to bind a
+ * DirectoryFileFilter (via logical AND) to this filter. This method does
+ * that for you.
+ * <p>
+ * An example: If you want to search through all directories called
+ * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code>
+ * <p>
+ * Another common usage of this method is find files in a directory
+ * tree but ignoring the directories generated CVS. You can simply pass
+ * in <code>FileFilterUtils.makeCVSAware(null)</code>.
+ *
+ * @param directory the directory to search in
+ * @param fileFilter filter to apply when finding files.
+ * @param dirFilter optional filter to apply when finding subdirectories.
+ * If this parameter is <code>null</code>, subdirectories will not be included in the
+ * search. Use TrueFileFilter.INSTANCE to match all directories.
+ * @return an collection of java.io.File with the matching files
+ * @see org.apache.commons.io.filefilter.FileFilterUtils
+ * @see org.apache.commons.io.filefilter.NameFileFilter
+ */
+ public static Collection<File> listFiles(
+ File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
+ if (!directory.isDirectory()) {
+ throw new IllegalArgumentException(
+ "Parameter 'directory' is not a directory");
+ }
+ if (fileFilter == null) {
+ throw new NullPointerException("Parameter 'fileFilter' is null");
+ }
+
+ //Setup effective file filter
+ IOFileFilter effFileFilter = FileFilterUtils.andFileFilter(fileFilter,
+ FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE));
+
+ //Setup effective directory filter
+ IOFileFilter effDirFilter;
+ if (dirFilter == null) {
+ effDirFilter = FalseFileFilter.INSTANCE;
+ } else {
+ effDirFilter = FileFilterUtils.andFileFilter(dirFilter,
+ DirectoryFileFilter.INSTANCE);
+ }
+
+ //Find files
+ Collection<File> files = new java.util.LinkedList<File>();
+ innerListFiles(files, directory,
+ FileFilterUtils.orFileFilter(effFileFilter, effDirFilter));
+ return files;
+ }
+
+ /**
+ * Allows iteration over the files in given directory (and optionally
+ * its subdirectories).
+ * <p>
+ * All files found are filtered by an IOFileFilter. This method is
+ * based on {@link #listFiles(File, IOFileFilter, IOFileFilter)}.
+ *
+ * @param directory the directory to search in
+ * @param fileFilter filter to apply when finding files.
+ * @param dirFilter optional filter to apply when finding subdirectories.
+ * If this parameter is <code>null</code>, subdirectories will not be included in the
+ * search. Use TrueFileFilter.INSTANCE to match all directories.
+ * @return an iterator of java.io.File for the matching files
+ * @see org.apache.commons.io.filefilter.FileFilterUtils
+ * @see org.apache.commons.io.filefilter.NameFileFilter
+ * @since Commons IO 1.2
+ */
+ public static Iterator<File> iterateFiles(
+ File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
+ return listFiles(directory, fileFilter, dirFilter).iterator();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts an array of file extensions to suffixes for use
+ * with IOFileFilters.
+ *
+ * @param extensions an array of extensions. Format: {"java", "xml"}
+ * @return an array of suffixes. Format: {".java", ".xml"}
+ */
+ private static String[] toSuffixes(String[] extensions) {
+ String[] suffixes = new String[extensions.length];
+ for (int i = 0; i < extensions.length; i++) {
+ suffixes[i] = "." + extensions[i];
+ }
+ return suffixes;
+ }
+
+
+ /**
+ * Finds files within a given directory (and optionally its subdirectories)
+ * which match an array of extensions.
+ *
+ * @param directory the directory to search in
+ * @param extensions an array of extensions, ex. {"java","xml"}. If this
+ * parameter is <code>null</code>, all files are returned.
+ * @param recursive if true all subdirectories are searched as well
+ * @return an collection of java.io.File with the matching files
+ */
+ public static Collection<File> listFiles(
+ File directory, String[] extensions, boolean recursive) {
+ IOFileFilter filter;
+ if (extensions == null) {
+ filter = TrueFileFilter.INSTANCE;
+ } else {
+ String[] suffixes = toSuffixes(extensions);
+ filter = new SuffixFileFilter(suffixes);
+ }
+ return listFiles(directory, filter,
+ (recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE));
+ }
+
+ /**
+ * Allows iteration over the files in a given directory (and optionally
+ * its subdirectories) which match an array of extensions. This method
+ * is based on {@link #listFiles(File, String[], boolean)}.
+ *
+ * @param directory the directory to search in
+ * @param extensions an array of extensions, ex. {"java","xml"}. If this
+ * parameter is <code>null</code>, all files are returned.
+ * @param recursive if true all subdirectories are searched as well
+ * @return an iterator of java.io.File with the matching files
+ * @since Commons IO 1.2
+ */
+ public static Iterator<File> iterateFiles(
+ File directory, String[] extensions, boolean recursive) {
+ return listFiles(directory, extensions, recursive).iterator();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares the contents of two files to determine if they are equal or not.
+ * <p>
+ * This method checks to see if the two files are different lengths
+ * or if they point to the same file, before resorting to byte-by-byte
+ * comparison of the contents.
+ * <p>
+ * Code origin: Avalon
+ *
+ * @param file1 the first file
+ * @param file2 the second file
+ * @return true if the content of the files are equal or they both don't
+ * exist, false otherwise
+ * @throws IOException in case of an I/O error
+ */
+ public static boolean contentEquals(File file1, File file2) throws IOException {
+ boolean file1Exists = file1.exists();
+ if (file1Exists != file2.exists()) {
+ return false;
+ }
+
+ if (!file1Exists) {
+ // two not existing files are equal
+ return true;
+ }
+
+ if (file1.isDirectory() || file2.isDirectory()) {
+ // don't want to compare directory contents
+ throw new IOException("Can't compare directories, only files");
+ }
+
+ if (file1.length() != file2.length()) {
+ // lengths differ, cannot be equal
+ return false;
+ }
+
+ if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
+ // same file
+ return true;
+ }
+
+ InputStream input1 = null;
+ InputStream input2 = null;
+ try {
+ input1 = new FileInputStream(file1);
+ input2 = new FileInputStream(file2);
+ return IOUtils.contentEquals(input1, input2);
+
+ } finally {
+ IOUtils.closeQuietly(input1);
+ IOUtils.closeQuietly(input2);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Convert from a <code>URL</code> to a <code>File</code>.
+ * <p>
+ * From version 1.1 this method will decode the URL.
+ * Syntax such as <code>file:///my%20docs/file.txt</code> will be
+ * correctly decoded to <code>/my docs/file.txt</code>.
+ *
+ * @param url the file URL to convert, <code>null</code> returns <code>null</code>
+ * @return the equivalent <code>File</code> object, or <code>null</code>
+ * if the URL's protocol is not <code>file</code>
+ * @throws IllegalArgumentException if the file is incorrectly encoded
+ */
+ public static File toFile(URL url) {
+ if (url == null || !url.getProtocol().equals("file")) {
+ return null;
+ } else {
+ String filename = url.getFile().replace('/', File.separatorChar);
+ int pos =0;
+ while ((pos = filename.indexOf('%', pos)) >= 0) {
+ if (pos + 2 < filename.length()) {
+ String hexStr = filename.substring(pos + 1, pos + 3);
+ char ch = (char) Integer.parseInt(hexStr, 16);
+ filename = filename.substring(0, pos) + ch + filename.substring(pos + 3);
+ }
+ }
+ return new File(filename);
+ }
+ }
+
+ /**
+ * Converts each of an array of <code>URL</code> to a <code>File</code>.
+ * <p>
+ * Returns an array of the same size as the input.
+ * If the input is <code>null</code>, an empty array is returned.
+ * If the input contains <code>null</code>, the output array contains <code>null</code> at the same
+ * index.
+ * <p>
+ * This method will decode the URL.
+ * Syntax such as <code>file:///my%20docs/file.txt</code> will be
+ * correctly decoded to <code>/my docs/file.txt</code>.
+ *
+ * @param urls the file URLs to convert, <code>null</code> returns empty array
+ * @return a non-<code>null</code> array of Files matching the input, with a <code>null</code> item
+ * if there was a <code>null</code> at that index in the input array
+ * @throws IllegalArgumentException if any file is not a URL file
+ * @throws IllegalArgumentException if any file is incorrectly encoded
+ * @since Commons IO 1.1
+ */
+ public static File[] toFiles(URL[] urls) {
+ if (urls == null || urls.length == 0) {
+ return EMPTY_FILE_ARRAY;
+ }
+ File[] files = new File[urls.length];
+ for (int i = 0; i < urls.length; i++) {
+ URL url = urls[i];
+ if (url != null) {
+ if (url.getProtocol().equals("file") == false) {
+ throw new IllegalArgumentException(
+ "URL could not be converted to a File: " + url);
+ }
+ files[i] = toFile(url);
+ }
+ }
+ return files;
+ }
+
+ /**
+ * Converts each of an array of <code>File</code> to a <code>URL</code>.
+ * <p>
+ * Returns an array of the same size as the input.
+ *
+ * @param files the files to convert
+ * @return an array of URLs matching the input
+ * @throws IOException if a file cannot be converted
+ */
+ public static URL[] toURLs(File[] files) throws IOException {
+ URL[] urls = new URL[files.length];
+
+ for (int i = 0; i < urls.length; i++) {
+ urls[i] = files[i].toURI().toURL();
+ }
+
+ return urls;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Copies a file to a directory preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file
+ * to a file of the same name in the specified destination directory.
+ * The destination directory is created if it does not exist.
+ * If the destination file exists, then this method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destDir the directory to place the copy in, must not be <code>null</code>
+ *
+ * @throws NullPointerException if source or destination is null
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFile(File, File, boolean)
+ */
+ public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
+ copyFileToDirectory(srcFile, destDir, true);
+ }
+
+ /**
+ * Copies a file to a directory optionally preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file
+ * to a file of the same name in the specified destination directory.
+ * The destination directory is created if it does not exist.
+ * If the destination file exists, then this method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destDir the directory to place the copy in, must not be <code>null</code>
+ * @param preserveFileDate true if the file date of the copy
+ * should be the same as the original
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFile(File, File, boolean)
+ * @since Commons IO 1.3
+ */
+ public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException {
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (destDir.exists() && destDir.isDirectory() == false) {
+ throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+ }
+ copyFile(srcFile, new File(destDir, srcFile.getName()), preserveFileDate);
+ }
+
+ /**
+ * Copies a file to a new location preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file to the
+ * specified destination file. The directory holding the destination file is
+ * created if it does not exist. If the destination file exists, then this
+ * method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destFile the new file, must not be <code>null</code>
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFileToDirectory(File, File)
+ */
+ public static void copyFile(File srcFile, File destFile) throws IOException {
+ copyFile(srcFile, destFile, true);
+ }
+
+ /**
+ * Copies a file to a new location.
+ * <p>
+ * This method copies the contents of the specified source file
+ * to the specified destination file.
+ * The directory holding the destination file is created if it does not exist.
+ * If the destination file exists, then this method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destFile the new file, must not be <code>null</code>
+ * @param preserveFileDate true if the file date of the copy
+ * should be the same as the original
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFileToDirectory(File, File, boolean)
+ */
+ public static void copyFile(File srcFile, File destFile,
+ boolean preserveFileDate) throws IOException {
+ if (srcFile == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destFile == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (srcFile.exists() == false) {
+ throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
+ }
+ if (srcFile.isDirectory()) {
+ throw new IOException("Source '" + srcFile + "' exists but is a directory");
+ }
+ if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
+ throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
+ }
+ if (destFile.getParentFile() != null && destFile.getParentFile().exists() == false) {
+ if (destFile.getParentFile().mkdirs() == false) {
+ throw new IOException("Destination '" + destFile + "' directory cannot be created");
+ }
+ }
+ if (destFile.exists() && destFile.canWrite() == false) {
+ throw new IOException("Destination '" + destFile + "' exists but is read-only");
+ }
+ doCopyFile(srcFile, destFile, preserveFileDate);
+ }
+
+ /**
+ * Internal copy file method.
+ *
+ * @param srcFile the validated source file, must not be <code>null</code>
+ * @param destFile the validated destination file, must not be <code>null</code>
+ * @param preserveFileDate whether to preserve the file date
+ * @throws IOException if an error occurs
+ */
+ private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+ if (destFile.exists() && destFile.isDirectory()) {
+ throw new IOException("Destination '" + destFile + "' exists but is a directory");
+ }
+
+ FileInputStream input = new FileInputStream(srcFile);
+ try {
+ FileOutputStream output = new FileOutputStream(destFile);
+ try {
+ IOUtils.copy(input, output);
+ } finally {
+ IOUtils.closeQuietly(output);
+ }
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+
+ if (srcFile.length() != destFile.length()) {
+ throw new IOException("Failed to copy full contents from '" +
+ srcFile + "' to '" + destFile + "'");
+ }
+ if (preserveFileDate) {
+ destFile.setLastModified(srcFile.lastModified());
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Copies a directory to within another directory preserving the file dates.
+ * <p>
+ * This method copies the source directory and all its contents to a
+ * directory of the same name in the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist.
+ * If the destination directory did exist, then this method merges
+ * the source with the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be <code>null</code>
+ * @param destDir the directory to place the copy in, must not be <code>null</code>
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.2
+ */
+ public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
+ if (srcDir == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (srcDir.exists() && srcDir.isDirectory() == false) {
+ throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (destDir.exists() && destDir.isDirectory() == false) {
+ throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+ }
+ copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
+ }
+
+ /**
+ * Copies a whole directory to a new location preserving the file dates.
+ * <p>
+ * This method copies the specified directory and all its child
+ * directories and files to the specified destination.
+ * The destination is the new location and name of the directory.
+ * <p>
+ * The destination directory is created if it does not exist.
+ * If the destination directory did exist, then this method merges
+ * the source with the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.1
+ */
+ public static void copyDirectory(File srcDir, File destDir) throws IOException {
+ copyDirectory(srcDir, destDir, true);
+ }
+
+ /**
+ * Copies a whole directory to a new location.
+ * <p>
+ * This method copies the contents of the specified source directory
+ * to within the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist.
+ * If the destination directory did exist, then this method merges
+ * the source with the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ * @param preserveFileDate true if the file date of the copy
+ * should be the same as the original
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.1
+ */
+ public static void copyDirectory(File srcDir, File destDir,
+ boolean preserveFileDate) throws IOException {
+ copyDirectory(srcDir, destDir, null, preserveFileDate);
+ }
+
+ /**
+ * Copies a filtered directory to a new location preserving the file dates.
+ * <p>
+ * This method copies the contents of the specified source directory
+ * to within the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist.
+ * If the destination directory did exist, then this method merges
+ * the source with the destination, with the source taking precedence.
+ *
+ * <h4>Example: Copy directories only</h4>
+ * <pre>
+ * // only copy the directory structure
+ * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
+ * </pre>
+ *
+ * <h4>Example: Copy directories and txt files</h4>
+ * <pre>
+ * // Create a filter for ".txt" files
+ * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
+ * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
+ *
+ * // Create a filter for either directories or ".txt" files
+ * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
+ *
+ * // Copy using the filter
+ * FileUtils.copyDirectory(srcDir, destDir, filter);
+ * </pre>
+ *
+ * @param srcDir an existing directory to copy, must not be <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ * @param filter the filter to apply, null means copy all directories and files
+ * should be the same as the original
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.4
+ */
+ public static void copyDirectory(File srcDir, File destDir,
+ FileFilter filter) throws IOException {
+ copyDirectory(srcDir, destDir, filter, true);
+ }
+
+ /**
+ * Copies a filtered directory to a new location.
+ * <p>
+ * This method copies the contents of the specified source directory
+ * to within the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist.
+ * If the destination directory did exist, then this method merges
+ * the source with the destination, with the source taking precedence.
+ *
+ * <h4>Example: Copy directories only</h4>
+ * <pre>
+ * // only copy the directory structure
+ * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
+ * </pre>
+ *
+ * <h4>Example: Copy directories and txt files</h4>
+ * <pre>
+ * // Create a filter for ".txt" files
+ * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
+ * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
+ *
+ * // Create a filter for either directories or ".txt" files
+ * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
+ *
+ * // Copy using the filter
+ * FileUtils.copyDirectory(srcDir, destDir, filter, false);
+ * </pre>
+ *
+ * @param srcDir an existing directory to copy, must not be <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ * @param filter the filter to apply, null means copy all directories and files
+ * @param preserveFileDate true if the file date of the copy
+ * should be the same as the original
+ *
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.4
+ */
+ public static void copyDirectory(File srcDir, File destDir,
+ FileFilter filter, boolean preserveFileDate) throws IOException {
+ if (srcDir == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (srcDir.exists() == false) {
+ throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
+ }
+ if (srcDir.isDirectory() == false) {
+ throw new IOException("Source '" + srcDir + "' exists but is not a directory");
+ }
+ if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
+ throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
+ }
+
+ // Cater for destination being directory within the source directory (see IO-141)
+ List<String> exclusionList = null;
+ if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
+ File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
+ if (srcFiles != null && srcFiles.length > 0) {
+ exclusionList = new ArrayList<String>(srcFiles.length);
+ for (int i = 0; i < srcFiles.length; i++) {
+ File copiedFile = new File(destDir, srcFiles[i].getName());
+ exclusionList.add(copiedFile.getCanonicalPath());
+ }
+ }
+ }
+ doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList);
+ }
+
+ /**
+ * Internal copy directory method.
+ *
+ * @param srcDir the validated source directory, must not be <code>null</code>
+ * @param destDir the validated destination directory, must not be <code>null</code>
+ * @param filter the filter to apply, null means copy all directories and files
+ * @param preserveFileDate whether to preserve the file date
+ * @param exclusionList List of files and directories to exclude from the copy, may be null
+ * @throws IOException if an error occurs
+ * @since Commons IO 1.1
+ */
+ private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter,
+ boolean preserveFileDate, List<String> exclusionList) throws IOException {
+ if (destDir.exists()) {
+ if (destDir.isDirectory() == false) {
+ throw new IOException("Destination '" + destDir + "' exists but is not a directory");
+ }
+ } else {
+ if (destDir.mkdirs() == false) {
+ throw new IOException("Destination '" + destDir + "' directory cannot be created");
+ }
+ if (preserveFileDate) {
+ destDir.setLastModified(srcDir.lastModified());
+ }
+ }
+ if (destDir.canWrite() == false) {
+ throw new IOException("Destination '" + destDir + "' cannot be written to");
+ }
+ // recurse
+ File[] files = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + srcDir);
+ }
+ for (int i = 0; i < files.length; i++) {
+ File copiedFile = new File(destDir, files[i].getName());
+ if (exclusionList == null || !exclusionList.contains(files[i].getCanonicalPath())) {
+ if (files[i].isDirectory()) {
+ doCopyDirectory(files[i], copiedFile, filter, preserveFileDate, exclusionList);
+ } else {
+ doCopyFile(files[i], copiedFile, preserveFileDate);
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Copies bytes from the URL <code>source</code> to a file
+ * <code>destination</code>. The directories up to <code>destination</code>
+ * will be created if they don't already exist. <code>destination</code>
+ * will be overwritten if it already exists.
+ *
+ * @param source the <code>URL</code> to copy bytes from, must not be <code>null</code>
+ * @param destination the non-directory <code>File</code> to write bytes to
+ * (possibly overwriting), must not be <code>null</code>
+ * @throws IOException if <code>source</code> URL cannot be opened
+ * @throws IOException if <code>destination</code> is a directory
+ * @throws IOException if <code>destination</code> cannot be written
+ * @throws IOException if <code>destination</code> needs creating but can't be
+ * @throws IOException if an IO error occurs during copying
+ */
+ public static void copyURLToFile(URL source, File destination) throws IOException {
+ InputStream input = source.openStream();
+ try {
+ FileOutputStream output = openOutputStream(destination);
+ try {
+ IOUtils.copy(input, output);
+ } finally {
+ IOUtils.closeQuietly(output);
+ }
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Deletes a directory recursively.
+ *
+ * @param directory directory to delete
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void deleteDirectory(File directory) throws IOException {
+ if (!directory.exists()) {
+ return;
+ }
+
+ cleanDirectory(directory);
+ if (!directory.delete()) {
+ String message =
+ "Unable to delete directory " + directory + ".";
+ throw new IOException(message);
+ }
+ }
+
+ /**
+ * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.
+ * <p>
+ * The difference between File.delete() and this method are:
+ * <ul>
+ * <li>A directory to be deleted does not have to be empty.</li>
+ * <li>No exceptions are thrown when a file or directory cannot be deleted.</li>
+ * </ul>
+ *
+ * @param file file or directory to delete, can be <code>null</code>
+ * @return <code>true</code> if the file or directory was deleted, otherwise
+ * <code>false</code>
+ *
+ * @since Commons IO 1.4
+ */
+ public static boolean deleteQuietly(File file) {
+ if (file == null) {
+ return false;
+ }
+ try {
+ if (file.isDirectory()) {
+ cleanDirectory(file);
+ }
+ } catch (Exception e) {
+ }
+
+ try {
+ return file.delete();
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Cleans a directory without deleting it.
+ *
+ * @param directory directory to clean
+ * @throws IOException in case cleaning is unsuccessful
+ */
+ public static void cleanDirectory(File directory) throws IOException {
+ if (!directory.exists()) {
+ String message = directory + " does not exist";
+ throw new IllegalArgumentException(message);
+ }
+
+ if (!directory.isDirectory()) {
+ String message = directory + " is not a directory";
+ throw new IllegalArgumentException(message);
+ }
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + directory);
+ }
+
+ IOException exception = null;
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ forceDelete(file);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+
+ if (null != exception) {
+ throw exception;
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Waits for NFS to propagate a file creation, imposing a timeout.
+ * <p>
+ * This method repeatedly tests {@link File#exists()} until it returns
+ * true up to the maximum time specified in seconds.
+ *
+ * @param file the file to check, must not be <code>null</code>
+ * @param seconds the maximum time in seconds to wait
+ * @return true if file exists
+ * @throws NullPointerException if the file is <code>null</code>
+ */
+ public static boolean waitFor(File file, int seconds) {
+ int timeout = 0;
+ int tick = 0;
+ while (!file.exists()) {
+ if (tick++ >= 10) {
+ tick = 0;
+ if (timeout++ > seconds) {
+ return false;
+ }
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignore) {
+ // ignore exception
+ } catch (Exception ex) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Reads the contents of a file into a String.
+ * The file is always closed.
+ *
+ * @param file the file to read, must not be <code>null</code>
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @return the file contents, never <code>null</code>
+ * @throws IOException in case of an I/O error
+ * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
+ */
+ public static String readFileToString(File file, String encoding) throws IOException {
+ InputStream in = null;
+ try {
+ in = openInputStream(file);
+ return IOUtils.toString(in, encoding);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+
+ /**
+ * Reads the contents of a file into a String using the default encoding for the VM.
+ * The file is always closed.
+ *
+ * @param file the file to read, must not be <code>null</code>
+ * @return the file contents, never <code>null</code>
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.3.1
+ */
+ public static String readFileToString(File file) throws IOException {
+ return readFileToString(file, null);
+ }
+
+ /**
+ * Reads the contents of a file into a byte array.
+ * The file is always closed.
+ *
+ * @param file the file to read, must not be <code>null</code>
+ * @return the file contents, never <code>null</code>
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.1
+ */
+ public static byte[] readFileToByteArray(File file) throws IOException {
+ InputStream in = null;
+ try {
+ in = openInputStream(file);
+ return IOUtils.toByteArray(in);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+ /**
+ * Reads the contents of a file line by line to a List of Strings.
+ * The file is always closed.
+ *
+ * @param file the file to read, must not be <code>null</code>
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @return the list of Strings representing each line in the file, never <code>null</code>
+ * @throws IOException in case of an I/O error
+ * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
+ * @since Commons IO 1.1
+ */
+ public static List<String> readLines(File file, String encoding) throws IOException {
+ InputStream in = null;
+ try {
+ in = openInputStream(file);
+ return IOUtils.readLines(in, encoding);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+ /**
+ * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM.
+ * The file is always closed.
+ *
+ * @param file the file to read, must not be <code>null</code>
+ * @return the list of Strings representing each line in the file, never <code>null</code>
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.3
+ */
+ public static List<String> readLines(File file) throws IOException {
+ return readLines(file, null);
+ }
+
+ /**
+ * Returns an Iterator for the lines in a <code>File</code>.
+ * <p>
+ * This method opens an <code>InputStream</code> for the file.
+ * When you have finished with the iterator you should close the stream
+ * to free internal resources. This can be done by calling the
+ * {@link LineIterator#close()} or
+ * {@link LineIterator#closeQuietly(LineIterator)} method.
+ * <p>
+ * The recommended usage pattern is:
+ * <pre>
+ * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
+ * try {
+ * while (it.hasNext()) {
+ * String line = it.nextLine();
+ * /// do something with line
+ * }
+ * } finally {
+ * LineIterator.closeQuietly(iterator);
+ * }
+ * </pre>
+ * <p>
+ * If an exception occurs during the creation of the iterator, the
+ * underlying stream is closed.
+ *
+ * @param file the file to open for input, must not be <code>null</code>
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @return an Iterator of the lines in the file, never <code>null</code>
+ * @throws IOException in case of an I/O error (file closed)
+ * @since Commons IO 1.2
+ */
+ public static LineIterator lineIterator(File file, String encoding) throws IOException {
+ InputStream in = null;
+ try {
+ in = openInputStream(file);
+ return IOUtils.lineIterator(in, encoding);
+ } catch (IOException ex) {
+ IOUtils.closeQuietly(in);
+ throw ex;
+ } catch (RuntimeException ex) {
+ IOUtils.closeQuietly(in);
+ throw ex;
+ }
+ }
+
+ /**
+ * Returns an Iterator for the lines in a <code>File</code> using the default encoding for the VM.
+ *
+ * @param file the file to open for input, must not be <code>null</code>
+ * @return an Iterator of the lines in the file, never <code>null</code>
+ * @throws IOException in case of an I/O error (file closed)
+ * @since Commons IO 1.3
+ * @see #lineIterator(File, String)
+ */
+ public static LineIterator lineIterator(File file) throws IOException {
+ return lineIterator(file, null);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes a String to a file creating the file if it does not exist.
+ *
+ * NOTE: As from v1.3, the parent directories of the file will be created
+ * if they do not exist.
+ *
+ * @param file the file to write
+ * @param data the content to write to the file
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @throws IOException in case of an I/O error
+ * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
+ */
+ public static void writeStringToFile(File file, String data, String encoding) throws IOException {
+ OutputStream out = null;
+ try {
+ out = openOutputStream(file);
+ IOUtils.write(data, out, encoding);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Writes a String to a file creating the file if it does not exist using the default encoding for the VM.
+ *
+ * @param file the file to write
+ * @param data the content to write to the file
+ * @throws IOException in case of an I/O error
+ */
+ public static void writeStringToFile(File file, String data) throws IOException {
+ writeStringToFile(file, data, null);
+ }
+
+ /**
+ * Writes a byte array to a file creating the file if it does not exist.
+ * <p>
+ * NOTE: As from v1.3, the parent directories of the file will be created
+ * if they do not exist.
+ *
+ * @param file the file to write to
+ * @param data the content to write to the file
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.1
+ */
+ public static void writeByteArrayToFile(File file, byte[] data) throws IOException {
+ OutputStream out = null;
+ try {
+ out = openOutputStream(file);
+ out.write(data);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Writes the <code>toString()</code> value of each item in a collection to
+ * the specified <code>File</code> line by line.
+ * The specified character encoding and the default line ending will be used.
+ * <p>
+ * NOTE: As from v1.3, the parent directories of the file will be created
+ * if they do not exist.
+ *
+ * @param file the file to write to
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @param lines the lines to write, <code>null</code> entries produce blank lines
+ * @throws IOException in case of an I/O error
+ * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
+ * @since Commons IO 1.1
+ */
+ public static void writeLines(File file, String encoding, Collection<Object> lines) throws IOException {
+ writeLines(file, encoding, lines, null);
+ }
+
+ /**
+ * Writes the <code>toString()</code> value of each item in a collection to
+ * the specified <code>File</code> line by line.
+ * The default VM encoding and the default line ending will be used.
+ *
+ * @param file the file to write to
+ * @param lines the lines to write, <code>null</code> entries produce blank lines
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.3
+ */
+ public static void writeLines(File file, Collection<Object> lines) throws IOException {
+ writeLines(file, null, lines, null);
+ }
+
+ /**
+ * Writes the <code>toString()</code> value of each item in a collection to
+ * the specified <code>File</code> line by line.
+ * The specified character encoding and the line ending will be used.
+ * <p>
+ * NOTE: As from v1.3, the parent directories of the file will be created
+ * if they do not exist.
+ *
+ * @param file the file to write to
+ * @param encoding the encoding to use, <code>null</code> means platform default
+ * @param lines the lines to write, <code>null</code> entries produce blank lines
+ * @param lineEnding the line separator to use, <code>null</code> is system default
+ * @throws IOException in case of an I/O error
+ * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
+ * @since Commons IO 1.1
+ */
+ public static void writeLines(File file, String encoding, Collection<Object> lines, String lineEnding) throws IOException {
+ OutputStream out = null;
+ try {
+ out = openOutputStream(file);
+ IOUtils.writeLines(lines, lineEnding, out, encoding);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Writes the <code>toString()</code> value of each item in a collection to
+ * the specified <code>File</code> line by line.
+ * The default VM encoding and the specified line ending will be used.
+ *
+ * @param file the file to write to
+ * @param lines the lines to write, <code>null</code> entries produce blank lines
+ * @param lineEnding the line separator to use, <code>null</code> is system default
+ * @throws IOException in case of an I/O error
+ * @since Commons IO 1.3
+ */
+ public static void writeLines(File file, Collection<Object> lines, String lineEnding) throws IOException {
+ writeLines(file, null, lines, lineEnding);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Deletes a file. If file is a directory, delete it and all sub-directories.
+ * <p>
+ * The difference between File.delete() and this method are:
+ * <ul>
+ * <li>A directory to be deleted does not have to be empty.</li>
+ * <li>You get exceptions when a file or directory cannot be deleted.
+ * (java.io.File methods returns a boolean)</li>
+ * </ul>
+ *
+ * @param file file or directory to delete, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws FileNotFoundException if the file was not found
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void forceDelete(File file) throws IOException {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else {
+ boolean filePresent = file.exists();
+ if (!file.delete()) {
+ if (!filePresent){
+ throw new FileNotFoundException("File does not exist: " + file);
+ }
+ String message =
+ "Unable to delete file: " + file;
+ throw new IOException(message);
+ }
+ }
+ }
+
+ /**
+ * Schedules a file to be deleted when JVM exits.
+ * If file is directory delete it and all sub-directories.
+ *
+ * @param file file or directory to delete, must not be <code>null</code>
+ * @throws NullPointerException if the file is <code>null</code>
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void forceDeleteOnExit(File file) throws IOException {
+ if (file.isDirectory()) {
+ deleteDirectoryOnExit(file);
+ } else {
+ file.deleteOnExit();
+ }
+ }
+
+ /**
+ * Schedules a directory recursively for deletion on JVM exit.
+ *
+ * @param directory directory to delete, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws IOException in case deletion is unsuccessful
+ */
+ private static void deleteDirectoryOnExit(File directory) throws IOException {
+ if (!directory.exists()) {
+ return;
+ }
+
+ cleanDirectoryOnExit(directory);
+ directory.deleteOnExit();
+ }
+
+ /**
+ * Cleans a directory without deleting it.
+ *
+ * @param directory directory to clean, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws IOException in case cleaning is unsuccessful
+ */
+ private static void cleanDirectoryOnExit(File directory) throws IOException {
+ if (!directory.exists()) {
+ String message = directory + " does not exist";
+ throw new IllegalArgumentException(message);
+ }
+
+ if (!directory.isDirectory()) {
+ String message = directory + " is not a directory";
+ throw new IllegalArgumentException(message);
+ }
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + directory);
+ }
+
+ IOException exception = null;
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ forceDeleteOnExit(file);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+
+ if (null != exception) {
+ throw exception;
+ }
+ }
+
+ /**
+ * Makes a directory, including any necessary but nonexistent parent
+ * directories. If there already exists a file with specified name or
+ * the directory cannot be created then an exception is thrown.
+ *
+ * @param directory directory to create, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws IOException if the directory cannot be created
+ */
+ public static void forceMkdir(File directory) throws IOException {
+ if (directory.exists()) {
+ if (directory.isFile()) {
+ String message =
+ "File "
+ + directory
+ + " exists and is "
+ + "not a directory. Unable to create directory.";
+ throw new IOException(message);
+ }
+ } else {
+ if (!directory.mkdirs()) {
+ String message =
+ "Unable to create directory " + directory;
+ throw new IOException(message);
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Counts the size of a directory recursively (sum of the length of all files).
+ *
+ * @param directory directory to inspect, must not be <code>null</code>
+ * @return size of directory in bytes, 0 if directory is security restricted
+ * @throws NullPointerException if the directory is <code>null</code>
+ */
+ public static long sizeOfDirectory(File directory) {
+ if (!directory.exists()) {
+ String message = directory + " does not exist";
+ throw new IllegalArgumentException(message);
+ }
+
+ if (!directory.isDirectory()) {
+ String message = directory + " is not a directory";
+ throw new IllegalArgumentException(message);
+ }
+
+ long size = 0;
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ return 0L;
+ }
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+
+ if (file.isDirectory()) {
+ size += sizeOfDirectory(file);
+ } else {
+ size += file.length();
+ }
+ }
+
+ return size;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Tests if the specified <code>File</code> is newer than the reference
+ * <code>File</code>.
+ *
+ * @param file the <code>File</code> of which the modification date must
+ * be compared, must not be <code>null</code>
+ * @param reference the <code>File</code> of which the modification date
+ * is used, must not be <code>null</code>
+ * @return true if the <code>File</code> exists and has been modified more
+ * recently than the reference <code>File</code>
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ * @throws IllegalArgumentException if the reference file is <code>null</code> or doesn't exist
+ */
+ public static boolean isFileNewer(File file, File reference) {
+ if (reference == null) {
+ throw new IllegalArgumentException("No specified reference file");
+ }
+ if (!reference.exists()) {
+ throw new IllegalArgumentException("The reference file '"
+ + file + "' doesn't exist");
+ }
+ return isFileNewer(file, reference.lastModified());
+ }
+
+ /**
+ * Tests if the specified <code>File</code> is newer than the specified
+ * <code>Date</code>.
+ *
+ * @param file the <code>File</code> of which the modification date
+ * must be compared, must not be <code>null</code>
+ * @param date the date reference, must not be <code>null</code>
+ * @return true if the <code>File</code> exists and has been modified
+ * after the given <code>Date</code>.
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ * @throws IllegalArgumentException if the date is <code>null</code>
+ */
+ public static boolean isFileNewer(File file, Date date) {
+ if (date == null) {
+ throw new IllegalArgumentException("No specified date");
+ }
+ return isFileNewer(file, date.getTime());
+ }
+
+ /**
+ * Tests if the specified <code>File</code> is newer than the specified
+ * time reference.
+ *
+ * @param file the <code>File</code> of which the modification date must
+ * be compared, must not be <code>null</code>
+ * @param timeMillis the time reference measured in milliseconds since the
+ * epoch (00:00:00 GMT, January 1, 1970)
+ * @return true if the <code>File</code> exists and has been modified after
+ * the given time reference.
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ */
+ public static boolean isFileNewer(File file, long timeMillis) {
+ if (file == null) {
+ throw new IllegalArgumentException("No specified file");
+ }
+ if (!file.exists()) {
+ return false;
+ }
+ return file.lastModified() > timeMillis;
+ }
+
+
+ //-----------------------------------------------------------------------
+ /**
+ * Tests if the specified <code>File</code> is older than the reference
+ * <code>File</code>.
+ *
+ * @param file the <code>File</code> of which the modification date must
+ * be compared, must not be <code>null</code>
+ * @param reference the <code>File</code> of which the modification date
+ * is used, must not be <code>null</code>
+ * @return true if the <code>File</code> exists and has been modified before
+ * the reference <code>File</code>
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ * @throws IllegalArgumentException if the reference file is <code>null</code> or doesn't exist
+ */
+ public static boolean isFileOlder(File file, File reference) {
+ if (reference == null) {
+ throw new IllegalArgumentException("No specified reference file");
+ }
+ if (!reference.exists()) {
+ throw new IllegalArgumentException("The reference file '"
+ + file + "' doesn't exist");
+ }
+ return isFileOlder(file, reference.lastModified());
+ }
+
+ /**
+ * Tests if the specified <code>File</code> is older than the specified
+ * <code>Date</code>.
+ *
+ * @param file the <code>File</code> of which the modification date
+ * must be compared, must not be <code>null</code>
+ * @param date the date reference, must not be <code>null</code>
+ * @return true if the <code>File</code> exists and has been modified
+ * before the given <code>Date</code>.
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ * @throws IllegalArgumentException if the date is <code>null</code>
+ */
+ public static boolean isFileOlder(File file, Date date) {
+ if (date == null) {
+ throw new IllegalArgumentException("No specified date");
+ }
+ return isFileOlder(file, date.getTime());
+ }
+
+ /**
+ * Tests if the specified <code>File</code> is older than the specified
+ * time reference.
+ *
+ * @param file the <code>File</code> of which the modification date must
+ * be compared, must not be <code>null</code>
+ * @param timeMillis the time reference measured in milliseconds since the
+ * epoch (00:00:00 GMT, January 1, 1970)
+ * @return true if the <code>File</code> exists and has been modified before
+ * the given time reference.
+ * @throws IllegalArgumentException if the file is <code>null</code>
+ */
+ public static boolean isFileOlder(File file, long timeMillis) {
+ if (file == null) {
+ throw new IllegalArgumentException("No specified file");
+ }
+ if (!file.exists()) {
+ return false;
+ }
+ return file.lastModified() < timeMillis;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Computes the checksum of a file using the CRC32 checksum routine.
+ * The value of the checksum is returned.
+ *
+ * @param file the file to checksum, must not be <code>null</code>
+ * @return the checksum value
+ * @throws NullPointerException if the file or checksum is <code>null</code>
+ * @throws IllegalArgumentException if the file is a directory
+ * @throws IOException if an IO error occurs reading the file
+ * @since Commons IO 1.3
+ */
+ public static long checksumCRC32(File file) throws IOException {
+ CRC32 crc = new CRC32();
+ checksum(file, crc);
+ return crc.getValue();
+ }
+
+ /**
+ * Computes the checksum of a file using the specified checksum object.
+ * Multiple files may be checked using one <code>Checksum</code> instance
+ * if desired simply by reusing the same checksum object.
+ * For example:
+ * <pre>
+ * long csum = FileUtils.checksum(file, new CRC32()).getValue();
+ * </pre>
+ *
+ * @param file the file to checksum, must not be <code>null</code>
+ * @param checksum the checksum object to be used, must not be <code>null</code>
+ * @return the checksum specified, updated with the content of the file
+ * @throws NullPointerException if the file or checksum is <code>null</code>
+ * @throws IllegalArgumentException if the file is a directory
+ * @throws IOException if an IO error occurs reading the file
+ * @since Commons IO 1.3
+ */
+ public static Checksum checksum(File file, Checksum checksum) throws IOException {
+ if (file.isDirectory()) {
+ throw new IllegalArgumentException("Checksums can't be computed on directories");
+ }
+ InputStream in = null;
+ try {
+ in = new CheckedInputStream(new FileInputStream(file), checksum);
+ IOUtils.copy(in, new NullOutputStream());
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ return checksum;
+ }
+
+ /**
+ * Moves a directory.
+ * <p>
+ * When the destination directory is on another file system, do a "copy and delete".
+ *
+ * @param srcDir the directory to be moved
+ * @param destDir the destination directory
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs moving the file
+ * @since Commons IO 1.4
+ */
+ public static void moveDirectory(File srcDir, File destDir) throws IOException {
+ if (srcDir == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!srcDir.exists()) {
+ throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
+ }
+ if (!srcDir.isDirectory()) {
+ throw new IOException("Source '" + srcDir + "' is not a directory");
+ }
+ if (destDir.exists()) {
+ throw new IOException("Destination '" + destDir + "' already exists");
+ }
+ boolean rename = srcDir.renameTo(destDir);
+ if (!rename) {
+ copyDirectory( srcDir, destDir );
+ deleteDirectory( srcDir );
+ if (srcDir.exists()) {
+ throw new IOException("Failed to delete original directory '" + srcDir +
+ "' after copy to '" + destDir + "'");
+ }
+ }
+ }
+
+ /**
+ * Moves a directory to another directory.
+ *
+ * @param src the file to be moved
+ * @param destDir the destination file
+ * @param createDestDir If <code>true</code> create the destination directory,
+ * otherwise if <code>false</code> throw an IOException
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs moving the file
+ * @since Commons IO 1.4
+ */
+ public static void moveDirectoryToDirectory(File src, File destDir, boolean createDestDir) throws IOException {
+ if (src == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination directory must not be null");
+ }
+ if (!destDir.exists() && createDestDir) {
+ destDir.mkdirs();
+ }
+ if (!destDir.exists()) {
+ throw new FileNotFoundException("Destination directory '" + destDir +
+ "' does not exist [createDestDir=" + createDestDir +"]");
+ }
+ if (!destDir.isDirectory()) {
+ throw new IOException("Destination '" + destDir + "' is not a directory");
+ }
+ moveDirectory(src, new File(destDir, src.getName()));
+
+ }
+
+ /**
+ * Moves a file.
+ * <p>
+ * When the destination file is on another file system, do a "copy and delete".
+ *
+ * @param srcFile the file to be moved
+ * @param destFile the destination file
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs moving the file
+ * @since Commons IO 1.4
+ */
+ public static void moveFile(File srcFile, File destFile) throws IOException {
+ if (srcFile == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destFile == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!srcFile.exists()) {
+ throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
+ }
+ if (srcFile.isDirectory()) {
+ throw new IOException("Source '" + srcFile + "' is a directory");
+ }
+ if (destFile.exists()) {
+ throw new IOException("Destination '" + destFile + "' already exists");
+ }
+ if (destFile.isDirectory()) {
+ throw new IOException("Destination '" + destFile + "' is a directory");
+ }
+ boolean rename = srcFile.renameTo(destFile);
+ if (!rename) {
+ copyFile( srcFile, destFile );
+ if (!srcFile.delete()) {
+ FileUtils.deleteQuietly(destFile);
+ throw new IOException("Failed to delete original file '" + srcFile +
+ "' after copy to '" + destFile + "'");
+ }
+ }
+ }
+
+ /**
+ * Moves a file to a directory.
+ *
+ * @param srcFile the file to be moved
+ * @param destDir the destination file
+ * @param createDestDir If <code>true</code> create the destination directory,
+ * otherwise if <code>false</code> throw an IOException
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs moving the file
+ * @since Commons IO 1.4
+ */
+ public static void moveFileToDirectory(File srcFile, File destDir, boolean createDestDir) throws IOException {
+ if (srcFile == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination directory must not be null");
+ }
+ if (!destDir.exists() && createDestDir) {
+ destDir.mkdirs();
+ }
+ if (!destDir.exists()) {
+ throw new FileNotFoundException("Destination directory '" + destDir +
+ "' does not exist [createDestDir=" + createDestDir +"]");
+ }
+ if (!destDir.isDirectory()) {
+ throw new IOException("Destination '" + destDir + "' is not a directory");
+ }
+ moveFile(srcFile, new File(destDir, srcFile.getName()));
+ }
+
+ /**
+ * Moves a file or directory to the destination directory.
+ * <p>
+ * When the destination is on another file system, do a "copy and delete".
+ *
+ * @param src the file or directory to be moved
+ * @param destDir the destination directory
+ * @param createDestDir If <code>true</code> create the destination directory,
+ * otherwise if <code>false</code> throw an IOException
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs moving the file
+ * @since Commons IO 1.4
+ */
+ public static void moveToDirectory(File src, File destDir, boolean createDestDir) throws IOException {
+ if (src == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!src.exists()) {
+ throw new FileNotFoundException("Source '" + src + "' does not exist");
+ }
+ if (src.isDirectory()) {
+ moveDirectoryToDirectory(src, destDir, createDestDir);
+ } else {
+ moveFileToDirectory(src, destDir, createDestDir);
+ }
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/FilenameUtils.java b/emailcommon/src/org/apache/commons/io/FilenameUtils.java new file mode 100644 index 000000000..d8cc78b24 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/FilenameUtils.java @@ -0,0 +1,1260 @@ +/*
+ * 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.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Stack;
+
+/**
+ * General filename and filepath manipulation utilities.
+ * <p>
+ * When dealing with filenames you can hit problems when moving from a Windows
+ * based development machine to a Unix based production machine.
+ * This class aims to help avoid those problems.
+ * <p>
+ * <b>NOTE</b>: You may be able to avoid using this class entirely simply by
+ * using JDK {@link java.io.File File} objects and the two argument constructor
+ * {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}.
+ * <p>
+ * Most methods on this class are designed to work the same on both Unix and Windows.
+ * Those that don't include 'System', 'Unix' or 'Windows' in their name.
+ * <p>
+ * Most methods recognise both separators (forward and back), and both
+ * sets of prefixes. See the javadoc of each method for details.
+ * <p>
+ * This class defines six components within a filename
+ * (example C:\dev\project\file.txt):
+ * <ul>
+ * <li>the prefix - C:\</li>
+ * <li>the path - dev\project\</li>
+ * <li>the full path - C:\dev\project\</li>
+ * <li>the name - file.txt</li>
+ * <li>the base name - file</li>
+ * <li>the extension - txt</li>
+ * </ul>
+ * Note that this class works best if directory filenames end with a separator.
+ * If you omit the last separator, it is impossible to determine if the filename
+ * corresponds to a file or a directory. As a result, we have chosen to say
+ * it corresponds to a file.
+ * <p>
+ * This class only supports Unix and Windows style names.
+ * Prefixes are matched as follows:
+ * <pre>
+ * Windows:
+ * a\b\c.txt --> "" --> relative
+ * \a\b\c.txt --> "\" --> current drive absolute
+ * C:a\b\c.txt --> "C:" --> drive relative
+ * C:\a\b\c.txt --> "C:\" --> absolute
+ * \\server\a\b\c.txt --> "\\server\" --> UNC
+ *
+ * Unix:
+ * a/b/c.txt --> "" --> relative
+ * /a/b/c.txt --> "/" --> absolute
+ * ~/a/b/c.txt --> "~/" --> current user
+ * ~ --> "~/" --> current user (slash added)
+ * ~user/a/b/c.txt --> "~user/" --> named user
+ * ~user --> "~user/" --> named user (slash added)
+ * </pre>
+ * Both prefix styles are matched always, irrespective of the machine that you are
+ * currently running on.
+ * <p>
+ * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
+ *
+ * @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A>
+ * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph.Reck</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
+ * @author Matthew Hawthorne
+ * @author Martin Cooper
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @author Stephen Colebourne
+ * @version $Id: FilenameUtils.java 609870 2008-01-08 04:46:26Z niallp $
+ * @since Commons IO 1.1
+ */
+public class FilenameUtils {
+
+ /**
+ * The extension separator character.
+ * @since Commons IO 1.4
+ */
+ public static final char EXTENSION_SEPARATOR = '.';
+
+ /**
+ * The extension separator String.
+ * @since Commons IO 1.4
+ */
+ public static final String EXTENSION_SEPARATOR_STR = (new Character(EXTENSION_SEPARATOR)).toString();
+
+ /**
+ * The Unix separator character.
+ */
+ private static final char UNIX_SEPARATOR = '/';
+
+ /**
+ * The Windows separator character.
+ */
+ private static final char WINDOWS_SEPARATOR = '\\';
+
+ /**
+ * The system separator character.
+ */
+ private static final char SYSTEM_SEPARATOR = File.separatorChar;
+
+ /**
+ * The separator character that is the opposite of the system separator.
+ */
+ private static final char OTHER_SEPARATOR;
+ static {
+ if (isSystemWindows()) {
+ OTHER_SEPARATOR = UNIX_SEPARATOR;
+ } else {
+ OTHER_SEPARATOR = WINDOWS_SEPARATOR;
+ }
+ }
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public FilenameUtils() {
+ super();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Determines if Windows file system is in use.
+ *
+ * @return true if the system is Windows
+ */
+ static boolean isSystemWindows() {
+ return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the character is a separator.
+ *
+ * @param ch the character to check
+ * @return true if it is a separator character
+ */
+ private static boolean isSeparator(char ch) {
+ return (ch == UNIX_SEPARATOR) || (ch == WINDOWS_SEPARATOR);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Normalizes a path, removing double and single dot path steps.
+ * <p>
+ * This method normalizes a path to a standard format.
+ * The input may contain separators in either Unix or Windows format.
+ * The output will contain separators in the format of the system.
+ * <p>
+ * A trailing slash will be retained.
+ * A double slash will be merged to a single slash (but UNC names are handled).
+ * A single dot path segment will be removed.
+ * A double dot will cause that path segment and the one before to be removed.
+ * If the double dot has no parent path segment to work with, <code>null</code>
+ * is returned.
+ * <p>
+ * The output will be the same on both Unix and Windows except
+ * for the separator character.
+ * <pre>
+ * /foo// --> /foo/
+ * /foo/./ --> /foo/
+ * /foo/../bar --> /bar
+ * /foo/../bar/ --> /bar/
+ * /foo/../bar/../baz --> /baz
+ * //foo//./bar --> /foo/bar
+ * /../ --> null
+ * ../foo --> null
+ * foo/bar/.. --> foo/
+ * foo/../../bar --> null
+ * foo/../bar --> bar
+ * //server/foo/../bar --> //server/bar
+ * //server/../bar --> null
+ * C:\foo\..\bar --> C:\bar
+ * C:\..\bar --> null
+ * ~/foo/../bar/ --> ~/bar/
+ * ~/../bar --> null
+ * </pre>
+ * (Note the file separator returned will be correct for Windows/Unix)
+ *
+ * @param filename the filename to normalize, null returns null
+ * @return the normalized filename, or null if invalid
+ */
+ public static String normalize(String filename) {
+ return doNormalize(filename, true);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Normalizes a path, removing double and single dot path steps,
+ * and removing any final directory separator.
+ * <p>
+ * This method normalizes a path to a standard format.
+ * The input may contain separators in either Unix or Windows format.
+ * The output will contain separators in the format of the system.
+ * <p>
+ * A trailing slash will be removed.
+ * A double slash will be merged to a single slash (but UNC names are handled).
+ * A single dot path segment will be removed.
+ * A double dot will cause that path segment and the one before to be removed.
+ * If the double dot has no parent path segment to work with, <code>null</code>
+ * is returned.
+ * <p>
+ * The output will be the same on both Unix and Windows except
+ * for the separator character.
+ * <pre>
+ * /foo// --> /foo
+ * /foo/./ --> /foo
+ * /foo/../bar --> /bar
+ * /foo/../bar/ --> /bar
+ * /foo/../bar/../baz --> /baz
+ * //foo//./bar --> /foo/bar
+ * /../ --> null
+ * ../foo --> null
+ * foo/bar/.. --> foo
+ * foo/../../bar --> null
+ * foo/../bar --> bar
+ * //server/foo/../bar --> //server/bar
+ * //server/../bar --> null
+ * C:\foo\..\bar --> C:\bar
+ * C:\..\bar --> null
+ * ~/foo/../bar/ --> ~/bar
+ * ~/../bar --> null
+ * </pre>
+ * (Note the file separator returned will be correct for Windows/Unix)
+ *
+ * @param filename the filename to normalize, null returns null
+ * @return the normalized filename, or null if invalid
+ */
+ public static String normalizeNoEndSeparator(String filename) {
+ return doNormalize(filename, false);
+ }
+
+ /**
+ * Internal method to perform the normalization.
+ *
+ * @param filename the filename
+ * @param keepSeparator true to keep the final separator
+ * @return the normalized filename
+ */
+ private static String doNormalize(String filename, boolean keepSeparator) {
+ if (filename == null) {
+ return null;
+ }
+ int size = filename.length();
+ if (size == 0) {
+ return filename;
+ }
+ int prefix = getPrefixLength(filename);
+ if (prefix < 0) {
+ return null;
+ }
+
+ char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy
+ filename.getChars(0, filename.length(), array, 0);
+
+ // fix separators throughout
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == OTHER_SEPARATOR) {
+ array[i] = SYSTEM_SEPARATOR;
+ }
+ }
+
+ // add extra separator on the end to simplify code below
+ boolean lastIsDirectory = true;
+ if (array[size - 1] != SYSTEM_SEPARATOR) {
+ array[size++] = SYSTEM_SEPARATOR;
+ lastIsDirectory = false;
+ }
+
+ // adjoining slashes
+ for (int i = prefix + 1; i < size; i++) {
+ if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == SYSTEM_SEPARATOR) {
+ System.arraycopy(array, i, array, i - 1, size - i);
+ size--;
+ i--;
+ }
+ }
+
+ // dot slash
+ for (int i = prefix + 1; i < size; i++) {
+ if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
+ (i == prefix + 1 || array[i - 2] == SYSTEM_SEPARATOR)) {
+ if (i == size - 1) {
+ lastIsDirectory = true;
+ }
+ System.arraycopy(array, i + 1, array, i - 1, size - i);
+ size -=2;
+ i--;
+ }
+ }
+
+ // double dot slash
+ outer:
+ for (int i = prefix + 2; i < size; i++) {
+ if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' && array[i - 2] == '.' &&
+ (i == prefix + 2 || array[i - 3] == SYSTEM_SEPARATOR)) {
+ if (i == prefix + 2) {
+ return null;
+ }
+ if (i == size - 1) {
+ lastIsDirectory = true;
+ }
+ int j;
+ for (j = i - 4 ; j >= prefix; j--) {
+ if (array[j] == SYSTEM_SEPARATOR) {
+ // remove b/../ from a/b/../c
+ System.arraycopy(array, i + 1, array, j + 1, size - i);
+ size -= (i - j);
+ i = j + 1;
+ continue outer;
+ }
+ }
+ // remove a/../ from a/../c
+ System.arraycopy(array, i + 1, array, prefix, size - i);
+ size -= (i + 1 - prefix);
+ i = prefix + 1;
+ }
+ }
+
+ if (size <= 0) { // should never be less than 0
+ return "";
+ }
+ if (size <= prefix) { // should never be less than prefix
+ return new String(array, 0, size);
+ }
+ if (lastIsDirectory && keepSeparator) {
+ return new String(array, 0, size); // keep trailing separator
+ }
+ return new String(array, 0, size - 1); // lose trailing separator
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Concatenates a filename to a base path using normal command line style rules.
+ * <p>
+ * The effect is equivalent to resultant directory after changing
+ * directory to the first argument, followed by changing directory to
+ * the second argument.
+ * <p>
+ * The first argument is the base path, the second is the path to concatenate.
+ * The returned path is always normalized via {@link #normalize(String)},
+ * thus <code>..</code> is handled.
+ * <p>
+ * If <code>pathToAdd</code> is absolute (has an absolute prefix), then
+ * it will be normalized and returned.
+ * Otherwise, the paths will be joined, normalized and returned.
+ * <p>
+ * The output will be the same on both Unix and Windows except
+ * for the separator character.
+ * <pre>
+ * /foo/ + bar --> /foo/bar
+ * /foo + bar --> /foo/bar
+ * /foo + /bar --> /bar
+ * /foo + C:/bar --> C:/bar
+ * /foo + C:bar --> C:bar (*)
+ * /foo/a/ + ../bar --> foo/bar
+ * /foo/ + ../../bar --> null
+ * /foo/ + /bar --> /bar
+ * /foo/.. + /bar --> /bar
+ * /foo + bar/c.txt --> /foo/bar/c.txt
+ * /foo/c.txt + bar --> /foo/c.txt/bar (!)
+ * </pre>
+ * (*) Note that the Windows relative drive prefix is unreliable when
+ * used with this method.
+ * (!) Note that the first parameter must be a path. If it ends with a name, then
+ * the name will be built into the concatenated path. If this might be a problem,
+ * use {@link #getFullPath(String)} on the base path argument.
+ *
+ * @param basePath the base path to attach to, always treated as a path
+ * @param fullFilenameToAdd the filename (or path) to attach to the base
+ * @return the concatenated path, or null if invalid
+ */
+ public static String concat(String basePath, String fullFilenameToAdd) {
+ int prefix = getPrefixLength(fullFilenameToAdd);
+ if (prefix < 0) {
+ return null;
+ }
+ if (prefix > 0) {
+ return normalize(fullFilenameToAdd);
+ }
+ if (basePath == null) {
+ return null;
+ }
+ int len = basePath.length();
+ if (len == 0) {
+ return normalize(fullFilenameToAdd);
+ }
+ char ch = basePath.charAt(len - 1);
+ if (isSeparator(ch)) {
+ return normalize(basePath + fullFilenameToAdd);
+ } else {
+ return normalize(basePath + '/' + fullFilenameToAdd);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts all separators to the Unix separator of forward slash.
+ *
+ * @param path the path to be changed, null ignored
+ * @return the updated path
+ */
+ public static String separatorsToUnix(String path) {
+ if (path == null || path.indexOf(WINDOWS_SEPARATOR) == -1) {
+ return path;
+ }
+ return path.replace(WINDOWS_SEPARATOR, UNIX_SEPARATOR);
+ }
+
+ /**
+ * Converts all separators to the Windows separator of backslash.
+ *
+ * @param path the path to be changed, null ignored
+ * @return the updated path
+ */
+ public static String separatorsToWindows(String path) {
+ if (path == null || path.indexOf(UNIX_SEPARATOR) == -1) {
+ return path;
+ }
+ return path.replace(UNIX_SEPARATOR, WINDOWS_SEPARATOR);
+ }
+
+ /**
+ * Converts all separators to the system separator.
+ *
+ * @param path the path to be changed, null ignored
+ * @return the updated path
+ */
+ public static String separatorsToSystem(String path) {
+ if (path == null) {
+ return null;
+ }
+ if (isSystemWindows()) {
+ return separatorsToWindows(path);
+ } else {
+ return separatorsToUnix(path);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the length of the filename prefix, such as <code>C:/</code> or <code>~/</code>.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * <p>
+ * The prefix length includes the first slash in the full filename
+ * if applicable. Thus, it is possible that the length returned is greater
+ * than the length of the input string.
+ * <pre>
+ * Windows:
+ * a\b\c.txt --> "" --> relative
+ * \a\b\c.txt --> "\" --> current drive absolute
+ * C:a\b\c.txt --> "C:" --> drive relative
+ * C:\a\b\c.txt --> "C:\" --> absolute
+ * \\server\a\b\c.txt --> "\\server\" --> UNC
+ *
+ * Unix:
+ * a/b/c.txt --> "" --> relative
+ * /a/b/c.txt --> "/" --> absolute
+ * ~/a/b/c.txt --> "~/" --> current user
+ * ~ --> "~/" --> current user (slash added)
+ * ~user/a/b/c.txt --> "~user/" --> named user
+ * ~user --> "~user/" --> named user (slash added)
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ * ie. both Unix and Windows prefixes are matched regardless.
+ *
+ * @param filename the filename to find the prefix in, null returns -1
+ * @return the length of the prefix, -1 if invalid or null
+ */
+ public static int getPrefixLength(String filename) {
+ if (filename == null) {
+ return -1;
+ }
+ int len = filename.length();
+ if (len == 0) {
+ return 0;
+ }
+ char ch0 = filename.charAt(0);
+ if (ch0 == ':') {
+ return -1;
+ }
+ if (len == 1) {
+ if (ch0 == '~') {
+ return 2; // return a length greater than the input
+ }
+ return (isSeparator(ch0) ? 1 : 0);
+ } else {
+ if (ch0 == '~') {
+ int posUnix = filename.indexOf(UNIX_SEPARATOR, 1);
+ int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1);
+ if (posUnix == -1 && posWin == -1) {
+ return len + 1; // return a length greater than the input
+ }
+ posUnix = (posUnix == -1 ? posWin : posUnix);
+ posWin = (posWin == -1 ? posUnix : posWin);
+ return Math.min(posUnix, posWin) + 1;
+ }
+ char ch1 = filename.charAt(1);
+ if (ch1 == ':') {
+ ch0 = Character.toUpperCase(ch0);
+ if (ch0 >= 'A' && ch0 <= 'Z') {
+ if (len == 2 || isSeparator(filename.charAt(2)) == false) {
+ return 2;
+ }
+ return 3;
+ }
+ return -1;
+
+ } else if (isSeparator(ch0) && isSeparator(ch1)) {
+ int posUnix = filename.indexOf(UNIX_SEPARATOR, 2);
+ int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2);
+ if ((posUnix == -1 && posWin == -1) || posUnix == 2 || posWin == 2) {
+ return -1;
+ }
+ posUnix = (posUnix == -1 ? posWin : posUnix);
+ posWin = (posWin == -1 ? posUnix : posWin);
+ return Math.min(posUnix, posWin) + 1;
+ } else {
+ return (isSeparator(ch0) ? 1 : 0);
+ }
+ }
+ }
+
+ /**
+ * Returns the index of the last directory separator character.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The position of the last forward or backslash is returned.
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to find the last path separator in, null returns -1
+ * @return the index of the last separator character, or -1 if there
+ * is no such character
+ */
+ public static int indexOfLastSeparator(String filename) {
+ if (filename == null) {
+ return -1;
+ }
+ int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
+ int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
+ return Math.max(lastUnixPos, lastWindowsPos);
+ }
+
+ /**
+ * Returns the index of the last extension separator character, which is a dot.
+ * <p>
+ * This method also checks that there is no directory separator after the last dot.
+ * To do this it uses {@link #indexOfLastSeparator(String)} which will
+ * handle a file in either Unix or Windows format.
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to find the last path separator in, null returns -1
+ * @return the index of the last separator character, or -1 if there
+ * is no such character
+ */
+ public static int indexOfExtension(String filename) {
+ if (filename == null) {
+ return -1;
+ }
+ int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
+ int lastSeparator = indexOfLastSeparator(filename);
+ return (lastSeparator > extensionPos ? -1 : extensionPos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the prefix from a full filename, such as <code>C:/</code>
+ * or <code>~/</code>.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The prefix includes the first slash in the full filename where applicable.
+ * <pre>
+ * Windows:
+ * a\b\c.txt --> "" --> relative
+ * \a\b\c.txt --> "\" --> current drive absolute
+ * C:a\b\c.txt --> "C:" --> drive relative
+ * C:\a\b\c.txt --> "C:\" --> absolute
+ * \\server\a\b\c.txt --> "\\server\" --> UNC
+ *
+ * Unix:
+ * a/b/c.txt --> "" --> relative
+ * /a/b/c.txt --> "/" --> absolute
+ * ~/a/b/c.txt --> "~/" --> current user
+ * ~ --> "~/" --> current user (slash added)
+ * ~user/a/b/c.txt --> "~user/" --> named user
+ * ~user --> "~user/" --> named user (slash added)
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ * ie. both Unix and Windows prefixes are matched regardless.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the prefix of the file, null if invalid
+ */
+ public static String getPrefix(String filename) {
+ if (filename == null) {
+ return null;
+ }
+ int len = getPrefixLength(filename);
+ if (len < 0) {
+ return null;
+ }
+ if (len > filename.length()) {
+ return filename + UNIX_SEPARATOR; // we know this only happens for unix
+ }
+ return filename.substring(0, len);
+ }
+
+ /**
+ * Gets the path from a full filename, which excludes the prefix.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The method is entirely text based, and returns the text before and
+ * including the last forward or backslash.
+ * <pre>
+ * C:\a\b\c.txt --> a\b\
+ * ~/a/b/c.txt --> a/b/
+ * a.txt --> ""
+ * a/b/c --> a/b/
+ * a/b/c/ --> a/b/c/
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ * <p>
+ * This method drops the prefix from the result.
+ * See {@link #getFullPath(String)} for the method that retains the prefix.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the path of the file, an empty string if none exists, null if invalid
+ */
+ public static String getPath(String filename) {
+ return doGetPath(filename, 1);
+ }
+
+ /**
+ * Gets the path from a full filename, which excludes the prefix, and
+ * also excluding the final directory separator.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The method is entirely text based, and returns the text before the
+ * last forward or backslash.
+ * <pre>
+ * C:\a\b\c.txt --> a\b
+ * ~/a/b/c.txt --> a/b
+ * a.txt --> ""
+ * a/b/c --> a/b
+ * a/b/c/ --> a/b/c
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ * <p>
+ * This method drops the prefix from the result.
+ * See {@link #getFullPathNoEndSeparator(String)} for the method that retains the prefix.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the path of the file, an empty string if none exists, null if invalid
+ */
+ public static String getPathNoEndSeparator(String filename) {
+ return doGetPath(filename, 0);
+ }
+
+ /**
+ * Does the work of getting the path.
+ *
+ * @param filename the filename
+ * @param separatorAdd 0 to omit the end separator, 1 to return it
+ * @return the path
+ */
+ private static String doGetPath(String filename, int separatorAdd) {
+ if (filename == null) {
+ return null;
+ }
+ int prefix = getPrefixLength(filename);
+ if (prefix < 0) {
+ return null;
+ }
+ int index = indexOfLastSeparator(filename);
+ if (prefix >= filename.length() || index < 0) {
+ return "";
+ }
+ return filename.substring(prefix, index + separatorAdd);
+ }
+
+ /**
+ * Gets the full path from a full filename, which is the prefix + path.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The method is entirely text based, and returns the text before and
+ * including the last forward or backslash.
+ * <pre>
+ * C:\a\b\c.txt --> C:\a\b\
+ * ~/a/b/c.txt --> ~/a/b/
+ * a.txt --> ""
+ * a/b/c --> a/b/
+ * a/b/c/ --> a/b/c/
+ * C: --> C:
+ * C:\ --> C:\
+ * ~ --> ~/
+ * ~/ --> ~/
+ * ~user --> ~user/
+ * ~user/ --> ~user/
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the path of the file, an empty string if none exists, null if invalid
+ */
+ public static String getFullPath(String filename) {
+ return doGetFullPath(filename, true);
+ }
+
+ /**
+ * Gets the full path from a full filename, which is the prefix + path,
+ * and also excluding the final directory separator.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The method is entirely text based, and returns the text before the
+ * last forward or backslash.
+ * <pre>
+ * C:\a\b\c.txt --> C:\a\b
+ * ~/a/b/c.txt --> ~/a/b
+ * a.txt --> ""
+ * a/b/c --> a/b
+ * a/b/c/ --> a/b/c
+ * C: --> C:
+ * C:\ --> C:\
+ * ~ --> ~
+ * ~/ --> ~
+ * ~user --> ~user
+ * ~user/ --> ~user
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the path of the file, an empty string if none exists, null if invalid
+ */
+ public static String getFullPathNoEndSeparator(String filename) {
+ return doGetFullPath(filename, false);
+ }
+
+ /**
+ * Does the work of getting the path.
+ *
+ * @param filename the filename
+ * @param includeSeparator true to include the end separator
+ * @return the path
+ */
+ private static String doGetFullPath(String filename, boolean includeSeparator) {
+ if (filename == null) {
+ return null;
+ }
+ int prefix = getPrefixLength(filename);
+ if (prefix < 0) {
+ return null;
+ }
+ if (prefix >= filename.length()) {
+ if (includeSeparator) {
+ return getPrefix(filename); // add end slash if necessary
+ } else {
+ return filename;
+ }
+ }
+ int index = indexOfLastSeparator(filename);
+ if (index < 0) {
+ return filename.substring(0, prefix);
+ }
+ int end = index + (includeSeparator ? 1 : 0);
+ return filename.substring(0, end);
+ }
+
+ /**
+ * Gets the name minus the path from a full filename.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The text after the last forward or backslash is returned.
+ * <pre>
+ * a/b/c.txt --> c.txt
+ * a.txt --> a.txt
+ * a/b/c --> c
+ * a/b/c/ --> ""
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the name of the file without the path, or an empty string if none exists
+ */
+ public static String getName(String filename) {
+ if (filename == null) {
+ return null;
+ }
+ int index = indexOfLastSeparator(filename);
+ return filename.substring(index + 1);
+ }
+
+ /**
+ * Gets the base name, minus the full path and extension, from a full filename.
+ * <p>
+ * This method will handle a file in either Unix or Windows format.
+ * The text after the last forward or backslash and before the last dot is returned.
+ * <pre>
+ * a/b/c.txt --> c
+ * a.txt --> a
+ * a/b/c --> c
+ * a/b/c/ --> ""
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the name of the file without the path, or an empty string if none exists
+ */
+ public static String getBaseName(String filename) {
+ return removeExtension(getName(filename));
+ }
+
+ /**
+ * Gets the extension of a filename.
+ * <p>
+ * This method returns the textual part of the filename after the last dot.
+ * There must be no directory separator after the dot.
+ * <pre>
+ * foo.txt --> "txt"
+ * a/b/c.jpg --> "jpg"
+ * a/b.txt/c --> ""
+ * a/b/c --> ""
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to retrieve the extension of.
+ * @return the extension of the file or an empty string if none exists.
+ */
+ public static String getExtension(String filename) {
+ if (filename == null) {
+ return null;
+ }
+ int index = indexOfExtension(filename);
+ if (index == -1) {
+ return "";
+ } else {
+ return filename.substring(index + 1);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Removes the extension from a filename.
+ * <p>
+ * This method returns the textual part of the filename before the last dot.
+ * There must be no directory separator after the dot.
+ * <pre>
+ * foo.txt --> foo
+ * a\b\c.jpg --> a\b\c
+ * a\b\c --> a\b\c
+ * a.b\c --> a.b\c
+ * </pre>
+ * <p>
+ * The output will be the same irrespective of the machine that the code is running on.
+ *
+ * @param filename the filename to query, null returns null
+ * @return the filename minus the extension
+ */
+ public static String removeExtension(String filename) {
+ if (filename == null) {
+ return null;
+ }
+ int index = indexOfExtension(filename);
+ if (index == -1) {
+ return filename;
+ } else {
+ return filename.substring(0, index);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks whether two filenames are equal exactly.
+ * <p>
+ * No processing is performed on the filenames other than comparison,
+ * thus this is merely a null-safe case-sensitive equals.
+ *
+ * @param filename1 the first filename to query, may be null
+ * @param filename2 the second filename to query, may be null
+ * @return true if the filenames are equal, null equals null
+ * @see IOCase#SENSITIVE
+ */
+ public static boolean equals(String filename1, String filename2) {
+ return equals(filename1, filename2, false, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Checks whether two filenames are equal using the case rules of the system.
+ * <p>
+ * No processing is performed on the filenames other than comparison.
+ * The check is case-sensitive on Unix and case-insensitive on Windows.
+ *
+ * @param filename1 the first filename to query, may be null
+ * @param filename2 the second filename to query, may be null
+ * @return true if the filenames are equal, null equals null
+ * @see IOCase#SYSTEM
+ */
+ public static boolean equalsOnSystem(String filename1, String filename2) {
+ return equals(filename1, filename2, false, IOCase.SYSTEM);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks whether two filenames are equal after both have been normalized.
+ * <p>
+ * Both filenames are first passed to {@link #normalize(String)}.
+ * The check is then performed in a case-sensitive manner.
+ *
+ * @param filename1 the first filename to query, may be null
+ * @param filename2 the second filename to query, may be null
+ * @return true if the filenames are equal, null equals null
+ * @see IOCase#SENSITIVE
+ */
+ public static boolean equalsNormalized(String filename1, String filename2) {
+ return equals(filename1, filename2, true, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Checks whether two filenames are equal after both have been normalized
+ * and using the case rules of the system.
+ * <p>
+ * Both filenames are first passed to {@link #normalize(String)}.
+ * The check is then performed case-sensitive on Unix and
+ * case-insensitive on Windows.
+ *
+ * @param filename1 the first filename to query, may be null
+ * @param filename2 the second filename to query, may be null
+ * @return true if the filenames are equal, null equals null
+ * @see IOCase#SYSTEM
+ */
+ public static boolean equalsNormalizedOnSystem(String filename1, String filename2) {
+ return equals(filename1, filename2, true, IOCase.SYSTEM);
+ }
+
+ /**
+ * Checks whether two filenames are equal, optionally normalizing and providing
+ * control over the case-sensitivity.
+ *
+ * @param filename1 the first filename to query, may be null
+ * @param filename2 the second filename to query, may be null
+ * @param normalized whether to normalize the filenames
+ * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive
+ * @return true if the filenames are equal, null equals null
+ * @since Commons IO 1.3
+ */
+ public static boolean equals(
+ String filename1, String filename2,
+ boolean normalized, IOCase caseSensitivity) {
+
+ if (filename1 == null || filename2 == null) {
+ return filename1 == filename2;
+ }
+ if (normalized) {
+ filename1 = normalize(filename1);
+ filename2 = normalize(filename2);
+ if (filename1 == null || filename2 == null) {
+ throw new NullPointerException(
+ "Error normalizing one or both of the file names");
+ }
+ }
+ if (caseSensitivity == null) {
+ caseSensitivity = IOCase.SENSITIVE;
+ }
+ return caseSensitivity.checkEquals(filename1, filename2);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks whether the extension of the filename is that specified.
+ * <p>
+ * This method obtains the extension as the textual part of the filename
+ * after the last dot. There must be no directory separator after the dot.
+ * The extension check is case-sensitive on all platforms.
+ *
+ * @param filename the filename to query, null returns false
+ * @param extension the extension to check for, null or empty checks for no extension
+ * @return true if the filename has the specified extension
+ */
+ public static boolean isExtension(String filename, String extension) {
+ if (filename == null) {
+ return false;
+ }
+ if (extension == null || extension.length() == 0) {
+ return (indexOfExtension(filename) == -1);
+ }
+ String fileExt = getExtension(filename);
+ return fileExt.equals(extension);
+ }
+
+ /**
+ * Checks whether the extension of the filename is one of those specified.
+ * <p>
+ * This method obtains the extension as the textual part of the filename
+ * after the last dot. There must be no directory separator after the dot.
+ * The extension check is case-sensitive on all platforms.
+ *
+ * @param filename the filename to query, null returns false
+ * @param extensions the extensions to check for, null checks for no extension
+ * @return true if the filename is one of the extensions
+ */
+ public static boolean isExtension(String filename, String[] extensions) {
+ if (filename == null) {
+ return false;
+ }
+ if (extensions == null || extensions.length == 0) {
+ return (indexOfExtension(filename) == -1);
+ }
+ String fileExt = getExtension(filename);
+ for (int i = 0; i < extensions.length; i++) {
+ if (fileExt.equals(extensions[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether the extension of the filename is one of those specified.
+ * <p>
+ * This method obtains the extension as the textual part of the filename
+ * after the last dot. There must be no directory separator after the dot.
+ * The extension check is case-sensitive on all platforms.
+ *
+ * @param filename the filename to query, null returns false
+ * @param extensions the extensions to check for, null checks for no extension
+ * @return true if the filename is one of the extensions
+ */
+ public static boolean isExtension(String filename, Collection<String> extensions) {
+ if (filename == null) {
+ return false;
+ }
+ if (extensions == null || extensions.isEmpty()) {
+ return (indexOfExtension(filename) == -1);
+ }
+ String fileExt = getExtension(filename);
+ for (Iterator<String> it = extensions.iterator(); it.hasNext();) {
+ if (fileExt.equals(it.next())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks a filename to see if it matches the specified wildcard matcher,
+ * always testing case-sensitive.
+ * <p>
+ * The wildcard matcher uses the characters '?' and '*' to represent a
+ * single or multiple wildcard characters.
+ * This is the same as often found on Dos/Unix command lines.
+ * The check is case-sensitive always.
+ * <pre>
+ * wildcardMatch("c.txt", "*.txt") --> true
+ * wildcardMatch("c.txt", "*.jpg") --> false
+ * wildcardMatch("a/b/c.txt", "a/b/*") --> true
+ * wildcardMatch("c.txt", "*.???") --> true
+ * wildcardMatch("c.txt", "*.????") --> false
+ * </pre>
+ *
+ * @param filename the filename to match on
+ * @param wildcardMatcher the wildcard string to match against
+ * @return true if the filename matches the wilcard string
+ * @see IOCase#SENSITIVE
+ */
+ public static boolean wildcardMatch(String filename, String wildcardMatcher) {
+ return wildcardMatch(filename, wildcardMatcher, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Checks a filename to see if it matches the specified wildcard matcher
+ * using the case rules of the system.
+ * <p>
+ * The wildcard matcher uses the characters '?' and '*' to represent a
+ * single or multiple wildcard characters.
+ * This is the same as often found on Dos/Unix command lines.
+ * The check is case-sensitive on Unix and case-insensitive on Windows.
+ * <pre>
+ * wildcardMatch("c.txt", "*.txt") --> true
+ * wildcardMatch("c.txt", "*.jpg") --> false
+ * wildcardMatch("a/b/c.txt", "a/b/*") --> true
+ * wildcardMatch("c.txt", "*.???") --> true
+ * wildcardMatch("c.txt", "*.????") --> false
+ * </pre>
+ *
+ * @param filename the filename to match on
+ * @param wildcardMatcher the wildcard string to match against
+ * @return true if the filename matches the wilcard string
+ * @see IOCase#SYSTEM
+ */
+ public static boolean wildcardMatchOnSystem(String filename, String wildcardMatcher) {
+ return wildcardMatch(filename, wildcardMatcher, IOCase.SYSTEM);
+ }
+
+ /**
+ * Checks a filename to see if it matches the specified wildcard matcher
+ * allowing control over case-sensitivity.
+ * <p>
+ * The wildcard matcher uses the characters '?' and '*' to represent a
+ * single or multiple wildcard characters.
+ *
+ * @param filename the filename to match on
+ * @param wildcardMatcher the wildcard string to match against
+ * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive
+ * @return true if the filename matches the wilcard string
+ * @since Commons IO 1.3
+ */
+ public static boolean wildcardMatch(String filename, String wildcardMatcher, IOCase caseSensitivity) {
+ if (filename == null && wildcardMatcher == null) {
+ return true;
+ }
+ if (filename == null || wildcardMatcher == null) {
+ return false;
+ }
+ if (caseSensitivity == null) {
+ caseSensitivity = IOCase.SENSITIVE;
+ }
+ filename = caseSensitivity.convertCase(filename);
+ wildcardMatcher = caseSensitivity.convertCase(wildcardMatcher);
+ String[] wcs = splitOnTokens(wildcardMatcher);
+ boolean anyChars = false;
+ int textIdx = 0;
+ int wcsIdx = 0;
+ Stack<int[]> backtrack = new Stack<int[]>();
+
+ // loop around a backtrack stack, to handle complex * matching
+ do {
+ if (backtrack.size() > 0) {
+ int[] array = backtrack.pop();
+ wcsIdx = array[0];
+ textIdx = array[1];
+ anyChars = true;
+ }
+
+ // loop whilst tokens and text left to process
+ while (wcsIdx < wcs.length) {
+
+ if (wcs[wcsIdx].equals("?")) {
+ // ? so move to next text char
+ textIdx++;
+ anyChars = false;
+
+ } else if (wcs[wcsIdx].equals("*")) {
+ // set any chars status
+ anyChars = true;
+ if (wcsIdx == wcs.length - 1) {
+ textIdx = filename.length();
+ }
+
+ } else {
+ // matching text token
+ if (anyChars) {
+ // any chars then try to locate text token
+ textIdx = filename.indexOf(wcs[wcsIdx], textIdx);
+ if (textIdx == -1) {
+ // token not found
+ break;
+ }
+ int repeat = filename.indexOf(wcs[wcsIdx], textIdx + 1);
+ if (repeat >= 0) {
+ backtrack.push(new int[] {wcsIdx, repeat});
+ }
+ } else {
+ // matching from current position
+ if (!filename.startsWith(wcs[wcsIdx], textIdx)) {
+ // couldnt match token
+ break;
+ }
+ }
+
+ // matched text token, move text index to end of matched token
+ textIdx += wcs[wcsIdx].length();
+ anyChars = false;
+ }
+
+ wcsIdx++;
+ }
+
+ // full match
+ if (wcsIdx == wcs.length && textIdx == filename.length()) {
+ return true;
+ }
+
+ } while (backtrack.size() > 0);
+
+ return false;
+ }
+
+ /**
+ * Splits a string into a number of tokens.
+ *
+ * @param text the text to split
+ * @return the tokens, never null
+ */
+ static String[] splitOnTokens(String text) {
+ // used by wildcardMatch
+ // package level so a unit test may run on this
+
+ if (text.indexOf("?") == -1 && text.indexOf("*") == -1) {
+ return new String[] { text };
+ }
+
+ char[] array = text.toCharArray();
+ ArrayList<String> list = new ArrayList<String>();
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == '?' || array[i] == '*') {
+ if (buffer.length() != 0) {
+ list.add(buffer.toString());
+ buffer.setLength(0);
+ }
+ if (array[i] == '?') {
+ list.add("?");
+ } else if (list.size() == 0 ||
+ (i > 0 && list.get(list.size() - 1).equals("*") == false)) {
+ list.add("*");
+ }
+ } else {
+ buffer.append(array[i]);
+ }
+ }
+ if (buffer.length() != 0) {
+ list.add(buffer.toString());
+ }
+
+ return list.toArray( new String[ list.size() ] );
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/HexDump.java b/emailcommon/src/org/apache/commons/io/HexDump.java new file mode 100644 index 000000000..b0d468d18 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/HexDump.java @@ -0,0 +1,149 @@ +/*
+ * 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.IOException;
+import java.io.OutputStream;
+
+/**
+ * Dumps data in hexadecimal format.
+ * <p>
+ * Provides a single function to take an array of bytes and display it
+ * in hexadecimal form.
+ * <p>
+ * Origin of code: POI.
+ *
+ * @author Scott Sanders
+ * @author Marc Johnson
+ * @version $Id: HexDump.java 596667 2007-11-20 13:50:14Z niallp $
+ */
+public class HexDump {
+
+ /**
+ * Instances should NOT be constructed in standard programming.
+ */
+ public HexDump() {
+ super();
+ }
+
+ /**
+ * Dump an array of bytes to an OutputStream.
+ *
+ * @param data the byte array to be dumped
+ * @param offset its offset, whatever that might mean
+ * @param stream the OutputStream to which the data is to be
+ * written
+ * @param index initial index into the byte array
+ *
+ * @throws IOException is thrown if anything goes wrong writing
+ * the data to stream
+ * @throws ArrayIndexOutOfBoundsException if the index is
+ * outside the data array's bounds
+ * @throws IllegalArgumentException if the output stream is null
+ */
+
+ public static void dump(byte[] data, long offset,
+ OutputStream stream, int index)
+ throws IOException, ArrayIndexOutOfBoundsException,
+ IllegalArgumentException {
+
+ if ((index < 0) || (index >= data.length)) {
+ throw new ArrayIndexOutOfBoundsException(
+ "illegal index: " + index + " into array of length "
+ + data.length);
+ }
+ if (stream == null) {
+ throw new IllegalArgumentException("cannot write to nullstream");
+ }
+ long display_offset = offset + index;
+ StringBuffer buffer = new StringBuffer(74);
+
+ for (int j = index; j < data.length; j += 16) {
+ int chars_read = data.length - j;
+
+ if (chars_read > 16) {
+ chars_read = 16;
+ }
+ dump(buffer, display_offset).append(' ');
+ for (int k = 0; k < 16; k++) {
+ if (k < chars_read) {
+ dump(buffer, data[k + j]);
+ } else {
+ buffer.append(" ");
+ }
+ buffer.append(' ');
+ }
+ for (int k = 0; k < chars_read; k++) {
+ if ((data[k + j] >= ' ') && (data[k + j] < 127)) {
+ buffer.append((char) data[k + j]);
+ } else {
+ buffer.append('.');
+ }
+ }
+ buffer.append(EOL);
+ stream.write(buffer.toString().getBytes());
+ stream.flush();
+ buffer.setLength(0);
+ display_offset += chars_read;
+ }
+ }
+
+ /**
+ * The line-separator (initializes to "line.separator" system property.
+ */
+ public static final String EOL =
+ System.getProperty("line.separator");
+ private static final char[] _hexcodes =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+ private static final int[] _shifts =
+ {
+ 28, 24, 20, 16, 12, 8, 4, 0
+ };
+
+ /**
+ * Dump a long value into a StringBuffer.
+ *
+ * @param _lbuffer the StringBuffer to dump the value in
+ * @param value the long value to be dumped
+ * @return StringBuffer containing the dumped value.
+ */
+ private static StringBuffer dump(StringBuffer _lbuffer, long value) {
+ for (int j = 0; j < 8; j++) {
+ _lbuffer
+ .append(_hexcodes[((int) (value >> _shifts[j])) & 15]);
+ }
+ return _lbuffer;
+ }
+
+ /**
+ * Dump a byte value into a StringBuffer.
+ *
+ * @param _cbuffer the StringBuffer to dump the value in
+ * @param value the byte value to be dumped
+ * @return StringBuffer containing the dumped value.
+ */
+ private static StringBuffer dump(StringBuffer _cbuffer, byte value) {
+ for (int j = 0; j < 2; j++) {
+ _cbuffer.append(_hexcodes[(value >> _shifts[j + 6]) & 15]);
+ }
+ return _cbuffer;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/IOCase.java b/emailcommon/src/org/apache/commons/io/IOCase.java new file mode 100644 index 000000000..4230f450d --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/IOCase.java @@ -0,0 +1,238 @@ +/*
+ * 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.Serializable;
+
+/**
+ * Enumeration of IO case sensitivity.
+ * <p>
+ * Different filing systems have different rules for case-sensitivity.
+ * Windows is case-insensitive, Unix is case-sensitive.
+ * <p>
+ * This class captures that difference, providing an enumeration to
+ * control how filename comparisons should be performed. It also provides
+ * methods that use the enumeration to perform comparisons.
+ * <p>
+ * Wherever possible, you should use the <code>check</code> methods in this
+ * class to compare filenames.
+ *
+ * @author Stephen Colebourne
+ * @version $Id: IOCase.java 606345 2007-12-21 23:43:01Z ggregory $
+ * @since Commons IO 1.3
+ */
+public final class IOCase implements Serializable {
+
+ /**
+ * The constant for case sensitive regardless of operating system.
+ */
+ public static final IOCase SENSITIVE = new IOCase("Sensitive", true);
+
+ /**
+ * The constant for case insensitive regardless of operating system.
+ */
+ public static final IOCase INSENSITIVE = new IOCase("Insensitive", false);
+
+ /**
+ * The constant for case sensitivity determined by the current operating system.
+ * Windows is case-insensitive when comparing filenames, Unix is case-sensitive.
+ * <p>
+ * If you derialize this constant of Windows, and deserialize on Unix, or vice
+ * versa, then the value of the case-sensitivity flag will change.
+ */
+ public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
+
+ /** Serialization version. */
+ private static final long serialVersionUID = -6343169151696340687L;
+
+ /** The enumeration name. */
+ private final String name;
+
+ /** The sensitivity flag. */
+ private final transient boolean sensitive;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Factory method to create an IOCase from a name.
+ *
+ * @param name the name to find
+ * @return the IOCase object
+ * @throws IllegalArgumentException if the name is invalid
+ */
+ public static IOCase forName(String name) {
+ if (IOCase.SENSITIVE.name.equals(name)){
+ return IOCase.SENSITIVE;
+ }
+ if (IOCase.INSENSITIVE.name.equals(name)){
+ return IOCase.INSENSITIVE;
+ }
+ if (IOCase.SYSTEM.name.equals(name)){
+ return IOCase.SYSTEM;
+ }
+ throw new IllegalArgumentException("Invalid IOCase name: " + name);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Private constructor.
+ *
+ * @param name the name
+ * @param sensitive the sensitivity
+ */
+ private IOCase(String name, boolean sensitive) {
+ this.name = name;
+ this.sensitive = sensitive;
+ }
+
+ /**
+ * Replaces the enumeration from the stream with a real one.
+ * This ensures that the correct flag is set for SYSTEM.
+ *
+ * @return the resolved object
+ */
+ private Object readResolve() {
+ return forName(name);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the name of the constant.
+ *
+ * @return the name of the constant
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Does the object represent case sensitive comparison.
+ *
+ * @return true if case sensitive
+ */
+ public boolean isCaseSensitive() {
+ return sensitive;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares two strings using the case-sensitivity rule.
+ * <p>
+ * This method mimics {@link String#compareTo} but takes case-sensitivity
+ * into account.
+ *
+ * @param str1 the first string to compare, not null
+ * @param str2 the second string to compare, not null
+ * @return true if equal using the case rules
+ * @throws NullPointerException if either string is null
+ */
+ public int checkCompareTo(String str1, String str2) {
+ if (str1 == null || str2 == null) {
+ throw new NullPointerException("The strings must not be null");
+ }
+ return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
+ }
+
+ /**
+ * Compares two strings using the case-sensitivity rule.
+ * <p>
+ * This method mimics {@link String#equals} but takes case-sensitivity
+ * into account.
+ *
+ * @param str1 the first string to compare, not null
+ * @param str2 the second string to compare, not null
+ * @return true if equal using the case rules
+ * @throws NullPointerException if either string is null
+ */
+ public boolean checkEquals(String str1, String str2) {
+ if (str1 == null || str2 == null) {
+ throw new NullPointerException("The strings must not be null");
+ }
+ return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
+ }
+
+ /**
+ * Checks if one string starts with another using the case-sensitivity rule.
+ * <p>
+ * This method mimics {@link String#startsWith(String)} but takes case-sensitivity
+ * into account.
+ *
+ * @param str the string to check, not null
+ * @param start the start to compare against, not null
+ * @return true if equal using the case rules
+ * @throws NullPointerException if either string is null
+ */
+ public boolean checkStartsWith(String str, String start) {
+ return str.regionMatches(!sensitive, 0, start, 0, start.length());
+ }
+
+ /**
+ * Checks if one string ends with another using the case-sensitivity rule.
+ * <p>
+ * This method mimics {@link String#endsWith} but takes case-sensitivity
+ * into account.
+ *
+ * @param str the string to check, not null
+ * @param end the end to compare against, not null
+ * @return true if equal using the case rules
+ * @throws NullPointerException if either string is null
+ */
+ public boolean checkEndsWith(String str, String end) {
+ int endLen = end.length();
+ return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen);
+ }
+
+ /**
+ * Checks if one string contains another at a specific index using the case-sensitivity rule.
+ * <p>
+ * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)}
+ * but takes case-sensitivity into account.
+ *
+ * @param str the string to check, not null
+ * @param strStartIndex the index to start at in str
+ * @param search the start to search for, not null
+ * @return true if equal using the case rules
+ * @throws NullPointerException if either string is null
+ */
+ public boolean checkRegionMatches(String str, int strStartIndex, String search) {
+ return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length());
+ }
+
+ /**
+ * Converts the case of the input String to a standard format.
+ * Subsequent operations can then use standard String methods.
+ *
+ * @param str the string to convert, null returns null
+ * @return the lower-case version if case-insensitive
+ */
+ String convertCase(String str) {
+ if (str == null) {
+ return null;
+ }
+ return sensitive ? str : str.toLowerCase();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets a string describing the sensitivity.
+ *
+ * @return a string describing the sensitivity
+ */
+ public String toString() {
+ return name;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/IOExceptionWithCause.java b/emailcommon/src/org/apache/commons/io/IOExceptionWithCause.java new file mode 100644 index 000000000..a15815a22 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/IOExceptionWithCause.java @@ -0,0 +1,69 @@ +/*
+ * 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.IOException;
+
+/**
+ * Subclasses IOException with the {@link Throwable} constructors missing before Java 6. If you are using Java 6,
+ * consider this class deprecated and use {@link IOException}.
+ *
+ * @author <a href="http://commons.apache.org/io/">Apache Commons IO</a>
+ * @version $Id$
+ * @since Commons IO 1.4
+ */
+public class IOExceptionWithCause extends IOException {
+
+ /**
+ * Defines the serial version UID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new instance with the given message and cause.
+ * <p>
+ * As specified in {@link Throwable}, the message in the given <code>cause</code> is not used in this instance's
+ * message.
+ * </p>
+ *
+ * @param message
+ * the message (see {@link #getMessage()})
+ * @param cause
+ * the cause (see {@link #getCause()}). A <code>null</code> value is allowed.
+ */
+ public IOExceptionWithCause(String message, Throwable cause) {
+ super(message);
+ this.initCause(cause);
+ }
+
+ /**
+ * Constructs a new instance with the given cause.
+ * <p>
+ * The message is set to <code>cause==null ? null : cause.toString()</code>, which by default contains the class
+ * and message of <code>cause</code>. This constructor is useful for call sites that just wrap another throwable.
+ * </p>
+ *
+ * @param cause
+ * the cause (see {@link #getCause()}). A <code>null</code> value is allowed.
+ */
+ public IOExceptionWithCause(Throwable cause) {
+ super(cause == null ? null : cause.toString());
+ this.initCause(cause);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/IOUtils.java b/emailcommon/src/org/apache/commons/io/IOUtils.java new file mode 100644 index 000000000..3f6c65c13 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/IOUtils.java @@ -0,0 +1,1274 @@ +/*
+ * 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.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;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+/**
+ * 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()}
+ */
+ 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[])}
+ */
+ 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)}
+ */
+ 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;
+ }
+
+ // lineIterator
+ //-----------------------------------------------------------------------
+ /**
+ * Return an Iterator for the lines in a <code>Reader</code>.
+ * <p>
+ * <code>LineIterator</code> holds a reference to the open
+ * <code>Reader</code> specified here. When you have finished with the
+ * iterator you should close the reader to free internal resources.
+ * This can be done by closing the reader directly, or by calling
+ * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
+ * <p>
+ * The recommended usage pattern is:
+ * <pre>
+ * try {
+ * LineIterator it = IOUtils.lineIterator(reader);
+ * while (it.hasNext()) {
+ * String line = it.nextLine();
+ * /// do something with line
+ * }
+ * } finally {
+ * IOUtils.closeQuietly(reader);
+ * }
+ * </pre>
+ *
+ * @param reader the <code>Reader</code> to read from, not null
+ * @return an Iterator of the lines in the reader, never null
+ * @throws IllegalArgumentException if the reader is null
+ * @since Commons IO 1.2
+ */
+ public static LineIterator lineIterator(Reader reader) {
+ return new LineIterator(reader);
+ }
+
+ /**
+ * Return an Iterator for the lines in an <code>InputStream</code>, using
+ * the character encoding specified (or default encoding if null).
+ * <p>
+ * <code>LineIterator</code> holds a reference to the open
+ * <code>InputStream</code> specified here. When you have finished with
+ * the iterator you should close the stream to free internal resources.
+ * This can be done by closing the stream directly, or by calling
+ * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
+ * <p>
+ * The recommended usage pattern is:
+ * <pre>
+ * try {
+ * LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
+ * while (it.hasNext()) {
+ * String line = it.nextLine();
+ * /// do something with line
+ * }
+ * } finally {
+ * IOUtils.closeQuietly(stream);
+ * }
+ * </pre>
+ *
+ * @param input the <code>InputStream</code> to read from, not null
+ * @param encoding the encoding to use, null means platform default
+ * @return an Iterator of the lines in the reader, never null
+ * @throws IllegalArgumentException if the input is null
+ * @throws IOException if an I/O error occurs, such as if the encoding is invalid
+ * @since Commons IO 1.2
+ */
+ public static LineIterator lineIterator(InputStream input, String encoding)
+ throws IOException {
+ Reader reader = null;
+ if (encoding == null) {
+ reader = new InputStreamReader(input);
+ } else {
+ reader = new InputStreamReader(input, encoding);
+ }
+ return new LineIterator(reader);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * 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/emailcommon/src/org/apache/commons/io/LineIterator.java b/emailcommon/src/org/apache/commons/io/LineIterator.java new file mode 100644 index 000000000..eac47d23a --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/LineIterator.java @@ -0,0 +1,181 @@ +/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An Iterator over the lines in a <code>Reader</code>.
+ * <p>
+ * <code>LineIterator</code> holds a reference to an open <code>Reader</code>.
+ * When you have finished with the iterator you should close the reader
+ * to free internal resources. This can be done by closing the reader directly,
+ * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)}
+ * method on the iterator.
+ * <p>
+ * The recommended usage pattern is:
+ * <pre>
+ * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
+ * try {
+ * while (it.hasNext()) {
+ * String line = it.nextLine();
+ * /// do something with line
+ * }
+ * } finally {
+ * LineIterator.closeQuietly(iterator);
+ * }
+ * </pre>
+ *
+ * @author Niall Pemberton
+ * @author Stephen Colebourne
+ * @author Sandy McArthur
+ * @version $Id: LineIterator.java 437567 2006-08-28 06:39:07Z bayard $
+ * @since Commons IO 1.2
+ */
+public class LineIterator implements Iterator {
+
+ /** The reader that is being read. */
+ private final BufferedReader bufferedReader;
+ /** The current line. */
+ private String cachedLine;
+ /** A flag indicating if the iterator has been fully read. */
+ private boolean finished = false;
+
+ /**
+ * Constructs an iterator of the lines for a <code>Reader</code>.
+ *
+ * @param reader the <code>Reader</code> to read from, not null
+ * @throws IllegalArgumentException if the reader is null
+ */
+ public LineIterator(final Reader reader) throws IllegalArgumentException {
+ if (reader == null) {
+ throw new IllegalArgumentException("Reader must not be null");
+ }
+ if (reader instanceof BufferedReader) {
+ bufferedReader = (BufferedReader) reader;
+ } else {
+ bufferedReader = new BufferedReader(reader);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Indicates whether the <code>Reader</code> has more lines.
+ * If there is an <code>IOException</code> then {@link #close()} will
+ * be called on this instance.
+ *
+ * @return <code>true</code> if the Reader has more lines
+ * @throws IllegalStateException if an IO exception occurs
+ */
+ public boolean hasNext() {
+ if (cachedLine != null) {
+ return true;
+ } else if (finished) {
+ return false;
+ } else {
+ try {
+ while (true) {
+ String line = bufferedReader.readLine();
+ if (line == null) {
+ finished = true;
+ return false;
+ } else if (isValidLine(line)) {
+ cachedLine = line;
+ return true;
+ }
+ }
+ } catch(IOException ioe) {
+ close();
+ throw new IllegalStateException(ioe.toString());
+ }
+ }
+ }
+
+ /**
+ * Overridable method to validate each line that is returned.
+ *
+ * @param line the line that is to be validated
+ * @return true if valid, false to remove from the iterator
+ */
+ protected boolean isValidLine(String line) {
+ return true;
+ }
+
+ /**
+ * Returns the next line in the wrapped <code>Reader</code>.
+ *
+ * @return the next line from the input
+ * @throws NoSuchElementException if there is no line to return
+ */
+ public Object next() {
+ return nextLine();
+ }
+
+ /**
+ * Returns the next line in the wrapped <code>Reader</code>.
+ *
+ * @return the next line from the input
+ * @throws NoSuchElementException if there is no line to return
+ */
+ public String nextLine() {
+ if (!hasNext()) {
+ throw new NoSuchElementException("No more lines");
+ }
+ String currentLine = cachedLine;
+ cachedLine = null;
+ return currentLine;
+ }
+
+ /**
+ * Closes the underlying <code>Reader</code> quietly.
+ * This method is useful if you only want to process the first few
+ * lines of a larger file. If you do not close the iterator
+ * then the <code>Reader</code> remains open.
+ * This method can safely be called multiple times.
+ */
+ public void close() {
+ finished = true;
+ IOUtils.closeQuietly(bufferedReader);
+ cachedLine = null;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Remove unsupported on LineIterator");
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Closes the iterator, handling null and ignoring exceptions.
+ *
+ * @param iterator the iterator to close
+ */
+ public static void closeQuietly(LineIterator iterator) {
+ if (iterator != null) {
+ iterator.close();
+ }
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/ThirdPartyProject.prop b/emailcommon/src/org/apache/commons/io/ThirdPartyProject.prop new file mode 100644 index 000000000..b09d3900c --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/ThirdPartyProject.prop @@ -0,0 +1,9 @@ +# Copyright 2010 Google Inc. All Rights Reserved. +#Fri Jul 16 10:03:08 PDT 2010 +currentVersion=1.4 +version=1.4 +isNative=false +name=apache_commons_io +keywords=apache commons io +onDevice=true +homepage=http\://commons.apache.org/io/ diff --git a/emailcommon/src/org/apache/commons/io/comparator/DefaultFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/DefaultFileComparator.java new file mode 100644 index 000000000..8de3cc4e7 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/DefaultFileComparator.java @@ -0,0 +1,66 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Compare two files using the <b>default</b> {@link File#compareTo(File)} method.
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by using the default file comparison.
+ * <p>
+ * Example of sorting a list of files using the
+ * {@link #DEFAULT_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, DefaultFileComparator.DEFAULT_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of doing a <i>reverse</i> sort of an array of files using the
+ * {@link #DEFAULT_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, DefaultFileComparator.DEFAULT_REVERSE);
+ * </pre>
+ * <p>
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class DefaultFileComparator implements Comparator<File>, Serializable {
+
+ /** Singleton default comparator instance */
+ public static final Comparator<File> DEFAULT_COMPARATOR = new DefaultFileComparator();
+
+ /** Singleton reverse default comparator instance */
+ public static final Comparator<File> DEFAULT_REVERSE = new ReverseComparator<File>(DEFAULT_COMPARATOR);
+
+ /**
+ * Compare the two files using the {@link File#compareTo(File)} method.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return the result of calling file1's
+ * {@link File#compareTo(File)} with file2 as the parameter.
+ */
+ public int compare(File file1, File file2) {
+ return file1.compareTo(file2);
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/ExtensionFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/ExtensionFileComparator.java new file mode 100644 index 000000000..5797b02eb --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/ExtensionFileComparator.java @@ -0,0 +1,110 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOCase;
+
+/**
+ * Compare the file name <b>extensions</b> for order
+ * (see {@link FilenameUtils#getExtension(String)}).
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by their file extension either in a case-sensitive, case-insensitive or
+ * system dependant case sensitive way. A number of singleton instances
+ * are provided for the various case sensitivity options (using {@link IOCase})
+ * and the reverse of those options.
+ * <p>
+ * Example of a <i>case-sensitive</i> file extension sort using the
+ * {@link #EXTENSION_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, ExtensionFileComparator.EXTENSION_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of a <i>reverse case-insensitive</i> file extension sort using the
+ * {@link #EXTENSION_INSENSITIVE_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, ExtensionFileComparator.EXTENSION_INSENSITIVE_REVERSE);
+ * </pre>
+ * <p>
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class ExtensionFileComparator implements Comparator<File>, Serializable {
+
+ /** Case-sensitive extension comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> EXTENSION_COMPARATOR = new ExtensionFileComparator();
+
+ /** Reverse case-sensitive extension comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> EXTENSION_REVERSE = new ReverseComparator<File>(EXTENSION_COMPARATOR);
+
+ /** Case-insensitive extension comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> EXTENSION_INSENSITIVE_COMPARATOR = new ExtensionFileComparator(IOCase.INSENSITIVE);
+
+ /** Reverse case-insensitive extension comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> EXTENSION_INSENSITIVE_REVERSE
+ = new ReverseComparator<File>(EXTENSION_INSENSITIVE_COMPARATOR);
+
+ /** System sensitive extension comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> EXTENSION_SYSTEM_COMPARATOR = new ExtensionFileComparator(IOCase.SYSTEM);
+
+ /** Reverse system sensitive path comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> EXTENSION_SYSTEM_REVERSE = new ReverseComparator<File>(EXTENSION_SYSTEM_COMPARATOR);
+
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Construct a case sensitive file extension comparator instance.
+ */
+ public ExtensionFileComparator() {
+ this.caseSensitivity = IOCase.SENSITIVE;
+ }
+
+ /**
+ * Construct a file extension comparator instance with the specified case-sensitivity.
+ *
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ */
+ public ExtensionFileComparator(IOCase caseSensitivity) {
+ this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
+ }
+
+ /**
+ * Compare the extensions of two files the specified case sensitivity.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return a negative value if the first file's extension
+ * is less than the second, zero if the extensions are the
+ * same and a positive value if the first files extension
+ * is greater than the second file.
+ *
+ */
+ public int compare(File file1, File file2) {
+ String suffix1 = FilenameUtils.getExtension(file1.getName());
+ String suffix2 = FilenameUtils.getExtension(file2.getName());
+ return caseSensitivity.checkCompareTo(suffix1, suffix2);
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java new file mode 100644 index 000000000..0dcd0b242 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java @@ -0,0 +1,77 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Compare the <b>last modified date/time</b> of two files for order
+ * (see {@link File#lastModified()}).
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by their last modified date/time.
+ * <p>
+ * Example of sorting a list of files using the
+ * {@link #LASTMODIFIED_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of doing a <i>reverse</i> sort of an array of files using the
+ * {@link #LASTMODIFIED_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
+ * </pre>
+ * <p>
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class LastModifiedFileComparator implements Comparator<File>, Serializable {
+
+ /** Last modified comparator instance */
+ public static final Comparator<File> LASTMODIFIED_COMPARATOR = new LastModifiedFileComparator();
+
+ /** Reverse last modified comparator instance */
+ public static final Comparator<File> LASTMODIFIED_REVERSE = new ReverseComparator<File>(LASTMODIFIED_COMPARATOR);
+
+ /**
+ * Compare the last the last modified date/time of two files.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return a negative value if the first file's lastmodified date/time
+ * is less than the second, zero if the lastmodified date/time are the
+ * same and a positive value if the first files lastmodified date/time
+ * is greater than the second file.
+ *
+ */
+ public int compare(File file1, File file2) {
+ long result = file1.lastModified() - file2.lastModified();
+ if (result < 0) {
+ return -1;
+ } else if (result > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/NameFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/NameFileComparator.java new file mode 100644 index 000000000..eb64fb589 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/NameFileComparator.java @@ -0,0 +1,104 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Compare the <b>names</b> of two files for order (see {@link File#getName()}).
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by their name either in a case-sensitive, case-insensitive or
+ * system dependant case sensitive way. A number of singleton instances
+ * are provided for the various case sensitivity options (using {@link IOCase})
+ * and the reverse of those options.
+ * <p>
+ * Example of a <i>case-sensitive</i> file name sort using the
+ * {@link #NAME_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, NameFileComparator.NAME_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of a <i>reverse case-insensitive</i> file name sort using the
+ * {@link #NAME_INSENSITIVE_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, NameFileComparator.NAME_INSENSITIVE_REVERSE);
+ * </pre>
+ * <p>
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class NameFileComparator implements Comparator<File>, Serializable {
+
+ /** Case-sensitive name comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> NAME_COMPARATOR = new NameFileComparator();
+
+ /** Reverse case-sensitive name comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> NAME_REVERSE = new ReverseComparator<File>(NAME_COMPARATOR);
+
+ /** Case-insensitive name comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> NAME_INSENSITIVE_COMPARATOR = new NameFileComparator(IOCase.INSENSITIVE);
+
+ /** Reverse case-insensitive name comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> NAME_INSENSITIVE_REVERSE = new ReverseComparator<File>(NAME_INSENSITIVE_COMPARATOR);
+
+ /** System sensitive name comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> NAME_SYSTEM_COMPARATOR = new NameFileComparator(IOCase.SYSTEM);
+
+ /** Reverse system sensitive name comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> NAME_SYSTEM_REVERSE = new ReverseComparator<File>(NAME_SYSTEM_COMPARATOR);
+
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Construct a case sensitive file name comparator instance.
+ */
+ public NameFileComparator() {
+ this.caseSensitivity = IOCase.SENSITIVE;
+ }
+
+ /**
+ * Construct a file name comparator instance with the specified case-sensitivity.
+ *
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ */
+ public NameFileComparator(IOCase caseSensitivity) {
+ this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
+ }
+
+ /**
+ * Compare the names of two files with the specified case sensitivity.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return a negative value if the first file's name
+ * is less than the second, zero if the names are the
+ * same and a positive value if the first files name
+ * is greater than the second file.
+ */
+ public int compare(File file1, File file2) {
+ return caseSensitivity.checkCompareTo(file1.getName(), file2.getName());
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/PathFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/PathFileComparator.java new file mode 100644 index 000000000..e93113825 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/PathFileComparator.java @@ -0,0 +1,105 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Compare the <b>path</b> of two files for order (see {@link File#getPath()}).
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by their path either in a case-sensitive, case-insensitive or
+ * system dependant case sensitive way. A number of singleton instances
+ * are provided for the various case sensitivity options (using {@link IOCase})
+ * and the reverse of those options.
+ * <p>
+ * Example of a <i>case-sensitive</i> file path sort using the
+ * {@link #PATH_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, PathFileComparator.PATH_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of a <i>reverse case-insensitive</i> file path sort using the
+ * {@link #PATH_INSENSITIVE_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, PathFileComparator.PATH_INSENSITIVE_REVERSE);
+ * </pre>
+ * <p>
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class PathFileComparator implements Comparator<File>, Serializable {
+
+ /** Case-sensitive path comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> PATH_COMPARATOR = new PathFileComparator();
+
+ /** Reverse case-sensitive path comparator instance (see {@link IOCase#SENSITIVE}) */
+ public static final Comparator<File> PATH_REVERSE = new ReverseComparator<File>(PATH_COMPARATOR);
+
+ /** Case-insensitive path comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> PATH_INSENSITIVE_COMPARATOR = new PathFileComparator(IOCase.INSENSITIVE);
+
+ /** Reverse case-insensitive path comparator instance (see {@link IOCase#INSENSITIVE}) */
+ public static final Comparator<File> PATH_INSENSITIVE_REVERSE = new ReverseComparator<File>(PATH_INSENSITIVE_COMPARATOR);
+
+ /** System sensitive path comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> PATH_SYSTEM_COMPARATOR = new PathFileComparator(IOCase.SYSTEM);
+
+ /** Reverse system sensitive path comparator instance (see {@link IOCase#SYSTEM}) */
+ public static final Comparator<File> PATH_SYSTEM_REVERSE = new ReverseComparator<File>(PATH_SYSTEM_COMPARATOR);
+
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Construct a case sensitive file path comparator instance.
+ */
+ public PathFileComparator() {
+ this.caseSensitivity = IOCase.SENSITIVE;
+ }
+
+ /**
+ * Construct a file path comparator instance with the specified case-sensitivity.
+ *
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ */
+ public PathFileComparator(IOCase caseSensitivity) {
+ this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
+ }
+
+ /**
+ * Compare the paths of two files the specified case sensitivity.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return a negative value if the first file's path
+ * is less than the second, zero if the paths are the
+ * same and a positive value if the first files path
+ * is greater than the second file.
+ *
+ */
+ public int compare(File file1, File file2) {
+ return caseSensitivity.checkCompareTo(file1.getPath(), file2.getPath());
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/ReverseComparator.java b/emailcommon/src/org/apache/commons/io/comparator/ReverseComparator.java new file mode 100644 index 000000000..ab0b38caa --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/ReverseComparator.java @@ -0,0 +1,57 @@ +/*
+ * 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.comparator;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Reverses the result of comparing two objects using
+ * the delegate {@link Comparator}.
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+class ReverseComparator<T> implements Comparator<T>, Serializable {
+
+ private final Comparator<T> delegate;
+
+ /**
+ * Construct an instance with the sepecified delegate {@link Comparator}.
+ *
+ * @param delegate The comparator to delegate to
+ */
+ public ReverseComparator(Comparator<T> delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException("Delegate comparator is missing");
+ }
+ this.delegate = delegate;
+ }
+
+ /**
+ * Compare using the delegate Comparator, but reversing the result.
+ *
+ * @param obj1 The first object to compare
+ * @param obj2 The second object to compare
+ * @return the result from the delegate {@link Comparator#compare(Object, Object)}
+ * reversing the value (i.e. positive becomes negative and vice versa)
+ */
+ public int compare(T obj1, T obj2) {
+ return delegate.compare(obj2, obj1); // parameters switched round
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/SizeFileComparator.java b/emailcommon/src/org/apache/commons/io/comparator/SizeFileComparator.java new file mode 100644 index 000000000..609c159c9 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/SizeFileComparator.java @@ -0,0 +1,130 @@ +/*
+ * 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.comparator;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Compare the <b>length/size</b> of two files for order (see
+ * {@link File#length()} and {@link FileUtils#sizeOfDirectory(File)}).
+ * <p>
+ * This comparator can be used to sort lists or arrays of files
+ * by their length/size.
+ * <p>
+ * Example of sorting a list of files using the
+ * {@link #SIZE_COMPARATOR} singleton instance:
+ * <pre>
+ * List<File> list = ...
+ * Collections.sort(list, LengthFileComparator.LENGTH_COMPARATOR);
+ * </pre>
+ * <p>
+ * Example of doing a <i>reverse</i> sort of an array of files using the
+ * {@link #SIZE_REVERSE} singleton instance:
+ * <pre>
+ * File[] array = ...
+ * Arrays.sort(array, LengthFileComparator.LENGTH_REVERSE);
+ * </pre>
+ * <p>
+ * <strong>N.B.</strong> Directories are treated as <b>zero size</b> unless
+ * <code>sumDirectoryContents</code> is <code>true</code>.
+ *
+ * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class SizeFileComparator implements Comparator<File>, Serializable {
+
+ /** Size comparator instance - directories are treated as zero size */
+ public static final Comparator<File> SIZE_COMPARATOR = new SizeFileComparator();
+
+ /** Reverse size comparator instance - directories are treated as zero size */
+ public static final Comparator<File> SIZE_REVERSE = new ReverseComparator<File>(SIZE_COMPARATOR);
+
+ /**
+ * Size comparator instance which sums the size of a directory's contents
+ * using {@link FileUtils#sizeOfDirectory(File)}
+ */
+ public static final Comparator<File> SIZE_SUMDIR_COMPARATOR = new SizeFileComparator(true);
+
+ /**
+ * Reverse size comparator instance which sums the size of a directory's contents
+ * using {@link FileUtils#sizeOfDirectory(File)}
+ */
+ public static final Comparator<File> SIZE_SUMDIR_REVERSE = new ReverseComparator<File>(SIZE_SUMDIR_COMPARATOR);
+
+ /** Whether the sum of the directory's contents should be calculated. */
+ private final boolean sumDirectoryContents;
+
+ /**
+ * Construct a file size comparator instance (directories treated as zero size).
+ */
+ public SizeFileComparator() {
+ this.sumDirectoryContents = false;
+ }
+
+ /**
+ * Construct a file size comparator instance specifying whether the size of
+ * the directory contents should be aggregated.
+ * <p>
+ * If the <code>sumDirectoryContents</code> is <code>true</code> The size of
+ * directories is calculated using {@link FileUtils#sizeOfDirectory(File)}.
+ *
+ * @param sumDirectoryContents <code>true</code> if the sum of the directoryies contents
+ * should be calculated, otherwise <code>false</code> if directories should be treated
+ * as size zero (see {@link FileUtils#sizeOfDirectory(File)}).
+ */
+ public SizeFileComparator(boolean sumDirectoryContents) {
+ this.sumDirectoryContents = sumDirectoryContents;
+ }
+
+ /**
+ * Compare the length of two files.
+ *
+ * @param obj1 The first file to compare
+ * @param obj2 The second file to compare
+ * @return a negative value if the first file's length
+ * is less than the second, zero if the lengths are the
+ * same and a positive value if the first files length
+ * is greater than the second file.
+ *
+ */
+ public int compare(File file1, File file2) {
+ long size1 = 0;
+ if (file1.isDirectory()) {
+ size1 = sumDirectoryContents && file1.exists() ? FileUtils.sizeOfDirectory(file1) : 0;
+ } else {
+ size1 = file1.length();
+ }
+ long size2 = 0;
+ if (file2.isDirectory()) {
+ size2 = sumDirectoryContents && file2.exists() ? FileUtils.sizeOfDirectory(file2) : 0;
+ } else {
+ size2 = file2.length();
+ }
+ long result = size1 - size2;
+ if (result < 0) {
+ return -1;
+ } else if (result > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/comparator/package.html b/emailcommon/src/org/apache/commons/io/comparator/package.html new file mode 100644 index 000000000..a2f756f18 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/comparator/package.html @@ -0,0 +1,25 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body>
+<p>This package provides various {@link java.util.Comparator} implementations
+for {@link java.io.File}s.
+</p>
+
+</body>
+</html>
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/AbstractFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/AbstractFileFilter.java new file mode 100644 index 000000000..9e188f82e --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/AbstractFileFilter.java @@ -0,0 +1,67 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+
+/**
+ * An abstract class which implements the Java FileFilter and FilenameFilter
+ * interfaces via the IOFileFilter interface.
+ * <p>
+ * Note that a subclass <b>must</b> override one of the accept methods,
+ * otherwise your class will infinitely loop.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 539231 $ $Date: 2007-05-18 04:10:33 +0100 (Fri, 18 May 2007) $
+ *
+ * @author Stephen Colebourne
+ */
+public abstract class AbstractFileFilter implements IOFileFilter {
+
+ /**
+ * Checks to see if the File should be accepted by this filter.
+ *
+ * @param file the File to check
+ * @return true if this file matches the test
+ */
+ public boolean accept(File file) {
+ return accept(file.getParentFile(), file.getName());
+ }
+
+ /**
+ * Checks to see if the File should be accepted by this filter.
+ *
+ * @param dir the directory File to check
+ * @param name the filename within the directory to check
+ * @return true if this file matches the test
+ */
+ public boolean accept(File dir, String name) {
+ return accept(new File(dir, name));
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ public String toString() {
+ String name = getClass().getName();
+ int period = name.lastIndexOf('.');
+ return (period > 0 ? name.substring(period + 1) : name);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/AgeFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/AgeFileFilter.java new file mode 100644 index 000000000..ab73cb840 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/AgeFileFilter.java @@ -0,0 +1,150 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Date;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Filters files based on a cutoff time, can filter either newer
+ * files or files equal to or older.
+ * <p>
+ * For example, to print all files and directories in the
+ * current directory older than one day:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * // We are interested in files older than one day
+ * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
+ * String[] files = dir.list( new AgeFileFilter(cutoff) );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @author Rahul Akolkar
+ * @version $Id: AgeFileFilter.java 606381 2007-12-22 02:03:16Z ggregory $
+ * @since Commons IO 1.2
+ */
+public class AgeFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The cutoff time threshold. */
+ private final long cutoff;
+ /** Whether the files accepted will be older or newer. */
+ private final boolean acceptOlder;
+
+ /**
+ * Constructs a new age file filter for files equal to or older than
+ * a certain cutoff
+ *
+ * @param cutoff the threshold age of the files
+ */
+ public AgeFileFilter(long cutoff) {
+ this(cutoff, true);
+ }
+
+ /**
+ * Constructs a new age file filter for files on any one side
+ * of a certain cutoff.
+ *
+ * @param cutoff the threshold age of the files
+ * @param acceptOlder if true, older files (at or before the cutoff)
+ * are accepted, else newer ones (after the cutoff).
+ */
+ public AgeFileFilter(long cutoff, boolean acceptOlder) {
+ this.acceptOlder = acceptOlder;
+ this.cutoff = cutoff;
+ }
+
+ /**
+ * Constructs a new age file filter for files older than (at or before)
+ * a certain cutoff date.
+ *
+ * @param cutoffDate the threshold age of the files
+ */
+ public AgeFileFilter(Date cutoffDate) {
+ this(cutoffDate, true);
+ }
+
+ /**
+ * Constructs a new age file filter for files on any one side
+ * of a certain cutoff date.
+ *
+ * @param cutoffDate the threshold age of the files
+ * @param acceptOlder if true, older files (at or before the cutoff)
+ * are accepted, else newer ones (after the cutoff).
+ */
+ public AgeFileFilter(Date cutoffDate, boolean acceptOlder) {
+ this(cutoffDate.getTime(), acceptOlder);
+ }
+
+ /**
+ * Constructs a new age file filter for files older than (at or before)
+ * a certain File (whose last modification time will be used as reference).
+ *
+ * @param cutoffReference the file whose last modification
+ * time is usesd as the threshold age of the files
+ */
+ public AgeFileFilter(File cutoffReference) {
+ this(cutoffReference, true);
+ }
+
+ /**
+ * Constructs a new age file filter for files on any one side
+ * of a certain File (whose last modification time will be used as
+ * reference).
+ *
+ * @param cutoffReference the file whose last modification
+ * time is usesd as the threshold age of the files
+ * @param acceptOlder if true, older files (at or before the cutoff)
+ * are accepted, else newer ones (after the cutoff).
+ */
+ public AgeFileFilter(File cutoffReference, boolean acceptOlder) {
+ this(cutoffReference.lastModified(), acceptOlder);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks to see if the last modification of the file matches cutoff
+ * favorably.
+ * <p>
+ * If last modification time equals cutoff and newer files are required,
+ * file <b>IS NOT</b> selected.
+ * If last modification time equals cutoff and older files are required,
+ * file <b>IS</b> selected.
+ *
+ * @param file the File to check
+ * @return true if the filename matches
+ */
+ public boolean accept(File file) {
+ boolean newer = FileUtils.isFileNewer(file, cutoff);
+ return acceptOlder ? !newer : newer;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ public String toString() {
+ String condition = acceptOlder ? "<=" : ">";
+ return super.toString() + "(" + condition + cutoff + ")";
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/AndFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/AndFileFilter.java new file mode 100644 index 000000000..9f3bb06ae --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/AndFileFilter.java @@ -0,0 +1,171 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A {@link java.io.FileFilter} providing conditional AND logic across a list of
+ * file filters. This filter returns <code>true</code> if all filters in the
+ * list return <code>true</code>. Otherwise, it returns <code>false</code>.
+ * Checking of the file filter list stops when the first filter returns
+ * <code>false</code>.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ *
+ * @author Steven Caswell
+ */
+public class AndFileFilter
+ extends AbstractFileFilter
+ implements ConditionalFileFilter, Serializable {
+
+ /** The list of file filters. */
+ private List<IOFileFilter> fileFilters;
+
+ /**
+ * Constructs a new instance of <code>AndFileFilter</code>.
+ *
+ * @since Commons IO 1.1
+ */
+ public AndFileFilter() {
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ }
+
+ /**
+ * Constructs a new instance of <code>AndFileFilter</code>
+ * with the specified list of filters.
+ *
+ * @param fileFilters a List of IOFileFilter instances, copied, null ignored
+ * @since Commons IO 1.1
+ */
+ public AndFileFilter(final List<IOFileFilter> fileFilters) {
+ if (fileFilters == null) {
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ } else {
+ this.fileFilters = new ArrayList<IOFileFilter>(fileFilters);
+ }
+ }
+
+ /**
+ * Constructs a new file filter that ANDs the result of two other filters.
+ *
+ * @param filter1 the first filter, must not be null
+ * @param filter2 the second filter, must not be null
+ * @throws IllegalArgumentException if either filter is null
+ */
+ public AndFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
+ if (filter1 == null || filter2 == null) {
+ throw new IllegalArgumentException("The filters must not be null");
+ }
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ addFileFilter(filter1);
+ addFileFilter(filter2);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addFileFilter(final IOFileFilter ioFileFilter) {
+ this.fileFilters.add(ioFileFilter);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<IOFileFilter> getFileFilters() {
+ return Collections.unmodifiableList(this.fileFilters);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeFileFilter(final IOFileFilter ioFileFilter) {
+ return this.fileFilters.remove(ioFileFilter);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setFileFilters(final List<IOFileFilter> fileFilters) {
+ this.fileFilters = new ArrayList<IOFileFilter>(fileFilters);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(final File file) {
+ if (this.fileFilters.size() == 0) {
+ return false;
+ }
+ for (Iterator<IOFileFilter> iter = this.fileFilters.iterator(); iter.hasNext();) {
+ IOFileFilter fileFilter = iter.next();
+ if (!fileFilter.accept(file)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(final File file, final String name) {
+ if (this.fileFilters.size() == 0) {
+ return false;
+ }
+ for (Iterator<IOFileFilter> iter = this.fileFilters.iterator(); iter.hasNext();) {
+ IOFileFilter fileFilter = iter.next();
+ if (!fileFilter.accept(file, name)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (fileFilters != null) {
+ for (int i = 0; i < fileFilters.size(); i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ Object filter = fileFilters.get(i);
+ buffer.append(filter == null ? "null" : filter.toString());
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/CanReadFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/CanReadFileFilter.java new file mode 100644 index 000000000..a9c132570 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/CanReadFileFilter.java @@ -0,0 +1,92 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts <code>File</code>s that can be read.
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>readable</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( CanReadFileFilter.CAN_READ );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>un-readable</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( CanReadFileFilter.CANNOT_READ );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>read-only</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( CanReadFileFilter.READ_ONLY );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 587916 $
+ */
+public class CanReadFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** Singleton instance of <i>readable</i> filter */
+ public static final IOFileFilter CAN_READ = new CanReadFileFilter();
+
+ /** Singleton instance of not <i>readable</i> filter */
+ public static final IOFileFilter CANNOT_READ = new NotFileFilter(CAN_READ);
+
+ /** Singleton instance of <i>read-only</i> filter */
+ public static final IOFileFilter READ_ONLY = new AndFileFilter(CAN_READ,
+ CanWriteFileFilter.CANNOT_WRITE);
+
+ /**
+ * Restrictive consructor.
+ */
+ protected CanReadFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file can be read.
+ *
+ * @param file the File to check.
+ * @return <code>true</code> if the file can be
+ * read, otherwise <code>false</code>.
+ */
+ public boolean accept(File file) {
+ return file.canRead();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java new file mode 100644 index 000000000..da664f25c --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java @@ -0,0 +1,80 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts <code>File</code>s that can be written to.
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>writable</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( CanWriteFileFilter.CAN_WRITE );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>un-writable</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( CanWriteFileFilter.CANNOT_WRITE );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * <b>N.B.</b> For read-only files, use
+ * <code>CanReadFileFilter.READ_ONLY</code>.
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 587916 $
+ */
+public class CanWriteFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** Singleton instance of <i>writable</i> filter */
+ public static final IOFileFilter CAN_WRITE = new CanWriteFileFilter();
+
+ /** Singleton instance of not <i>writable</i> filter */
+ public static final IOFileFilter CANNOT_WRITE = new NotFileFilter(CAN_WRITE);
+
+ /**
+ * Restrictive consructor.
+ */
+ protected CanWriteFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file can be written to.
+ *
+ * @param file the File to check
+ * @return <code>true</code> if the file can be
+ * written to, otherwise <code>false</code>.
+ */
+ public boolean accept(File file) {
+ return file.canWrite();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java new file mode 100644 index 000000000..b1c481368 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java @@ -0,0 +1,67 @@ +/*
+ * 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.filefilter;
+
+import java.util.List;
+
+/**
+ * Defines operations for conditional file filters.
+ *
+ * @since Commons IO 1.1
+ * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $
+ *
+ * @author Steven Caswell
+ */
+public interface ConditionalFileFilter {
+
+ /**
+ * Adds the specified file filter to the list of file filters at the end of
+ * the list.
+ *
+ * @param ioFileFilter the filter to be added
+ * @since Commons IO 1.1
+ */
+ public void addFileFilter(IOFileFilter ioFileFilter);
+
+ /**
+ * Returns this conditional file filter's list of file filters.
+ *
+ * @return the file filter list
+ * @since Commons IO 1.1
+ */
+ public List<IOFileFilter> getFileFilters();
+
+ /**
+ * Removes the specified file filter.
+ *
+ * @param ioFileFilter filter to be removed
+ * @return <code>true</code> if the filter was found in the list,
+ * <code>false</code> otherwise
+ * @since Commons IO 1.1
+ */
+ public boolean removeFileFilter(IOFileFilter ioFileFilter);
+
+ /**
+ * Sets the list of file filters, replacing any previously configured
+ * file filters on this filter.
+ *
+ * @param fileFilters the list of filters
+ * @since Commons IO 1.1
+ */
+ public void setFileFilters(List<IOFileFilter> fileFilters);
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/DelegateFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/DelegateFileFilter.java new file mode 100644 index 000000000..c2d67c469 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/DelegateFileFilter.java @@ -0,0 +1,104 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.io.Serializable;
+
+/**
+ * This class turns a Java FileFilter or FilenameFilter into an IO FileFilter.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 591058 $ $Date: 2007-11-01 15:47:05 +0000 (Thu, 01 Nov 2007) $
+ *
+ * @author Stephen Colebourne
+ */
+public class DelegateFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The Filename filter */
+ private final FilenameFilter filenameFilter;
+ /** The File filter */
+ private final FileFilter fileFilter;
+
+ /**
+ * Constructs a delegate file filter around an existing FilenameFilter.
+ *
+ * @param filter the filter to decorate
+ */
+ public DelegateFileFilter(FilenameFilter filter) {
+ if (filter == null) {
+ throw new IllegalArgumentException("The FilenameFilter must not be null");
+ }
+ this.filenameFilter = filter;
+ this.fileFilter = null;
+ }
+
+ /**
+ * Constructs a delegate file filter around an existing FileFilter.
+ *
+ * @param filter the filter to decorate
+ */
+ public DelegateFileFilter(FileFilter filter) {
+ if (filter == null) {
+ throw new IllegalArgumentException("The FileFilter must not be null");
+ }
+ this.fileFilter = filter;
+ this.filenameFilter = null;
+ }
+
+ /**
+ * Checks the filter.
+ *
+ * @param file the file to check
+ * @return true if the filter matches
+ */
+ public boolean accept(File file) {
+ if (fileFilter != null) {
+ return fileFilter.accept(file);
+ } else {
+ return super.accept(file);
+ }
+ }
+
+ /**
+ * Checks the filter.
+ *
+ * @param dir the directory
+ * @param name the filename in the directory
+ * @return true if the filter matches
+ */
+ public boolean accept(File dir, String name) {
+ if (filenameFilter != null) {
+ return filenameFilter.accept(dir, name);
+ } else {
+ return super.accept(dir, name);
+ }
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ public String toString() {
+ String delegate = (fileFilter != null ? fileFilter.toString() : filenameFilter.toString());
+ return super.toString() + "(" + delegate + ")";
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java new file mode 100644 index 000000000..3412e7bef --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java @@ -0,0 +1,73 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts <code>File</code>s that are directories.
+ * <p>
+ * For example, here is how to print out a list of the
+ * current directory's subdirectories:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( DirectoryFileFilter.INSTANCE );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 587916 $ $Date: 2007-10-24 16:53:07 +0100 (Wed, 24 Oct 2007) $
+ *
+ * @author Stephen Colebourne
+ * @author Peter Donald
+ */
+public class DirectoryFileFilter extends AbstractFileFilter implements Serializable {
+
+ /**
+ * Singleton instance of directory filter.
+ * @since Commons IO 1.3
+ */
+ public static final IOFileFilter DIRECTORY = new DirectoryFileFilter();
+ /**
+ * Singleton instance of directory filter.
+ * Please use the identical DirectoryFileFilter.DIRECTORY constant.
+ * The new name is more JDK 1.5 friendly as it doesn't clash with other
+ * values when using static imports.
+ */
+ public static final IOFileFilter INSTANCE = DIRECTORY;
+
+ /**
+ * Restrictive consructor.
+ */
+ protected DirectoryFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file is a directory.
+ *
+ * @param file the File to check
+ * @return true if the file is a directory
+ */
+ public boolean accept(File file) {
+ return file.isDirectory();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/EmptyFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/EmptyFileFilter.java new file mode 100644 index 000000000..e88a862d4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/EmptyFileFilter.java @@ -0,0 +1,84 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts files or directories that are empty.
+ * <p>
+ * If the <code>File</code> is a directory it checks that
+ * it contains no files.
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's empty files/directories:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( EmptyFileFilter.EMPTY );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's non-empty files/directories:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( EmptyFileFilter.NOT_EMPTY );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 587916 $
+ */
+public class EmptyFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** Singleton instance of <i>empty</i> filter */
+ public static final IOFileFilter EMPTY = new EmptyFileFilter();
+
+ /** Singleton instance of <i>not-empty</i> filter */
+ public static final IOFileFilter NOT_EMPTY = new NotFileFilter(EMPTY);
+
+ /**
+ * Restrictive consructor.
+ */
+ protected EmptyFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file is empty.
+ *
+ * @param file the file or directory to check
+ * @return <code>true</code> if the file or directory
+ * is <i>empty</i>, otherwise <code>false</code>.
+ */
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ return (files == null || files.length == 0);
+ } else {
+ return (file.length() == 0);
+ }
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/FalseFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/FalseFileFilter.java new file mode 100644 index 000000000..8a87d4092 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/FalseFileFilter.java @@ -0,0 +1,72 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * A file filter that always returns false.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 587978 $ $Date: 2007-10-24 20:36:51 +0100 (Wed, 24 Oct 2007) $
+ *
+ * @author Stephen Colebourne
+ */
+public class FalseFileFilter implements IOFileFilter, Serializable {
+
+ /**
+ * Singleton instance of false filter.
+ * @since Commons IO 1.3
+ */
+ public static final IOFileFilter FALSE = new FalseFileFilter();
+ /**
+ * Singleton instance of false filter.
+ * Please use the identical FalseFileFilter.FALSE constant.
+ * The new name is more JDK 1.5 friendly as it doesn't clash with other
+ * values when using static imports.
+ */
+ public static final IOFileFilter INSTANCE = FALSE;
+
+ /**
+ * Restrictive consructor.
+ */
+ protected FalseFileFilter() {
+ }
+
+ /**
+ * Returns false.
+ *
+ * @param file the file to check
+ * @return false
+ */
+ public boolean accept(File file) {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @param dir the directory to check
+ * @param name the filename
+ * @return false
+ */
+ public boolean accept(File dir, String name) {
+ return false;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/FileFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/FileFileFilter.java new file mode 100644 index 000000000..0d49eddd4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/FileFileFilter.java @@ -0,0 +1,60 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts <code>File</code>s that are files (not directories).
+ * <p>
+ * For example, here is how to print out a list of the real files
+ * within the current directory:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( FileFileFilter.FILE );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 155419 $ $Date: 2007-10-24 16:53:07 +0100 (Wed, 24 Oct 2007) $
+ */
+public class FileFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** Singleton instance of file filter */
+ public static final IOFileFilter FILE = new FileFileFilter();
+
+ /**
+ * Restrictive consructor.
+ */
+ protected FileFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file is a file.
+ *
+ * @param file the File to check
+ * @return true if the file is a file
+ */
+ public boolean accept(File file) {
+ return file.isFile();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/FileFilterUtils.java b/emailcommon/src/org/apache/commons/io/filefilter/FileFilterUtils.java new file mode 100644 index 000000000..71c37b1d2 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/FileFilterUtils.java @@ -0,0 +1,361 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.util.Date;
+
+/**
+ * Useful utilities for working with file filters. It provides access to all
+ * file filter implementations in this package so you don't have to import
+ * every class you use.
+ *
+ * @since Commons IO 1.0
+ * @version $Id: FileFilterUtils.java 609286 2008-01-06 10:01:26Z scolebourne $
+ *
+ * @author Stephen Colebourne
+ * @author Jeremias Maerki
+ * @author Masato Tezuka
+ * @author Rahul Akolkar
+ */
+public class FileFilterUtils {
+
+ /**
+ * FileFilterUtils is not normally instantiated.
+ */
+ public FileFilterUtils() {
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a filter that returns true if the filename starts with the specified text.
+ *
+ * @param prefix the filename prefix
+ * @return a prefix checking filter
+ */
+ public static IOFileFilter prefixFileFilter(String prefix) {
+ return new PrefixFileFilter(prefix);
+ }
+
+ /**
+ * Returns a filter that returns true if the filename ends with the specified text.
+ *
+ * @param suffix the filename suffix
+ * @return a suffix checking filter
+ */
+ public static IOFileFilter suffixFileFilter(String suffix) {
+ return new SuffixFileFilter(suffix);
+ }
+
+ /**
+ * Returns a filter that returns true if the filename matches the specified text.
+ *
+ * @param name the filename
+ * @return a name checking filter
+ */
+ public static IOFileFilter nameFileFilter(String name) {
+ return new NameFileFilter(name);
+ }
+
+ /**
+ * Returns a filter that checks if the file is a directory.
+ *
+ * @return file filter that accepts only directories and not files
+ */
+ public static IOFileFilter directoryFileFilter() {
+ return DirectoryFileFilter.DIRECTORY;
+ }
+
+ /**
+ * Returns a filter that checks if the file is a file (and not a directory).
+ *
+ * @return file filter that accepts only files and not directories
+ */
+ public static IOFileFilter fileFileFilter() {
+ return FileFileFilter.FILE;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a filter that ANDs the two specified filters.
+ *
+ * @param filter1 the first filter
+ * @param filter2 the second filter
+ * @return a filter that ANDs the two specified filters
+ */
+ public static IOFileFilter andFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
+ return new AndFileFilter(filter1, filter2);
+ }
+
+ /**
+ * Returns a filter that ORs the two specified filters.
+ *
+ * @param filter1 the first filter
+ * @param filter2 the second filter
+ * @return a filter that ORs the two specified filters
+ */
+ public static IOFileFilter orFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
+ return new OrFileFilter(filter1, filter2);
+ }
+
+ /**
+ * Returns a filter that NOTs the specified filter.
+ *
+ * @param filter the filter to invert
+ * @return a filter that NOTs the specified filter
+ */
+ public static IOFileFilter notFileFilter(IOFileFilter filter) {
+ return new NotFileFilter(filter);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a filter that always returns true.
+ *
+ * @return a true filter
+ */
+ public static IOFileFilter trueFileFilter() {
+ return TrueFileFilter.TRUE;
+ }
+
+ /**
+ * Returns a filter that always returns false.
+ *
+ * @return a false filter
+ */
+ public static IOFileFilter falseFileFilter() {
+ return FalseFileFilter.FALSE;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an <code>IOFileFilter</code> that wraps the
+ * <code>FileFilter</code> instance.
+ *
+ * @param filter the filter to be wrapped
+ * @return a new filter that implements IOFileFilter
+ */
+ public static IOFileFilter asFileFilter(FileFilter filter) {
+ return new DelegateFileFilter(filter);
+ }
+
+ /**
+ * Returns an <code>IOFileFilter</code> that wraps the
+ * <code>FilenameFilter</code> instance.
+ *
+ * @param filter the filter to be wrapped
+ * @return a new filter that implements IOFileFilter
+ */
+ public static IOFileFilter asFileFilter(FilenameFilter filter) {
+ return new DelegateFileFilter(filter);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a filter that returns true if the file was last modified after
+ * the specified cutoff time.
+ *
+ * @param cutoff the time threshold
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(long cutoff) {
+ return new AgeFileFilter(cutoff);
+ }
+
+ /**
+ * Returns a filter that filters files based on a cutoff time.
+ *
+ * @param cutoff the time threshold
+ * @param acceptOlder if true, older files get accepted, if false, newer
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(long cutoff, boolean acceptOlder) {
+ return new AgeFileFilter(cutoff, acceptOlder);
+ }
+
+ /**
+ * Returns a filter that returns true if the file was last modified after
+ * the specified cutoff date.
+ *
+ * @param cutoffDate the time threshold
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(Date cutoffDate) {
+ return new AgeFileFilter(cutoffDate);
+ }
+
+ /**
+ * Returns a filter that filters files based on a cutoff date.
+ *
+ * @param cutoffDate the time threshold
+ * @param acceptOlder if true, older files get accepted, if false, newer
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(Date cutoffDate, boolean acceptOlder) {
+ return new AgeFileFilter(cutoffDate, acceptOlder);
+ }
+
+ /**
+ * Returns a filter that returns true if the file was last modified after
+ * the specified reference file.
+ *
+ * @param cutoffReference the file whose last modification
+ * time is usesd as the threshold age of the files
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(File cutoffReference) {
+ return new AgeFileFilter(cutoffReference);
+ }
+
+ /**
+ * Returns a filter that filters files based on a cutoff reference file.
+ *
+ * @param cutoffReference the file whose last modification
+ * time is usesd as the threshold age of the files
+ * @param acceptOlder if true, older files get accepted, if false, newer
+ * @return an appropriately configured age file filter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter ageFileFilter(File cutoffReference, boolean acceptOlder) {
+ return new AgeFileFilter(cutoffReference, acceptOlder);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a filter that returns true if the file is bigger than a certain size.
+ *
+ * @param threshold the file size threshold
+ * @return an appropriately configured SizeFileFilter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter sizeFileFilter(long threshold) {
+ return new SizeFileFilter(threshold);
+ }
+
+ /**
+ * Returns a filter that filters based on file size.
+ *
+ * @param threshold the file size threshold
+ * @param acceptLarger if true, larger files get accepted, if false, smaller
+ * @return an appropriately configured SizeFileFilter
+ * @since Commons IO 1.2
+ */
+ public static IOFileFilter sizeFileFilter(long threshold, boolean acceptLarger) {
+ return new SizeFileFilter(threshold, acceptLarger);
+ }
+
+ /**
+ * Returns a filter that accepts files whose size is >= minimum size
+ * and <= maximum size.
+ *
+ * @param minSizeInclusive the minimum file size (inclusive)
+ * @param maxSizeInclusive the maximum file size (inclusive)
+ * @return an appropriately configured IOFileFilter
+ * @since Commons IO 1.3
+ */
+ public static IOFileFilter sizeRangeFileFilter(long minSizeInclusive, long maxSizeInclusive ) {
+ IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
+ IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
+ return new AndFileFilter(minimumFilter, maximumFilter);
+ }
+
+ //-----------------------------------------------------------------------
+ /* Constructed on demand and then cached */
+ private static IOFileFilter cvsFilter;
+
+ /* Constructed on demand and then cached */
+ private static IOFileFilter svnFilter;
+
+ /**
+ * Decorates a filter to make it ignore CVS directories.
+ * Passing in <code>null</code> will return a filter that accepts everything
+ * except CVS directories.
+ *
+ * @param filter the filter to decorate, null means an unrestricted filter
+ * @return the decorated filter, never null
+ * @since Commons IO 1.1 (method existed but had bug in 1.0)
+ */
+ public static IOFileFilter makeCVSAware(IOFileFilter filter) {
+ if (cvsFilter == null) {
+ cvsFilter = notFileFilter(
+ andFileFilter(directoryFileFilter(), nameFileFilter("CVS")));
+ }
+ if (filter == null) {
+ return cvsFilter;
+ } else {
+ return andFileFilter(filter, cvsFilter);
+ }
+ }
+
+ /**
+ * Decorates a filter to make it ignore SVN directories.
+ * Passing in <code>null</code> will return a filter that accepts everything
+ * except SVN directories.
+ *
+ * @param filter the filter to decorate, null means an unrestricted filter
+ * @return the decorated filter, never null
+ * @since Commons IO 1.1
+ */
+ public static IOFileFilter makeSVNAware(IOFileFilter filter) {
+ if (svnFilter == null) {
+ svnFilter = notFileFilter(
+ andFileFilter(directoryFileFilter(), nameFileFilter(".svn")));
+ }
+ if (filter == null) {
+ return svnFilter;
+ } else {
+ return andFileFilter(filter, svnFilter);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Decorates a filter so that it only applies to directories and not to files.
+ *
+ * @param filter the filter to decorate, null means an unrestricted filter
+ * @return the decorated filter, never null
+ * @since Commons IO 1.3
+ */
+ public static IOFileFilter makeDirectoryOnly(IOFileFilter filter) {
+ if (filter == null) {
+ return DirectoryFileFilter.DIRECTORY;
+ }
+ return new AndFileFilter(DirectoryFileFilter.DIRECTORY, filter);
+ }
+
+ /**
+ * Decorates a filter so that it only applies to files and not to directories.
+ *
+ * @param filter the filter to decorate, null means an unrestricted filter
+ * @return the decorated filter, never null
+ * @since Commons IO 1.3
+ */
+ public static IOFileFilter makeFileOnly(IOFileFilter filter) {
+ if (filter == null) {
+ return FileFileFilter.FILE;
+ }
+ return new AndFileFilter(FileFileFilter.FILE, filter);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/HiddenFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/HiddenFileFilter.java new file mode 100644 index 000000000..244153d5e --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/HiddenFileFilter.java @@ -0,0 +1,76 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter accepts <code>File</code>s that are hidden.
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>hidden</i> files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( HiddenFileFilter.HIDDEN );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the
+ * current directory's <i>visible</i> (i.e. not hidden) files:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( HiddenFileFilter.VISIBLE );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 587916 $
+ */
+public class HiddenFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** Singleton instance of <i>hidden</i> filter */
+ public static final IOFileFilter HIDDEN = new HiddenFileFilter();
+
+ /** Singleton instance of <i>visible</i> filter */
+ public static final IOFileFilter VISIBLE = new NotFileFilter(HIDDEN);
+
+ /**
+ * Restrictive consructor.
+ */
+ protected HiddenFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file is hidden.
+ *
+ * @param file the File to check
+ * @return <code>true</code> if the file is
+ * <i>hidden</i>, otherwise <code>false</code>.
+ */
+ public boolean accept(File file) {
+ return file.isHidden();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/IOFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/IOFileFilter.java new file mode 100644 index 000000000..5ebd82751 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/IOFileFilter.java @@ -0,0 +1,55 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+
+/**
+ * An interface which brings the FileFilter and FilenameFilter
+ * interfaces together.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 471628 $ $Date: 2006-11-06 04:06:45 +0000 (Mon, 06 Nov 2006) $
+ *
+ * @author Stephen Colebourne
+ */
+public interface IOFileFilter extends FileFilter, FilenameFilter {
+
+ /**
+ * Checks to see if the File should be accepted by this filter.
+ * <p>
+ * Defined in {@link java.io.FileFilter}.
+ *
+ * @param file the File to check
+ * @return true if this file matches the test
+ */
+ public boolean accept(File file);
+
+ /**
+ * Checks to see if the File should be accepted by this filter.
+ * <p>
+ * Defined in {@link java.io.FilenameFilter}.
+ *
+ * @param dir the directory File to check
+ * @param name the filename within the directory to check
+ * @return true if this file matches the test
+ */
+ public boolean accept(File dir, String name);
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/NameFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/NameFileFilter.java new file mode 100644 index 000000000..19fe380e1 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/NameFileFilter.java @@ -0,0 +1,194 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Filters filenames for a certain name.
+ * <p>
+ * For example, to print all files and directories in the
+ * current directory whose name is <code>Test</code>:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( new NameFileFilter("Test") );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ *
+ * @author Stephen Colebourne
+ * @author Federico Barbieri
+ * @author Serge Knystautas
+ * @author Peter Donald
+ */
+public class NameFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The filenames to search for */
+ private final String[] names;
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Constructs a new case-sensitive name file filter for a single name.
+ *
+ * @param name the name to allow, must not be null
+ * @throws IllegalArgumentException if the name is null
+ */
+ public NameFileFilter(String name) {
+ this(name, null);
+ }
+
+ /**
+ * Construct a new name file filter specifying case-sensitivity.
+ *
+ * @param name the name to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the name is null
+ */
+ public NameFileFilter(String name, IOCase caseSensitivity) {
+ if (name == null) {
+ throw new IllegalArgumentException("The wildcard must not be null");
+ }
+ this.names = new String[] {name};
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new case-sensitive name file filter for an array of names.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param names the names to allow, must not be null
+ * @throws IllegalArgumentException if the names array is null
+ */
+ public NameFileFilter(String[] names) {
+ this(names, null);
+ }
+
+ /**
+ * Constructs a new name file filter for an array of names specifying case-sensitivity.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param names the names to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the names array is null
+ */
+ public NameFileFilter(String[] names, IOCase caseSensitivity) {
+ if (names == null) {
+ throw new IllegalArgumentException("The array of names must not be null");
+ }
+ this.names = names;
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new case-sensitive name file filter for a list of names.
+ *
+ * @param names the names to allow, must not be null
+ * @throws IllegalArgumentException if the name list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public NameFileFilter(List<String> names) {
+ this(names, null);
+ }
+
+ /**
+ * Constructs a new name file filter for a list of names specifying case-sensitivity.
+ *
+ * @param names the names to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the name list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public NameFileFilter(List<String> names, IOCase caseSensitivity) {
+ if (names == null) {
+ throw new IllegalArgumentException("The list of names must not be null");
+ }
+ this.names = names.toArray(new String[names.size()]);
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks to see if the filename matches.
+ *
+ * @param file the File to check
+ * @return true if the filename matches
+ */
+ @Override
+ public boolean accept(File file) {
+ String name = file.getName();
+ for (int i = 0; i < this.names.length; i++) {
+ if (caseSensitivity.checkEquals(name, names[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks to see if the filename matches.
+ *
+ * @param file the File directory
+ * @param name the filename
+ * @return true if the filename matches
+ */
+ @Override
+ public boolean accept(File file, String name) {
+ for (int i = 0; i < names.length; i++) {
+ if (caseSensitivity.checkEquals(name, names[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (names != null) {
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(names[i]);
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/NotFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/NotFileFilter.java new file mode 100644 index 000000000..710c8ecf3 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/NotFileFilter.java @@ -0,0 +1,78 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This filter produces a logical NOT of the filters specified.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 591058 $ $Date: 2007-11-01 15:47:05 +0000 (Thu, 01 Nov 2007) $
+ *
+ * @author Stephen Colebourne
+ */
+public class NotFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The filter */
+ private final IOFileFilter filter;
+
+ /**
+ * Constructs a new file filter that NOTs the result of another filters.
+ *
+ * @param filter the filter, must not be null
+ * @throws IllegalArgumentException if the filter is null
+ */
+ public NotFileFilter(IOFileFilter filter) {
+ if (filter == null) {
+ throw new IllegalArgumentException("The filter must not be null");
+ }
+ this.filter = filter;
+ }
+
+ /**
+ * Checks to see if both filters are true.
+ *
+ * @param file the File to check
+ * @return true if the filter returns false
+ */
+ public boolean accept(File file) {
+ return ! filter.accept(file);
+ }
+
+ /**
+ * Checks to see if both filters are true.
+ *
+ * @param file the File directory
+ * @param name the filename
+ * @return true if the filter returns false
+ */
+ public boolean accept(File file, String name) {
+ return ! filter.accept(file, name);
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ public String toString() {
+ return super.toString() + "(" + filter.toString() + ")";
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/OrFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/OrFileFilter.java new file mode 100644 index 000000000..520eefa4f --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/OrFileFilter.java @@ -0,0 +1,164 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A {@link java.io.FileFilter} providing conditional OR logic across a list of
+ * file filters. This filter returns <code>true</code> if any filters in the
+ * list return <code>true</code>. Otherwise, it returns <code>false</code>.
+ * Checking of the file filter list stops when the first filter returns
+ * <code>true</code>.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ *
+ * @author Steven Caswell
+ */
+public class OrFileFilter
+ extends AbstractFileFilter
+ implements ConditionalFileFilter, Serializable {
+
+ /** The list of file filters. */
+ private List<IOFileFilter> fileFilters;
+
+ /**
+ * Constructs a new instance of <code>OrFileFilter</code>.
+ *
+ * @since Commons IO 1.1
+ */
+ public OrFileFilter() {
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ }
+
+ /**
+ * Constructs a new instance of <code>OrFileFilter</code>
+ * with the specified filters.
+ *
+ * @param fileFilters the file filters for this filter, copied, null ignored
+ * @since Commons IO 1.1
+ */
+ public OrFileFilter(final List<IOFileFilter> fileFilters) {
+ if (fileFilters == null) {
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ } else {
+ this.fileFilters = new ArrayList<IOFileFilter>(fileFilters);
+ }
+ }
+
+ /**
+ * Constructs a new file filter that ORs the result of two other filters.
+ *
+ * @param filter1 the first filter, must not be null
+ * @param filter2 the second filter, must not be null
+ * @throws IllegalArgumentException if either filter is null
+ */
+ public OrFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
+ if (filter1 == null || filter2 == null) {
+ throw new IllegalArgumentException("The filters must not be null");
+ }
+ this.fileFilters = new ArrayList<IOFileFilter>();
+ addFileFilter(filter1);
+ addFileFilter(filter2);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addFileFilter(final IOFileFilter ioFileFilter) {
+ this.fileFilters.add(ioFileFilter);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<IOFileFilter> getFileFilters() {
+ return Collections.unmodifiableList(this.fileFilters);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeFileFilter(IOFileFilter ioFileFilter) {
+ return this.fileFilters.remove(ioFileFilter);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setFileFilters(final List<IOFileFilter> fileFilters) {
+ this.fileFilters = fileFilters;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(final File file) {
+ for (Iterator<IOFileFilter> iter = this.fileFilters.iterator(); iter.hasNext();) {
+ IOFileFilter fileFilter = iter.next();
+ if (fileFilter.accept(file)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(final File file, final String name) {
+ for (Iterator<IOFileFilter> iter = this.fileFilters.iterator(); iter.hasNext();) {
+ IOFileFilter fileFilter = iter.next();
+ if (fileFilter.accept(file, name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (fileFilters != null) {
+ for (int i = 0; i < fileFilters.size(); i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ Object filter = fileFilters.get(i);
+ buffer.append(filter == null ? "null" : filter.toString());
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/PrefixFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/PrefixFileFilter.java new file mode 100644 index 000000000..8c6b737fb --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/PrefixFileFilter.java @@ -0,0 +1,200 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Filters filenames for a certain prefix.
+ * <p>
+ * For example, to print all files and directories in the
+ * current directory whose name starts with <code>Test</code>:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( new PrefixFileFilter("Test") );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ *
+ * @author Stephen Colebourne
+ * @author Federico Barbieri
+ * @author Serge Knystautas
+ * @author Peter Donald
+ */
+public class PrefixFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The filename prefixes to search for */
+ private final String[] prefixes;
+
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Constructs a new Prefix file filter for a single prefix.
+ *
+ * @param prefix the prefix to allow, must not be null
+ * @throws IllegalArgumentException if the prefix is null
+ */
+ public PrefixFileFilter(String prefix) {
+ this(prefix, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Prefix file filter for a single prefix
+ * specifying case-sensitivity.
+ *
+ * @param prefix the prefix to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the prefix is null
+ * @since Commons IO 1.4
+ */
+ public PrefixFileFilter(String prefix, IOCase caseSensitivity) {
+ if (prefix == null) {
+ throw new IllegalArgumentException("The prefix must not be null");
+ }
+ this.prefixes = new String[] {prefix};
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new Prefix file filter for any of an array of prefixes.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param prefixes the prefixes to allow, must not be null
+ * @throws IllegalArgumentException if the prefix array is null
+ */
+ public PrefixFileFilter(String[] prefixes) {
+ this(prefixes, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Prefix file filter for any of an array of prefixes
+ * specifying case-sensitivity.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param prefixes the prefixes to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the prefix is null
+ * @since Commons IO 1.4
+ */
+ public PrefixFileFilter(String[] prefixes, IOCase caseSensitivity) {
+ if (prefixes == null) {
+ throw new IllegalArgumentException("The array of prefixes must not be null");
+ }
+ this.prefixes = prefixes;
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new Prefix file filter for a list of prefixes.
+ *
+ * @param prefixes the prefixes to allow, must not be null
+ * @throws IllegalArgumentException if the prefix list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public PrefixFileFilter(List<String> prefixes) {
+ this(prefixes, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Prefix file filter for a list of prefixes
+ * specifying case-sensitivity.
+ *
+ * @param prefixes the prefixes to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the prefix list is null
+ * @throws ClassCastException if the list does not contain Strings
+ * @since Commons IO 1.4
+ */
+ public PrefixFileFilter(List<String> prefixes, IOCase caseSensitivity) {
+ if (prefixes == null) {
+ throw new IllegalArgumentException("The list of prefixes must not be null");
+ }
+ this.prefixes = prefixes.toArray(new String[prefixes.size()]);
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Checks to see if the filename starts with the prefix.
+ *
+ * @param file the File to check
+ * @return true if the filename starts with one of our prefixes
+ */
+ @Override
+ public boolean accept(File file) {
+ String name = file.getName();
+ for (int i = 0; i < this.prefixes.length; i++) {
+ if (caseSensitivity.checkStartsWith(name, prefixes[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks to see if the filename starts with the prefix.
+ *
+ * @param file the File directory
+ * @param name the filename
+ * @return true if the filename starts with one of our prefixes
+ */
+ @Override
+ public boolean accept(File file, String name) {
+ for (int i = 0; i < prefixes.length; i++) {
+ if (caseSensitivity.checkStartsWith(name, prefixes[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (prefixes != null) {
+ for (int i = 0; i < prefixes.length; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(prefixes[i]);
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/RegexFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/RegexFileFilter.java new file mode 100644 index 000000000..b49a1bd3b --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/RegexFileFilter.java @@ -0,0 +1,122 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Filters files using supplied regular expression(s).
+ * <p/>
+ * See java.util.regex.Pattern for regex matching rules
+ * <p/>
+ *
+ * <p/>
+ * e.g.
+ * <pre>
+ * File dir = new File(".");
+ * FileFilter fileFilter = new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$");
+ * File[] files = dir.listFiles(fileFilter);
+ * for (int i = 0; i < files.length; i++) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @author Oliver Siegmar
+ * @version $Revision: 606381 $
+ * @since Commons IO 1.4
+ */
+public class RegexFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The regular expression pattern that will be used to match filenames */
+ private final Pattern pattern;
+
+ /**
+ * Construct a new regular expression filter.
+ *
+ * @param pattern regular string expression to match
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public RegexFileFilter(String pattern) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern is missing");
+ }
+
+ this.pattern = Pattern.compile(pattern);
+ }
+
+ /**
+ * Construct a new regular expression filter with the specified flags case sensitivity.
+ *
+ * @param pattern regular string expression to match
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public RegexFileFilter(String pattern, IOCase caseSensitivity) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern is missing");
+ }
+ int flags = 0;
+ if (caseSensitivity != null && !caseSensitivity.isCaseSensitive()) {
+ flags = Pattern.CASE_INSENSITIVE;
+ }
+ this.pattern = Pattern.compile(pattern, flags);
+ }
+
+ /**
+ * Construct a new regular expression filter with the specified flags.
+ *
+ * @param pattern regular string expression to match
+ * @param flags pattern flags - e.g. {@link Pattern#CASE_INSENSITIVE}
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public RegexFileFilter(String pattern, int flags) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern is missing");
+ }
+ this.pattern = Pattern.compile(pattern, flags);
+ }
+
+ /**
+ * Construct a new regular expression filter for a compiled regular expression
+ *
+ * @param pattern regular expression to match
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public RegexFileFilter(Pattern pattern) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern is missing");
+ }
+
+ this.pattern = pattern;
+ }
+
+ /**
+ * Checks to see if the filename matches one of the regular expressions.
+ *
+ * @param dir the file directory
+ * @param name the filename
+ * @return true if the filename matches one of the regular expressions
+ */
+ public boolean accept(File dir, String name) {
+ return (pattern.matcher(name).matches());
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/SizeFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/SizeFileFilter.java new file mode 100644 index 000000000..614e4243f --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/SizeFileFilter.java @@ -0,0 +1,103 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * Filters files based on size, can filter either smaller files or
+ * files equal to or larger than a given threshold.
+ * <p>
+ * For example, to print all files and directories in the
+ * current directory whose size is greater than 1 MB:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( new SizeFileFilter(1024 * 1024) );
+ * for ( int i = 0; i < files.length; i++ ) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @author Rahul Akolkar
+ * @version $Id: SizeFileFilter.java 591058 2007-11-01 15:47:05Z niallp $
+ * @since Commons IO 1.2
+ */
+public class SizeFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The size threshold. */
+ private final long size;
+ /** Whether the files accepted will be larger or smaller. */
+ private final boolean acceptLarger;
+
+ /**
+ * Constructs a new size file filter for files equal to or
+ * larger than a certain size.
+ *
+ * @param size the threshold size of the files
+ * @throws IllegalArgumentException if the size is negative
+ */
+ public SizeFileFilter(long size) {
+ this(size, true);
+ }
+
+ /**
+ * Constructs a new size file filter for files based on a certain size
+ * threshold.
+ *
+ * @param size the threshold size of the files
+ * @param acceptLarger if true, files equal to or larger are accepted,
+ * otherwise smaller ones (but not equal to)
+ * @throws IllegalArgumentException if the size is negative
+ */
+ public SizeFileFilter(long size, boolean acceptLarger) {
+ if (size < 0) {
+ throw new IllegalArgumentException("The size must be non-negative");
+ }
+ this.size = size;
+ this.acceptLarger = acceptLarger;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks to see if the size of the file is favorable.
+ * <p>
+ * If size equals threshold and smaller files are required,
+ * file <b>IS NOT</b> selected.
+ * If size equals threshold and larger files are required,
+ * file <b>IS</b> selected.
+ *
+ * @param file the File to check
+ * @return true if the filename matches
+ */
+ public boolean accept(File file) {
+ boolean smaller = file.length() < size;
+ return acceptLarger ? !smaller : smaller;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ public String toString() {
+ String condition = acceptLarger ? ">=" : "<";
+ return super.toString() + "(" + condition + size + ")";
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/SuffixFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/SuffixFileFilter.java new file mode 100644 index 000000000..8bdf781a4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/SuffixFileFilter.java @@ -0,0 +1,201 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.io.IOCase;
+
+/**
+ * Filters files based on the suffix (what the filename ends with).
+ * This is used in retrieving all the files of a particular type.
+ * <p>
+ * For example, to retrieve and print all <code>*.java</code> files
+ * in the current directory:
+ *
+ * <pre>
+ * File dir = new File(".");
+ * String[] files = dir.list( new SuffixFileFilter(".java") );
+ * for (int i = 0; i < files.length; i++) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ *
+ * @author Stephen Colebourne
+ * @author Federico Barbieri
+ * @author Serge Knystautas
+ * @author Peter Donald
+ */
+public class SuffixFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The filename suffixes to search for */
+ private final String[] suffixes;
+
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Constructs a new Suffix file filter for a single extension.
+ *
+ * @param suffix the suffix to allow, must not be null
+ * @throws IllegalArgumentException if the suffix is null
+ */
+ public SuffixFileFilter(String suffix) {
+ this(suffix, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Suffix file filter for a single extension
+ * specifying case-sensitivity.
+ *
+ * @param suffix the suffix to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the suffix is null
+ * @since Commons IO 1.4
+ */
+ public SuffixFileFilter(String suffix, IOCase caseSensitivity) {
+ if (suffix == null) {
+ throw new IllegalArgumentException("The suffix must not be null");
+ }
+ this.suffixes = new String[] {suffix};
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new Suffix file filter for an array of suffixs.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param suffixes the suffixes to allow, must not be null
+ * @throws IllegalArgumentException if the suffix array is null
+ */
+ public SuffixFileFilter(String[] suffixes) {
+ this(suffixes, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Suffix file filter for an array of suffixs
+ * specifying case-sensitivity.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param suffixes the suffixes to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the suffix array is null
+ * @since Commons IO 1.4
+ */
+ public SuffixFileFilter(String[] suffixes, IOCase caseSensitivity) {
+ if (suffixes == null) {
+ throw new IllegalArgumentException("The array of suffixes must not be null");
+ }
+ this.suffixes = suffixes;
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Constructs a new Suffix file filter for a list of suffixes.
+ *
+ * @param suffixes the suffixes to allow, must not be null
+ * @throws IllegalArgumentException if the suffix list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public SuffixFileFilter(List<String> suffixes) {
+ this(suffixes, IOCase.SENSITIVE);
+ }
+
+ /**
+ * Constructs a new Suffix file filter for a list of suffixes
+ * specifying case-sensitivity.
+ *
+ * @param suffixes the suffixes to allow, must not be null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the suffix list is null
+ * @throws ClassCastException if the list does not contain Strings
+ * @since Commons IO 1.4
+ */
+ public SuffixFileFilter(List<String> suffixes, IOCase caseSensitivity) {
+ if (suffixes == null) {
+ throw new IllegalArgumentException("The list of suffixes must not be null");
+ }
+ this.suffixes = suffixes.toArray(new String[suffixes.size()]);
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Checks to see if the filename ends with the suffix.
+ *
+ * @param file the File to check
+ * @return true if the filename ends with one of our suffixes
+ */
+ @Override
+ public boolean accept(File file) {
+ String name = file.getName();
+ for (int i = 0; i < this.suffixes.length; i++) {
+ if (caseSensitivity.checkEndsWith(name, suffixes[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks to see if the filename ends with the suffix.
+ *
+ * @param file the File directory
+ * @param name the filename
+ * @return true if the filename ends with one of our suffixes
+ */
+ @Override
+ public boolean accept(File file, String name) {
+ for (int i = 0; i < this.suffixes.length; i++) {
+ if (caseSensitivity.checkEndsWith(name, suffixes[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (suffixes != null) {
+ for (int i = 0; i < suffixes.length; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(suffixes[i]);
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/TrueFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/TrueFileFilter.java new file mode 100644 index 000000000..be1b13a7e --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/TrueFileFilter.java @@ -0,0 +1,72 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * A file filter that always returns true.
+ *
+ * @since Commons IO 1.0
+ * @version $Revision: 587978 $ $Date: 2007-10-24 20:36:51 +0100 (Wed, 24 Oct 2007) $
+ *
+ * @author Stephen Colebourne
+ */
+public class TrueFileFilter implements IOFileFilter, Serializable {
+
+ /**
+ * Singleton instance of true filter.
+ * @since Commons IO 1.3
+ */
+ public static final IOFileFilter TRUE = new TrueFileFilter();
+ /**
+ * Singleton instance of true filter.
+ * Please use the identical TrueFileFilter.TRUE constant.
+ * The new name is more JDK 1.5 friendly as it doesn't clash with other
+ * values when using static imports.
+ */
+ public static final IOFileFilter INSTANCE = TRUE;
+
+ /**
+ * Restrictive consructor.
+ */
+ protected TrueFileFilter() {
+ }
+
+ /**
+ * Returns true.
+ *
+ * @param file the file to check
+ * @return true
+ */
+ public boolean accept(File file) {
+ return true;
+ }
+
+ /**
+ * Returns true.
+ *
+ * @param dir the directory to check
+ * @param name the filename
+ * @return true
+ */
+ public boolean accept(File dir, String name) {
+ return true;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/WildcardFileFilter.java b/emailcommon/src/org/apache/commons/io/filefilter/WildcardFileFilter.java new file mode 100644 index 000000000..f3a1ee930 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/WildcardFileFilter.java @@ -0,0 +1,199 @@ +/*
+ * 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.filefilter;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOCase;
+
+/**
+ * Filters files using the supplied wildcards.
+ * <p>
+ * This filter selects files and directories based on one or more wildcards.
+ * Testing is case-sensitive by default, but this can be configured.
+ * <p>
+ * The wildcard matcher uses the characters '?' and '*' to represent a
+ * single or multiple wildcard characters.
+ * This is the same as often found on Dos/Unix command lines.
+ * The extension check is case-sensitive by .
+ * See {@link FilenameUtils#wildcardMatchOnSystem} for more information.
+ * <p>
+ * For example:
+ * <pre>
+ * File dir = new File(".");
+ * FileFilter fileFilter = new WildcardFileFilter("*test*.java~*~");
+ * File[] files = dir.listFiles(fileFilter);
+ * for (int i = 0; i < files.length; i++) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @author Jason Anderson
+ * @version $Revision: 155419 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $
+ * @since Commons IO 1.3
+ */
+public class WildcardFileFilter extends AbstractFileFilter implements Serializable {
+
+ /** The wildcards that will be used to match filenames. */
+ private final String[] wildcards;
+ /** Whether the comparison is case sensitive. */
+ private final IOCase caseSensitivity;
+
+ /**
+ * Construct a new case-sensitive wildcard filter for a single wildcard.
+ *
+ * @param wildcard the wildcard to match
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public WildcardFileFilter(String wildcard) {
+ this(wildcard, null);
+ }
+
+ /**
+ * Construct a new wildcard filter for a single wildcard specifying case-sensitivity.
+ *
+ * @param wildcard the wildcard to match, not null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the pattern is null
+ */
+ public WildcardFileFilter(String wildcard, IOCase caseSensitivity) {
+ if (wildcard == null) {
+ throw new IllegalArgumentException("The wildcard must not be null");
+ }
+ this.wildcards = new String[] { wildcard };
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Construct a new case-sensitive wildcard filter for an array of wildcards.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param wildcards the array of wildcards to match
+ * @throws IllegalArgumentException if the pattern array is null
+ */
+ public WildcardFileFilter(String[] wildcards) {
+ this(wildcards, null);
+ }
+
+ /**
+ * Construct a new wildcard filter for an array of wildcards specifying case-sensitivity.
+ * <p>
+ * The array is not cloned, so could be changed after constructing the
+ * instance. This would be inadvisable however.
+ *
+ * @param wildcards the array of wildcards to match, not null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the pattern array is null
+ */
+ public WildcardFileFilter(String[] wildcards, IOCase caseSensitivity) {
+ if (wildcards == null) {
+ throw new IllegalArgumentException("The wildcard array must not be null");
+ }
+ this.wildcards = wildcards;
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ /**
+ * Construct a new case-sensitive wildcard filter for a list of wildcards.
+ *
+ * @param wildcards the list of wildcards to match, not null
+ * @throws IllegalArgumentException if the pattern list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public WildcardFileFilter(List<String> wildcards) {
+ this(wildcards, null);
+ }
+
+ /**
+ * Construct a new wildcard filter for a list of wildcards specifying case-sensitivity.
+ *
+ * @param wildcards the list of wildcards to match, not null
+ * @param caseSensitivity how to handle case sensitivity, null means case-sensitive
+ * @throws IllegalArgumentException if the pattern list is null
+ * @throws ClassCastException if the list does not contain Strings
+ */
+ public WildcardFileFilter(List<String> wildcards, IOCase caseSensitivity) {
+ if (wildcards == null) {
+ throw new IllegalArgumentException("The wildcard list must not be null");
+ }
+ this.wildcards = wildcards.toArray(new String[wildcards.size()]);
+ this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks to see if the filename matches one of the wildcards.
+ *
+ * @param dir the file directory
+ * @param name the filename
+ * @return true if the filename matches one of the wildcards
+ */
+ @Override
+ public boolean accept(File dir, String name) {
+ for (int i = 0; i < wildcards.length; i++) {
+ if (FilenameUtils.wildcardMatch(name, wildcards[i], caseSensitivity)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks to see if the filename matches one of the wildcards.
+ *
+ * @param file the file to check
+ * @return true if the filename matches one of the wildcards
+ */
+ @Override
+ public boolean accept(File file) {
+ String name = file.getName();
+ for (int i = 0; i < wildcards.length; i++) {
+ if (FilenameUtils.wildcardMatch(name, wildcards[i], caseSensitivity)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide a String representaion of this file filter.
+ *
+ * @return a String representaion
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append("(");
+ if (wildcards != null) {
+ for (int i = 0; i < wildcards.length; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(wildcards[i]);
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/filefilter/package.html b/emailcommon/src/org/apache/commons/io/filefilter/package.html new file mode 100644 index 000000000..7a45f251d --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/filefilter/package.html @@ -0,0 +1,143 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body>
+<p>This package defines an interface (IOFileFilter) that combines both
+{@link java.io.FileFilter} and {@link java.io.FilenameFilter}. Besides
+that the package offers a series of ready-to-use implementations of the
+IOFileFilter interface including implementation that allow you to combine
+other such filters.</p>
+<p>These filter can be used to list files or in {@link java.awt.FileDialog},
+for example.</p>
+
+<p>There are a number of 'primitive' filters:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td><a href="DirectoryFileFilter.html">DirectoryFilter</a></td>
+ <td>Only accept directories</td>
+ </tr>
+ <tr>
+ <td><a href="PrefixFileFilter.html">PrefixFileFilter</a></td>
+ <td>Filter based on a prefix</td>
+ </tr>
+ <tr>
+ <td><a href="SuffixFileFilter.html">SuffixFileFilter</a></td>
+ <td>Filter based on a suffix</td>
+ </tr>
+ <tr>
+ <td><a href="NameFileFilter.html">NameFileFilter</a></td>
+ <td>Filter based on a filename</td>
+ </tr>
+ <tr>
+ <td><a href="WildcardFileFilter.html">WildcardFileFilter</a></td>
+ <td>Filter based on wildcards</td>
+ </tr>
+ <tr>
+ <td><a href="AgeFileFilter.html">AgeFileFilter</a></td>
+ <td>Filter based on last modified time of file</td>
+ </tr>
+ <tr>
+ <td><a href="SizeFileFilter.html">SizeFileFilter</a></td>
+ <td>Filter based on file size</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>And there are five 'boolean' filters:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td><a href="TrueFileFilter.html">TrueFileFilter</a></td>
+ <td>Accept all files</td>
+ </tr>
+ <tr>
+ <td><a href="FalseFileFilter.html">FalseFileFilter</a></td>
+ <td>Accept no files</td>
+ </tr>
+ <tr>
+ <td><a href="NotFileFilter.html">NotFileFilter</a></td>
+ <td>Applies a logical NOT to an existing filter</td>
+ </tr>
+ <tr>
+ <td><a href="AndFileFilter.html">AndFileFilter</a></td>
+ <td>Combines two filters using a logical AND</td>
+ </tr>
+ <tr>
+ <td><a href="OrFileFilter.html">OrFileFilter</a></td>
+ <td>Combines two filter using a logical OR</td>
+ </tr>
+
+ </tbody>
+</table>
+
+<p>These boolean FilenameFilters can be nested, to allow arbitrary expressions.
+For example, here is how one could print all non-directory files in the
+current directory, starting with "A", and ending in ".java" or ".class":</p>
+
+<pre>
+ File dir = new File(".");
+ String[] files = dir.list(
+ new AndFileFilter(
+ new AndFileFilter(
+ new PrefixFileFilter("A"),
+ new OrFileFilter(
+ new SuffixFileFilter(".class"),
+ new SuffixFileFilter(".java")
+ )
+ ),
+ new NotFileFilter(
+ new DirectoryFileFilter()
+ )
+ )
+ );
+ for ( int i=0; i<files.length; i++ ) {
+ System.out.println(files[i]);
+ }
+</pre>
+
+<p>This package also contains a utility class:
+<a href="FileFilterUtils.html">FileFilterUtils</a>. It allows you to use all
+file filters without having to put them in the import section. Here's how the
+above example will look using FileFilterUtils:</p>
+<pre>
+ File dir = new File(".");
+ String[] files = dir.list(
+ FileFilterUtils.andFileFilter(
+ FileFilterUtils.andFileFilter(
+ FileFilterUtils.prefixFileFilter("A"),
+ FileFilterUtils.orFileFilter(
+ FileFilterUtils.suffixFileFilter(".class"),
+ FileFilterUtils.suffixFileFilter(".java")
+ )
+ ),
+ FileFilterUtils.notFileFilter(
+ FileFilterUtils.directoryFileFilter()
+ )
+ )
+ );
+ for ( int i=0; i<files.length; i++ ) {
+ System.out.println(files[i]);
+ }
+</pre>
+<p>There are a few other goodies in that class so please have a look at the
+documentation in detail.</p>
+ </body>
+</html>
diff --git a/emailcommon/src/org/apache/commons/io/input/AutoCloseInputStream.java b/emailcommon/src/org/apache/commons/io/input/AutoCloseInputStream.java new file mode 100644 index 000000000..bb62358f7 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/AutoCloseInputStream.java @@ -0,0 +1,129 @@ +/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Proxy stream that closes and discards the underlying stream as soon as the
+ * end of input has been reached or when the stream is explicitly closed.
+ * Not even a reference to the underlying stream is kept after it has been
+ * closed, so any allocated in-memory buffers can be freed even if the
+ * client application still keeps a reference to the proxy stream.
+ * <p>
+ * This class is typically used to release any resources related to an open
+ * stream as soon as possible even if the client application (by not explicitly
+ * closing the stream when no longer needed) or the underlying stream (by not
+ * releasing resources once the last byte has been read) do not do that.
+ *
+ * @version $Id: AutoCloseInputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ * @since Commons IO 1.4
+ */
+public class AutoCloseInputStream extends ProxyInputStream {
+
+ /**
+ * Creates an automatically closing proxy for the given input stream.
+ *
+ * @param in underlying input stream
+ */
+ public AutoCloseInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * Closes the underlying input stream and replaces the reference to it
+ * with a {@link ClosedInputStream} instance.
+ * <p>
+ * This method is automatically called by the read methods when the end
+ * of input has been reached.
+ * <p>
+ * Note that it is safe to call this method any number of times. The original
+ * underlying input stream is closed and discarded only once when this
+ * method is first called.
+ *
+ * @throws IOException if the underlying input stream can not be closed
+ */
+ public void close() throws IOException {
+ in.close();
+ in = new ClosedInputStream();
+ }
+
+ /**
+ * Reads and returns a single byte from the underlying input stream.
+ * If the underlying stream returns -1, the {@link #close()} method is
+ * called to automatically close and discard the stream.
+ *
+ * @return next byte in the stream, or -1 if no more bytes are available
+ * @throws IOException if the stream could not be read or closed
+ */
+ public int read() throws IOException {
+ int n = in.read();
+ if (n == -1) {
+ close();
+ }
+ return n;
+ }
+
+ /**
+ * Reads and returns bytes from the underlying input stream to the given
+ * buffer. If the underlying stream returns -1, the {@link #close()} method
+ * i called to automatically close and discard the stream.
+ *
+ * @param b buffer to which bytes from the stream are written
+ * @return number of bytes read, or -1 if no more bytes are available
+ * @throws IOException if the stream could not be read or closed
+ */
+ public int read(byte[] b) throws IOException {
+ int n = in.read(b);
+ if (n == -1) {
+ close();
+ }
+ return n;
+ }
+
+ /**
+ * Reads and returns bytes from the underlying input stream to the given
+ * buffer. If the underlying stream returns -1, the {@link #close()} method
+ * i called to automatically close and discard the stream.
+ *
+ * @param b buffer to which bytes from the stream are written
+ * @param off start offset within the buffer
+ * @param len maximum number of bytes to read
+ * @return number of bytes read, or -1 if no more bytes are available
+ * @throws IOException if the stream could not be read or closed
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ int n = in.read(b, off, len);
+ if (n == -1) {
+ close();
+ }
+ return n;
+ }
+
+ /**
+ * Ensures that the stream is closed before it gets garbage-collected.
+ * As mentioned in {@link #close()}, this is a no-op if the stream has
+ * already been closed.
+ * @throws Throwable if an error occurs
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/CharSequenceReader.java b/emailcommon/src/org/apache/commons/io/input/CharSequenceReader.java new file mode 100644 index 000000000..6ee11d87d --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/CharSequenceReader.java @@ -0,0 +1,155 @@ +/*
+ * 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.input;
+
+import java.io.Reader;
+import java.io.Serializable;
+
+/**
+ * {@link Reader} implementation that can read from String, StringBuffer,
+ * StringBuilder or CharBuffer.
+ * <p>
+ * <strong>Note:</strong> Supports {@link #mark(int)} and {@link #reset()}.
+ *
+ * @version $Revision: 610516 $ $Date: 2008-01-09 19:05:05 +0000 (Wed, 09 Jan 2008) $
+ * @since Commons IO 1.4
+ */
+public class CharSequenceReader extends Reader implements Serializable {
+
+ private final CharSequence charSequence;
+ private int idx;
+ private int mark;
+
+ /**
+ * Construct a new instance with the specified character sequence.
+ *
+ * @param charSequence The character sequence, may be <code>null</code>
+ */
+ public CharSequenceReader(CharSequence charSequence) {
+ this.charSequence = (charSequence != null ? charSequence : "");
+ }
+
+ /**
+ * Close resets the file back to the start and removes any marked position.
+ */
+ public void close() {
+ idx = 0;
+ mark = 0;
+ }
+
+ /**
+ * Mark the current position.
+ *
+ * @param readAheadLimit ignored
+ */
+ public void mark(int readAheadLimit) {
+ mark = idx;
+ }
+
+ /**
+ * Mark is supported (returns true).
+ *
+ * @return <code>true</code>
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Read a single character.
+ *
+ * @return the next character from the character sequence
+ * or -1 if the end has been reached.
+ */
+ public int read() {
+ if (idx >= charSequence.length()) {
+ return -1;
+ } else {
+ return charSequence.charAt(idx++);
+ }
+ }
+
+ /**
+ * Read the sepcified number of characters into the array.
+ *
+ * @param array The array to store the characters in
+ * @param offset The starting position in the array to store
+ * @param length The maximum number of characters to read
+ * @return The number of characters read or -1 if there are
+ * no more
+ */
+ public int read(char[] array, int offset, int length) {
+ if (idx >= charSequence.length()) {
+ return -1;
+ }
+ if (array == null) {
+ throw new NullPointerException("Character array is missing");
+ }
+ if (length < 0 || (offset + length) > array.length) {
+ throw new IndexOutOfBoundsException("Array Size=" + array.length +
+ ", offset=" + offset + ", length=" + length);
+ }
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ int c = read();
+ if (c == -1) {
+ return count;
+ }
+ array[offset + i] = (char)c;
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Reset the reader to the last marked position (or the beginning if
+ * mark has not been called).
+ */
+ public void reset() {
+ idx = mark;
+ }
+
+ /**
+ * Skip the specified number of characters.
+ *
+ * @param n The number of characters to skip
+ * @return The actual number of characters skipped
+ */
+ public long skip(long n) {
+ if (n < 0) {
+ throw new IllegalArgumentException(
+ "Number of characters to skip is less than zero: " + n);
+ }
+ if (idx >= charSequence.length()) {
+ return -1;
+ }
+ int dest = (int)Math.min(charSequence.length(), (idx + n));
+ int count = dest - idx;
+ idx = dest;
+ return count;
+ }
+
+ /**
+ * Return a String representation of the underlying
+ * character sequence.
+ *
+ * @return The contents of the character sequence
+ */
+ public String toString() {
+ return charSequence.toString();
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java b/emailcommon/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java new file mode 100644 index 000000000..13d048946 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java @@ -0,0 +1,77 @@ +/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.io.StreamCorruptedException;
+
+/**
+ * A special ObjectInputStream that loads a class based on a specified
+ * <code>ClassLoader</code> rather than the system default.
+ * <p>
+ * This is useful in dynamic container environments.
+ *
+ * @author Paul Hammant
+ * @version $Id: ClassLoaderObjectInputStream.java 437567 2006-08-28 06:39:07Z bayard $
+ * @since Commons IO 1.1
+ */
+public class ClassLoaderObjectInputStream extends ObjectInputStream {
+
+ /** The class loader to use. */
+ private ClassLoader classLoader;
+
+ /**
+ * Constructs a new ClassLoaderObjectInputStream.
+ *
+ * @param classLoader the ClassLoader from which classes should be loaded
+ * @param inputStream the InputStream to work on
+ * @throws IOException in case of an I/O error
+ * @throws StreamCorruptedException if the stream is corrupted
+ */
+ public ClassLoaderObjectInputStream(
+ ClassLoader classLoader, InputStream inputStream)
+ throws IOException, StreamCorruptedException {
+ super(inputStream);
+ this.classLoader = classLoader;
+ }
+
+ /**
+ * Resolve a class specified by the descriptor using the
+ * specified ClassLoader or the super ClassLoader.
+ *
+ * @param objectStreamClass descriptor of the class
+ * @return the Class object described by the ObjectStreamClass
+ * @throws IOException in case of an I/O error
+ * @throws ClassNotFoundException if the Class cannot be found
+ */
+ protected Class resolveClass(ObjectStreamClass objectStreamClass)
+ throws IOException, ClassNotFoundException {
+
+ Class clazz = Class.forName(objectStreamClass.getName(), false, classLoader);
+
+ if (clazz != null) {
+ // the classloader knows of the class
+ return clazz;
+ } else {
+ // classloader knows not of class, let the super classloader do it
+ return super.resolveClass(objectStreamClass);
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/CloseShieldInputStream.java b/emailcommon/src/org/apache/commons/io/input/CloseShieldInputStream.java new file mode 100644 index 000000000..2058beeb2 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/CloseShieldInputStream.java @@ -0,0 +1,52 @@ +/*
+ * 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.input;
+
+import java.io.InputStream;
+
+/**
+ * Proxy stream that prevents the underlying input stream from being closed.
+ * <p>
+ * This class is typically used in cases where an input stream needs to be
+ * passed to a component that wants to explicitly close the stream even if
+ * more input would still be available to other components.
+ *
+ * @version $Id: CloseShieldInputStream.java 587913 2007-10-24 15:47:30Z niallp $
+ * @since Commons IO 1.4
+ */
+public class CloseShieldInputStream extends ProxyInputStream {
+
+ /**
+ * Creates a proxy that shields the given input stream from being
+ * closed.
+ *
+ * @param in underlying input stream
+ */
+ public CloseShieldInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * Replaces the underlying input stream with a {@link ClosedInputStream}
+ * sentinel. The original input stream will remain open, but this proxy
+ * will appear closed.
+ */
+ public void close() {
+ in = new ClosedInputStream();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/ClosedInputStream.java b/emailcommon/src/org/apache/commons/io/input/ClosedInputStream.java new file mode 100644 index 000000000..86c83c903 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/ClosedInputStream.java @@ -0,0 +1,48 @@ +/*
+ * 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.input;
+
+import java.io.InputStream;
+
+/**
+ * Closed input stream. This stream returns -1 to all attempts to read
+ * something from the stream.
+ * <p>
+ * Typically uses of this class include testing for corner cases in methods
+ * that accept input streams and acting as a sentinel value instead of a
+ * <code>null</code> input stream.
+ *
+ * @version $Id: ClosedInputStream.java 601751 2007-12-06 14:55:45Z niallp $
+ * @since Commons IO 1.4
+ */
+public class ClosedInputStream extends InputStream {
+
+ /**
+ * A singleton.
+ */
+ public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream();
+
+ /**
+ * Returns -1 to indicate that the stream is closed.
+ *
+ * @return always -1
+ */
+ public int read() {
+ return -1;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/CountingInputStream.java b/emailcommon/src/org/apache/commons/io/input/CountingInputStream.java new file mode 100644 index 000000000..2782276c8 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/CountingInputStream.java @@ -0,0 +1,175 @@ +/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A decorating input stream that counts the number of bytes that have passed
+ * through the stream so far.
+ * <p>
+ * A typical use case would be during debugging, to ensure that data is being
+ * read as expected.
+ *
+ * @author Marcelo Liberato
+ * @version $Id: CountingInputStream.java 471628 2006-11-06 04:06:45Z bayard $
+ */
+public class CountingInputStream extends ProxyInputStream {
+
+ /** The count of bytes that have passed. */
+ private long count;
+
+ /**
+ * Constructs a new CountingInputStream.
+ *
+ * @param in the InputStream to delegate to
+ */
+ public CountingInputStream(InputStream in) {
+ super(in);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Reads a number of bytes into the byte array, keeping count of the
+ * number read.
+ *
+ * @param b the buffer into which the data is read, not null
+ * @return the total number of bytes read into the buffer, -1 if end of stream
+ * @throws IOException if an I/O error occurs
+ * @see java.io.InputStream#read(byte[])
+ */
+ public int read(byte[] b) throws IOException {
+ int found = super.read(b);
+ this.count += (found >= 0) ? found : 0;
+ return found;
+ }
+
+ /**
+ * Reads a number of bytes into the byte array at a specific offset,
+ * keeping count of the number read.
+ *
+ * @param b the buffer into which the data is read, not null
+ * @param off the start offset in the buffer
+ * @param len the maximum number of bytes to read
+ * @return the total number of bytes read into the buffer, -1 if end of stream
+ * @throws IOException if an I/O error occurs
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ int found = super.read(b, off, len);
+ this.count += (found >= 0) ? found : 0;
+ return found;
+ }
+
+ /**
+ * Reads the next byte of data adding to the count of bytes received
+ * if a byte is successfully read.
+ *
+ * @return the byte read, -1 if end of stream
+ * @throws IOException if an I/O error occurs
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOException {
+ int found = super.read();
+ this.count += (found >= 0) ? 1 : 0;
+ return found;
+ }
+
+ /**
+ * Skips the stream over the specified number of bytes, adding the skipped
+ * amount to the count.
+ *
+ * @param length the number of bytes to skip
+ * @return the actual number of bytes skipped
+ * @throws IOException if an I/O error occurs
+ * @see java.io.InputStream#skip(long)
+ */
+ public long skip(final long length) throws IOException {
+ final long skip = super.skip(length);
+ this.count += skip;
+ return skip;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * The number of bytes that have passed through this stream.
+ * <p>
+ * NOTE: From v1.3 this method throws an ArithmeticException if the
+ * count is greater than can be expressed by an <code>int</code>.
+ * See {@link #getByteCount()} for a method using a <code>long</code>.
+ *
+ * @return the number of bytes accumulated
+ * @throws ArithmeticException if the byte count is too large
+ */
+ public synchronized int getCount() {
+ long result = getByteCount();
+ if (result > Integer.MAX_VALUE) {
+ throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
+ }
+ return (int) result;
+ }
+
+ /**
+ * Set the byte count back to 0.
+ * <p>
+ * NOTE: From v1.3 this method throws an ArithmeticException if the
+ * count is greater than can be expressed by an <code>int</code>.
+ * See {@link #resetByteCount()} for a method using a <code>long</code>.
+ *
+ * @return the count previous to resetting
+ * @throws ArithmeticException if the byte count is too large
+ */
+ public synchronized int resetCount() {
+ long result = resetByteCount();
+ if (result > Integer.MAX_VALUE) {
+ throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
+ }
+ return (int) result;
+ }
+
+ /**
+ * The number of bytes that have passed through this stream.
+ * <p>
+ * NOTE: This method is an alternative for <code>getCount()</code>
+ * and was added because that method returns an integer which will
+ * result in incorrect count for files over 2GB.
+ *
+ * @return the number of bytes accumulated
+ * @since Commons IO 1.3
+ */
+ public synchronized long getByteCount() {
+ return this.count;
+ }
+
+ /**
+ * Set the byte count back to 0.
+ * <p>
+ * NOTE: This method is an alternative for <code>resetCount()</code>
+ * and was added because that method returns an integer which will
+ * result in incorrect count for files over 2GB.
+ *
+ * @return the count previous to resetting
+ * @since Commons IO 1.3
+ */
+ public synchronized long resetByteCount() {
+ long tmp = this.count;
+ this.count = 0;
+ return tmp;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/DemuxInputStream.java b/emailcommon/src/org/apache/commons/io/input/DemuxInputStream.java new file mode 100644 index 000000000..64b41c4d4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/DemuxInputStream.java @@ -0,0 +1,93 @@ +/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Data written to this stream is forwarded to a stream that has been associated
+ * with this thread.
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $
+ */
+public class DemuxInputStream
+ extends InputStream
+{
+ private InheritableThreadLocal<InputStream> m_streams = new InheritableThreadLocal<InputStream>();
+
+ /**
+ * Bind the specified stream to the current thread.
+ *
+ * @param input the stream to bind
+ * @return the InputStream that was previously active
+ */
+ public InputStream bindStream( InputStream input )
+ {
+ InputStream oldValue = getStream();
+ m_streams.set( input );
+ return oldValue;
+ }
+
+ /**
+ * Closes stream associated with current thread.
+ *
+ * @throws IOException if an error occurs
+ */
+ @Override
+ public void close()
+ throws IOException
+ {
+ InputStream input = getStream();
+ if( null != input )
+ {
+ input.close();
+ }
+ }
+
+ /**
+ * Read byte from stream associated with current thread.
+ *
+ * @return the byte read from stream
+ * @throws IOException if an error occurs
+ */
+ @Override
+ public int read()
+ throws IOException
+ {
+ InputStream input = getStream();
+ if( null != input )
+ {
+ return input.read();
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * Utility method to retrieve stream bound to current thread (if any).
+ *
+ * @return the input stream
+ */
+ private InputStream getStream()
+ {
+ return m_streams.get();
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/NullInputStream.java b/emailcommon/src/org/apache/commons/io/input/NullInputStream.java new file mode 100644 index 000000000..7cee2c6d0 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/NullInputStream.java @@ -0,0 +1,329 @@ +/*
+ * 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.input;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A functional, light weight {@link InputStream} that emulates
+ * a stream of a specified size.
+ * <p>
+ * This implementation provides a light weight
+ * object for testing with an {@link InputStream}
+ * where the contents don't matter.
+ * <p>
+ * One use case would be for testing the handling of
+ * large {@link InputStream} as it can emulate that
+ * scenario without the overhead of actually processing
+ * large numbers of bytes - significantly speeding up
+ * test execution times.
+ * <p>
+ * This implementation returns zero from the method that
+ * reads a byte and leaves the array unchanged in the read
+ * methods that are passed a byte array.
+ * If alternative data is required the <code>processByte()</code> and
+ * <code>processBytes()</code> methods can be implemented to generate
+ * data, for example:
+ *
+ * <pre>
+ * public class TestInputStream extends NullInputStream {
+ * public TestInputStream(int size) {
+ * super(size);
+ * }
+ * protected int processByte() {
+ * return ... // return required value here
+ * }
+ * protected void processBytes(byte[] bytes, int offset, int length) {
+ * for (int i = offset; i < length; i++) {
+ * bytes[i] = ... // set array value here
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 463529 $
+ */
+public class NullInputStream extends InputStream {
+
+ private long size;
+ private long position;
+ private long mark = -1;
+ private long readlimit;
+ private boolean eof;
+ private boolean throwEofException;
+ private boolean markSupported;
+
+ /**
+ * Create an {@link InputStream} that emulates a specified size
+ * which supports marking and does not throw EOFException.
+ *
+ * @param size The size of the input stream to emulate.
+ */
+ public NullInputStream(long size) {
+ this(size, true, false);
+ }
+
+ /**
+ * Create an {@link InputStream} that emulates a specified
+ * size with option settings.
+ *
+ * @param size The size of the input stream to emulate.
+ * @param markSupported Whether this instance will support
+ * the <code>mark()</code> functionality.
+ * @param throwEofException Whether this implementation
+ * will throw an {@link EOFException} or return -1 when the
+ * end of file is reached.
+ */
+ public NullInputStream(long size, boolean markSupported, boolean throwEofException) {
+ this.size = size;
+ this.markSupported = markSupported;
+ this.throwEofException = throwEofException;
+ }
+
+ /**
+ * Return the current position.
+ *
+ * @return the current position.
+ */
+ public long getPosition() {
+ return position;
+ }
+
+ /**
+ * Return the size this {@link InputStream} emulates.
+ *
+ * @return The size of the input stream to emulate.
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Return the number of bytes that can be read.
+ *
+ * @return The number of bytes that can be read.
+ */
+ public int available() {
+ long avail = size - position;
+ if (avail <= 0) {
+ return 0;
+ } else if (avail > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ } else {
+ return (int)avail;
+ }
+ }
+
+ /**
+ * Close this input stream - resets the internal state to
+ * the initial values.
+ *
+ * @throws IOException If an error occurs.
+ */
+ public void close() throws IOException {
+ eof = false;
+ position = 0;
+ mark = -1;
+ }
+
+ /**
+ * Mark the current position.
+ *
+ * @param readlimit The number of bytes before this marked position
+ * is invalid.
+ * @throws UnsupportedOperationException if mark is not supported.
+ */
+ public synchronized void mark(int readlimit) {
+ if (!markSupported) {
+ throw new UnsupportedOperationException("Mark not supported");
+ }
+ mark = position;
+ this.readlimit = readlimit;
+ }
+
+ /**
+ * Indicates whether <i>mark</i> is supported.
+ *
+ * @return Whether <i>mark</i> is supported or not.
+ */
+ public boolean markSupported() {
+ return markSupported;
+ }
+
+ /**
+ * Read a byte.
+ *
+ * @return Either The byte value returned by <code>processByte()</code>
+ * or <code>-1</code> if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read() throws IOException {
+ if (eof) {
+ throw new IOException("Read after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position++;
+ return processByte();
+ }
+
+ /**
+ * Read some bytes into the specified array.
+ *
+ * @param bytes The byte array to read into
+ * @return The number of bytes read or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read(byte[] bytes) throws IOException {
+ return read(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Read the specified number bytes into an array.
+ *
+ * @param bytes The byte array to read into.
+ * @param offset The offset to start reading bytes into.
+ * @param length The number of bytes to read.
+ * @return The number of bytes read or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read(byte[] bytes, int offset, int length) throws IOException {
+ if (eof) {
+ throw new IOException("Read after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position += length;
+ int returnLength = length;
+ if (position > size) {
+ returnLength = length - (int)(position - size);
+ position = size;
+ }
+ processBytes(bytes, offset, returnLength);
+ return returnLength;
+ }
+
+ /**
+ * Reset the stream to the point when mark was last called.
+ *
+ * @throws UnsupportedOperationException if mark is not supported.
+ * @throws IOException If no position has been marked
+ * or the read limit has been exceed since the last position was
+ * marked.
+ */
+ public synchronized void reset() throws IOException {
+ if (!markSupported) {
+ throw new UnsupportedOperationException("Mark not supported");
+ }
+ if (mark < 0) {
+ throw new IOException("No position has been marked");
+ }
+ if (position > (mark + readlimit)) {
+ throw new IOException("Marked position [" + mark +
+ "] is no longer valid - passed the read limit [" +
+ readlimit + "]");
+ }
+ position = mark;
+ eof = false;
+ }
+
+ /**
+ * Skip a specified number of bytes.
+ *
+ * @param numberOfBytes The number of bytes to skip.
+ * @return The number of bytes skipped or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public long skip(long numberOfBytes) throws IOException {
+ if (eof) {
+ throw new IOException("Skip after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position += numberOfBytes;
+ long returnLength = numberOfBytes;
+ if (position > size) {
+ returnLength = numberOfBytes - (position - size);
+ position = size;
+ }
+ return returnLength;
+ }
+
+ /**
+ * Return a byte value for the <code>read()</code> method.
+ * <p>
+ * This implementation returns zero.
+ *
+ * @return This implementation always returns zero.
+ */
+ protected int processByte() {
+ // do nothing - overridable by subclass
+ return 0;
+ }
+
+ /**
+ * Process the bytes for the <code>read(byte[], offset, length)</code>
+ * method.
+ * <p>
+ * This implementation leaves the byte array unchanged.
+ *
+ * @param bytes The byte array
+ * @param offset The offset to start at.
+ * @param length The number of bytes.
+ */
+ protected void processBytes(byte[] bytes, int offset, int length) {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Handle End of File.
+ *
+ * @return <code>-1</code> if <code>throwEofException</code> is
+ * set to <code>false</code>
+ * @throws EOFException if <code>throwEofException</code> is set
+ * to <code>true</code>.
+ */
+ private int doEndOfFile() throws EOFException {
+ eof = true;
+ if (throwEofException) {
+ throw new EOFException();
+ }
+ return -1;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/NullReader.java b/emailcommon/src/org/apache/commons/io/input/NullReader.java new file mode 100644 index 000000000..159e39021 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/NullReader.java @@ -0,0 +1,313 @@ +/*
+ * 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.input;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A functional, light weight {@link Reader} that emulates
+ * a reader of a specified size.
+ * <p>
+ * This implementation provides a light weight
+ * object for testing with an {@link Reader}
+ * where the contents don't matter.
+ * <p>
+ * One use case would be for testing the handling of
+ * large {@link Reader} as it can emulate that
+ * scenario without the overhead of actually processing
+ * large numbers of characters - significantly speeding up
+ * test execution times.
+ * <p>
+ * This implementation returns a space from the method that
+ * reads a character and leaves the array unchanged in the read
+ * methods that are passed a character array.
+ * If alternative data is required the <code>processChar()</code> and
+ * <code>processChars()</code> methods can be implemented to generate
+ * data, for example:
+ *
+ * <pre>
+ * public class TestReader extends NullReader {
+ * public TestReader(int size) {
+ * super(size);
+ * }
+ * protected char processChar() {
+ * return ... // return required value here
+ * }
+ * protected void processChars(char[] chars, int offset, int length) {
+ * for (int i = offset; i < length; i++) {
+ * chars[i] = ... // set array value here
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * @since Commons IO 1.3
+ * @version $Revision: 463529 $
+ */
+public class NullReader extends Reader {
+
+ private long size;
+ private long position;
+ private long mark = -1;
+ private long readlimit;
+ private boolean eof;
+ private boolean throwEofException;
+ private boolean markSupported;
+
+ /**
+ * Create a {@link Reader} that emulates a specified size
+ * which supports marking and does not throw EOFException.
+ *
+ * @param size The size of the reader to emulate.
+ */
+ public NullReader(long size) {
+ this(size, true, false);
+ }
+
+ /**
+ * Create a {@link Reader} that emulates a specified
+ * size with option settings.
+ *
+ * @param size The size of the reader to emulate.
+ * @param markSupported Whether this instance will support
+ * the <code>mark()</code> functionality.
+ * @param throwEofException Whether this implementation
+ * will throw an {@link EOFException} or return -1 when the
+ * end of file is reached.
+ */
+ public NullReader(long size, boolean markSupported, boolean throwEofException) {
+ this.size = size;
+ this.markSupported = markSupported;
+ this.throwEofException = throwEofException;
+ }
+
+ /**
+ * Return the current position.
+ *
+ * @return the current position.
+ */
+ public long getPosition() {
+ return position;
+ }
+
+ /**
+ * Return the size this {@link Reader} emulates.
+ *
+ * @return The size of the reader to emulate.
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Close this Reader - resets the internal state to
+ * the initial values.
+ *
+ * @throws IOException If an error occurs.
+ */
+ public void close() throws IOException {
+ eof = false;
+ position = 0;
+ mark = -1;
+ }
+
+ /**
+ * Mark the current position.
+ *
+ * @param readlimit The number of characters before this marked position
+ * is invalid.
+ * @throws UnsupportedOperationException if mark is not supported.
+ */
+ public synchronized void mark(int readlimit) {
+ if (!markSupported) {
+ throw new UnsupportedOperationException("Mark not supported");
+ }
+ mark = position;
+ this.readlimit = readlimit;
+ }
+
+ /**
+ * Indicates whether <i>mark</i> is supported.
+ *
+ * @return Whether <i>mark</i> is supported or not.
+ */
+ public boolean markSupported() {
+ return markSupported;
+ }
+
+ /**
+ * Read a character.
+ *
+ * @return Either The character value returned by <code>processChar()</code>
+ * or <code>-1</code> if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read() throws IOException {
+ if (eof) {
+ throw new IOException("Read after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position++;
+ return processChar();
+ }
+
+ /**
+ * Read some characters into the specified array.
+ *
+ * @param chars The character array to read into
+ * @return The number of characters read or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read(char[] chars) throws IOException {
+ return read(chars, 0, chars.length);
+ }
+
+ /**
+ * Read the specified number characters into an array.
+ *
+ * @param chars The character array to read into.
+ * @param offset The offset to start reading characters into.
+ * @param length The number of characters to read.
+ * @return The number of characters read or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public int read(char[] chars, int offset, int length) throws IOException {
+ if (eof) {
+ throw new IOException("Read after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position += length;
+ int returnLength = length;
+ if (position > size) {
+ returnLength = length - (int)(position - size);
+ position = size;
+ }
+ processChars(chars, offset, returnLength);
+ return returnLength;
+ }
+
+ /**
+ * Reset the stream to the point when mark was last called.
+ *
+ * @throws UnsupportedOperationException if mark is not supported.
+ * @throws IOException If no position has been marked
+ * or the read limit has been exceed since the last position was
+ * marked.
+ */
+ public synchronized void reset() throws IOException {
+ if (!markSupported) {
+ throw new UnsupportedOperationException("Mark not supported");
+ }
+ if (mark < 0) {
+ throw new IOException("No position has been marked");
+ }
+ if (position > (mark + readlimit)) {
+ throw new IOException("Marked position [" + mark +
+ "] is no longer valid - passed the read limit [" +
+ readlimit + "]");
+ }
+ position = mark;
+ eof = false;
+ }
+
+ /**
+ * Skip a specified number of characters.
+ *
+ * @param numberOfChars The number of characters to skip.
+ * @return The number of characters skipped or <code>-1</code>
+ * if the end of file has been reached and
+ * <code>throwEofException</code> is set to <code>false</code>.
+ * @throws EOFException if the end of file is reached and
+ * <code>throwEofException</code> is set to <code>true</code>.
+ * @throws IOException if trying to read past the end of file.
+ */
+ public long skip(long numberOfChars) throws IOException {
+ if (eof) {
+ throw new IOException("Skip after end of file");
+ }
+ if (position == size) {
+ return doEndOfFile();
+ }
+ position += numberOfChars;
+ long returnLength = numberOfChars;
+ if (position > size) {
+ returnLength = numberOfChars - (position - size);
+ position = size;
+ }
+ return returnLength;
+ }
+
+ /**
+ * Return a character value for the <code>read()</code> method.
+ * <p>
+ * This implementation returns zero.
+ *
+ * @return This implementation always returns zero.
+ */
+ protected int processChar() {
+ // do nothing - overridable by subclass
+ return 0;
+ }
+
+ /**
+ * Process the characters for the <code>read(char[], offset, length)</code>
+ * method.
+ * <p>
+ * This implementation leaves the character array unchanged.
+ *
+ * @param chars The character array
+ * @param offset The offset to start at.
+ * @param length The number of characters.
+ */
+ protected void processChars(char[] chars, int offset, int length) {
+ // do nothing - overridable by subclass
+ }
+
+ /**
+ * Handle End of File.
+ *
+ * @return <code>-1</code> if <code>throwEofException</code> is
+ * set to <code>false</code>
+ * @throws EOFException if <code>throwEofException</code> is set
+ * to <code>true</code>.
+ */
+ private int doEndOfFile() throws EOFException {
+ eof = true;
+ if (throwEofException) {
+ throw new EOFException();
+ }
+ return -1;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/ProxyInputStream.java b/emailcommon/src/org/apache/commons/io/input/ProxyInputStream.java new file mode 100644 index 000000000..a08ad92d0 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/ProxyInputStream.java @@ -0,0 +1,129 @@ +/*
+ * 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.input;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A Proxy stream which acts as expected, that is it passes the method
+ * calls on to the proxied stream and doesn't change which methods are
+ * being called.
+ * <p>
+ * It is an alternative base class to FilterInputStream
+ * to increase reusability, because FilterInputStream changes the
+ * methods being called, such as read(byte[]) to read(byte[], int, int).
+ *
+ * @author Stephen Colebourne
+ * @version $Id: ProxyInputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public abstract class ProxyInputStream extends FilterInputStream {
+
+ /**
+ * Constructs a new ProxyInputStream.
+ *
+ * @param proxy the InputStream to delegate to
+ */
+ public ProxyInputStream(InputStream proxy) {
+ super(proxy);
+ // the proxy is stored in a protected superclass variable named 'in'
+ }
+
+ /**
+ * Invokes the delegate's <code>read()</code> method.
+ * @return the byte read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ /**
+ * Invokes the delegate's <code>read(byte[])</code> method.
+ * @param bts the buffer to read the bytes into
+ * @return the number of bytes read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read(byte[] bts) throws IOException {
+ return in.read(bts);
+ }
+
+ /**
+ * Invokes the delegate's <code>read(byte[], int, int)</code> method.
+ * @param bts the buffer to read the bytes into
+ * @param st The start offset
+ * @param end The number of bytes to read
+ * @return the number of bytes read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read(byte[] bts, int st, int end) throws IOException {
+ return in.read(bts, st, end);
+ }
+
+ /**
+ * Invokes the delegate's <code>skip(long)</code> method.
+ * @param ln the number of bytes to skip
+ * @return the number of bytes to skipped or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public long skip(long ln) throws IOException {
+ return in.skip(ln);
+ }
+
+ /**
+ * Invokes the delegate's <code>available()</code> method.
+ * @return the number of available bytes
+ * @throws IOException if an I/O error occurs
+ */
+ public int available() throws IOException {
+ return in.available();
+ }
+
+ /**
+ * Invokes the delegate's <code>close()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /**
+ * Invokes the delegate's <code>mark(int)</code> method.
+ * @param idx read ahead limit
+ */
+ public synchronized void mark(int idx) {
+ in.mark(idx);
+ }
+
+ /**
+ * Invokes the delegate's <code>reset()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void reset() throws IOException {
+ in.reset();
+ }
+
+ /**
+ * Invokes the delegate's <code>markSupported()</code> method.
+ * @return true if mark is supported, otherwise false
+ */
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/ProxyReader.java b/emailcommon/src/org/apache/commons/io/input/ProxyReader.java new file mode 100644 index 000000000..d55290f5a --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/ProxyReader.java @@ -0,0 +1,130 @@ +/*
+ * 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.input;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A Proxy stream which acts as expected, that is it passes the method
+ * calls on to the proxied stream and doesn't change which methods are
+ * being called.
+ * <p>
+ * It is an alternative base class to FilterReader
+ * to increase reusability, because FilterReader changes the
+ * methods being called, such as read(char[]) to read(char[], int, int).
+ *
+ * @author Stephen Colebourne
+ * @version $Id: ProxyReader.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public abstract class ProxyReader extends FilterReader {
+
+ /**
+ * Constructs a new ProxyReader.
+ *
+ * @param proxy the Reader to delegate to
+ */
+ public ProxyReader(Reader proxy) {
+ super(proxy);
+ // the proxy is stored in a protected superclass variable named 'in'
+ }
+
+ /**
+ * Invokes the delegate's <code>read()</code> method.
+ * @return the character read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ /**
+ * Invokes the delegate's <code>read(char[])</code> method.
+ * @param chr the buffer to read the characters into
+ * @return the number of characters read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read(char[] chr) throws IOException {
+ return in.read(chr);
+ }
+
+ /**
+ * Invokes the delegate's <code>read(char[], int, int)</code> method.
+ * @param chr the buffer to read the characters into
+ * @param st The start offset
+ * @param end The number of bytes to read
+ * @return the number of characters read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public int read(char[] chr, int st, int end) throws IOException {
+ return in.read(chr, st, end);
+ }
+
+ /**
+ * Invokes the delegate's <code>skip(long)</code> method.
+ * @param ln the number of bytes to skip
+ * @return the number of bytes to skipped or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ */
+ public long skip(long ln) throws IOException {
+ return in.skip(ln);
+ }
+
+ /**
+ * Invokes the delegate's <code>ready()</code> method.
+ * @return true if the stream is ready to be read
+ * @throws IOException if an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return in.ready();
+ }
+
+ /**
+ * Invokes the delegate's <code>close()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /**
+ * Invokes the delegate's <code>mark(int)</code> method.
+ * @param idx read ahead limit
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void mark(int idx) throws IOException {
+ in.mark(idx);
+ }
+
+ /**
+ * Invokes the delegate's <code>reset()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void reset() throws IOException {
+ in.reset();
+ }
+
+ /**
+ * Invokes the delegate's <code>markSupported()</code> method.
+ * @return true if mark is supported, otherwise false
+ */
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/SwappedDataInputStream.java b/emailcommon/src/org/apache/commons/io/input/SwappedDataInputStream.java new file mode 100644 index 000000000..5b65b1eee --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/SwappedDataInputStream.java @@ -0,0 +1,251 @@ +/*
+ * 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.input;
+
+import java.io.DataInput;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.EndianUtils;
+
+/**
+ * DataInput for systems relying on little endian data formats.
+ * When read, values will be changed from little endian to big
+ * endian formats for internal usage.
+ * <p>
+ * <b>Origin of code: </b>Avalon Excalibur (IO)
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version CVS $Revision: 610010 $ $Date: 2008-01-08 14:50:59 +0000 (Tue, 08 Jan 2008) $
+ */
+public class SwappedDataInputStream extends ProxyInputStream
+ implements DataInput
+{
+
+ /**
+ * Constructs a SwappedDataInputStream.
+ *
+ * @param input InputStream to read from
+ */
+ public SwappedDataInputStream( InputStream input )
+ {
+ super( input );
+ }
+
+ /**
+ * Return <code>{@link #readByte()} == 0</code>
+ * @return the true if the byte read is zero, otherwise false
+ * @throws IOException if an I/O error occurs
+ * @throws EOFException if an end of file is reached unexpectedly
+ */
+ public boolean readBoolean()
+ throws IOException, EOFException
+ {
+ return ( 0 == readByte() );
+ }
+
+ /**
+ * Invokes the delegate's <code>read()</code> method.
+ * @return the byte read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ * @throws EOFException if an end of file is reached unexpectedly
+ */
+ public byte readByte()
+ throws IOException, EOFException
+ {
+ return (byte)in.read();
+ }
+
+ /**
+ * Reads a character delegating to {@link #readShort()}.
+ * @return the byte read or -1 if the end of stream
+ * @throws IOException if an I/O error occurs
+ * @throws EOFException if an end of file is reached unexpectedly
+ */
+ public char readChar()
+ throws IOException, EOFException
+ {
+ return (char)readShort();
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedDouble(InputStream)}.
+ * @return the read long
+ * @throws IOException if an I/O error occurs
+ * @throws EOFException if an end of file is reached unexpectedly
+ */
+ public double readDouble()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedDouble( in );
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedFloat(InputStream)}.
+ * @return the read long
+ * @throws IOException if an I/O error occurs
+ * @throws EOFException if an end of file is reached unexpectedly
+ */
+ public float readFloat()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedFloat( in );
+ }
+
+ /**
+ * Invokes the delegate's <code>read(byte[] data, int, int)</code> method.
+ *
+ * @param data the buffer to read the bytes into
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public void readFully( byte[] data )
+ throws IOException, EOFException
+ {
+ readFully( data, 0, data.length );
+ }
+
+
+ /**
+ * Invokes the delegate's <code>read(byte[] data, int, int)</code> method.
+ *
+ * @param data the buffer to read the bytes into
+ * @param offset The start offset
+ * @param length The number of bytes to read
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public void readFully( byte[] data, int offset, int length )
+ throws IOException, EOFException
+ {
+ int remaining = length;
+
+ while( remaining > 0 )
+ {
+ int location = offset + ( length - remaining );
+ int count = read( data, location, remaining );
+
+ if( -1 == count )
+ {
+ throw new EOFException();
+ }
+
+ remaining -= count;
+ }
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedInteger(InputStream)}.
+ * @return the read long
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public int readInt()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedInteger( in );
+ }
+
+ /**
+ * Not currently supported - throws {@link UnsupportedOperationException}.
+ * @return the line read
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public String readLine()
+ throws IOException, EOFException
+ {
+ throw new UnsupportedOperationException(
+ "Operation not supported: readLine()" );
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedLong(InputStream)}.
+ * @return the read long
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public long readLong()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedLong( in );
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedShort(InputStream)}.
+ * @return the read long
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public short readShort()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedShort( in );
+ }
+
+ /**
+ * Invokes the delegate's <code>read()</code> method.
+ * @return the byte read or -1 if the end of stream
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public int readUnsignedByte()
+ throws IOException, EOFException
+ {
+ return in.read();
+ }
+
+ /**
+ * Delegates to {@link EndianUtils#readSwappedUnsignedShort(InputStream)}.
+ * @return the read long
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public int readUnsignedShort()
+ throws IOException, EOFException
+ {
+ return EndianUtils.readSwappedUnsignedShort( in );
+ }
+
+ /**
+ * Not currently supported - throws {@link UnsupportedOperationException}.
+ * @return UTF String read
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public String readUTF()
+ throws IOException, EOFException
+ {
+ throw new UnsupportedOperationException(
+ "Operation not supported: readUTF()" );
+ }
+
+ /**
+ * Invokes the delegate's <code>skip(int)</code> method.
+ * @param count the number of bytes to skip
+ * @return the number of bytes to skipped or -1 if the end of stream
+ * @throws EOFException if an end of file is reached unexpectedly
+ * @throws IOException if an I/O error occurs
+ */
+ public int skipBytes( int count )
+ throws IOException, EOFException
+ {
+ return (int)in.skip( count );
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/TeeInputStream.java b/emailcommon/src/org/apache/commons/io/input/TeeInputStream.java new file mode 100644 index 000000000..fed000ed6 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/TeeInputStream.java @@ -0,0 +1,147 @@ +/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * InputStream proxy that transparently writes a copy of all bytes read
+ * from the proxied stream to a given OutputStream. Using {@link #skip(long)}
+ * or {@link #mark(int)}/{@link #reset()} on the stream will result on some
+ * bytes from the input stream being skipped or duplicated in the output
+ * stream.
+ * <p>
+ * The proxied input stream is closed when the {@link #close()} method is
+ * called on this proxy. It is configurable whether the associated output
+ * stream will also closed.
+ *
+ * @version $Id: TeeInputStream.java 587913 2007-10-24 15:47:30Z niallp $
+ * @since Commons IO 1.4
+ */
+public class TeeInputStream extends ProxyInputStream {
+
+ /**
+ * The output stream that will receive a copy of all bytes read from the
+ * proxied input stream.
+ */
+ private final OutputStream branch;
+
+ /**
+ * Flag for closing also the associated output stream when this
+ * stream is closed.
+ */
+ private final boolean closeBranch;
+
+ /**
+ * Creates a TeeInputStream that proxies the given {@link InputStream}
+ * and copies all read bytes to the given {@link OutputStream}. The given
+ * output stream will not be closed when this stream gets closed.
+ *
+ * @param input input stream to be proxied
+ * @param branch output stream that will receive a copy of all bytes read
+ */
+ public TeeInputStream(InputStream input, OutputStream branch) {
+ this(input, branch, false);
+ }
+
+ /**
+ * Creates a TeeInputStream that proxies the given {@link InputStream}
+ * and copies all read bytes to the given {@link OutputStream}. The given
+ * output stream will be closed when this stream gets closed if the
+ * closeBranch parameter is <code>true</code>.
+ *
+ * @param input input stream to be proxied
+ * @param branch output stream that will receive a copy of all bytes read
+ * @param closeBranch flag for closing also the output stream when this
+ * stream is closed
+ */
+ public TeeInputStream(
+ InputStream input, OutputStream branch, boolean closeBranch) {
+ super(input);
+ this.branch = branch;
+ this.closeBranch = closeBranch;
+ }
+
+ /**
+ * Closes the proxied input stream and, if so configured, the associated
+ * output stream. An exception thrown from one stream will not prevent
+ * closing of the other stream.
+ *
+ * @throws IOException if either of the streams could not be closed
+ */
+ public void close() throws IOException {
+ try {
+ super.close();
+ } finally {
+ if (closeBranch) {
+ branch.close();
+ }
+ }
+ }
+
+ /**
+ * Reads a single byte from the proxied input stream and writes it to
+ * the associated output stream.
+ *
+ * @return next byte from the stream, or -1 if the stream has ended
+ * @throws IOException if the stream could not be read (or written)
+ */
+ public int read() throws IOException {
+ int ch = super.read();
+ if (ch != -1) {
+ branch.write(ch);
+ }
+ return ch;
+ }
+
+ /**
+ * Reads bytes from the proxied input stream and writes the read bytes
+ * to the associated output stream.
+ *
+ * @param bts byte buffer
+ * @param st start offset within the buffer
+ * @param end maximum number of bytes to read
+ * @return number of bytes read, or -1 if the stream has ended
+ * @throws IOException if the stream could not be read (or written)
+ */
+ public int read(byte[] bts, int st, int end) throws IOException {
+ int n = super.read(bts, st, end);
+ if (n != -1) {
+ branch.write(bts, st, n);
+ }
+ return n;
+ }
+
+ /**
+ * Reads bytes from the proxied input stream and writes the read bytes
+ * to the associated output stream.
+ *
+ * @param bts byte buffer
+ * @return number of bytes read, or -1 if the stream has ended
+ * @throws IOException if the stream could not be read (or written)
+ */
+ public int read(byte[] bts) throws IOException {
+ int n = super.read(bts);
+ if (n != -1) {
+ branch.write(bts, 0, n);
+ }
+ return n;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/input/package.html b/emailcommon/src/org/apache/commons/io/input/package.html new file mode 100644 index 000000000..9aa8b15ba --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/input/package.html @@ -0,0 +1,25 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body>
+<p>
+This package provides implementations of input classes, such as
+<code>InputStream</code> and <code>Reader</code>.
+</p>
+</body>
+</html>
diff --git a/emailcommon/src/org/apache/commons/io/output/ByteArrayOutputStream.java b/emailcommon/src/org/apache/commons/io/output/ByteArrayOutputStream.java new file mode 100644 index 000000000..906a41dd4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/ByteArrayOutputStream.java @@ -0,0 +1,312 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class implements an output stream in which the data is
+ * written into a byte array. The buffer automatically grows as data
+ * is written to it.
+ * <p>
+ * The data can be retrieved using <code>toByteArray()</code> and
+ * <code>toString()</code>.
+ * <p>
+ * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ * <p>
+ * This is an alternative implementation of the java.io.ByteArrayOutputStream
+ * class. The original implementation only allocates 32 bytes at the beginning.
+ * As this class is designed for heavy duty it starts at 1024 bytes. In contrast
+ * to the original it doesn't reallocate the whole memory block but allocates
+ * additional buffers. This way no buffers need to be garbage collected and
+ * the contents don't have to be copied to the new buffer. This class is
+ * designed to behave exactly like the original. The only exception is the
+ * deprecated toString(int) method that has been ignored.
+ *
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @author Holger Hoffstatte
+ * @version $Id: ByteArrayOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class ByteArrayOutputStream extends OutputStream {
+
+ /** A singleton empty byte array. */
+ private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ /** The list of buffers, which grows and never reduces. */
+ private List<byte[]> buffers = new ArrayList<byte[]>();
+ /** The index of the current buffer. */
+ private int currentBufferIndex;
+ /** The total count of bytes in all the filled buffers. */
+ private int filledBufferSum;
+ /** The current buffer. */
+ private byte[] currentBuffer;
+ /** The total count of bytes written. */
+ private int count;
+
+ /**
+ * Creates a new byte array output stream. The buffer capacity is
+ * initially 1024 bytes, though its size increases if necessary.
+ */
+ public ByteArrayOutputStream() {
+ this(1024);
+ }
+
+ /**
+ * Creates a new byte array output stream, with a buffer capacity of
+ * the specified size, in bytes.
+ *
+ * @param size the initial size
+ * @throws IllegalArgumentException if size is negative
+ */
+ public ByteArrayOutputStream(int size) {
+ if (size < 0) {
+ throw new IllegalArgumentException(
+ "Negative initial size: " + size);
+ }
+ needNewBuffer(size);
+ }
+
+ /**
+ * Return the appropriate <code>byte[]</code> buffer
+ * specified by index.
+ *
+ * @param index the index of the buffer required
+ * @return the buffer
+ */
+ private byte[] getBuffer(int index) {
+ return buffers.get(index);
+ }
+
+ /**
+ * Makes a new buffer available either by allocating
+ * a new one or re-cycling an existing one.
+ *
+ * @param newcount the size of the buffer if one is created
+ */
+ private void needNewBuffer(int newcount) {
+ if (currentBufferIndex < buffers.size() - 1) {
+ //Recycling old buffer
+ filledBufferSum += currentBuffer.length;
+
+ currentBufferIndex++;
+ currentBuffer = getBuffer(currentBufferIndex);
+ } else {
+ //Creating new buffer
+ int newBufferSize;
+ if (currentBuffer == null) {
+ newBufferSize = newcount;
+ filledBufferSum = 0;
+ } else {
+ newBufferSize = Math.max(
+ currentBuffer.length << 1,
+ newcount - filledBufferSum);
+ filledBufferSum += currentBuffer.length;
+ }
+
+ currentBufferIndex++;
+ currentBuffer = new byte[newBufferSize];
+ buffers.add(currentBuffer);
+ }
+ }
+
+ /**
+ * Write the bytes to byte array.
+ * @param b the bytes to write
+ * @param off The start offset
+ * @param len The number of bytes to write
+ */
+ @Override
+ public void write(byte[] b, int off, int len) {
+ if ((off < 0)
+ || (off > b.length)
+ || (len < 0)
+ || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ synchronized (this) {
+ int newcount = count + len;
+ int remaining = len;
+ int inBufferPos = count - filledBufferSum;
+ while (remaining > 0) {
+ int part = Math.min(remaining, currentBuffer.length - inBufferPos);
+ System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part);
+ remaining -= part;
+ if (remaining > 0) {
+ needNewBuffer(newcount);
+ inBufferPos = 0;
+ }
+ }
+ count = newcount;
+ }
+ }
+
+ /**
+ * Write a byte to byte array.
+ * @param b the byte to write
+ */
+ @Override
+ public synchronized void write(int b) {
+ int inBufferPos = count - filledBufferSum;
+ if (inBufferPos == currentBuffer.length) {
+ needNewBuffer(count + 1);
+ inBufferPos = 0;
+ }
+ currentBuffer[inBufferPos] = (byte) b;
+ count++;
+ }
+
+ /**
+ * Writes the entire contents of the specified input stream to this
+ * byte stream. Bytes from the input stream are read directly into the
+ * internal buffers of this streams.
+ *
+ * @param in the input stream to read from
+ * @return total number of bytes read from the input stream
+ * (and written to this stream)
+ * @throws IOException if an I/O error occurs while reading the input stream
+ * @since Commons IO 1.4
+ */
+ public synchronized int write(InputStream in) throws IOException {
+ int readCount = 0;
+ int inBufferPos = count - filledBufferSum;
+ int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
+ while (n != -1) {
+ readCount += n;
+ inBufferPos += n;
+ count += n;
+ if (inBufferPos == currentBuffer.length) {
+ needNewBuffer(currentBuffer.length);
+ inBufferPos = 0;
+ }
+ n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
+ }
+ return readCount;
+ }
+
+ /**
+ * Return the current size of the byte array.
+ * @return the current size of the byte array
+ */
+ public synchronized int size() {
+ return count;
+ }
+
+ /**
+ * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ *
+ * @throws IOException never (this method should not declare this exception
+ * but it has to now due to backwards compatability)
+ */
+ @Override
+ public void close() throws IOException {
+ //nop
+ }
+
+ /**
+ * @see java.io.ByteArrayOutputStream#reset()
+ */
+ public synchronized void reset() {
+ count = 0;
+ filledBufferSum = 0;
+ currentBufferIndex = 0;
+ currentBuffer = getBuffer(currentBufferIndex);
+ }
+
+ /**
+ * Writes the entire contents of this byte stream to the
+ * specified output stream.
+ *
+ * @param out the output stream to write to
+ * @throws IOException if an I/O error occurs, such as if the stream is closed
+ * @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
+ */
+ public synchronized void writeTo(OutputStream out) throws IOException {
+ int remaining = count;
+ for (int i = 0; i < buffers.size(); i++) {
+ byte[] buf = getBuffer(i);
+ int c = Math.min(buf.length, remaining);
+ out.write(buf, 0, c);
+ remaining -= c;
+ if (remaining == 0) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets the curent contents of this byte stream as a byte array.
+ * The result is independent of this stream.
+ *
+ * @return the current contents of this output stream, as a byte array
+ * @see java.io.ByteArrayOutputStream#toByteArray()
+ */
+ public synchronized byte[] toByteArray() {
+ int remaining = count;
+ if (remaining == 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ byte newbuf[] = new byte[remaining];
+ int pos = 0;
+ for (int i = 0; i < buffers.size(); i++) {
+ byte[] buf = getBuffer(i);
+ int c = Math.min(buf.length, remaining);
+ System.arraycopy(buf, 0, newbuf, pos, c);
+ pos += c;
+ remaining -= c;
+ if (remaining == 0) {
+ break;
+ }
+ }
+ return newbuf;
+ }
+
+ /**
+ * Gets the curent contents of this byte stream as a string.
+ * @return the contents of the byte array as a String
+ * @see java.io.ByteArrayOutputStream#toString()
+ */
+ @Override
+ public String toString() {
+ return new String(toByteArray());
+ }
+
+ /**
+ * Gets the curent contents of this byte stream as a string
+ * using the specified encoding.
+ *
+ * @param enc the name of the character encoding
+ * @return the string converted from the byte array
+ * @throws UnsupportedEncodingException if the encoding is not supported
+ * @see java.io.ByteArrayOutputStream#toString(String)
+ */
+ public String toString(String enc) throws UnsupportedEncodingException {
+ return new String(toByteArray(), enc);
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/CloseShieldOutputStream.java b/emailcommon/src/org/apache/commons/io/output/CloseShieldOutputStream.java new file mode 100644 index 000000000..63f44be40 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/CloseShieldOutputStream.java @@ -0,0 +1,52 @@ +/*
+ * 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.output;
+
+import java.io.OutputStream;
+
+/**
+ * Proxy stream that prevents the underlying output stream from being closed.
+ * <p>
+ * This class is typically used in cases where an output stream needs to be
+ * passed to a component that wants to explicitly close the stream even if
+ * other components would still use the stream for output.
+ *
+ * @version $Id: CloseShieldOutputStream.java 587913 2007-10-24 15:47:30Z niallp $
+ * @since Commons IO 1.4
+ */
+public class CloseShieldOutputStream extends ProxyOutputStream {
+
+ /**
+ * Creates a proxy that shields the given output stream from being
+ * closed.
+ *
+ * @param out underlying output stream
+ */
+ public CloseShieldOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /**
+ * Replaces the underlying output stream with a {@link ClosedOutputStream}
+ * sentinel. The original output stream will remain open, but this proxy
+ * will appear closed.
+ */
+ public void close() {
+ out = new ClosedOutputStream();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/ClosedOutputStream.java b/emailcommon/src/org/apache/commons/io/output/ClosedOutputStream.java new file mode 100644 index 000000000..b585c0cf4 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/ClosedOutputStream.java @@ -0,0 +1,50 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Closed output stream. This stream throws an exception on all attempts to
+ * write something to the stream.
+ * <p>
+ * Typically uses of this class include testing for corner cases in methods
+ * that accept an output stream and acting as a sentinel value instead of
+ * a <code>null</code> output stream.
+ *
+ * @version $Id: ClosedOutputStream.java 601751 2007-12-06 14:55:45Z niallp $
+ * @since Commons IO 1.4
+ */
+public class ClosedOutputStream extends OutputStream {
+
+ /**
+ * A singleton.
+ */
+ public static final ClosedOutputStream CLOSED_OUTPUT_STREAM = new ClosedOutputStream();
+
+ /**
+ * Throws an {@link IOException} to indicate that the stream is closed.
+ *
+ * @param b ignored
+ * @throws IOException always thrown
+ */
+ public void write(int b) throws IOException {
+ throw new IOException("write(" + b + ") failed: stream is closed");
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/CountingOutputStream.java b/emailcommon/src/org/apache/commons/io/output/CountingOutputStream.java new file mode 100644 index 000000000..672882860 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/CountingOutputStream.java @@ -0,0 +1,154 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A decorating output stream that counts the number of bytes that have passed
+ * through the stream so far.
+ * <p>
+ * A typical use case would be during debugging, to ensure that data is being
+ * written as expected.
+ *
+ * @version $Id: CountingOutputStream.java 471628 2006-11-06 04:06:45Z bayard $
+ */
+public class CountingOutputStream extends ProxyOutputStream {
+
+ /** The count of bytes that have passed. */
+ private long count;
+
+ /**
+ * Constructs a new CountingOutputStream.
+ *
+ * @param out the OutputStream to write to
+ */
+ public CountingOutputStream( OutputStream out ) {
+ super(out);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the contents of the specified byte array to this output stream
+ * keeping count of the number of bytes written.
+ *
+ * @param b the bytes to write, not null
+ * @throws IOException if an I/O error occurs
+ * @see java.io.OutputStream#write(byte[])
+ */
+ public void write(byte[] b) throws IOException {
+ count += b.length;
+ super.write(b);
+ }
+
+ /**
+ * Writes a portion of the specified byte array to this output stream
+ * keeping count of the number of bytes written.
+ *
+ * @param b the bytes to write, not null
+ * @param off the start offset in the buffer
+ * @param len the maximum number of bytes to write
+ * @throws IOException if an I/O error occurs
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte[] b, int off, int len) throws IOException {
+ count += len;
+ super.write(b, off, len);
+ }
+
+ /**
+ * Writes a single byte to the output stream adding to the count of the
+ * number of bytes written.
+ *
+ * @param b the byte to write
+ * @throws IOException if an I/O error occurs
+ * @see java.io.OutputStream#write(int)
+ */
+ public void write(int b) throws IOException {
+ count++;
+ super.write(b);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * The number of bytes that have passed through this stream.
+ * <p>
+ * NOTE: From v1.3 this method throws an ArithmeticException if the
+ * count is greater than can be expressed by an <code>int</code>.
+ * See {@link #getByteCount()} for a method using a <code>long</code>.
+ *
+ * @return the number of bytes accumulated
+ * @throws ArithmeticException if the byte count is too large
+ */
+ public synchronized int getCount() {
+ long result = getByteCount();
+ if (result > Integer.MAX_VALUE) {
+ throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
+ }
+ return (int) result;
+ }
+
+ /**
+ * Set the byte count back to 0.
+ * <p>
+ * NOTE: From v1.3 this method throws an ArithmeticException if the
+ * count is greater than can be expressed by an <code>int</code>.
+ * See {@link #resetByteCount()} for a method using a <code>long</code>.
+ *
+ * @return the count previous to resetting
+ * @throws ArithmeticException if the byte count is too large
+ */
+ public synchronized int resetCount() {
+ long result = resetByteCount();
+ if (result > Integer.MAX_VALUE) {
+ throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
+ }
+ return (int) result;
+ }
+
+ /**
+ * The number of bytes that have passed through this stream.
+ * <p>
+ * NOTE: This method is an alternative for <code>getCount()</code>.
+ * It was added because that method returns an integer which will
+ * result in incorrect count for files over 2GB.
+ *
+ * @return the number of bytes accumulated
+ * @since Commons IO 1.3
+ */
+ public synchronized long getByteCount() {
+ return this.count;
+ }
+
+ /**
+ * Set the byte count back to 0.
+ * <p>
+ * NOTE: This method is an alternative for <code>resetCount()</code>.
+ * It was added because that method returns an integer which will
+ * result in incorrect count for files over 2GB.
+ *
+ * @return the count previous to resetting
+ * @since Commons IO 1.3
+ */
+ public synchronized long resetByteCount() {
+ long tmp = this.count;
+ this.count = 0;
+ return tmp;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/DeferredFileOutputStream.java b/emailcommon/src/org/apache/commons/io/output/DeferredFileOutputStream.java new file mode 100644 index 000000000..b8a9e9607 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/DeferredFileOutputStream.java @@ -0,0 +1,269 @@ +/*
+ * 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.output;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+
+/**
+ * An output stream which will retain data in memory until a specified
+ * threshold is reached, and only then commit it to disk. If the stream is
+ * closed before the threshold is reached, the data will not be written to
+ * disk at all.
+ * <p>
+ * This class originated in FileUpload processing. In this use case, you do
+ * not know in advance the size of the file being uploaded. If the file is small
+ * you want to store it in memory (for speed), but if the file is large you want
+ * to store it to file (to avoid memory issues).
+ *
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ * @author gaxzerow
+ *
+ * @version $Id: DeferredFileOutputStream.java 606381 2007-12-22 02:03:16Z ggregory $
+ */
+public class DeferredFileOutputStream
+ extends ThresholdingOutputStream
+{
+
+ // ----------------------------------------------------------- Data members
+
+
+ /**
+ * The output stream to which data will be written prior to the theshold
+ * being reached.
+ */
+ private ByteArrayOutputStream memoryOutputStream;
+
+
+ /**
+ * The output stream to which data will be written at any given time. This
+ * will always be one of <code>memoryOutputStream</code> or
+ * <code>diskOutputStream</code>.
+ */
+ private OutputStream currentOutputStream;
+
+
+ /**
+ * The file to which output will be directed if the threshold is exceeded.
+ */
+ private File outputFile;
+
+ /**
+ * The temporary file prefix.
+ */
+ private String prefix;
+
+ /**
+ * The temporary file suffix.
+ */
+ private String suffix;
+
+ /**
+ * The directory to use for temporary files.
+ */
+ private File directory;
+
+
+ /**
+ * True when close() has been called successfully.
+ */
+ private boolean closed = false;
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs an instance of this class which will trigger an event at the
+ * specified threshold, and save data to a file beyond that point.
+ *
+ * @param threshold The number of bytes at which to trigger an event.
+ * @param outputFile The file to which data is saved beyond the threshold.
+ */
+ public DeferredFileOutputStream(int threshold, File outputFile)
+ {
+ super(threshold);
+ this.outputFile = outputFile;
+
+ memoryOutputStream = new ByteArrayOutputStream();
+ currentOutputStream = memoryOutputStream;
+ }
+
+
+ /**
+ * Constructs an instance of this class which will trigger an event at the
+ * specified threshold, and save data to a temporary file beyond that point.
+ *
+ * @param threshold The number of bytes at which to trigger an event.
+ * @param prefix Prefix to use for the temporary file.
+ * @param suffix Suffix to use for the temporary file.
+ * @param directory Temporary file directory.
+ *
+ * @since Commons IO 1.4
+ */
+ public DeferredFileOutputStream(int threshold, String prefix, String suffix, File directory)
+ {
+ this(threshold, (File)null);
+ if (prefix == null) {
+ throw new IllegalArgumentException("Temporary file prefix is missing");
+ }
+ this.prefix = prefix;
+ this.suffix = suffix;
+ this.directory = directory;
+ }
+
+
+ // --------------------------------------- ThresholdingOutputStream methods
+
+
+ /**
+ * Returns the current output stream. This may be memory based or disk
+ * based, depending on the current state with respect to the threshold.
+ *
+ * @return The underlying output stream.
+ *
+ * @exception IOException if an error occurs.
+ */
+ protected OutputStream getStream() throws IOException
+ {
+ return currentOutputStream;
+ }
+
+
+ /**
+ * Switches the underlying output stream from a memory based stream to one
+ * that is backed by disk. This is the point at which we realise that too
+ * much data is being written to keep in memory, so we elect to switch to
+ * disk-based storage.
+ *
+ * @exception IOException if an error occurs.
+ */
+ protected void thresholdReached() throws IOException
+ {
+ if (prefix != null) {
+ outputFile = File.createTempFile(prefix, suffix, directory);
+ }
+ FileOutputStream fos = new FileOutputStream(outputFile);
+ memoryOutputStream.writeTo(fos);
+ currentOutputStream = fos;
+ memoryOutputStream = null;
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Determines whether or not the data for this output stream has been
+ * retained in memory.
+ *
+ * @return <code>true</code> if the data is available in memory;
+ * <code>false</code> otherwise.
+ */
+ public boolean isInMemory()
+ {
+ return (!isThresholdExceeded());
+ }
+
+
+ /**
+ * Returns the data for this output stream as an array of bytes, assuming
+ * that the data has been retained in memory. If the data was written to
+ * disk, this method returns <code>null</code>.
+ *
+ * @return The data for this output stream, or <code>null</code> if no such
+ * data is available.
+ */
+ public byte[] getData()
+ {
+ if (memoryOutputStream != null)
+ {
+ return memoryOutputStream.toByteArray();
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns either the output file specified in the constructor or
+ * the temporary file created or null.
+ * <p>
+ * If the constructor specifying the file is used then it returns that
+ * same output file, even when threashold has not been reached.
+ * <p>
+ * If constructor specifying a temporary file prefix/suffix is used
+ * then the temporary file created once the threashold is reached is returned
+ * If the threshold was not reached then <code>null</code> is returned.
+ *
+ * @return The file for this output stream, or <code>null</code> if no such
+ * file exists.
+ */
+ public File getFile()
+ {
+ return outputFile;
+ }
+
+
+ /**
+ * Closes underlying output stream, and mark this as closed
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void close() throws IOException
+ {
+ super.close();
+ closed = true;
+ }
+
+
+ /**
+ * Writes the data from this output stream to the specified output stream,
+ * after it has been closed.
+ *
+ * @param out output stream to write to.
+ * @exception IOException if this stream is not yet closed or an error occurs.
+ */
+ public void writeTo(OutputStream out) throws IOException
+ {
+ // we may only need to check if this is closed if we are working with a file
+ // but we should force the habit of closing wether we are working with
+ // a file or memory.
+ if (!closed)
+ {
+ throw new IOException("Stream not closed");
+ }
+
+ if(isInMemory())
+ {
+ memoryOutputStream.writeTo(out);
+ }
+ else
+ {
+ FileInputStream fis = new FileInputStream(outputFile);
+ try {
+ IOUtils.copy(fis, out);
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/DemuxOutputStream.java b/emailcommon/src/org/apache/commons/io/output/DemuxOutputStream.java new file mode 100644 index 000000000..280df14d3 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/DemuxOutputStream.java @@ -0,0 +1,105 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Data written to this stream is forwarded to a stream that has been associated
+ * with this thread.
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $
+ */
+public class DemuxOutputStream
+ extends OutputStream
+{
+ private InheritableThreadLocal<OutputStream> m_streams = new InheritableThreadLocal<OutputStream>();
+
+ /**
+ * Bind the specified stream to the current thread.
+ *
+ * @param output the stream to bind
+ * @return the OutputStream that was previously active
+ */
+ public OutputStream bindStream( OutputStream output )
+ {
+ OutputStream stream = getStream();
+ m_streams.set( output );
+ return stream;
+ }
+
+ /**
+ * Closes stream associated with current thread.
+ *
+ * @throws IOException if an error occurs
+ */
+ @Override
+ public void close()
+ throws IOException
+ {
+ OutputStream output = getStream();
+ if( null != output )
+ {
+ output.close();
+ }
+ }
+
+ /**
+ * Flushes stream associated with current thread.
+ *
+ * @throws IOException if an error occurs
+ */
+ @Override
+ public void flush()
+ throws IOException
+ {
+ OutputStream output = getStream();
+ if( null != output )
+ {
+ output.flush();
+ }
+ }
+
+ /**
+ * Writes byte to stream associated with current thread.
+ *
+ * @param ch the byte to write to stream
+ * @throws IOException if an error occurs
+ */
+ @Override
+ public void write( int ch )
+ throws IOException
+ {
+ OutputStream output = getStream();
+ if( null != output )
+ {
+ output.write( ch );
+ }
+ }
+
+ /**
+ * Utility method to retrieve stream bound to current thread (if any).
+ *
+ * @return the output stream
+ */
+ private OutputStream getStream()
+ {
+ return m_streams.get();
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/FileWriterWithEncoding.java b/emailcommon/src/org/apache/commons/io/output/FileWriterWithEncoding.java new file mode 100644 index 000000000..a8f89334b --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/FileWriterWithEncoding.java @@ -0,0 +1,324 @@ +/*
+ * 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.output;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+/**
+ * Writer of files that allows the encoding to be set.
+ * <p>
+ * This class provides a simple alternative to <code>FileWriter</code>
+ * that allows an encoding to be set. Unfortunately, it cannot subclass
+ * <code>FileWriter</code>.
+ * <p>
+ * By default, the file will be overwritten, but this may be changed to append.
+ * <p>
+ * The encoding must be specified using either the name of the {@link Charset},
+ * the {@link Charset}, or a {@link CharsetEncoder}. If the default encoding
+ * is required then use the {@link java.io.FileWriter} directly, rather than
+ * this implementation.
+ * <p>
+ *
+ *
+ * @since Commons IO 1.4
+ * @version $Id: FileWriterWithEncoding.java 611634 2008-01-13 20:35:00Z niallp $
+ */
+public class FileWriterWithEncoding extends Writer {
+ // Cannot extend ProxyWriter, as requires writer to be
+ // known when super() is called
+
+ /** The writer to decorate. */
+ private final Writer out;
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, String encoding) throws IOException {
+ this(new File(filename), encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, String encoding, boolean append) throws IOException {
+ this(new File(filename), encoding, append);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, Charset encoding) throws IOException {
+ this(new File(filename), encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, Charset encoding, boolean append) throws IOException {
+ this(new File(filename), encoding, append);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, CharsetEncoder encoding) throws IOException {
+ this(new File(filename), encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param filename the name of the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file name or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(String filename, CharsetEncoder encoding, boolean append) throws IOException {
+ this(new File(filename), encoding, append);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, String encoding) throws IOException {
+ this(file, encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, String encoding, boolean append) throws IOException {
+ super();
+ this.out = initWriter(file, encoding, append);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, Charset encoding) throws IOException {
+ this(file, encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, Charset encoding, boolean append) throws IOException {
+ super();
+ this.out = initWriter(file, encoding, append);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, CharsetEncoder encoding) throws IOException {
+ this(file, encoding, false);
+ }
+
+ /**
+ * Constructs a FileWriterWithEncoding with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException in case of an I/O error
+ */
+ public FileWriterWithEncoding(File file, CharsetEncoder encoding, boolean append) throws IOException {
+ super();
+ this.out = initWriter(file, encoding, append);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Initialise the wrapped file writer.
+ * Ensure that a cleanup occurs if the writer creation fails.
+ *
+ * @param file the file to be accessed
+ * @param encoding the encoding to use - may be Charset, CharsetEncoder or String
+ * @param append true to append
+ * @return the initialised writer
+ * @throws NullPointerException if the file or encoding is null
+ * @throws IOException if an error occurs
+ */
+ private static Writer initWriter(File file, Object encoding, boolean append) throws IOException {
+ if (file == null) {
+ throw new NullPointerException("File is missing");
+ }
+ if (encoding == null) {
+ throw new NullPointerException("Encoding is missing");
+ }
+ boolean fileExistedAlready = file.exists();
+ OutputStream stream = null;
+ Writer writer = null;
+ try {
+ stream = new FileOutputStream(file, append);
+ if (encoding instanceof Charset) {
+ writer = new OutputStreamWriter(stream, (Charset)encoding);
+ } else if (encoding instanceof CharsetEncoder) {
+ writer = new OutputStreamWriter(stream, (CharsetEncoder)encoding);
+ } else {
+ writer = new OutputStreamWriter(stream, (String)encoding);
+ }
+ } catch (IOException ex) {
+ IOUtils.closeQuietly(writer);
+ IOUtils.closeQuietly(stream);
+ if (fileExistedAlready == false) {
+ FileUtils.deleteQuietly(file);
+ }
+ throw ex;
+ } catch (RuntimeException ex) {
+ IOUtils.closeQuietly(writer);
+ IOUtils.closeQuietly(stream);
+ if (fileExistedAlready == false) {
+ FileUtils.deleteQuietly(file);
+ }
+ throw ex;
+ }
+ return writer;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Write a character.
+ * @param idx the character to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(int idx) throws IOException {
+ out.write(idx);
+ }
+
+ /**
+ * Write the characters from an array.
+ * @param chr the characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr) throws IOException {
+ out.write(chr);
+ }
+
+ /**
+ * Write the specified characters from an array.
+ * @param chr the characters to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr, int st, int end) throws IOException {
+ out.write(chr, st, end);
+ }
+
+ /**
+ * Write the characters from a string.
+ * @param str the string to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str) throws IOException {
+ out.write(str);
+ }
+
+ /**
+ * Write the specified characters from a string.
+ * @param str the string to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str, int st, int end) throws IOException {
+ out.write(str, st, end);
+ }
+
+ /**
+ * Flush the stream.
+ * @throws IOException if an I/O error occurs
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Close the stream.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ out.close();
+ }
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/LockableFileWriter.java b/emailcommon/src/org/apache/commons/io/output/LockableFileWriter.java new file mode 100644 index 000000000..6b10bd282 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/LockableFileWriter.java @@ -0,0 +1,333 @@ +/*
+ * 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.output;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+/**
+ * FileWriter that will create and honor lock files to allow simple
+ * cross thread file lock handling.
+ * <p>
+ * This class provides a simple alternative to <code>FileWriter</code>
+ * that will use a lock file to prevent duplicate writes.
+ * <p>
+ * By default, the file will be overwritten, but this may be changed to append.
+ * The lock directory may be specified, but defaults to the system property
+ * <code>java.io.tmpdir</code>.
+ * The encoding may also be specified, and defaults to the platform default.
+ *
+ * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
+ * @author <a href="mailto:ms@collab.net">Michael Salmon</a>
+ * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author Stephen Colebourne
+ * @author Andy Lehane
+ * @version $Id: LockableFileWriter.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class LockableFileWriter extends Writer {
+ // Cannot extend ProxyWriter, as requires writer to be
+ // known when super() is called
+
+ /** The extension for the lock file. */
+ private static final String LCK = ".lck";
+
+ /** The writer to decorate. */
+ private final Writer out;
+ /** The lock file. */
+ private final File lockFile;
+
+ /**
+ * Constructs a LockableFileWriter.
+ * If the file exists, it is overwritten.
+ *
+ * @param fileName the file to write to, not null
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(String fileName) throws IOException {
+ this(fileName, false, null);
+ }
+
+ /**
+ * Constructs a LockableFileWriter.
+ *
+ * @param fileName file to write to, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(String fileName, boolean append) throws IOException {
+ this(fileName, append, null);
+ }
+
+ /**
+ * Constructs a LockableFileWriter.
+ *
+ * @param fileName the file to write to, not null
+ * @param append true if content should be appended, false to overwrite
+ * @param lockDir the directory in which the lock file should be held
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(String fileName, boolean append, String lockDir) throws IOException {
+ this(new File(fileName), append, lockDir);
+ }
+
+ /**
+ * Constructs a LockableFileWriter.
+ * If the file exists, it is overwritten.
+ *
+ * @param file the file to write to, not null
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(File file) throws IOException {
+ this(file, false, null);
+ }
+
+ /**
+ * Constructs a LockableFileWriter.
+ *
+ * @param file the file to write to, not null
+ * @param append true if content should be appended, false to overwrite
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(File file, boolean append) throws IOException {
+ this(file, append, null);
+ }
+
+ /**
+ * Constructs a LockableFileWriter.
+ *
+ * @param file the file to write to, not null
+ * @param append true if content should be appended, false to overwrite
+ * @param lockDir the directory in which the lock file should be held
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(File file, boolean append, String lockDir) throws IOException {
+ this(file, null, append, lockDir);
+ }
+
+ /**
+ * Constructs a LockableFileWriter with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, null means platform default
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(File file, String encoding) throws IOException {
+ this(file, encoding, false, null);
+ }
+
+ /**
+ * Constructs a LockableFileWriter with a file encoding.
+ *
+ * @param file the file to write to, not null
+ * @param encoding the encoding to use, null means platform default
+ * @param append true if content should be appended, false to overwrite
+ * @param lockDir the directory in which the lock file should be held
+ * @throws NullPointerException if the file is null
+ * @throws IOException in case of an I/O error
+ */
+ public LockableFileWriter(File file, String encoding, boolean append,
+ String lockDir) throws IOException {
+ super();
+ // init file to create/append
+ file = file.getAbsoluteFile();
+ if (file.getParentFile() != null) {
+ FileUtils.forceMkdir(file.getParentFile());
+ }
+ if (file.isDirectory()) {
+ throw new IOException("File specified is a directory");
+ }
+
+ // init lock file
+ if (lockDir == null) {
+ lockDir = System.getProperty("java.io.tmpdir");
+ }
+ File lockDirFile = new File(lockDir);
+ FileUtils.forceMkdir(lockDirFile);
+ testLockDir(lockDirFile);
+ lockFile = new File(lockDirFile, file.getName() + LCK);
+
+ // check if locked
+ createLock();
+
+ // init wrapped writer
+ out = initWriter(file, encoding, append);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Tests that we can write to the lock directory.
+ *
+ * @param lockDir the File representing the lock directory
+ * @throws IOException if we cannot write to the lock directory
+ * @throws IOException if we cannot find the lock file
+ */
+ private void testLockDir(File lockDir) throws IOException {
+ if (!lockDir.exists()) {
+ throw new IOException(
+ "Could not find lockDir: " + lockDir.getAbsolutePath());
+ }
+ if (!lockDir.canWrite()) {
+ throw new IOException(
+ "Could not write to lockDir: " + lockDir.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Creates the lock file.
+ *
+ * @throws IOException if we cannot create the file
+ */
+ private void createLock() throws IOException {
+ synchronized (LockableFileWriter.class) {
+ if (!lockFile.createNewFile()) {
+ throw new IOException("Can't write file, lock " +
+ lockFile.getAbsolutePath() + " exists");
+ }
+ lockFile.deleteOnExit();
+ }
+ }
+
+ /**
+ * Initialise the wrapped file writer.
+ * Ensure that a cleanup occurs if the writer creation fails.
+ *
+ * @param file the file to be accessed
+ * @param encoding the encoding to use
+ * @param append true to append
+ * @return The initialised writer
+ * @throws IOException if an error occurs
+ */
+ private Writer initWriter(File file, String encoding, boolean append) throws IOException {
+ boolean fileExistedAlready = file.exists();
+ OutputStream stream = null;
+ Writer writer = null;
+ try {
+ if (encoding == null) {
+ writer = new FileWriter(file.getAbsolutePath(), append);
+ } else {
+ stream = new FileOutputStream(file.getAbsolutePath(), append);
+ writer = new OutputStreamWriter(stream, encoding);
+ }
+ } catch (IOException ex) {
+ IOUtils.closeQuietly(writer);
+ IOUtils.closeQuietly(stream);
+ lockFile.delete();
+ if (fileExistedAlready == false) {
+ file.delete();
+ }
+ throw ex;
+ } catch (RuntimeException ex) {
+ IOUtils.closeQuietly(writer);
+ IOUtils.closeQuietly(stream);
+ lockFile.delete();
+ if (fileExistedAlready == false) {
+ file.delete();
+ }
+ throw ex;
+ }
+ return writer;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Closes the file writer.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ try {
+ out.close();
+ } finally {
+ lockFile.delete();
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Write a character.
+ * @param idx the character to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(int idx) throws IOException {
+ out.write(idx);
+ }
+
+ /**
+ * Write the characters from an array.
+ * @param chr the characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr) throws IOException {
+ out.write(chr);
+ }
+
+ /**
+ * Write the specified characters from an array.
+ * @param chr the characters to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr, int st, int end) throws IOException {
+ out.write(chr, st, end);
+ }
+
+ /**
+ * Write the characters from a string.
+ * @param str the string to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str) throws IOException {
+ out.write(str);
+ }
+
+ /**
+ * Write the specified characters from a string.
+ * @param str the string to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str, int st, int end) throws IOException {
+ out.write(str, st, end);
+ }
+
+ /**
+ * Flush the stream.
+ * @throws IOException if an I/O error occurs
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/NullOutputStream.java b/emailcommon/src/org/apache/commons/io/output/NullOutputStream.java new file mode 100644 index 000000000..7e3cdaf2c --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/NullOutputStream.java @@ -0,0 +1,65 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This OutputStream writes all data to the famous <b>/dev/null</b>.
+ * <p>
+ * This output stream has no destination (file/socket etc.) and all
+ * bytes written to it are ignored and lost.
+ *
+ * @author Jeremias Maerki
+ * @version $Id: NullOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class NullOutputStream extends OutputStream {
+
+ /**
+ * A singleton.
+ */
+ public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param b The bytes to write
+ * @param off The start offset
+ * @param len The number of bytes to write
+ */
+ public void write(byte[] b, int off, int len) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param b The byte to write
+ */
+ public void write(int b) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param b The bytes to write
+ * @throws IOException never
+ */
+ public void write(byte[] b) throws IOException {
+ //to /dev/null
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/NullWriter.java b/emailcommon/src/org/apache/commons/io/output/NullWriter.java new file mode 100644 index 000000000..aed52aba8 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/NullWriter.java @@ -0,0 +1,96 @@ +/*
+ * 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.output;
+
+import java.io.Writer;
+
+/**
+ * This {@link Writer} writes all data to the famous <b>/dev/null</b>.
+ * <p>
+ * This <code>Writer</code> has no destination (file/socket etc.) and all
+ * characters written to it are ignored and lost.
+ *
+ * @version $Id: NullWriter.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class NullWriter extends Writer {
+
+ /**
+ * A singleton.
+ */
+ public static final NullWriter NULL_WRITER = new NullWriter();
+
+ /**
+ * Constructs a new NullWriter.
+ */
+ public NullWriter() {
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param idx The character to write
+ */
+ public void write(int idx) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param chr The characters to write
+ */
+ public void write(char[] chr) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param chr The characters to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ */
+ public void write(char[] chr, int st, int end) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param str The string to write
+ */
+ public void write(String str) {
+ //to /dev/null
+ }
+
+ /**
+ * Does nothing - output to <code>/dev/null</code>.
+ * @param str The string to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ */
+ public void write(String str, int st, int end) {
+ //to /dev/null
+ }
+
+ /** @see java.io.Writer#flush() */
+ public void flush() {
+ //to /dev/null
+ }
+
+ /** @see java.io.Writer#close() */
+ public void close() {
+ //to /dev/null
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/ProxyOutputStream.java b/emailcommon/src/org/apache/commons/io/output/ProxyOutputStream.java new file mode 100644 index 000000000..b63d72317 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/ProxyOutputStream.java @@ -0,0 +1,89 @@ +/*
+ * 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.output;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A Proxy stream which acts as expected, that is it passes the method
+ * calls on to the proxied stream and doesn't change which methods are
+ * being called. It is an alternative base class to FilterOutputStream
+ * to increase reusability.
+ *
+ * @author Stephen Colebourne
+ * @version $Id: ProxyOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class ProxyOutputStream extends FilterOutputStream {
+
+ /**
+ * Constructs a new ProxyOutputStream.
+ *
+ * @param proxy the OutputStream to delegate to
+ */
+ public ProxyOutputStream(OutputStream proxy) {
+ super(proxy);
+ // the proxy is stored in a protected superclass variable named 'out'
+ }
+
+ /**
+ * Invokes the delegate's <code>write(int)</code> method.
+ * @param idx the byte to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(int idx) throws IOException {
+ out.write(idx);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(byte[])</code> method.
+ * @param bts the bytes to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(byte[] bts) throws IOException {
+ out.write(bts);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(byte[])</code> method.
+ * @param bts the bytes to write
+ * @param st The start offset
+ * @param end The number of bytes to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(byte[] bts, int st, int end) throws IOException {
+ out.write(bts, st, end);
+ }
+
+ /**
+ * Invokes the delegate's <code>flush()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Invokes the delegate's <code>close()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ out.close();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/ProxyWriter.java b/emailcommon/src/org/apache/commons/io/output/ProxyWriter.java new file mode 100644 index 000000000..fbec62885 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/ProxyWriter.java @@ -0,0 +1,111 @@ +/*
+ * 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.output;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * A Proxy stream which acts as expected, that is it passes the method
+ * calls on to the proxied stream and doesn't change which methods are
+ * being called. It is an alternative base class to FilterWriter
+ * to increase reusability, because FilterWriter changes the
+ * methods being called, such as write(char[]) to write(char[], int, int)
+ * and write(String) to write(String, int, int).
+ *
+ * @author Stephen Colebourne
+ * @version $Id: ProxyWriter.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class ProxyWriter extends FilterWriter {
+
+ /**
+ * Constructs a new ProxyWriter.
+ *
+ * @param proxy the Writer to delegate to
+ */
+ public ProxyWriter(Writer proxy) {
+ super(proxy);
+ // the proxy is stored in a protected superclass variable named 'out'
+ }
+
+ /**
+ * Invokes the delegate's <code>write(int)</code> method.
+ * @param idx the character to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(int idx) throws IOException {
+ out.write(idx);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(char[])</code> method.
+ * @param chr the characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr) throws IOException {
+ out.write(chr);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(char[], int, int)</code> method.
+ * @param chr the characters to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(char[] chr, int st, int end) throws IOException {
+ out.write(chr, st, end);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(String)</code> method.
+ * @param str the string to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str) throws IOException {
+ out.write(str);
+ }
+
+ /**
+ * Invokes the delegate's <code>write(String)</code> method.
+ * @param str the string to write
+ * @param st The start offset
+ * @param end The number of characters to write
+ * @throws IOException if an I/O error occurs
+ */
+ public void write(String str, int st, int end) throws IOException {
+ out.write(str, st, end);
+ }
+
+ /**
+ * Invokes the delegate's <code>flush()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Invokes the delegate's <code>close()</code> method.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ out.close();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/TeeOutputStream.java b/emailcommon/src/org/apache/commons/io/output/TeeOutputStream.java new file mode 100644 index 000000000..ee957fb3b --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/TeeOutputStream.java @@ -0,0 +1,94 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Classic splitter of OutputStream. Named after the unix 'tee'
+ * command. It allows a stream to be branched off so there
+ * are now two streams.
+ *
+ * @version $Id: TeeOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
+ */
+public class TeeOutputStream extends ProxyOutputStream {
+
+ /** the second OutputStream to write to */
+ protected OutputStream branch;
+
+ /**
+ * Constructs a TeeOutputStream.
+ * @param out the main OutputStream
+ * @param branch the second OutputStream
+ */
+ public TeeOutputStream( OutputStream out, OutputStream branch ) {
+ super(out);
+ this.branch = branch;
+ }
+
+ /**
+ * Write the bytes to both streams.
+ * @param b the bytes to write
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void write(byte[] b) throws IOException {
+ super.write(b);
+ this.branch.write(b);
+ }
+
+ /**
+ * Write the specified bytes to both streams.
+ * @param b the bytes to write
+ * @param off The start offset
+ * @param len The number of bytes to write
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void write(byte[] b, int off, int len) throws IOException {
+ super.write(b, off, len);
+ this.branch.write(b, off, len);
+ }
+
+ /**
+ * Write a byte to both streams.
+ * @param b the byte to write
+ * @throws IOException if an I/O error occurs
+ */
+ public synchronized void write(int b) throws IOException {
+ super.write(b);
+ this.branch.write(b);
+ }
+
+ /**
+ * Flushes both streams.
+ * @throws IOException if an I/O error occurs
+ */
+ public void flush() throws IOException {
+ super.flush();
+ this.branch.flush();
+ }
+
+ /**
+ * Closes both streams.
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ super.close();
+ this.branch.close();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/ThresholdingOutputStream.java b/emailcommon/src/org/apache/commons/io/output/ThresholdingOutputStream.java new file mode 100644 index 000000000..fa69a804c --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/ThresholdingOutputStream.java @@ -0,0 +1,257 @@ +/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * An output stream which triggers an event when a specified number of bytes of
+ * data have been written to it. The event can be used, for example, to throw
+ * an exception if a maximum has been reached, or to switch the underlying
+ * stream type when the threshold is exceeded.
+ * <p>
+ * This class overrides all <code>OutputStream</code> methods. However, these
+ * overrides ultimately call the corresponding methods in the underlying output
+ * stream implementation.
+ * <p>
+ * NOTE: This implementation may trigger the event <em>before</em> the threshold
+ * is actually reached, since it triggers when a pending write operation would
+ * cause the threshold to be exceeded.
+ *
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ *
+ * @version $Id: ThresholdingOutputStream.java 540714 2007-05-22 19:39:44Z niallp $
+ */
+public abstract class ThresholdingOutputStream
+ extends OutputStream
+{
+
+ // ----------------------------------------------------------- Data members
+
+
+ /**
+ * The threshold at which the event will be triggered.
+ */
+ private int threshold;
+
+
+ /**
+ * The number of bytes written to the output stream.
+ */
+ private long written;
+
+
+ /**
+ * Whether or not the configured threshold has been exceeded.
+ */
+ private boolean thresholdExceeded;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs an instance of this class which will trigger an event at the
+ * specified threshold.
+ *
+ * @param threshold The number of bytes at which to trigger an event.
+ */
+ public ThresholdingOutputStream(int threshold)
+ {
+ this.threshold = threshold;
+ }
+
+
+ // --------------------------------------------------- OutputStream methods
+
+
+ /**
+ * Writes the specified byte to this output stream.
+ *
+ * @param b The byte to be written.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void write(int b) throws IOException
+ {
+ checkThreshold(1);
+ getStream().write(b);
+ written++;
+ }
+
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array to this
+ * output stream.
+ *
+ * @param b The array of bytes to be written.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void write(byte b[]) throws IOException
+ {
+ checkThreshold(b.length);
+ getStream().write(b);
+ written += b.length;
+ }
+
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array starting at
+ * offset <code>off</code> to this output stream.
+ *
+ * @param b The byte array from which the data will be written.
+ * @param off The start offset in the byte array.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void write(byte b[], int off, int len) throws IOException
+ {
+ checkThreshold(len);
+ getStream().write(b, off, len);
+ written += len;
+ }
+
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes to be
+ * written out.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void flush() throws IOException
+ {
+ getStream().flush();
+ }
+
+
+ /**
+ * Closes this output stream and releases any system resources associated
+ * with this stream.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public void close() throws IOException
+ {
+ try
+ {
+ flush();
+ }
+ catch (IOException ignored)
+ {
+ // ignore
+ }
+ getStream().close();
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Returns the threshold, in bytes, at which an event will be triggered.
+ *
+ * @return The threshold point, in bytes.
+ */
+ public int getThreshold()
+ {
+ return threshold;
+ }
+
+
+ /**
+ * Returns the number of bytes that have been written to this output stream.
+ *
+ * @return The number of bytes written.
+ */
+ public long getByteCount()
+ {
+ return written;
+ }
+
+
+ /**
+ * Determines whether or not the configured threshold has been exceeded for
+ * this output stream.
+ *
+ * @return <code>true</code> if the threshold has been reached;
+ * <code>false</code> otherwise.
+ */
+ public boolean isThresholdExceeded()
+ {
+ return (written > threshold);
+ }
+
+
+ // ------------------------------------------------------ Protected methods
+
+
+ /**
+ * Checks to see if writing the specified number of bytes would cause the
+ * configured threshold to be exceeded. If so, triggers an event to allow
+ * a concrete implementation to take action on this.
+ *
+ * @param count The number of bytes about to be written to the underlying
+ * output stream.
+ *
+ * @exception IOException if an error occurs.
+ */
+ protected void checkThreshold(int count) throws IOException
+ {
+ if (!thresholdExceeded && (written + count > threshold))
+ {
+ thresholdExceeded = true;
+ thresholdReached();
+ }
+ }
+
+ /**
+ * Resets the byteCount to zero. You can call this from
+ * {@link #thresholdReached()} if you want the event to be triggered again.
+ */
+ protected void resetByteCount()
+ {
+ this.thresholdExceeded = false;
+ this.written = 0;
+ }
+
+ // ------------------------------------------------------- Abstract methods
+
+
+ /**
+ * Returns the underlying output stream, to which the corresponding
+ * <code>OutputStream</code> methods in this class will ultimately delegate.
+ *
+ * @return The underlying output stream.
+ *
+ * @exception IOException if an error occurs.
+ */
+ protected abstract OutputStream getStream() throws IOException;
+
+
+ /**
+ * Indicates that the configured threshold has been reached, and that a
+ * subclass should take whatever action necessary on this event. This may
+ * include changing the underlying output stream.
+ *
+ * @exception IOException if an error occurs.
+ */
+ protected abstract void thresholdReached() throws IOException;
+}
diff --git a/emailcommon/src/org/apache/commons/io/output/package.html b/emailcommon/src/org/apache/commons/io/output/package.html new file mode 100644 index 000000000..db2cbce59 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/output/package.html @@ -0,0 +1,25 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body>
+<p>
+This package provides implementations of output classes, such as
+<code>OutputStream</code> and <code>Writer</code>.
+</p>
+</body>
+</html>
diff --git a/emailcommon/src/org/apache/commons/io/overview.html b/emailcommon/src/org/apache/commons/io/overview.html new file mode 100644 index 000000000..31311b5e9 --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/overview.html @@ -0,0 +1,32 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body bgcolor="white">
+<p>
+The commons-io component contains utility classes,
+filters, streams, readers and writers.
+</p>
+<p>
+These classes aim to add to the standard JDK IO classes.
+The utilities provide convenience wrappers around the JDK, simplifying
+various operations into pre-tested units of code.
+The filters and streams provide useful implementations that perhaps should
+be in the JDK itself.
+</p>
+</body>
+</html>
diff --git a/emailcommon/src/org/apache/commons/io/package.html b/emailcommon/src/org/apache/commons/io/package.html new file mode 100644 index 000000000..e5ba9b0aa --- /dev/null +++ b/emailcommon/src/org/apache/commons/io/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+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.
+-->
+<html>
+<body bgcolor="white">
+<p>
+This package defines utility classes for working with streams, readers,
+writers and files. The most commonly used classes are described here:
+</p>
+<p>
+<b>IOUtils</b> is the most frequently used class.
+It provides operations to read, write, copy and close streams.
+</p>
+<p>
+<b>FileUtils</b> provides operations based around the JDK File class.
+These include reading, writing, copying, comparing and deleting.
+</p>
+<p>
+<b>FilenameUtils</b> provides utilities based on filenames.
+This utility class manipulates filenames without using File objects.
+It aims to simplify the transition between Windows and Unix.
+Before using this class however, you should consider whether you should
+be using File objects.
+</p>
+<p>
+<b>FileSystemUtils</b> allows access to the filing system in ways the JDK
+does not support. At present this allows you to get the free space on a drive.
+</p>
+<p>
+<b>EndianUtils</b> swaps data between Big-Endian and Little-Endian formats.
+</p>
+</body>
+</html>
diff --git a/emailcommon/src/org/apache/james/mime4j/AbstractContentHandler.java b/emailcommon/src/org/apache/james/mime4j/AbstractContentHandler.java new file mode 100644 index 000000000..06c9b90a0 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/AbstractContentHandler.java @@ -0,0 +1,113 @@ +/****************************************************************
+ * 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;
+
+/**
+ * Abstract <code>ContentHandler</code> with default implementations of all
+ * the methods of the <code>ContentHandler</code> interface.
+ *
+ * The default is to todo nothing.
+ *
+ *
+ * @version $Id: AbstractContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $
+ */
+public abstract class AbstractContentHandler implements ContentHandler {
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endMultipart()
+ */
+ public void endMultipart() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startMultipart(org.apache.james.mime4j.BodyDescriptor)
+ */
+ public void startMultipart(BodyDescriptor bd) {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream)
+ */
+ public void body(BodyDescriptor bd, InputStream is) throws IOException {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endBodyPart()
+ */
+ public void endBodyPart() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endHeader()
+ */
+ public void endHeader() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endMessage()
+ */
+ public void endMessage() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#epilogue(java.io.InputStream)
+ */
+ public void epilogue(InputStream is) throws IOException {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#field(java.lang.String)
+ */
+ public void field(String fieldData) {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#preamble(java.io.InputStream)
+ */
+ public void preamble(InputStream is) throws IOException {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startBodyPart()
+ */
+ public void startBodyPart() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startHeader()
+ */
+ public void startHeader() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startMessage()
+ */
+ public void startMessage() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#raw(java.io.InputStream)
+ */
+ public void raw(InputStream is) throws IOException {
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/BodyDescriptor.java b/emailcommon/src/org/apache/james/mime4j/BodyDescriptor.java new file mode 100644 index 000000000..2fef0be04 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/BodyDescriptor.java @@ -0,0 +1,392 @@ +/****************************************************************
+ * 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;
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/CloseShieldInputStream.java b/emailcommon/src/org/apache/james/mime4j/CloseShieldInputStream.java new file mode 100644 index 000000000..94995d110 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/CloseShieldInputStream.java @@ -0,0 +1,129 @@ +/****************************************************************
+ * 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");
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/ContentHandler.java b/emailcommon/src/org/apache/james/mime4j/ContentHandler.java new file mode 100644 index 000000000..946c89401 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/ContentHandler.java @@ -0,0 +1,177 @@ +/****************************************************************
+ * 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;
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/EOLConvertingInputStream.java b/emailcommon/src/org/apache/james/mime4j/EOLConvertingInputStream.java new file mode 100644 index 000000000..7d5009ca5 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/EOLConvertingInputStream.java @@ -0,0 +1,108 @@ +/****************************************************************
+ * 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;
+
+ /**
+ * 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) {
+ this(in, CONVERT_BOTH);
+ }
+ /**
+ * 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 flags one of <code>CONVERT_CR</code>, <code>CONVERT_LF</code> or
+ * <code>CONVERT_BOTH</code>.
+ */
+ public EOLConvertingInputStream(InputStream in, int flags) {
+ super();
+
+ this.in = new PushbackInputStream(in, 2);
+ this.flags = flags;
+ }
+
+ /**
+ * Closes the underlying stream.
+ *
+ * @throws IOException on I/O errors.
+ */
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /**
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOException {
+ int b = in.read();
+
+ if (b == -1) {
+ return -1;
+ }
+
+ if ((flags & CONVERT_CR) != 0 && b == '\r') {
+ int c = in.read();
+ if (c != -1) {
+ in.unread(c);
+ }
+ if (c != '\n') {
+ in.unread('\n');
+ }
+ } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') {
+ b = '\r';
+ in.unread('\n');
+ }
+
+ previous = b;
+
+ return b;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/Log.java b/emailcommon/src/org/apache/james/mime4j/Log.java new file mode 100644 index 000000000..e7f33fcc7 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/Log.java @@ -0,0 +1,114 @@ +/* + * 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; + +import com.android.emailcommon.Logging; + +/** + * Empty stub for the apache logging library. + */ +public class 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(Logging.LOG_TAG, toString(message, null)); + } + + public void trace(Object message, Throwable t) { + if (!isTraceEnabled()) return; + android.util.Log.v(Logging.LOG_TAG, toString(message, t)); + } + + public void debug(Object message) { + if (!isDebugEnabled()) return; + android.util.Log.d(Logging.LOG_TAG, toString(message, null)); + } + + public void debug(Object message, Throwable t) { + if (!isDebugEnabled()) return; + android.util.Log.d(Logging.LOG_TAG, toString(message, t)); + } + + public void info(Object message) { + if (!isInfoEnabled()) return; + android.util.Log.i(Logging.LOG_TAG, toString(message, null)); + } + + public void info(Object message, Throwable t) { + if (!isInfoEnabled()) return; + android.util.Log.i(Logging.LOG_TAG, toString(message, t)); + } + + public void warn(Object message) { + android.util.Log.w(Logging.LOG_TAG, toString(message, null)); + } + + public void warn(Object message, Throwable t) { + android.util.Log.w(Logging.LOG_TAG, toString(message, t)); + } + + public void error(Object message) { + android.util.Log.e(Logging.LOG_TAG, toString(message, null)); + } + + public void error(Object message, Throwable t) { + android.util.Log.e(Logging.LOG_TAG, toString(message, t)); + } + + public void fatal(Object message) { + android.util.Log.e(Logging.LOG_TAG, toString(message, null)); + } + + public void fatal(Object message, Throwable t) { + android.util.Log.e(Logging.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(); + } + } +} diff --git a/emailcommon/src/org/apache/james/mime4j/LogFactory.java b/emailcommon/src/org/apache/james/mime4j/LogFactory.java new file mode 100644 index 000000000..c8f00d1d3 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/LogFactory.java @@ -0,0 +1,29 @@ +/* + * 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); + } +} diff --git a/emailcommon/src/org/apache/james/mime4j/MimeBoundaryInputStream.java b/emailcommon/src/org/apache/james/mime4j/MimeBoundaryInputStream.java new file mode 100644 index 000000000..0fffb7820 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/MimeBoundaryInputStream.java @@ -0,0 +1,184 @@ +/****************************************************************
+ * 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;
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/MimeStreamParser.java b/emailcommon/src/org/apache/james/mime4j/MimeStreamParser.java new file mode 100644 index 000000000..d2eaa9707 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/MimeStreamParser.java @@ -0,0 +1,325 @@ +/****************************************************************
+ * 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 com.android.emailcommon.utility.LoggingInputStream;
+
+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 final boolean DEBUG_LOG_MESSAGE = false; //DO NOT RELEASE AS 'TRUE'
+
+ private static BitSet fieldChars = null;
+
+ private RootInputStream rootStream = null;
+ private LinkedList<BodyDescriptor> bodyDescriptors = new LinkedList<BodyDescriptor>();
+ private ContentHandler handler = null;
+ private boolean raw = 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 {
+ if (DEBUG_LOG_MESSAGE) {
+ is = new LoggingInputStream(is, "MIME", true);
+ }
+ 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()) {
+// 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();
+ }
+ }
+
+ 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;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/RootInputStream.java b/emailcommon/src/org/apache/james/mime4j/RootInputStream.java new file mode 100644 index 000000000..fa848df18 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/RootInputStream.java @@ -0,0 +1,111 @@ +/****************************************************************
+ * 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);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/SimpleContentHandler.java b/emailcommon/src/org/apache/james/mime4j/SimpleContentHandler.java new file mode 100644 index 000000000..13f1fd2c6 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/SimpleContentHandler.java @@ -0,0 +1,100 @@ +/****************************************************************
+ * 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 org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.message.Header;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Abstract implementation of ContentHandler that automates common
+ * tasks. Currently performs header parsing and applies content-transfer
+ * decoding to body parts.
+ *
+ *
+ */
+public abstract class SimpleContentHandler extends AbstractContentHandler {
+
+ /**
+ * Called after headers are parsed.
+ */
+ public abstract void headers(Header header);
+
+ /**
+ * Called when the body of a discrete (non-multipart) entity is encountered.
+
+ * @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.
+ * @param is the contents of the body. Base64 or quoted-printable
+ * decoding will be applied transparently.
+ * @throws IOException should be thrown on I/O errors.
+ */
+ public abstract void bodyDecoded(BodyDescriptor bd, InputStream is) throws IOException;
+
+
+ /* Implement introduced callbacks. */
+
+ private Header currHeader;
+
+ /**
+ * @see org.apache.james.mime4j.AbstractContentHandler#startHeader()
+ */
+ public final void startHeader() {
+ currHeader = new Header();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.AbstractContentHandler#field(java.lang.String)
+ */
+ public final void field(String fieldData) {
+ currHeader.addField(Field.parse(fieldData));
+ }
+
+ /**
+ * @see org.apache.james.mime4j.AbstractContentHandler#endHeader()
+ */
+ public final void endHeader() {
+ Header tmp = currHeader;
+ currHeader = null;
+ headers(tmp);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.AbstractContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream)
+ */
+ public final void body(BodyDescriptor bd, InputStream is) throws IOException {
+ if (bd.isBase64Encoded()) {
+ bodyDecoded(bd, new Base64InputStream(is));
+ }
+ else if (bd.isQuotedPrintableEncoded()) {
+ bodyDecoded(bd, new QuotedPrintableInputStream(is));
+ }
+ else {
+ bodyDecoded(bd, is);
+ }
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/ThirdPartyProject.prop b/emailcommon/src/org/apache/james/mime4j/ThirdPartyProject.prop new file mode 100644 index 000000000..525791c21 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/ThirdPartyProject.prop @@ -0,0 +1,10 @@ +# Copyright 2010 Google Inc. All Rights Reserved. +#Fri Jul 16 10:03:08 PDT 2010 +currentVersion=0.6 +version=Unknown / modified locally +isNative=false +feedurl=https\://issues.apache.org/jira/secure/ReleaseNote.jspa +name=apache_mime4j +keywords=apache mime4j +onDevice=true +homepage=http\://james.apache.org/index.html diff --git a/emailcommon/src/org/apache/james/mime4j/codec/EncoderUtil.java b/emailcommon/src/org/apache/james/mime4j/codec/EncoderUtil.java new file mode 100644 index 000000000..6841bc998 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/codec/EncoderUtil.java @@ -0,0 +1,630 @@ +/**************************************************************** + * 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/emailcommon/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/emailcommon/src/org/apache/james/mime4j/decoder/Base64InputStream.java new file mode 100644 index 000000000..2461ed571 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/decoder/Base64InputStream.java @@ -0,0 +1,151 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/decoder/ByteQueue.java b/emailcommon/src/org/apache/james/mime4j/decoder/ByteQueue.java new file mode 100644 index 000000000..68e7d3380 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/decoder/ByteQueue.java @@ -0,0 +1,62 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/emailcommon/src/org/apache/james/mime4j/decoder/DecoderUtil.java new file mode 100644 index 000000000..551be0f57 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/decoder/DecoderUtil.java @@ -0,0 +1,279 @@ +/****************************************************************
+ * 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 "?=".
+ int endScan = begin + 2;
+ if (begin != -1) {
+ int qm1 = body.indexOf('?', endScan + 2);
+ int qm2 = body.indexOf('?', qm1 + 1);
+ if (qm2 != -1) {
+ endScan = qm2 + 1;
+ }
+ }
+
+ int end = begin == -1 ? -1 : body.indexOf("?=", endScan);
+ if (end == -1) {
+ if (previousEnd == 0)
+ return body;
+
+ sb.append(body.substring(previousEnd));
+ return sb.toString();
+ }
+ 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;
+ }
+ }
+
+ // return null on error
+ private static String decodeEncodedWord(String body, int begin, int end) {
+ int qm1 = body.indexOf('?', begin + 2);
+ if (qm1 == end - 2)
+ return null;
+
+ int qm2 = body.indexOf('?', qm1 + 1);
+ if (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/emailcommon/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java b/emailcommon/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java new file mode 100644 index 000000000..cbcb22628 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java @@ -0,0 +1,229 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java b/emailcommon/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java new file mode 100644 index 000000000..dc32caf36 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java @@ -0,0 +1,272 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/AddressListField.java b/emailcommon/src/org/apache/james/mime4j/field/AddressListField.java new file mode 100644 index 000000000..b37abbb11 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/AddressListField.java @@ -0,0 +1,65 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/emailcommon/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java new file mode 100644 index 000000000..eb6151377 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java @@ -0,0 +1,88 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/ContentTypeField.java b/emailcommon/src/org/apache/james/mime4j/field/ContentTypeField.java new file mode 100644 index 000000000..646cf141a --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/ContentTypeField.java @@ -0,0 +1,259 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/DateTimeField.java b/emailcommon/src/org/apache/james/mime4j/field/DateTimeField.java new file mode 100644 index 000000000..e65551fcd --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/DateTimeField.java @@ -0,0 +1,72 @@ +/****************************************************************
+ * 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.emailcommon.utility.Utility;
+
+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 = Utility.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/emailcommon/src/org/apache/james/mime4j/field/DefaultFieldParser.java b/emailcommon/src/org/apache/james/mime4j/field/DefaultFieldParser.java new file mode 100644 index 000000000..84fcdcb2d --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/DefaultFieldParser.java @@ -0,0 +1,45 @@ +/*
+ * 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/emailcommon/src/org/apache/james/mime4j/field/DelegatingFieldParser.java b/emailcommon/src/org/apache/james/mime4j/field/DelegatingFieldParser.java new file mode 100644 index 000000000..2a2866f57 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/DelegatingFieldParser.java @@ -0,0 +1,47 @@ +/*
+ * 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/emailcommon/src/org/apache/james/mime4j/field/Field.java b/emailcommon/src/org/apache/james/mime4j/field/Field.java new file mode 100644 index 000000000..7c2a20dc8 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/Field.java @@ -0,0 +1,192 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/FieldParser.java b/emailcommon/src/org/apache/james/mime4j/field/FieldParser.java new file mode 100644 index 000000000..4f33c9e26 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/FieldParser.java @@ -0,0 +1,21 @@ +/*
+ * 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/emailcommon/src/org/apache/james/mime4j/field/MailboxField.java b/emailcommon/src/org/apache/james/mime4j/field/MailboxField.java new file mode 100644 index 000000000..9404fd621 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/MailboxField.java @@ -0,0 +1,70 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/MailboxListField.java b/emailcommon/src/org/apache/james/mime4j/field/MailboxListField.java new file mode 100644 index 000000000..6364fc88c --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/MailboxListField.java @@ -0,0 +1,67 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/UnstructuredField.java b/emailcommon/src/org/apache/james/mime4j/field/UnstructuredField.java new file mode 100644 index 000000000..5e2adf9f2 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/UnstructuredField.java @@ -0,0 +1,49 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/Address.java b/emailcommon/src/org/apache/james/mime4j/field/address/Address.java new file mode 100644 index 000000000..2a5d61e36 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/Address.java @@ -0,0 +1,52 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/AddressList.java b/emailcommon/src/org/apache/james/mime4j/field/address/AddressList.java new file mode 100644 index 000000000..fa4d02c23 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/AddressList.java @@ -0,0 +1,138 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/Builder.java b/emailcommon/src/org/apache/james/mime4j/field/address/Builder.java new file mode 100644 index 000000000..a2bd3f0c6 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/Builder.java @@ -0,0 +1,243 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/DomainList.java b/emailcommon/src/org/apache/james/mime4j/field/address/DomainList.java new file mode 100644 index 000000000..df5b4de27 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/DomainList.java @@ -0,0 +1,76 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/Group.java b/emailcommon/src/org/apache/james/mime4j/field/address/Group.java new file mode 100644 index 000000000..cca2b40b5 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/Group.java @@ -0,0 +1,75 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/Mailbox.java b/emailcommon/src/org/apache/james/mime4j/field/address/Mailbox.java new file mode 100644 index 000000000..c05a57f8e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/Mailbox.java @@ -0,0 +1,121 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/MailboxList.java b/emailcommon/src/org/apache/james/mime4j/field/address/MailboxList.java new file mode 100644 index 000000000..25337de9e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/MailboxList.java @@ -0,0 +1,71 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/NamedMailbox.java b/emailcommon/src/org/apache/james/mime4j/field/address/NamedMailbox.java new file mode 100644 index 000000000..a54bd1dad --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/NamedMailbox.java @@ -0,0 +1,71 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java new file mode 100644 index 000000000..4d56d000b --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java new file mode 100644 index 000000000..47bdeda8e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java new file mode 100644 index 000000000..737840e38 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java new file mode 100644 index 000000000..8cb8f421f --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java new file mode 100644 index 000000000..b52664386 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java new file mode 100644 index 000000000..f6017b9fc --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java new file mode 100644 index 000000000..5c244fa3e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java new file mode 100644 index 000000000..aeb469da1 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java new file mode 100644 index 000000000..846c73167 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java new file mode 100644 index 000000000..7d711c529 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTroute.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTroute.java new file mode 100644 index 000000000..54ea11523 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ASTroute.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java new file mode 100644 index 000000000..dde2a0892 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java @@ -0,0 +1,977 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj new file mode 100644 index 000000000..685988634 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj @@ -0,0 +1,595 @@ +/*@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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java new file mode 100644 index 000000000..a21ad35db --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java @@ -0,0 +1,76 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java new file mode 100644 index 000000000..df8974a3b --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java @@ -0,0 +1,1009 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java new file mode 100644 index 000000000..5987f19d8 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java @@ -0,0 +1,35 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java new file mode 100644 index 000000000..8ec2fe7d2 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java @@ -0,0 +1,19 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/BaseNode.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/BaseNode.java new file mode 100644 index 000000000..42fe3db0c --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/BaseNode.java @@ -0,0 +1,30 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java new file mode 100644 index 000000000..08b5c5bef --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java @@ -0,0 +1,123 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/Node.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/Node.java new file mode 100644 index 000000000..158892016 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/Node.java @@ -0,0 +1,37 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/ParseException.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ParseException.java new file mode 100644 index 000000000..939c6cfed --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/ParseException.java @@ -0,0 +1,207 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java new file mode 100644 index 000000000..957bbeabc --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java @@ -0,0 +1,454 @@ +/* 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 + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @deprecated + * @see #getEndLine + */ + + 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java new file mode 100644 index 000000000..9bf537e60 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java @@ -0,0 +1,87 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/Token.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/Token.java new file mode 100644 index 000000000..0228aac3e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/Token.java @@ -0,0 +1,96 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java b/emailcommon/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java new file mode 100644 index 000000000..c06a44cf3 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java @@ -0,0 +1,148 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java new file mode 100644 index 000000000..9d4a0f564 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java @@ -0,0 +1,268 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java new file mode 100644 index 000000000..8a763287d --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java @@ -0,0 +1,62 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java new file mode 100644 index 000000000..05d940db5 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java @@ -0,0 +1,877 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java new file mode 100644 index 000000000..2c5dc8275 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java @@ -0,0 +1,207 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java new file mode 100644 index 000000000..c139e4f38 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java @@ -0,0 +1,454 @@ +/* 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 + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @deprecated + * @see #getEndLine + */ + + 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/Token.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/Token.java new file mode 100644 index 000000000..5bef6cf02 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/Token.java @@ -0,0 +1,96 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java new file mode 100644 index 000000000..4a490efac --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java @@ -0,0 +1,148 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/DateTime.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/DateTime.java new file mode 100644 index 000000000..bf00ca753 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/DateTime.java @@ -0,0 +1,127 @@ +/****************************************************************
+ * 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java new file mode 100644 index 000000000..04cb9520b --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java @@ -0,0 +1,570 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java new file mode 100644 index 000000000..17389d816 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java @@ -0,0 +1,86 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java new file mode 100644 index 000000000..e75998cf2 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java @@ -0,0 +1,882 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java new file mode 100644 index 000000000..418699107 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java @@ -0,0 +1,207 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java new file mode 100644 index 000000000..d44a9018b --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java @@ -0,0 +1,454 @@ +/* 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 + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @deprecated + * @see #getEndLine + */ + + 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/Token.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/Token.java new file mode 100644 index 000000000..52d101ed0 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/Token.java @@ -0,0 +1,96 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java new file mode 100644 index 000000000..973255070 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java @@ -0,0 +1,148 @@ +/* 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/emailcommon/src/org/apache/james/mime4j/message/AbstractBody.java b/emailcommon/src/org/apache/james/mime4j/message/AbstractBody.java new file mode 100644 index 000000000..d2647ec77 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/AbstractBody.java @@ -0,0 +1,47 @@ +/****************************************************************
+ * 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.message;
+
+
+/**
+ * Abstract <code>Body</code> implementation providing the parent
+ * functionality required by bodies.
+ *
+ *
+ * @version $Id: AbstractBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+public abstract class AbstractBody implements Body {
+ private Entity parent = null;
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/BinaryBody.java b/emailcommon/src/org/apache/james/mime4j/message/BinaryBody.java new file mode 100644 index 000000000..bfc992a8f --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/BinaryBody.java @@ -0,0 +1,42 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * Interface implemented by bodies containing binary data.
+ *
+ *
+ * @version $Id: BinaryBody.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public interface BinaryBody extends Body {
+
+ /**
+ * Gets a <code>InputStream</code> which reads the bytes of the
+ * body.
+ *
+ * @return the stream.
+ * @throws IOException on I/O errors.
+ */
+ InputStream getInputStream() throws IOException;
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/Body.java b/emailcommon/src/org/apache/james/mime4j/message/Body.java new file mode 100644 index 000000000..54b8948db --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/Body.java @@ -0,0 +1,54 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encapsulates the body of an entity (see RFC 2045).
+ *
+ *
+ * @version $Id: Body.java,v 1.4 2004/10/04 15:36:43 ntherning Exp $
+ */
+public interface Body {
+
+ /**
+ * Gets the parent of this body.
+ *
+ * @return the parent.
+ */
+ Entity getParent();
+
+ /**
+ * Sets the parent of this body.
+ *
+ * @param parent the parent.
+ */
+ void setParent(Entity parent);
+
+ /**
+ * Writes this body to the given stream in MIME message format.
+ *
+ * @param out the stream to write to.
+ * @throws IOException on I/O errors.
+ */
+ void writeTo(OutputStream out) throws IOException;
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/BodyPart.java b/emailcommon/src/org/apache/james/mime4j/message/BodyPart.java new file mode 100644 index 000000000..474030d7f --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/BodyPart.java @@ -0,0 +1,42 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Represents a MIME body part (see RFC 2045).
+ *
+ *
+ * @version $Id: BodyPart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public class BodyPart extends Entity {
+
+ /**
+ *
+ * @see org.apache.james.mime4j.message.Entity#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ getHeader().writeTo(out);
+ getBody().writeTo(out);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/Entity.java b/emailcommon/src/org/apache/james/mime4j/message/Entity.java new file mode 100644 index 000000000..96f2a4875 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/Entity.java @@ -0,0 +1,170 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.james.mime4j.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.Field;
+
+/**
+ * MIME entity. An entity has a header and a body (see RFC 2045).
+ *
+ *
+ * @version $Id: Entity.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public abstract class Entity {
+ private Header header = null;
+ private Body body = null;
+ private Entity parent = null;
+
+ /**
+ * Gets the parent entity of this entity.
+ * Returns <code>null</code> if this is the root entity.
+ *
+ * @return the parent or <code>null</code>.
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parent entity of this entity.
+ *
+ * @param parent the parent entity or <code>null</code> if
+ * this will be the root entity.
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the entity header.
+ *
+ * @return the header.
+ */
+ public Header getHeader() {
+ return header;
+ }
+
+ /**
+ * Sets the entity header.
+ *
+ * @param header the header.
+ */
+ public void setHeader(Header header) {
+ this.header = header;
+ }
+
+ /**
+ * Gets the body of this entity.
+ *
+ * @return the body,
+ */
+ public Body getBody() {
+ return body;
+ }
+
+ /**
+ * Sets the body of this entity.
+ *
+ * @param body the body.
+ */
+ public void setBody(Body body) {
+ this.body = body;
+ body.setParent(this);
+ }
+
+ /**
+ * Determines the MIME type of this <code>Entity</code>. The MIME type
+ * is derived by looking at the parent's Content-Type field if no
+ * Content-Type field is set for this <code>Entity</code>.
+ *
+ * @return the MIME type.
+ */
+ public String getMimeType() {
+ ContentTypeField child =
+ (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE);
+ ContentTypeField parent = getParent() != null
+ ? (ContentTypeField) getParent().getHeader().
+ getField(Field.CONTENT_TYPE)
+ : null;
+
+ return ContentTypeField.getMimeType(child, parent);
+ }
+
+ /**
+ * Determines the MIME character set encoding of this <code>Entity</code>.
+ *
+ * @return the MIME character set encoding.
+ */
+ public String getCharset() {
+ return ContentTypeField.getCharset(
+ (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE));
+ }
+
+ /**
+ * Determines the transfer encoding of this <code>Entity</code>.
+ *
+ * @return the transfer encoding.
+ */
+ public String getContentTransferEncoding() {
+ ContentTransferEncodingField f = (ContentTransferEncodingField)
+ getHeader().getField(Field.CONTENT_TRANSFER_ENCODING);
+
+ return ContentTransferEncodingField.getEncoding(f);
+ }
+
+ /**
+ * Determines if the MIME type of this <code>Entity</code> matches the
+ * given one. MIME types are case-insensitive.
+ *
+ * @param type the MIME type to match against.
+ * @return <code>true</code> on match, <code>false</code> otherwise.
+ */
+ public boolean isMimeType(String type) {
+ return getMimeType().equalsIgnoreCase(type);
+ }
+
+ /**
+ * Determines if the MIME type of this <code>Entity</code> is
+ * <code>multipart/*</code>. Since multipart-entities must have
+ * a boundary parameter in the <code>Content-Type</code> field this
+ * method returns <code>false</code> if no boundary exists.
+ *
+ * @return <code>true</code> on match, <code>false</code> otherwise.
+ */
+ public boolean isMultipart() {
+ ContentTypeField f =
+ (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE);
+ return f != null && f.getBoundary() != null
+ && getMimeType().startsWith(ContentTypeField.TYPE_MULTIPART_PREFIX);
+ }
+
+ /**
+ * Write the content to the given outputstream
+ *
+ * @param out the outputstream to write to
+ * @throws IOException
+ */
+ public abstract void writeTo(OutputStream out) throws IOException;
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/Header.java b/emailcommon/src/org/apache/james/mime4j/message/Header.java new file mode 100644 index 000000000..e9216a821 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/Header.java @@ -0,0 +1,158 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.james.mime4j.AbstractContentHandler;
+import org.apache.james.mime4j.MimeStreamParser;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+
+/**
+ * The header of an entity (see RFC 2045).
+ *
+ *
+ * @version $Id: Header.java,v 1.3 2004/10/04 15:36:44 ntherning Exp $
+ */
+public class Header {
+ private List<Field> fields = new LinkedList<Field>();
+ private HashMap<String, List<Field>> fieldMap = new HashMap<String, List<Field>>();
+
+ /**
+ * Creates a new empty <code>Header</code>.
+ */
+ public Header() {
+ }
+
+ /**
+ * Creates a new <code>Header</code> from the specified stream.
+ *
+ * @param is the stream to read the header from.
+ */
+ public Header(InputStream is) throws IOException {
+ final MimeStreamParser parser = new MimeStreamParser();
+ parser.setContentHandler(new AbstractContentHandler() {
+ @Override
+ public void endHeader() {
+ parser.stop();
+ }
+ @Override
+ public void field(String fieldData) {
+ addField(Field.parse(fieldData));
+ }
+ });
+ parser.parse(is);
+ }
+
+ /**
+ * Adds a field to the end of the list of fields.
+ *
+ * @param field the field to add.
+ */
+ public void addField(Field field) {
+ List<Field> values = fieldMap.get(field.getName().toLowerCase());
+ if (values == null) {
+ values = new LinkedList<Field>();
+ fieldMap.put(field.getName().toLowerCase(), values);
+ }
+ values.add(field);
+ fields.add(field);
+ }
+
+ /**
+ * Gets the fields of this header. The returned list will not be
+ * modifiable.
+ *
+ * @return the list of <code>Field</code> objects.
+ */
+ public List<Field> getFields() {
+ return Collections.unmodifiableList(fields);
+ }
+
+ /**
+ * Gets a <code>Field</code> given a field name. If there are multiple
+ * such fields defined in this header the first one will be returned.
+ *
+ * @param name the field name (e.g. From, Subject).
+ * @return the field or <code>null</code> if none found.
+ */
+ public Field getField(String name) {
+ List<Field> l = fieldMap.get(name.toLowerCase());
+ if (l != null && !l.isEmpty()) {
+ return l.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Gets all <code>Field</code>s having the specified field name.
+ *
+ * @param name the field name (e.g. From, Subject).
+ * @return the list of fields.
+ */
+ public List<Field> getFields(String name) {
+ List<Field> l = fieldMap.get(name.toLowerCase());
+ return Collections.unmodifiableList(l);
+ }
+
+ /**
+ * Return Header Object as String representation. Each headerline is
+ * seperated by "\r\n"
+ *
+ * @return headers
+ */
+ @Override
+ public String toString() {
+ StringBuffer str = new StringBuffer();
+ for (Iterator<Field> it = fields.iterator(); it.hasNext();) {
+ str.append(it.next().toString());
+ str.append("\r\n");
+ }
+ return str.toString();
+ }
+
+
+ /**
+ * Write the Header to the given OutputStream
+ *
+ * @param out the OutputStream to write to
+ * @throws IOException
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ String charString = ((ContentTypeField) getField(Field.CONTENT_TYPE)).getCharset();
+
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CharsetUtil.getCharset(charString)),8192);
+ writer.write(toString()+ "\r\n");
+ writer.flush();
+ }
+
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/MemoryBinaryBody.java b/emailcommon/src/org/apache/james/mime4j/message/MemoryBinaryBody.java new file mode 100644 index 000000000..a44db4db1 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/MemoryBinaryBody.java @@ -0,0 +1,92 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+//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.TempPath;
+import org.apache.james.mime4j.util.TempStorage;
+
+
+/**
+ * Binary body backed by a {@link org.apache.james.mime4j.util.TempFile}.
+ *
+ *
+ * @version $Id: TempFileBinaryBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+class MemoryBinaryBody extends AbstractBody implements BinaryBody {
+ private static Log log = LogFactory.getLog(MemoryBinaryBody.class);
+
+ private Entity parent = null;
+ private byte[] tempFile = null;
+
+ /**
+ * Use the given InputStream to build the TemporyFileBinaryBody
+ *
+ * @param is the InputStream to use as source
+ * @throws IOException
+ */
+ public MemoryBinaryBody(InputStream is) throws IOException {
+
+ TempPath tempPath = TempStorage.getInstance().getRootTempPath();
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IOUtils.copy(is, out);
+ out.close();
+ tempFile = out.toByteArray();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.AbstractBody#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.AbstractBody#setParent(org.apache.james.mime4j.message.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.BinaryBody#getInputStream()
+ */
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(tempFile);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ IOUtils.copy(getInputStream(),out);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/MemoryTextBody.java b/emailcommon/src/org/apache/james/mime4j/message/MemoryTextBody.java new file mode 100644 index 000000000..71af6637c --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/MemoryTextBody.java @@ -0,0 +1,118 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.io.IOUtils;
+//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 org.apache.james.mime4j.util.TempPath;
+import org.apache.james.mime4j.util.TempStorage;
+
+
+/**
+ * Text body backed by a {@link org.apache.james.mime4j.util.TempFile}.
+ *
+ *
+ * @version $Id: TempFileTextBody.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $
+ */
+class MemoryTextBody extends AbstractBody implements TextBody {
+ private static Log log = LogFactory.getLog(MemoryTextBody.class);
+
+ private String mimeCharset = null;
+ private byte[] tempFile = null;
+
+ public MemoryTextBody(InputStream is) throws IOException {
+ this(is, null);
+ }
+
+ public MemoryTextBody(InputStream is, String mimeCharset)
+ throws IOException {
+
+ this.mimeCharset = mimeCharset;
+
+ TempPath tempPath = TempStorage.getInstance().getRootTempPath();
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IOUtils.copy(is, out);
+ out.close();
+ tempFile = out.toByteArray();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.TextBody#getReader()
+ */
+ public Reader getReader() throws UnsupportedEncodingException, IOException {
+ String javaCharset = null;
+ if (mimeCharset != null) {
+ javaCharset = CharsetUtil.toJavaCharset(mimeCharset);
+ }
+
+ if (javaCharset == null) {
+ javaCharset = "ISO-8859-1";
+
+ if (log.isWarnEnabled()) {
+ if (mimeCharset == null) {
+ log.warn("No MIME charset specified. Using " + javaCharset
+ + " instead.");
+ } else {
+ log.warn("MIME charset '" + mimeCharset + "' has no "
+ + "corresponding Java charset. Using " + javaCharset
+ + " instead.");
+ }
+ }
+ }
+ /*
+ if (log.isWarnEnabled()) {
+ if (mimeCharset == null) {
+ log.warn("No MIME charset specified. Using the "
+ + "platform's default charset.");
+ } else {
+ log.warn("MIME charset '" + mimeCharset + "' has no "
+ + "corresponding Java charset. Using the "
+ + "platform's default charset.");
+ }
+ }
+
+ return new InputStreamReader(tempFile.getInputStream());
+ }*/
+
+ return new InputStreamReader(new ByteArrayInputStream(tempFile), javaCharset);
+ }
+
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ IOUtils.copy(new ByteArrayInputStream(tempFile), out);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/Message.java b/emailcommon/src/org/apache/james/mime4j/message/Message.java new file mode 100644 index 000000000..514307185 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/Message.java @@ -0,0 +1,257 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Stack;
+
+import org.apache.james.mime4j.BodyDescriptor;
+import org.apache.james.mime4j.ContentHandler;
+import org.apache.james.mime4j.MimeStreamParser;
+import org.apache.james.mime4j.decoder.Base64InputStream;
+import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
+import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.field.UnstructuredField;
+
+
+/**
+ * Represents a MIME message. The following code parses a stream into a
+ * <code>Message</code> object.
+ *
+ * <pre>
+ * Message msg = new Message(new BufferedInputStream(
+ * new FileInputStream("mime.msg")));
+ * </pre>
+ *
+ *
+ *
+ * @version $Id: Message.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public class Message extends Entity implements Body {
+
+ /**
+ * Creates a new empty <code>Message</code>.
+ */
+ public Message() {
+ }
+
+ /**
+ * Parses the specified MIME message stream into a <code>Message</code>
+ * instance.
+ *
+ * @param is the stream to parse.
+ * @throws IOException on I/O errors.
+ */
+ public Message(InputStream is) throws IOException {
+ MimeStreamParser parser = new MimeStreamParser();
+ parser.setContentHandler(new MessageBuilder());
+ parser.parse(is);
+ }
+
+
+ /**
+ * Gets the <code>Subject</code> field.
+ *
+ * @return the <code>Subject</code> field or <code>null</code> if it
+ * doesn't exist.
+ */
+ public UnstructuredField getSubject() {
+ return (UnstructuredField) getHeader().getField(Field.SUBJECT);
+ }
+
+ /**
+ *
+ * @see org.apache.james.mime4j.message.Entity#writeTo(java.io.OutputStream)
+ */
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
+ getHeader().writeTo(out);
+
+ Body body = getBody();
+ if (body instanceof Multipart) {
+ Multipart mp = (Multipart) body;
+ mp.writeTo(out);
+ } else {
+ body.writeTo(out);
+ }
+ }
+
+
+ private class MessageBuilder implements ContentHandler {
+ private Stack<Object> stack = new Stack<Object>();
+
+ public MessageBuilder() {
+ }
+
+ private void expect(Class c) {
+ if (!c.isInstance(stack.peek())) {
+ throw new IllegalStateException("Internal stack error: "
+ + "Expected '" + c.getName() + "' found '"
+ + stack.peek().getClass().getName() + "'");
+ }
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startMessage()
+ */
+ public void startMessage() {
+ if (stack.isEmpty()) {
+ stack.push(Message.this);
+ } else {
+ expect(Entity.class);
+ Message m = new Message();
+ ((Entity) stack.peek()).setBody(m);
+ stack.push(m);
+ }
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endMessage()
+ */
+ public void endMessage() {
+ expect(Message.class);
+ stack.pop();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startHeader()
+ */
+ public void startHeader() {
+ stack.push(new Header());
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#field(java.lang.String)
+ */
+ public void field(String fieldData) {
+ expect(Header.class);
+ ((Header) stack.peek()).addField(Field.parse(fieldData));
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endHeader()
+ */
+ public void endHeader() {
+ expect(Header.class);
+ Header h = (Header) stack.pop();
+ expect(Entity.class);
+ ((Entity) stack.peek()).setHeader(h);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startMultipart(org.apache.james.mime4j.BodyDescriptor)
+ */
+ public void startMultipart(BodyDescriptor bd) {
+ expect(Entity.class);
+
+ Entity e = (Entity) stack.peek();
+ Multipart multiPart = new Multipart();
+ e.setBody(multiPart);
+ stack.push(multiPart);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream)
+ */
+ public void body(BodyDescriptor bd, InputStream is) throws IOException {
+ expect(Entity.class);
+
+ String enc = bd.getTransferEncoding();
+ if ("base64".equals(enc)) {
+ is = new Base64InputStream(is);
+ } else if ("quoted-printable".equals(enc)) {
+ is = new QuotedPrintableInputStream(is);
+ }
+
+ Body body = null;
+ if (bd.getMimeType().startsWith("text/")) {
+ body = new MemoryTextBody(is, bd.getCharset());
+ } else {
+ body = new MemoryBinaryBody(is);
+ }
+
+ ((Entity) stack.peek()).setBody(body);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endMultipart()
+ */
+ public void endMultipart() {
+ stack.pop();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#startBodyPart()
+ */
+ public void startBodyPart() {
+ expect(Multipart.class);
+
+ BodyPart bodyPart = new BodyPart();
+ ((Multipart) stack.peek()).addBodyPart(bodyPart);
+ stack.push(bodyPart);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#endBodyPart()
+ */
+ public void endBodyPart() {
+ expect(BodyPart.class);
+ stack.pop();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#epilogue(java.io.InputStream)
+ */
+ public void epilogue(InputStream is) throws IOException {
+ expect(Multipart.class);
+ StringBuffer sb = new StringBuffer();
+ int b;
+ while ((b = is.read()) != -1) {
+ sb.append((char) b);
+ }
+ ((Multipart) stack.peek()).setEpilogue(sb.toString());
+ }
+
+ /**
+ * @see org.apache.james.mime4j.ContentHandler#preamble(java.io.InputStream)
+ */
+ public void preamble(InputStream is) throws IOException {
+ expect(Multipart.class);
+ StringBuffer sb = new StringBuffer();
+ int b;
+ while ((b = is.read()) != -1) {
+ sb.append((char) b);
+ }
+ ((Multipart) stack.peek()).setPreamble(sb.toString());
+ }
+
+ /**
+ * TODO: Implement me
+ *
+ * @see org.apache.james.mime4j.ContentHandler#raw(java.io.InputStream)
+ */
+ public void raw(InputStream is) throws IOException {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/Multipart.java b/emailcommon/src/org/apache/james/mime4j/message/Multipart.java new file mode 100644 index 000000000..d83400097 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/Multipart.java @@ -0,0 +1,203 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Represents a MIME multipart body (see RFC 2045).A multipart body has a
+ * ordered list of body parts. The multipart body also has a preamble and
+ * epilogue. The preamble consists of whatever characters appear before the
+ * first body part while the epilogue consists of whatever characters come
+ * after the last body part.
+ *
+ *
+ * @version $Id: Multipart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public class Multipart implements Body {
+ private String preamble = "";
+ private String epilogue = "";
+ private List<BodyPart> bodyParts = new LinkedList<BodyPart>();
+ private Entity parent = null;
+ private String subType = "alternative";
+
+ /**
+ * Creates a new empty <code>Multipart</code> instance.
+ */
+ public Multipart() {
+ }
+
+ /**
+ * Gets the multipart sub-type. E.g. <code>alternative</code> (the default)
+ * or <code>parallel</code>. See RFC 2045 for common sub-types and their
+ * meaning.
+ *
+ * @return the multipart sub-type.
+ */
+ public String getSubType() {
+ return subType;
+ }
+
+ /**
+ * Sets the multipart sub-type. E.g. <code>alternative</code>
+ * or <code>parallel</code>. See RFC 2045 for common sub-types and their
+ * meaning.
+ *
+ * @param subType the sub-type.
+ */
+ public void setSubType(String subType) {
+ this.subType = subType;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ for (Iterator<BodyPart> it = bodyParts.iterator(); it.hasNext();) {
+ it.next().setParent(parent);
+ }
+ }
+
+ /**
+ * Gets the epilogue.
+ *
+ * @return the epilogue.
+ */
+ public String getEpilogue() {
+ return epilogue;
+ }
+
+ /**
+ * Sets the epilogue.
+ *
+ * @param epilogue the epilogue.
+ */
+ public void setEpilogue(String epilogue) {
+ this.epilogue = epilogue;
+ }
+
+ /**
+ * Gets the list of body parts. The list is immutable.
+ *
+ * @return the list of <code>BodyPart</code> objects.
+ */
+ public List<BodyPart> getBodyParts() {
+ return Collections.unmodifiableList(bodyParts);
+ }
+
+ /**
+ * Sets the list of body parts.
+ *
+ * @param bodyParts the new list of <code>BodyPart</code> objects.
+ */
+ public void setBodyParts(List<BodyPart> bodyParts) {
+ this.bodyParts = bodyParts;
+ for (Iterator<BodyPart> it = bodyParts.iterator(); it.hasNext();) {
+ it.next().setParent(parent);
+ }
+ }
+
+ /**
+ * Adds a body part to the end of the list of body parts.
+ *
+ * @param bodyPart the body part.
+ */
+ public void addBodyPart(BodyPart bodyPart) {
+ bodyParts.add(bodyPart);
+ bodyPart.setParent(parent);
+ }
+
+ /**
+ * Gets the preamble.
+ *
+ * @return the preamble.
+ */
+ public String getPreamble() {
+ return preamble;
+ }
+
+ /**
+ * Sets the preamble.
+ *
+ * @param preamble the preamble.
+ */
+ public void setPreamble(String preamble) {
+ this.preamble = preamble;
+ }
+
+ /**
+ *
+ * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ String boundary = getBoundary();
+ List<BodyPart> bodyParts = getBodyParts();
+
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CharsetUtil.getCharset(getCharset())),8192);
+
+ writer.write(getPreamble() + "\r\n");
+
+ for (int i = 0; i < bodyParts.size(); i++) {
+ writer.write(boundary + "\r\n");
+ bodyParts.get(i).writeTo(out);
+ }
+
+ writer.write(getEpilogue() + "\r\n");
+ writer.write(boundary + "--" + "\r\n");
+
+ }
+
+ /**
+ * Return the boundory of the parent Entity
+ *
+ * @return boundery
+ */
+ private String getBoundary() {
+ Entity e = getParent();
+ ContentTypeField cField = (ContentTypeField) e.getHeader().getField(
+ Field.CONTENT_TYPE);
+ return cField.getBoundary();
+ }
+
+ private String getCharset() {
+ Entity e = getParent();
+ String charString = ((ContentTypeField) e.getHeader().getField(Field.CONTENT_TYPE)).getCharset();
+ return charString;
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/TempFileBinaryBody.java b/emailcommon/src/org/apache/james/mime4j/message/TempFileBinaryBody.java new file mode 100644 index 000000000..9db1482f4 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/TempFileBinaryBody.java @@ -0,0 +1,91 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+//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.TempFile;
+import org.apache.james.mime4j.util.TempPath;
+import org.apache.james.mime4j.util.TempStorage;
+
+
+/**
+ * Binary body backed by a {@link org.apache.james.mime4j.util.TempFile}.
+ *
+ *
+ * @version $Id: TempFileBinaryBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+class TempFileBinaryBody extends AbstractBody implements BinaryBody {
+ private static Log log = LogFactory.getLog(TempFileBinaryBody.class);
+
+ private Entity parent = null;
+ private TempFile tempFile = null;
+
+ /**
+ * Use the given InputStream to build the TemporyFileBinaryBody
+ *
+ * @param is the InputStream to use as source
+ * @throws IOException
+ */
+ public TempFileBinaryBody(InputStream is) throws IOException {
+
+ TempPath tempPath = TempStorage.getInstance().getRootTempPath();
+ tempFile = tempPath.createTempFile("attachment", ".bin");
+
+ OutputStream out = tempFile.getOutputStream();
+ IOUtils.copy(is, out);
+ out.close();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.AbstractBody#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.AbstractBody#setParent(org.apache.james.mime4j.message.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.BinaryBody#getInputStream()
+ */
+ public InputStream getInputStream() throws IOException {
+ return tempFile.getInputStream();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ IOUtils.copy(getInputStream(),out);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/TempFileTextBody.java b/emailcommon/src/org/apache/james/mime4j/message/TempFileTextBody.java new file mode 100644 index 000000000..b74e15d24 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/TempFileTextBody.java @@ -0,0 +1,117 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.io.IOUtils;
+//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 org.apache.james.mime4j.util.TempFile;
+import org.apache.james.mime4j.util.TempPath;
+import org.apache.james.mime4j.util.TempStorage;
+
+
+/**
+ * Text body backed by a {@link org.apache.james.mime4j.util.TempFile}.
+ *
+ *
+ * @version $Id: TempFileTextBody.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $
+ */
+class TempFileTextBody extends AbstractBody implements TextBody {
+ private static Log log = LogFactory.getLog(TempFileTextBody.class);
+
+ private String mimeCharset = null;
+ private TempFile tempFile = null;
+
+ public TempFileTextBody(InputStream is) throws IOException {
+ this(is, null);
+ }
+
+ public TempFileTextBody(InputStream is, String mimeCharset)
+ throws IOException {
+
+ this.mimeCharset = mimeCharset;
+
+ TempPath tempPath = TempStorage.getInstance().getRootTempPath();
+ tempFile = tempPath.createTempFile("attachment", ".txt");
+
+ OutputStream out = tempFile.getOutputStream();
+ IOUtils.copy(is, out);
+ out.close();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.message.TextBody#getReader()
+ */
+ public Reader getReader() throws UnsupportedEncodingException, IOException {
+ String javaCharset = null;
+ if (mimeCharset != null) {
+ javaCharset = CharsetUtil.toJavaCharset(mimeCharset);
+ }
+
+ if (javaCharset == null) {
+ javaCharset = "ISO-8859-1";
+
+ if (log.isWarnEnabled()) {
+ if (mimeCharset == null) {
+ log.warn("No MIME charset specified. Using " + javaCharset
+ + " instead.");
+ } else {
+ log.warn("MIME charset '" + mimeCharset + "' has no "
+ + "corresponding Java charset. Using " + javaCharset
+ + " instead.");
+ }
+ }
+ }
+ /*
+ if (log.isWarnEnabled()) {
+ if (mimeCharset == null) {
+ log.warn("No MIME charset specified. Using the "
+ + "platform's default charset.");
+ } else {
+ log.warn("MIME charset '" + mimeCharset + "' has no "
+ + "corresponding Java charset. Using the "
+ + "platform's default charset.");
+ }
+ }
+
+ return new InputStreamReader(tempFile.getInputStream());
+ }*/
+
+ return new InputStreamReader(tempFile.getInputStream(), javaCharset);
+ }
+
+
+ /**
+ * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ IOUtils.copy(tempFile.getInputStream(), out);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/message/TextBody.java b/emailcommon/src/org/apache/james/mime4j/message/TextBody.java new file mode 100644 index 000000000..4fe714466 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/message/TextBody.java @@ -0,0 +1,42 @@ +/****************************************************************
+ * 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.message;
+
+import java.io.IOException;
+import java.io.Reader;
+
+
+/**
+ * Encapsulates the contents of a <code>text/*</code> entity body.
+ *
+ *
+ * @version $Id: TextBody.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public interface TextBody extends Body {
+
+ /**
+ * Gets a <code>Reader</code> which may be used to read out the contents
+ * of this body.
+ *
+ * @return the <code>Reader</code>.
+ * @throws IOException on I/O errors.
+ */
+ Reader getReader() throws IOException;
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/CharsetUtil.java b/emailcommon/src/org/apache/james/mime4j/util/CharsetUtil.java new file mode 100644 index 000000000..0fc267d3e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/CharsetUtil.java @@ -0,0 +1,1246 @@ +/****************************************************************
+ * 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.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());
+ } catch (UnsupportedOperationException e) {
+ } catch (UnsupportedEncodingException e) {
+ }
+ try {
+ "dummy".getBytes(JAVA_CHARSETS[i].canonical);
+ encodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase());
+ } 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(), c);
+ if (c.mime != null) {
+ charsetMap.put(c.mime.toLowerCase(), c);
+ }
+ if (c.aliases != null) {
+ for (int j = 0; j < c.aliases.length; j++) {
+ charsetMap.put(c.aliases[j].toLowerCase(), 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());
+ }
+
+ /**
+ * 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());
+ }
+
+ /**
+ * 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());
+ 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());
+ 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());
+ }*/
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/PartialInputStream.java b/emailcommon/src/org/apache/james/mime4j/util/PartialInputStream.java new file mode 100644 index 000000000..a5ac0596d --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/PartialInputStream.java @@ -0,0 +1,63 @@ +/****************************************************************
+ * 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.InputStream;
+import java.io.IOException;
+
+public class PartialInputStream extends PositionInputStream {
+ private final long limit;
+
+ public PartialInputStream(InputStream inputStream, long offset, long length) throws IOException {
+ super(inputStream);
+ inputStream.skip(offset);
+ this.limit = offset + length;
+ }
+
+ public int available() throws IOException {
+ return Math.min(super.available(), getBytesLeft());
+ }
+
+ public int read() throws IOException {
+ if (limit > position)
+ return super.read();
+ else
+ return -1;
+ }
+
+ public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ len = Math.min(len, getBytesLeft());
+ return super.read(b, off, len); //To change body of overridden methods use File | Settings | File Templates.
+ }
+
+ public long skip(long n) throws IOException {
+ n = Math.min(n, getBytesLeft());
+ return super.skip(n); //To change body of overridden methods use File | Settings | File Templates.
+ }
+
+ private int getBytesLeft() {
+ return (int)Math.min(Integer.MAX_VALUE, limit - position);
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/PositionInputStream.java b/emailcommon/src/org/apache/james/mime4j/util/PositionInputStream.java new file mode 100644 index 000000000..9fcd21d0c --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/PositionInputStream.java @@ -0,0 +1,87 @@ +/****************************************************************
+ * 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.InputStream;
+import java.io.IOException;
+
+public class PositionInputStream extends InputStream {
+
+ private final InputStream inputStream;
+ protected long position = 0;
+ private long markedPosition = 0;
+
+ public PositionInputStream(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ public long getPosition() {
+ return position;
+ }
+
+ public int available() throws IOException {
+ return inputStream.available();
+ }
+
+ public int read() throws IOException {
+ int b = inputStream.read();
+ if (b != -1)
+ position++;
+ return b;
+ }
+
+ public void close() throws IOException {
+ inputStream.close();
+ }
+
+ public void reset() throws IOException {
+ inputStream.reset();
+ position = markedPosition;
+ }
+
+ public boolean markSupported() {
+ return inputStream.markSupported();
+ }
+
+ public void mark(int readlimit) {
+ inputStream.mark(readlimit);
+ markedPosition = position;
+ }
+
+ public long skip(long n) throws IOException {
+ final long c = inputStream.skip(n);
+ position += c;
+ return c;
+ }
+
+ public int read(byte b[]) throws IOException {
+ final int c = inputStream.read(b);
+ position += c;
+ return c;
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ final int c = inputStream.read(b, off, len);
+ position += c;
+ return c;
+ }
+
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/SimpleTempStorage.java b/emailcommon/src/org/apache/james/mime4j/util/SimpleTempStorage.java new file mode 100644 index 000000000..930e4db02 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/SimpleTempStorage.java @@ -0,0 +1,238 @@ +/****************************************************************
+ * 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.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Random;
+
+//BEGIN android-changed: Stubbing out logging
+import org.apache.james.mime4j.Log;
+import org.apache.james.mime4j.LogFactory;
+//END android-changed
+
+/**
+ *
+ * @version $Id: SimpleTempStorage.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+public class SimpleTempStorage extends TempStorage {
+ private static Log log = LogFactory.getLog(SimpleTempStorage.class);
+
+ private TempPath rootPath = null;
+ private Random random = new Random();
+
+ /**
+ * Creates a new <code>SimpleTempStorageManager</code> instance.
+ */
+ public SimpleTempStorage() {
+ rootPath = new SimpleTempPath(System.getProperty("java.io.tmpdir"));
+ }
+
+ private TempPath createTempPath(TempPath parent, String prefix)
+ throws IOException {
+
+ if (prefix == null) {
+ prefix = "";
+ }
+
+ File p = null;
+ int count = 1000;
+ do {
+ long n = Math.abs(random.nextLong());
+ p = new File(parent.getAbsolutePath(), prefix + n);
+ count--;
+ } while (p.exists() && count > 0);
+
+ if (p.exists() || !p.mkdirs()) {
+ log.error("Unable to mkdirs on " + p.getAbsolutePath());
+ throw new IOException("Creating dir '"
+ + p.getAbsolutePath() + "' failed.");
+ }
+
+ return new SimpleTempPath(p);
+ }
+
+ private TempFile createTempFile(TempPath parent, String prefix,
+ String suffix) throws IOException {
+
+ if (prefix == null) {
+ prefix = "";
+ }
+ if (suffix == null) {
+ suffix = ".tmp";
+ }
+
+ File f = null;
+
+ int count = 1000;
+ synchronized (this) {
+ do {
+ long n = Math.abs(random.nextLong());
+ f = new File(parent.getAbsolutePath(), prefix + n + suffix);
+ count--;
+ } while (f.exists() && count > 0);
+
+ if (f.exists()) {
+ throw new IOException("Creating temp file failed: "
+ + "Unable to find unique file name");
+ }
+
+ try {
+ f.createNewFile();
+ } catch (IOException e) {
+ throw new IOException("Creating dir '"
+ + f.getAbsolutePath() + "' failed.");
+ }
+ }
+
+ return new SimpleTempFile(f);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempStorage#getRootTempPath()
+ */
+ public TempPath getRootTempPath() {
+ return rootPath;
+ }
+
+ private class SimpleTempPath implements TempPath {
+ private File path = null;
+
+ private SimpleTempPath(String path) {
+ this.path = new File(path);
+ }
+
+ private SimpleTempPath(File path) {
+ this.path = path;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#createTempFile()
+ */
+ public TempFile createTempFile() throws IOException {
+ return SimpleTempStorage.this.createTempFile(this, null, null);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#createTempFile(java.lang.String, java.lang.String)
+ */
+ public TempFile createTempFile(String prefix, String suffix)
+ throws IOException {
+
+ return SimpleTempStorage.this.createTempFile(this, prefix, suffix);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#createTempFile(java.lang.String, java.lang.String, boolean)
+ */
+ public TempFile createTempFile(String prefix, String suffix,
+ boolean allowInMemory)
+ throws IOException {
+
+ return SimpleTempStorage.this.createTempFile(this, prefix, suffix);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#getAbsolutePath()
+ */
+ public String getAbsolutePath() {
+ return path.getAbsolutePath();
+ }
+
+ /**
+ * Do nothing
+ */
+ public void delete() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#createTempPath()
+ */
+ public TempPath createTempPath() throws IOException {
+ return SimpleTempStorage.this.createTempPath(this, null);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempPath#createTempPath(java.lang.String)
+ */
+ public TempPath createTempPath(String prefix) throws IOException {
+ return SimpleTempStorage.this.createTempPath(this, prefix);
+ }
+
+ }
+
+ private class SimpleTempFile implements TempFile {
+ private File file = null;
+
+ private SimpleTempFile(File file) {
+ this.file = file;
+ this.file.deleteOnExit();
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempFile#getInputStream()
+ */
+ public InputStream getInputStream() throws IOException {
+ return new BufferedInputStream(new FileInputStream(file));
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempFile#getOutputStream()
+ */
+ public OutputStream getOutputStream() throws IOException {
+ return new BufferedOutputStream(new FileOutputStream(file));
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempFile#getAbsolutePath()
+ */
+ public String getAbsolutePath() {
+ return file.getAbsolutePath();
+ }
+
+ /**
+ * Do nothing
+ */
+ public void delete() {
+ // Not implementated
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempFile#isInMemory()
+ */
+ public boolean isInMemory() {
+ return false;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.util.TempFile#length()
+ */
+ public long length() {
+ return file.length();
+ }
+
+ }
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/TempFile.java b/emailcommon/src/org/apache/james/mime4j/util/TempFile.java new file mode 100644 index 000000000..f67e1e93e --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/TempFile.java @@ -0,0 +1,84 @@ +/****************************************************************
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @version $Id: TempFile.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
+ */
+public interface TempFile {
+ /**
+ * Gets an <code>InputStream</code> to read bytes from this temporary file.
+ * NOTE: The stream should NOT be wrapped in
+ * <code>BufferedInputStream</code> by the caller. If the implementing
+ * <code>TempFile</code> creates a <code>FileInputStream</code> or any
+ * other stream which would benefit from being buffered it's the
+ * <code>TempFile</code>'s responsibility to wrap it.
+ *
+ * @return the stream.
+ * @throws IOException
+ */
+ InputStream getInputStream() throws IOException;
+
+ /**
+ * Gets an <code>OutputStream</code> to write bytes to this temporary file.
+ * NOTE: The stream should NOT be wrapped in
+ * <code>BufferedOutputStream</code> by the caller. If the implementing
+ * <code>TempFile</code> creates a <code>FileOutputStream</code> or any
+ * other stream which would benefit from being buffered it's the
+ * <code>TempFile</code>'s responsibility to wrap it.
+ *
+ * @return the stream.
+ * @throws IOException
+ */
+ OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Returns the absolute path including file name of this
+ * <code>TempFile</code>. The path may be <code>null</code> if this is
+ * an in-memory file.
+ *
+ * @return the absolute path.
+ */
+ String getAbsolutePath();
+
+ /**
+ * Deletes this file as soon as possible.
+ */
+ void delete();
+
+ /**
+ * Determines if this is an in-memory file.
+ *
+ * @return <code>true</code> if this file is currently in memory,
+ * <code>false</code> otherwise.
+ */
+ boolean isInMemory();
+
+ /**
+ * Gets the length of this temporary file.
+ *
+ * @return the length.
+ */
+ long length();
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/TempPath.java b/emailcommon/src/org/apache/james/mime4j/util/TempPath.java new file mode 100644 index 000000000..3b55aa6db --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/TempPath.java @@ -0,0 +1,73 @@ +/****************************************************************
+ * 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.IOException;
+
+/**
+ *
+ * @version $Id: TempPath.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+public interface TempPath {
+ TempPath createTempPath() throws IOException;
+ TempPath createTempPath(String prefix) throws IOException;
+
+ /**
+ * Creates a new temporary file. Wheter it will be be created in memory
+ * or on disk is up to to the implementation.
+ * The prefix will be empty and the suffix will be
+ * <code>.tmp</code> if created on disk.
+ *
+ * @return the temporary file.
+ */
+ TempFile createTempFile() throws IOException;
+
+ /**
+ * Creates a new temporary file. Wheter it will be be created in memory
+ * or on disk is up to to the implementation.
+ * The prefix and suffix can be set by the user.
+ *
+ * @param prefix the prefix to use. <code>null</code> gives no prefix.
+ * @param suffix the suffix to use. <code>null</code> gives
+ * <code>.tmp</code>.
+ * @return the temporary file.
+ */
+ TempFile createTempFile(String prefix, String suffix) throws IOException;
+
+ /**
+ * Creates a new temporary file. Wheter it will be be created in memory
+ * or on disk can be specified using the <code>allowInMemory</code>
+ * parameter. If the implementation doesn't support in-memory files
+ * the new file will be created on disk.
+ * The prefix and suffix can be set by the user.
+ *
+ * @param prefix the prefix to use. <code>null</code> gives no prefix.
+ * @param suffix the suffix to use. <code>null</code> gives
+ * <code>.tmp</code>.
+ * @param allowInMemory if <code>true</code> the file MIGHT be created in
+ * memory if supported by the implentation. If <code>false</code> the
+ * file MUST be created on disk.
+ * @return the temporary file.
+ */
+ TempFile createTempFile(String prefix, String suffix,
+ boolean allowInMemory) throws IOException;
+ String getAbsolutePath();
+ void delete();
+}
diff --git a/emailcommon/src/org/apache/james/mime4j/util/TempStorage.java b/emailcommon/src/org/apache/james/mime4j/util/TempStorage.java new file mode 100644 index 000000000..4d3be4746 --- /dev/null +++ b/emailcommon/src/org/apache/james/mime4j/util/TempStorage.java @@ -0,0 +1,72 @@ +/****************************************************************
+ * 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;
+
+//BEGIN android-changed: Stubbing out logging
+import org.apache.james.mime4j.Log;
+import org.apache.james.mime4j.LogFactory;
+//END android-changed
+
+/**
+ *
+ * @version $Id: TempStorage.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ */
+public abstract class TempStorage {
+ private static Log log = LogFactory.getLog(TempStorage.class);
+ private static TempStorage inst = null;
+
+ static {
+
+ String clazz = System.getProperty("org.apache.james.mime4j.tempStorage");
+ try {
+
+ if (inst != null) {
+ inst = (TempStorage) Class.forName(clazz).newInstance();
+ }
+
+ } catch (Throwable t) {
+ log.warn("Unable to create or instantiate TempStorage class '"
+ + clazz + "' using SimpleTempStorage instead", t);
+ }
+
+ if (inst == null) {
+ inst = new SimpleTempStorage();
+ }
+ }
+
+ /**
+ * Gets the root temporary path which should be used to
+ * create new temporary paths or files.
+ *
+ * @return the root temporary path.
+ */
+ public abstract TempPath getRootTempPath();
+
+ public static TempStorage getInstance() {
+ return inst;
+ }
+
+ public static void setInstance(TempStorage inst) {
+ if (inst == null) {
+ throw new NullPointerException("inst");
+ }
+ TempStorage.inst = inst;
+ }
+}
diff --git a/proguard.flags b/proguard.flags index 198e4e665..4ead936ec 100644 --- a/proguard.flags +++ b/proguard.flags @@ -1,4 +1,5 @@ -# keep names that are used by reflection. +#Email-specific proguard flags that are not covered by UnifiedEmail go here + -keep class com.android.emailcommon.provider.Account -keepclasseswithmembers class * { diff --git a/res/layout/action_bar_spinner.xml b/res/layout/action_bar_spinner.xml index a3b1cf260..35b83198e 100644 --- a/res/layout/action_bar_spinner.xml +++ b/res/layout/action_bar_spinner.xml @@ -43,7 +43,7 @@ android:gravity="center_vertical"> <TextView android:id="@+id/spinner_line_1" - style="@style/AccountSpinnerAnchorTextPrimary" + style="@style/action_bar_spinner_primary_text" android:singleLine="true" android:ellipsize="end" android:includeFontPadding="false" @@ -51,7 +51,7 @@ android:layout_height="wrap_content" /> <TextView android:id="@+id/spinner_line_2" - style="@style/AccountSpinnerAnchorTextSecondary" + style="@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle" android:singleLine="true" android:ellipsize="end" android:includeFontPadding="false" diff --git a/res/layout/action_bar_spinner_dropdown.xml b/res/layout/action_bar_spinner_dropdown.xml index 41fd00c21..d39d1f164 100644 --- a/res/layout/action_bar_spinner_dropdown.xml +++ b/res/layout/action_bar_spinner_dropdown.xml @@ -20,9 +20,8 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" style="?android:attr/spinnerDropDownItemStyle" - android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="48dip" + android:layout_width="match_parent" android:gravity="center_vertical"> <RelativeLayout @@ -35,7 +34,7 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:ellipsize="end" - style="@style/AccountSpinnerDropdownTextPrimary" /> + style="@android:style/TextAppearance.Holo.Widget.ActionBar.Title"/> <TextView android:id="@+id/email_address" @@ -45,7 +44,7 @@ android:layout_below="@id/display_name" android:layout_alignWithParentIfMissing="true" android:layout_centerVertical="true" - style="@style/AccountSpinnerDropdownTextSecondary" /> + style="@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle"/> </RelativeLayout> <RelativeLayout diff --git a/res/layout/action_bar_spinner_dropdown_header.xml b/res/layout/action_bar_spinner_dropdown_header.xml index 93b0b2fae..2f4aad9d7 100644 --- a/res/layout/action_bar_spinner_dropdown_header.xml +++ b/res/layout/action_bar_spinner_dropdown_header.xml @@ -17,5 +17,4 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/display_name" android:ellipsize="end" - android:textColor="@color/label_list_heading_text_color" style="?android:attr/listSeparatorTextViewStyle" /> diff --git a/res/layout/mailbox_list_header.xml b/res/layout/mailbox_list_header.xml index b6bba17be..4bef0c5e6 100644 --- a/res/layout/mailbox_list_header.xml +++ b/res/layout/mailbox_list_header.xml @@ -18,6 +18,5 @@ android:id="@+id/display_name" android:layout_width="match_parent" android:ellipsize="end" - android:textColor="@color/label_list_heading_text_color" style="?android:attr/listSeparatorTextViewStyle" android:layout_marginLeft="@dimen/mailbox_list_padding_left" /> diff --git a/res/layout/quick_response_edit_dialog.xml b/res/layout/quick_response_edit_dialog.xml deleted file mode 100644 index cdb8fb79f..000000000 --- a/res/layout/quick_response_edit_dialog.xml +++ /dev/null @@ -1,32 +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. ---> - -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:focusable="true" - android:paddingLeft="4dip" - android:paddingTop="6dip" - android:paddingRight="4dip" - android:paddingBottom="6dip"> - - <EditText - android:id="@+id/quick_response_text" - android:layout_width="match_parent" - android:layout_height="wrap_content"/> - -</RelativeLayout>
\ No newline at end of file diff --git a/res/layout/waiting_for_sync_message.xml b/res/layout/waiting_for_sync_message.xml index 8d5281da0..a9d8aadf4 100644 --- a/res/layout/waiting_for_sync_message.xml +++ b/res/layout/waiting_for_sync_message.xml @@ -13,44 +13,41 @@ See the License for the specific language governing permissions and limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/waiting_for_sync_message" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@android:color/white" - android:id="@+id/waiting_for_sync_message"> - + android:padding="16dip" + > <RelativeLayout - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:id="@+id/wait_for_sync_wrapper" - android:layout_marginTop="16dip" - android:layout_marginLeft="16dip"> - + android:layout_gravity="center|top" + > <ProgressBar - android:indeterminate="true" + android:id="@+id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:id="@+id/progress_spinner"/> - + android:layout_centerVertical="true" + android:layout_marginRight="8dip" + /> <TextView - android:layout_width="wrap_content" + android:id="@+id/title" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/waitinf_for_sync_message_1" + android:layout_toRightOf="@+id/progress" android:textAppearance="?android:attr/textAppearanceMedium" - android:id="@+id/title" - android:layout_toRightOf="@id/progress_spinner" - android:layout_marginLeft="4dip" /> - + android:text="@string/waitinf_for_sync_message_1" + /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/waitinf_for_sync_message_2" + android:layout_toRightOf="@+id/progress" + android:layout_below="@+id/title" android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_below="@id/title" - android:layout_toRightOf="@id/progress_spinner" - android:layout_marginLeft="4dip" /> - + android:text="@string/waitinf_for_sync_message_2" + /> </RelativeLayout> - -</RelativeLayout> +</FrameLayout> diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index c3acf66d7..18e47e5f7 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Lees e-posaanhegsels"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Laat die program toe om jou e-pos se aanhegsels te lees."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Laat hierdie program toe om jou e-pos-aanhegsels te lees."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Kry toegang tot e-posverskafferdata"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Laat die program toe om toegang te kry tot jou e-posdatabasis, insluitend ontvangde boodskappe, gestuurde boodskappe, gebruikername en wagwoorde."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Gee hierdie program toegang tot jou e-posdatabasis, insluitend ontvangde boodskappe, gestuurde boodskappe, gebruikername en wagwoorde."</string> <string name="app_name" msgid="5815426892327290362">"E-pos"</string> <string name="compose_title" msgid="427986915662706899">"Skryf"</string> <string name="debug_title" msgid="5175710493691536719">"Ontfout"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Gedoen"</string> <string name="create_action" msgid="3062715563215392251">"Skep nuwe"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Vee uit"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Geen vinnige reaksies nie."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Geen vinnige antwoorde nie"</string> <string name="discard_action" msgid="6532206074859505968">"Gooi weg"</string> <string name="save_draft_action" msgid="6413714270991417223">"Stoor konsep"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Voer vinnige antwoord in"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> het geskryf:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Sluit aangehaalde teks in"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Sluit teks in"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Voeg ten minste een ontvanger by."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Jy moet ten minste een ontvanger byvoeg."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Sekere e-posadresse is ongeldig."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Lêer te groot om aan te heg."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Voer vinnige antwoord in"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Gestoor"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stop"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Aanhegsel gestoor as <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Kon nie aanhegsel stoor nie."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Een of meer aanhegsels in jou aangestuurde boodskap sal afgelaai word voor dit gestuur word."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Kon nie die aanhegsel stoor nie."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Let wel: Een of meer aanhegsels in jou aangestuurde boodskap sal afgelaai word voor dit gestuur word."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Boodskap"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Nooi uit"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Kon een of meer aanhegsels nie aanstuur nie"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Aanhegsel nie aangestuur nie"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> se aanmelding is onsuksesvol."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>-aanmelding het misluk"</string> <string name="login_failed_title" msgid="7624349996212476176">"Kan nie aanmeld nie"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Jy kan \'n Exchange ActiveSync-rekening in net \'n paar stappe opstel."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-posadres"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Wagwoord"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Stuur e-pos van hierdie rekening by verstek"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Stuur e-pos by verstek vanaf hierdie rekening."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Handmatige opstelling"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Voer asseblief \'n geldige e-posadres en wagwoord in."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplikaatrekening"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Kontroleer tans inkomende bedienerinstellings…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kontroleer tans uitgaande bedienerinstellings…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Rekening-opstelling"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Jou rekening is opgestel en die e-pos is op pad!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Jou rekening is nou opgestel en e-pos is op pad!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Gee hierdie rekening \'n naam (opsioneel)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Jou naam (staan op uitgaande boodskappe)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Hierdie veld kan nie leeg wees nie."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-bediener"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Poort"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Sekuriteitstipe"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Vereis aanmelding"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Vereis aanmelding."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Gebruikernaam"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Wagwoord"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Rekening-opstelling"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Elke 15 minute"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Elke 30 minute"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Elke uur"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Stuur e-pos van hierdie rekening by verstek"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Laat my weet wanneer e-pos aankom"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinkroniseer kontakte uit hierdie rekening"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinkroniseer kalender uit hierdie rekening"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinkroniseer e-pos uit hierdie rekening"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Stuur e-pos by verstek vanaf hierdie rekening."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Laat my weet wanneer ek e-pos kry."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinkroniseer kontakte uit hierdie rekening."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinkroniseer kalender vanaf hierdie rekening."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sinkroniseer e-pos vanaf hierdie rekening."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Laai aanhegsels outomaties af wanneer aan Wi-Fi gekoppel is"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Kon nie voltooi word nie"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dae om te sinkroniseer"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Een maand"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alle"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Gebruik rekening se verstek"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Gebruikernaam of wagwoord verkeerd."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Gebruikernaam of wagwoord is verkeerd"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Gebruikernaam of wagwoord verkeerd."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Gebruikernaam of wagwoord verkeerd."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Kan nie veilig aan bediener koppel nie."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Kan nie veilig aan bediener koppel nie."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"\'n Kliëntsertifikaat word vereis. Wil jy aan die bediener koppel met \'n kliëntsertifikaat?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Die sertifikaat is ongeldig of ontoeganklik."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Die bediener het gereageer met \'n foutboodskap. Kontroleer jou gebruikernaam en wagwoord, en herprobeer dan."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Kliëntsertifikaat word vereis. Koppel aan bediener met kliëntsertifikaat?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikaat is ongeldig of ontoeganklik."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Die bediener het met \'n fout gereageer; kontroleer jou gebruikernaam en wagwoord en probeer weer."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Kan nie aan bediener koppel nie."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Kan nie aan bediener koppel nie."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS vereis, maar nie deur bediener ondersteun nie."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"LET WEL: Deaktivering van die e-posprogram se magtiging om jou toestel te administreer, sal alle e-posrekeninge wat dit benodig, uitvee, asook hul e-posse, kontakte, kalendergebeure en ander data."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Sekuriteitsopdatering"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> vereis dat jy jou sekuriteitsinstellings opdateer."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Rekening \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kan nie gesinchroniseer word nie weens sekuriteitvereistes."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Rekening \"<xliff:g id="ACCOUNT">%s</xliff:g>\" vereis opdatering van sekuriteitsinstellings."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Rekening \"<xliff:g id="ACCOUNT">%s</xliff:g>\" het sy sekuriteitsinstellings verander; geen handeling deur die gebruiker is nodig nie."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Sekuriteitsopdatering vereis"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Sekuriteitsbeleide het verander"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Kan nie sekuriteitbeleid nakom nie"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Rekening \"<xliff:g id="ACCOUNT">%s</xliff:g>\" vereis opdatering van sekuriteitsinstellings."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Sekuriteitsopdatering vereis"</string> <string name="account_security_title" msgid="3511543138560418587">"Toestelsekuriteit"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Die bediener <xliff:g id="SERVER">%s</xliff:g> vereis dat jy dit toelaat om sekere sekuriteitskenmerke van jou Android-toestel afgeleë te beheer."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Redigeer details"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Jou skermslot se PIN of wagwoord het verval."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Wagwoord vir skermslot het verval"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Wagwoord vir skermslot verval"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Jy moet jou skermslot-PIN of -wagwoord binnekort verander, anders sal die data vir <xliff:g id="ACCOUNT">%s</xliff:g> uitgevee word. Wil jy dit nou verander?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Jy moet jou skermslot se PIN of wagwoord gou verander, anders gaan <xliff:g id="ACCOUNT">%s</xliff:g> se data uitgevee word. Wil jy dit nou verander?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Wagwoord vir skermslot het verval"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Die data vir <xliff:g id="ACCOUNT">%s</xliff:g> word uit jou toestel gevee. Jy kan dit teruglaai deur jou skermslot-PIN of -wagwoord te verander. Wil jy dit nou verander?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Die data vir <xliff:g id="ACCOUNT">%s</xliff:g> word van jou toestel afgevee. Jy kan dit teruglaai deur jou skermslot se PIN of wagwoord te verander. Wil jy dit nou verander?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Raak van ongestoorde veranderinge ontslae?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Kon nie aanmeld nie."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Die gebruikernaam of wagwoord vir <xliff:g id="ACCOUNT">%s</xliff:g> is verkeerd. Wil jy dit nou opdateer?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Die gebruikernaam of wagwoord vir <xliff:g id="ACCOUNT">%s</xliff:g> is verkeerd. Dateer hulle nou op?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Verstek rekening"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Stuur e-pos by verstek vanaf hierdie rekening"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Laai aanhegsels af"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Laai outomaties aanhegsels van onlangse boodskappe via Wi-Fi af"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-poskennisgewings"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sinkroniseerfrekwensie, kennisgewings, ens."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Stuur berig wanneer e-pos aankom"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Wys in statusbalk wanneer e-pos aankom"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Kontroleer inkassie elke"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Inkomende instellings"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Gebruikernaam, wagwoord en ander instellings vir inkomende bediener"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Uitgaande instellings"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Gebruikernaam, wagwoord en ander instellings vir uitgaandebediener-instellings"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Beleide toegepas"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Geen"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nie-ondersteunde beleide"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Geen"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Probeer sinkroniseer"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Raak hier om hierdie rekening te sinkroniseer"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Rekeningnaam"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Jou naam"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Handtekening"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Vinnige reaksies"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Redigeer teks wat jy gereeld invoeg wanneer jy e-pos skryf"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Redigeer teks wat jy gereeld invoeg wanneer jy e-posse skryf"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Las teks by die boodskappe wat jy stuur"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Kennisgewingsinstellings"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Datagebruik"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sekuriteitsbeleide"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Redigeer vinnige antwoord"</string> <string name="save_action" msgid="1988862706623227093">"Stoor"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinkroniseer kontakte"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sinkroniseer kontakte vir hierdie rekening"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinkroniseer kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinkroniseer kalendergebeurtenis uit hierdie rekening"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sinkroniseer kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sinkroniseer kalender vir hierdie rekening"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sinkroniseer e-pos"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sinkroniseer e-pos vir hierdie rekening"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibreer"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Wag vir resultate"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Sommige bedieners neem \'n lang tyd."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Vouers"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Weier gebruik van die toestel se kamera"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Vereis toestelwagwoord"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Beperk die hergebruik van onlangse wagwoorde"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Vereis dat wagwoorde verval"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Vereis dat \'n ledige toestel sy skerm sluit"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Beperk die aantal kalendergebeurtenisse wat gesinchroniseer word"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Beperk die aantal e-posse wat gesinchroniseer word"</string> - <string name="quick_1" msgid="3426057697353380951">"Dankie!"</string> - <string name="quick_2" msgid="4188036352885736617">"Klink vir my goed!"</string> - <string name="quick_3" msgid="8061819976353395585">"Ek sal dit later lees en jou antwoord."</string> - <string name="quick_4" msgid="3988974084396883051">"Kom ons skeduleer \'n vergadering om dit te bespreek."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Agtergrond-sinkronisasie vir hierdie rekening is gedeaktiveer tydens swerwing."</string> </resources> diff --git a/res/values-af/uploader.xml b/res/values-af/uploader.xml index 904581f4c..25ec5f0c2 100644 --- a/res/values-af/uploader.xml +++ b/res/values-af/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Versteek details"</string> <string name="menu_settings" msgid="5088116127086866634">"Instellings"</string> <string name="format_date_uploaded" msgid="803752037646090928">"%s opgelaai"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Rekening"</string> <string name="upload" msgid="2615541458361216022">"Laai op"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 96ab218bd..38b2ab4e9 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"የኢሜይል ዓባሪዎችን አንብብ"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"የኢሜይል አባሪዎችህን እንዲያነብ ለመተግበሪያ ይፈቅዳል።"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"ይህ መተግበሪያ የኢሜይል አባሪዎችህን እንዲያነብ ይፈቅዳል።"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"የኢሜይል አቅራቢ ውሂብ ድረስ።"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">" የኢሜይል የውሂብ ጎታህን፣ የደረሱ መልዕክቶች፣ የተላኩ መልዕክቶች፣ ተጠቃሚ ስሞች እና የይለፍ ቃሎችን ጨምሮ ለመድረስ ለመተግበሪያ ይፈቅዳል።"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"ይህ መተግበሪያ የኢሜይል የውሂብ ጎታህን፣ የደረሱ መልዕክቶች፣ የተላኩ መልዕክቶች፣ ተጠቃሚ ስሞች እና የይለፍ ቃሎችን ጨምሮ ለመድረስ ይፈቅዳል።"</string> <string name="app_name" msgid="5815426892327290362">"ኢሜይል"</string> <string name="compose_title" msgid="427986915662706899">"ፅሁፍ አዘጋጅ"</string> <string name="debug_title" msgid="5175710493691536719">"አርም"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"ተከናውኗል"</string> <string name="create_action" msgid="3062715563215392251">"አዲስ ፍጠር"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"ሰርዝ"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"ምንም ፈጣን ምላሾች የሉም።"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"ምንም ፈጣን ምላሾች የሉም"</string> <string name="discard_action" msgid="6532206074859505968">"አስወግድ"</string> <string name="save_draft_action" msgid="6413714270991417223">"ረቂቅ አስቀምጥ"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"ፈጣን ምላሽ አስገባ"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>ፃፈ፡"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"የተጠቀሰ ጽሁፍ አካትት"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"ፅሁፍ አካት"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"እባክህን ቢያንስ አንድ ተቀባይ አክል።"</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"ቢያንስ አንድ ተቀባይ ማከል አለብዎ።"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"አንዳንድ ኢሜይል አድራሻዎች ትክክል አይደሉም።"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"የፋይል መጠንለማያያዝ በጣም ትልቅ ነው።"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"ፈጣን ምላሽ አስገባ"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"ተቀምጧል"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"ቁም"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"አባሪ እንደ <xliff:g id="FILENAME">%s</xliff:g> ተቀምጧል።"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"ዓባሪውን ማስቀመጥ አልተቻለም።"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"በሚተላለፈው መልዕክትህ ውስጥ አንድ ወይም ተጨማሪ አባሪዎች ከመላኩ አስቀድሞ ይወርዳሉ።"</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"ዓባሪውን ማስቀመጥ አልተቻለም::"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"ማስታወሻ፡ በሚተላለፈው መልዕክትዎ ውስጥ አንድ ወይም ተጨማሪ አባሪዎች ከመላኩ አስቀድሞ ይወርዳሉ።"</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"መልዕክት"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"ጋብዝ"</string> <plurals name="message_view_show_attachments_action"> @@ -179,7 +179,7 @@ <string name="attachment_info_dialog_default_title" msgid="4995755709689009622">"የአባሪ መረጃ"</string> <string name="attachment_info_dialog_wifi_title" msgid="3174350153882915382">"የWi-Fi ተያያዥ ይጠበቃል"</string> <string name="attachment_info_wifi_settings" msgid="96432970927503597">"የWi-Fi ቅንብሮች"</string> - <string name="attachment_info_application_settings" msgid="4124655487276125596">"መተግበሪያ ቅንብሮች"</string> + <string name="attachment_info_application_settings" msgid="4124655487276125596">"መተግበሪያ ቅንጅቶች"</string> <string name="attachment_info_unknown" msgid="8342655396805943320">"አባሪ መክፈት አልተቻለም።"</string> <string name="attachment_info_malware" msgid="6576029010855055528">"እንዲህ ዓይነቱ ዓባሪ ተንኮል አዘል ሶፍትዌር ሊይዝ ስለሚችል ይህን ፋይል ማስቀመጥ ሆነ መክፈት አትችልም::"</string> <string name="attachment_info_policy" msgid="3560422300127587508">"በዚህ መለያ የደህንነት ቋሚ መመሪያዎች የተነሳ ይህ ዓባሪ ሊቀመጥ ሆነ ሊከፈት አይችልም::"</string> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"አንድ ወይም ከዛ በላይ ዓባሪዎችን ለማስተላለፍ አልተቻለም::"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"አባሪ አልተላለፈም"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> በመለያ መግባት አልተሳካም።"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> በመለያ መግባት ተሰናክሏል::"</string> <string name="login_failed_title" msgid="7624349996212476176">"በመለያ መግባት አልተቻለም፡፡"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"በጥቂት እርምጃዎች Exchange ActiveSync መለያ ማዘጋጀት ትችላለህ።"</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"ኢሜይል አድራሻ"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"የይለፍ ቃል፡"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"ከዚህ መለያ በነባሪ ኢሜይል ላክ"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"ከዚህ መለያ በነባሪኢሜይል ላክ"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"በእጅ አዘጋጅ"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"እባክህ ትክክለኛ ኢሜይል አድራሻ እና ይለፍ ቃል ፃፍ።"</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"ተመሳሳይ መለያ"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"የገቢ አገልጋይ ቅንብሮች በመመልከት ላይ...."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"የወጪ አገልጋይ ቅንብሮች በመመልከት ላይ...."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"መለያ አዘጋጅ"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"መለያህ ተዋቅሯል፣ ኢሜይልህም መንገድ ላይ ነው!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"መለያዎ ዝግጁ ነው፣ኢሜይልዎ መንገድ ላይ ነው!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"ለዚሀመለያ ስም ስጥ(አማራጭ)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"ስምዎ(በወጪ መልዕክቶች ላይ አሳይቷል)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"ይህ መስክ ባዶ መሆን አይችልም።"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"የSMTP አገልጋይ"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"ወደብ"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"የደህንነትአይነት"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"ከፍቶ መግባት ይፈልጋል"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"ግባ ይጠበቃል።"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"የተጠቃሚ ስም"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"የይለፍ ቃል"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"መለያ አዘጋጅ"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"በየ15 ደቂቃዎቹ"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"በየ30 ደቂቃዎቹ"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"በየሰዓቱ"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"ከዚህ መለያ በነባሪ ኢሜይል ላክ"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"ኢሜይል ሲደርስ አሳውቀኝ"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"ከዚህ መለያ ዕውቂያዎች አመሳስል"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"ከዚህ መለያ የቀን አቆጣጠር አመሳስል"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"ከዚህ መለያ ኢሜይል አመሳስል"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"ከዚህ መለያ በነባሪኢሜይል ላክ"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"ኢሜይል ሲደርስ አሳውቀኝ።"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"ከዚህ መለያ ዕውቂያዎች አሳምር"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"ከዚህ መለያ የቀን አቆጣጠር አሳምር።"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"ከዚህ መለያ ኢሜይል አሳምር።"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"ወደ Wi-Fi ስትገናኝ አባሪዎችን በራስ ሰር አውርድ"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"ማጠናቀቅ አልተቻለም"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"ቀኖች አሳምር"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"አንድ ወር"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"ሁሉም"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"የመለያ ነባሪ ተጠቀም"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"ተጠቃሚ ስም ወይም ይለፍ ቃል የተሳሳተ ነው።"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"የተጠቃሚው ስም ወይም ይለፍ ቃል የተሳሳተ ነው። "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"ተጠቃሚ ስም ወይም ይለፍ ቃል ተሳስቷል።"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"ተጠቃሚ ስም ወይም ይለፍ ቃል ተሳስቷል።"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"ወደ አገልጋዩ በሰላም ማገናኘት አልተቻለም።"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"ወደ አገልጋዩ በሰላም ማገናኘት አልተቻለም።"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"የተገልጋይ ሰርቲፊኬት ያስፈልጋል። በተገልጋይ ሰርቲፊኬት ወደ አገልጋይ መገናኘት ትፈልጋለህ?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"የዕውቅና ማረጋገጫው ልክ ያልሆነ ወይም ተደራሽ ያልሆነ ነው።"</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"አገልጋዩ ከስህተት ጋር መልሷል፤ የተጠቃሚ ስምህን እና የይለፍ ቃልህን ተመልከት እና እንደገና ሞክር።"</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"የደንበኛ የዕውቅና ማረጋገጫ ይጠበቃል። ከደንበኛ የዕውቅና ማረጋገጫ ጋር ወደ አገልጋይ ይገናኝ?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"የዕውቅና ማረጋገጫው ልክ ያልሆነ ወይም ተደራሽ ያልሆነ ነው::"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"አገልጋዩ ከክስተት ጋር መልሷል፤ እባክህ የተጠቃሚ ስምህን እና የይለፍ ቃልህን ተመልከት እና እንደገና ሞክር።"</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"ወደ አገልጋይ መገናኘት አይቻልም።"</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"ወደ አገልጋዩ ማገናኘት አይችልም።"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS ይጠየቃል ነገር ግን በአገልጋይ አይደገፍም።"</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ማስጠንቀቂያ፣ መሣሪያህን ለማስተዳደር የኢሜይል ትግበራዎችን ኃላፊነት ማቦዘን የሚጠይቁትን ሁሉ የኢሜይል መለያዎች ከኢሜይል፣ ዕውቂያዎች፣ ቀን መቁጠሪያ ክስተቶች፣ እና ሌላ ውሂብ ጋር አብሮ ይሰርዛል።"</string> <string name="account_security_dialog_title" msgid="430041952584831904">"ደህንነት ዝማኔ"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> የደህንነት ቅንጅቶችህን ማዘመን ይጠይቅሃል።"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"በደህንነት ጥያቄዎች ምክንያት መለያ «<xliff:g id="ACCOUNT">%s</xliff:g>» ሊመሳሰል አልቻለም።"</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"መለያ \"<xliff:g id="ACCOUNT">%s</xliff:g>\" የደህንነት ቅንብሮችን ማዘመን ይጠይቃል።"</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"መለያ<xliff:g id="ACCOUNT">%s</xliff:g> የደህንነት ቅንጅቶቹን ለውጧል፤ምንም የተጠቃሚ እርምጃ አይጠበቅም፡፡"</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"የደህንነት አዘምን ይጠበቃል"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"የደህንነት ቋሚ መመሪያዎች ተለውጠዎል"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"የደህንነት ቋሚ መመሪያዎች ሊሟሉ አይችሉም"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"መለያ \"<xliff:g id="ACCOUNT">%s</xliff:g> \" የደህንነት ቅንብሮችን ማዘመን ይጠይቃል።"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"የደህንነት አዘምን ይጠበቃል"</string> <string name="account_security_title" msgid="3511543138560418587">"የመሣሪያ ደህንነት"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"<xliff:g id="SERVER">%s</xliff:g> አገልጋይየAndroid መሣሪያዎ አንዳንድገፅታዎች በርቀት ለመቆጣጠር እንዲፈቅዱ ይጠይቃል። ይህን መለያ ጨርሰው ለማቀናበር ይፈልጋሉ?"</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"ዝርዝሮችን አርትዕ"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"የእርስዎ የማያመቆለፊያ PIN ወይም ይለፍ ቃል ጊዜው አልፏል።"</string> <string name="password_expired_content_title" msgid="4349518706602252979">"የማያ ቆልፍ ይለፍ ቃል ጊዜው አልፏል"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"የማያ ቆልፍ ይለፍ ቃል ጊዜው እያለፈነው"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"በቅርቡ የማሳያህ ቆልፍ ፒን ወይም የይለፍ ቃል መለወጥ ያስፈልግሃል፤ አለበለዚያ የ<xliff:g id="ACCOUNT">%s</xliff:g> ውሂብ ይሰረዛል። አሁን እንዲለወጥ ትፈልጋለህ?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"የማያ መቆለፊያዎንPIN ወይም ይለፍቃል በቅርቡ መለወጥ አለብዎ፣ ወይም የ <xliff:g id="ACCOUNT">%s</xliff:g> ውሂብ ይሰረዛል። አሁን ይለወጥ?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"የማያ ቆልፍ ይለፍ ቃል ጊዜው አልፏል"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"የ<xliff:g id="ACCOUNT">%s</xliff:g> ውሂብ ከመሳሪያህ ላይ እየተሰረዘ ነው። የማያ መቆለፊያ PIN ወይም ይለፍ ቃል በመለወጥ እነበረበት መመለስ ትችላለህ። አሁን መለወጥ ትፈልጋለህ?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"የ<xliff:g id="ACCOUNT">%s</xliff:g> ውሂብ ከመሣሪያዎ ላይ ተሰርዟል።የማያ መቆለፊያ PIN ወይም ይለፍቃል በመለወጥ እነበረበት መመለስ ይችላሉ። አሁን ይለወጥ?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"ያልተቀመጠ ለውጦችን ይወገዱ?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"በመለያ መግባት አልተቻለም፡፡"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"የ<xliff:g id="ACCOUNT">%s</xliff:g> የተጠቃሚው ስም ወይም ይለፍ ቃል የተሳሳተ ነው። አሁን ልታዘምናቸው ትፈልጋለህ?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">" የ<xliff:g id="ACCOUNT">%s</xliff:g> ተጠቃሚ ስም ወይም ይለፍቃል የተሳሳተ ነው። አሁን ይዘምኑ?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"ነባሪ መለያ"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"ከዚህ መለያ በነባሪኢሜይል ላክ"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"አባሪዎችን አውርድ"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"ራስሰር-አውርድ አባሪዎች ወደ በቅርብ ጊዜ በWi-Fi የተላኩ መልዕክቶች"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"የኢሜይል ማሳወቂያ"</string> <string name="account_settings_summary" msgid="8403582255413830007">"ድግግሞሽ፣ ማሳወቂያዎች፣ ወዘተ አሳምር።"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"ኢሜይል ሲመጣ ማሳወቂያ አሳይ"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"ኢሜይል ሲደርስ በሁኔታ አሞሌ ውስጥ አሳውቅ"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"የገቢ መልዕክት ምልከታ ድግግሞሽ"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"የገቢ ቅንብሮች"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"የተጠቃሚ ስም፣ ይለፍቃል፣ እና ሌላ የገቢ አገልጋይ ቅንብሮች"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"የወጪ ቅንብሮች"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"የተጠቃሚ ስም፣ ይለፍቃል፣ እና ሌላ የወጪ አገልጋይ ቅንብሮች"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"ቋሚ መመሪያዎችን አስገድድ"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"ምንም"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"ያልተደገፉ ቋሚ መመሪያዎች"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"ምንም"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"ማመሳሰል ሞክር"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"ይህን መለያ ለማመሳሰል እዚጋ ንካ"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"የመለያ ስም"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"ስምዎ"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"ፊርማ"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"ፈጣን ምላሾች"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"ኢሜይል ስትጽፍ በተደጋጋሚ የምታስገባውን ፅሁፍ አርትዕ አድርግ"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"ኢሜይል ሲያቀናብሩ በተደጋጋሚ የሚያስገቡትን ፅሁፍ አርትዕ ያድርጉ"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"ወደ ሚልኩት መለልዕክቶች ፅሁፍ ይጨምሩ"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"የማሳወቂያ ቅንብሮች"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"የውሂብ አጠቃቀም"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"የደህንነት ቋሚ መመሪያዎች"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"ፈጣን ምላሽ አርትዕ"</string> <string name="save_action" msgid="1988862706623227093">"አስቀምጥ"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"ዕውቂያዎች አሳምር"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"ለዚህ መለያ እውቂያዎች አሳምር"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"የቀን አቆጣጠር አሳምር"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"ለዚህ መለያ የቀን መቁጠሪያ ክስተት አመሳስል"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"የቀን አቆጣጠር አሳምር"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"ለዚህ መለያ የቀን አቆጣጠር አሳምር"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"ኢሜይል አመሳስል"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"ለዚህ መለያ ኢሜይል አሳምር"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"ንዘር"</string> @@ -462,7 +451,7 @@ <string name="trusted_senders_cleared" msgid="4762002183756251723">"\"ፎቶዎች አሳይ\" ጠርቷል።"</string> <string name="position_of_count" msgid="7989353140376877792">"<xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$s</xliff:g>"</string> <string name="waitinf_for_sync_message_1" msgid="1393719303955128036">"አስምር በመጠበቅ ላይ"</string> - <string name="waitinf_for_sync_message_2" msgid="5656175205790694016">"የአንተ ኢሜይል በቅርቡ ብቅ ይላል::"</string> + <string name="waitinf_for_sync_message_2" msgid="5656175205790694016">"ያንተ ኢሜይል በቅርቡ ብቅ ይላል::"</string> <string name="widget_other_views" msgid="4988574907386539499">"ለመለወጥ አዶ ንካ::"</string> <string name="widget_all_mail" msgid="4352573990283094963">"የተቀላቀለ ገቢ መልዕክት"</string> <string name="widget_unread" msgid="4404711399009077833">"ያልተነበበ"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"ውጤቶችን በመጠበቅ ላይ"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"አንዳንድ አገልጋዮች ረጅም ጊዜ ሊወስዱ ይችላሉ።"</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"አቃፊዎች"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"የመሳሪያውን ካሜራ መጠቀምን አትፍቀድ"</string> - <string name="policy_require_password" msgid="7177274900480984702">"የመሳሪያ የይለፍ ቃል ጠይቅ"</string> - <string name="policy_password_history" msgid="5743544498302303181">"የቅርብ የይለፍ ቃሎችን ዳግመኛ መጠቀምን ከልክል"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"የይለፍ ቃሎች ጊዜያቸው እንዲያልፍባቸው ይፈልጋል"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"ስራ የፈታን መሳሪያ ማሳያውን እንዲቆልፍ ይጠብቃል"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"የሚመሳሰሉ የቀን መቁጠሪያ ክስተቶችን ቁጥር ወሰን አድርግ"</string> - <string name="policy_email_age" msgid="7144148367145424963">"የሚመሳሰሉ ኢሜይሎችን ቁጥር ወሰን አድርግ"</string> - <string name="quick_1" msgid="3426057697353380951">"እናመሰግናለን!"</string> - <string name="quick_2" msgid="4188036352885736617">"ለኔ ጥሩ ይመስላል!"</string> - <string name="quick_3" msgid="8061819976353395585">"በኋላ ይሄንን አነባለው እና ወደ አንተ እመለሳለሁ፡፡"</string> - <string name="quick_4" msgid="3988974084396883051">"ስብሰባ እናዘጋጅ እስቲ ይሄንን ለመወያየት፡፡"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"ውጫዊ አገልግሎት በማድረግ ጊዜ የዳራ ማመሳሰል ለዚህ መለያ ቦዝኗል፡፡"</string> </resources> diff --git a/res/values-am/uploader.xml b/res/values-am/uploader.xml index 6ec5625af..5a0c08e94 100644 --- a/res/values-am/uploader.xml +++ b/res/values-am/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"ዝርዝሮች ደብቅ"</string> <string name="menu_settings" msgid="5088116127086866634">"ቅንብሮች"</string> <string name="format_date_uploaded" msgid="803752037646090928">"%s ተሰቅሏል"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"መለያ"</string> <string name="upload" msgid="2615541458361216022">"ስቀል"</string> <string name="ok" msgid="2516349681897895312">"እሺ"</string> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 7388ffe9a..896f6ab39 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"قراءة مرفقات البريد الإلكتروني"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"للسماح للتطبيق بقراءة مرفقات البريد الإلكتروني."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"للسماح لهذا التطبيق بقراءة مرفقات البريد الإلكتروني."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"الدخول إلى بيانات موفر البريد الإلكتروني"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"للسماح للتطبيق بالدخول إلى قاعدة بيانات بريدك الإلكتروني، بما في ذلك الرسائل المستلمة والرسائل المرسلة وأسماء المستخدمين وكلمات المرور."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"للسماح للتطبيق بالدخول إلى قاعدة بيانات بريدك الإلكتروني، بما في ذلك الرسائل المتلقاة والرسائل المرسلة وأسماء المستخدمين وكلمات المرور."</string> <string name="app_name" msgid="5815426892327290362">"بريد"</string> <string name="compose_title" msgid="427986915662706899">"إنشاء"</string> <string name="debug_title" msgid="5175710493691536719">"تصحيح الأخطاء"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"تم"</string> <string name="create_action" msgid="3062715563215392251">"إنشاء رد جديد"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"حذف"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"ليست هناك ردود سريعة."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"ليست هناك ردود سريعة"</string> <string name="discard_action" msgid="6532206074859505968">"إلغاء"</string> <string name="save_draft_action" msgid="6413714270991417223">"حفظ المسودة"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"إدراج رد سريع"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> كتَب:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"إدراج النص المقتبس"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"تضمين نص"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"أضف مستلمًا واحدًا على الأقل."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"يلزم إضافة مستلم واحد على الأقل."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"بعض عناوين البريد الإلكتروني غير صالحة"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"الملف كبير جدًا بحيث لا يمكن إرفاقه."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"إدراج رد سريع"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"تم الحفظ"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"إيقاف"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"تم حفظ المرفق باسم <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"تعذر حفظ المرفق."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"سيتم تنزيل مرفق أو أكثر في الرسالة التي تمت إعادة توجيهها قبل الإرسال."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"تعذر حفظ المرفق."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"ملاحظة: هناك واحد أو أكثر من المرفقات في الرسالة المعاد توجيهها سيتم تنزيله قبل الإرسال."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"الرسالة"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"دعوة"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"تتعذر إعادة توجيه واحد أو أكثر من المرفقات."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"لم تتم إعادة توجيه المرفق"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"لم يتم تسجيل <xliff:g id="ACCOUNT_NAME">%s</xliff:g> بنجاح."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"أخفق تسجيل الدخول إلى <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"تعذر تسجيل الدخول"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> بايت"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"يمكنك إعداد حساب Exchange ActiveSync من خلال اتباع خطوات قليلة."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"عنوان البريد الإلكتروني"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"كلمة المرور"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"إرسال البريد الإلكتروني من هذا الحساب افتراضيًا"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"إرسال الرسائل الإلكترونية من هذا الحساب افتراضيًا."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"إعداد يدوي"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"اكتب عنوان بريد إلكتروني وكلمة مرور صالحين."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"حساب متكرر"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"جارٍ فحص إعدادات خادم البريد الوارد…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"جارٍ فحص إعدادات خادم البريد الصادر…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"إعداد الحساب"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"تمّ إعداد حسابك، وستصلك رسالة إلكترونية بعد قليل."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"تمّ إعداد حسابك، وستصلك رسالة إلكترونية قريبًا!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"تسمية هذا الحساب (اختياري)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"الاسم (يظهر في الرسائل الصادرة)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"لا يمكن أن يكون هذا الحقل فارغًا."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"خادم SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"المنفذ"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"نوع الأمان"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"طلب تسجيل الدخول"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"يلزم تسجيل الدخول."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"اسم المستخدم"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"كلمة المرور"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"إعداد الحساب"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"كل 15 دقيقة"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"كل 30 دقيقة"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"كل ساعة"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"إرسال البريد الإلكتروني من هذا الحساب افتراضيًا"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"تنبيهي عند استلام رسالة إلكترونية"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"مزامنة جهات الاتصال من هذا الحساب"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"مزامنة التقويم من هذا الحساب"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"مزامنة البريد الإلكتروني من هذا الحساب"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"إرسال الرسائل الإلكترونية من هذا الحساب افتراضيًا."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"تنبيهي عند استلام رسالة إلكترونية."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"مزامنة جهات الاتصال من هذا الحساب."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"مزامنة التقويم من هذا الحساب أيضًا."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"مزامنة البريد الإلكتروني من هذا الحساب"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"تنزيل المرفقات تلقائيًا عند الاتصال بشبكة Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"تعذر الإنهاء"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"الأيام المطلوب مزامنتها"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"شهر واحد"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"الكل"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"استخدام الإعدادات الافتراضية للحساب"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"اسم المستخدم غير صحيح أو كلمة مرور غير صحيحة."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"اسم المستخدم غير صحيح أو كلمة المرور غير صحيحة."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"اسم المستخدم أو كلمة المرور غير صحيحة."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"اسم المستخدم أو كلمة المرور غير صحيحة."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"لا يمكن الاتصال بالخادم بأمان."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"لا يمكن الاتصال بالخادم بأمان."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"يستلزم الأمر شهادة عميل. هل تريد الاتصال بالخادم باستخدام شهادة عميل؟"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"الشهادة غير صالحة أو يتعذر الدخول إليها."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"لقد استجاب الخادم بخطأ. تحقق من اسم المستخدم وكلمة المرور ثم أعد المحاولة."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"شهادة العميل مطلوبة. هل تريد الاتصال بالخادم باستخدام شهادة العميل؟"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"الشهادة غير صالحة أو لا يمكن الدخول إليها."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"لقد استجاب الخادم بخطأ. تحقق من اسم المستخدم وكلمة المرور ثم أعد المحاولة."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"لا يمكن الاتصال بالخادم."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"لا يمكن الاتصال بالخادم."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"يلزم وجود TLS لكن لا يتيح الخادم استخدامه."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"تحذير: سيؤدي إلغاء تنشيط صلاحية تطبيق البريد الإلكتروني لإدارة الجهاز إلى حذف جميع حسابات البريد الإلكتروني التي تتطلب الصلاحية، وأيضًا حذف البريد الإلكتروني وجهات الاتصال وأحداث التقويم وغيرها من البيانات."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"تحديث أمني"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"يتطلب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" تحديث إعدادات الأمان."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"تتعذر مزامنة الحساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" بسبب متطلبات الأمان."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"يتطلب الحساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" تحديث إعدادات الأمان."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"غير الحساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" إعدادات الأمان له؛ ولا يلزم اتخاذ أي إجراء من قبل المستخدم."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"يلزم تحديث الأمان"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"لقد تغيرت سياسات الأمان"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"لا يمكن تلبية سياسات الأمان"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"يتطلب الحساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" تحديث إعدادات الأمان."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"تحديث الأمان مطلوب"</string> <string name="account_security_title" msgid="3511543138560418587">"أمان الجهاز"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"يتطلب الخادم <xliff:g id="SERVER">%s</xliff:g> أن تسمح له بالتحكم في بعض ميزات الأمان في جهاز Android عن بعد."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"تعديل التفاصيل"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"لقد انتهت صلاحية رقم التعريف الشخصي (PIN) أو كلمة مرور لتأمين الشاشة."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"انتهت كلمة مرور تأمين الشاشة"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"ستنتهي صلاحية كلمة مرور تأمين الشاشة"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"يلزمك تغيير رقم التعريف الشخصي لشاشة التأمين أو كلمة المرور قريبًا، وإلا فسيتم محو بيانات <xliff:g id="ACCOUNT">%s</xliff:g>. هل تريد تغييره الآن؟"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"يجب تغيير رقم التعريف الشخصي (PIN) أو كلمة المرور الخاصة بتأمين الشاشة قريبًا، أو سيتم محو بيانات <xliff:g id="ACCOUNT">%s</xliff:g>. هل تريد التغيير الآن؟"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"انتهت كلمة مرور تأمين الشاشة"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"تتم الآن إزالة بيانات <xliff:g id="ACCOUNT">%s</xliff:g> من جهازك. يمكنك استعادتها من خلال تغيير رقم التعريف الشخصي لشاشة التأمين أو كلمة المرور. هل تريد تغييره الآن؟"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"يتم حاليًا محو بيانات <xliff:g id="ACCOUNT">%s</xliff:g> من جهازك. ويمكنك استعادتها من خلال تغيير رقم التعريف الشخصي (PIN) أو كلمة مرور الخاصة بتأمين الشاشة. هل تريد التغيير الآن؟"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"أتريد إلغاء أي تغييرات غير محفوظة؟"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"تعذر تسجيل الدخول"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"اسم المستخدم أو كلمة المرور للحساب <xliff:g id="ACCOUNT">%s</xliff:g> غير صحيح؟. هل تريد تحديثهما الآن؟"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"اسم المستخدم أو كلمة مرور <xliff:g id="ACCOUNT">%s</xliff:g> غير صحيحة. هل تريد التحديث الآن؟"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"الحساب الافتراضي"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"إرسال البريد الإلكتروني من هذا الحساب افتراضيًا"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"تنزيل المرفقات"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"تنزيل مرفقات الرسائل الأخيرة تلقائيًا عبر WiFi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"إشعارات البريد إلكتروني"</string> <string name="account_settings_summary" msgid="8403582255413830007">"معدل المزامنة والتنبيهات وما إلى ذلك"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"إرسال إشعار عند وصول بريد إلكتروني"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"التنبيه في شريط النظام عند استلام رسالة إلكترونية"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"معدل الإطلاع على البريد الوارد"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"إعدادات البريد الوارد"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"اسم المستخدم وكلمة المرور وإعدادات خادم الوارد الأخرى"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"إعدادات البريد الصادر"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"اسم المستخدم وكلمة المرور وإعدادات خادم الصادر الأخرى"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"السياسات المطبقة"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"بلا"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"سياسات غير معتمدة"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"بلا"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"محاولة المزامنة"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"المس هنا لمزامنة الحساب"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"اسم الحساب"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"الاسم"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"التوقيع"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"الردود السريعة"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"تعديل النص الذي تدرجه بشكل متكرر عند إنشاء رسالة إلكترونية"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"تعديل النص الذي تدرجه بشكل متكرر عند إنشاء رسائل إلكترونية"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"إلحاق نص بالرسائل التي يتم إرسالها"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"إعدادات التنبيه"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"استخدام البيانات"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"سياسات الأمان"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"تعديل رد سريع"</string> <string name="save_action" msgid="1988862706623227093">"حفظ"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"مزامنة جهات الاتصال"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"مزامنة جهات الاتصال لهذا الحساب"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"مزامنة التقويم"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"مزامنة حدث التقويم لهذا الحساب"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"مزامنة التقويم"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"مزامنة التقويم لهذا الحساب"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"مزامنة البريد الإلكتروني"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"مزامنة البريد الإلكتروني لهذا الحساب"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"اهتزاز"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"في انتظار النتائج"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"قد يستغرق بعض الخوادم وقتًا طويلاً."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"المجلدات"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"عدم السماح لاستخدام كاميرا الجهاز"</string> - <string name="policy_require_password" msgid="7177274900480984702">"يلزم كلمة مرور الجهاز"</string> - <string name="policy_password_history" msgid="5743544498302303181">"تقييد إعادة استخدام كلمات المرور الأخيرة"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"يلزم انتهاء صلاحية كلمات المرور"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"يلزم جهاز بوضع الخمول لتأمين شاشته"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"تقييد عدد أحداث التقويم المتزامنة"</string> - <string name="policy_email_age" msgid="7144148367145424963">"تقييد عدد الرسائل الإلكترونية المتزامنة"</string> - <string name="quick_1" msgid="3426057697353380951">"شكرًا!"</string> - <string name="quick_2" msgid="4188036352885736617">"يبدو جيدًا بالنسبة إليّ!"</string> - <string name="quick_3" msgid="8061819976353395585">"سأقرأ هذا لاحقًا، وسأرد عليك."</string> - <string name="quick_4" msgid="3988974084396883051">"دعونا نعد اجتماعًا لمناقشة هذا الأمر."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"تم تعطيل المزامنة في الخلفية لهذا الحساب أثناء التجوال."</string> </resources> diff --git a/res/values-ar/uploader.xml b/res/values-ar/uploader.xml index dd150b164..dae9b4c36 100644 --- a/res/values-ar/uploader.xml +++ b/res/values-ar/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"إخفاء التفاصيل"</string> <string name="menu_settings" msgid="5088116127086866634">"الإعدادات"</string> <string name="format_date_uploaded" msgid="803752037646090928">"تم تحميل %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"الحساب"</string> <string name="upload" msgid="2615541458361216022">"تحميل"</string> <string name="ok" msgid="2516349681897895312">"موافق"</string> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 72b5f1805..14a8c4ead 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Чытаць далучаныя файлы ў электроннай пошце"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Дазваляе прыкладанням чытаць вашыя далучэнні да электронных лістоў."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Дазваляе прыкладанням чытаць далучаныя файлы ў вашай электроннай пошце."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Доступ да дадзеных пастаўшчыка паслуг электроннай пошты"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Дазваляе прыкладанням атрымліваць доступ да базы дадзеных вашай электроннай пошты, у тым ліку да атрыманых і адпраўленых паведамленняў, імёнаў карыстальнікаў і пароляў."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Дазваляе гэтаму прыкладанню атрымліваць доступ да базы дадзеных вашай электроннай пошты, у тым ліку да атрыманых і адпраўленых паведамленняў, імёнаў карыстальнікаў і пароляў."</string> <string name="app_name" msgid="5815426892327290362">"Электронная пошта"</string> <string name="compose_title" msgid="427986915662706899">"Напісаць"</string> <string name="debug_title" msgid="5175710493691536719">"Адладка"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Зроблена"</string> <string name="create_action" msgid="3062715563215392251">"Стварыць"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Выдаліць"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Хуткіх адказаў няма."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Няма хуткіх адказаў"</string> <string name="discard_action" msgid="6532206074859505968">"Адхіліць"</string> <string name="save_draft_action" msgid="6413714270991417223">"Захаваць праект"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Уставіць хуткі адказ"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"Карыстальнiк <xliff:g id="SENDER">%s</xliff:g> пісаў: "\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Уключыць цытаваны тэкст"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Уключыць тэкст"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Дадайце хаця б аднаго атрымальнiка."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Неабходна дадаць хаця б аднаго атрымальніка."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Некаторыя адрасы электроннай пошты несапраўдныя."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Файл занадта вялікі для далучэння."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Уставіць хуткі адказ"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Захавана"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Спыніць"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Укладанне захаванае як <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Немагчыма захаваць далучэнне."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Адзін або некалькі далучаных файлаў у пераадрасаваным паведамленні будуць перад адпраўкай спампаваны."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Немагчыма захаваць далучаны файл."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Нататка. Адно або некалькі ўкладанняў у перанапраўленным паведамленні будуць загружаныя перад адпраўкай."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Паведамленне"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Запрасіць"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Не атрымалася перанакiраваць адзін або некалькі далучаных файлаў."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Далуч. файлы не перасылаюцца"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Няўдалы ўваход з уліковага запісу <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Не атрымалася ўвайсцi ва ўлiковы запiс <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Не атрымалася ўвайсці"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> Б"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Вы можаце наладзіць уліковы запіс Exchange ActiveSync усяго за некалькі крокаў."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Адрас электроннай пошты"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Пароль"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Адпраўляць пошту з гэтага ўліковага запісу па змаўчанні"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Адпраўляць пошту з гэтага уліковага запісу па змаўчанні."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Самастойнае ўсталяванне"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Увядзіце правільны адрас электроннай пошты і пароль."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Дублікат уліковага запісу"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Праверка ўваходных налад сервера..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Праверка выходных налад сервера..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Усталяванне ўліковага запісу"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Уліковы запіс створаны, электронная пошта адпраўляецца."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ваш уліковы запіс створаны, электронная пошта адпраўленая"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Дайце гэтаму ўліковаму запісу назву (не абавязкова)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Вашае імя (адлюстроўваецца на выходных паведамленнях)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Гэта поле не можа быць пустым"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Сервер SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Порт"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Тып бяспекі"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Патрабаваць уваход"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Патрабаваць ўваход ў сістэму."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Імя карыстальніка"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Пароль"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Усталяванне ўліковага запісу"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Кожныя 15 хвілін"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Кожныя 30 хвілін"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Кожную гадзіну"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Адпраўляць пошту з гэтага ўліковага запісу па змаўчанні"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Паведамляць мне аб атрыманні электроннай пошты"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Сінхранізаваць кантакты з гэтага ўліковага запісу"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Сінхранізаваць каляндар з гэтага ўліковага запісу"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Сінхранізаваць электронную пошту з гэтага ўліковага запісу"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Адпраўляць пошту з гэтага ўліковага запісу па змаўчанні."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Паведамляць мне пры атрыманні паведамлення электроннай пошты."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Сінхранізаваць кантакты з гэтага ўліковага запісу."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Сінхранізаваць календар з гэтага ўліковага запісу."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Сінхранізацыя электроннай пошты з гэтага ўліковага запісу."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Аўтаматычна спампоўваць далучаныя файлы пры падключэнні да Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Не атрымалася скончыць"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Дні для сінхранізацыі"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Адзін месяц"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Усе"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Выкарыстоўваць параметры ўліковага запісу па змаўчанню"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Няправiльны пароль цi iмя карыстальнiка."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Імя карыстальніка ці пароль няправільныя."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Няправільнае імя карыстальніка ці пароль."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Няправільнае імя карыстальніка ці пароль. "\n" (<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Не атрымлiваецца ўсталяваць бяспечнае злучэнне з серверам."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Не атрымліваецца ўсталяваць бяспечнае злучэнне з серверам."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Патрабуецца сертыфікат кліента. Жадаеце падключыцца да сервера з сертыфікатам кліента?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Несапраўдны або недаступны сертыфікат."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Адказ сервера змяшчае памылку. Праверце сваe імя карыстальніка і пароль, а потым паспрабуйце яшчэ раз."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Патрабуецца сертыфікат кліента. Падключыцца да сервера з сертыфікатам кліента?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Сертыфікат несапраўдны або недаступны."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Сервер адказаў з памылкай; праверце свае імя карыстальніка і пароль і паспрабуйце яшчэ раз."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Немагчыма падключыцца да сервера."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Не атрымлiваецца падлучыцца да сервера."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS патрабуецца, але не падтрымліваецца серверам."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"УВАГА! Адключэнне кіравання прыкладаннем электроннай пошты, прызначаным для адміністравання вашай прылады, прывядзе да выдалення ўсiх уліковых запісаў электроннай пошты, якія яго патрабуюць, разам з электроннай поштай, кантактамі, мерапрыемствамi календара і іншымі дадзенымі."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Абнаўленне бяспекі"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Патрэбна абнавіць налады бяспекі ўлiковага запiсу <xliff:g id="ACCOUNT">%s</xliff:g>"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Немагчыма сiнхранiзаваць улiковы запiс \"<xliff:g id="ACCOUNT">%s</xliff:g>\" з-за патрабаванняў бяспекі."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Уліковы запіс \"<xliff:g id="ACCOUNT">%s</xliff:g>\" патрабуе абнаўлення налад бяспекі."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Змянiлiся налады бяспекi для ўлiковага запiсу \"<xliff:g id="ACCOUNT">%s</xliff:g>\". Не патрабуюцца дзеяннi карыстальнiка."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Абнавіце сістэму бяспекі"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Правiлы бяспекі змяніліся"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Немагчыма выконваць правiлы бяспекі"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Уліковы запіс \"<xliff:g id="ACCOUNT">%s</xliff:g>\" патрабуе абнаўлення налад бяспекі."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Абнавіце сістэму бяспекі"</string> <string name="account_security_title" msgid="3511543138560418587">"Бяспека прылады"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Сервер <xliff:g id="SERVER">%s</xliff:g> патрабуе дазволу аддалена кіраваць некаторымі функцыямі бяспекі вашай прылады Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Рэдагаваць дэталі"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Скончыўся тэрмін дзеяння вашага PIN-кода альбо пароля блакавання экрана."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Скончылася дзеянне пароля блак. экрана"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Заканчваецца дзеянне пароля блак. экрана"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Вы павінны змяніць свой PIN-код для блакiроўкi экрана або пароль у бліжэйшы час, iнакш дадзеныя для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g> будуць выдалены. Змяніць PIN-код зараз?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Вы павінны змяніць свой PIN-код альбо пароль блакавання экрана ў бліжэйшы час, у адваротным выпадку дадзеныя ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g> будуць выдаленыя. Змяніць цяпер?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Скончылася дзеянне пароля блак. экрана"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Дадзеныя для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g> выдаляюцца з памяці прылады. Вы можаце аднавіць іх пры змене PIN-кода для блакiроўкi экрана або пароля. Змяніць яго цяпер?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Дадзеныя для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g> выдаляюцца з памяці прылады. Вы можаце аднавіць іх, змяніўшы ПІН-код альбо пароль блакавання экрана. Змяніць цяпер?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Скасаваць незахаваныя змяненні?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Не атрымалася ўвайсці"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Імя карыстальніка і пароль для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g> няправільныя. Абнавіць іх зараз?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Імя карыстальніка і пароль для ўваходу ва ўліковы запіс <xliff:g id="ACCOUNT">%s</xliff:g> не сапраўдныя. Абнавіць іх цяпер?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Уліковы запіс па змаўчанні"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Адпраўляць пошту з гэтага ўліковага запісу па змаўчанні"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Спампаваць далучэнні"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Аўтаматычнае спампаванне далучэнняў з апошніх паведамленняў праз Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Апавяшчэннi па электроннай пошце"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Сінхранізаваць частату, паведамленні і г. д."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Дасылаць апавяшчэнне пры атрыманні электроннай пошты"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Паведамляць аб атрыманні электроннага ліста ў сістэмным радку"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Частата праверкі ўваходных паведамленняў"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Уваходныя налады"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Імя карыстальніка, пароль і іншыя налады сервера ўвах. паведамл."</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Выходныя налады"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Імя карыстальніка, пароль і іншыя налады сервера вых. паведамл."</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Правiлы парушаны"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Няма"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Правiлы не падтрымліваюцца"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Няма"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Спроба сінхранізацыі"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Націсніце тут, каб сінхранізаваць гэты ўліковы запіс"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Назва уліковага запісу:"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Вашае імя"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Подпіс"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Хуткія адказы"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Змяніць тэкст, які часта ўстаўляецца пры напiсанні паведамлення"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Змяніць тэкст, які часта ўстаўляецца пры напiсанні паведамлення"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Дадаць тэкст у паведамленні, што вы адпраўляеце"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Налады апавяшчэнняў"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Выкарыстанне дадзеных"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Правiлы бяспекі"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Змяніць хуткі адказ"</string> <string name="save_action" msgid="1988862706623227093">"Захаваць"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Сінхранізаваць кантакты"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Сінх. кантактаў для гэтага ўл. зап."</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Сінхранізаваць каляндар"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Сінхр.. мерапр. для гэтага ўл. зап."</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Сінхр. каляндар"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Сінх. каляндар для гэтага ўл. зап."</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Сінхранізаваць электронную пошту"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Сінхранізацыя электроннай пошты для гэтага ўліковага запісу"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Вібрацыя"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Чаканне вынікаў"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Некаторыя серверы могуць заняць працяглы час."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Папкі"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Забараніць выкарыстанне камеры прылады"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Патрабаваць пароль прылады"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Абмежаваць паўторнае выкарыстанне апошніх пароляў"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Запытаць заканчэнне дзеяння пароля"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Патр. рэж. праст. прыл. для блак. экр."</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Абмежаванне колькасці сінхр. мерапр. календара"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Абмежаванне колькасці сінхр. паведамл. эл. пошты"</string> - <string name="quick_1" msgid="3426057697353380951">"Дзякуй!"</string> - <string name="quick_2" msgid="4188036352885736617">"Гучыць нядрэнна!"</string> - <string name="quick_3" msgid="8061819976353395585">"Я прачытаю гэта пазней i звяжуся з вамi."</string> - <string name="quick_4" msgid="3988974084396883051">"Давайце прызначым сустрэчу, каб абмеркаваць гэта."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Фонавая сінхранізацыя для гэтага ўліковага запісу адключана ў роўмінгу."</string> </resources> diff --git a/res/values-be/uploader.xml b/res/values-be/uploader.xml index f8aee8e6e..eef060d2e 100644 --- a/res/values-be/uploader.xml +++ b/res/values-be/uploader.xml @@ -28,7 +28,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Схаваць падрабязнасці"</string> <string name="menu_settings" msgid="5088116127086866634">"Налады"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Загружана %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Уліковы запіс"</string> <string name="upload" msgid="2615541458361216022">"Загрузіць"</string> <string name="ok" msgid="2516349681897895312">"ОК"</string> diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 4f5fe5fe7..682c96a2d 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Четене на прикачени файлове в имейла"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Разрешава на приложението да чете прикачените файлове в имейла ви."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Разрешава на това приложение да чете прикачените файлове в имейла ви."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Достъп до данни на доставчика на имейл"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Дава на приложението достъп до базата от данни на имейла ви, включително получени и изпратени съобщения, потребителски имена и пароли."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Дава на това приложение достъп до базата от данни на имейла ви, включително получени и изпратени съобщения, потребителски имена и пароли."</string> <string name="app_name" msgid="5815426892327290362">"Имейл"</string> <string name="compose_title" msgid="427986915662706899">"Ново съобщение"</string> <string name="debug_title" msgid="5175710493691536719">"Отстраняване на грешки"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Готово"</string> <string name="create_action" msgid="3062715563215392251">"Създаване на нов"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Изтриване"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Няма бързи отговори."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Няма бързи отговори"</string> <string name="discard_action" msgid="6532206074859505968">"Отхвърляне"</string> <string name="save_draft_action" msgid="6413714270991417223">"Запазване на чернова"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Вмъкване на бърз отговор"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> написа:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Включване на цитирания текст"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Включване на текста"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Добавете поне един получател."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Трябва да добавите поне един получател."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Някои имейл адреси са невалидни."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Файлът е твърде голям за прикачване."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Вмъкване на бърз отговор"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Запазено"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Стоп"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Запазен прикачен файл: <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Прикач. файл не бе запазен."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Един или повече прикачени файла в препратеното ви съобщение ще бъдат изтеглени преди изпращане."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Прикач. файл не бе запазен."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Забележка: Един или повече прикачени файла в препратеното ви съобщение ще бъдат изтеглени преди изпращане."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Съобщение"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Покана"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Един или повече прикачени файла не можаха да се препратят."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Прикаченото не бе препратено"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Не успяхте да влезете в профила си <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Не влязохте: <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> <string name="login_failed_title" msgid="7624349996212476176">"Не можах да вляза в профила си"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> Б"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Можете да настроите профил в Exchange ActiveSync само с няколко стъпки."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Имейл адрес"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Парола"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Изпращане на имейл от този профил по подразбиране"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Изпращане на имейл от този профил по подразбиране."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ръчна настройка"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Въведете валиден имейл адрес и парола."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Дублиращ профил"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Настройките на вх. сървър се проверяват..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Настройките на изх. сървър се проверяват..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Настройка на профила"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Профилът ви е настроен и имейлите са на път!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Профилът ви е настроен и имейлите са на път!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Именуване на този профил (незадължително)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Името ви (показвано в изходящи съобщения)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Това поле трябва да се попълни."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP сървър"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Порт"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Вид защита"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Изисква влизане в профил"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Изисква влизане в профил."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Потребителско име"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Парола"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Настройка на профила"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"На всеки 15 мин"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"На всеки 30 мин"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"На всеки час"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Изпращане на имейл от този профил по подразбиране"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Известие при получаване на имейл"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Синхронизиране на контактите в този профил"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Синхронизиране на календара в този профил"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Синхронизиране на имейлите от този профил"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Изпращане на имейл от този профил по подразбиране."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Известие при пристигане на имейл."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Синхронизиране на контактите в този профил."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Синхронизиране на календара в този профил."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Синхрон на имейлите от този профил"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Автоматично изтегляне на прикачените файлове при връзка с Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Не можа да завърши"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Дни за синхронизиране"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Един месец"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Всички"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Стандартното за профила"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Неправилно потребителско име или парола."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Неправилно потребителско име или парола."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Неправилно потребителско име или парола."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Неправилно потребителско име или парола."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Не може да се осъществи безопасна връзка със сървъра."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Не може да се осъществи безопасна връзка със сървъра."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Изисква се сертификат за клиентска програма. Да се установи ли връзка със сървъра чрез него?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Сертификатът е невалиден или недостъпен."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Сървърът отговори с грешка. Проверете потребителското име и паролата си, след което опитайте отново."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Изисква се сертификат за клиентска програма. Да се установи ли връзка със сървъра чрез него?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Сертификатът е невалиден или недостъпен."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Сървърът отговори с грешка. Проверете потребителското име и паролата си и опитайте отново."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Не може да се осъществи връзка със сървъра."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Не може да се осъществи връзка със сървъра."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Изисква се TLS, но не се поддържа от сървъра."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ПРЕДУПРЕЖДЕНИЕ: Деактивирането на възможността приложението Имейл да администрира устройството ви ще изтрие всички имейл адреси, които го изискват, заедно с имейлите, контактите, събитията от календара и други данни в тях."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Атуализация на защитата"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> изисква да актуализирате защитните си настройки."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Профилът „<xliff:g id="ACCOUNT">%s</xliff:g>“ не може да бъде синхронизиран поради изискванията за сигурност."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Профилът „<xliff:g id="ACCOUNT">%s</xliff:g>“ изисква актуализация на настройките за сигурност."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Настройките за сигурност на профила „<xliff:g id="ACCOUNT">%s</xliff:g>“ са променени. Не е необходимо действие от страна на потребителя."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Актуализирайте за сигурност"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Променени правила за сигурност"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Неизпълнени правила за сигурност"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Профилът „<xliff:g id="ACCOUNT">%s</xliff:g>“ изисква актуализация на защитните настройки."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Изисква се актуална защита"</string> <string name="account_security_title" msgid="3511543138560418587">"Сигурност на устройството"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Сървърът <xliff:g id="SERVER">%s</xliff:g> изисква отдалечен контрол над някои от защитните функции на устройството ви с Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Редактиране на подробностите"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN кодът или паролата за заключен екран изтече."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Паролата изтече"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Паролата за заключен екран изтича"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Трябва скоро да промените ПИН кода или паролата си за заключен екран или данните за <xliff:g id="ACCOUNT">%s</xliff:g> ще бъдат изтрити. Искате ли да извършите промяната сега?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Трябва скоро да промените PIN кода или паролата си за заключен екран или данните за <xliff:g id="ACCOUNT">%s</xliff:g> ще бъдат изтрити. Искате ли да извършите промяната сега?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Паролата за заключен екран изтече"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Данните за <xliff:g id="ACCOUNT">%s</xliff:g> се изтриват от устройството ви. Можете да ги възстановите, като промените ПИН кода или паролата си за заключен екран. Искате ли да извършите промяната сега?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Данните за <xliff:g id="ACCOUNT">%s</xliff:g> се изтриват от устройството ви. Можете да ги възстановите, като промените PIN кода или паролата си за заключен екран. Искате ли да извършите промяната сега?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Да се отхвърлят ли незапазените промени?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Не можах да вляза в профила си"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Неправилно потребителско име или парола за <xliff:g id="ACCOUNT">%s</xliff:g>. Искате ли да ги актуализирате сега?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Потребителското име или паролата за <xliff:g id="ACCOUNT">%s</xliff:g> не са правилни. Искате ли да ги актуализирате сега?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Основен профил"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Изпращане на имейл от този профил по подразбиране"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Изтегляне на прикачените файлове"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Автоизтегляне на прик. файлове към скорошни съобщения през Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Известия за имейл"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Честота на синхронизиране, известия и т.н."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Изпращане на известие при получаване на имейл"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Известие в системната лента при получаване на имейл"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Честота на проверяване за входяща поща"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Входящи настройки"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Потребителско име, парола и други настройки на входящия сървър"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Изходящи настройки"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Потребителско име, парола и други настройки на изходящия сървър"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Наложени правила"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Нито едно"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Неподдържани правила"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Нито едно"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Опит за синхронизиране"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Докоснете тук, за да синхронизирате този профил"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Име на профила"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Името ви"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Подпис"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Бързи отговори"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Редактиране на текст, който често вмъквате при писане на имейл"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Редактиране на текст, който често вмъквате при писане на имейли"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Прибавяне на текст към изпращаните от вас съобщения"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Настройки за известия"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Използване на данни"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Правила за сигурност"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Редактиране на бърз отговор"</string> <string name="save_action" msgid="1988862706623227093">"Запазване"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Синхронизиране на контакти"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Синхр. на контактите за този профил"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Синхронизиране на календар"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Синхр. на календарно събитие за профила"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Синхрон на календара"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Синхрон на календара за този профил"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Синхрон на имейлите"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Синхрон на имейлите за този профил"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Вибриране"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Резултатите се изчакват"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Някои сървъри може да отнемат много време."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Папки"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Забраняване на използването на камерата"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Изискване на парола за устройството"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Без повторно ползване на скорошни пароли"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Изискване паролите да изтичат"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Неактивно у-во за заключ. на екрана"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ограничаване на броя синхрон. събития в календара"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ограничаване на броя синхронизирани имейли"</string> - <string name="quick_1" msgid="3426057697353380951">"Благодаря!"</string> - <string name="quick_2" msgid="4188036352885736617">"Звучи добре!"</string> - <string name="quick_3" msgid="8061819976353395585">"Ще прочета това по-късно и ще се свържа с Вас."</string> - <string name="quick_4" msgid="3988974084396883051">"Нека да насрочим среща, за да обсъдим това."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Синхронизирането на заден план за този профил е деактивирано при роуминг."</string> </resources> diff --git a/res/values-bg/uploader.xml b/res/values-bg/uploader.xml index 74ce71deb..1c38811e6 100644 --- a/res/values-bg/uploader.xml +++ b/res/values-bg/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Скриване на подробностите"</string> <string name="menu_settings" msgid="5088116127086866634">"Настройки"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Качени: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Профил"</string> <string name="upload" msgid="2615541458361216022">"Качване"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index c4d83c7a8..c2cb7a512 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Llegeix els fitxers adjunts al correu electrònic"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permet que l\'aplicació llegeixi els fitxers adjunts al correu electrònic."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permet que aquesta aplicació llegeixi els fitxers adjunts al correu electrònic."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Accedeix a les dades del proveïdor de correu electrònic"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permet que l\'aplicació accedeixi a la base de dades del teu correu electrònic, inclosos els missatges rebuts, els missatges enviats, els noms d\'usuari i les contrasenyes."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permet que aquesta aplicació accedeixi a la base de dades del teu correu electrònic, inclosos els missatges rebuts, els missatges enviats, els noms d\'usuari i les contrasenyes."</string> <string name="app_name" msgid="5815426892327290362">"Correu electrònic"</string> <string name="compose_title" msgid="427986915662706899">"Redacció"</string> <string name="debug_title" msgid="5175710493691536719">"Depuració"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Fet"</string> <string name="create_action" msgid="3062715563215392251">"Crea"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Suprimeix"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"No hi ha respostes ràpides."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"No hi ha respostes ràpides"</string> <string name="discard_action" msgid="6532206074859505968">"Descarta"</string> <string name="save_draft_action" msgid="6413714270991417223">"Desa l\'esborrany"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Insereix resposta ràpida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> ha escrit:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Inclou el text citat"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Inclou text"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Afegeix com a mínim un destinatari."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Heu d\'afegir com a mínim un destinatari."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Algunes adreces electròniques no són vàlides."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"El fitxer és massa gran per adjuntar-lo."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Inserció d\'una resposta ràpida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Desat"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Atura"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Fitxer adjunt desat com a <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"No es pot desar fitxer adjunt."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Nota: Un o més fitxers adjunts del teu missatge reenviat es baixaran abans de l\'enviament."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"No s\'ha pogut desar el fitxer adjunt."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota: Un o més fitxers adjunts del teu missatge reenviat es baixaran abans de l\'enviament."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Missatge"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invitació"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"No s\'han pogut reenviar un o més fitxers adjunts."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"El fitxer adjunt no s\'ha reenviat"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Error en l\'inici de sessió a <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"L\'inici de sessió de <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ha fallat."</string> <string name="login_failed_title" msgid="7624349996212476176">"No es pot iniciar la sessió"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Pots configurar un compte d\'Exchange ActiveSync en només uns quants passos."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Adreça electrònica"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Contrasenya"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Envia correu electrònic des d\'aquest compte de manera predeterminada"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Envia correu electrònic des d\'aquest compte de manera predeterminada."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuració manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Escriu una adreça electrònica i una contrasenya vàlides."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Compte duplicat"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"S\'està comprovant la configuració del servidor d\'entrada…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"S\'està comprovant la configuració del servidor de sortida…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuració del compte"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"El compte s\'ha configurat i aviat rebràs un correu electrònic."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"El compte s\'ha configurat i aviat rebre un correu electrònic."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Assigneu un nom al compte (opcional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"El vostre nom (visualitzat als missatges de sortida)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Aquest camp no pot estar en blanc."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Servidor SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipus de seguretat"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Requereix l\'inici de sessió"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Requereix l\'inici de sessió."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nom d\'usuari"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Contrasenya"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuració del compte"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Cada 15 minuts"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Cada 30 minuts"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Cada hora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Envia correu electrònic des d\'aquest compte de manera predeterminada"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Notifica\'m quan arribi un correu electrònic"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronitza els contactes d\'aquest compte"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronitza el calendari d\'aquest compte"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronitza el correu electrònic d\'aquest compte"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Envia correu electrònic des d\'aquest compte de manera predeterminada."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Notifica\'m quan arribi correu electrònic nou."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronitza els contactes d\'aquest compte."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronitza el calendari d\'aquest compte."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronitza el correu electrònic d\'aquest compte."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Baixa automàticament els fitxers adjunts en connectar-te a Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"No s\'ha pogut acabar"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dies per sincronitzar"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Un mes"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Tots"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Utilitza l\'opció predeterminada del compte"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"El nom d\'usuari o la contrasenya no són correctes."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"El nom d\'usuari o la contrasenya són incorrectes."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nom d\'usuari o contrasenya incorrectes."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nom d\'usuari o contrasenya incorrectes."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"No es pot establir una connexió segura amb el servidor."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"No es pot establir una connexió segura amb el servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Es necessita un certificat de client. Et vols connectar al servidor amb un certificat de client?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"El certificat no és vàlid o no s\'hi pot accedir."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"El servidor ha contestat amb un error. Comprova el nom d\'usuari i la contrasenya i torna-ho a provar."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Es necessita un certificat de client. Et vols connectar al servidor amb el certificat de client?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"El certificat no és vàlid o bé no s\'hi pot accedir."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"El servidor ha contestat amb un error. Comprova el nom d\'usuari i la contrasenya i torna-ho a provar."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"No es pot establir la connexió amb el servidor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"No es pot connectar amb el servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS necessari, però no compatible amb el servidor."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ADVERTIMENT: Desactivar l\'autoritat de l\'aplicació de correu electrònic per administrar el dispositiu suprimirà tots els comptes de correu electrònic que ho requereixin, juntament amb els correus electrònics, els contactes, els esdeveniments de calendari i altres dades."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Actualització de seguretat"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> necessita que actualitzis la configuració de seguretat."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"El compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\" no es pot sincronitzar a causa de requisits de seguretat."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Cal actualitzar la configuració de seguretat del compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"El compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ha canviat la configuració de seguretat; no es requereix cap acció de l\'usuari."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Cal actualització de seguretat"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Les polítiques de seguretat han canviat"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"No es compleixen polít. segur."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Cal actualitzar la configuració de seguretat del compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Cal fer una actualització de seguretat"</string> <string name="account_security_title" msgid="3511543138560418587">"Seguretat del dispositiu"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"El servidor <xliff:g id="SERVER">%s</xliff:g> requereix que li permetis controlar de manera remota algunes funcions de seguretat del dispositiu Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Edita\'n els detalls"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"La contrasenya o el PIN de bloqueig de pantalla ha caducat."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"La contrasenya de bloqueig de pantalla ha caducat"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"La contrasenya de bloqueig de pantalla està a punt de caducar"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Has de canviar la contrasenya o el PIN de bloqueig de pantalla aviat. Si no ho fas, s\'esborraran les dades de <xliff:g id="ACCOUNT">%s</xliff:g>. Vols fer el canvi ara?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Has de canviar la contrasenya o el PIN de bloqueig de pantalla aviat. Si no ho fas, s\'esborraran les dades de <xliff:g id="ACCOUNT">%s</xliff:g>. Vols fer el canvi ara?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"La contrasenya de bloqueig de pantalla ha caducat"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Les dades de <xliff:g id="ACCOUNT">%s</xliff:g> s\'estan esborrant del dispositiu. Pots restaurar-les si canvies la contrasenya o el PIN de bloqueig de pantalla. Vols fer el canvi ara?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Les dades de <xliff:g id="ACCOUNT">%s</xliff:g> s\'estan esborrant del dispositiu. Pots restaurar-les si canvies la contrasenya o el PIN de bloqueig de pantalla. Vols fer el canvi ara?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Vols descartar els canvis no desats?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"No es pot iniciar la sessió"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"El nom d\'usuari o la contrasenya de <xliff:g id="ACCOUNT">%s</xliff:g> no són correctes. Vols actualitzar-los ara?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"El nom d\'usuari o la contrasenya de <xliff:g id="ACCOUNT">%s</xliff:g> són incorrectes. Vols actualitzar-los ara?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Compte predeterminat"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Envia correu electrònic des d\'aquest compte de manera predeterminada"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Baixada de fitxers adjunts"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Baixa automàtic. fitxers adjunts de missatges recents per Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificacions de correu electrònic"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Freqüència de sincronització, notificacions, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Envia una notificació quan arribi un correu electrònic"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notifica a la barra del sistema quan arribi un correu electrònic"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Freqüència de comprovació de la safata d\'entrada"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Configuració d\'entrada"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nom d\'usuari, contrasenya i altres opcions de configuració del servidor d\'entrada"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Configuració de sortida"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nom d\'usuari, contrasenya i altres opcions de configuració del servidor de sortida"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Polítiques aplicades"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Cap"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Polítiques no compatibles"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Cap"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Intenta la sincronització"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Toca aquí per sincronitzar aquest compte"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nom del compte"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"El vostre nom"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signatura"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respostes ràpides"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edita text que insereixes sovint en redactar correus electrònics"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edita text que insereixes sovint en redactar correu electrònic"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Annexa text als missatges que envieu"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Configuració de notificacions"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Ús de dades"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Polítiques de seguretat"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Edita una resposta ràpida"</string> <string name="save_action" msgid="1988862706623227093">"Desa"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronitza els contactes"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincr. contactes d\'aquest compte"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronitza el calendari"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sincr. esdev. calend. per al compte"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronitza el calendari"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincr. calendari p. aq. compte"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronitza el correu electrònic"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincr. miss. correu d\'aquest compte"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibra"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"S\'estan esperant els resultats"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Alguns servidors poden trigar molt."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Carpetes"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"No permetis l\'ús de la càmera del dispositiu"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Requereix la contrasenya del dispositiu"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Restringeix la reutilització de contrasenyes recents"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Requereix que les contrasenyes caduquin"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Requereix un dispositiu absent per bloquejar-ne la pantalla"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limita el nombre d\'esdev. calendari sincronitzats"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limita el nombre de correus electr. sincronitzats"</string> - <string name="quick_1" msgid="3426057697353380951">"Gràcies."</string> - <string name="quick_2" msgid="4188036352885736617">"Em sembla molt bé."</string> - <string name="quick_3" msgid="8061819976353395585">"Ho llegiré més tard i et respondré."</string> - <string name="quick_4" msgid="3988974084396883051">"Organitzem una reunió per parlar-ne."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"La sincronització de fons per a aquest compte està desactivada en itinerància."</string> </resources> diff --git a/res/values-ca/uploader.xml b/res/values-ca/uploader.xml index 8e251c9c6..13b33af96 100644 --- a/res/values-ca/uploader.xml +++ b/res/values-ca/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Amaga els detalls"</string> <string name="menu_settings" msgid="5088116127086866634">"Configuració"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Penjats: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Compte"</string> <string name="upload" msgid="2615541458361216022">"Penja"</string> <string name="ok" msgid="2516349681897895312">"D\'acord"</string> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 3d54bead5..1627d80e3 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Číst přílohy e-mailů"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Umožňuje této aplikaci číst přílohy vašich e-mailů."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Umožňuje této aplikaci číst přílohy e-mailů."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Přístup k datům poskytovatele e-mailu"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Povoluje aplikaci přístup do databáze e-mailů, a to včetně přijatých a odeslaných zpráv, uživatelských jmen a hesel."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Povoluje této aplikaci přístup do databáze e-mailů, včetně přijatých a odeslaných zpráv, uživatelských jmen a hesel."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Napsat"</string> <string name="debug_title" msgid="5175710493691536719">"Ladit"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Hotovo"</string> <string name="create_action" msgid="3062715563215392251">"Vytvořit novou"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Smazat"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Žádné rychlé odpovědi."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Žádné rychlé odpovědi"</string> <string name="discard_action" msgid="6532206074859505968">"Zrušit"</string> <string name="save_draft_action" msgid="6413714270991417223">"Uložit koncept"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Vložit rychlou odpověď"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>napsal/a:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Zahrnout text v uvozovkách"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Zahrnout text"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Přidejte alespoň jednoho příjemce."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Je třeba přidat nejméně jednoho příjemce."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Některé e-mailové adresy jsou neplatné."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Soubor nelze připojit, protože je příliš velký."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Vložit rychlou odpověď"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Uloženo"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Zastavit"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Příloha uložena jako <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Přílohu se nepodařilo uložit."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Jedna či více příloh v přeposílané zprávě bude před odesláním stažena."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Přílohu nelze uložit."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Poznámka: Jedna či více příloh v přeposílané zprávě bude před odesláním stažena."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Zpráva"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Pozvánka"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Nepodařilo se přeposlat jednu nebo více příloh."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Příloha nebyla přeposlána"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Přihlášení do účtu <xliff:g id="ACCOUNT_NAME">%s</xliff:g> se nezdařilo."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Přihlášení selhalo: <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> <string name="login_failed_title" msgid="7624349996212476176">"Přihlášení se nezdařilo."</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Účet služby Exchange ActiveSync můžete nakonfigurovat v několika snadných krocích."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-mailová adresa"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Heslo"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Ve výchozím nastavení odesílat e-maily z tohoto účtu"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Ve výchozím nastavení odesílat e-maily z tohoto účtu."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ruční nastavení"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Zadejte platnou e-mailovou adresu a heslo."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplicitní účet"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Kontrola nastavení serveru příchozí pošty..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kontrola nastavení serveru odchozí pošty..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Nastavení účtu"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Váš účet je nastaven, e-mail je na cestě!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Váš účet je nastaven, e-mail je na cestě!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Pojmenovat tento účet (nepovinné)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Vaše jméno (zobrazované na odchozích zprávách)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Toto pole nesmí být prázdné."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Typ zabezpečení"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Vyžadovat přihlášení"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Požadovat přihlášení"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Uživatelské jméno"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Heslo"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Nastavení účtu"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Každých 15 minut"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Každých 30 minut"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Každou hodinu"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Ve výchozím nastavení odesílat e-maily z tohoto účtu"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Upozornit mě na příchod e-mailu"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synchronizovat kontakty z tohoto účtu"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synchronizovat kalendář z tohoto účtu"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synchronizovat e-mail z tohoto účtu"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Ve výchozím nastavení odesílat e-maily z tohoto účtu."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Upozornit mě na příchod e-mailu"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synchronizovat kontakty z tohoto účtu."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synchronizovat kalendář z tohoto účtu."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synchronizovat e-mail z tohoto účtu."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Během připojení k síti Wi-Fi automaticky stahovat přílohy"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nelze dokončit"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Počet dní k synchronizaci"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Jeden měsíc"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Vše"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Použít výchozí nastavení účtu"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Uživatelské jméno nebo heslo jsou nesprávné."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Uživatelské jméno nebo heslo jsou nesprávné."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Uživatelské jméno nebo heslo není správné"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Uživatelské jméno nebo heslo není správné."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nelze se bezpečně připojit k serveru."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nelze se bezpečně připojit k serveru."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Je vyžadován certifikát klienta. Chcete se k serveru připojit pomocí certifikátu klienta?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certifikát je neplatný nebo nedostupný."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Server odpověděl chybou. Zkontrolujte prosím uživatelské jméno a heslo a zkuste to znovu."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Je vyžadován certifikát klienta. Chcete se připojit k serveru pomocí certifikátu klienta?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certifikát je neplatný nebo nedostupný."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Server odpověděl chybou. Zkontrolujte prosím uživatelské jméno a heslo a zkuste to znovu."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nelze se připojit k serveru."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nelze se připojit k serveru."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Služba TLS je požadována, ale není podporována na serveru."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"UPOZORNĚNÍ: Deaktivujete-li oprávnění aplikace E-mail spravovat toto zařízení, budou smazány všechny účty aplikace E-mail, které toto oprávnění vyžadují. Společně s těmito účty budou smazány i všechny jejich e-maily, kontakty, události v kalendářích a další údaje."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Aktualizace zabezpečení"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Účet <xliff:g id="ACCOUNT">%s</xliff:g> vyžaduje aktualizaci nastavení zabezpečení."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Účet „<xliff:g id="ACCOUNT">%s</xliff:g>“ nelze synchronizovat z důvodu požadavků na zabezpečení."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Účet <xliff:g id="ACCOUNT">%s</xliff:g> požaduje aktualizaci nastavení zabezpečení."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Nastavení zabezpečení účtu <xliff:g id="ACCOUNT">%s</xliff:g> byla změněna. Uživatel nemusí provádět žádnou akci."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Je třeba aktualizovat zabezp."</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Zásady zabezpečení se změnily"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Nelze splnit zásady zabezp."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Účet <xliff:g id="ACCOUNT">%s</xliff:g> požaduje aktualizaci nastavení zabezpečení."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Je třeba aktualizovat zabezp."</string> <string name="account_security_title" msgid="3511543138560418587">"Zabezpečení zařízení"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Server <xliff:g id="SERVER">%s</xliff:g> žádá o povolení, aby mohl vzdáleně ovládat některé funkce zabezpečení v zařízení Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Upravit podrobnosti"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Platnost kódu PIN nebo hesla pro uzamčení obrazovky vypršela."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Platnost hesla pro uzamčení obrazovky vypršela"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Heslo zámku obrazovky brzy vyprší"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Je nutné, abyste si brzy změnili kód PIN nebo heslo pro uzamčení obrazovky, jinak dojde k vymazání údajů účtu <xliff:g id="ACCOUNT">%s</xliff:g>. Chcete tuto změnu provést hned?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Brzy bude třeba změnit kód PIN nebo heslo pro uzamčení obrazovky. Pokud tak neučiníte, budou data účtu <xliff:g id="ACCOUNT">%s</xliff:g> vymazána. Chcete nyní změnit kód PIN nebo heslo?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Platnost hesla zámku obrazovky vypršela"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Ze zařízení jsou mazány údaje účtu <xliff:g id="ACCOUNT">%s</xliff:g>. Můžete je obnovit změnou kódu PIN nebo hesla pro uzamčení obrazovky. Chcete tuto změnu provést hned?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Ze zařízení jsou mazána data účtu <xliff:g id="ACCOUNT">%s</xliff:g>. Data můžete obnovit změnou kódu PIN nebo hesla pro uzamčení obrazovky."</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Zrušit neuložené změny?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Přihlášení se nezdařilo."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Uživatelské jméno nebo heslo k účtu <xliff:g id="ACCOUNT">%s</xliff:g> je nesprávné. Chcete je aktualizovat?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Uživatelské jméno nebo heslo pro účet <xliff:g id="ACCOUNT">%s</xliff:g> je nesprávné. Chcete údaje aktualizovat?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Výchozí účet"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Ve výchozím nastavení odesílat e-maily z tohoto účtu"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Stáhnout přílohy"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automaticky stahovat přílohy posledních zpráv pomocí sítě Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-mailová upozornění"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frekvence synchronizace, oznámení apod."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Zaslat upozornění, když přijde e-mail"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Oznámit příchod e-mailu na systémové liště"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Četnost kontroly doručené pošty"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Nastavení příchozí pošty"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Uživatelské jméno, heslo a jiná nastavení serveru příchozí pošty"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Nastavení odchozí pošty"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Uživatelské jméno, heslo a jiná nastavení serveru odchozí pošty"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Vynucené zásady"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Žádné"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Zásady, které nejsou podporované"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Žádné"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Pokusit se synchronizovat"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Pokud chcete účet synchronizovat, dotkněte se tohoto tlačítka"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Název účtu"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Vaše jméno"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Podpis"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Rychlé odpovědi"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Upravit text, který při psaní e-mailů často vkládáte"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Upravit text, který při psaní e-mailů často vkládáte"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Připojit text k odesílaným zprávám"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Nastavení upozornění"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Využití dat"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Zásady zabezpečení"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Upravit rychlou odpověď"</string> <string name="save_action" msgid="1988862706623227093">"Uložit"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synchronizovat kontakty"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synchronizovat kontakty pro tento účet"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synchronizovat kalendář"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synch. udál. kalend. pro tento účet"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synchronizovat kalendář"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synchronizovat kalendář pro tento účet"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synchronizovat e-maily"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synchronizovat e-mail pro tento účet"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrace"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Čekání na výsledky"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Některým serverům může tento proces trvat dlouho."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Složky"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Zakázat používání fotoaparátu v zařízení"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Požadovat heslo zařízení"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Omezit opětovné použití nedávných hesel"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Požadovat omezenou platnost hesel"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Při nečinnosti zamknout obrazovku"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Omezit počet synchronizovaných událostí kalendáře"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Omezit počet synchronizovaných e-mailů"</string> - <string name="quick_1" msgid="3426057697353380951">"Díky!"</string> - <string name="quick_2" msgid="4188036352885736617">"To zní dobře!"</string> - <string name="quick_3" msgid="8061819976353395585">"Přečtu si to později a ozvu se."</string> - <string name="quick_4" msgid="3988974084396883051">"Můžeme si dohodnout schůzku, abychom to prodiskutovali."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Synchronizace na pozadí je v tomto účtu při roamingu zakázána."</string> </resources> diff --git a/res/values-cs/uploader.xml b/res/values-cs/uploader.xml index f15f9879d..0ce8a868f 100644 --- a/res/values-cs/uploader.xml +++ b/res/values-cs/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Skrýt podrobnosti"</string> <string name="menu_settings" msgid="5088116127086866634">"Nastavení"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Nahráno: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Účet"</string> <string name="upload" msgid="2615541458361216022">"Nahrát"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 477f5ccc0..2856a6f0e 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Læs vedhæftede filer i e-mails"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Tillader, at appen kan læse vedhæftede filer i dine e-mails."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Tillader, at denne applikation læser vedhæftede filer i dine e-mails."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Få adgang til data om e-mailudbyder"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Tillader, at denne app kan få adgang til din e-maildatabase, f.eks. modtagne beskeder, sendte beskeder, brugernavne og adgangskoder."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Tillader, at denne applikation får adgang til din e-maildatabase, f.eks. modtagne beskeder, sendte beskeder, brugernavne og adgangskoder."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Skriv"</string> <string name="debug_title" msgid="5175710493691536719">"Fejlretning"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Udfør"</string> <string name="create_action" msgid="3062715563215392251">"Opret nyt"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Slet"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Ingen hurtige svar."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Ingen hurtige svar"</string> <string name="discard_action" msgid="6532206074859505968">"Kassér"</string> <string name="save_draft_action" msgid="6413714270991417223">"Gem kladde"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Indsæt hurtigt svar"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> skrev:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Inkluder citeret tekst"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Medtag tekst"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Tilføj mindst én modtager."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Du skal tilføje mindst en modtager."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Nogle e-mailadresser er ugyldige."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Filen er for stor til at vedhæfte."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Indsæt hurtigt svar"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Gemt"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stop"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Vedhæftelse gemmes som <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Vedhæftning kunne ikke gemmes"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"En eller flere vedhæftede filer i din videresendte besked downloades før afsendelse."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Vedhæftning kunne ikke gemmes."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Bemærk: En eller flere vedhæftede filer i din videresendte besked downloades før afsendelse."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Besked"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Inviter"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"En eller flere vedhæftede filer kunne ikke videresendes."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Vedhæftet fil er ikke sendt"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> kunne ikke logge ind."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> kunne ikke logge ind."</string> <string name="login_failed_title" msgid="7624349996212476176">"Login mislykkedes"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> b"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Du kan nemt konfigurere en Exchange ActiveSync-konto."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-mail-adresse"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Adgangskode"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Send e-mail fra denne konto som standard"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Send e-mail fra denne konto som standard."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuel opsætning"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Indtast en gyldig e-mailadresse og adgangskode."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dobbeltforekomst af konto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Kontrollerer indstillinger for indgående server ..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kontrollerer indstillinger for udgående server ..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Kontoindstillinger"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Din konto er konfigureret, og der er e-mail på vej."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Din konto er oprettet, og der er e-mail på vej."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Giv kontoen et navn (valgfrit)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Dit navn (vist på udgående beskeder)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Dette felt må ikke være tomt."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Sikkerhedstype"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Kræv login"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Kræver login"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Brugernavn"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Adgangskode"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Kontoindstillinger"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Hvert 15. minut"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Hvert 30. minut"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Hver time"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Send e-mail fra denne konto som standard"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Giv mig besked ved nye e-mails"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synkroniser kontaktpersoner fra denne konto"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synkroniser kalender fra denne konto"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synkroniser e-mails fra denne konto"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Send e-mail fra denne konto som standard."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Underret mig, når der kommer e-mail."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synkroniser kontaktpersoner fra denne konto."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synkroniser kalender fra denne konto."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synkroniser e-mail fra denne konto."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Download vedhæftede filer automatisk, når forbundet til Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Kunne ikke afsluttes"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dage, der skal synkroniseres"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"En måned"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alle"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Anvend kontostandarden"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Brugernavn eller adgangskode er forkert."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Brugernavn eller adgangskode er forkert."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Brugernavn eller adgangskode er forkert."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Brugernavn eller adgangskode er forkert."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Der kan ikke oprettes en sikker forbindelse til serveren."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Der kan ikke oprettes en sikker forbindelse til serveren."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Der kræves et klientcertifikat. Vil du oprette forbindelse til serveren med et klientcertifikat?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certifikatet er ugyldigt eller ikke tilgængeligt."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Serveren reagerede med en fejl. Kontroller dit brugernavn og din adgangskode, og prøv igen."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Klientcertifikat kræves. Vil du oprette forbindelse til serveren med et klientcertifikat?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certifikatet er ugyldigt eller ikke tilgængeligt."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Serveren reagerede med en fejl. Kontroller dit brugernavn og din adgangskode, og prøv igen."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Der kan ikke oprettes forbindelse til serveren."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Der kan ikke oprettes forbindelse til serveren."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS er påkrævet, men understøttes ikke af serveren."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ADVARSEL! Hvis du deaktiverer appen E-mails tilladelse til at administrere din enhed, slettes alle konti i E-mail, der kræver dette, sammen med alle e-mails, kontaktpersoner, kalenderbegivenheder og andre data på disse konti."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Sikkerhedsopdatering"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> kræver, at du opdaterer dine sikkerhedsindstillinger."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Kontoen \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kan ikke synkroniseres på grund af sikkerhedskravene."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Kontoen \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kræver opdatering af sikkerhedsindstillingerne."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Kontoen \"<xliff:g id="ACCOUNT">%s</xliff:g>\" har skiftet sikkerhedsindstillinger. Ingen brugerhandling er påkrævet."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Sikkerhedsopdatering kræves"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Sikkerhedpolitikker er ændret"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Politikker kan ikke opfyldes"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Kontoen \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kræver opdatering af sikkerhedsindstillingerne."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Sikkerhedsopdatering kræves"</string> <string name="account_security_title" msgid="3511543138560418587">"Enhedssikkerhed"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Serveren <xliff:g id="SERVER">%s</xliff:g> kræver, at du giver den tilladelse til eksternt at kontrollere nogle af Android-enhedens sikkerhedsfunktioner."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Rediger detaljer"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Pinkoden eller adgangskoden til skærmlåsen er udløbet."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Skærmlåskoden er udløbet"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Skærmlåskoden er ved at udløbe"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Du skal ændre pinkoden eller adgangskoden til din skærmlås snart, ellers vil data for <xliff:g id="ACCOUNT">%s</xliff:g> vil blive slettet. Vil du ændre dette nu?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Du skal snart ændre skærmlåsens pinkode eller adgangskode, ellers vil dataene på <xliff:g id="ACCOUNT">%s</xliff:g> blive slettet. Vil du ændre den nu?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Skærmlåskoden er udløbet"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Dataene for <xliff:g id="ACCOUNT">%s</xliff:g> er ved at blive slettet fra enheden. Du kan gendanne dem ved at ændre skærmlåsens pinkode eller adgangskode. Vil du ændre dette nu?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Dataene for <xliff:g id="ACCOUNT">%s</xliff:g> slettes på din enhed. Du kan gendanne dem ved at ændre skærmlåsens pinkode eller adgangskode. Vil du ændre den nu?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Vil du kassere ændringer, som ikke er gemt?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Login mislykkedes"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Brugernavn eller adgangskode for <xliff:g id="ACCOUNT">%s</xliff:g> er forkert. Vil du opdatere dem nu?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Brugernavn eller adgangskode for <xliff:g id="ACCOUNT">%s</xliff:g> er forkert. Vil du opdatere dem nu?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Standardkonto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Send e-mail fra denne konto som standard"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Download vedhæftede filer"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Download autom. vedhæftede filer i de seneste beskeder via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-mail-beskeder"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synkroniseringsinterval, meddelelser osv."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Send en meddelelse ved nye e-mails"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Underret i statuslinjen, når der kommer e-mail"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Kontrolfrekvens for indbakke"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Indgående indstillinger"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Brugernavn, adgangskode og indstillinger for indgående server"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Udgående indstillinger"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Brugernavn, adgangskode og indstillinger for udgående server"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Politikker håndhævet"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ingen"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Ikke-understøttede politikker"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ingen"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Forsøg synkronisering"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Tryk her for at synkronisere denne konto"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Kontonavn"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Dit navn"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signatur"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Hurtige svar"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Rediger tekst, som du ofte indsætter, når du skriver e-mails"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Rediger tekst, du ofte indsætter, når du skriver e-mails"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Vedhæft tekst til beskeder, du sender"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Indstillinger for underretninger"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Dataforbrug"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sikkerhedspolitikker"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Rediger hurtigt svar"</string> <string name="save_action" msgid="1988862706623227093">"Gem"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synkroniser kontaktpersoner"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synkroniser kontaktpersoner til denne konto"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synkroniser kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synkroniser begivenhed for konto"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synkroniser kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synkroniser kalender for denne konto"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synkroniser e-mails"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synkroniser e-mail for denne konto"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibration"</string> @@ -421,7 +410,7 @@ <string name="toast_account_not_found" msgid="8144242451730692816">"Kontoen blev ikke fundet. Den er muligvis blevet fjernet."</string> <string name="toast_mailbox_not_found" msgid="4960014581292378895">"Mappen blev ikke fundet. Den kan være blevet fjernet."</string> <string name="provider_note_live" msgid="2995297671709325333">"Det er kun nogle \"Plus\"-konti med POP-adgang, der tillader, at dette program opretter forbindelse. Hvis du ikke kan logge ind med din rigtige e-mailadresse og adgangskode, har du muligvis ikke en betalt \"Plus\"-konto. Åbn webbrowseren igen for at få adgang til disse e-mailkonti."</string> - <string name="provider_note_t_online" msgid="1630642061431427894">"Inden du konfigurerer denne e-mailkonto, skal du gå til T-Onlines website og oprette en adgangskode for e-mailadgang via POP3."</string> + <string name="provider_note_t_online" msgid="1630642061431427894">"Inden du konfigurerer denne e-mailkonto, skal du gå til T-Onlines websted og oprette en adgangskode for e-mailadgang via POP3."</string> <string name="exchange_name" msgid="1190783774800310346">"Exchange"</string> <string name="exchange_name_alternate" msgid="5772529644749041052">"Microsoft Exchange ActiveSync"</string> <string name="system_account_create_failed" msgid="3673792980526246177">"Kontoen kunne ikke oprettes. Prøv igen."</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Venter på resultater"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Nogle servere kan være langsomme."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mapper"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Tillad ikke brug af enheden kamera"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Kræv adgangskode for enheden"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Begræns genbrug af seneste adgangskoder"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Kræv, at adgangskoder udløber"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Kræv, at en inaktiv enheds skærm låses"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Begræns antallet af synkron. kalenderbegivenheder"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Begræns antallet af synkroniserede e-mails"</string> - <string name="quick_1" msgid="3426057697353380951">"Tak!"</string> - <string name="quick_2" msgid="4188036352885736617">"Det passer mig fint!"</string> - <string name="quick_3" msgid="8061819976353395585">"Jeg læser dette senere og vender tilbage til dig."</string> - <string name="quick_4" msgid="3988974084396883051">"Lad os holde et møde for at diskutere dette."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Baggrundssynkronisering for denne konto deaktiveres under roaming."</string> </resources> diff --git a/res/values-da/uploader.xml b/res/values-da/uploader.xml index f2a6f1aa6..cc8f0e854 100644 --- a/res/values-da/uploader.xml +++ b/res/values-da/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Skjul detaljer"</string> <string name="menu_settings" msgid="5088116127086866634">"Indstillinger"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Uploadet %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Upload"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> @@ -105,7 +105,7 @@ <string name="preference_title_videos_upload_connectivity" msgid="4029897303763182477">"Betingelser for upload"</string> <string name="preference_title_videos_upload_connectivity_summary" msgid="2228943790654186152">"Billedernes forbindelsesindstillinger bruges i øjeblikket."</string> <string name="preference_mobile_data_usage_for_photos_only" msgid="8047534381344601018">"Kun billeder via mobilnetværk"</string> - <string name="preference_mobile_data_usage_for_all_media" msgid="4228623171763750182">"Fotos og videoer via mobilnetværk"</string> + <string name="preference_mobile_data_usage_for_all_media" msgid="4228623171763750182">"Billeder og videoer via mobilnetværk"</string> <string name="preference_mobile_data_usage_never" msgid="4887062654163669480">"Kun billeder og videoer via Wi-Fi"</string> <string name="preference_category_title_about" msgid="3001183168471659844">"Om"</string> <string name="preference_title_camera_sync_version" msgid="1590760570503808392">"Øjebl. upload-v."</string> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 3eca4cf28..96b6a5ddc 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"E-Mail-Anhänge lesen"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Ermöglicht der App, Ihre E-Mail-Anhänge zu lesen"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Ermöglicht der App, Ihre E-Mail-Anhänge zu lesen"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Auf Daten des E-Mail-Anbieters zugreifen"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Ermöglicht der App, auf Ihre E-Mail-Datenbank zuzugreifen, einschließlich empfangener und gesendeter Nachrichten, Nutzernamen sowie Passwörtern"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Ermöglicht der App, auf Ihre E-Mail-Datenbank zuzugreifen, einschließlich erhaltener Nachrichten, gesendeter Nachrichten, Nutzernamen und Passwörtern."</string> <string name="app_name" msgid="5815426892327290362">"E-Mail"</string> <string name="compose_title" msgid="427986915662706899">"Schreiben"</string> <string name="debug_title" msgid="5175710493691536719">"Fehler suchen"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Fertig"</string> <string name="create_action" msgid="3062715563215392251">"Neue erstellen"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Löschen"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Keine Kurzantworten"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Keine Kurzantworten"</string> <string name="discard_action" msgid="6532206074859505968">"Verwerfen"</string> <string name="save_draft_action" msgid="6413714270991417223">"Speichern"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Kurzantwort einfügen"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> schrieb:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Zitierten Text einfügen"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Text einfügen"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Fügen Sie mindestens einen Empfänger hinzu."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Sie müssen mindestens einen Empfänger hinzufügen."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Einige E-Mail-Adressen sind ungültig."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Dateianhang zu groß"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Kurzantwort einfügen"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Gespeichert"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stoppen"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Anhang als <xliff:g id="FILENAME">%s</xliff:g> gespeichert."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Speichern nicht möglich"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Mindestens ein Anhang in Ihrer weitergeleiteten Nachricht wird vor dem Senden heruntergeladen."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Anhang nicht gespeichert"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Hinweis: Mindestens ein Anhang in Ihrer weitergeleiteten Nachricht wird vor dem Senden heruntergeladen."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Nachricht"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Einladen"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Mindestens ein Anhang wurde nicht weitergeleitet."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Anhang nicht weitergeleitet"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Anmeldung in <xliff:g id="ACCOUNT_NAME">%s</xliff:g> erfolglos"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Fehler beim Anmelden in <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Anmeldung nicht möglich"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Sie können ein Exchange ActiveSync-Konto in wenigen Schritten einrichten."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-Mail-Adresse"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Passwort"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"E-Mails standardmäßig von diesem Konto senden"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"E-Mails standardmäßig von diesem Konto senden"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuell einrichten"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Geben Sie eine gültige E-Mail-Adresse und ein gültiges Passwort ein."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dupliziertes Konto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Einstellungen des Eingangsservers werden überprüft..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Einstellungen des Ausgangsservers werden überprüft..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Kontoeinrichtung"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Das Konto ist jetzt eingerichtet und die E-Mail ist unterwegs."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ihr Konto ist nun eingerichtet."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Konto benennen (optional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Ihr Name (wird bei ausgehenden Nachrichten angezeigt)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Dieses Feld darf nicht leer sein."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-Server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Sicherheitstyp"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Anmeldung erforderlich"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Anmeldung erforderlich"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nutzername"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Passwort"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Kontoeinrichtung"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Alle 15 Minuten"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Alle 30 Minuten"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Stündlich"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"E-Mails standardmäßig von diesem Konto senden"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Bei neuer E-Mail benachrichtigen"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Kontakte dieses Kontos synchronisieren"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Kalender dieses Kontos synchronisieren"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"E-Mails dieses Kontos synchronisieren"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"E-Mails standardmäßig von diesem Konto senden"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Benachrichtigung bei E-Mail-Eingang"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Kontakte dieses Kontos synchronisieren"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Kalender dieses Kontos synchronisieren"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"E-Mails dieses Kontos synchronisieren"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Anhänge bei WLAN-Verbindung automatisch herunterladen"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Fertigstellen nicht möglich"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Zu synchronisierende Tage"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Ein Monat"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alle"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Kontostandard verwenden"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nutzername oder Passwort ist falsch."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nutzername oder Passwort ist falsch."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nutzername oder Passwort falsch"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nutzername/Password falsch"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Keine sichere Verbindung zum Server möglich"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Keine sichere Verbindung zum Server möglich."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Ein Client-Zertifikat ist erforderlich. Möchten Sie mit einem Client-Zertifikat eine Verbindung zum Server herstellen?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Das Zertifikat ist ungültig oder nicht aufrufbar."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Der Server hat einen Fehler zurückgegeben. Bitte überprüfen Sie Ihren Nutzernamen und Ihr Passwort und versuchen Sie es erneut."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Client-Zertifikat ist erforderlich. Verbindung zu einem Server mit Client-Zertifikat herstellen?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Zertifikat ist ungültig oder nicht aufrufbar."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Der Server hat einen Fehler zurückgegeben. Bitte überprüfen Sie Ihren Nutzernamen und Ihr Passwort und versuchen Sie es erneut."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Derzeit kann keine Verbindung zum Server hergestellt werden."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Keine Verbindung zum Server möglich."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS erforderlich aber nicht von Server unterstützt"</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"Warnung: Wenn Sie die Berechtigung der E-Mail-App zur Verwaltung Ihres Geräts deaktivieren, werden alle E-Mail-Konten, die diese Berechtigung benötigen, mit allen zugehörigen E-Mails, Kontakten, Terminen und anderen Daten gelöscht."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Sicherheitsupdate"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> erfordert, dass Sie Ihre Sicherheitseinstellungen aktualisieren."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Das Konto \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kann aufgrund von Sicherheitsanforderungen nicht synchronisiert werden."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Für das Konto \"<xliff:g id="ACCOUNT">%s</xliff:g>\" müssen die Sicherheitseinstellungen aktualisiert werden."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Die Sicherheitseinstellungen des Kontos \"<xliff:g id="ACCOUNT">%s</xliff:g>\" haben sich geändert. Es sind keine Maßnahmen durch den Nutzer erforderlich."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Sicherheitsupdate erforderlich"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Richtlinien wurden geändert."</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Richtlinien nicht einzuhalten"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Das Konto \"<xliff:g id="ACCOUNT">%s</xliff:g>\" erfordert eine Aktualisierung der Sicherheitseinstellungen."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Sicherheitsupdate erforderlich"</string> <string name="account_security_title" msgid="3511543138560418587">"Gerätesicherheit"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Der Server <xliff:g id="SERVER">%s</xliff:g> fordert die Erlaubnis zur Remote-Steuerung einiger Sicherheitsfunktionen auf Ihrem Android-Gerät an."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Details bearbeiten"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Ihre PIN bzw. Ihr Passwort zum Sperren des Bildschirms ist abgelaufen."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Sperr-Passwort abgelaufen"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Passwort für Bildschirmsperre läuft ab"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Sie müssen Ihre PIN für die Display-Sperre bald ändern, da sonst die Daten für <xliff:g id="ACCOUNT">%s</xliff:g> gelöscht werden. Möchten Sie sie jetzt ändern?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Sie müssen Ihre PIN bzw. Ihr Passwort zum Sperren des Bildschirms bald ändern, sonst werden die Daten für <xliff:g id="ACCOUNT">%s</xliff:g> gelöscht. Jetzt ändern?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Sperr-Passwort abgelaufen"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Die Daten für <xliff:g id="ACCOUNT">%s</xliff:g> werden von Ihrem Gerät gelöscht. Sie können die Daten wiederherstellen, indem Sie Ihre PIN für die Display-Sperre oder Ihr Passwort ändern. Möchten Sie die PIN oder das Passwort jetzt ändern?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Die Daten für <xliff:g id="ACCOUNT">%s</xliff:g> werden von Ihrem Gerät gelöscht. Sie können sie wiederherstellen, indem Sie Ihre PIN bzw. Ihr Passwort zum Sperren des Bildschirms ändern. Jetzt ändern?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Nicht gespeicherte Änderungen verwerfen?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Anmeldung nicht möglich"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Nutzername oder Kennwort für <xliff:g id="ACCOUNT">%s</xliff:g> ist falsch. Möchten Sie die Daten jetzt ändern?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Der Nutzername oder das Passwort für <xliff:g id="ACCOUNT">%s</xliff:g> ist falsch. Jetzt aktualisieren?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Standardkonto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"E-Mails standardmäßig von diesem Konto senden"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Anhänge herunterladen"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Anhänge neuer Nachrichten automatisch über WLAN herunterladen"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-Mail-Benachrichtigung"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synchronisierungshäufigkeit, Benachrichtigungen usw."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Bei neuen E-Mails benachrichtigen"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Bei E-Mail-Eingang Benachrichtigung in der Systemleiste"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Häufigkeit des E-Mail-Abrufs"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Eingehende Nachrichten"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nutzername, Passwort und andere Einstellungen für Eingangsserver"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Ausgehende Nachrichten"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nutzername, Passwort und andere Einstellungen für Ausgangsserver"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Richtlinien durchgesetzt"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Keine"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nicht unterstützte Richtlinien"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Keine"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Synchronisieren"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Hier berühren, um dieses Konto zu synchronisieren"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Kontoname"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Mein Name"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signatur"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Kurzantworten"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Häufig in neue E-Mails eingefügten Text bearbeiten"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Bearbeiten Sie beim Verfassen von E-Mails oft eingefügten Text."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Text an ausgehende Nachrichten anhängen"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Benachrichtigungseinstellungen"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Datenverbrauch"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sicherheitsrichtlinien"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Kurzantwort bearbeiten"</string> <string name="save_action" msgid="1988862706623227093">"Speichern"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Kontakte synchr."</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Kontakte dieses Kontos synchronisieren"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Kalender synchr"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Termin für dieses Kontos synchronisieren"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Kalender synchronisieren"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Kalender dieses Kontos synchronisieren"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"E-Mails synchr."</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"E-Mails dieses Kontos synchronisieren"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibration"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Warten auf Ergebnisse"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Bei einigen Servern benötigen Sie möglicherweise etwas mehr Geduld."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Ordner"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Verwendung der Kamera nicht zulassen"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Geräte-Passwort erforderlich"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Einsatz der letzten Passw. beschränken"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Ablaufen von Passwörtern erforderlich"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Bildschirmsperre für inaktives Gerät"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Anzahl synchronisierter Kalendereinträge begrenzen"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Anzahl synchronisierter E-Mails begrenzen"</string> - <string name="quick_1" msgid="3426057697353380951">"Vielen Dank!"</string> - <string name="quick_2" msgid="4188036352885736617">"Hört sich gut an!"</string> - <string name="quick_3" msgid="8061819976353395585">"Ich lese Ihre Nachricht später und melde mich bei Ihnen."</string> - <string name="quick_4" msgid="3988974084396883051">"Lassen Sie uns das bei einem Meeting besprechen."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Die Hintergrundsynchronisierung ist für dieses Konto während des Roamings deaktiviert."</string> </resources> diff --git a/res/values-de/uploader.xml b/res/values-de/uploader.xml index 3bb1deacf..c8a6f2114 100644 --- a/res/values-de/uploader.xml +++ b/res/values-de/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Details ausblenden"</string> <string name="menu_settings" msgid="5088116127086866634">"Einstellungen"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Hochgeladen: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Hochladen"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 7aa192ec7..713c47cb4 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Ανάγνωση επισυνάψεων μηνύματος ηλεκτρονικού ταχυδρομείου"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Επιτρέπει στην εφαρμογή την ανάγνωση των συνημμένων ηλεκτρονικού ταχυδρομείου."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Επιτρέπει σε αυτήν την εφαρμογή την ανάγνωση των επισυνάψεων μηνυμάτων ηλεκτρονικού ταχυδρομείου."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Πρόσβαση στα δεδομένα παρόχου ηλεκτρονικού ταχυδρομείου"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Επιτρέπει στην εφαρμογή την πρόσβαση στη βάση δεδομένων του ηλεκτρονικού ταχυδρομείου σας, συμπεριλαμβανομένων των ληφθέντων μηνυμάτων, των απεσταλμένων, των ονομάτων χρηστών και των κωδικών πρόσβασης."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Επιτρέπει στην εφαρμογή να έχει πρόσβαση στη βάση δεδομένων του ηλεκτρονικού ταχυδρομείου σας, συμπεριλαμβανομένων των ληφθέντων μηνυμάτων, των απεσταλμένων, των ονομάτων χρηστών και των κωδικών πρόσβασης."</string> <string name="app_name" msgid="5815426892327290362">"Μήνυμα ηλεκτρονικού ταχυδρομείου"</string> <string name="compose_title" msgid="427986915662706899">"Σύνταξη"</string> <string name="debug_title" msgid="5175710493691536719">"Εντοπισμός σφαλμάτων"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Τέλος"</string> <string name="create_action" msgid="3062715563215392251">"Δημιουργία νέου"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Διαγραφή"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Δεν υπάρχουν γρήγορες απαντήσεις."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Δεν υπάρχουν γρήγορες απαντήσεις"</string> <string name="discard_action" msgid="6532206074859505968">"Απόρριψη"</string> <string name="save_draft_action" msgid="6413714270991417223">"Αποθ. πρόχειρου"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Εισαγωγή γρήγ. απάντησης"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"Ο χρήστης <xliff:g id="SENDER">%s</xliff:g> έγραψε:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Συμπερίληψη του αναφερόμενου κειμένου"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Συμπερίληψη κειμένου"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Προσθέστε τουλάχιστον έναν παραλήπτη."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Πρέπει να προσθέσετε τουλάχιστον έναν παραλήπτη."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Ορισμένες διευθύνσεις ηλεκτρονικού ταχυδρομείου δεν είναι έγκυρες."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Πολύ μεγάλο αρχείο για επισύναψη."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Εισαγάγετε γρήγορη απάντηση"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Αποθηκεύτ."</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Διακοπή"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Αποθήκευση επισύναψης ως <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Αδύν. η αποθ. του συνημμένου."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Ένα ή περισσότερα συνημμένα στο προωθημένο μήνυμά σας θα ληφθούν πριν την αποστολή."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Σφάλμα αποθήκευσης επισύναψης."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Σημείωση: Μία ή περισσότερες επισυνάψεις στο προωθημένο μήνυμά σας θα ληφθούν πριν την αποστολή."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Μήνυμα"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Πρόσκληση"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Δεν ήταν δυνατή η προώθηση μίας ή περισσότερων επισυνάψεων."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Η επισύναψη δεν προωθήθηκε"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Η σύνδεση στον λογαριασμό <xliff:g id="ACCOUNT_NAME">%s</xliff:g> δεν ήταν επιτυχής."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Αποτυχία σύνδεσης <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> <string name="login_failed_title" msgid="7624349996212476176">"Δεν ήταν δυνατή η σύνδεση"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Μπορείτε να δημιουργήσετε έναν λογαριασμό Exchange ActiveSync σε λίγα μόλις βήματα."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Διεύθυνση ηλεκτρονικού ταχυδρομείου"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Κωδικός πρόσβασης"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό από προεπιλογή"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό από προεπιλογή."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Μη αυτόματη ρύθμιση"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Πληκτρολογήστε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου και έναν έγκυρο κωδικό πρόσβασης."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Διπλότυπος λογαριασμός"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Έλεγχος ρυθμίσεων διακομιστή εισερχομένων..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Έλεγχος ρυθμίσεων διακομιστή εξερχομένων..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Ρύθμιση λογαριασμού"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Ο λογαριασμός σας ρυθμίστηκε και γίνεται λήψη μηνυμάτων ηλεκτρονικού ταχυδρομείου!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ο λογαριασμός σας ρυθμίστηκε και γίνεται λήψη μηνυμάτων ηλεκτρονικού ταχυδρομείου!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Δώστε σε αυτόν τον λογαριασμό ένα όνομα (προαιρετικό)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Το όνομά σας (προβάλλεται στα εξερχόμενα μηνύματα)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Αυτό το πεδίο δεν μπορεί να είναι κενό."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Διακομιστής SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Θύρα"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Τύπος ασφάλειας"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Να απαιτείται σύνδεση"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Να απαιτείται σύνδεση."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Όνομα χρήστη"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Κωδικός πρόσβασης"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Ρύθμιση λογαριασμού"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Κάθε 15 λεπτά"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Κάθε 30 λεπτά"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Κάθε ώρα"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό από προεπιλογή"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Να ειδοποιούμαι κατά τη λήψη μηνύματος ηλεκτρονικού ταχυδρομείου"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Συγχρονισμός επαφών από αυτόν τον λογαριασμό"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Συγχρονισμός ημερολογίου από αυτόν τον λογαριασμό"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Συγχρονισμός ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό από προεπιλογή."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Να ειδοποιούμαι κατά τη λήψη μηνύματος ηλεκτρονικού ταχυδρομείου."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Συγχρονισμός επαφών από αυτόν τον λογαριασμό."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Συγχρονισμός ημερολογίου από αυτόν τον λογαριασμό."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Συγχρονισμός μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Αυτόματη λήψη συνημμένων κατά τη σύνδεση σε δίκτυο Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Αδυναμία ολοκλήρωσης"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Ημέρες για συγχρονισμό"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Ένας μήνας"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Όλες"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Χρήση των προεπιλογών του λογαριασμού"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Λάθος όνομα χρήστη ή κωδικός πρόσβασης."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Το όνομα χρήστη ή ο κωδικός πρόσβασης είναι λάθος."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Λάθος όνομα χρήστη ή κωδικός πρόσβασης."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Λάθος όνομα χρήστη ή κωδικός πρόσβασης."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Δεν είναι δυνατή η ασφαλής σύνδεση με τον διακομιστή."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Δεν είναι δυνατή η ασφαλής σύνδεση με τον διακομιστή."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Απαιτείται πιστοποιητικό προγράμματος-πελάτη. Θέλετε να συνδεθείτε στο διακομιστή με ένα πιστοποιητικό προγράμματος-πελάτη;"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Το πιστοποιητικό δεν είναι έγκυρο ή δεν είναι δυνατή η πρόσβαση σε αυτό."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Ο διακομιστής ανταποκρίθηκε με σφάλμα. Ελέγξτε το όνομα χρήστη και τον κωδικό πρόσβασης και δοκιμάστε ξανά."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Απαιτείται πιστοποιητικό πελάτη. Να γίνει σύνδεση στο διακομιστή με χρήση πιστοποιητικού πελάτη;"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Το πιστοποιητικό δεν είναι έγκυρο ή δεν είναι δυνατή η πρόσβαση σε αυτό."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Ο διακομιστής απάντησε με σφάλμα. Ελέγξτε το όνομα χρήστη και τον κωδικό πρόσβασης και δοκιμάστε ξανά."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Δεν είναι δυνατή η σύνδεση με τον διακομιστή."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Δεν είναι δυνατή η σύνδεση με τον διακομιστή."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Το TLS απαιτείται αλλά δεν υποστηρίζεται από τον διακομιστή."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η απενεργοποίηση της αρμοδιότητας της εφαρμογής ηλεκτρονικού ταχυδρομείου να διαχειρίζεται τη συσκευή σας, θα διαγράψει όλους τους λογαριασμούς ηλεκτρονικού ταχυδρομείου στους οποίους είναι απαραίτητη, καθώς και τα μηνύματα ηλεκτρονικού ταχυδρομείου, τις επαφές, τα συμβάντα ημερολογίου και άλλα δεδομένα."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Ενημέρωση ασφάλειας"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Ο λογαριασμός <xliff:g id="ACCOUNT">%s</xliff:g> απαιτεί την ενημέρωση των ρυθμίσεων ασφαλείας."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Δεν είναι δυνατός ο συγχρονισμός του Λογαριασμού \"<xliff:g id="ACCOUNT">%s</xliff:g>\" λόγω απαιτήσεων ασφαλείας."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Η ενημέρωση των ρυθμίσεων ασφαλείας είναι απαραίτητη για τον λογαριασμό \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Άλλαξαν οι ρυθμίσεις ασφαλείας για τον Λογαριασμό \"<xliff:g id="ACCOUNT">%s</xliff:g>\". Δεν απαιτείται ενέργεια χρήστη."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Απαιτείται ενημέρωση ασφαλείας"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Οι πολιτικές ασφαλείας άλλαξαν"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Δεν είναι δυνατή η συμμόρφωση με τις πολιτικές ασφαλείας"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Από το λογαριασμό \"<xliff:g id="ACCOUNT">%s</xliff:g>\" απαιτείται ενημέρωση ρυθμίσεων ασφαλείας."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Απαιτείται ενημέρωση ασφαλείας"</string> <string name="account_security_title" msgid="3511543138560418587">"Ασφάλεια συσκευής"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Ο διακομιστής <xliff:g id="SERVER">%s</xliff:g> χρειάζεται την άδειά σας για να πραγματοποιήσει απομακρυσμένο έλεγχο ορισμένων λειτουργιών ασφαλείας της συσκευής σας Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Επεξεργασία λεπτομερειών"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Το PIN ή ο κωδικός πρόσβασης κλειδώματος οθόνης έχουν λήξει."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Ο κωδ. κλειδ. οθόνης έληξε"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Λήγει ο κωδικός κλειδώματος οθόνης"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Θα πρέπει να αλλάξετε σύντομα το PIN ή τον κωδικό πρόσβασης της οθνόνης κλειδώματος, διαφορετικά τα δεδομένα του λογαριασμού <xliff:g id="ACCOUNT">%s</xliff:g> θα διαγραφούν. Θέλετε να το αλλάξετε τώρα;"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Πρέπει να αλλάξετε σύντομα το PIN ή τον κωδικό πρόσβασης κλειδώματος οθόνης, διαφορετικά τα δεδομένα του λογαριασμού <xliff:g id="ACCOUNT">%s</xliff:g> θα διαγραφούν. Θέλετε να το αλλάξετε τώρα;"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Ο κωδικός κλειδώματος οθόνης έληξε"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Γίνεται διαγραφή των δεδομένων του λογαριασμού <xliff:g id="ACCOUNT">%s</xliff:g> από τη συσκευή σας. Μπορείτε να τα επαναφέρετε αλλάζοντας το PIN ή τον κωδικό πρόσβασης της οθόνης κλειδώματος. Θέλετε να το αλλάξετε τώρα;"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Τα δεδομένα του λογαριασμού <xliff:g id="ACCOUNT">%s</xliff:g> διαγράφονται από τη συσκευή σας. Μπορείτε να τα επαναφέρετε αλλάζοντας το PIN ή τον κωδικό πρόσβασης κλειδώματος οθόνης. Θέλετε να τα αλλάξετε τώρα;"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Απόρριψη μη αποθηκευμένων αλλαγών;"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Δεν ήταν δυνατή η σύνδεση"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Το όνομα χρήστη ή ο κωδικός πρόσβασης του λογαριασμού <xliff:g id="ACCOUNT">%s</xliff:g> είναι λάθος. Θέλετε να τα ενημερώσετε τώρα;"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Το όνομα χρήστη ή ο κωδικός πρόσβασης για τον λογαριασμό <xliff:g id="ACCOUNT">%s</xliff:g> είναι λανθασμένα. Θέλετε να τα ενημερώσετε τώρα;"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Προεπιλεγμένος λογαριασμός"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου από αυτόν τον λογαριασμό από προεπιλογή"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Λήψη συνημμένων"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Αυτόματη λήψη συνημμένων πρόσφατων μηνυμάτων μέσω Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Ειδοποιήσεις μηνυμάτων ηλεκτρονικού ταχυδρομείου"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Συχνότητα συγχρονισμού, ειδοποιήσεις, κτλ."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Αποστολή ειδοποίησης κατά τη λήψη μηνύματος ηλεκτρονικού ταχυδρομείου"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Εμφάνιση ειδοποίησης στη γραμμή συστήματος κατά τη λήψη μηνύματος ηλεκτρονικού ταχυδρομείου"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Συχνότητα ελέγχου εισερχομένων"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Ρυθμίσεις εισερχομένων"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Όνομα χρήστη, κωδ. πρόσβ. και άλλες ρυθμίσεις διακομιστή εισερχ."</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Ρυθμίσεις εξερχομένων"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Όνομα χρήστη, κωδ. πρόσβ. και άλλες ρυθμίσεις διακομιστή εξερχ."</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Εφαρμογή πολιτικών"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Κ"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Πολιτικές που δεν υποστηρίζονται"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Κανένα"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Προσπάθεια συγχρονισμού"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Αγγίξτε εδώ για να συγχρονίσετε αυτόν τον λογαριασμό"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Όνομα λογαριασμού"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Το όνομά σας"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Υπογραφή"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Γρήγορες απαντήσεις"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Επεξ. κειμένου που εισάγετε συχνά κατά τη σύνταξη μην. ηλ. ταχ."</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Επεξ. κειμένου που εισάγετε συχνά κατά τη σύνταξη μην. ηλ. ταχ."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Προσάρτηση κειμένου στα μηνύματα που αποστέλλετε"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Ρυθμίσεις ειδοποιήσεων"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Χρήση δεδομένων"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Πολιτικές ασφαλείας"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Επεξεργασία γρήγορης απάντησης"</string> <string name="save_action" msgid="1988862706623227093">"Αποθήκευση"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Συγχρονισμός επαφών"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Συγχρονισμός επαφών για αυτόν τον λογαριασμό"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Συγχρονισμός ημερολογίου"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Συγχρον. συμβ. ημερολ. λογαριασμού"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Συγχρονισμός Ημερολογίου"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Συγχρονισμός ημερολογίου για αυτόν τον λογαριασμό"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Συγχρονισμός ηλεκτρονικού ταχυδρομείου"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Συγχρονισμός μηνυμάτων ηλεκτρονικού ταχυδρομείου για αυτόν τον λογαριασμό"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Δόνηση"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Αναμονή για αποτελέσματα"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Ορισμένοι διακομιστές ενδέχεται να χρειαστούν αρκετό χρόνο."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Φάκελοι"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Να μην επιτρ. η χρήση της κάμ. της συσκ."</string> - <string name="policy_require_password" msgid="7177274900480984702">"Απαιτείται κρυπτογράφηση συσκευής"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Περιορισμός της χρήσης πρόσφατων κωδικών"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Απαιτείται η λήξη των κωδικών πρόσβασης"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Απαιτείται αδρ. συσκ. για κλείδ. οθόνης."</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Περιορισμός αριθμού συγχρον. συμβάντων ημερολογίου"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Περιορισμός αριθμού συγχρον. μηνυμ. ηλ. ταχυδρομ."</string> - <string name="quick_1" msgid="3426057697353380951">"Ευχαριστούμε!"</string> - <string name="quick_2" msgid="4188036352885736617">"Καλή ιδέα!"</string> - <string name="quick_3" msgid="8061819976353395585">"Θα το διαβάσω αργότερα και θα επικοινωνήσω μαζί σου."</string> - <string name="quick_4" msgid="3988974084396883051">"Ας κανονίσουμε μία συνάντηση για να συζητήσουμε αυτό το θέμα."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Ο συγχρονισμός στο παρασκήνιο για αυτόν το λογαριασμό είναι απενεργοποιημένος κατά την περιαγωγή."</string> </resources> diff --git a/res/values-el/uploader.xml b/res/values-el/uploader.xml index 62e6b7ab6..5cc8922ec 100644 --- a/res/values-el/uploader.xml +++ b/res/values-el/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Απόκρυψη λεπτομερειών"</string> <string name="menu_settings" msgid="5088116127086866634">"Ρυθμίσεις"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Μεταφορτώθηκαν %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Λογαριασμός"</string> <string name="upload" msgid="2615541458361216022">"Μεταφόρτωση"</string> <string name="ok" msgid="2516349681897895312">"ΟΚ"</string> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 9b176bd48..7ba128b08 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Read email attachments"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Allows the app to read your email attachments."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Allows this application to read your email attachments."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Access email provider data"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Allows the app to access your email database, including received messages, sent messages, usernames and passwords."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Allows this application to access your email database, including received messages, sent messages, usernames and passwords."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Compose"</string> <string name="debug_title" msgid="5175710493691536719">"Debug"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Done"</string> <string name="create_action" msgid="3062715563215392251">"Create new"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Delete"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"No quick responses."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"No quick responses"</string> <string name="discard_action" msgid="6532206074859505968">"Discard"</string> <string name="save_draft_action" msgid="6413714270991417223">"Save draft"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Insert quick response"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> wrote:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Include quoted text"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Include text"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Add at least one recipient."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"You must add at least one recipient."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Some email addresses are invalid."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"File too large to attach."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Insert quick response"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Saved"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stop"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Attachment saved as <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Couldn\'t save attachment."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"One or more attachments in your forwarded message will be downloaded prior to sending."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Couldn\'t save the attachment."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Note: One or more attachments in your forwarded message will be downloaded prior to sending."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Message"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invite"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Could not forward one or more attachments"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Attachment not forwarded"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> sign-in unsuccessful."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> sign-in failed."</string> <string name="login_failed_title" msgid="7624349996212476176">"Couldn\'t sign in"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"You can set up an Exchange ActiveSync account in just a few steps."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Email address"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Password"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Send emails from this account by default"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Send email from this account by default."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manual setup"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Type a valid email address and password."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplicate Account"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Checking incoming server settings…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Checking outgoing server settings…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Account setup"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Your account is set up and emails are on their way!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Your account is set up and email is on its way!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Give this account a name (optional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Your name (displayed on outgoing messages)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"This field can\'t be blank."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Security type"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Require sign-in"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Require sign-in."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Username"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Password"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Account setup"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Every 15 minutes"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Every 30 minutes"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Every hour"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Send emails from this account by default"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Notify me when emails arrive"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sync contacts from this account"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sync calendar from this account"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sync emails from this account"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Send email from this account by default."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Notify me when email arrives."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sync contacts from this account."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sync calendar from this account."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sync email from this account."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automatically download attachments when connected to Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Couldn\'t finish"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Days to sync"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"One month"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"All"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Use account\'s default"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Your username or password is incorrect."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Username or password is incorrect."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Username or password incorrect."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Username or password incorrect."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Can\'t safely connect to server."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Can\'t safely connect to server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"A client certificate is required. Do you want to connect to the server with a client certificate?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"The certificate is invalid or inaccessible."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"The server responded with an error. Check your username and password, then try again."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Client certificate is required. Connect to server with client certificate?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificate is invalid or inaccessible."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"The server responded with an error. Check your username and password and then try again."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Can\'t connect to server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Can\'t connect to server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS required but not supported by server."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"WARNING: Deactivating the Email app\'s authority to administer your device will delete all email accounts that require it, along with their email, contacts, calendar events and other data."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Security update"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> requires you to update your security settings."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" can\'t be synced due to security requirements."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requires a security-settings update."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" has changed its security settings; no user action is required."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Security update required"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Security policies have changed"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Security policies can\'t be met"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requires security settings update."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Security update required"</string> <string name="account_security_title" msgid="3511543138560418587">"Device Security"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"The server <xliff:g id="SERVER">%s</xliff:g> requires that you allow it to remotely control some security features of your Android device."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Edit details"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Your lock-screen PIN or password has expired."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Lock-screen password expired"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Lock-screen password expiring"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"You need to change your lock screen PIN or password soon or the data for <xliff:g id="ACCOUNT">%s</xliff:g> will be erased. Do you want to change it now?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"You must change your lock-screen PIN or password soon or the data for <xliff:g id="ACCOUNT">%s</xliff:g> will be erased. Change it now?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Lock-screen password expired"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"The data for <xliff:g id="ACCOUNT">%s</xliff:g> is being erased from your device. You can restore it by changing your lock screen PIN or password. Do you want to change it now?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"The data for <xliff:g id="ACCOUNT">%s</xliff:g> is being erased from your device. You can restore it by changing your lock-screen PIN or password. Change it now?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Discard unsaved changes?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Couldn\'t sign in"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"The username or password for <xliff:g id="ACCOUNT">%s</xliff:g> is incorrect. Do you want to update them now?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"The username or password for <xliff:g id="ACCOUNT">%s</xliff:g> is incorrect. Update them now?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Default account"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Send email from this account by default"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Download attachments"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Auto-download attachments to recent messages via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Email notifications"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sync frequency, notifications, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Send notification when emails arrive"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notify in System bar when emails arrive"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Inbox check frequency"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Incoming settings"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Username, password and other incoming server settings"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Outgoing settings"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Username, password and other outgoing server settings"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Policies enforced"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"None"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Unsupported policies"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"None"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Attempt sync"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Touch here to sync this account"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Account name"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Your name"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signature"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Quick responses"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edit text that you frequently insert when composing emails"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edit text that you frequently insert when composing emails"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Append text to messages that you send"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Notification settings"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Data usage"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Security policies"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Edit quick response"</string> <string name="save_action" msgid="1988862706623227093">"Save"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sync contacts"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sync contacts for this account"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sync calendar"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sync calendar event for this account"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sync Calendar"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sync calendar for this account"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sync Email"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sync email for this account"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrate"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Waiting for results"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Some servers may take a long time."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Folders"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Disallow use of the device\'s camera"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Require device password"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Restrict the reuse of recent passwords"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Require passwords to expire"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Require an idle device to lock its screen"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limit the number of calendar events synced"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limit the number of emails synced"</string> - <string name="quick_1" msgid="3426057697353380951">"Thanks!"</string> - <string name="quick_2" msgid="4188036352885736617">"Sounds good to me!"</string> - <string name="quick_3" msgid="8061819976353395585">"I\'ll read this later and get back to you."</string> - <string name="quick_4" msgid="3988974084396883051">"Let\'s set up a meeting to discuss this."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Background sync for this account is disabled while roaming."</string> </resources> diff --git a/res/values-en-rGB/uploader.xml b/res/values-en-rGB/uploader.xml index 884d92385..17bcf9267 100644 --- a/res/values-en-rGB/uploader.xml +++ b/res/values-en-rGB/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Hide Details"</string> <string name="menu_settings" msgid="5088116127086866634">"Settings"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Uploaded %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Account"</string> <string name="upload" msgid="2615541458361216022">"Upload"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index c49ed8495..69b35adf1 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Leer archivos adjuntos de correo"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permite a la aplicación leer los archivos adjuntos de tu correo."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permite a esta aplicación leer los archivos adjuntos de tus correos electrónicos."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Acceder a los datos del proveedor de correo"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permite que la aplicación acceda a la base de datos de tu correo, como mensajes recibidos, mensajes enviados, nombres de usuario y contraseñas."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permite que la aplicación acceda a la base de datos de tu correo, como mensajes recibidos, mensajes enviados, nombres de usuario y contraseñas."</string> <string name="app_name" msgid="5815426892327290362">"Correo"</string> <string name="compose_title" msgid="427986915662706899">"Redactar"</string> <string name="debug_title" msgid="5175710493691536719">"Depurar"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Finalizado"</string> <string name="create_action" msgid="3062715563215392251">"Crear una nueva respuesta rápida"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Eliminar"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"No hay respuestas rápidas."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"No hay respuestas rápidas."</string> <string name="discard_action" msgid="6532206074859505968">"Descartar"</string> <string name="save_draft_action" msgid="6413714270991417223">"Guardar borrador"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Insertar respuesta rápida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> escribió:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Incluir el texto citado"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Incluir texto"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Agrega al menos un destinatario."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Debes agregar al menos un destinatario."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Algunas direcciones de correo no son válidas."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"El archivo es demasiado grande para adjuntarlo."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Insertar respuesta rápida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Guardado"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Detener"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Archivo adj guardado como <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Error al guardar el adjunto"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Se descargarán uno o más archivos adjuntos de tu mensaje reenviado antes de enviar."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"No se pudo guardar el archivo adjunto."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota: Se descargarán uno o más archivos adjuntos de tu mensaje reenviado antes de enviar."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mensaje"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invitar"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"No se pudieron enviar uno o más adjuntos."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"No se reenvió el archivo adjunto"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Acceso a <xliff:g id="ACCOUNT_NAME">%s</xliff:g> sin éxito"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Error al acceder a <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> <string name="login_failed_title" msgid="7624349996212476176">"No se ha podido acceder."</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Puedes configurar una cuenta de Exchange ActiveSync en pocos pasos."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Dirección de correo"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Contraseña"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Enviar correo desde esta cuenta de forma predeterminada"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Enviar mensaje de correo desde esta cuenta de forma predeterminada."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuración manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Escribe una dirección de correo y contraseña válidas."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Cuenta duplicada"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Comprobando configuración del servidor entrante…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Comprobando configuración del servidor saliente…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuración de la cuenta"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Se ha configurado tu cuenta y el correo está en camino."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Se ha configurado tu cuenta, ¡y el correo está en camino!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Asigna un nombre a esta cuenta (opcional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Tu nombre (mostrado en mensajes salientes)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Este campo no puede estar vacío."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Servidor SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Puerto"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipo de seguridad"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Requiere acceso"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Requiere inicio de sesión."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nombre de usuario"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Contraseña"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuración de la cuenta"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Cada 15 minutos"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Cada 30 minutos"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Cada hora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Enviar correo desde esta cuenta de forma predeterminada"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Avisarme cuando llegue un correo"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronizar contactos desde esta cuenta"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronizar el calendario desde esta cuenta"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronizar el correo desde esta cuenta"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Enviar mensaje de correo desde esta cuenta de forma predeterminada."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Notificarme cuando llegue un mensaje de correo."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronizar contactos desde esta cuenta"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincroniza el calendario desde esta cuenta"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronizar el correo desde esta cuenta"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Descargar los archivos adjuntos automáticamente al conectarte a Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"No se pudo terminar"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Período de sincronización"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Un mes"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Todos"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Utilizar la configuración predeterminada de la cuenta."</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"El nombre de usuario o la contraseña son incorrectos."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nombre de usuario o contraseña incorrectos "\n" (<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nombre de usuario o contraseña incorrecta."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nombre de usuario o contraseña incorrecta."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"No se puede conectar de forma segura al servidor."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"No se puede conectar de forma segura al servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Se necesita un certificado de cliente. ¿Quieres conectarte al servidor con un certificado de cliente?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"El certificado no es válido o es inaccesible."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"El servidor ha devuelto un error. Verifica tu nombre de usuario y contraseña e inténtalo de nuevo."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Se requiere un certificado de cliente. ¿Deseas conectarte al servidor con un certificado de cliente?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificado no válido o inaccesible."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"El servidor ha devuelto un error. Verifica tu nombre de usuario y contraseña e inténtalo de nuevo."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"No se puede conectar al servidor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"No se puede conectar al servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Se requiere TLS pero el servidor no la admite."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ADVERTENCIA: si desactivas la autoridad de la aplicación de correo para administrar tu dispositivo, se eliminarán todas las cuentas de correo que la requieran, así como sus mensajes, contactos, eventos de calendario y otros datos."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Actualización de seguridad"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> requiere que actualices tu configuración de seguridad."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"No se puede sincronizar la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" debido a diferentes requisitos de seguridad."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Debe actualizarse la configuración de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Se modificó la configuración de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\". El usuario no debe tomar ninguna medida."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Act. de seguridad requerida"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Políts. seguridad modificadas"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Falta en políts. de seguridad"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"La cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requiere que se actualice la configuración de seguridad."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Se requiere actualizar Seguridad"</string> <string name="account_security_title" msgid="3511543138560418587">"Seguridad del dispositivo"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"El servidor <xliff:g id="SERVER">%s</xliff:g> requiere tu permiso para controlar de forma remota algunas funciones de seguridad en tu dispositivo Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Editar detalles"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Tu PIN o contraseña de bloqueo de pantalla expiró."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"La contraseña de bloqueo de pantalla expiró"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"La contraseña de bloqueo de pantalla expiró"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Debes cambiar el PIN o la contraseña de la pantalla de bloqueo lo antes posible o se eliminarán los datos de <xliff:g id="ACCOUNT">%s</xliff:g>. ¿Quieres cambiarlos ahora?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Debes cambiar su PIN o contraseña de bloqueo de pantalla pronto, o se eliminarán los datos de <xliff:g id="ACCOUNT">%s</xliff:g>. ¿Deseas cambiarla ahora?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"La contraseña de bloqueo de pantalla expiró"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Los datos de <xliff:g id="ACCOUNT">%s</xliff:g> se eliminarán de su dispositivo. Puedes restaurarlo al cambiar tu PIN o tu contraseña de bloqueo de pantalla. ¿Deseas cambiarlos ahora?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Los datos de <xliff:g id="ACCOUNT">%s</xliff:g> se eliminarán de su dispositivo. Puedes restaurarlo al cambiar tu PIN o contraseña de bloqueo de pantalla. ¿Deseas cambiarla ahora?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"¿Descartar cambios sin guardar?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"No se pudo acceder"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"El nombre de usuario o la contraseña de <xliff:g id="ACCOUNT">%s</xliff:g> son incorrectos. ¿Quieres actualizarlos ahora?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"El nombre de usuario o la contraseña de <xliff:g id="ACCOUNT">%s</xliff:g>no es correcta. ¿Deseas actualizarlos ahora?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Cuenta predeterminada"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Enviar mensaje de correo desde esta cuenta de forma predeterminada"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Descargar archivos adjuntos"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Descarga automática por Wi-Fi de los adjuntos de msjs. recientes"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificaciones de correo"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frecuencia de sincronización, notificaciones, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Enviar una notificación cuando llegue el correo"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notificar en la barra de estado cuando llegue un correo"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frecuencia de verificación de bandeja de entrada"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Configuración del servidor entrante"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nombre de usuario, contraseña y otras configuraciones de servidor de entrada"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Configuración del servidor saliente"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nombre de usuario, contraseña y otras configuraciones de servidor de salida"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Políticas en vigencia"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ninguna"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Políticas incompatibles"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ninguna"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Sincronizar esta cuenta"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Toca para sincronizar esta cuenta."</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nombre de la cuenta"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Tu nombre"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Firma"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respuestas rápidas"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edita el texto que sueles usar al redactar correos electrónicos."</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edita el texto que a menudo insertas en los correos electrónicos que redactas."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Agrega texto a los mensajes que envíes"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Configuración de notificación"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Uso de datos"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Políticas de seguridad"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Editar respuesta rápida"</string> <string name="save_action" msgid="1988862706623227093">"Guardar"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizar contactos"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronizar contactos de esta cuenta"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizar calendario"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sincr. evento calen. de esta cuenta"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronizar calendario"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronizar el calendario de esta cuenta"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronizar correo"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronizar el correo de esta cuenta"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrar"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Esperando los resultados..."</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Algunos servidores pueden tardar mucho tiempo."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Carpetas"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"No usar la cámara del dispositivo"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Requerir la contraseña del dispositivo"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Limitar la reutilización de contraseñas"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Forzar la caducidad de las contraseñas"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Bloquear pant. de dispositivo inactivo"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitar eventos del calendario que se sincronizan"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitar los correos que se sincronizan"</string> - <string name="quick_1" msgid="3426057697353380951">"¡Gracias!"</string> - <string name="quick_2" msgid="4188036352885736617">"Me parece bien."</string> - <string name="quick_3" msgid="8061819976353395585">"Lo leeré más adelante y me pondré en contacto contigo."</string> - <string name="quick_4" msgid="3988974084396883051">"Vamos a convocar a una reunión para tratar esto."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Se ha inhabilitado la sincronización en segundo plano de esta cuenta en itinerancia."</string> </resources> diff --git a/res/values-es-rUS/uploader.xml b/res/values-es-rUS/uploader.xml index 5dda4d043..b3d583920 100644 --- a/res/values-es-rUS/uploader.xml +++ b/res/values-es-rUS/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ocultar detalles"</string> <string name="menu_settings" msgid="5088116127086866634">"Configuración"</string> <string name="format_date_uploaded" msgid="803752037646090928">"%s cargados"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Cuenta"</string> <string name="upload" msgid="2615541458361216022">"Cargar"</string> <string name="ok" msgid="2516349681897895312">"Aceptar"</string> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 6a3bc8402..f3207b321 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Leer archivos adjuntos de correos electrónicos"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permite que la aplicación consulte los archivos adjuntos de los correos electrónicos."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permite que la aplicación consulte los archivos adjuntos de los mensajes de correo."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Acceder a los datos del proveedor de correo electrónico"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permite que la aplicación acceda a la base de datos de tu correo electrónico, incluidos los mensajes recibidos, los mensajes enviados, los nombres de usuario y las contraseñas."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permite que la aplicación acceda a la base de datos de tu correo electrónico, incluidos los mensajes recibidos, los mensajes enviados, los nombres de usuario y las contraseñas."</string> <string name="app_name" msgid="5815426892327290362">"Correo"</string> <string name="compose_title" msgid="427986915662706899">"Redactar"</string> <string name="debug_title" msgid="5175710493691536719">"Depurar"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Listo"</string> <string name="create_action" msgid="3062715563215392251">"Crear nueva"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Eliminar"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"No hay respuestas rápidas."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"No hay respuestas rápidas"</string> <string name="discard_action" msgid="6532206074859505968">"Descartar"</string> <string name="save_draft_action" msgid="6413714270991417223">"Guardar borrador"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Usar respuesta rápida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> wrote:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Incluir texto citado"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Incluir texto"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Añade al menos un destinatario."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Debes especificar, al menos, un destinatario."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Algunas direcciones de correo electrónico no son válidas."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"El archivo es demasiado grande para adjuntarlo."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Usar respuesta rápida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Guardado"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Detener"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Adjunto guardado como <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Error al guardar el adjunto"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Uno o varios de los archivos adjuntos del mensaje reenviado se descargarán antes de enviarse."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Error al guardar archivo adjunto"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota: uno o varios de los archivos adjuntos del mensaje reenviado se descargarán antes de enviarse."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mensaje"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invitación"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Error al enviar uno o varios archivos adjuntos"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Archivo adjunto no reenviado"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Error al iniciar sesión en <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Error al iniciar sesión en <xliff:g id="ACCOUNT_NAME">%s</xliff:g>"</string> <string name="login_failed_title" msgid="7624349996212476176">"Error al iniciar sesión"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Puedes configurar una cuenta de Exchange ActiveSync en pocos pasos."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Dirección de correo electrónico"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Contraseña"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Enviar correo desde esta cuenta de forma predeterminada"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Enviar correo electrónico desde esta cuenta de forma predeterminada"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Conf. manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Introduce una dirección de correo electrónico y una contraseña válidas."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Cuenta duplicada"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Comprobando la configuración del servidor de entrada..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Comprobando la configuración del servidor de salida..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuración de cuenta"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Tu cuenta ya está configurada y en breve verás tu correo."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Tu cuenta ya está configurada y en breve verás tu correo"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Asignar un nombre a esta cuenta (opcional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Tu nombre (aparece en los mensajes enviados)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Este campo no puede estar vacío."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Servidor SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Puerto"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipo de seguridad"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Solicitar inicio de sesión"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Acceso obligatorio"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nombre de usuario"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Contraseña"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuración de cuenta"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Cada 15 minutos"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Cada 30 minutos"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Cada hora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Enviar correo electrónico desde esta cuenta de forma predeterminada"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Notificarme cuando llegue un correo electrónico"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronizar contactos de esta cuenta"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronizar calendario de esta cuenta"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronizar correo de esta cuenta"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Enviar correo electrónico desde esta cuenta de forma predeterminada"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Avisarme cuando llegue un correo electrónico"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronizar contactos desde esta cuenta"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronizar calendario desde esta cuenta"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronizar mensajes de correo procedentes de esta cuenta"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Descargar adjuntos automáticamente al conectar a una red WiFi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Error al completar la configuración"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Días para sincronizar"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Un mes"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Todo"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Predeterminada de cuenta"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nombre de usuario o contraseña incorrectos"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nombre de usuario o contraseña incorrectos"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nombre de usuario o contraseña incorrecta"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nombre de usuario o contraseña incorrecta"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"No se puede establecer conexión de forma segura con el servidor."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"No se puede establecer conexión de forma segura con el servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Se necesita un certificado de cliente. ¿Quieres conectarte al servidor con un certificado de cliente?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"El certificado no es válido o no se puede acceder a él."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"El servidor ha devuelto un error. Comprueba tu nombre de usuario y tu contraseña y vuelve a intentarlo."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Se requiere un certificado de cliente. ¿Quieres conectarte al servidor con un certificado de cliente?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"El certificado no es válido o no se puede acceder a él."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"El servidor ha devuelto un error. Comprueba tu nombre de usuario y tu contraseña y vuelve a intentarlo."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"No se puede establecer conexión con el servidor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"No se puede establecer conexión con el servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"El protocolo TLS es obligatorio, pero el servidor no lo admite."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ADVERTENCIA: si desactivas el permiso de la aplicación Correo para administrar tu dispositivo, se eliminarán todas las cuentas de esta aplicación que requieran su uso, así como las direcciones de correo electrónico, los contactos, los eventos de calendario y otro tipo de datos."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Actualización de seguridad"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> requiere que actualices la configuración de seguridad."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Los requisitos de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" no permiten su sincronización."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Es necesario actualizar la configuración de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Se ha modificado la configuración de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" (no es necesaria la intervención del usuario)."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Actualización seguridad necesaria"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Políticas de seguridad modificadas"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Error al cumplir políticas seguridad"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Es necesario actualizar la configuración de seguridad de la cuenta \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Actualización seguridad necesaria"</string> <string name="account_security_title" msgid="3511543138560418587">"Seguridad del dispositivo"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Es necesario que permitas que el servidor <xliff:g id="SERVER">%s</xliff:g> controle de forma remota algunas funciones de seguridad de tu dispositivo Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Editar detalles"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"La contraseña o el PIN de la pantalla de bloqueo ha caducado."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Contraseña bloqueo caducada"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Contraseña bloqueo pantalla va a caducar"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Debes cambiar la contraseña o el PIN de la pantalla de bloqueo lo antes posible para que no se borren los datos de <xliff:g id="ACCOUNT">%s</xliff:g>. ¿Quieres hacerlo ahora?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Deberás modificar la contraseña o el PIN de la pantalla de bloqueo en breve o se borrarán los datos de <xliff:g id="ACCOUNT">%s</xliff:g>. ¿Quieres cambiarla ahora?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Contraseña bloqueo caducada"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Los datos de <xliff:g id="ACCOUNT">%s</xliff:g> se están borrando del dispositivo. Para restaurarlos, modifica la contraseña o el PIN de la pantalla de bloqueo. ¿Quieres hacerlo ahora?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Los datos de <xliff:g id="ACCOUNT">%s</xliff:g> se están borrando del dispositivo. Para restaurarlos, modifica la contraseña o el PIN de la pantalla de bloqueo. ¿Quieres cambiarlos ahora?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"¿Quieres descartar los cambios no guardados?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Error al iniciar sesión"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"El nombre de usuario o la contraseña de <xliff:g id="ACCOUNT">%s</xliff:g> son incorrectos. ¿Quieres actualizarlos ahora?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"El nombre de usuario o la contraseña de <xliff:g id="ACCOUNT">%s</xliff:g> son incorrectos. ¿Quieres actualizarlos ahora?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Cuenta predeterminada"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Enviar correo electrónico desde esta cuenta de forma predeterminada"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Descargar adjuntos"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Descarga automática de adjuntos de mensajes recientes por Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificaciones de correo"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frecuencia de sincronización, notificaciones, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Enviar notificación cuando llegue un correo electrónico"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notificar en barra del sistema cuando llegue un correo electrónico"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Comprobar si hay mensajes nuevos"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Ajustes de entrada"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nombre usuario, contraseña y otros ajustes servidor de entrada"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Ajustes de salida"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nombre usuario, contraseña y otros ajustes servidor de salida"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Políticas aplicadas"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ninguno"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Políticas no admitidas"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ninguno"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Intentar sincronización"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Toca para sincronizar esta cuenta."</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nombre de cuenta"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Tu nombre"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Firma"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respuestas rápidas"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edita texto que suelas usar al redactar correos electrónicos"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edita texto que suelas usar en mensajes de correo electrónico."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Añadir texto al final de los mensajes enviados"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Ajustes de notificaciones"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Uso de datos"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Políticas de seguridad"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Editar respuesta rápida"</string> <string name="save_action" msgid="1988862706623227093">"Guardar"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizar contactos"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronizar contactos de esta cuenta"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizar calendario"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sincronizar eventos de calendario para esta cuenta"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronizar calendario"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronizar calendario de esta cuenta"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronizar correo"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronizar mensajes de correo electrónico de esta cuenta"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrar"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Esperando resultados"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Algunos servidores pueden tardar mucho tiempo."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Carpetas"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"No permitir usar cámara del dispositivo"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Solicitar contraseña del dispositivo"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Restringir nuevo uso contraseñas recientes"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Forzar vencimiento de contraseñas"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Dispositivo inactivo necesario para bloqueo"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitar número de eventos que se sincronizan"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitar número de correos que se sincronizan"</string> - <string name="quick_1" msgid="3426057697353380951">"¡Gracias!"</string> - <string name="quick_2" msgid="4188036352885736617">"Me parece bien, ¡gracias!"</string> - <string name="quick_3" msgid="8061819976353395585">"Lo leeré más tarde y te enviaré una respuesta."</string> - <string name="quick_4" msgid="3988974084396883051">"Vamos a reunirnos para hablar de este tema."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Se ha inhabilitado la sincronización en segundo plano de esta cuenta en itinerancia."</string> </resources> diff --git a/res/values-es/uploader.xml b/res/values-es/uploader.xml index c706c4aa9..fb6ff2ae0 100644 --- a/res/values-es/uploader.xml +++ b/res/values-es/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ocultar detalles"</string> <string name="menu_settings" msgid="5088116127086866634">"Ajustes"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Subido el: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Cuenta"</string> <string name="upload" msgid="2615541458361216022">"Subir"</string> <string name="ok" msgid="2516349681897895312">"Aceptar"</string> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index f34e15360..8ba8c1969 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Loe meili manuseid"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Võimaldab rakendusel lugeda teie meilisõnumite manuseid."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Võimaldab sellel rakendusel lugeda teie meilimanuseid."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Juurdepääs e-posti teenusepakkuja andmetele"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Võimaldab rakendusel pääseda teie meiliandmebaasi, sealhulgas vastuvõetud ja saadetud sõnumite, kasutajanimede ning paroolide juurde."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Lubab sellel rakendusel juurde pääseda teie e-posti andmebaasile, sh vastuvõetud sõnumitele, saadetud sõnumitele, kasutajanimedele ja paroolidele."</string> <string name="app_name" msgid="5815426892327290362">"E-post"</string> <string name="compose_title" msgid="427986915662706899">"Koostamine"</string> <string name="debug_title" msgid="5175710493691536719">"Silumine"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Valmis"</string> <string name="create_action" msgid="3062715563215392251">"Loo uus"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Kustuta"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Kiirvastuseid pole."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Kiireid vastuseid pole"</string> <string name="discard_action" msgid="6532206074859505968">"Loobu"</string> <string name="save_draft_action" msgid="6413714270991417223">"Salvesta mustand"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Sisesta kiirvastus"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> kirjutas:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Osundatud teksti lisamine"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Lisa tekst"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Lisage vähemalt üks saaja."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Peate lisama vähemalt ühe saaja."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Mõned e-posti aadressid on kehtetud."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Fail on manustamiseks liiga suur."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Kiirvastuse sisestamine"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Salvestatud"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Peata"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Manus salvestatakse nimega <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Manust ei saanud salvestada."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Vähemalt üks edastatava sõnumi manus laaditakse enne saatmist alla."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Ei saanud manust salvestada."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Märkus: üks või mitu manust edastatud sõnumis laaditakse enne saatmist alla."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Sõnum"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Kutsu"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Ühe või mitme manuse edastamine ebaõnnestus."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Manust ei edastatud"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Kontole <xliff:g id="ACCOUNT_NAME">%s</xliff:g> sisselogimine ebaõnnestus."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Kasutaja <xliff:g id="ACCOUNT_NAME">%s</xliff:g> sisselogimine ebaõnnestus."</string> <string name="login_failed_title" msgid="7624349996212476176">"Sisselogimine ebaõnnestus"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Exchange ActiveSynci konto saate seadistada vaid mõne sammuga."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-posti aadress"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Parool"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Saada meilid vaikimisi sellelt kontolt"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Saada meilid vaikimisi sellelt kontolt."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Seadista käsitsi"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Sisestage kehtiv e-posti aadress ja parool."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplikaatkonto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Sissetuleva serveri seadete kontrollimine ..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Väljuva serveri seadete kontrollimine ..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Konto seadistamine"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Teie konto on seadistatud ja meilid on tulekul."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Teie konto on seadistatud ja e-post on loomisel."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Anna sellele kontole nimi (valikuline)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Teie nimi (kuvatakse väljuvates sõnumites)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"See väli ei tohi tühi olla."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Turvalisuse tüüp"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Sisselogimine on nõutav"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Nõua sisselogimist."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Kasutajanimi"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Parool"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Konto seadistamine"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Iga 15 minuti järel"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Iga 30 minuti järel"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Kord tunnis"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Saada meilid vaikimisi sellelt kontolt"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Teavita mind meili saabumisest"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sünkrooni selle konto kontaktid"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sünkrooni selle konto kalender"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sünkrooni selle konto meilid"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Saada meilid vaikimisi sellelt kontolt."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Teavita mind meili saabumisest."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sünkrooni selle konto kontaktid."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sünkrooni selle konto kalender."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sünkrooni selle konto meil."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Manuste automaatne allalaadimine WiFi-ühenduse olemasolul"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Ei saanud lõpetada"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Päevi sünkroonimiseks"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Üks kuu"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Kõik"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Konto vaikeseade kasutam."</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Kasutajanimi või parool on vale."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Kasutajanimi või parool on vale."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Kasutajanimi või parool on vale."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Kasutajanimi või parool on vale."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Serveriga ei saa turvaliselt ühendust."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Serveriga ei saa turvaliselt ühendust."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Kliendi sertifikaat on nõutav. Kas soovite luua ühenduse serveriga kliendi sertifikaadi abil?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifikaat on kehtetu või juurdepääsmatu."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Server saatis veateate. Kontrollige kasutajanime ja parooli ning proovige uuesti."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Vajalik on kliendi sertifikaat. Kas soovite kliendi sertifikaadiga luua ühenduse serveriga?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikaat on kehtetu või juurdepääsmatu."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Server saatis veateate. Kontrollige kasutajanime ja parooli ning proovige uuesti."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Serveriga ei saa ühendust."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Serveriga ei saa ühendust."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS on vajalik, kuid server ei toeta seda."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"HOIATUS: meilirakenduse volituse inaktiveerimine seadme haldamiseks kustutab kõik meilikontod, mis seda nõuavad, sh nende meilid, kontaktid, kalendrisündmused ja muud andmed."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Turvavärskendus"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> nõuab, et värskendaksite oma turvaseadeid."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Kontot „<xliff:g id="ACCOUNT">%s</xliff:g>” ei saa turvanõuete tõttu sünkroonida."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Konto „<xliff:g id="ACCOUNT">%s</xliff:g>” vajab turvaseadete värskendamist."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Konto „<xliff:g id="ACCOUNT">%s</xliff:g>” muutis turvaseadeid. Kasutaja ei pea midagi tegema."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Nõutav turvavärskendus"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Turvaeeskirjad on muutunud"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Turbe-eeskirju ei saa täita"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Konto „<xliff:g id="ACCOUNT">%s</xliff:g>” vajab turvaseadete värskendamist."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Vaja on turvavärskendust"</string> <string name="account_security_title" msgid="3511543138560418587">"Seadme turvalisus"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Server <xliff:g id="SERVER">%s</xliff:g> nõuab mõnede teie Android-seadme turvafunktsioonide kaugjuhtimise lubamist."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Muuda üksikasju"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Teie ekraaniluku PIN-kood või parool on aegunud."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Ekraaniluku parool on aegunud"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Ekraaniluku parool on aegumas"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Teil tuleb varsti lukustuskuva PIN-koodi või parooli muuta, vastasel korral kustutatakse konto <xliff:g id="ACCOUNT">%s</xliff:g> andmed. Kas soovite kohe muuta?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Peate ekraaniluku PIN-koodi või parooli varsti muutma või konto <xliff:g id="ACCOUNT">%s</xliff:g> andmed kustutatakse. Kas muuta kohe?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Ekraaniluku parool on aegunud"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Konto <xliff:g id="ACCOUNT">%s</xliff:g> andmed kustutatakse teie seadmest. Taastamiseks muutke oma lukustuskuva PIN-koodi või parooli. Kas soovite kohe muuta?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Konto <xliff:g id="ACCOUNT">%s</xliff:g> andmeid kustutatakse seadmest. Taastada saate, muutes ekraaniluku PIN-koodi või parooli. Kas muuda seda kohe?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Kas loobute salvestamata muudatustest?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Sisselogimine ebaõnnestus"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Konto <xliff:g id="ACCOUNT">%s</xliff:g> kasutajanimi või parool on vale. Kas soovite neid kohe värskendada?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Konto <xliff:g id="ACCOUNT">%s</xliff:g> kasutajanimi või parool on vale. Kas värskendada praegu?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Vaikekonto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Saada meilid vaikimisi sellelt kontolt"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Manuste allalaadimine"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Hiljutiste sõnumite manuste automaatne allalaadimine WiFi kaudu"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Meiliteatised"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sünkroonimise sagedus, teatised jne."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Saada teatis meili saabumisel"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Teavita süsteemiribal, kui saabub meil"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Postkasti kontrollimise sagedus"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Sissetulevate seaded"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Kasutajanimi, parool ja muud sissetuleva posti serveri seaded"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Väljuvad seaded"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Kasutajanimi, parool ja muud väljamineva posti serveri seaded"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Eeskirjad on jõustatud"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Puudub"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Toeta eeskirjad"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Puudub"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Proovi sünkroonida"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Konto sünkroonimiseks puudutage siin"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Konto nimi"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Teie nimi"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Allkiri"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Kiirvastused"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Muutke teksti, mida meilide koostamisel sageli sisestate"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Muuda teksti, mida sageli sisestate meilide koostamisel"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Lisa saadetavatele sõnumitele tekst"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Teadistusseaded"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Andmete kasutamine"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Turvaeeskirjad"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Kiirvastuse muutmine"</string> <string name="save_action" msgid="1988862706623227093">"Salvesta"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sünkrooni kontaktid"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Konto kontaktide sünkroonimine"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sünkrooni kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sünkrooni konto kalendri sündmused"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sünkrooni kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Konto kalendri sünkroonimine"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sünkrooni meil"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Konto meili sünkroonimine"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibreering"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Tulemuste ootamine"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Mõnede serverite vastust tuleb kaua oodata."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Kaustad"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Keela seadme kaamera kasutamine"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Nõua seadme parooli"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Piira hiljutiste paroolide taaskasutamist"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Paroolide aegumise nõue"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Nõua jõudeolekus seadme ekraanilukustust"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Piirab sünkroonitavate kalendrisündmuste arvu"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Piirab sünkroonitavate meilide arvu"</string> - <string name="quick_1" msgid="3426057697353380951">"Aitäh!"</string> - <string name="quick_2" msgid="4188036352885736617">"Mulle sobib!"</string> - <string name="quick_3" msgid="8061819976353395585">"Loen seda hiljem ja võtan siis ühendust."</string> - <string name="quick_4" msgid="3988974084396883051">"Lepime kokku kohtumise, et seda arutada."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Taustsünkroonimine on sellel kontol rändluse ajal keelatud."</string> </resources> diff --git a/res/values-et/uploader.xml b/res/values-et/uploader.xml index f42e288a5..a13e3197d 100644 --- a/res/values-et/uploader.xml +++ b/res/values-et/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Peida üksikasjad"</string> <string name="menu_settings" msgid="5088116127086866634">"Seaded"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Üles laaditud %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Laadi üles"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 39a58c719..ec176ecdd 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"خواندن پیوستهای ایمیل"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"به برنامه اجازه میدهد پیوستهای ایمیل شما را بخواند."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"به این برنامه اجازه میدهد پیوستهای ایمیل شما را بخواند."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"دسترسی به دادههای ارائهکننده ایمیل"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"به برنامه کاربردی اجازه میدهد به پایگاه داده ایمیل شما، شامل پیامهای دریافتی، پیامهای ارسالی، نامهای کاربری و گذرواژهها دسترسی داشته باشد."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"به این برنامه کاربردی اجازه میدهد به پایگاه داده ایمیل شما، شامل پیامهای دریافتی، پیامهای ارسالی، نامهای کاربری و گذرواژهها دسترسی داشته باشد."</string> <string name="app_name" msgid="5815426892327290362">"ایمیل"</string> <string name="compose_title" msgid="427986915662706899">"نگاشتن"</string> <string name="debug_title" msgid="5175710493691536719">"رفع خطا"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"انجام شد"</string> <string name="create_action" msgid="3062715563215392251">"ایجاد مورد جدید"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"حذف"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"پاسخ سریعی وجود ندارد."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"پاسخ سریعی وجود ندارد"</string> <string name="discard_action" msgid="6532206074859505968">"صرفنظر"</string> <string name="save_draft_action" msgid="6413714270991417223">"ذخیره پیش نویس"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"درج پاسخ سریع"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> نوشت:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"شامل نوشتار نقل قول شده"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"شامل متن"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"حداقل یک گیرنده اضافه کنید."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"باید حداقل یک گیرنده اضافه کنید."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"برخی از آدرس های ایمیل نامعتبر هستند."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"فایل خیلی بزرگ است و پیوست نمی شود"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"درج پاسخ سریع"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"ذخیره شد"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"توقف"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"پیوست به عنوان <xliff:g id="FILENAME">%s</xliff:g> ذخیره شد."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"پیوست ذخیره نشد."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"یک یا چند پیوست در پیام هدایت شده شما قبل از ارسال دانلود خواهد شد."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"نمیتوان پیوست را ذخیره کرد."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"توجه: یک یا چند پیوست در پیام هدایت شده شما قبل از ارسال دانلود می شود."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"پیام"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"دعوت کردن"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"یک یا چند پیوست باز ارسال نشد."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"پیوست هدایت نشد"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"ورود به سیستم <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ناموفق بود."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"ورود به سیستم <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ناموفق بود."</string> <string name="login_failed_title" msgid="7624349996212476176">"ورود به سیستم ممکن نیست"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> بایت"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"میتوانید فقط با انجام چند مرحله، یک حساب Exchange ActiveSync تنظیم کنید."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"آدرس ایمیل"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"رمز ورود"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"ارسال ایمیل از این حساب به صورت پیشفرض"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"ارسال ایمیل از این حساب به صورت پیش فرض."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"تنظیم دستی"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"یک آدرس ایمیل و گذرواژه معتبر تایپ کنید."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"حساب تکراری"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"در حال بررسی تنظیمات سرور ورودی..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"در حال بررسی تنظیمات سرور خروجی..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"تنظیم حساب"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"حساب شما تنظیم شد و ایمیل در راه است!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"حساب شما تنظیم شد و ایمیل در راه است!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"نامی به این حساب اختصاص دهید (اختیاری)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"نام شما (در پیام های خروجی نمایش داده می شود)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"این قسمت نمیتواند خالی باشد."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"سرور SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"درگاه"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"نوع امنیت"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"ورود به سیستم لازم است"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"باید به سیستم وارد شوید."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"نام کاربری"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"رمز ورود"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"تنظیم حساب"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"هر 15 دقیقه"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"هر 30 دقیقه"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"هر ساعت"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"ارسال ایمیل از این حساب به صورت پیشفرض"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"ورود ایمیل به من اعلان شود"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"همگام سازی مخاطبین از این حساب"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"همگامسازی تقویم از این حساب"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"همگامسازی ایمیل از این حساب"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"ارسال ایمیل از این حساب به صورت پیش فرض."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"ورود ایمیل به من اعلان شود."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"همگام سازی مخاطبین از این حساب."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"همگام سازی تقویم از این حساب."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"ایمیل را از این حساب همگام سازی کنید."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"دانلود خودکار پیوست ها هنگام اتصال به Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"پایان نیافت"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"روزهای همگامسازی"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"یک ماه"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"همه"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"استفاده از پیش فرض حساب"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"نام کاربری یا گذرواژه شما اشتباه است."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"نام کاربری یا گذرواژه نادرست است."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"نام کاربری یا رمز ورود نادرست است."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"نام کاربری یا رمز ورود نادرست است. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"اتصال امن به سرور امکانپذیر نیست."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"اتصال امن به سرور امکانپذیر نیست."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"به گواهینامه کلاینت نیاز دارد. آیا میخواهید با گواهینامه کلاینت به سرور متصل شوید؟"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"گواهینامه نامعتبر است و یا غیرقابل دسترس است."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"سرور با یک خطا پاسخ داد. نام کاربری و گذرواژه خود را بررسی کرده و دوباره امتحان کنید."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"گواهی سرویس گیرنده مورد نیاز است. اتصال به سرور با گواهی سرویس گیرنده؟"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"گواهینامه نامعتبر است و یا غیر قابلدسترسی است."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"سرور با یک خطا پاسخ داد. لطفاً نام کاربری و گذرواژه خود را بررسی کرده و دوباره امتحان کنید."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"اتصال به سرور امکانپذیر نیست."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"اتصال به سرور امکانپذیر نیست."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS لازم است اما توسط سرور پشتیبانی نمی شود."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"اخطار: غیرفعال کردن اختیار برنامه ایمیل برای سرپرستی دستگاه شما، همه حسابهای ایمیلی که به آن احتیاج دارند، به همراه ایمیل، مخاطبین، رویدادهای تقویم و سایر دادههای آنها را حذف میکند."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"بهروزرسانی امنیتی"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> از شما میخواهد تنظیمات امنیتی خود را بهروزرسانی کنید."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"به دلایل امنیتی، امکان همگامسازی حساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" وجود ندارد."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"تنظیمات امنیتی حساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" باید بهروزرسانی شود."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"حساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" تنظیمات امنیتی خود را تغییر داده است؛ نیازی به انجام هیچ کاری از طرف کاربر نیست."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"بهروزرسانی امنیتی لازم است"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"خطمشیهای امنیتی تغییر کردهاند"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"از خطمشیهای امنیتی تبعیت نمیشود"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"تنظیمات امنیتی حساب \"<xliff:g id="ACCOUNT">%s</xliff:g>\" باید به روزرسانی شود."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"به روزرسانی امنیتی لازم است"</string> <string name="account_security_title" msgid="3511543138560418587">"امنیت دستگاه"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"سرور <xliff:g id="SERVER">%s</xliff:g> از شما می خواهد که به آن اجازه دهید برخی از ویژگی های امنیتی دستگاه Android شما را از راه دور کنترل کند."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"ویرایش جزئیات"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"کد پین یا رمز ورود قفل صفحه منقضی شده است."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"رمز ورود قفل صفحه منقضی شده است"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"رمز ورود قفل صفحه در حال انقضا"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"باید پین قفل صفحه یا گذرواژه خود را سریع تغییر دهید، در غیر اینصورت دادههای <xliff:g id="ACCOUNT">%s</xliff:g> پاک خواهد شد . آیا میخواهید اکنون آن را تغییر دهید؟"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"شما باید به زودی کد پین یا رمز ورود قفل صفحه را تغییر دهید، در غیر این صورت داده های <xliff:g id="ACCOUNT">%s</xliff:g> پاک می شود. اکنون تغییر می دهید؟"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"رمز ورود قفل صفحه منقضی شده است"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"دادههای <xliff:g id="ACCOUNT">%s</xliff:g> درحال پاک شدن از دستگاه شما است. با تغییر دادن پین صفحه قفل یا گذرواژه خود میتوانید آنها را بازگردانید. آیا میخواهید هم اکنون آن را تغییر دهید؟"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"داده های <xliff:g id="ACCOUNT">%s</xliff:g> از دستگاه شما حذف می شوند. می توانید با تغییر کد پین یا رمز ورود صفحه قفل خود آنها را بازیابی کنید. اکنون آنرا تغییر می دهید؟"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"از تغییرات ذخیره نشده صرفنظر شود؟"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"ورود به سیستم ممکن نیست"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"نام کاربری یا گذرواژه <xliff:g id="ACCOUNT">%s</xliff:g> نادرست است. آیا میخواهید هم اکنون آنها را بهروز کنید؟"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"نام کاربری یا رمز ورود <xliff:g id="ACCOUNT">%s</xliff:g> نادرست است. اکنون آنها را به روزرسانی می کنید؟"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"حساب پیش فرض"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"ارسال ایمیل از این حساب به صورت پیش فرض"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"دانلود پیوستها"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"دانلود خودکار پیوستها به پیامهای اخیر از طریق Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"اعلان های ایمیل"</string> <string name="account_settings_summary" msgid="8403582255413830007">"تکرار همگام سازی، اعلان ها، موارد دیگر"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"ارسال اعلان هنگام ورود ایمیل"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"ورود ایمیل در نوار سیستم اعلام شود"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"دفعات بررسی صندوق دریافت"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"تنظیمات ورودی"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"نام کاربری، رمز ورود و سایر تنظیمات سرور ورودی"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"تنظیمات خروجی"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"نام کاربری، رمز ورود و سایر تنظیمات سرور خروجی"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"خطمشیهای اعمال شده"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"هیچکدام"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"خط مشیهای پشتیبانی نشده"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"هیچکدام"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"تلاش برای همگامسازی"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"برای همگامسازی این حساب اینجا را لمس کنید"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"نام حساب"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"نام شما"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"امضا"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"پاسخهای سریع"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"ویرایش متنی که غالباً هنگام نوشتن ایمیل درج میکنید"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"متنی را که غالباً هنگام نوشتن ایمیل ها درج می کنید، ویرایش کنید"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"افزودن متن به پیام هایی که ارسال می کنید"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"تنظیمات اعلان"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"مصرف داده"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"خطمشیهای امنیتی"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"ویرایش پاسخ سریع"</string> <string name="save_action" msgid="1988862706623227093">"ذخیره"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"همگام سازی مخاطبین"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"همگام سازی مخاطبین برای این حساب"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"همگام سازی تقویم"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"همگامسازی رویداد تقویم برای این حساب"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"همگام سازی تقویم"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"همگام سازی تقویم برای این حساب"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"همگامسازی ایمیل"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"همگام سازی ایمیل برای این حساب"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"لرزش"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"در انتظار نتایج"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"در بعضی از سرورها ممکن است زمان طولانی شود."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"پوشه ها"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"استفاده از دوربین دستگاه مجاز نیست"</string> - <string name="policy_require_password" msgid="7177274900480984702">"گذرواژه دستگاه لازم است"</string> - <string name="policy_password_history" msgid="5743544498302303181">"استفاده مجدد از گذرواژههای اخیر محدود است"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"گذرواژهها باید منقضی شوند"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"برای قفل کردن صفحه خود یک دستگاه آماده به کار لازم است"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"محدود کردن تعداد رویدادهای همگامسازی شده تقویم"</string> - <string name="policy_email_age" msgid="7144148367145424963">"محدود کردن تعداد ایمیلهای همگامسازی شده"</string> - <string name="quick_1" msgid="3426057697353380951">"متشکریم!"</string> - <string name="quick_2" msgid="4188036352885736617">"به نظرم خوب است!"</string> - <string name="quick_3" msgid="8061819976353395585">"بعداً این را میخوانم و به شما اطلاع میدهم."</string> - <string name="quick_4" msgid="3988974084396883051">"بیایید یک جلسه تشکیل بدهیم و درباره آن گفتگو کنیم."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"هنگام رومینگ، همگامسازی پسزمینه برای این حساب غیرفعال است."</string> </resources> diff --git a/res/values-fa/uploader.xml b/res/values-fa/uploader.xml index 2fdb77ec7..f4657da3a 100644 --- a/res/values-fa/uploader.xml +++ b/res/values-fa/uploader.xml @@ -30,7 +30,7 @@ <!-- String.format failed for translation --> <!-- no translation found for format_date_uploaded (803752037646090928) --> <skip /> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"حساب"</string> <string name="upload" msgid="2615541458361216022">"آپلود"</string> <string name="ok" msgid="2516349681897895312">"تأیید"</string> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index b356c82bd..8688190f5 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Lue sähköpostiliitteitä"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Antaa sovelluksen lukea sähköpostiliitteitä."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Antaa sovelluksen lukea sähköpostiliitteitä."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Käytä sähköpostintarjoajan tietoja"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Antaa sovelluksen käyttää sähköpostitietokantaasi, mukaan lukien vastaanotetut viestit, lähetetyt viestit, käyttäjänimet ja salasanat."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Antaa sovelluksen käyttää sähköpostitietokantaasi, mukaan lukien vastaanotettuja viestejä, lähetettyjä viestejä, käyttäjänimiä ja salasanoja."</string> <string name="app_name" msgid="5815426892327290362">"Sähköposti"</string> <string name="compose_title" msgid="427986915662706899">"Viestin kirjoitus"</string> <string name="debug_title" msgid="5175710493691536719">"Virheenjäljitys"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Valmis"</string> <string name="create_action" msgid="3062715563215392251">"Luo uusi"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Poista"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Ei pikavastauksia."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Ei pikavastauksia"</string> <string name="discard_action" msgid="6532206074859505968">"Hylkää"</string> <string name="save_draft_action" msgid="6413714270991417223">"Tallenna luonnos"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Lisää pikavastaus"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> kirjoitti:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Lisää lainattu teksti"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Liitä teksti mukaan"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Lisää vähintään yksi vastaanottaja."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Vähintään yksi vastaanottaja on lisättävä."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Kaikki sähköpostiosoitteet eivät kelpaa."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Tiedosto on liian suuri liitettäväksi."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Lisää pikavastaus"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Tallennettu"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Lopeta"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Liite tallennettu nimellä <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Liitetied. tall. epäonnistui."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Vähintään yksi edelleen lähetettävän viestisi liitteistä ladataan ennen lähettämistä."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Liitettä ei voitu tallentaa."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Huomaa: vähintään yksi edelleen lähetettävän viestisi liitteistä ladataan ennen lähettämistä."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Viesti"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Kutsu"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Vähintään yhden liitteen edelleenlähettäminen epäonnistui."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Liitettä ei lähetetty edelleen"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Kirjautuminen tiliin <xliff:g id="ACCOUNT_NAME">%s</xliff:g> epäonnistui."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Kirjautuminen tiliin <xliff:g id="ACCOUNT_NAME">%s</xliff:g> epäonnistui."</string> <string name="login_failed_title" msgid="7624349996212476176">"Kirjautuminen ei onnistu"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> t"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Voit määrittää Exchange ActiveSync -tilin asetukset helposti."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Sähköpostiosoite"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Salasana"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Lähetä sähköposti oletuksena tältä tililtä"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Lähetä sähköposti oletuksena tältä tililtä."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuaalinen määritys"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Anna kelvollinen sähköpostiosoite ja salasana."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Päällekkäiset tilit"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Tarkistetaan saapuvan postin palvelimen asetuksia…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Tarkistetaan lähtevän postin palvelimen asetuksia…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Tilin asetukset"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Tili on määritetty ja sähköposteja noudetaan."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Tili on määritetty ja sähköposteja noudetaan."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Anna tilille nimi (valinnainen)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Oma nimi (näytetään lähtevissä viesteissä)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Kenttä ei voi olla tyhjä."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-palvelin"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Portti"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Suojaustyyppi"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Vaadi kirjautuminen"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Edellytä kirjautumista."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Käyttäjänimi"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Salasana"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Tilin asetukset"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"15 minuutin välein"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"30 minuutin välein"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Tunnin välein"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Lähetä sähköposti oletuksena tältä tililtä"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Ilmoita saapuvasta sähköpostista"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synkronoi tämän tilin yhteystiedot"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synkronoi tämän tilin kalenteri"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synkronoi tämän tilin sähköpostit"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Lähetä sähköposti oletuksena tältä tililtä."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Ilmoita saapuvasta sähköpostista."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synkronoi tämän tilin yhteystiedot."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synkronoi tämän tilin kalenteri."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synkronoi tämän tilin lähetetyt sähköpostit."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Lataa liitteet automaattisesti wifi-yhteyden ollessa käytössä."</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Ei onnistunut"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Synkronoitavien päivien määrä"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Yksi kuukausi"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Kaikki"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Käytä tilin oletusta"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Käyttäjänimi tai salasana on virheellinen."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Käyttäjänimi tai salasana on virheellinen."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Virheellinen käyttäjänimi tai salasana."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Virheellinen käyttäjänimi tai salasana."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Palvelimeen ei voi muodostaa suojattua yhteyttä."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Palvelimeen ei voi muodostaa suojattua yhteyttä."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Asiakasvarmenne vaaditaan. Haluatko yhdistää palvelimeen asiakasvarmenteen avulla?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Varmenne ei kelpaa tai ole käytettävissä."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Palvelin lähetti virheilmoituksen. Tarkista käyttäjänimesi ja salasanasi ja yritä uudelleen."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Asiakasvarmenne vaaditaan. Yhdistetäänkö asiakasvarmenteelliseen palvelimeen?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Varmenne ei kelpaa tai ole käytettävissä."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Palvelin lähetti virheilmoituksen. Tarkista käyttäjänimesi ja salasanasi ja yritä uudelleen."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Palvelimeen ei voi muodostaa yhteyttä."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Palvelimeen ei voi muodostaa yhteyttä."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS vaaditaan, mutta palvelin ei tue sitä."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"VAROITUS: jos poistat sähköpostisovellukselta oikeuden hallinnoida laitettasi, myös kaikki sovellukseen liittyvät sähköpostitilit sekä niiden sähköpostit, yhteystiedot, kalenteritapahtumat ja muut tiedot poistetaan."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Tietoturvapäivitys"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> pyytää sinua päivittämään suojausasetuksesi."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Tiliä <xliff:g id="ACCOUNT">%s</xliff:g> ei voi synkronoida suojausvaatimusten vuoksi."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Tili \"<xliff:g id="ACCOUNT">%s</xliff:g>\" edellyttää, että suojausasetukset päivitetään."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Tili \"<xliff:g id="ACCOUNT">%s</xliff:g>\" muutti suojausasetuksiaan. Käyttäjältä ei vaadita toimia."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Suojauspäivitys tarvitaan"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Suojauskäytännöt muuttuneet"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Ei vastaa suojauskäytäntöjä"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Tili \"<xliff:g id="ACCOUNT">%s</xliff:g>\" edellyttää, että suojausasetukset päivitetään."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Suojauspäivitys tarvitaan"</string> <string name="account_security_title" msgid="3511543138560418587">"Laitteen suojaus"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Palvelin <xliff:g id="SERVER">%s</xliff:g> vaatii, että sen sallitaan hallita joitakin Android-laitteen suojaustoiminnoista."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Muokkaa tietoja"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Ruudunlukituksen PIN-koodi tai salasana on vanhentunut."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Ruudunlukituksen salasana vanhentunut"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Ruudunlukituksen salasana vanhentuu pian"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Ruudunlukituksen PIN-koodi tai salasana tulee vaihtaa pian, tai tilin <xliff:g id="ACCOUNT">%s</xliff:g> tiedot poistetaan. Haluatko vaihtaa koodin nyt?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Ruudunlukituksen PIN-koodi tai salasana tulee vaihtaa pian, tai tilin <xliff:g id="ACCOUNT">%s</xliff:g> tiedot poistetaan. Vaihdetaanko koodi nyt?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Ruudunlukituksen salasana vanhentunut"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Tilin <xliff:g id="ACCOUNT">%s</xliff:g> tietoja poistetaan laitteeltasi. Voit palauttaa tilin vaihtamalla ruudunlukituksen PIN-koodin tai salasanan. Haluatko vaihtaa koodin nyt?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Tilin <xliff:g id="ACCOUNT">%s</xliff:g> tietoja poistetaan laitteeltasi. Voit palauttaa tilin vaihtamalla ruudunlukituksen PIN-koodin tai salasanan. Vaihdetaanko koodi nyt?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Hylätäänkö tallentamattomat muutokset?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Kirjautuminen ei onnistu."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Tilin <xliff:g id="ACCOUNT">%s</xliff:g> käyttäjänimi tai salasana on virheellinen. Haluatko päivittää ne nyt?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Tilin <xliff:g id="ACCOUNT">%s</xliff:g> käyttäjänimi tai salasana on virheellinen. Päivitetäänkö?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Oletustili"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Lähetä sähköposti oletuksena tältä tililtä"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Lataa liitetiedostoja"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Lataa viimeaikaisten viestien liitteet wifi-yhteyden kautta."</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Sähköposti-ilmoitukset"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synkronoinnin tiheys, ilmoitukset jne."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Lähetä ilmoitus, kun sähköpostiviesti saapuu"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Ilmoita tilarivissä, kun sähköpostiviesti saapuu"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Uusien viestien tarkistustiheys"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Saapuvan postin asetukset"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Käyttäjänimi, salasana ja muut tulevat palvelimen asetukset"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Lähtevän postin asetukset"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Käyttäjänimi, salasana ja muut lähtevät palvelimen asetukset"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Käytännöt otettu käyttöön"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ei mitään"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Käytäntöjä ei tueta"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ei mitään"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Yritä synkronointia"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Synkronoi tili koskettamalla tätä"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Tilin nimi"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Oma nimi"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Allekirjoitus"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Pikavastaukset"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Muokkaa tekstiä, jota lisäät usein sähköpostiviesteihin"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Muokkaa tekstiä, jota lisäät usein sähköpostiviesteihin"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Liitä lähettämiisi viesteihin teksti"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Ilmoitusasetukset"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Tiedonsiirto"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Suojauskäytännöt"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Muokkaa pikavastausta"</string> <string name="save_action" msgid="1988862706623227093">"Tallenna"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synkronoi yhteystiedot"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synkronoi tämän tilin yhteystiedot"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synkronoi kalenteri"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synkronoi tilin kalenteritapahtuma"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synkronoi Kalenteri"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synkronoi tämän tilin kalenteri"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synkronoi sähköposti"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synkronoi tämän tilin sähköpostit"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Värinä"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Odotetaan tuloksia"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Joidenkin palvelimien vastaus voi kestää kauan."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Kansiot"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Älä salli laitteen kameran käyttöä"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Vaadi laitteen salasana"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Rajoita viim. salasanojen uud.käyttöä"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Vaadi salasanojen vanhenemista"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Käyttämättömän laitteen lukittava ruutu"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Rajoita synkronoitavien kalenteritap. lukumäärää"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Rajoita synkronoitavien sähköpostien lukumäärää"</string> - <string name="quick_1" msgid="3426057697353380951">"Kiitos!"</string> - <string name="quick_2" msgid="4188036352885736617">"Kuulostaa hyvältä!"</string> - <string name="quick_3" msgid="8061819976353395585">"Luen tämän myöhemmin ja palaan asiaan."</string> - <string name="quick_4" msgid="3988974084396883051">"Järjestetään tapaaminen ja keskustellaan asiasta."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Tämän tilin taustasynkronointi on pois käytöstä roaming-tilassa."</string> </resources> diff --git a/res/values-fi/uploader.xml b/res/values-fi/uploader.xml index 170571733..8ca406f22 100644 --- a/res/values-fi/uploader.xml +++ b/res/values-fi/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Piilota tiedot"</string> <string name="menu_settings" msgid="5088116127086866634">"Asetukset"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Ladattu %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Tili"</string> <string name="upload" msgid="2615541458361216022">"Lataa"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 3a7dd25b5..d6c4e9478 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Lire les pièces jointes"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permet à l\'application de lire les pièces jointes aux e-mails."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permet à cette application de lire les pièces jointes aux e-mails."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Accéder aux données du fournisseur de messagerie"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permet à l\'application d\'accéder à la base de données de votre messagerie, y compris aux messages reçus et envoyés, aux noms d\'utilisateur et aux mots de passe."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permet à cette application d\'accéder à votre base de données de messagerie, y compris aux messages reçus et envoyés, aux noms d\'utilisateur et aux mots de passe."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Nouveau message"</string> <string name="debug_title" msgid="5175710493691536719">"Débogage"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"OK"</string> <string name="create_action" msgid="3062715563215392251">"Créer"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Supprimer"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Aucune réponse rapide"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Aucune réponse rapide"</string> <string name="discard_action" msgid="6532206074859505968">"Supprimer"</string> <string name="save_draft_action" msgid="6413714270991417223">"Enregistrer"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Insérer la réponse rapide"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> a écrit :"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Inclure le texte des messages précédents"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Inclure le texte"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Ajoutez au moins un destinataire."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Vous devez ajouter au moins un destinataire."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Certaines adresses e-mail sont incorrectes."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Impossible de joindre le fichier, car il est trop volumineux."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Insérer une réponse rapide"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Enregistré"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Arrêter"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"PJ enregistrée sous <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Impossible enreg. pièce jointe."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Une ou plusieurs pièces jointes au message que vous transférez vont être téléchargées avant l\'envoi."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Impossible enreg. pièce jointe."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Remarque : Une ou plusieurs pièces jointes du message que vous transférez vont être téléchargées avant l\'envoi."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Message"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Inviter"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Impossible de transférer une ou plusieurs pièces jointes."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Pièce jointe non transférée"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Échec de la connexion au compte <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Échec de la connexion au compte <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Impossible de se connecter"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> O"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Vous pouvez configurer un compte Exchange ActiveSync en quelques étapes seulement."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Adresse e-mail"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Mot de passe"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Par défaut, envoyer les e-mails avec ce compte"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Par défaut, envoyer les e-mails avec ce compte"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuration manuelle"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Saisissez une adresse e-mail et un mot de passe corrects."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dupliquer le compte"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Vérification des paramètres de serveur entrant…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Vérification des paramètres de serveur sortant…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuration du compte"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Votre compte est configuré et votre messagerie est activée !"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Votre compte est configuré et votre messagerie a été activée !"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Nom du compte (facultatif)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Votre nom (affiché sur les messages sortants)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Ce champ est obligatoire."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Serveur SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Type de sécurité"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Exiger une connexion"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Connexion obligatoire."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nom d\'utilisateur"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Mot de passe"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuration du compte"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Toutes les 15 minutes"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Toutes les 30 minutes"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Toutes les heures"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Par défaut, envoyer les e-mails avec ce compte"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"M\'avertir lors de la réception d\'un e-mail"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synchroniser les contacts de ce compte"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synchroniser l\'agenda de ce compte"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synchroniser les e-mails de ce compte"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Par défaut, envoyer les e-mails avec ce compte"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Afficher une notification lors de la réception d\'un e-mail"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synchroniser les contacts issus de ce compte"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synchroniser l\'agenda à partir de ce compte"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synchroniser les e-mails à partir de ce compte"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Télécharger automatiquement les pièces jointes une fois connecté au Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Impossible de terminer"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Jours à synchroniser"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Un mois"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Tous"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Utiliser paramètres défaut"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nom d\'utilisateur ou mot de passe incorrect."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Le nom d\'utilisateur ou le mot de passe est incorrect."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nom d\'utilisateur ou mot de passe incorrect."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nom d\'utilisateur ou mot de passe incorrect."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Impossible d\'établir une connexion sécurisée avec le serveur."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Impossible d\'établir une connexion sécurisée avec le serveur."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Certificat client requis. Voulez-vous vous connecter au serveur avec un certificat client ?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Le certificat est invalide ou inaccessible."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Erreur du serveur. Veuillez vérifier votre nom d\'utilisateur et votre mot de passe, puis réessayer."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Certificat client requis. Voulez-vous vous connecter au serveur avec le certificat client ?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Le certificat n\'est pas valide ou est inaccessible."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Erreur du serveur. Veuillez vérifier votre nom d\'utilisateur et votre mot de passe, puis réessayer."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Impossible de se connecter au serveur."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Impossible de se connecter au serveur."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Protocole TLS requis mais non pris en charge par le serveur."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AVERTISSEMENT : Si vous désactivez la gestion de votre appareil par l\'application E-mail, tous les comptes de messagerie qui y sont associés seront supprimés, de même que leurs données (e-mails, contacts, événements d\'agenda, etc.)."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Mise à jour de sécurité"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> nécessite la mise à jour de vos paramètres de sécurité."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Impossible de synchroniser le compte <xliff:g id="ACCOUNT">%s</xliff:g> en raison des exigences de sécurité."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Les paramètres de sécurité du compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\" doivent être mis à jour."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Les paramètres de sécurité du compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ont été modifiés. Aucune action de votre part n\'est requise."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Mise à jour de sécurité requise"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Règles de sécurité modifiées"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Imposs. appliquer règles sécu"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Le compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\" nécessite une mise à jour de ses paramètres de sécurité."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Mise à jour de sécurité requise"</string> <string name="account_security_title" msgid="3511543138560418587">"Sécurité de l\'appareil"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Vous devez autoriser le serveur <xliff:g id="SERVER">%s</xliff:g> à contrôler à distance certaines fonctionnalités de sécurité de votre mobile Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Modifier les infos"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Le code PIN ou le mot de passe de verrouillage de votre écran a expiré."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Mot de passe verrou. expiré"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Expiration mot de passe de verrouillage"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Vous allez bientôt devoir modifier le code PIN ou le mot de passe de verrouillage de l\'écran, faute de quoi les données de <xliff:g id="ACCOUNT">%s</xliff:g> vont être effacées. Voulez-vous le modifier maintenant ?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Vous devrez bientôt modifier le code PIN ou le mot de passe de verrouillage de votre écran, faute de quoi les données du compte <xliff:g id="ACCOUNT">%s</xliff:g> seront effacées. Modifier maintenant ?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Le mot de passe de verrouillage de votre écran a expiré."</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Les données de <xliff:g id="ACCOUNT">%s</xliff:g> sont en cours d\'effacement de votre appareil. Vous pouvez les restaurer en modifiant le code PIN ou le mot de passe de verrouillage de l\'écran. Voulez-vous le modifier maintenant ?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Les données du compte <xliff:g id="ACCOUNT">%s</xliff:g> sont en cours d\'effacement de votre appareil. Vous pouvez les restaurer en modifiant le code PIN ou le mot de passe de verrouillage de votre écran. Le modifier maintenant ?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Annuler les modifications non enregistrées ?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Impossible de se connecter."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Le nom d\'utilisateur ou le mot de passe de <xliff:g id="ACCOUNT">%s</xliff:g> est incorrect. Voulez-vous les mettre à jour maintenant ?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Le nom d\'utilisateur ou le mot de passe du compte <xliff:g id="ACCOUNT">%s</xliff:g> est incorrect. Mettre à jour maintenant ?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Compte par défaut"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Par défaut, envoyer les e-mails avec ce compte"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Télécharger les pièces jointes"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Téléch. auto des pièces jointes aux messages récents via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notifications"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Fréquence de synchronisation, notifications, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Envoyer une notification en cas de nouvel e-mail"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Afficher une notification dans la barre système à la réception d\'e-mails"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Fréquence de consultation de la boîte de réception"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Paramètres de réception"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nom d\'utilisateur, mot de passe et autres param. serveur entrant"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Paramètres d\'envoi"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nom d\'utilisateur, mot de passe et autres param. serveur sortant"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Règles appliquées"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Aucun"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Règles non compatibles"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Aucun"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Synchroniser (tentative)"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Appuyer ici pour synchroniser ce compte"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nom du compte"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Votre nom"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signature"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Réponses rapides"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Modifier texte fréquemment inséré lors de la rédaction d\'e-mails"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Modifier texte fréquemment inséré lors de la rédaction d\'e-mails"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Ajouter un texte aux messages envoyés"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Paramètres de notification"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Consommation des données"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Règles de sécurité"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Modifier une réponse rapide"</string> <string name="save_action" msgid="1988862706623227093">"Enregistrer"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synchroniser les contacts"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synchroniser les contacts pour ce compte"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synchroniser l\'agenda"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synchro événement agenda pour ce compte"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synchroniser l\'agenda"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synchroniser l\'agenda pour ce compte"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synchr. messagerie"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synchroniser les e-mails pour ce compte"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibreur"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"En attente des résultats..."</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Cette opération peut prendre du temps avec certains serveurs."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Dossiers"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Interdire utilisation de l\'appareil photo"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Exiger un mot de passe pour l\'appareil"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Restreindre réutil. mots de passe récents"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Exiger l\'expiration des mots de passe"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Exiger verrouillage appareils inactifs"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limiter nombre d\'événements d\'agenda synchronisés"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limiter le nombre d\'e-mails synchronisés"</string> - <string name="quick_1" msgid="3426057697353380951">"Merci !"</string> - <string name="quick_2" msgid="4188036352885736617">"Cela me convient."</string> - <string name="quick_3" msgid="8061819976353395585">"Je lirai cela plus tard, et je vous recontacterai."</string> - <string name="quick_4" msgid="3988974084396883051">"Organisons une réunion pour en discuter."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"La synchronisation en arrière-plan pour ce compte est désactivée en itinérance."</string> </resources> diff --git a/res/values-fr/uploader.xml b/res/values-fr/uploader.xml index f3e16a1fc..42de0bc5d 100644 --- a/res/values-fr/uploader.xml +++ b/res/values-fr/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Masquer les détails"</string> <string name="menu_settings" msgid="5088116127086866634">"Paramètres"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Transféré le %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Compte"</string> <string name="upload" msgid="2615541458361216022">"Transférer"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 86930e0e7..cfa8bdbe7 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"ईमेल अनुलग्नक पढ़ें"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"एप्लिकेशन को आपके ईमेल अनुलग्नक पढ़ने देता है."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"इस एप्लिकेशन को आपके ईमेल अनुलग्नक पढ़ने देता है."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"ईमेल प्रदाता के डेटा तक पहुंचें"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"इस एप्लिकेशन को प्राप्त संदेशों, भेजे गए संदेशों, उपयोगकर्ता नाम और पासवर्ड सहित आपके ईमेल डेटाबेस में पहुंच देता है."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"इस एप्लिकेशन को प्राप्त संदेशों, भेजे गए संदेशों, उपयोगकर्ता नाम और पासवर्ड सहित आपके ईमेल डेटाबेस में पहुंच देता है."</string> <string name="app_name" msgid="5815426892327290362">"ईमेल"</string> <string name="compose_title" msgid="427986915662706899">"लिखें"</string> <string name="debug_title" msgid="5175710493691536719">"डीबग करें"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"पूर्ण"</string> <string name="create_action" msgid="3062715563215392251">"नया बनाएं"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"हटाएं"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"कोई त्वरित प्रतिसाद नहीं."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"कोई त्वरित प्रतिसाद नहीं"</string> <string name="discard_action" msgid="6532206074859505968">"छोड़ें"</string> <string name="save_draft_action" msgid="6413714270991417223">"ड्राफ़्ट सहेजें"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"त्वरित प्रतिसाद शामिल करें"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> ने लिखा:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"उद्धरित पाठ शामिल करें"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"पाठ शामिल करें"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"कम से कम एक प्राप्तकर्ता जोड़ें."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"आपको कम से कम एक प्राप्तकर्ता जोड़ना चाहिए."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"कुछ ईमेल पते अमान्य हैं."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"अनुलग्न करने के लिए फ़ाइल बहुत बड़ी है."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"त्वरित प्रतिसाद सम्मिलित करें"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"सहेजा गया"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"रोकें"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"अनुलग्नक को <xliff:g id="FILENAME">%s</xliff:g> के रूप में सहेजा गया है."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"अनुलग्नक सहेजा नहीं जा सका."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"आपके द्वारा अग्रेषित संदेश को भेजने से पहले उसके एक या अधिक अनुलग्नक डाउनलोड किए जाएंगे."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"अनुलग्नक सहेजा नहीं जा सका."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"ध्यान दें: आपके द्वारा अग्रेषित संदेश में एक या एक से अधिक अनुलग्नक भेजने से पहले डाउनलोड किए जाएंगे."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"संदेश"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"आमंत्रित करें"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"एक या अधिक अनुलग्नक अग्रेषित नहीं किए जा सके."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"अनुलग्नक अग्रेषित नहीं किया गया"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> में साइन इन करना विफल रहा."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> साइन इन विफल."</string> <string name="login_failed_title" msgid="7624349996212476176">"साइन इन नहीं हो सका"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"आप बस कुछ ही चरणों में Exchange ActiveSync खाता सेट कर सकते हैं."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"ईमेल पता"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"पासवर्ड"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"डिफ़ॉल्ट रूप से, इस खाते से ईमेल भेजें"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"डिफ़ॉल्ट रूप से इस खाते से ईमेल भेजें."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"मैन्युअल सेटअप"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"कोई मान्य ईमेल पता और पासवर्ड लिखें."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"डुप्लिकेट खाता"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"इनकमिंग सर्वर सेटिंग जांच रहा है…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"आउटगोइंग सर्वर सेटिंग जांच रहा है…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"खाता सेटअप"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"आपका खाता सेट हो गया है और शीघ्र ही ईमेल मिलने वाला है!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"आपका खाता सेट हो गया है, और शीघ्र ही ईमेल मिलने वाला है!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"इस खाते को कोई नाम दें (वैकल्पिक)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"आपका नाम (आउटगोइंग संदेशों में प्रदर्शित)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"यह फ़ील्ड रिक्त नहीं हो सकती."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP सर्वर"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"पोर्ट"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"सुरक्षा प्रकार"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"साइन इन आवश्यक"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"साइन-इन की आवश्यकता है."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"उपयोगकर्ता नाम"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"पासवर्ड"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"खाता सेटअप"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"प्रत्येक 15 मिनट"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"प्रत्येक 30 मिनट"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"प्रत्येक घंटा"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"डिफ़ॉल्ट रूप से, इस खाते से ईमेल भेजें"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"ईमेल आने पर मुझे सूचित करें"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"संपर्कों को इस खाते से समन्ववित करें"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"इस खाते से कैलेंडर समन्वयित करें"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"इस खाते से ईमेल समन्वयित करें"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"डिफ़ॉल्ट रूप से इस खाते से ईमेल भेजें."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"ईमेल आने पर मुझे सूचित करें."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"संपर्कों को इस खाते से सिंक करें."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"इस खाते से कैलेंडर सिंक करें."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"इस खाते से ईमेल सिंक करें."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Wi-Fi से कनेक्ट होने पर अनुलग्नकों को स्वचालित रूप से डाउनलोड करें"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"पूरा नहीं हो सका"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"समन्वयन के लिए दिन:"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"एक माह"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"सभी"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"खाते के डिफ़ॉल्ट का उपयोग करें"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"उपयोगकर्ता नाम या पासवर्ड गलत है."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"उपयोगकर्ता नाम या पासवर्ड गलत है."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"उपयोगकर्तानाम या पासवर्ड गलत है."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"उपयोगकर्ता नाम या पासवर्ड गलत है."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"सर्वर से सुरक्षित रूप से कनेक्ट नहीं हो सकता."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"सर्वर से सुरक्षित रूप से कनेक्ट नहीं हो सकता."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"एक क्लाइंट प्रमाणपत्र की आवश्यकता है. क्या आप क्लाइंट प्रमाणपत्र के साथ सर्वर से कनेक्ट होना चाहते हैं?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"प्रमाणपत्र अमान्य है या उस पर पहुंचा नहीं जा सकता."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"सर्वर ने एक त्रुटि के साथ प्रतिसाद दिया. अपना उपयोगकर्ता नाम और पासवर्ड जांचें फिर पुन: प्रयास करें."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"क्लाइंट प्रमाणपत्र आवश्यक है. क्लाइंट प्रमाणपत्र वाले सर्वर से कनेक्ट करें?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"प्रमाणपत्र अमान्य है या उस पर पहुंचा नहीं जा सकता."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"सर्वर ने एक त्रुटि के साथ प्रतिसाद दिया. अपना उपयोगकर्ता नाम और पासवर्ड जांचें फिर पुन: प्रयास करें."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"सर्वर से कनेक्ट नहीं हो सकता."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"सर्वर से कनेक्ट नहीं कर सकता."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS आवश्यक है लेकिन सर्वर द्वारा समर्थित नहीं है."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"चेतावनी: आपके उपकरण को प्रबंधित करने के लिए ईमेल एप्लिकेशन का प्राधिकार निष्क्रिय कर देने से उसके लिए आवश्यक सभी ईमेल खाते, उनके ईमेल, संपर्क, कैलेंडर ईवेंट, और अन्य डेटा सहित, हटा दिए जाएंगे."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"सुरक्षा अपडेट"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"आपको <xliff:g id="ACCOUNT">%s</xliff:g> के लिए अपनी सुरक्षा सेटिंग अपडेट करने की आवश्यकता है."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"सुरक्षा आवश्यकताओं के कारण खाता \"<xliff:g id="ACCOUNT">%s</xliff:g>\" समन्वयित नहीं किया जा सकता."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"खाते \"<xliff:g id="ACCOUNT">%s</xliff:g>\" को सुरक्षा सेटिंग अपडेट की आवश्यकता है."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" खाते ने अपनी सुरक्षा सेटिंग बदल दी है; किसी उपयोगकर्ता कार्यवाही की आवश्यकता नहीं."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"सुरक्षा अपडेट आवश्यक"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"सुरक्षा नीतियां बदल दी गई हैं"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"सुरक्षा नीतियां पूरी नहीं हो सकतीं"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"खाते \"<xliff:g id="ACCOUNT">%s</xliff:g>\" को सुरक्षा सेटिंग अपडेट की आवश्यकता है."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"सुरक्षा अपडेट आवश्यक"</string> <string name="account_security_title" msgid="3511543138560418587">"उपकरण सुरक्षा"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"सर्वर <xliff:g id="SERVER">%s</xliff:g> के लिए यह आवश्यक है कि आप उसे अपने Android उपकरण की कुछ सुरक्षा सुविधाओं को दूरस्थ रूप से नियंत्रित करने दें."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"विवरण संपादित करें"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"आपकी स्क्रीन लॉक करें पिन या पासवर्ड की समय-सीमा समाप्त हो गई है."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"स्क्रीन लॉक करें पासवर्ड की समय-सीमा समाप्त"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"स्क्रीन लॉक करें पासवर्ड समाप्त होने वाला है"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"आपको शीघ्र ही अपना लॉक स्क्रीन पिन या पासवर्ड को बदलना होगा, अन्यथा <xliff:g id="ACCOUNT">%s</xliff:g> का डेटा मिट जाएगा. क्या आप इसे अभी बदलना चाहते हैं?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"आपको जल्द ही अपनी स्क्रीन लॉक करें पिन या पासवर्ड बदल लेना चाहिए, अन्यथा <xliff:g id="ACCOUNT">%s</xliff:g> का डेटा मिटा दिया जाएगा. इसे अभी बदलें?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"स्क्रीन लॉक करें पासवर्ड की समय-सीमा समाप्त हो गई है"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g> का डेटा आपके उपकरण से मिटाया जा रहा है. आप इसे अपने लॉक स्क्रीन पिन या पासवर्ड बदलकर पुनर्स्थापित कर सकते हैं. क्या आप इसे अभी बदलना चाहते हैं?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g> का डेटा आपके उपकरण से मिटाया जा रहा है. आप अपनी स्क्रीन लॉक करें पिन या पासवर्ड को बदलकर उसे पुनर्स्थापित कर सकते हैं. इसे अभी बदलें?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"न सहेजे गए परिवर्तनों को छोड़ें?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"साइन इन नहीं हो सका"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g> का उपयोगकर्ता नाम या पासवर्ड गलत है. क्या आप उन्हें अभी अपडेट करना चाहते हैं?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g> का उपयोगकर्ता नाम या पासवर्ड गलत है. उन्हें अभी अपडेट करें?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"डिफ़ॉल्ट खाता"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"डिफ़ॉल्ट रूप से, इस खाते से ईमेल भेजें"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"अनुलग्नकों को डाउनलोड करें"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"WiFi के माध्यम से हाल के संदेशों के अनुलग्नक स्वत: डाउनलोड करें"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"ईमेल सूचनाएं"</string> <string name="account_settings_summary" msgid="8403582255413830007">"आवृत्ति, सूचनाएं आदि सिंक करें."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"ईमेल आने पर सूचना भेजें"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"ईमेल आने पर सिस्टम बार में सूचित करें"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"इनबॉक्स देखने की आवृत्ति"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"इनकमिंग सेटिंग"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"उपयोगकर्ता नाम, पासवर्ड, और अन्य इनकमिंग सर्वर सेटिंग"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"आउटगोइंग सेटिंग"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"उपयोगकर्ता नाम, पासवर्ड, और अन्य आउटगोइंग सर्वर सेटिंग"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"नीतियां लागू की गईं"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"कोई नहीं"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"असमर्थित नीतियां"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"कोई नहीं"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"समन्वयन का प्रयास करें"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"इस खाते को समन्वयित करने के लिए यहां स्पर्श करें"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"खाता नाम"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"आपका नाम"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"हस्ताक्षर"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"त्वरित प्रतिसाद"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"वह पाठ संपादित करें जिसे आप अक्सर ईमेल लिखते समय शामिल करते हैं"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"वह पाठ संपादित करें जिसे आप अक्सर ईमेल लिखते समय शामिल करते हैं"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"आपके भेजे जाने वाले संदेशों में पाठ संशोधित करें"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"सूचना सेटिंग"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"डेटा उपयोग"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"सुरक्षा नीतियां"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"त्वरित प्रतिसाद संपादित करें"</string> <string name="save_action" msgid="1988862706623227093">"सहेजें"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"संपर्कों को सिंक करें"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"इस खाते के लिए संपर्क सिंक करें"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"कैलेंडर सिंक करें"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"इस खाता हेतु कैलें. इवेंट समन्व. करें"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"कैलेंडर सिंक करें"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"इस खाते के लिए कैलेंडर सिंक करें"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"ईमेल समन्वयित करें"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"इस खाते के लिए ईमेल सिंक करें"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"कंपन"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"परिणामों की प्रतीक्षा कर रहा है"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"कुछ सर्वर को अधिक समय लग सकता है."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"फ़ोल्डर"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"उपकरण के कैमरे के उपयोग की अनुमति न दें"</string> - <string name="policy_require_password" msgid="7177274900480984702">"उपकरण पासवर्ड आवश्यक"</string> - <string name="policy_password_history" msgid="5743544498302303181">"हाल के पासवर्ड का पुन: उपयोग प्रतिबं. करें"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"पासवर्ड के लिए समय सीमा समाप्ति आवश्यक"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"स्क्रीन लॉक के लिए निष्क्रिय उपकरण चाहिए"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"समन्वयित कैलेंडर ईवेंट की संख्या सीमित करें"</string> - <string name="policy_email_age" msgid="7144148367145424963">"समन्वयित ईमेल की संख्या सीमित करें"</string> - <string name="quick_1" msgid="3426057697353380951">"धन्यवाद!"</string> - <string name="quick_2" msgid="4188036352885736617">"मुझे अच्छा लगता है!"</string> - <string name="quick_3" msgid="8061819976353395585">"मैं इसे बाद में पढ़ूंगा/पढ़ूगी और आपसे संपर्क करूंगा/करूंगी."</string> - <string name="quick_4" msgid="3988974084396883051">"आइए इस पर चर्चा करने के लिए कोई मीटिंग सेट करें."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"रोमिंग के दौरान इस खाते के लिए पृष्ठभूमि समन्वयन अक्षम है."</string> </resources> diff --git a/res/values-hi/uploader.xml b/res/values-hi/uploader.xml index ba69c8589..b06101ad4 100644 --- a/res/values-hi/uploader.xml +++ b/res/values-hi/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"विवरण छुपाएं"</string> <string name="menu_settings" msgid="5088116127086866634">"सेटिंग"</string> <string name="format_date_uploaded" msgid="803752037646090928">"अपलोड किया गया %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"खाता"</string> <string name="upload" msgid="2615541458361216022">"अपलोड करें"</string> <string name="ok" msgid="2516349681897895312">"ठीक"</string> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 7a9dff11c..f791a8eb8 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Čitanje privitaka e-pošte"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Omogućuje aplikaciji da čita vaše privitke e-pošte."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Aplikaciji omogućuje čitanje privitaka vaše e-pošte."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Pristup podacima o davatelju usluge e-pošte"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Aplikaciji omogućuje pristup podatkovnoj bazi vaše e-pošte, uključujući primljene poruke, poslane poruke, korisnička imena i zaporke."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Aplikaciji omogućuje pristup bazi podataka vaše e-pošte, uključujući primljene poruke, poslane poruke, korisnička imena i zaporke."</string> <string name="app_name" msgid="5815426892327290362">"E-pošta"</string> <string name="compose_title" msgid="427986915662706899">"Stvori novu poruku"</string> <string name="debug_title" msgid="5175710493691536719">"Otklanjanje pogrešaka"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Gotovo"</string> <string name="create_action" msgid="3062715563215392251">"Izradi novi"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Izbriši"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nema brzih odgovora."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nema brzih odgovora"</string> <string name="discard_action" msgid="6532206074859505968">"Odbaci"</string> <string name="save_draft_action" msgid="6413714270991417223">"Spremanje skice"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Umetni brzi odgovor"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> je napisao:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Obuhvati citirani tekst"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Uključi tekst"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Dodajte barem jednog primatelja."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Morate dodati barem jednog primatelja."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Neke adrese e-pošte nisu važeće."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Datoteka je prevelika za privitak."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Umetanje brzog odgovora"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Spremljeno"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Zaustavi"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Privitak spremljen kao <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Privitak nije moguće spremiti."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Jedan ili više privitaka u proslijeđenoj poruci preuzet će se prije slanja."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Spremanje privitka neuspješno."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Bilješka: Jedan ili više privitaka u vašoj proslijeđenoj poruci preuzet će se prije slanja."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Poruka"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Pozovi"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Jedan ili više privitaka nije bilo moguće proslijediti."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Privitak nije proslijeđen"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Prijava računa <xliff:g id="ACCOUNT_NAME">%s</xliff:g> neuspješna."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Neuspješna prijava na račun <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Neuspjela prijava"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Račun sustava Exchange ActiveSync možete postaviti u samo nekoliko koraka."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Adresa e-pošte"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Zaporka"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Šalji e-poštu s ovog računa prema zadanim postavkama"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Šalji e-poštu s ovog računa prema zadanim postavkama."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ručno postavljanje"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Upišite važeću adresu e-pošte i zaporku."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dvostruki račun"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Provjeravanje postavki dolaznog poslužitelja..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Provjeravanje postavki izlaznog poslužitelja..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Postavljanje računa"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Vaš je račun postavljen, a e-pošta stiže!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Vaš je račun postavljen, a e-pošta stiže!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Dodijelite ovom računu naziv (opcionalno)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Vaše ime (prikazano u izlaznim porukama)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Ovo polje ne može biti prazno."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP poslužitelj"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Vrsta sigurnosti"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Potrebna je prijava"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Zahtijevajte prijavu."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Korisničko ime"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Zaporka"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Postavljanje računa"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Svakih 15 minuta"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Svakih 30 minuta"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Svaki sati"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Šalji e-poštu s ovog računa prema zadanim postavkama"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Obavijesti me kad stigne e-pošta"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinkroniziraj kontakte s ovog računa."</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinkroniziraj kalendar s ovog računa"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinkroniziraj e-poštu s ovog računa"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Šalji e-poštu s ovog računa prema zadanim postavkama."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Obavijesti me kad stigne e-pošta."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinkroniziraj i kontakte s ovog računa."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinkroniziraj kalendar s ovog računa"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sink. e-poštu za ovaj račun."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automatski preuzmi privitke za vrijeme povezanosti s Wi-Fi mrežom"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Završavanje nije bilo moguće"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dani za sinkronizaciju"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Jedan mjesec"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Sve"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Upotrijebi zadanu postavku računa"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Korisničko ime ili zaporka nisu ispravni."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Neispravno korisničko ime ili zaporka."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Korisničko ime ili zaporka nisu točni."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Korisničko ime ili zaporka nisu točni."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Sigurno povezivanje s poslužiteljem nije moguće."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Sigurno povezivanje s poslužiteljem nije moguće."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Potrebna je klijentska potvrda. Želite li se povezati s poslužiteljem s klijentskom potvrdom?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Potvrda je neispravna ili nedostupna."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Poslužitelj je odgovorio s pogreškom. Provjerite korisničko ime i zaporku i pokušajte ponovo."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Potreban certifikat klijenta. Spojiti se na poslužitelj s certifikatom klijenta?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certifikat je nevažeći ili nedostupan."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Poslužitelj je odgovorio pogreškom. Provjerite korisničko ime i zaporku i pokušajte ponovo."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Povezivanje s poslužiteljem nije moguće."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Povezivanje s poslužiteljem nije moguće."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS je obavezan, ali ga poslužitelj ne podržava."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"UPOZORENJE: Deaktivacijom ovlasti aplikacije E-pošta za upravljanje uređajem izbrisat će se svi računi e-pošte koji traže tu ovlast, kao i e-pošta, kontakti, događaji kalendara i drugi podaci."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Sigurnosno ažuriranje"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Račun <xliff:g id="ACCOUNT">%s</xliff:g> zahtijeva da ažurirate svoje sigurnosne postavke."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Račun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" nije moguće sinkronizirati zbog sigurnosnih zahtjeva."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Račun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" zahtijeva ažuriranje sigurnosnih postavki."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Račun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" promijenio je sigurnosne postavke, korisnik ne mora poduzimati ništa."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Potrebno sigurnosno ažuriranje"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Promjena sigurnosnih pravila"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Nemoguće ispuniti sig. pravila"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Račun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" zahtijeva ažuriranje sigurnosnih postavki."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Potrebno sigurnosno ažuriranje"</string> <string name="account_security_title" msgid="3511543138560418587">"Sigurnost uređaja"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Poslužitelj <xliff:g id="SERVER">%s</xliff:g> zahtijeva da mu omogućite daljinsko upravljanje nekim sigurnosnim značajkama vašeg Android uređaja."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Uredi pojedinosti"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN ili zaporka za zaključavanje zaslona istekli su."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Istekla zap. za zaklj. zasl."</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Istječe zaporka za zaključavanje zaslona"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Uskoro morate promijeniti svoj PIN ili zaporku za zaključavanje zaslona ili će biti izbrisani podaci za račun <xliff:g id="ACCOUNT">%s</xliff:g>. Želite li to promijeniti sada?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Uskoro morate promijeniti PIN ili zaporku za zaključavanje zaslona jer će inače podaci računa <xliff:g id="ACCOUNT">%s</xliff:g> biti izbrisani. Promijeniti sada?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Istekla zap. za zaklj. zasl."</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Podaci za račun <xliff:g id="ACCOUNT">%s</xliff:g> brišu se s vašeg uređaja. Možete ih vratiti promjenom PIN-a ili zaporke za zaključavanje. Želite li to promijeniti sada?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Brišu se podaci računa <xliff:g id="ACCOUNT">%s</xliff:g> s vašeg uređaja. Oporaviti ih možete promjenom PIN-a ili zaporke za zaključavanje zaslona. Promijeniti sada?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Odbaciti nespremljene promjene?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Neuspjela prijava"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Netočno je korisničko ime ili zaporka za račun <xliff:g id="ACCOUNT">%s</xliff:g>. Želite li to ažurirati sada?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Korisničko ime ili zaporka za <xliff:g id="ACCOUNT">%s</xliff:g> nisu točni. Ažurirati sada?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Zadani račun"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Šalji e-poštu s ovog računa prema zadanim postavkama"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Preuzimanje privitaka"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automatsko preuzimanje privitaka uz nedavne poruke WiFi mrežom"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Obavijesti e-pošte"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Učestalost sinkronizacije, obavijesti itd."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Pošalji obavijest kada stigne e-pošta"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Obavijesti u traci sustava kad stigne e-pošta"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Učestalost provjeravanja e-pošte"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Dolazne postavke"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Korisničko ime, zaporka i ostale postavke dolaznog poslužitelja"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Odlazne postavke"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Korisničko ime, zaporka i ostale postavke odlaznog poslužitelja"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Pravila provedena"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ništa"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nepodržana pravila"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ništa"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Pokušaj sinkronizaciju"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Dodirnite ovdje za sinkronizaciju tog računa"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Naziv računa"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Vaše ime"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Potpis"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Brzi odgovori"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Uredite tekst koji često umećete prilikom pisanja e-pošte"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Uređivanje teksta koji često umećete prilikom pisanja e-pošte"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Dodajte tekst porukama koje šaljete"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Postavke obavijesti"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Potrošnja podataka"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sigurnosna pravila"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Uredi brzi odgovor"</string> <string name="save_action" msgid="1988862706623227093">"Spremi"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinkroniziraj kontakte"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sink. kontakata za ovaj račun"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinkroniziraj kalendar"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sink. kal. dog. za ovaj račun"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sink. Kalendar"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sink. kalendara za ovaj račun"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sink. e-pošte"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sink. e-pošte za ovaj račun"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibracija"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Čekaju se rezultati"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Nekim poslužiteljima može trebati više vremena."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mape"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Onemogući upotrebu fotoaparata uređaja"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Zahtijevaj zaporku uređaja"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Ograniči ponovnu upotrebu novijih zapor."</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Zahtijevaj istek zaporke"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Zahtijevaj zaključ. zaslona u mirovanju"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ograniči broj sinkroniziranih događaja kalendara"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ograniči broj sinkroniziranih poruka e-pošte"</string> - <string name="quick_1" msgid="3426057697353380951">"Hvala!"</string> - <string name="quick_2" msgid="4188036352885736617">"Izvrsno!"</string> - <string name="quick_3" msgid="8061819976353395585">"Pročitat ću to kasnije i javiti vam se."</string> - <string name="quick_4" msgid="3988974084396883051">"Hajdemo dogovoriti sastanak na kojem ćemo raspraviti o tome."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Pozadinska sinkronizacija za ovaj račun onemogućena je u roamingu."</string> </resources> diff --git a/res/values-hr/uploader.xml b/res/values-hr/uploader.xml index 124e7f12b..e84da77f0 100644 --- a/res/values-hr/uploader.xml +++ b/res/values-hr/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Sakrij pojedinosti"</string> <string name="menu_settings" msgid="5088116127086866634">"Postavke"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Preneseno %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Račun"</string> <string name="upload" msgid="2615541458361216022">"Šalji"</string> <string name="ok" msgid="2516349681897895312">"U redu"</string> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 895f9dcaf..7d128b37c 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"E-mail mellékletek olvasása"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Lehetővé teszi az alkalmazás számára az e-mailek mellékleteinek olvasását."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Lehetővé teszi az alkalmazás számára az e-mail mellékletek olvasását."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Hozzáférés az e-mail szolgáltató adataihoz"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Lehetővé teszi az alkalmazás számára az e-mail adatbázisához, így a fogadott és elküldött üzenetekhez, a felhasználónevekhez és jelszavakhoz való hozzáférést."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Lehetővé teszi, hogy az alkalmazás hozzáférjen az e-mail adatbázishoz, beleértve a fogadott és elküldött üzeneteket, a felhasználóneveket és a jelszavakat."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Levélírás"</string> <string name="debug_title" msgid="5175710493691536719">"Hibakeresés"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Kész"</string> <string name="create_action" msgid="3062715563215392251">"Új létrehozása"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Törlés"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nincsenek gyors válaszok."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nincsenek gyors válaszok"</string> <string name="discard_action" msgid="6532206074859505968">"Elvetés"</string> <string name="save_draft_action" msgid="6413714270991417223">"Piszkozatmentés"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Gyors válasz beilleszt."</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> a következőt írta:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Idézett szöveg beillesztése"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Szöveggel együtt"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Vegyen fel legalább egy címzettet."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Legalább egy résztvevőt hozzá kell adnia."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Egyes e-mail címek érvénytelenek."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"A csatolni kívánt fájl túl nagy."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Gyors válasz beillesztése"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Elmentve"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Leállítás"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Melléklet elmentve: <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"A melléklet mentése nem sikerült."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Küldés előtt továbbított üzenete egy vagy több melléklete letöltődik."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Nem sikerült a melléklet mentése."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Megjegyzés: a továbbított üzenet egy vagy több melléklete letöltésre kerül a küldés előtt."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Üzenet"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Meghívás"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Egy vagy több melléklet nem továbbítható."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"A melléklet nincs továbbítva"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"A(z) <xliff:g id="ACCOUNT_NAME">%s</xliff:g> fiókba való bejelentkezés sikertelen."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> bejelentkezése sikertelen volt."</string> <string name="login_failed_title" msgid="7624349996212476176">"Sikertelen bejelentkezés"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Mindössze néhány lépésben létrehozhat egy Exchange ActiveSync-fiókot."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-mail cím"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Jelszó"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"E-mail küldése ebből a fiókból alapértelmezés szerint"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"E-mailek küldése ebből a fiókból alapértelmezés szerint."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuális beállítás"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Írjon be egy érvényes e-mail címet és jelszót."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Már létező fiók"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Bejövő üzeneteket kezelő szerver beállításainak ellenőrzése..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kimenő üzeneteket kezelő szerver beállításainak ellenőrzése..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Fiók beállítása"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"A fiók beállítása befejeződött, az e-mailek úton vannak."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"A fiók beállítása befejeződött, a levelezőprogram készen áll az e-mailek fogadására."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Fiók elnevezése (opcionális)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Az Ön neve (a kimenő üzenetekben való megjelenítéshez)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Ez a mező nem lehet üres."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-szerver"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Biztonság típusa"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Bejelentkezés szükséges"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Bejelentkezés szükséges."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Felhasználónév"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Jelszó"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Fiók beállítása"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"15 percenként"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"30 percenként"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Óránként"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"E-mail küldése ebből a fiókból alapértelmezés szerint"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Értesítés megjelenítése e-mail érkezésekor"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Névjegyek szinkronizálása ebből a fiókból"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Naptár szinkronizálása ebből a fiókból"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Az e-mailek szinkronizálása ebből a fiókból"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"E-mail küldése ebből a fiókból alapértelmezés szerint"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Értesítés megjelenítése e-mail érkezésekor"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Névjegyek szinkronizálása ebben a fiókban."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Naptár szinkronizálása ebben a fiókban."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Az e-mailek szinkronizálása ebből a fiókból."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Mellékletek automatikus letöltése Wi-Fi-kapcsolatnál"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nem sikerült befejezni"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Szinkronizálási időtartam"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Egy hónap"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Összes"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Alapbeállítás használata"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Helytelen felhasználónév vagy jelszó."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Helytelen felhasználónév vagy jelszó."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Helytelen felhasználónév vagy jelszó."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Helytelen felhasználónév vagy jelszó."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nem lehet biztonságos kapcsolatot létesíteni a szerverrel."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nem lehet biztonságos kapcsolatot létesíteni a szerverrel."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Klienstanúsítvány szükséges. Szeretne klienstanúsítvánnyal rendelkező szerverhez csatlakozni?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"A tanúsítvány érvénytelen vagy elérhetetlen."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"A szerver hibaüzenettel válaszolt. Ellenőrizze felhasználónevét és jelszavát, majd próbálja újra."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Ügyféltanúsítvány szükséges. Csatlakozzon ügyféltanúsítvánnyal rendelkező szerverhez?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Az igazolás érvénytelen vagy elérhetetlen."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"A szerver hibaüzenettel válaszolt. Ellenőrizze felhasználónevét és jelszavát, majd próbálja újra."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nem lehet kapcsolatot létesíteni a szerverrel."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nem lehet kapcsolódni a szerverhez."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS szükséges, de a szerver nem támogatja."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"FIGYELMEZTETÉS: ha kikapcsolja az E-mail alkalmazás azon jogosultságát, hogy felügyelje az eszközt, akkor törli az összes olyan e-mail fiókot, amelyhez szükség van az alkalmazásra; a fiókokkal együtt pedig törli az e-maileket, a névjegyeket, a naptári eseményeket és más adatokat is."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Biztonsági frissítés"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> a biztonsági beállítások frissítését igényli."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"A(z) \"<xliff:g id="ACCOUNT">%s</xliff:g>\" fiókot a biztonsági követelmények miatt nem lehet szinkronizálni."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Frissíteni kell a(z) \"<xliff:g id="ACCOUNT">%s</xliff:g>\" fiók biztonsági beállításait."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"A(z) \"<xliff:g id="ACCOUNT">%s</xliff:g>\" nevű fiók módosította a biztonsági beállításokat, nem szükséges felhasználói beavatkozás."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Biztonsági frissítés szükséges"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"A rendszabályok megváltoztak"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"A biztonsági házirend nem tartható be"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Frissíteni kell a(z) \"<xliff:g id="ACCOUNT">%s</xliff:g>\" fiók biztonsági beállításait."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Biztonsági frissítés szükséges"</string> <string name="account_security_title" msgid="3511543138560418587">"Eszközbiztonság"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"A(z) <xliff:g id="SERVER">%s</xliff:g> szerver engedélyt kér arra, hogy távolról vezérelhesse az Android-eszköz egyes biztonsági funkcióit."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Részletek szerkesztése"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"A képernyőzár PIN kódja vagy jelszava lejárt."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Képernyőzár jelszava lejárt"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Képernyőzár jelszava hamarosan lejár"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Hamarosan módosítania kell a képernyőzár PIN-kódját vagy jelszavát, különben a(z) <xliff:g id="ACCOUNT">%s</xliff:g> fiók adatai törlődnek. Módosítja most?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Hamarosan módosítani kell a képernyőzár PIN kódját vagy jelszavát, különben <xliff:g id="ACCOUNT">%s</xliff:g> adatait törli a készülék. Módosítja most?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Képernyőzár jelszava lejárt"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g> adatai törlésre kerülnek a készülékről. Visszaállíthatja a képernyőzár PIN-kódjának vagy jelszavának módosításával. Módosítja most?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g> adatai törlésre kerülnek a készülékről. Visszaállíthatja a képernyőzár PIN kódjának vagy jelszavának módosításával. Módosítja most?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Elveti a nem mentett módosításokat?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Sikertelen bejelentkezés"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"A(z) <xliff:g id="ACCOUNT">%s</xliff:g> fiókhoz tartozó felhasználónév és jelszó helytelen. Szeretné frissíteni őket most?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g> felhasználóneve vagy jelszava helytelen. Frissíti most?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Alapértelmezett fiók"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"E-mail küldése ebből a fiókból alapértelmezés szerint"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Mellékletek letöltése"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Mellékletek automatikus letöltése az üzenetekbe Wi-Fin keresztül"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-mail értesítések"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Szinkronizálási gyakoriság, értesítések stb."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"E-mail érkezése esetén értesítés küldése"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Értesítés megjelenítése a Rendszersávon e-mailek érkezése esetén"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Beérkező levelek ellenőrzésének gyakorisága"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Bejövő üzenetek beállításai"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Felhasználónév, jelszó és a beérkező szerver egyéb beállításai"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Kimenő üzenetek beállításai"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Felhasználónév, jelszó és a kimenő szerver beállításai"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Kényszerített rendszabályok"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nincs"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nem támogatott rendszabályok"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nincs"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Szinkronizálás megkísérlése"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"A fiók szinkronizálásához érintse meg itt"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Fióknév"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Az Ön neve"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Aláírás"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Gyors válaszok"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"E-mail írásakor gyakran beillesztett szöveg szerkesztése"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"E-mail íráskor gyakran beillesztett szöveg szerkesztése"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Szöveg hozzáfűzése az elküldendő üzenetekhez"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Értesítési beállítások"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Adathasználat"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Biztonsági rendszabályok"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Gyors válasz szerkesztése"</string> <string name="save_action" msgid="1988862706623227093">"Mentés"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Névjegyek szinkronizálása"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"A fiók névjegyeinek szinkronizálása"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Naptár szinkronizálása"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"A fiók naptárának szinkronizálása"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Naptár szinkr."</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"A fiók naptárának szinkronizálása"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"E-mail szinkroniz."</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"A fiók e-mailjeinek szinkronizálása"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Rezgés"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Várakozás a találatokra"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Egyes szervereknek több időre van szükségük."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mappák"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"A kamera használatának tiltása"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Eszközjelszó kötelező"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Előző jelszavak kizárása"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"A jelszavak kötelezően lejárnak"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Képernyőzároláshoz szükséges nyugalmi idő"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Szinkronizált naptáresemények számának korlátozása"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Szinkronizált e-mailek számának korlátozása"</string> - <string name="quick_1" msgid="3426057697353380951">"Köszönjük!"</string> - <string name="quick_2" msgid="4188036352885736617">"Jól hangzik!"</string> - <string name="quick_3" msgid="8061819976353395585">"Később elolvasom és visszatérünk rá."</string> - <string name="quick_4" msgid="3988974084396883051">"Szervezzünk egy találkozót a dolog megvitatására."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"A fiók háttérben zajló szinkronizálása le van tiltva barangolás közben."</string> </resources> diff --git a/res/values-hu/uploader.xml b/res/values-hu/uploader.xml index 480cddbe6..2560959c0 100644 --- a/res/values-hu/uploader.xml +++ b/res/values-hu/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Részletek elrejtése"</string> <string name="menu_settings" msgid="5088116127086866634">"Beállítások"</string> <string name="format_date_uploaded" msgid="803752037646090928">"%s feltöltve"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Fiók"</string> <string name="upload" msgid="2615541458361216022">"Feltöltés"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 7747aff89..6cb1f16ee 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -17,14 +17,14 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Baca lampiran email"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Memungkinkan apl membaca lampiran email Anda."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Mengizinkan aplikasi membaca lampiran email Anda."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Akses data penyedia email"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Mengizinkan apl mengakses basis data email Anda, termasuk pesan yang diterima, pesan yang dikirim, nama pengguna, dan sandi."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Mengizinkan aplikasi ini mengakses basis data email Anda, termasuk pesan yang diterima, pesan yang dikirim, nama pengguna, dan sandi."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Tulis"</string> <string name="debug_title" msgid="5175710493691536719">"Debug"</string> <string name="next_action" msgid="3931301986364184415">"Berikutnya"</string> - <string name="okay_action" msgid="8365197396795675617">"Oke"</string> + <string name="okay_action" msgid="8365197396795675617">"OK"</string> <string name="cancel_action" msgid="6967435583794021865">"Batal"</string> <string name="previous_action" msgid="5181616311579820981">"Sebelumnya"</string> <string name="send_action" msgid="1729766205562446418">"Kirimkan"</string> @@ -36,9 +36,9 @@ <string name="done_action" msgid="7497990549515580249">"Selesai"</string> <string name="create_action" msgid="3062715563215392251">"Buat baru"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Hapus"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Tidak ada tanggapan cepat."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Tidak ada tanggapan cepat"</string> <string name="discard_action" msgid="6532206074859505968">"Buang"</string> - <string name="save_draft_action" msgid="6413714270991417223">"Simpan draf"</string> + <string name="save_draft_action" msgid="6413714270991417223">"Simpan konsep"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Masukkan tanggapan cepat"</string> <string name="read_action" msgid="4701484794504781686">"Tandai sudah dibaca"</string> <string name="unread_action" msgid="6280399049357552826">"Tandai belum dibaca"</string> @@ -55,7 +55,7 @@ <string name="move_action" msgid="3059189775933985898">"Pindahkan"</string> <string name="plus_cc_label" msgid="3365150001259912183">"+ Cc/Bcc"</string> <string name="add_cc_bcc_menu" msgid="4757145078498200242">"Tambahkan Cc/Bcc"</string> - <string name="add_file_attachment" msgid="2203398371671979481">"Lampirkan file"</string> + <string name="add_file_attachment" msgid="2203398371671979481">"Lampirkan berkas"</string> <string name="close_action" msgid="533058985745238100">"Tutup"</string> <string name="message_list_send_pending_messages_action" msgid="8502942186631824114">"Kirim semua pesan"</string> <string name="choose_attachment_dialog_title" msgid="81937507117528954">"Pilih lampiran"</string> @@ -69,7 +69,7 @@ </plurals> <string name="cannot_move_protocol_not_supported_toast" msgid="6558083148128616292">"Pemindahan tidak didukung pada akun POP3."</string> <string name="cannot_move_multiple_accounts_toast" msgid="7922594026384944163">"Tidak dapat memindah karena pilihan berisi beberapa akun."</string> - <string name="cannot_move_special_mailboxes_toast" msgid="7093107954841896970">"Pesan dalam Draf, Kotak Keluar, dan Terkirim tidak dapat dipindah."</string> + <string name="cannot_move_special_mailboxes_toast" msgid="7093107954841896970">"Pesan dalam Konsep, Kotak Keluar, dan Terkirim tidak dapat dipindah."</string> <plurals name="notification_new_one_account_fmt"> <item quantity="one" msgid="3422945912787702191">"<xliff:g id="UNREAD_MESSAGE_COUNT">%1$d</xliff:g> yang belum dibaca (<xliff:g id="ACCOUNT">%2$s</xliff:g>)"</item> <item quantity="few" msgid="6543078667692990869">"<xliff:g id="UNREAD_MESSAGE_COUNT">%1$d</xliff:g> yang belum dibaca (<xliff:g id="ACCOUNT">%2$s</xliff:g>)"</item> @@ -88,7 +88,7 @@ </plurals> <string name="mailbox_name_display_inbox" msgid="3542327124749861736">"Kotak Masuk"</string> <string name="mailbox_name_display_outbox" msgid="2826214174661417662">"Kotak Keluar"</string> - <string name="mailbox_name_display_drafts" msgid="4868718300700514319">"Draf"</string> + <string name="mailbox_name_display_drafts" msgid="4868718300700514319">"Konsep"</string> <string name="mailbox_name_display_trash" msgid="9139069064580630647">"Sampah"</string> <string name="mailbox_name_display_sent" msgid="3426058998191869523">"Terkirim"</string> <string name="mailbox_name_display_junk" msgid="9046762505977999288">"Junk"</string> @@ -103,14 +103,14 @@ <string name="debug_version_fmt" msgid="6160213145745376955">"Versi: <xliff:g id="VERSION">%s</xliff:g>"</string> <string name="account_folder_list_summary_inbox" msgid="7518263761297423255">"Kotak Masuk"</string> <string name="account_folder_list_summary_starred" msgid="3134312269246375723">"Yang berkilau bintangnya"</string> - <string name="account_folder_list_summary_drafts" msgid="5514845993247300437">"Draf"</string> + <string name="account_folder_list_summary_drafts" msgid="5514845993247300437">"Konsep"</string> <string name="account_folder_list_summary_outbox" msgid="3059836696049399377">"Kotak Keluar"</string> <string name="mailbox_list_account_selector_combined_view" msgid="1556327299894225044">"Tampilan kombinasi"</string> - <string name="mailbox_list_account_selector_show_all_folders" msgid="4185052839366909439">"Tampilkan semua folder"</string> + <string name="mailbox_list_account_selector_show_all_folders" msgid="4185052839366909439">"Tampilkan semua map"</string> <string name="mailbox_list_account_selector_account_header" msgid="4261295503836387876">"Akun"</string> - <string name="mailbox_list_account_selector_mailbox_header_fmt" msgid="3320144348694625092">"Folder terkini (<xliff:g id="EMAIL_ADDRESS">%s</xliff:g>)"</string> - <string name="mailbox_list_user_mailboxes" msgid="484260487104726379">"Semua folder"</string> - <string name="mailbox_list_recent_mailboxes" msgid="8922653040520361032">"Folder terkini"</string> + <string name="mailbox_list_account_selector_mailbox_header_fmt" msgid="3320144348694625092">"Map terkini (<xliff:g id="EMAIL_ADDRESS">%s</xliff:g>)"</string> + <string name="mailbox_list_user_mailboxes" msgid="484260487104726379">"Semua map"</string> + <string name="mailbox_list_recent_mailboxes" msgid="8922653040520361032">"Map terkini"</string> <string name="message_subject_description" msgid="3597047441062021199">"Subjek"</string> <string name="message_is_empty_description" msgid="4004644319382041459">"Tanpa subjek"</string> <string name="message_list_load_more_messages_action" msgid="7428302707908825692">"Muat pesan lainnya"</string> @@ -133,9 +133,9 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n" <xliff:g id="SENDER">%s</xliff:g> menulis:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Sertakan kutipan teks"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Sertakan teks"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Tambahkan setidaknya satu penerima."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Anda harus menambahkan setidaknya satu penerima."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Beberapa alamat email tidak valid."</string> - <string name="message_compose_attachment_size" msgid="4401081828287333647">"File terlalu besar untuk dilampirkan."</string> + <string name="message_compose_attachment_size" msgid="4401081828287333647">"Berkas terlalu besar untuk dilampirkan."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Masukkan tanggapan cepat"</string> <string name="message_compose_display_name" msgid="6415258924917140704">"<xliff:g id="NAME">%1$s</xliff:g> dan <xliff:g id="NUMBER">%2$d</xliff:g> lainnya"</string> <string name="message_view_to_label" msgid="6485191743265527381">"Kepada:"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Disimpan"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Hentikan"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Lampiran disimpan sebagai <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Tak dapat menyimpan lampiran."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Satu atau beberapa lampiran dalam pesan yang diteruskan akan diunduh sebelum dikirim."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Tak dapat menyimpan lampiran."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Catatan: Satu atau beberapa lampiran dalam pesan yang diteruskan akan diunduh sebelum dikirim."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Pesan"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Undang"</string> <plurals name="message_view_show_attachments_action"> @@ -181,14 +181,14 @@ <string name="attachment_info_wifi_settings" msgid="96432970927503597">"Setelan Wi-Fi"</string> <string name="attachment_info_application_settings" msgid="4124655487276125596">"Setelan apl"</string> <string name="attachment_info_unknown" msgid="8342655396805943320">"Tidak dapat membuka lampiran."</string> - <string name="attachment_info_malware" msgid="6576029010855055528">"Anda tidak dapat menyimpan atau membuka file ini karena jenis lampiran mungkin berisi perangkat lunak berbahaya."</string> + <string name="attachment_info_malware" msgid="6576029010855055528">"Anda tidak dapat menyimpan atau membuka berkas ini karena jenis lampiran mungkin berisi perangkat lunak berbahaya."</string> <string name="attachment_info_policy" msgid="3560422300127587508">"Lampiran ini tidak dapat disimpan atau dibuka karena kebijakan keamanan akun ini."</string> <string name="attachment_info_wifi_only" msgid="1481120960014563617">"Lampiran ini terlalu besar untuk diunduh melalui jaringan seluler. Anda dapat mengunduhnya saat tersambung lagi ke jaringan Wi-Fi."</string> <string name="attachment_info_no_intent" msgid="8139209405745777924">"Tidak ada apl terpasang yang dapat membuka lampiran ini. Coba unduh apl yang tepat dari Android Market."</string> <string name="attachment_info_sideload_disabled" msgid="3270731101769840006">"Lampiran ini adalah sebuah apl. Anda harus mencentang Sumber Tidak Dikenal dalam Setelan > Apl sebelum Anda dapat memasangnya."</string> <string name="attachment_info_apk_install_disabled" msgid="2817790592227462682">"Apl tidak dapat dipasang langsung dari email. Simpan apl ini terlebih dahulu, lalu pasang menggunakan apl Unduhan."</string> <string name="attachment_not_found" msgid="7155322700141145123">"Tidak dapat mengunduh lampiran."</string> - <string name="message_decode_error" msgid="5016042255170947834">"Terjadi kesalahan saat mengawasandikan pesan."</string> + <string name="message_decode_error" msgid="5016042255170947834">"Terjadi galat saat mengawasandikan pesan."</string> <string name="eml_view_title" msgid="8827210108543430336">"Melihat <xliff:g id="FILENAME">%s</xliff:g>"</string> <string name="message_delete_dialog_title" msgid="6603370107217227252"></string> <plurals name="message_delete_confirm"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Tidak dapat meneruskan satu lampiran atau lebih."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Lampiran tidak diteruskan"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Gagal masuk <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Gagal masuk <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Tidak dapat masuk"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Anda dapat menyiapkan akun Exchange ActiveSync hanya dalam beberapa langkah."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Alamat email"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Sandi"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Kirim email dari akun ini secara default"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Kirim email dari akun ini secara bawaan."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Penyiapan manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Ketik alamat email dan sandi yang valid."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Akun rangkap"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Memeriksa setelan server masuk…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Memeriksa setelan server keluar…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Penyiapan akun"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Akun Anda sudah siap dan email akan segera tiba!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Akun Anda sudah siap, dan email akan segera tiba!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Beri nama akun ini (opsional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Nama (yang ditampilkan pada pesan keluar)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Bidang ini tidak boleh kosong."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Jenis keamanan"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Harus masuk"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Harus masuk"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nama Pengguna"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Sandi"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Penyiapan akun"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Setiap 15 menit"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Setiap 30 menit"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Setiap jam"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Kirim email dari akun ini secara default"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Beri tahu saya ketika email tiba"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinkronkan kenalan dari akun ini"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinkronkan kalender dari akun ini"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinkronkan email dari akun ini"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Kirim email dari akun ini secara bawaan."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Beri tahu saya ketika email tiba."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinkronkan kenalan dari akun ini."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinkronkan kalender dari akun ini."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sinkronkan email dari akun ini."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Unduh lampiran secara otomatis ketika tersambung dengan Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Tidak dapat menyelesaikan"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Hari yang disinkronkan"</string> @@ -320,19 +320,19 @@ <string name="account_setup_options_mail_window_2weeks" msgid="4567049268124213035">"Dua minggu"</string> <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Satu bulan"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Semua"</string> - <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Gunakan default akun"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nama pengguna atau sandi salah."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nama pengguna atau sandi salah."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Gunakan bawaan akun"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nama pengguna atau sandi salah."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nama pengguna atau sandi salah."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Tidak dapat tersambung ke server dengan aman."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Tidak dapat tersambung ke server dengan aman."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Diperlukan sertifikat klien. Apakah Anda ingin menyambung ke server dengan sertifikat klien?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifikat tidak valid atau tidak dapat diakses."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Server menanggapi dengan kesalahan. Periksa nama pengguna dan sandi, lalu coba lagi."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Sertifikat klien diwajibkan. Sambungkan ke server dengan sertifikat klien?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikat tidak valid atau tidak dapat diakses."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Server merespons dengan galat. Periksa nama pengguna dan sandi Anda lalu coba lagi."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Tidak dapat tersambung ke server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Tidak dapat menyambung ke server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS diperlukan, tetapi tidak didukung oleh server."</string> <string name="account_setup_failed_auth_required" msgid="6799839150250217566">"Metode autentikasi tidak didukung oleh server."</string> - <string name="account_setup_failed_security" msgid="925820957665764964">"Tidak dapat membuka sambungan ke server karena kesalahan keamanan."</string> + <string name="account_setup_failed_security" msgid="925820957665764964">"Tidak dapat membuka sambungan ke server karena galat keamanan."</string> <string name="account_setup_failed_ioerror" msgid="7802604687451830378">"Tidak dapat membuka koneksi ke server."</string> <string name="account_setup_failed_protocol_unsupported" msgid="4607759927226943569">"Anda mengetikkan alamat server yang salah atau server memerlukan versi protokol yang tidak didukung Email."</string> <string name="account_setup_failed_access_denied" msgid="6835358740050287051">"Anda tidak memiliki izin untuk menyinkronkan dengan server ini. Hubungi administrator server untuk informasi lebih lanjut."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"PERINGATAN: Menonaktifkan otoritas apl Email untuk mengatur perangkat Anda akan menghapus semua akun email yang memerlukannya, beserta email, data kenalan, acara kalender, dan data lainnya."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Pembaruan keamanan"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> mengharuskan Anda memperbarui setelan keamanan."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Akun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" tidak dapat disinkronkan karena persyaratan keamanan."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Akun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" memerlukan pembaruan setelan keamanan."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Akun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" mengubah setelan keamanannya, tidak diperlukan tindakan pengguna."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Diperlukan pembaruan keamanan"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Kebijakan keamanan tlh diubah"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Kbijakan keamanan tak terpnuhi"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Akun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" memerlukan pembaruan setelan keamanan."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Pemutakhiran keamanan diperlukan"</string> <string name="account_security_title" msgid="3511543138560418587">"Keamanan perangkat"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Server <xliff:g id="SERVER">%s</xliff:g> meminta Anda mengizinkannya mengontrol beberapa fitur keamanan perangkat Android dari jarak jauh."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Edit detail"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN atau sandi pengunci layar Anda kedaluwarsa."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Sandi pengunci layar kedaluwarsa"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Sandi pengunci layar akan kedaluwarsa"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Anda perlu segera mengganti PIN atau sandi pengunci layar. Bila tidak, data untuk <xliff:g id="ACCOUNT">%s</xliff:g> akan dihapus. Ganti sekarang?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Anda harus mengganti PIN atau sandi pengunci layar segera, atau data untuk<xliff:g id="ACCOUNT">%s</xliff:g> akan dihapus. Ganti sekarang?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Sandi pengunci layar kedaluwarsa"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Data untuk <xliff:g id="ACCOUNT">%s</xliff:g> sedang dihapus dari perangkat. Anda dapat memulihkannya dengan mengganti PIN atau sandi pengunci layar. Ganti sekarang?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Data untuk <xliff:g id="ACCOUNT">%s</xliff:g> sedang dihapus dari perangkat Anda. Anda dapat memulihkannya dengan mengganti PIN atau sandi pengunci layar. Ganti sekarang?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Buang perubahan yang tidak tersimpan?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Tidak dapat masuk"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Nama pengguna atau sandi untuk <xliff:g id="ACCOUNT">%s</xliff:g> salah. Perbarui sekarang?"</string> - <string name="account_settings_default_label" msgid="3575963379680943640">"Akun default"</string> - <string name="account_settings_default_summary" msgid="1531901438624688482">"Kirim email dari akun ini secara default"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Nama pengguna atau sandi untuk <xliff:g id="ACCOUNT">%s</xliff:g> salah. Mutakhirkan keduanya sekarang?"</string> + <string name="account_settings_default_label" msgid="3575963379680943640">"Akun bawaan"</string> + <string name="account_settings_default_summary" msgid="1531901438624688482">"Kirim email dari akun ini secara bawaan"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Unduh lampiran"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Unduh-otomatis lampiran pada pesan terbaru melalui WiFi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Pemberitahuan email"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sinkronkan frekuensi, pemberitahuan, dll."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Mengirimkan pemberitahuan bila email tiba"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Beri tahukan dalam bilah Sistem ketika email tiba"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frekuensi pemeriksaan kotak masuk"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Setelan masuk"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nama pengguna, sandi, dan setelan server masuk lainnya"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Setelan keluar"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nama pengguna, sandi, dan setelan server keluar lainnya"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Kebijakan diberlakukan"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Tidak ada"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Kebijakan tidak didukung"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Tidak ada"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Coba sinkronisasi"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Sentuh di sini untuk menyinkronkan akun ini"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nama akun"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Nama Anda"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Tanda tangan"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Tanggapan cepat"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edit teks yang sering Anda masukkan ketika menulis email"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edit teks yang sering Anda masukkan ketika membuat email"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Menambahkan teks ke pesan yang Anda kirim"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Setelan pemberitahuan"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Penggunaan data"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Kebijakan keamanan"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Edit tanggapan cepat"</string> <string name="save_action" msgid="1988862706623227093">"Simpan"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinkronkan kenalan"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sinkronkan kenalan untuk akun ini"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinkronkan kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Snkronkan acr kalender utk akun ini"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sinkronkan Kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sinkronkan kalender untuk akun ini"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sinkronkan email"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sinkronkan email untuk akun ini"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Getar"</string> @@ -417,10 +406,10 @@ <string name="mailbox_settings_mailbox_sync_window_label" msgid="2957945231022052672">"Hari yang disinkronkan"</string> <string name="account_shortcut_picker_name" msgid="1994861845225243190">"Akun email"</string> <string name="account_shortcut_picker_title" msgid="1039929224016048015">"Pilih akun"</string> - <string name="mailbox_shortcut_picker_title" msgid="4152973927804882131">"Pilih folder"</string> + <string name="mailbox_shortcut_picker_title" msgid="4152973927804882131">"Pilih map"</string> <string name="toast_account_not_found" msgid="8144242451730692816">"Akun tidak ditemukan. Akun mungkin telah dihapus."</string> - <string name="toast_mailbox_not_found" msgid="4960014581292378895">"Folder tidak ditemukan. Folder mungkin telah dihapus."</string> - <string name="provider_note_live" msgid="2995297671709325333">"Hanya beberapa akun \"Plus\" termasuk akses POP yang mengizinkan program ini tersambung. Jika tidak dapat masuk dengan sandi dan alamat email yang benar, Anda mungkin tidak memiliki akun \"Plus\" berbayar. Luncurkan browser web untuk mendapat akses ke akun email ini."</string> + <string name="toast_mailbox_not_found" msgid="4960014581292378895">"Map tidak ditemukan. Map mungkin telah dihapus."</string> + <string name="provider_note_live" msgid="2995297671709325333">"Hanya beberapa akun \"Plus\" termasuk akses POP yang mengizinkan program ini tersambung. Jika tidak dapat masuk dengan sandi dan alamat email yang benar, Anda mungkin tidak memiliki akun \"Plus\" berbayar. Luncurkan peramban web untuk mendapat akses ke akun email ini."</string> <string name="provider_note_t_online" msgid="1630642061431427894">"Sebelum menyiapkan akun email ini, kunjungi situs web T-Online dan buat sandi untuk akses email POP3."</string> <string name="exchange_name" msgid="1190783774800310346">"Perusahaan"</string> <string name="exchange_name_alternate" msgid="5772529644749041052">"Microsoft Exchange ActiveSync"</string> @@ -456,7 +445,7 @@ <string name="general_preference_text_zoom_large" msgid="6874323663381586918">"Besar"</string> <string name="general_preference_text_zoom_huge" msgid="4270503132355963031">"Sangat besar"</string> <string name="general_preference_reply_all_label" msgid="7806833609810003510">"Balas semua"</string> - <string name="general_preference_reply_all_summary" msgid="9191932552604733245">"Jadikan \"Balas semua\" sebagai default untuk membalas pesan"</string> + <string name="general_preference_reply_all_summary" msgid="9191932552604733245">"Jadikan \"Balas semua\" sebagai bawaan untuk membalas pesan"</string> <string name="general_preferences_clear_trusted_senders_title" msgid="507988226277210305">"Tanyakan untuk menampilkan gambar"</string> <string name="general_preferences_clear_trusted_senders_summary" msgid="2648501128162793879">"Gambar dalam pesan tidak akan ditampilkan secara otomatis"</string> <string name="trusted_senders_cleared" msgid="4762002183756251723">"\"Tampilkan gambar\" dihapus."</string> @@ -476,17 +465,6 @@ <string name="search_header_text_fmt" msgid="3857004638127418247">"Hasil penelusuran untuk \"<xliff:g id="ID_1">%1$s</xliff:g>\""</string> <string name="search_slow_warning_title" msgid="2826118321880530239">"Menunggu hasil"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Beberapa server mungkin membutuhkan waktu yang lama."</string> - <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Folder"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Tolak penggunaan kamera perangkat"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Memerlukan sandi perangkat"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Batasi penggunaan ulang sandi terkini"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Mewajibkan sandi dapat kedaluwarsa"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Mnghrskan prgkt nganggur utk mngunci lyr"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Batasi jumlah acara kalender yang disinkronkan"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Batasi jumlah email yang disinkronkan"</string> - <string name="quick_1" msgid="3426057697353380951">"Terima kasih!"</string> - <string name="quick_2" msgid="4188036352885736617">"Menurut saya itu bagus!"</string> - <string name="quick_3" msgid="8061819976353395585">"Saya akan membaca ini nanti dan mengabari Anda."</string> - <string name="quick_4" msgid="3988974084396883051">"Mari kita adakan pertemuan untuk membahas masalah ini."</string> + <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Map"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Sinkronisasi latar belakang untuk akun ini dinonaktifkan saat roaming."</string> </resources> diff --git a/res/values-in/uploader.xml b/res/values-in/uploader.xml index 67849039a..fa9c3be4e 100644 --- a/res/values-in/uploader.xml +++ b/res/values-in/uploader.xml @@ -19,23 +19,23 @@ <string name="summary_subtitle_paused_retry_format" msgid="3851931944505090119">"mencoba ulang dalam %s"</string> <string name="summary_menu_show_pending" msgid="658361192495996">"Tampilkan Unggahan yang Tertunda"</string> <string name="summary_menu_show_finished" msgid="8544099132633066086">"Tampilkan Unggahan yang Sudah Selesai"</string> - <string name="menu_view_online" msgid="6546633605818509942">"Lihat Secara Online"</string> + <string name="menu_view_online" msgid="6546633605818509942">"Lihat Secara Daring"</string> <string name="menu_show_pending_items" msgid="8798191388238604213">"Tampilkan Unggahan yang Tertunda"</string> <string name="menu_hide_pending_items" msgid="9216079748638469160">"Sembunyikan Unggahan yang Tertunda"</string> <string name="menu_show_completed_items" msgid="4380487776635859783">"Tampilkan Detail"</string> <string name="menu_hide_completed_items" msgid="6126007571523662799">"Sembunyikan Detail"</string> <string name="menu_settings" msgid="5088116127086866634">"Setelan"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Diunggah %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Akun"</string> <string name="upload" msgid="2615541458361216022">"Unggah"</string> - <string name="ok" msgid="2516349681897895312">"Oke"</string> + <string name="ok" msgid="2516349681897895312">"OK"</string> <string name="cancel" msgid="1207103189404543868">"Batal"</string> <string name="uploading_to" msgid="3986362895940069510">"Mengunggah ke "<b>"%s"</b></string> <string name="uploading_for" msgid="1735961974624867111">" untuk "<b>"%s"</b></string> <string name="destination_format" msgid="7472552212462849956">"%1$s \"%2$s\""</string> <string name="toast_intent_error" msgid="6164928822619692280">"Inisiasi unggahan gagal."</string> - <string name="toast_file_error" msgid="1315722681020841350">"File tidak tersedia."</string> + <string name="toast_file_error" msgid="1315722681020841350">"Berkas tidak tersedia."</string> <string name="account_error" msgid="1904775271866104941">"Gagal mengambil informasi akun."</string> <string name="toast_failed_auth" msgid="2196450105656960566">"Terjadi masalah saat masuk ke akun Anda."</string> <string name="upload_state_queued" msgid="3990598443227105526"></string> @@ -57,10 +57,10 @@ <string name="retry_in_2min" msgid="5845688527405283031">"2 menit"</string> <string name="retry_in_5min" msgid="3153220715959570358">"5 menit"</string> <string name="retry_no_data" msgid="630347885498641534">"Tidak ada sambungan data"</string> - <string name="account_out_of_quota" msgid="1849612079678906607">"Kuota disk akun habis"</string> - <string name="completed_no_file" msgid="6719715000947601844">"File tidak ditemukan"</string> - <string name="failed_bad_response" msgid="8357723053952213242">"Kesalahan layanan"</string> - <string name="failed_network_error" msgid="2531660472217573602">"Kesalahan jaringan"</string> + <string name="account_out_of_quota" msgid="1849612079678906607">"Kuota diska akun habis"</string> + <string name="completed_no_file" msgid="6719715000947601844">"Berkas tidak ditemukan"</string> + <string name="failed_bad_response" msgid="8357723053952213242">"Galat layanan"</string> + <string name="failed_network_error" msgid="2531660472217573602">"Galat jaringan"</string> <string name="failed_server_auth" msgid="2428208784689362254">"Autentikasi gagal"</string> <string name="manager_list_switcher_pending_format" msgid="3517166351274747172">"Unggahan yang tertunda [%d]"</string> <string name="manager_list_switcher_completed_format" msgid="4700366545949687846">"Unggahan yang selesai [%d]"</string> @@ -80,8 +80,8 @@ <string name="notify_resolved" msgid="8111194870485485674">"Unggahan selesai"</string> <string name="notify_paused" msgid="3999817913227671338">"Unggahan dijeda"</string> <string name="notify_activation_reminder" msgid="1639234651193843030">"Unggah Sekejap belum diaktifkan"</string> - <string name="dialog_first_wifi" msgid="4318047428346248089">"File berukuran besar akan diunggah melalui sambungan WiFi saja."</string> - <string name="dialog_sync_all_scanning" msgid="3175935645776839524">"Memindai file..."</string> + <string name="dialog_first_wifi" msgid="4318047428346248089">"Berkas berukuran besar akan diunggah melalui sambungan WiFi saja."</string> + <string name="dialog_sync_all_scanning" msgid="3175935645776839524">"Memindai berkas..."</string> <string name="dialog_sync_all_preparing" msgid="1666557491871126684">"Menyiapkan <xliff:g id="PHOTOCOUNT">%1$d</xliff:g> foto dan <xliff:g id="VIDEOCOUNT">%2$d</xliff:g> video untuk diunggah..."</string> <string name="dialog_sync_all_found_none" msgid="4066988191364416995">"Tidak ada foto/video tambahan yang perlu diunggah."</string> <string name="dialog_sync_all_server_error" msgid="2177063494820815086">"Terjadi masalah saat berkomunikasi dengan server. Coba lagi nanti."</string> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index da561eda7..8e0d67cc8 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Lettura allegati email"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Consente all\'applicazione di leggere gli allegati email."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Consente all\'applicazione di leggere i tuoi allegati email."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Accesso ai dati del provider di posta"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Consente all\'applicazione di accedere al database della tua posta, inclusi i messaggi ricevuti e inviati, i nomi utente e le password."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Consente a questa applicazione di accedere al database della tua posta, inclusi i messaggi ricevuti e inviati, i nomi utente e le password."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Scrivi"</string> <string name="debug_title" msgid="5175710493691536719">"Debug"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Fine"</string> <string name="create_action" msgid="3062715563215392251">"Crea nuova"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Elimina"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nessuna risposta rapida."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nessuna risposta rapida"</string> <string name="discard_action" msgid="6532206074859505968">"Elimina"</string> <string name="save_draft_action" msgid="6413714270991417223">"Salva bozza"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Inserisci risposta rapida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> ha scritto:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Includi testo citato"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Includi testo"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Aggiungi almeno un destinatario."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Devi aggiungere almeno un destinatario."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Alcuni indirizzi email non sono validi."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"File troppo grande. Impossibile allegarlo."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Inserisci risposta rapida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Salvato"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Interrompi"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Allegato salvato come <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Impossibile salvare allegato."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Prima dell\'invio verranno scaricati uno o più allegati del messaggio inoltrato."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Impossibile salvare allegato."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota. Prima dell\'invio verranno scaricati uno o più allegati del messaggio inoltrato."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Messaggio"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invito"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Impossibile inoltrare uno o più allegati."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Allegato non inoltrato"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Accesso a <xliff:g id="ACCOUNT_NAME">%s</xliff:g> non riuscito."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Accesso a <xliff:g id="ACCOUNT_NAME">%s</xliff:g> non riuscito."</string> <string name="login_failed_title" msgid="7624349996212476176">"Accesso non riuscito"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Puoi configurare un account Exchange ActiveSync con pochi passaggi."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Indirizzo email"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Password"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Invia email da questo account per impostazione predefinita"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Invia email da questo account per impostazione predefinita."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Config. manuale"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Digita un indirizzo email e una password validi."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Account duplicato"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Verifica impostazioni server della posta in arrivo..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Verifica impostazioni server posta in uscita…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Impostazione account"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Il tuo account è stato impostato e l\'email sarà presto disponibile."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Il tuo account è stato impostato e l\'email sarà presto disponibile."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Assegna un nome all\'account (facoltativo)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Il tuo nome (visualizzato nei messaggi in uscita)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Questo campo non può essere vuoto."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Porta"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipo di sicurezza"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Richiedi accesso"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Richiedi accesso"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nome utente"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Password"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Impostazione account"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Ogni 15 minuti"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Ogni 30 minuti"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Ogni ora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Invia email da questo account per impostazione predefinita"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Avvisami all\'arrivo di email"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronizza contatti di questo account"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronizza calendario di questo account"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronizza email di questo account"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Invia email da questo account per impostazione predefinita."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Avvisami all\'arrivo di email."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronizza contatti da questo account."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronizza il calendario da questo account."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronizza le email da questo account."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Scarica allegati automaticamente quando connesso a Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Impossibile completare"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Giorni da sincronizzare"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Un mese"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Tutto"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Usa imp. predefinite account"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Password o nome utente errato."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Password o nome utente errato."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nome utente o password errata."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nome utente o password errata."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Impossibile connettersi in modo sicuro al server."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Impossibile connettersi in modo sicuro al server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"È necessario un certificato client. Vuoi connetterti al server con un certificato client?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certificato non valido o non accessibile."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Il server ha risposto con un errore. Controlla nome utente e password e riprova."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Certificato client richiesto. Connettersi al server con certificato client?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificato non valido o non accessibile."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Il server ha risposto con un errore. Controlla nome utente e password e riprova."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Impossibile connettersi al server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Impossibile connettersi al server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS richiesto ma non supportato dal server."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AVVISO. La disattivazione dell\'autorità dell\'applicazione Email per l\'amministrazione del dispositivo comporterà l\'eliminazione di tutti gli account email che la richiedono, compresi i relativi messaggi email, contatti, eventi di calendario e altri dati."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Aggiornamento sicurezza"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> richiede l\'aggiornamento delle impostazioni di sicurezza."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"L\'account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" non può essere sincronizzato a causa di requisiti di sicurezza."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"È richiesto l\'aggiornamento delle impostazioni di sicurezza per l\'account \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Impostazioni di sicurezza dell\'account \"<xliff:g id="ACCOUNT">%s</xliff:g>\" modificate; nessun intervento richiesto."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Aggiornamento sicurezza richiesto"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Criteri di sicurezza modificati"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Criteri sicurezza non rispettab."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"È richiesto l\'aggiornamento delle impostazioni di sicurezza per l\'account \"<xliff:g id="ACCOUNT">%s</xliff:g>\"."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Aggiornamento sicurezza richiesto"</string> <string name="account_security_title" msgid="3511543138560418587">"Sicurezza dispositivo"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Il server <xliff:g id="SERVER">%s</xliff:g> richiede che tu consenta il controllo remoto di alcune funzionalità di sicurezza del tuo dispositivo Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Modifica dettagli"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Il PIN o la password di blocco dello schermo sono scaduti."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Password blocco schermo scaduta"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Password blocco schermo in scadenza"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Appena possibile devi cambiare il PIN o la password di blocco dello schermo; in caso contrario i dati di <xliff:g id="ACCOUNT">%s</xliff:g> verranno cancellati. Vuoi apportare la modifica ora?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Devi modificare il PIN o la password di blocco dello schermo a breve altrimenti i dati relativi a <xliff:g id="ACCOUNT">%s</xliff:g> verranno cancellati. Apportare la modifica ora?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Password blocco schermo scaduta"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"I dati relativi a <xliff:g id="ACCOUNT">%s</xliff:g> stanno per essere cancellati dal dispositivo. È possibile ripristinarli modificando il PIN o la password di blocco dello schermo. Vuoi apportare la modifica ora?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"I dati relativi a <xliff:g id="ACCOUNT">%s</xliff:g> stanno per essere cancellati dal dispositivo. È possibile ripristinarli modificando il PIN o la password di blocco dello schermo. Apportare la modifica ora?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Ignorare le modifiche non salvate?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Impossibile accedere"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Password o nome utente di <xliff:g id="ACCOUNT">%s</xliff:g> errato. Vuoi aggiornarli ora?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Il nome utente o la password per <xliff:g id="ACCOUNT">%s</xliff:g> non sono corretti. Aggiornarli ora?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Account predefinito"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Invia email da questo account per impostazione predefinita"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Scarica allegati"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Scarica automaticamente allegati messaggi recenti tramite Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notifiche email"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frequenza sincronizzazione, notifiche e altro."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Invia notifica all\'arrivo di email"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notifica sulla barra di sistema l\'arrivo di email"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frequenza di controllo Posta in arrivo"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Impost. posta in arrivo"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nome utente, password e altre impostazioni server in entrata"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Impost. posta in uscita"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nome utente, password e altre impostazioni server in uscita"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Criteri applicati"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nessuna"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Criteri non supportati"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nessuna"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Tentativo di sincronizzazione"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Tocca qui per sincronizzare l\'account"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nome account"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Nome"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Firma"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Risposte rapide"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Modifica il testo che inserisci spesso quando scrivi email"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Modifica il testo che inserisci spesso quando componi le email"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Aggiungi testo ai messaggi inviati"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Impostazioni notifiche"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Utilizzo dati"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Criteri di sicurezza"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Modifica risposta rapida"</string> <string name="save_action" msgid="1988862706623227093">"Salva"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizza contatti"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronizza i contatti per questo account"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizza calendario"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sincron. evento calendario account"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronizza calendario"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronizza il calendario per questo account"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronizza email"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronizza le email per questo account"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrazione"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"In attesa dei risultati"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Alcuni server possono richiedere molto tempo."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Cartelle"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Non consentire uso fotocamera dispositivo"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Richiedi password dispositivo"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Limita riutilizzo password recenti"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Richiedi scadenza password"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Richiedi dispos. inattivo per blocco schermo"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limita numero di eventi calendario sincronizzati"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limita numero di email sincronizzate"</string> - <string name="quick_1" msgid="3426057697353380951">"Grazie."</string> - <string name="quick_2" msgid="4188036352885736617">"Per me va bene."</string> - <string name="quick_3" msgid="8061819976353395585">"Lo leggerò più tardi e ti farò sapere."</string> - <string name="quick_4" msgid="3988974084396883051">"Organizziamo una riunione per discuterne."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Sincronizzazione dello sfondo per questo account disattivata durante il roaming."</string> </resources> diff --git a/res/values-it/uploader.xml b/res/values-it/uploader.xml index 7441ef07c..e1fa61b79 100644 --- a/res/values-it/uploader.xml +++ b/res/values-it/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Nascondi dettagli"</string> <string name="menu_settings" msgid="5088116127086866634">"Impostazioni"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Data caricamento: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Account"</string> <string name="upload" msgid="2615541458361216022">"Carica"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index e018f706f..83ecfd15b 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"קרא קבצים מצורפים לדוא\"ל"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"מאפשר ליישום לקרוא את הקבצים המצורפים לדוא\"ל."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"מאפשר ליישום זה לקרוא את הקבצים המצורפים להודעות הדוא\"ל שלך."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"גש לנתוני ספק הדוא\"ל"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"מאפשר ליישום לגשת למסד הנתונים של הדוא\"ל שלך, כולל להודעות שהתקבלו, להודעות שנשלחו, לשמות משתמש ולסיסמאות."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"מאפשר ליישום זה לגשת למסד הנתונים של הדוא\"ל שלך, כולל להודעות שהתקבלו, להודעות שנשלחו, לשמות משתמש ולסיסמאות."</string> <string name="app_name" msgid="5815426892327290362">"דוא\"ל"</string> <string name="compose_title" msgid="427986915662706899">"חבר הודעה"</string> <string name="debug_title" msgid="5175710493691536719">"ניקוי באגים"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"סיום"</string> <string name="create_action" msgid="3062715563215392251">"צור חדש"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"מחק"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"אין תגובות מהירות."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"אין תגובות מהירות"</string> <string name="discard_action" msgid="6532206074859505968">"מחק"</string> <string name="save_draft_action" msgid="6413714270991417223">"שמור טיוטה"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"הוסף תגובה מהירה"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> כתב:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"כלול טקסט מצוטט"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"כלול טקסט"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"הוסף לפחות נמען אחד."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"עליך להוסיף נמען אחד לפחות."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"חלק מכתובות הדוא\"ל אינן חוקיות."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"הקובץ גדול מדי ולא ניתן לצרף אותו."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"הוסף תגובה מהירה"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"נשמר"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"עצור"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"קובץ מצורף נשמר בשם <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"לא ניתן לשמור את הקובץ המצורף."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"המערכת תוריד קובץ מצורף אחד או יותר בהודעה שהעברת לפני השליחה."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"לא ניתן לשמור את הקובץ המצורף."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"הערה: המערכת תוריד קובץ מצורף אחד או יותר בהודעה שהעברת לפני השליחה."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"הודעה"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"הזמן"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"לא ניתן להעביר קובץ מצורף אחד או יותר."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"הקובץ המצורף לא הועבר"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"הכניסה ל-<xliff:g id="ACCOUNT_NAME">%s</xliff:g> נכשלה."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"הכניסה ל-<xliff:g id="ACCOUNT_NAME">%s</xliff:g> נכשלה."</string> <string name="login_failed_title" msgid="7624349996212476176">"לא ניתן היה להיכנס"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"תוכל להגדיר חשבון Exchange ActiveSync במספר פעולות פשוטות."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"כתובת דוא\"ל"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"סיסמה"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"שלח דוא\"ל מחשבון זה כברירת מחדל"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"שלח דוא\"ל מחשבון זה כברירת מחדל."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"הגדרה ידנית"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"הקלד כתובת דוא\"ל וסיסמה חוקיות."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"חשבון משוכפל"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"בודק הגדרות שרת דואר נכנס..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"בודק הגדרות שרת דואר יוצא..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"הגדרת חשבון"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"החשבון שלך הוגדר והדוא\"ל בדרך!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"החשבון שלך הוגדר והדוא\"ל בדרך!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"תן שם לחשבון זה (אופציונלי)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"שמך (מוצג בהודעות יוצאות)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"שדה זה לא יכול להיות ריק."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"שרת SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"יציאה"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"סוג אבטחה"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"דרושה כניסה"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"דרוש כניסה."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"שם משתמש"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"סיסמה"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"הגדרת חשבון"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"כל 15 דקות"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"כל 30 דקות"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"כל שעה"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"שלח דוא\"ל מחשבון זה כברירת מחדל"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"הודע לי כשמגיע דוא\"ל"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"סנכרן אנשי קשר מחשבון זה"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"סנכרן את לוח השנה מחשבון זה"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"סנכרן דוא\"ל מחשבון זה"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"שלח דוא\"ל מחשבון זה כברירת מחדל."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"הודע לי כשמגיע דוא\"ל."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"סנכרן אנשי קשר מחשבון זה."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"סנכרן את לוח השנה מחשבון זה."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"סנכרן דוא\"ל מחשבון זה."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"הורד קבצים מצורפים באופן אוטומטי כאשר יש חיבור ל-Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"לא ניתן להשלים את הפעולה"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"ימים לסינכרון"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"חודש אחד"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"הכל"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"השתמש בברירת המחדל של החשבון"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"שם המשתמש או הסיסמה שגויים."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"שם המשתמש או הסיסמה שגויים. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"שם המשתמש או הסיסמה שגויים."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"שם המשתמש או הסיסמה שגויים."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"לא ניתן להתחבר לשרת באופן בטוח."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"לא ניתן להתחבר לשרת באופן בטוח."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"דרוש אישרו לקוח. האם אתה רוצה להתחבר לשרת עם אישור לקוח?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"האישור אינו חוקי או שלא ניתן לגשת אליו."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"השרת הגיב עם שגיאה. בדוק את שם המשתמש והסיסמה ונסה שוב."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"נדרש אישור לקוח. להתחבר לשרת עם אישור לקוח?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"האישור אינו חוקי או שלא ניתן לגשת אליו."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"השרת הגיב עם שגיאה. בדוק את שם המשתמש והסיסמה ונסה שוב."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"לא ניתן להתחבר לשרת."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"לא ניתן להתחבר לשרת."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS נדרש אך אינו נתמך בשרת."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"אזהרה: השבתת ההרשאה של יישום הדוא\"ל לטפל במכשיר תגרום למחיקת כל חשבונות הדוא\"ל שמחייבים הרשאה זו, כולל הודעות הדוא\"ל, אנשי הקשר, האירועים בלוח השנה ונתונים אחרים."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"עדכון אבטחה"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> מחייב עדכון של הגדרות האבטחה שלך."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"לא ניתן לסנכרן את החשבון \"<xliff:g id="ACCOUNT">%s</xliff:g>\" עקב דרישות אבטחה."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"החשבון \"<xliff:g id="ACCOUNT">%s</xliff:g>\" דורש עדכון של הגדרות אבטחה."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"חשבון \"<xliff:g id="ACCOUNT">%s</xliff:g>\" שינה את הגדרות האבטחה שלו; לא נדרשת כל פעולה מצד המשתמש."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"נדרש עדכון אבטחה"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"מדיניות האבטחה השתנתה"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"לא ניתן לקיים את הוראות מדיניות האבטחה"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"החשבון \"<xliff:g id="ACCOUNT">%s</xliff:g>\" דורש עדכון של הגדרות אבטחה."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"נדרש עדכון אבטחה"</string> <string name="account_security_title" msgid="3511543138560418587">"אבטחת המכשיר"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"השרת <xliff:g id="SERVER">%s</xliff:g> דורש שתאפשר לו שליטה מרחוק על תכונות אבטחה מסוימות במכשיר ה-Android שלך."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"ערוך פרטים"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"פג תוקף ה-PIN או הסיסמה של נעילת המסך שלך."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"פג תוקף הסיסמה של נעילת המסך"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"תוקף הסיסמה של נעילת המסך עומד לפוג"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"עליך לשנות את ה-PIN או הסיסמה המשמשים לנעילת מסך, אחרת הנתונים של <xliff:g id="ACCOUNT">%s</xliff:g> יימחקו. האם ברצונך להשנות כעת?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"עליך לשנות את ה-PIN או הסיסמה של נעילת המסך בקרוב, אחרת הנתונים של <xliff:g id="ACCOUNT">%s</xliff:g> יימחקו. לשנות זאת כעת?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"פג תוקף הסיסמה של נעילת המסך"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"הנתונים עבור <xliff:g id="ACCOUNT">%s</xliff:g> נמחקים מהמכשיר שלך. תוכל לשחזר אותם על ידי שינוי ה-PIN או הסיסמה של נעילת המסך. האם ברצונך לשנות כעת?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"הנתונים עבור <xliff:g id="ACCOUNT">%s</xliff:g> נמחקים מהמכשיר שלך. תוכל לשחזר אותם על ידי שינוי ה-PIN או הסיסמה של נעילת המסך. לשנות זאת כעת?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"למחוק שינויים שלא נשמרו?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"לא ניתן להיכנס"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"שם המשתמש או הסיסמה עבור <xliff:g id="ACCOUNT">%s</xliff:g> שגוי. האם ברצונך לעדכן כעת?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"שם המשתמש או הסיסמה עבור <xliff:g id="ACCOUNT">%s</xliff:g> שגויים. לעדכן אותם כעת?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"חשבון ברירת מחדל"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"שלח דוא\"ל מחשבון זה כברירת מחדל"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"הורד קבצים מצורפים"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"הורד באופן אוטומטי קבצים מצורפים להודעות שהתקבלו לאחרונה באמצעות WiFi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"התראות דוא\"ל"</string> <string name="account_settings_summary" msgid="8403582255413830007">"תדירות סינכרון, התראות וכדומה"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"שלח הודעה כשמגיע דוא\"ל"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"הצג הודעה בשורת המערכת כאשר מגיע דוא\"ל"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"תדירות בדיקה של דואר נכנס"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"הגדרות דואר נכנס"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"שם משתמש, סיסמה והגדרות אחרות של שרת דואר נכנס"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"הגדרות דואר יוצא"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"שם משתמש, סיסמה והגדרות אחרות של שרת דואר יוצא"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"מדיניות שנאכפה"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"ללא"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"מדיניות לא נתמכת"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"ללא"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"נסה לסנכרן"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"גע כאן כדי לסנכרן חשבון זה"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"שם חשבון"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"השם שלך"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"חתימה"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"תגובות מהירות"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"ערוך טקסט שאתה מוסיף לעתים קרובות בזמן כתיבת דוא\"ל"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"ערוך טקסט שאתה מוסיף לעתים קרובות בזמן כתיבת הודעות דוא\"ל"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"צרף טקסט להודעות שאתה שולח"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"הגדרות התראה"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"שימוש בנתונים"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"מדיניות אבטחה"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"ערוך תגובה מהירה"</string> <string name="save_action" msgid="1988862706623227093">"שמור"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"סנכרן אנשי קשר"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"סנכרן אנשי קשר בחשבון זה"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"סנכרן יומן"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"סינכרון אירוע לוח שנה עבור חשבון זה"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"סנכרן יומן"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"סנכרן יומן בחשבון זה"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"סנכרן דוא\"ל"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"סנכרן דוא\"ל בחשבון זה"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"רטט"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"ממתין לתוצאות"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"שרתים מסוימים עשויים לדרוש זמן רב."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"תיקיות"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"אל תאפשר שימוש במצלמה של המכשיר"</string> - <string name="policy_require_password" msgid="7177274900480984702">"נדרשת סיסמת מכשיר"</string> - <string name="policy_password_history" msgid="5743544498302303181">"הגבל את השימוש החוזר בסיסמאות אחרונות"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"נדרשת תפוגת סיסמאות"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"כפה נעילת מסך של מכשיר לא פעיל"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"הגבל את מספר אירועי לוח השנה המסונכרנים"</string> - <string name="policy_email_age" msgid="7144148367145424963">"הגבל את מספר פריטי הדוא\"ל המסונכרנים"</string> - <string name="quick_1" msgid="3426057697353380951">"תודה!"</string> - <string name="quick_2" msgid="4188036352885736617">"נשמע לי טוב!"</string> - <string name="quick_3" msgid="8061819976353395585">"אקרא את זה מאוחר יותר ואחזור אליך."</string> - <string name="quick_4" msgid="3988974084396883051">"בוא נקבע פגישה כדי לדון בנושא זה."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"סינכרון ברקע של חשבון זה מושבת בזמן נדידה."</string> </resources> diff --git a/res/values-iw/uploader.xml b/res/values-iw/uploader.xml index 4d34fdf06..712280bd1 100644 --- a/res/values-iw/uploader.xml +++ b/res/values-iw/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"הסתר פרטים"</string> <string name="menu_settings" msgid="5088116127086866634">"הגדרות"</string> <string name="format_date_uploaded" msgid="803752037646090928">"הועלה בתאריך %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"חשבון"</string> <string name="upload" msgid="2615541458361216022">"העלה"</string> <string name="ok" msgid="2516349681897895312">"אישור"</string> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index ca25626e9..4484762ef 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"メール添付ファイルの読み取り"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"メールの添付ファイルの読み取りをこのアプリに許可します。"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"メールの添付ファイルの読み取りをこのアプリケーションに許可します。"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"メールプロバイダのデータへのアクセス"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"このアプリにメールデータベース(送受信したメッセージ、ユーザー名、パスワードを含む)へのアクセスを許可します。"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"このアプリケーションにメールデータベース(送受信したメッセージ、ユーザー名、パスワードを含む)へのアクセスを許可します。"</string> <string name="app_name" msgid="5815426892327290362">"メール"</string> <string name="compose_title" msgid="427986915662706899">"作成"</string> <string name="debug_title" msgid="5175710493691536719">"デバッグ"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"完了"</string> <string name="create_action" msgid="3062715563215392251">"新規作成"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"削除"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"クイック返信がありません。"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"クイック返信がありません"</string> <string name="discard_action" msgid="6532206074859505968">"破棄"</string> <string name="save_draft_action" msgid="6413714270991417223">"下書きを保存"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"クイック返信を挿入"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>: "\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"元のメッセージを挿入"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"元のメールを入れる"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"宛先を入力してください。"</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"宛先を入力してください。"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"無効なメールアドレスがあります。"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"添付ファイルが大きすぎます。"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"クイック返信の挿入"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"保存済み"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"停止"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"添付ファイル<xliff:g id="FILENAME">%s</xliff:g>を保存しました。"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"添付ファイルを保存できませんでした。"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"送信前に転送メッセージの添付ファイルがダウンロードされます。"</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"添付ファイルを保存できません。"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"注: 送信前に転送メッセージの添付ファイルがダウンロードされます。"</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"メッセージ"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"招待"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"添付ファイルを転送できませんでした。"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"添付ファイルを転送できません"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>でログインできませんでした。"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>でログインできませんでした。"</string> <string name="login_failed_title" msgid="7624349996212476176">"ログインできませんでした"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Exchange ActiveSyncアカウントのセットアップは簡単な操作で完了します。"</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"メールアドレス"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"パスワード"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"常にこのアカウントでメールを送信"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"いつもこのアカウントでメールを送信"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"手動セットアップ"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"有効なメールアドレスとパスワードを入力してください。"</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"重複するアカウント"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"受信サーバーの設定を確認中..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"送信サーバーの設定を確認中..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"アカウント設定"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"アカウントの設定が完了しました。"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"アカウントの設定が完了しました。"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"このアカウントに名前を付ける (省略可):"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"あなたの名前(送信メールに表示されます)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"このフィールドは必須です。"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTPサーバー"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"ポート"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"セキュリティの種類"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"ログインが必要"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"ログインが必要"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"ユーザー名"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"パスワード"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"アカウント設定"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"15分毎"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"30分毎"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"1時間毎"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"常にこのアカウントでメールを送信"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"メールの着信を知らせる"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"このアカウントから連絡先を同期"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"このアカウントからカレンダーを同期"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"このアカウントからメールを同期"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"いつもこのアカウントでメールを送信"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"メールの着信を知らせる"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"このアカウントから連絡先を同期します。"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"このアカウントからカレンダーを同期"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"このアカウントからメールを同期する"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Wi-Fiへの接続時に添付ファイルを自動的にダウンロードする"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"完了できませんでした"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"同期する日数"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"1か月"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"すべて"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"アカウントのデフォルトを使用"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"ユーザー名またはパスワードが正しくありません。"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"ユーザー名かパスワードが間違っています。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"ユーザー名かパスワードが間違っています。"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"ユーザー名かパスワードが間違っています。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"サーバーへの安全な接続を確立できません。"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"サーバーへの安全な接続を確立できません。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"クライアント証明書が必要です。クライアント証明書を使用してサーバーに接続しますか?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"証明書が無効か、証明書にアクセスできません。"</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"サーバーからエラーが返されました。ユーザー名とパスワードを確認してもう一度お試しください。"</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"クライアント証明書が必要です。クライアント証明書を使用してサーバーに接続しますか?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"証明書が無効か、証明書にアクセスできません。"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"サーバーからエラーが返されました。ユーザー名とパスワードを確認してもう一度お試しください。"</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"サーバーに接続できません。"</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"サーバーに接続できません。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLSが必要ですがサーバーが対応していません。"</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"警告: メールアプリの端末管理権限を無効にすると、権限を必要とするすべてのメールアカウントが削除されます。また、そのアカウントのメール、連絡先、カレンダーの予定などのデータも削除されます。"</string> <string name="account_security_dialog_title" msgid="430041952584831904">"セキュリティの更新"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g>のセキュリティ設定を更新する必要があります。"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"アカウント「<xliff:g id="ACCOUNT">%s</xliff:g>」はセキュリティ要件により同期できません。"</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"アカウント「<xliff:g id="ACCOUNT">%s</xliff:g>」でセキュリティ設定の更新が必要です。"</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"アカウント「<xliff:g id="ACCOUNT">%s</xliff:g>」がセキュリティ設定を変更しました。ユーザーの操作は不要です。"</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"セキュリティの更新が必要です"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"ポリシーが変更されました"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"ポリシーを満たすことができません"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"アカウント「<xliff:g id="ACCOUNT">%s</xliff:g>」でセキュリティ設定の更新が必要です。"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"セキュリティの更新が必要です"</string> <string name="account_security_title" msgid="3511543138560418587">"端末のセキュリティ"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Android搭載携帯のセキュリティ機能の一部に対するリモートコントロールをサーバー<xliff:g id="SERVER">%s</xliff:g>に許可する必要があります。"</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"設定を編集"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"ロック解除PINまたはパスワードの有効期限が切れました。"</string> <string name="password_expired_content_title" msgid="4349518706602252979">"ロック解除パスワードが期限切れ"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"ロック解除パスワードの有効期限が間近です"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"ロック解除PINまたはパスワードを変更しないと、まもなく<xliff:g id="ACCOUNT">%s</xliff:g>のデータが消去されます。今すぐ変更しますか?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"ロック解除PINまたはパスワードを変更しないと、まもなく「<xliff:g id="ACCOUNT">%s</xliff:g>」のデータが消去されます。今すぐ変更しますか?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"ロック解除パスワードが期限切れです"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g>のデータが端末から消去されます。ロック解除PINまたはパスワードを変更するとデータを元に戻すことができます。今すぐ変更しますか?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g>のデータが端末から消去されます。ロック解除PINまたはパスワードを変更するとデータを元に戻すことができます。今すぐ変更しますか?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"保存されていない変更を破棄しますか?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"ログインできませんでした"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g>のユーザー名またはパスワードが正しくありません。今すぐ更新しますか?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g>のユーザー名またはパスワードが正しくありません。今すぐ更新しますか?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"優先アカウントにする"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"いつもこのアカウントでメールを送信"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"添付ファイルのダウンロード"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Wi-Fi接続時に最近のメールの添付ファイルを自動的にダウンロード"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"メール着信通知"</string> <string name="account_settings_summary" msgid="8403582255413830007">"同期頻度、通知、その他"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"メールの着信時に通知を送信"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"メール受信: システムバーで通知"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"受信トレイの確認頻度"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"受信設定"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"ユーザー名、パスワードなど受信サーバーを設定する"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"送信設定"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"ユーザー名、パスワードなど送信サーバーを設定する"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"適用済みポリシー"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"なし"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"未対応ポリシー"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"なし"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"同期する"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"アカウントを同期するにはこちらをタップします"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"アカウント名"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"名前"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"署名"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"クイック返信"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"メールの作成時に頻繁に挿入する文章を編集する"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"メールの作成時に頻繁に挿入する文章を編集する"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"送信メッセージに署名を付ける"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"通知設定"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"データ使用"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"セキュリティポリシー"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"クイック返信の編集"</string> <string name="save_action" msgid="1988862706623227093">"保存"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"連絡先を同期"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"このアカウントの連絡先を同期"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"カレンダーを同期"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"このアカウントのカレンダーの予定を同期"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"カレンダーを同期"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"このアカウントのカレンダーを同期"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"メールを同期する"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"このアカウントのメールを同期"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"バイブレーション"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"結果を待機中"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"サーバーによって時間がかかる場合があります。"</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"フォルダ"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"端末のカメラの使用を許可しない"</string> - <string name="policy_require_password" msgid="7177274900480984702">"端末のパスワードを必須とする"</string> - <string name="policy_password_history" msgid="5743544498302303181">"最近使用したパスワードの再使用を制限する"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"パスワードの有効期限を設定する"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"画面ロック前のアイドル時間を設定する"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"同期するカレンダーの予定の数を制限する"</string> - <string name="policy_email_age" msgid="7144148367145424963">"同期するメールの数を制限する"</string> - <string name="quick_1" msgid="3426057697353380951">"ありがとうございます。"</string> - <string name="quick_2" msgid="4188036352885736617">"良いと思います。"</string> - <string name="quick_3" msgid="8061819976353395585">"確認して折り返し連絡します。"</string> - <string name="quick_4" msgid="3988974084396883051">"この件についてミーティングを行いませんか。"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"このアカウントのバックグラウンドでの同期は、ローミング中は無効です。"</string> </resources> diff --git a/res/values-ja/uploader.xml b/res/values-ja/uploader.xml index bcd33ca87..c3d7ec45f 100644 --- a/res/values-ja/uploader.xml +++ b/res/values-ja/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"詳細を表示しない"</string> <string name="menu_settings" msgid="5088116127086866634">"設定"</string> <string name="format_date_uploaded" msgid="803752037646090928">"アップロード済み: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"アカウント"</string> <string name="upload" msgid="2615541458361216022">"アップロード"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index bb331a12b..e4d8a6f3f 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"이메일 첨부파일 읽기"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"앱이 이메일 첨부파일을 읽도록 허용합니다."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"애플리케이션이 이메일 첨부파일을 읽도록 허용합니다."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"이메일 제공업체 데이터 액세스"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"앱이 받은 메일, 보낸 메일, 사용자 이름 및 비밀번호를 포함하는 이메일 데이터베이스에 액세스하도록 허용합니다."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"애플리케이션이 받은 메일, 보낸 메일, 사용자 이름 및 비밀번호를 포함하는 이메일 데이터베이스에 액세스하도록 합니다."</string> <string name="app_name" msgid="5815426892327290362">"이메일"</string> <string name="compose_title" msgid="427986915662706899">"편지쓰기"</string> <string name="debug_title" msgid="5175710493691536719">"디버그"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"완료"</string> <string name="create_action" msgid="3062715563215392251">"새로 만들기"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"삭제"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"빠른 응답이 없습니다."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"빠른 응답이 없습니다."</string> <string name="discard_action" msgid="6532206074859505968">"삭제"</string> <string name="save_draft_action" msgid="6413714270991417223">"임시보관함에 저장"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"빠른 응답 삽입"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>님이 작성:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"받은메일 포함"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"받은메일 포함"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"받는 사람을 한 명 이상 추가하세요."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"받는 사람을 한 명 이상 추가해야 합니다."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"일부 이메일 주소가 올바르지 않습니다."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"파일이 너무 커서 첨부할 수 없습니다."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"빠른 응답 삽입"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"저장됨"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"중지"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"첨부파일을 <xliff:g id="FILENAME">%s</xliff:g>(으)로 저장했습니다."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"첨부파일을 저장하지 못했습니다."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"전달된 메일에 하나 이상의 첨부파일을 다운로드한 다음 전송합니다."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"첨부파일을 저장할 수 없습니다."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"참고: 메일을 전달하기 전에 첨부파일을 다운로드합니다."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"메일"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"초대"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"하나 이상의 첨부파일을 전달하지 못했습니다."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"첨부파일을 전달하지 못했습니다."</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>에 로그인하지 못했습니다."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>에 로그인하지 못했습니다."</string> <string name="login_failed_title" msgid="7624349996212476176">"로그인하지 못했습니다."</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"간단한 절차만으로 Exchange ActiveSync 계정을 설정할 수 있습니다."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"이메일 주소"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"비밀번호"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"이 계정에서 이메일 보냄(기본값)"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"기본적으로 이 계정에서 이메일 전송"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"수동 설정"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"올바른 이메일 주소와 비밀번호를 입력하세요."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"중복 계정"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"받는 서버 설정 확인 중..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"발신 서버 설정 확인 중..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"계정 설정"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"계정이 설정되었으며 이메일을 사용할 수 있습니다."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"계정이 설정되었으며 이메일을 사용할 수 있습니다."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"계정 이름 지정(선택사항)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"이름(메일에 표시)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"이 입력란은 비워 둘 수 없습니다."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP 서버"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"포트"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"보안 유형"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"로그인 필요"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"로그인 필요"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"사용자 이름"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"비밀번호"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"계정 설정"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"15분마다"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"30분마다"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"1시간마다"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"이 계정에서 이메일 보냄(기본값)"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"이메일이 오면 알림"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"이 계정에서 연락처 동기화"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"이 계정에서 캘린더 동기화"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"이 계정에서 이메일 동기화"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"기본적으로 이 계정에서 이메일 전송"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"이메일이 오면 알림"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"이 계정에서 연락처를 동기화합니다."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"이 계정에서 캘린더를 동기화합니다."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"이메일 동기화"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Wi-Fi에 연결되면 자동으로 첨부파일 다운로드"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"완료할 수 없음"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"동기화할 일 수"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"1달"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"전체"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"계정 기본값 사용"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"사용자 이름 또는 비밀번호가 잘못되었습니다."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"사용자 이름 또는 비밀번호가 잘못되었습니다."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"서버에 안전하게 연결할 수 없습니다."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"서버에 안전하게 연결할 수 없습니다."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"클라이언트 인증서가 필요합니다. 클라이언트 인증서로 서버에 연결하시겠습니까?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"인증서가 잘못되었거나 액세스할 수 없습니다."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"서버에서 오류를 발견했습니다. 사용자 이름과 비밀번호를 확인한 다음 다시 시도해 주세요."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"클라이언트 인증서가 필요합니다. 클라이언트 인증서로 서버에 연결하시겠습니까?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"인증서가 잘못되었거나 액세스할 수 없습니다."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"서버에서 오류를 발견했습니다. 사용자 이름과 비밀번호를 확인한 다음 다시 시도해 주세요."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"서버에 연결할 수 없습니다."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"서버에 연결할 수 없습니다."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS가 필요하지만 서버에서 지원하지 않습니다."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"경고: 이메일 앱의 기기 관리 권한을 비활성화하면 관련된 모든 이메일 계정 및 이메일, 주소록, 캘린더 일정 및 기타 데이터가 모두 삭제됩니다."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"보안 업데이트"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g>의 보안 설정을 업데이트해야 합니다."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"\'<xliff:g id="ACCOUNT">%s</xliff:g>\' 계정이 보안 요구사항으로 인해 동기화될 수 없습니다."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"\'<xliff:g id="ACCOUNT">%s</xliff:g>\' 계정의 보안 설정을 업데이트해야 합니다."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"\'<xliff:g id="ACCOUNT">%s</xliff:g>\' 계정의 보안 설정이 변경되었습니다. 사용자의 조치는 필요하지 않습니다."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"보안 업데이트 필요"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"보안 정책 변경됨"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"보안 정책을 준수할 수 없음"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"\'<xliff:g id="ACCOUNT">%s</xliff:g>\' 계정을 사용하려면 보안 설정을 업데이트해야 합니다."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"보안 업데이트가 필요합니다."</string> <string name="account_security_title" msgid="3511543138560418587">"기기 보안"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"<xliff:g id="SERVER">%s</xliff:g> 서버가 Android 기기의 몇 가지 보안 기능을 원격으로 제어할 수 있도록 해야 합니다."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"세부정보 수정"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"화면 잠금 PIN 또는 비밀번호가 만료되었습니다."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"화면 잠금 비밀번호가 만료되었습니다."</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"화면 잠금 비밀번호가 곧 만료될 예정입니다."</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"곧 화면 잠금 PIN 또는 비밀번호를 변경해야 하며, 변경하지 않으면 <xliff:g id="ACCOUNT">%s</xliff:g>의 데이터가 지워집니다. 지금 변경하시겠습니까?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"곧 화면 잠금 PIN 또는 비밀번호를 변경해야 하며, 변경하지 않으면 <xliff:g id="ACCOUNT">%s</xliff:g>의 데이터가 지워집니다. 지금 변경하시겠습니까?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"화면 잠금 비밀번호가 만료되었습니다."</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g>의 데이터가 기기에서 지워졌습니다. 화면 잠금 PIN 또는 비밀번호를 변경하면 데이터를 복구할 수 있습니다. 지금 변경하시겠습니까?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g>의 데이터가 기기에서 지워졌습니다. 화면 잠금 PIN 또는 비밀번호를 변경하면 데이터를 복구할 수 있습니다. 지금 변경하시겠습니까?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"저장되지 않은 변경사항을 삭제하시겠습니까?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"로그인하지 못했습니다."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g>의 사용자 이름 또는 비밀번호가 잘못되었습니다. 지금 업데이트하시겠습니까?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g>의 사용자 이름 또는 비밀번호가 잘못되었습니다. 지금 업데이트하시겠습니까?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"기본 계정"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"기본적으로 이 계정에서 이메일 전송"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"첨부파일 다운로드"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Wi-Fi를 통해 최근 메일의 첨부파일을 자동으로 다운로드합니다."</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"이메일 알림"</string> <string name="account_settings_summary" msgid="8403582255413830007">"빈도 및 알림 등을 동기화합니다."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"이메일이 오면 알림을 보냄"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"이메일이 오면 시스템 바에서 알림"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"받은편지함 확인 빈도"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"수신 설정"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"사용자 이름, 비밀번호 및 기타 받는 서버 설정"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"발신 설정"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"사용자 이름, 비밀번호 및 기타 보내는 서버 설정"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"적용 정책"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"선택 안함"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"지원되지 않는 정책"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"선택 안함"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"동기화 시도"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"이 계정을 동기화하려면 여기를 터치하세요."</string> <string name="account_settings_description_label" msgid="8894815221204511715">"계정 이름"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"이름"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"서명"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"빠른 응답"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"이메일을 작성할 때 자주 사용하는 텍스트 수정"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"이메일을 작성할 때 자주 사용하는 텍스트 수정"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"보내는 메일에 텍스트 첨부"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"알림 설정"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"데이터 사용"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"보안 정책"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"빠른 응답 수정"</string> <string name="save_action" msgid="1988862706623227093">"저장"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"연락처 동기화"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"이 계정의 주소록을 동기화합니다."</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"캘린더 동기화"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"이 계정의 캘린더 일정을 동기화합니다."</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"캘린더 동기화"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"이 계정의 캘린더를 동기화합니다."</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"이메일 동기화"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"이 계정의 이메일을 동기화합니다."</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"진동"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"결과를 기다리는 중"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"일부 서버는 시간이 오래 걸릴 수 있습니다."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"폴더"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"기기 카메라 사용 허용 안함"</string> - <string name="policy_require_password" msgid="7177274900480984702">"기기 비밀번호 필요"</string> - <string name="policy_password_history" msgid="5743544498302303181">"최근 사용한 비밀번호 재사용 제한"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"비밀번호 만료 필요"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"유휴 상태인 기기 화면 잠금 필요"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"동기화된 캘린더 일정의 개수 제한"</string> - <string name="policy_email_age" msgid="7144148367145424963">"동기화된 이메일의 개수 제한"</string> - <string name="quick_1" msgid="3426057697353380951">"감사합니다."</string> - <string name="quick_2" msgid="4188036352885736617">"좋습니다."</string> - <string name="quick_3" msgid="8061819976353395585">"나중에 읽어보고 연락 드리겠습니다."</string> - <string name="quick_4" msgid="3988974084396883051">"회의에서 얘기해 봅시다."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"계정 백그라운드 동기화가 로밍하는 동안 사용 중지됩니다."</string> </resources> diff --git a/res/values-ko/uploader.xml b/res/values-ko/uploader.xml index 64dec285b..adbc79f10 100644 --- a/res/values-ko/uploader.xml +++ b/res/values-ko/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"세부정보 숨기기"</string> <string name="menu_settings" msgid="5088116127086866634">"설정"</string> <string name="format_date_uploaded" msgid="803752037646090928">"업로드 날짜: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"계정"</string> <string name="upload" msgid="2615541458361216022">"업로드"</string> <string name="ok" msgid="2516349681897895312">"확인"</string> diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml index deb62c96e..d4fb81fc7 100644 --- a/res/values-land/styles.xml +++ b/res/values-land/styles.xml @@ -23,6 +23,23 @@ <item name="android:ellipsize">end</item> </style> + <style name="action_bar_spinner_primary_text"> + <item name="android:includeFontPadding">false</item> + <item name="android:textSize">14sp</item> + <item name="android:textColor">@color/text_primary_color</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">end</item> + </style> + + <style name="action_bar_spinner_secondary_text"> + <item name="android:includeFontPadding">false</item> + <item name="android:textSize">12sp</item> + <item name="android:textColor">@color/text_secondary_color</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">end</item> + <item name="android:layout_marginTop">-2dip</item> + </style> + <style name="message_view_action_buttons" parent="android:Widget.Holo.Button.Borderless"> <item name="android:layout_width">32dip</item> <item name="android:layout_height">24dip</item> diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index e3764834e..e97eab52f 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Skaityti el. laiškų priedus"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Leidžiama programai skaityti el. laiškų priedus."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Leidžiama šiai programai skaityti el. laiškų priedus."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Pasiekti el. pašto paslaugų teikėjo duomenis"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Leidžiama šiai programai pasiekti el. pašto duomenis, įskaitant gautus, išsiųstus pranešimus, naudotojų vardus ir slaptažodžius."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Leidžiama šiai programai pasiekti el. pašto duomenis, įskaitant gautus, išsiųstus pranešimus, naudotojų vardus ir slaptažodžius."</string> <string name="app_name" msgid="5815426892327290362">"El. paštas"</string> <string name="compose_title" msgid="427986915662706899">"Sukurti"</string> <string name="debug_title" msgid="5175710493691536719">"Derinti"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Atlikta"</string> <string name="create_action" msgid="3062715563215392251">"Sukurti naują"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Ištrinti"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nėra greitų atsakymų."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nėra greitų atsakymų"</string> <string name="discard_action" msgid="6532206074859505968">"Atmesti"</string> <string name="save_draft_action" msgid="6413714270991417223">"Išsaug. juodraš."</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Įterpti greitą atsaką"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> rašė:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Įtraukti cituojamą tekstą"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Įtraukti tekstą"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Pridėkite bent vieną gavėją."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Turite pridėti bent vieną gavėją."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Kai kurie el. pašto adresai neteisingi."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Failas per didelis, kad būtų pridėtas."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Įterpti greitą atsaką"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Išsaugota"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Sustabdyti"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Priedas išsaugotas kaip <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Nepavyko išsaugoti priedo."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Prieš siunčiant persiųstame pranešime bus atsisiųstas mažiausiai vienas priedas."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Nepavyko išsaugoti priedo."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Pastaba: prieš siunčiant bus atsisiųstas mažiausiai vienas priedas persiųstame pranešime."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Pranešimas"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Pakviesti"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Nepavyko persiųsti mažiausiai vieno priedo."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Priedas nepersiųstas"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Nepavyko prisijungti prie <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Įvyko prisijungimo prie „<xliff:g id="ACCOUNT_NAME">%s</xliff:g>“ klaida."</string> <string name="login_failed_title" msgid="7624349996212476176">"Nepavyko prisijungti"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Galite nustatyti „Exchange ActiveSync“ paskyrą atlikę vos kelis veiksmus."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"El. pašto adresas"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Slaptažodis"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Pagal numatytuosius nustatymus siųsti el. laišką iš šios paskyros"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Pagal numatytuosius nustatymus siųsti el. laišką iš šios paskyros."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Neaut. nustat."</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Įveskite galiojantį el. pašto adresą ir slaptažodį."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Kopijuoti paskyrą"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Tikrinami gaunamų laiškų serverio nustatymai..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Tikrinami siunčiamo serverio nustatymai..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Paskyros sąranka"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Paskyra nustatyta, el. laiškas išsiųstas!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Paskyra nustatyta ir išsiųstas el. laiškas!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Suteikti šiai paskyrai pavadinimą (pasirenkama)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Jūsų vardas ir pavardė (pateikiami siunčiamuose pranešimuose)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Šis laukas negali būti tuščias."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP serveris"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Prievadas"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Saugos tipas"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Reikalauti prisijungti"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Reikalauti prisijungti."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Naudotojo vardas"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Slaptažodis"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Paskyros sąranka"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Kas 15 min."</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Kas 30 min."</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Kas valandą"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Pagal numatytuosius nustatymus siųsti el. laišką iš šios paskyros"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Pranešti, kai gausiu el. laišką"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinchronizuoti šios paskyros kontaktus"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinchronizuoti šios paskyros kalendorių"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinchronizuoti šios paskyros el. paštą"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Pagal numatytuosius nustatymus siųsti el. laišką iš šios paskyros."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Pranešti man, kai gausiu el. laišką."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinchronizuoti šios paskyros adresatus."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinchronizuoti šios paskyros kalendorių."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sinchronizuoti el. paštą iš šios paskyros."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automatiškai atsisiųsti priedus, kai prisijungiama prie „Wi-Fi“"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nepavyko užbaigti"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Sinchronizuojamų dienų skaičius"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Vienas mėnuo"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Visas"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Naudoti num. pask. nust."</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Neteisingas naudotojo vardas ar slaptažodis."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Neteisingas naudotojo vardas ar slaptažodis."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Neteisingas naudotojo vardas ar slaptažodis."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Neteisingas naudotojo vardas ar slaptažodis."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nepavyksta saugiai prisijungti prie serverio."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nepavyksta saugiai prisijungti prie serverio."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Reikalingas kliento sertifikatas. Ar norite prie serverio prisijungti naudodami kliento sertifikatą?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifikatas netinkamas ar nepasiekiamas."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Serveris atsakė pateikdamas klaidą. Patikrinkite naudotojo vardą bei slaptažodį ir bandykite dar kartą."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Reikia kliento sertifikato. Prisijungti prie serverio naudojant kliento sertifikatą?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikatas negalioja arba nepasiekiamas."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Serveris atsakė pateikdamas klaidą. Patikrinkite naudotojo vardą bei slaptažodį ir bandykite dar kartą."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nepavyksta prisijungti prie serverio."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Negalima prisijungti prie serverio."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Reikalingas TLS, bet jo nepalaiko serveris."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ĮSPĖJIMAS: išaktyvinus el. pašto programos leidimą administruoti įrenginį, bus ištrintos visos el. pašto paskyros, kurioms jis reikalingas, įskaitant el. laiškus, kontaktus, kalendoriaus įvykius ir kitus duomenis."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Saugos naujinys"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"„<xliff:g id="ACCOUNT">%s</xliff:g>“ reikia atnaujinti saugos nustatymus."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Paskyros „<xliff:g id="ACCOUNT">%s</xliff:g>“ negalima sinchronizuoti dėl saugos reikalavimų."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Reikalingas „<xliff:g id="ACCOUNT">%s</xliff:g>“ paskyros saugos nustatymų atnaujinimas."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Pasikeitė paskyros „<xliff:g id="ACCOUNT">%s</xliff:g>“ saugos nustatymai. Nereikia imtis jokių veiksmų."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Reikalingas saugos atnaujinimas"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Pakeista saugos politika"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Neįman. atitikti saugos polit."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Reikalingas paskyros „<xliff:g id="ACCOUNT">%s</xliff:g>“ saugos nustatymų atnaujinimas."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Būtina atnaujinti saugumą"</string> <string name="account_security_title" msgid="3511543138560418587">"Įrenginio sauga"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Serveris „<xliff:g id="SERVER">%s</xliff:g>“ reikalauja leisti jam nuotoliniu būdu valdyti kai kurias „Android“ įrenginio saugos funkcijas."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Redaguoti išsamią informaciją"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Baigėsi ekrano užrakto PIN kodo ar slaptažodžio galiojimo laikas."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Baig. ekr. užr. slapt. galioj. laikas"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Baigiasi ekr. užr. slapt. galioj. laikas"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Būtinai reikia greitu metu pakeisti ekrano užrakinimo PIN kodą ar slaptažodį, nes bus ištrinti „<xliff:g id="ACCOUNT">%s</xliff:g>“ duomenys. Ar norite jį pakeisti dabar?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Būtina greitai pakeisti ekrano užrakto PIN kodą ar slaptažodį, nes bus ištrinti „<xliff:g id="ACCOUNT">%s</xliff:g>“ duomenys. Pakeisti dabar?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Baig. ekr. užr. slapt. galioj. laikas"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Iš įrenginio ištrinami „<xliff:g id="ACCOUNT">%s</xliff:g>“ duomenys. Galite juos atkurti pakeisdami ekrano užrakinimo PIN kodą ar slaptažodį. Ar norite pakeisti jį dabar?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Iš jūsų įrenginio ištrinami „<xliff:g id="ACCOUNT">%s</xliff:g>“ duomenys. Atkurti juos galite pakeisdami ekrano užrakto PIN kodą ar slaptažodį. Pakeisti dabar?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Atmesti neišsaugotus pakeitimus?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Nepavyko prisijungti"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Neteisingas „<xliff:g id="ACCOUNT">%s</xliff:g>“ naudotojo vardas ar slaptažodis. Ar norite atnaujinti juos dabar?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"„<xliff:g id="ACCOUNT">%s</xliff:g>“ naudotojo vardas ar slaptažodis neteisingas. Atnaujinti juos dabar?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Numatytoji paskyra"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Pagal numatytuosius nustatymus siųsti el. laišką iš šios paskyros"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Atsisiųsti priedus"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automatiškai atsis. naujausių pranešimų priedai per „Wi-Fi“"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"El. pašto pranešimai"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sinchronizavimo dažnumas, pranešimai ir kt."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Siųsti pranešimą, kai gaunamas el. laiškas"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Kai atsiunčiamas el. laiškas, pranešti sistemos juostoje"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Gautųjų tikrinimo dažnumas"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Gaunamų laiškų nustatymai"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Naudotojo vardas, slaptažodis ir kiti gavimo serverio nustatymai"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Siunčiamų laiškų nustatymai"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Naudotojo vardas, slaptažodis ir kiti siuntimo serv. nustatymai"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Vykdoma politika"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nėra"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nepalaikoma politika"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nėra"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Bandyti sinchronizuoti"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Jei norite sinchronizuoti šią paskyrą, palieskite čia"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Paskyros pavadinimas"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Jūsų vardas ir pavardė"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Parašas"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Greiti atsakai"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Redaguokite tekstą, kurį dažnai įterpiate kurdami el. laišką"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Redaguokite tekstą, kurį dažnai įterpiate kurdami el. laiškus"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Priskirti tekstą prie siunčiamų pranešimų"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Įspėjimų nustatymai"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Duomenų naudojimas"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Saugos politika"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Redaguoti greitą atsaką"</string> <string name="save_action" msgid="1988862706623227093">"Išsaugoti"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinchronizuoti adresatus"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sinchron. šios paskyros kontaktus"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinchronizuoti kalendorių"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinchron. šios paskyros kalendorių"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sinchron. Kalendorių"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sinchron. šios paskyros kalendorių"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sinchron. el. paštą"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sinchron. šios paskyros el. paštą"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibruoti"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Laukiama rezultatų"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Kai kurie serveriai gali ilgai užtrukti."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Aplankai"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Neleisti naudoti įrenginio fotoaparato"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Reikalauti įrenginio slaptažodžio"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Riboti naujausių slapt. pakart. panaud."</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Reikalauti slaptaž. galiojimo pabaigos"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Užrakinti ekraną nenaudojant įrenginio"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Riboti sinchron. kalendoriaus įvykių skaičių"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Riboti sinchronizuojamų el. laiškų skaičių"</string> - <string name="quick_1" msgid="3426057697353380951">"Ačiū!"</string> - <string name="quick_2" msgid="4188036352885736617">"Skamba gerai!"</string> - <string name="quick_3" msgid="8061819976353395585">"Perskaitysiu vėliau ir jums atsakysiu."</string> - <string name="quick_4" msgid="3988974084396883051">"Aptarkime tai susitikę."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Foninis šios paskyros sinchronizavimas neleidžiamas perduodant duomenis tarptinkliniu ryšiu."</string> </resources> diff --git a/res/values-lt/uploader.xml b/res/values-lt/uploader.xml index 281fd8cf6..d1a65c669 100644 --- a/res/values-lt/uploader.xml +++ b/res/values-lt/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Slėpti išsamią informaciją"</string> <string name="menu_settings" msgid="5088116127086866634">"Nustatymai"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Įkelta %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Paskyra"</string> <string name="upload" msgid="2615541458361216022">"Įkelti"</string> <string name="ok" msgid="2516349681897895312">"Gerai"</string> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index e1eef468a..10985e5d8 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Lasīt e-pasta ziņojumu pielikumus"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Ļauj lietotnei lasīt e-pasta ziņojumu pielikumus."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Nodrošina šai lietojumprogrammai lasīšanas piekļuvi e-pasta ziņojumu pielikumiem."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Piekļūt e-pasta pakalpojumu sniedzēja datiem"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Ļauj lietotnei piekļūt jūsu e-pasta datu bāzei, tostarp saņemtajiem ziņojumiem, nosūtītajiem ziņojumiem, lietotājvārdiem un parolēm."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Ļauj lietojumprogrammai piekļūt jūsu e-pasta datu bāzei, tostarp saņemtajiem ziņojumiem, nosūtītajiem ziņojumiem, lietotājvārdiem un parolēm."</string> <string name="app_name" msgid="5815426892327290362">"E-pasts"</string> <string name="compose_title" msgid="427986915662706899">"E-pasta ziņojuma rakstīšana"</string> <string name="debug_title" msgid="5175710493691536719">"Atkļūdot"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Gatavs"</string> <string name="create_action" msgid="3062715563215392251">"Izveidot jaunu"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Dzēst"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nav ātro atbilžu."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nav ātro atbilžu."</string> <string name="discard_action" msgid="6532206074859505968">"Atmest"</string> <string name="save_draft_action" msgid="6413714270991417223">"Saglabāt melnr."</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Ievietot ātro atbildi"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> rakstīja:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Citēta teksta iekļaušana"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Iekļaut tekstu"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Pievienojiet vismaz vienu adresātu."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Jāpievieno vismaz viens adresāts."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Dažas e-pasta adreses nav derīgas."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Failu nevar pievienot, jo tas ir pārāk liels."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Ātrās atbildes ievietošana"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Saglabāts"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Apturēt"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Pielikums saglabāts kā <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Nevarēja saglabāt pielikumu."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Viens vai vairāki pārsūtītā ziņojuma pielikumi pirms sūtīšanas tiks lejupielādēti."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Nevarēja saglabāt pielikumu."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Piezīme. Viens vai vairāki pārsūtītā ziņojuma pielikumi pirms sūtīšanas tiks lejupielādēti."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Ziņojums"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Uzaicināt"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Nevarēja pārsūtīt vienu vai vairākus pielikumus."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Pielikums netika nosūtīts."</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Neizdevās pierakstīties kontā <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Neizdevās pierakstīties kontā <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Nevarēja pierakstīties"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Varat iestatīt Exchange ActiveSync kontu, veicot tikai dažas darbības."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-pasta adrese"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Parole"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Pēc noklusējuma sūtīt e-pasta ziņojumus no šī konta"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Pēc noklusējuma sūtīt e-pastu no šī konta."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuāla iestatīšana"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Ierakstiet derīgu e-pasta adresi un paroli."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dublikāta konts"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Notiek servera ienākošo datu iestatījumu pārbaude..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Notiek servera izejošo datu iestatījumu pārbaude…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Konta iestatīšana"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Jūsu konts ir izveidots, un ir nosūtīts e-pasta ziņojums."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Jūsu konts ir iestatīts, un ir nosūtīts e-pasta ziņojums."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Ievadiet konta nosaukumu (neobligāti)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Jūsu vārds (attēlots izejošajos ziņojumos)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Šis lauks nedrīkst būt tukšs."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP serveris"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Ports"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Drošības veids"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Pieprasīt pierakstīšanos"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Pieprasīt pierakstīšanos."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Lietotājvārds"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Parole"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Konta iestatīšana"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Ik pēc 15 minūtēm"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Ik pēc 30 minūtēm"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Ik pēc stundas"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Pēc noklusējuma sūtīt e-pasta ziņojumus no šī konta"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Paziņot man, kad tiek saņemts jauns e-pasta ziņojums"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinhronizēt šī konta kontaktpersonas"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinhronizēt šī konta kalendāru"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinhronizēt šī konta e-pastu"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Pēc noklusējuma sūtīt e-pastu no šī konta."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Paziņot man, kad tiek saņemts jauns e-pasta ziņojums."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinhronizēt kontaktpersonas no šī konta."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinhronizēt šī konta kalendāru."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Šī konta e-pasta sinhronizācija."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automātiski lejupielādēt pielikumus, kad ir izveidots WiFi savienojums"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nevarēja pabeigt"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Sinhronizējamās dienas"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Viens mēnesis"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Visi"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Izmantot konta noklusēj."</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nepareizs lietotājvārds vai parole."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Lietotājvārds vai parole nav pareiza."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Lietotājvārds vai parole nav pareiza."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Lietotājvārds vai parole nav pareiza."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nevar izveidot drošu savienojumu ar serveri."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nevar izveidot drošu savienojumu ar serveri."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Ir nepieciešams klienta sertifikāts. Vai vēlaties izveidot savienojumu ar serveri, izmantojot klienta sertifikātu?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifikāts nav derīgs vai nav pieejams."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Serveris atgrieza kļūdu. Pārbaudiet lietotājvārdu un paroli un pēc tam mēģiniet vēlreiz."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Ir nepieciešams klienta sertifikāts. Vai izveidot savienojumu ar serveri, izmantojot klienta sertifikātu?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikāts nav derīgs vai nav pieejams."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Serveris atgrieza kļūdu. Pārbaudiet lietotājvārdu un paroli un pēc tam mēģiniet vēlreiz."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nevar izveidot savienojumu ar serveri."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nevar izveidot savienojumu ar serveri."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Protokols TLS ir obligāts, taču serveris to neatbalsta."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"BRĪDINĀJUMS: deaktivizējot lietotnes E-pasts tiesības administrēt jūsu ierīci, tiks dzēsti visi e-pasta konti, kuriem šī funkcionalitāte ir nepieciešama, kā arī šo kontu e-pasta ziņojumi, kontaktpersonas, kalendāra pasākumi un citi dati."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Drošības atjauninājums"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Kontam <xliff:g id="ACCOUNT">%s</xliff:g> ir jāatjaunina drošības iestatījumi."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Kontu <xliff:g id="ACCOUNT">%s</xliff:g> nevar sinhronizēt drošības prasību dēļ."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Kontā <xliff:g id="ACCOUNT">%s</xliff:g> ir jāatjaunina drošības iestatījumi."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Kontā <xliff:g id="ACCOUNT">%s</xliff:g> ir mainīti drošības iestatījumi; lietotājam nav jāveic nekādas darbības."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Nepieciešams drošības atjaun."</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Droš. politikas ir mainītas."</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Netiek ievērota droš. politika"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Kontā “<xliff:g id="ACCOUNT">%s</xliff:g>” nepieciešams atjaunināt drošības iestatījumus."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Nepiecieš. droš. atjauninājums"</string> <string name="account_security_title" msgid="3511543138560418587">"Ierīces drošība"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Serveris <xliff:g id="SERVER">%s</xliff:g> pieprasa, lai jūs tam atļautu attālināti vadīt dažas jūsu Android ierīces drošības funkcijas."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Rediģēt datus"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Ekrāna bloķēšanas PIN vai paroles derīguma termiņš ir beidzies."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Ekr. bloķ. paroles term. b."</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Ekr. bloķ. paroles term. tuvojas beigām"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Jums drīzumā ir jāmaina ekrāna bloķēšanas PIN vai parole, citādi konta <xliff:g id="ACCOUNT">%s</xliff:g> dati tiks dzēsti. Vai vēlaties to mainīt tūlīt?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Jums drīzumā ir jāmaina ekrāna bloķēšanas PIN vai parole, pretējā gadījumā konta <xliff:g id="ACCOUNT">%s</xliff:g> dati tiks dzēsti. Vai mainīt tūlīt?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Ekrāna bloķēš. paroles termiņa beigas"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Konta <xliff:g id="ACCOUNT">%s</xliff:g> dati tiek dzēsti no šīs ierīces. Tos var atjaunot, nomainot ekrāna bloķēšanas PIN vai paroli. Vai vēlaties to mainīt tūlīt?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Konta <xliff:g id="ACCOUNT">%s</xliff:g> dati tiek dzēsti no šīs ierīces. Varat tos atjaunot, nomainot ekrāna bloķēšanas PIN vai paroli. Vai mainīt tūlīt?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Vai atmest nesaglabātās izmaiņas?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Nevarēja pierakstīties"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Konta <xliff:g id="ACCOUNT">%s</xliff:g> lietotājvārds vai parole nav pareiza. Vai vēlaties tos atjaunināt tūlīt?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Konta <xliff:g id="ACCOUNT">%s</xliff:g> lietotājvārds un parole nav pareizi. Vai atjaunināt tos tūlīt?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Noklusējuma konts"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Pēc noklusējuma sūtīt e-pasta ziņojumus no šī konta"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Lejupielādēt pielikumus"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automātiski lejupielādēt jaunāko ziņojumu pielikumus Wi-Fi tīklā"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-pasta paziņojumi"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sinhronizācijas biežums, paziņojumi u.c."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Nosūtīt paziņojumu, kad tiek saņemts e-pasta ziņojums"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Rādīt paziņojumu statusa joslā, kad tiek saņemts e-pasta ziņojums"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Iesūtnes pārbaudes biežums"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Ienākošo datu iestatījumi"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Lietotājvārds, parole u.c. ienākošā pasta servera iestatījumi"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Izejošo datu iestatījumi"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Lietotājvārds, parole un citi izejošā pasta servera iestatījumi"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Īstenotās politikas"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nav"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Neatbalstītas politikas"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nav"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Sinhronizēt"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Pieskarties šeit, lai sinhronizētu šo kontu"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Konta nosaukums"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Jūsu vārds"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Paraksts"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Ātrās atbildes"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Rediģēt tekstu, kuru bieži ievietojat e-pasta ziņojumos"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Rediģējiet tekstu, kuru bieži ievietojat e-pasta ziņojumos."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Pievienot tekstu nosūtītajiem ziņojumiem"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Paziņojumu iestatījumi"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Datu lietojums"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Drošības politikas"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Ātrās atbildes rediģēšana"</string> <string name="save_action" msgid="1988862706623227093">"Saglabāt"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinhronizēt kontaktpersonas"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sinhron. kontaktpersonas šim kontam"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinhronizēt kalendāru"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinhr. šī konta kalendāra notikumus"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sinhron. kalendāru"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sinhronizēt kalendāru šim kontam"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sinhronizēt e-pastu"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sinhronizēt e-pastu šim kontam"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrozvans"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Tiek gaidīti rezultāti"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Dažu serveru darbība var aizņemt ilgu laiku."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mapes"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Neatļaut ierīces kameras izmantošanu"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Pieprasīt ierīces paroli"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Ierobežot jaunāko paroļu atkārt. izmant."</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Pieprasīt paroļu derīguma term. beigas"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Bloķēt ierīc. ekr., kad tā ir dīkstāvē"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ierobežot sinhronizēto kalendāra notikumu skaitu"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ierobežot sinhronizēto e-pasta ziņojumu skaitu"</string> - <string name="quick_1" msgid="3426057697353380951">"Paldies!"</string> - <string name="quick_2" msgid="4188036352885736617">"Esmu ar mieru!"</string> - <string name="quick_3" msgid="8061819976353395585">"Vēlāk izlasīšu šo ziņojumu un atbildēšu."</string> - <string name="quick_4" msgid="3988974084396883051">"Norunāsim tikšanos, lai to pārrunātu."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Viesabonēšanas laikā fona sinhronizācija šajā kontā ir atspējota."</string> </resources> diff --git a/res/values-lv/uploader.xml b/res/values-lv/uploader.xml index 82b74dfa5..d333de6d7 100644 --- a/res/values-lv/uploader.xml +++ b/res/values-lv/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Slēpt informāciju"</string> <string name="menu_settings" msgid="5088116127086866634">"Iestatījumi"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Augšupielādēts: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konts"</string> <string name="upload" msgid="2615541458361216022">"Augšupielādēt"</string> <string name="ok" msgid="2516349681897895312">"Labi"</string> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index d2a546d0a..96f65f02f 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Baca lampiran e-mel"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Membenarkan apl membaca lampiran e-mel anda."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Membenarkan aplikasi ini membaca lampiran e-mel anda."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Akses data pembekal e-mel"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Membenarkan apl ini mengakses pangkalan data e-mel anda, termasuk mesej diterima, mesej dihantar, nama pengguna dan kata laluan."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Membenarkan aplikasi ini mengakses pangkalan data e-mel anda, termasuk mesej diterima, mesej dihantar, nama pengguna dan kata laluan."</string> <string name="app_name" msgid="5815426892327290362">"E-mel"</string> <string name="compose_title" msgid="427986915662706899">"Karang"</string> <string name="debug_title" msgid="5175710493691536719">"Nyahpepijat"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Selesai"</string> <string name="create_action" msgid="3062715563215392251">"Buat baru"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Padam"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Tiada tindak balas cepat."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Tiada tindak balas cepat"</string> <string name="discard_action" msgid="6532206074859505968">"Buang"</string> <string name="save_draft_action" msgid="6413714270991417223">"Simpan draf"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Sisipkan respons pantas"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> menulis:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Sertakan teks petikan"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Sertakan teks"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Tambahkan sekurang-kurangnya satu penerima."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Anda mesti menambah sekurang-kurangnya satu penerima."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Sesetengah alamat e-mel tidak sah."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Fail terlalu besar untuk dilampirkan."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Sisipkan respons pantas"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Disimpan"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Berhenti"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Lampiran disimpan sbg <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Tidak dapat menyimpan lampiran."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Satu atau lebih lampiran dalam mesej anda yang dikirim semula akan dimuat turun sebelum dihantar."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Tidak dapat menyimpan lampiran."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota: Satu atau lebih lampiran dalam mesej anda yang dikirim semula akan dimuat turun sebelum dihantar."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mesej"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Jemput"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Tidak boleh mengirim semula satu atau lebih lampiran."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Lampiran tidak dikirim semula"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> log masuk gagal."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Log masuk <xliff:g id="ACCOUNT_NAME">%s</xliff:g> gagal."</string> <string name="login_failed_title" msgid="7624349996212476176">"Tidak dapat melog masuk"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Anda boleh membuat akaun Exchange ActiveSync dalam hanya beberapa langkah."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Alamat e-mel"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Kata laluan"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Hantar e-mel daripada akaun ini secara lalai"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Hantarkan e-mel dari akaun ini secara lalainya."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Persediaan manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Taipkan alamat e-mel dan kata laluan yang sah."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Akaun pendua"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Menyemak tetapan pelayan masuk..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Menyemak tetapan pelayan keluar..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Persediaan akaun"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Akaun anda sudah disediakan dan e-mel akan muncul sebentar lagi!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Akaun anda sudah disediakan dan e-mel akan muncul sebentar lagi!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Namakan akaun ini (pilihan)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Nama anda (dipaparkan pada mesej keluar)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Medan ini tidak boleh kosong."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Pelayan SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Jenis keselamatan"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Memerlukan log masuk"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Memerlukan log masuk."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nama pengguna"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Kata laluan"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Persediaan akaun"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Setiap 15 minit"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Setiap 30 minit"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Setiap jam"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Hantar e-mel daripada akaun ini secara lalai"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Beritahu saya apabila e-mel diterima"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Segerakkan kenalan daripada akaun ini"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Segerakkan kalendar dari akaun ini."</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Segerakkan e-mel dari akaun ini"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Hantar e-mel dari akaun ini secara lalainya."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Beritahu saya apabila e-mel diterima."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Segerakkan kenalan daripada akaun ini."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Segerakkan kalendar dari akaun ini."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Segerakkan e-mel dari akaun ini."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Muat turun lampiran secara automatik apabila disambungkan kepada Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Tidak boleh diselesaikan"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Hari untuk disegerakkan"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Satu bulan"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Semua"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Gunakan lalai akaun"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nama pengguna atau kata laluan salah."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nama pengguna atau kata laluan salah. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nama pengguna atau kata laluan salah."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nama pengguna atau kata laluan salah."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Tidak boleh menyambung ke pelayan dengan selamat."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Tidak dapat menyambung ke pelayan dengan selamat."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Sijil klien diperlukan. Adakah anda mahu menyambung ke pelayan dengan sijil klien?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sijil itu adalah tidak sah atau tidak boleh diakses."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Pelayan memberi maklum balas dengan ralat. Semak nama pengguna dan kata laluan anda, kemudian cuba lagi."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Sijil klien diperlukan. Sambung ke pelayan dengan sijil klien?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sijil adalah tidak sah atau tidak boleh diakses."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Pelayan memberi maklum balas dengan ralat. Semak nama pengguna dan kata laluan anda, kemudian cuba lagi."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Tidak dapat menyambung ke pelayan."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Tidak dapat menyambung ke pelayan."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS diperlukan tetapi tidak disokong oleh pelayan."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AMARAN: Menyahaktifkan autoriti aplikasi E-mel untuk mentadbir peranti anda akan memadamkan semua akaun e-mel yang memerlukannya, bersama-sama dengan e-mel, kenalan, acara kalendar dan datanya yang lain."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Kemas kini keselamatan"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> memerlukan anda untuk mengemas kini tetapan keselamatan anda."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Akaun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" tidak dapat disegerakkan kerana keperluan keselamatan."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Akaun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" memerlukan kemas kini tetapan keselamatan."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Akaun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" telah mengubah tetapan keselamatannya, tidak tindakan pengguna diperlukan."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Kemas kini keselamatan diperlukan"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Dasar keselamatan telah berubah"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Dasar keselamatan tidak dapat dipenuhi"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Akaun \"<xliff:g id="ACCOUNT">%s</xliff:g>\" memerlukan kemas kini tetapan keselamatan."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Kemas kini keselamtn diperlukn"</string> <string name="account_security_title" msgid="3511543138560418587">"Keselamatan peranti"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Pelayan <xliff:g id="SERVER">%s</xliff:g> menghendaki anda membenarkannya mengawal beberapa ciri keselamatan peranti Android anda secara jauh."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Edit butiran"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN kunci skrin atau kata laluan anda telah tamat tempoh."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"K/lln knci skrn tlh tmt tmph"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Kata laluan kunci skrin akn tmt tempoh"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Anda perlu menukar PIN atau kata laluan kunci skrin anda, atau data untuk <xliff:g id="ACCOUNT">%s</xliff:g> akan dipadamkan. Adakah anda mahu menukarnya sekarang?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Anda harus menukar PIN kunci skrin atau kata laluan anda secepat mungkin atau data untuk <xliff:g id="ACCOUNT">%s</xliff:g> akan dipadamkan. Tukar sekarang?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Kata laluan kunci skrin telah tmt tempoh"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Data untuk <xliff:g id="ACCOUNT">%s</xliff:g> sedang dipadamkan dari peranti anda. Anda boleh memulihkannya dengan menukar PIN atau kata laluan kunci skrin anda. Adakah anda ingin menukarnya sekarang?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Data untuk <xliff:g id="ACCOUNT">%s</xliff:g> sedang dipadamkan dari peranti anda. Anda boleh memulihkannya dengan menukar PIN kunci skrin atau kata laluan anda. Tukar sekarang?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Buang perubahan yang belum disimpan?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Tidak dapat melog masuk"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Nama pengguna atau kata laluan untuk <xliff:g id="ACCOUNT">%s</xliff:g> adalah tidak betul. Adakah anda mahu mengemaskininya sekarang?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Nama pengguna atau kata laluan untuk <xliff:g id="ACCOUNT">%s</xliff:g> tidak betul. Kemas kininya sekarang?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Akaun lalai"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Hantar e-mel daripada akaun ini secara lalainya"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Muat turun lampiran"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Auto muat turun lampiran ke mesej terbaharu melalui Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Pemberitahuan e-mel"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Kekerapan penyegerakan, pemberitahuan, dsb."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Hantar pemberitahuan apabila e-mel tiba"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Beritahu dalam bar Sistem apabila e-mel diterima"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Kekerapan semak peti masuk"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Tetapan masuk"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nama pengguna, kata laluan dan tetapan pelayan masuk yang lain"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Tetapan keluar"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nama pengguna, kata laluan dan tetapan pelayan keluar yang lain"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Dasar yang dikuatkuasakan"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Tiada"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Dasar tidak disokong"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Tiada"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Cuba segerak"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Sentuh di sini untuk menyegerakkan akaun ini"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nama akaun"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Nama anda"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Tandatangan"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respons pantas"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edit teks yang anda kerap sisipkan semasa mengarang e-mel"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edit teks yang anda kerap sisipkan semasa mengarang e-mel"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Lampirkan teks pada mesej yang anda hantarkan"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Tetapan pemberitahuan"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Penggunaan data"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Dasar keselamatan"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Edit respons pantas"</string> <string name="save_action" msgid="1988862706623227093">"Simpan"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Segerakkan kenalan"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Segerakkan kenalan untuk akaun ini"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Segerakkan kalendar"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Segerakkan acara kalendar untuk akaun ini"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Segerak Kalendar"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Segerakkan kalendar untuk akaun ini"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Segerakkan e-mel"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Segerakkan e-mel untuk akaun ini"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Getar"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Menunggu hasil"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Sesetengah pelayan mungkin mengambil masa yang lama."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Folder"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Jgn benarkan penggunaan kamera peranti"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Perlukan kata laluan peranti"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Hadkan penggunaan semula kata laluan terbaru"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Memerlukan kata laluan untuk tamat"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Perlukan peranti yang melahu mengunci skrinnya"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Hadkan bilangan peristiwa kalendar yang disegerakkan"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Hadkan bilangan e-mel yang disegerakkan"</string> - <string name="quick_1" msgid="3426057697353380951">"Terima kasih!"</string> - <string name="quick_2" msgid="4188036352885736617">"Saya setuju saja!"</string> - <string name="quick_3" msgid="8061819976353395585">"Saya akan baca ini nanti dan hubungi anda semula."</string> - <string name="quick_4" msgid="3988974084396883051">"Mari adakan mesyuarat untuk membincangkannya."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Segerakkan latar belakang untuk akaun ini dilumpuhkan semasa perayauan."</string> </resources> diff --git a/res/values-ms/uploader.xml b/res/values-ms/uploader.xml index 3d1ce5ddf..1b760de4b 100644 --- a/res/values-ms/uploader.xml +++ b/res/values-ms/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Sembunyikan Butiran"</string> <string name="menu_settings" msgid="5088116127086866634">"Tetapan"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Dimuat naik %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Akaun"</string> <string name="upload" msgid="2615541458361216022">"Muat naik"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index ea178f34d..4a3aa5188 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Les e-postvedlegg"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Lar appen lese e-postvedleggene dine."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Gir appen tilgang til å lese e-postvedleggene dine."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Få tilgang til data om e-postleverandør"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Gir appen tilgang til e-postdatabasen, herunder mottatte meldinger, sendte meldinger, brukernavn og passord."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Gir appen tilgang til e-postdatabasen, inklusivt mottatte og sendte meldinger samt brukernavn og passord."</string> <string name="app_name" msgid="5815426892327290362">"E-post"</string> <string name="compose_title" msgid="427986915662706899">"Skriv e-post"</string> <string name="debug_title" msgid="5175710493691536719">"Debug"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Ferdig"</string> <string name="create_action" msgid="3062715563215392251">"Opprett ny"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Slett"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Ingen hurtigsvar."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Ingen raske svar"</string> <string name="discard_action" msgid="6532206074859505968">"Forkast"</string> <string name="save_draft_action" msgid="6413714270991417223">"Lagre utkast"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Sett inn hurtigsvar"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Inkluder sitert tekst"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Inkluder tekst"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Legg til minst én mottaker."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Du må legge til minst én mottager."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Noen e-postadresser er ugyldige."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Filen er for stor til å bli lagt ved."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Sett inn hurtigsvar"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Lagret"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stopp"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Vedlegget lagret som <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Vedlegget kunne ikke lagres."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Ett eller flere vedlegg i den videresendte e-posten blir lastet ned før du sender."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Kan ikke lagre vedlegget."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Merk: Ett eller flere vedlegg i den videresendte meldingen lastes ned før sending."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Melding"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Inviter"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Kunne ikke videresende ett eller flere vedlegg."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Vedlegget ble ikke videresendt"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Pålogging til <xliff:g id="ACCOUNT_NAME">%s</xliff:g> mislyktes."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Pålogging til <xliff:g id="ACCOUNT_NAME">%s</xliff:g> mislyktes."</string> <string name="login_failed_title" msgid="7624349996212476176">"Kunne ikke logge på"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Du kan konfigurere en Exchange ActiveSync-konto i løpet av bare noen få trinn."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-postadresse"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Passord"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Send e-post fra denne kontoen som standard"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Bruk denne kontoen som standard for utgående e-post."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuelt oppsett"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Angi gyldig e-postadresse og passord."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplisert konto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Sjekker tjenerinnstillinger for inngående e-post…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Sjekker tjenerinnstillinger for utgående e-post…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Konfigurering av konto"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Kontoen din er konfigurert, og e-post er på vei."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Kontoen din er konfigurert, og e-post er på vei!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Gi denne kontoen et navn (valgfritt)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Navnet ditt (vises i utgående meldinger)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Dette feltet må fylles ut."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-tjener"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Sikkerhetstype"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Krev pålogging"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Krev pålogging."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Brukernavn"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Passord"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Konfigurering av konto"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Hvert 15. minutt"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Hvert 30. minutt"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Hver time"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Send e-post fra denne kontoen som standard"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Gi meg beskjed når jeg mottar e-postmeldinger"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synkroniser kontakter fra denne kontoen"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synkroniser kalender fra denne kontoen"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synkroniser e-postmeldinger fra denne kontoen"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Bruk denne kontoen som standard for utgående e-post."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Varsle når det kommer e-post."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synkroniser kontakter fra denne kontoen."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synkroniser kalendere fra denne kontoen."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synkroniser e-postmeldinger fra denne kontoen."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Last ned vedlegg automatisk når tilkoblet til trådløst nettverk"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Kunne ikke fullføre"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Antall dager å synkronisere"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Én måned"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alle"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Bruk kontostandard"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Brukernavnet eller passordet er feil."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Brukernavnet eller passordet er feil."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Feil brukernavn eller passord."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Feil brukernavn eller passord."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Kan ikke koble til tjeneren på en sikker måte."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Kan ikke koble til tjeneren på en sikker måte."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Et klientsertifikat er påkrevd. Vil du koble til tjeneren med et klientsertifikat?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifikatet er ugyldig eller utilgjengelig."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Tjeneren svarte med en feil. Kontroller brukernavn og passord, og prøv på nytt."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Klientsertifikat er nødvendig. Vil du koble til tjener med klientsertifikat?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifikatet er ugyldig eller utilgjengelig."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Tjeneren svarte med en feil. Kontroller brukernavn og passord og prøv på nytt."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Kan ikke koble til tjeneren."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Kan ikke koble til tjeneren."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS påkrevd, men tjeneren støtter det ikke."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ADVARSEL: Hvis du deaktiverer e-postappens rett til å administrere enheten, slettes alle e-postkontoene som krever appen sammen med e-poster, kontakter, kalenderaktiviteter og andre data."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Sikkerhetsoppdatering"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> krever at du oppdaterer sikkerhetsinnstillingene."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Kontoen <xliff:g id="ACCOUNT">%s</xliff:g> kan ikke synkroniseres på grunn av sikkerhetskrav."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Kontoen «<xliff:g id="ACCOUNT">%s</xliff:g>» krever oppdatering av sikkerhetsinnstillingene."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Kontoen «<xliff:g id="ACCOUNT">%s</xliff:g>» har endret sikkerhetsinnstillinger. Du trenger ikke å foreta deg noe."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Sikkerhetsoppdatering påkrevd"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Sikkerh.retn.linjer er endret"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Sikkerhetsretningslinjene kan ikke følges"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Kontoen «<xliff:g id="ACCOUNT">%s</xliff:g>» krever oppdatering av sikkerhetsinnstillingene."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Sikkerhetsoppdatering påkrevd"</string> <string name="account_security_title" msgid="3511543138560418587">"Enhetssikkerhet"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Tjeneren <xliff:g id="SERVER">%s</xliff:g> krever at den kan kontrollere noen av sikkerhetsfunksjonene på Android-enheten utenfra."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Rediger detaljer"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Personlig kode eller passord for skjermlås er utløpt."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Passord for skjermlås utløpt"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Passord for skjermlås utløper"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Du må endre PIN-koden eller passordet for skjermlåsen snart, hvis ikke blir dataene for <xliff:g id="ACCOUNT">%s</xliff:g> slettet. Vil du endre dette nå?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Du må endre personlig kode eller passord for skjermlås snart, ellers slettes dataene for <xliff:g id="ACCOUNT">%s</xliff:g>. Vil du endre det nå?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Passord for skjermlås utløpt"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Dataene for <xliff:g id="ACCOUNT">%s</xliff:g> slettes fra enheten. Du kan gjenopprette dem ved å endre PIN-kode eller passord til skjermlåsen. Vil du endre det nå?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Dataene for <xliff:g id="ACCOUNT">%s</xliff:g> slettes fra enheten. Du kan gjenopprette dataene ved å endre personlig kode eller passord for skjermlåsing. Vil du endre dette nå?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Vil du forkaste endringer som ikke er lagret?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Kunne ikke logge på"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Brukernavnet eller passordet til <xliff:g id="ACCOUNT">%s</xliff:g> er feil. Vil du oppdatere dette nå?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Brukernavn eller passord for <xliff:g id="ACCOUNT">%s</xliff:g> er feil. Vil du oppdatere nå?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Standardkonto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Bruk denne kontoen som standard for utgående e-post."</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Nedlasting av vedlegg"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Last ned vedlegg fra nye e-poster automatisk via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Varsling om e-post"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synkroniseringsfrekvens, varslinger m.m."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Gi meg beskjed når jeg mottar e-post"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Gi beskjed i systemfeltet når nye e-postmeldinger kommer"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frekvens for kontroll av innboks"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Inngående innstillinger"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Brukernavn, passord og andre innstillinger for innkommende tjener"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Utgående innstillinger"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Brukernavn, passord og andre innstillinger for utgående tjener"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Retningslinjer som håndheves"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ingen"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Retningslinjer som ikke støttes"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ingen"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Forsøk synkronisering"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Trykk her for å synkronisere denne kontoen"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Kontonavn"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Ditt navn"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Underskrift"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Hurtigsvar"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Rediger tekst som du ofte skriver inn når du skriver e-post"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Rediger tekst som du ofte setter inn når du skriver e-poster"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Legg til tekst i e-postmeldinger"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Innstillinger for varsling"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Databruk"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sikkerhetsretningslinjer"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Rediger hurtigsvar"</string> <string name="save_action" msgid="1988862706623227093">"Lagre"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synkroniser kontakter"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synkroniser kontakter fra denne kontoen"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synkroniser kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synkroniser kalenderarrangement for denne kontoen"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synkroniser kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synkroniser kalender fra denne kontoen"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synkroniser e-post"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synkroniser e-postmeldinger fra denne kontoen"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrering"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Venter på resultater"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Noen tjenere kan ta lang tid."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mapper"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Ikke tillat bruk av enhetens kamera"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Krev enhetspassord"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Begrens gjenbruk av nylige passord"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Krev at passord utløper"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Krev at skjerm låses på inaktive enheter"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Begrens antallet synkroniserte kalenderhendelser"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Begrens antallet synkroniserte e-poster"</string> - <string name="quick_1" msgid="3426057697353380951">"Takk!"</string> - <string name="quick_2" msgid="4188036352885736617">"Det høres bra ut!"</string> - <string name="quick_3" msgid="8061819976353395585">"Jeg skal lese dette senere og ta kontakt."</string> - <string name="quick_4" msgid="3988974084396883051">"Jeg foreslår at vi avtaler et møte for å diskutere dette."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Bakgrunnssynkronisering for denne kontoen er deaktivert under streifing."</string> </resources> diff --git a/res/values-nb/uploader.xml b/res/values-nb/uploader.xml index 0f154f6b9..0846aff57 100644 --- a/res/values-nb/uploader.xml +++ b/res/values-nb/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Skjul detaljer"</string> <string name="menu_settings" msgid="5088116127086866634">"Innstillinger"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Lastet opp %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Last opp"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index f098f3e4c..a8a48d465 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"E-mailbijlagen lezen"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Hiermee kan de app uw e-mailbijlagen lezen."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Staat deze app toe uw e-mailbijlagen te lezen."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Gegevens e-mailprovider openen"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Hiermee geeft u deze app toegang tot uw e-maildatabase, inclusief ontvangen berichten, verzonden berichten, gebruikersnamen en wachtwoorden."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Hiermee geeft u deze app toegang tot uw e-maildatabase, inclusief ontvangen berichten, verzonden berichten, gebruikersnamen en wachtwoorden."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Opstellen"</string> <string name="debug_title" msgid="5175710493691536719">"Foutopsporing"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Gereed"</string> <string name="create_action" msgid="3062715563215392251">"Nieuwe maken"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Verwijderen"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Geen snelle reacties."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Geen snelle reacties"</string> <string name="discard_action" msgid="6532206074859505968">"Weggooien"</string> <string name="save_draft_action" msgid="6413714270991417223">"Concept opslaan"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Snelle reactie invoegen"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>schreef:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Tekst uit oorspronkelijk bericht weergeven"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Tekst opnemen"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Voeg ten minste één ontvanger toe."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"U moet minstens één ontvanger toevoegen."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Sommige e-mailadressen zijn ongeldig."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Bestand is te groot om bij te voegen."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Snelle reactie invoegen"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Opgeslagen"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stoppen"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Bijlage opgeslagen als <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Kan bijlage niet opslaan."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Een of meer bijlagen in uw doorgestuurde bericht worden gedownload voordat het bericht wordt verzonden."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Kan de bijlage niet opslaan."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Opmerking: een of meer bijlagen in uw doorgestuurde bericht worden gedownload voordat het bericht wordt verzonden."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Bericht"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Uitnodigen"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Kan een of meer bijlagen niet doorsturen."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Bijlage niet doorgestuurd"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>: aanmelden mislukt."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g>: aanmelden mislukt."</string> <string name="login_failed_title" msgid="7624349996212476176">"Kan niet aanmelden"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"U kunt een Exchange ActiveSync-account in slechts enkele stappen instellen."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-mailadres"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Wachtwoord"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"E-mail standaard vanaf dit account verzenden"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"E-mail standaard vanaf dit account verzenden"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Handmatig instellen"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Typ een geldig e-mailadres en wachtwoord."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dubbel account"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Serverinstellingen inkomende e-mail controleren..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Serverinstellingen uitgaande e-mail controleren..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Accountinstellingen"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Uw account is ingesteld en er is e-mail onderweg."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Uw account is ingesteld en er is e-mail onderweg."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Geef dit account een naam (optioneel)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Uw naam (wordt weergegeven in uitgaande berichten)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Dit veld mag niet leeg zijn."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Poort"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Beveiligingstype"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Aanmelding vereisen"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Aanmelden vereist"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Gebruikersnaam"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Wachtwoord"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Accountinstellingen"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Elke 15 minuten"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Elke 30 minuten"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Elk uur"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"E-mail standaard vanaf dit account verzenden"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Stuur me een melding wanneer er e-mail binnenkomt"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Contacten van dit account synchroniseren"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Agenda van dit account synchroniseren"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"E-mail van dit account synchroniseren"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"E-mail standaard vanaf dit account verzenden"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Stuur me een melding wanneer er e-mail binnenkomt."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Contacten van dit account synchroniseren."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Agenda van dit account synchroniseren."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"E-mail voor dit account synchroniseren."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Bijlagen automatisch downloaden indien verbonden met Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Is niet voltooid"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dagen om te synchroniseren"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Eén maand"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alles"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Accountstandaard gebruiken"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Gebruikersnaam of wachtwoord is onjuist."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Gebruikersnaam of wachtwoord is onjuist. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Gebruikersnaam of wachtwoord is onjuist."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Gebruikersnaam of wachtwoord is onjuist."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Kan geen veilige verbinding met de server tot stand brengen."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Kan geen veilige verbinding met de server tot stand brengen."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Er is een client-certificaat vereist. Wilt u verbinding maken met de server met een client-certificaat?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Het certificaat is ongeldig of niet toegankelijk."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"De server heeft een fout geretourneerd. Controleer uw gebruikersnaam en wachtwoord en probeer het opnieuw."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Clientcertificaat is vereist. Met clientcertificaat verbinding maken met de server?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificaat is ongeldig of niet toegankelijk."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"De server heeft een fout geretourneerd. Controleer uw gebruikersnaam en wachtwoord en probeer het opnieuw."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Kan geen verbinding maken met de server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Kan geen verbinding maken met de server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS is vereist maar wordt niet ondersteund door de server."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"WAARSCHUWING: als u de rechten van de app E-mail voor het beheren van uw apparaat uitschakelt, worden alle e-mailaccounts verwijderd waarvoor deze rechten vereist zijn, samen met de bijbehorende e-mails, contacten, agenda-afspraken en andere gegevens."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Beveiligingsupdate"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Voor <xliff:g id="ACCOUNT">%s</xliff:g> moet u uw beveiligingsinstellingen bijwerken."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Account \'<xliff:g id="ACCOUNT">%s</xliff:g>\' kan niet worden gesynchroniseerd wegens beveiligingsvereisten."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Account \'<xliff:g id="ACCOUNT">%s</xliff:g>\' vereist een update van de beveiligingsinstellingen."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"De beveiligingsinstellingen van het account \'<xliff:g id="ACCOUNT">%s</xliff:g>\' zijn gewijzigd, er is geen gebruikersactie vereist."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Beveiligingsupdate vereist"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Beveiligingsbeleid gewijzigd"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Beveil.-beleid niet voldaan"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Account \'<xliff:g id="ACCOUNT">%s</xliff:g>\' vereist een update van de beveiligingsinstellingen."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Beveiligingsupdate vereist"</string> <string name="account_security_title" msgid="3511543138560418587">"Apparaatbeveiliging"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"De server <xliff:g id="SERVER">%s</xliff:g> vereist dat u de server toestemming geeft bepaalde beveiligingsfuncties van uw Android-apparaat extern te bedienen."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Details bewerken"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Uw PIN-code of wachtwoord voor schermvergrendeling is verlopen."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Wachtw. schermvergr. verlopen"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Wachtw. schermvergr. bijna verlopen"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"U moet uw pincode of wachtwoord voor schermvergrendeling snel wijzigen, of de gegevens voor <xliff:g id="ACCOUNT">%s</xliff:g> worden gewist. Wilt u dit nu wijzigen?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"U moet uw PIN-code of wachtwoord voor schermvergrendeling binnenkort wijzigen, anders worden de gegevens voor <xliff:g id="ACCOUNT">%s</xliff:g> gewist. Nu wijzigen?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Wachtwoord schermvergrendeling verlopen"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"De gegevens voor <xliff:g id="ACCOUNT">%s</xliff:g> worden gewist op uw apparaat. U kunt het account herstellen door uw pincode of wachtwoord voor schermvergrendeling te wijzigen. Nu wijzigen?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"De gegevens voor <xliff:g id="ACCOUNT">%s</xliff:g> worden gewist op uw apparaat. U kunt het account herstellen door uw PIN-code of wachtwoord voor schermvergrendeling te wijzigen. Nu wijzigen?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Niet-opgeslagen wijzigingen annuleren?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Kan niet aanmelden"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"De gebruikersnaam of het wachtwoord voor <xliff:g id="ACCOUNT">%s</xliff:g> is onjuist. Wilt u deze nu bijwerken?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"De gebruikersnaam of het wachtwoord voor <xliff:g id="ACCOUNT">%s</xliff:g> is onjuist. Nu bijwerken?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Standaardaccount"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"E-mail standaard vanaf dit account verzenden"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Bijlagen downloaden"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Bijlagen van recente berichten automatisch downloaden via wifi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Meldingen via e-mail"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synchronisatiefrequentie, meldingen, enzovoort"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Melding sturen wanneer e-mail binnenkomt"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Melding in de systeembalk wanneer er e-mail binnenkomt"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Controlefrequentie inbox"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Instellingen inkomende e-mail"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Gebruikersnaam, wachtwoord en andere inst. voor inkomende server"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Instellingen uitgaande e-mail"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Gebruikersnaam, wachtwoord en andere inst. voor uitgaande server"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Afgedwongen beleid"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Geen"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Niet-ondersteund beleid"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Geen"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Poging tot synchroniseren"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Raak dit aan om dit account te synchroniseren"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Accountnaam"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Uw naam"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Handtekening"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Snelle reacties"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Tekst bewerken die u vaak invoegt wanneer u e-mails opstelt"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Tekst bewerken die u vaak invoegt wanneer u e-mails opstelt"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Tekst toevoegen aan berichten die u verzendt"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Instellingen voor meldingen"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Gegevensgebruik"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Beveiligingsbeleid"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Snelle reactie bewerken"</string> <string name="save_action" msgid="1988862706623227093">"Opslaan"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Contacten synchroniseren"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Contacten voor dit account synchroniseren"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Agenda synchroniseren"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Agenda-afspraak voor dit account synchroniseren"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Agenda synchroniseren"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Agenda voor dit account synchroniseren"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"E-mail synch."</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"E-mail voor dit account synchroniseren"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Trillen"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Wachten op resultaten"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Het duurt soms langer voordat servers reageren."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mappen"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Gebruik van apparaatcamera niet toestaan"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Apparaatwachtwoord vereisen"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Hergebruik recente wachtwoorden beperken"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Vereisen dat wachtwoord verloopt"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Inactief apparaat vergrendelt scherm"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Aantal gesynchroniseerde agenda-afspraken beperken"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Aantal gesynchroniseerde e-mails beperken"</string> - <string name="quick_1" msgid="3426057697353380951">"Hartelijk dank!"</string> - <string name="quick_2" msgid="4188036352885736617">"Dat lijkt me prima."</string> - <string name="quick_3" msgid="8061819976353395585">"Ik zal dit later lezen en kom er dan op terug."</string> - <string name="quick_4" msgid="3988974084396883051">"Laten we een afspraak maken om dit te bespreken."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Achtergrondsynchronisatie voor dit account is uitgeschakeld tijdens roaming."</string> </resources> diff --git a/res/values-nl/uploader.xml b/res/values-nl/uploader.xml index 451f05e96..f2d6c8242 100644 --- a/res/values-nl/uploader.xml +++ b/res/values-nl/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Details verbergen"</string> <string name="menu_settings" msgid="5088116127086866634">"Instellingen"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Geüpload op %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Account"</string> <string name="upload" msgid="2615541458361216022">"Uploaden"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 85d5de3b1..79e5e9103 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Odczyt załączników do e-maili"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Pozwala aplikacji na odczyt załączników do e-maili."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Zezwala aplikacji na odczyt załączników do e-maili."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Dostęp do danych dostawcy poczty e-mail"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Zezwala aplikacji na dostęp do bazy danych e-maili, w tym odebranych i wysłanych wiadomości, nazw użytkowników oraz haseł."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Zezwala aplikacji na dostęp do bazy danych poczty e-mail, w tym odebranych i wysłanych wiadomości, nazw użytkowników oraz haseł."</string> <string name="app_name" msgid="5815426892327290362">"Poczta"</string> <string name="compose_title" msgid="427986915662706899">"Utwórz"</string> <string name="debug_title" msgid="5175710493691536719">"Debuguj"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Gotowe"</string> <string name="create_action" msgid="3062715563215392251">"Utwórz nową"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Usuń"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Brak szybkich odpowiedzi"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Brak szybkich odpowiedzi"</string> <string name="discard_action" msgid="6532206074859505968">"Odrzuć"</string> <string name="save_draft_action" msgid="6413714270991417223">"Zapisz wersję roboczą"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Wstaw szybką odpowiedź"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> napisał(a):"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Dołącz cytowany tekst"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Dołącz tekst"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Dodaj co najmniej jednego adresata."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Musisz dodać co najmniej jednego adresata."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Niektóre adresy e-mail są nieprawidłowe."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Plik jest zbyt duży do załączenia."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Wstaw szybką odpowiedź"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Zapisany"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Zatrzymaj"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Załącznik zapisany jako <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Nie można zapisać załącznika."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Co najmniej jeden załącznik w przekazywanej wiadomości zostanie pobrany przed wysłaniem."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Nie można zapisać załącznika."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Uwaga: co najmniej jeden załącznik w przekazywanej wiadomości zostanie pobrany przed wysłaniem."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Wiadomość"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Zaproś"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Co najmniej jednego załącznika nie można przekazać dalej."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Nie przekazano załącznika"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Nie udało się zalogować na konto <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Nie udało się zalogować na konto <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Nie można się zalogować"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Możesz skonfigurować konto Exchange ActiveSync w zaledwie kilku krokach."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Adres e-mail"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Hasło"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Domyślnie wysyłaj e-maile z tego konta."</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Domyślnie wysyłaj wiadomości e-mail z tego konta"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Konfig. ręczna"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Wpisz prawidłowy adres e-mail i hasło."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Zduplikowane konto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Sprawdzanie ustawień serwera poczty przychodzącej…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Sprawdzanie ustawień serwera poczty wychodzącej…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Konfiguracja konta"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Konto zostało skonfigurowane, a e-maile są w drodze."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Konto zostało skonfigurowane, a wiadomości e-mail są w drodze!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Nazwa konta (opcjonalnie)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Twoja nazwa (wyświetlana w wiadomościach wychodzących)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"To pole nie może być puste."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Serwer SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Typ zabezpieczeń"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Wymagaj logowania."</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Wymagaj zalogowania się."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nazwa użytkownika"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Hasło"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Konfiguracja konta"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Co 15 minut"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Co 30 minut"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Co godzinę"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Domyślnie wysyłaj wiadomości e-mail z tego konta."</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Powiadom mnie o odebranych e-mailach."</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synchronizuj kontakty na tym koncie."</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synchronizuj kalendarz na tym koncie."</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synchronizuj e-maile z tego konta."</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Domyślnie wysyłaj wiadomości e-mail z tego konta"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Powiadom mnie o odebranej poczcie e-mail."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synchronizuj kontakty na tym koncie"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synchronizuj kalendarz na tym koncie"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synchronizuj wiadomości e-mail z tego konta"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automatycznie pobieraj załączniki, gdy połączono z siecią Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nie można zakończyć"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dni do synchronizacji"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Jeden miesiąc"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Wszystkie"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Użyj wartości domyślnej konta"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nieprawidłowa nazwa użytkownika lub hasło"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nieprawidłowa nazwa użytkownika lub hasło"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nieprawidłowa nazwa użytkownika lub hasło."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nieprawidłowa nazwa użytkownika lub hasło."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nie można bezpiecznie połączyć się z serwerem."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nie można bezpiecznie połączyć się z serwerem."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Certyfikat klienta jest wymagany. Czy chcesz się połączyć z serwerem za pomocą certyfikatu klienta?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certyfikat jest nieważny lub niedostępny."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Serwer zgłosił błąd. Sprawdź nazwę użytkownika i hasło, a następnie spróbuj ponownie."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Wymagany jest certyfikat klienta. Połączyć z serwerem przy jego użyciu?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certyfikat jest nieważny lub niedostępny."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Serwer zgłosił błąd. Sprawdź nazwę użytkownika i hasło, a następnie spróbuj ponownie."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nie można połączyć się z serwerem."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nie można połączyć się z serwerem."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Wymagane połączenie TLS nie jest obsługiwane przez serwer."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"OSTRZEŻENIE: cofnięcie Poczcie uprawnień do administrowania urządzeniem spowoduje usunięcie wszystkich kont e-mail, które ich wymagają, wraz z wiadomościami, kontaktami, wydarzeniami w kalendarzu i innymi danymi."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Aktualizacja zabezpieczeń"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Konto <xliff:g id="ACCOUNT">%s</xliff:g> wymaga aktualizacji ustawień zabezpieczeń."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Nie można zsynchronizować konta „<xliff:g id="ACCOUNT">%s</xliff:g>” ze względu na wymogi bezpieczeństwa."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Konto „<xliff:g id="ACCOUNT">%s</xliff:g>” wymaga aktualizacji ustawień zabezpieczeń."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Ustawienia zabezpieczeń konta „<xliff:g id="ACCOUNT">%s</xliff:g>” uległy zmianie. Nie jest wymagane podejmowanie działań przez użytkownika."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Wymagana aktualizacja zabezp."</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Zasady bezpieczeństwa uległy zmianie"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Nie można spełnić zasad bezp."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Konto „<xliff:g id="ACCOUNT">%s</xliff:g>” wymaga aktualizacji ustawień zabezpieczeń."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Wymagana aktualizacja zabezp."</string> <string name="account_security_title" msgid="3511543138560418587">"Zabezpieczenia urządzenia"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Serwer <xliff:g id="SERVER">%s</xliff:g> wymaga udzielenia zezwolenia na zdalną kontrolę niektórych funkcji zabezpieczeń tego urządzenia z systemem Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Edytuj szczegóły"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Kod PIN lub hasło ekranu blokady wygasły."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Hasło ekranu blokady wygasło"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Hasło ekranu blokady wkrótce wygaśnie"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Musisz wkrótce zmienić PIN lub hasło ekranu blokady. W przeciwnym razie dane konta <xliff:g id="ACCOUNT">%s</xliff:g> zostaną usunięte. Zmienić je teraz?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Należy wkrótce zmienić kod PIN lub hasło ekranu blokady, albo dane konta <xliff:g id="ACCOUNT">%s</xliff:g> zostaną wymazane. Zmienić teraz?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Hasło ekranu blokady wygasło"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Trwa wymazywanie z urządzenia danych konta <xliff:g id="ACCOUNT">%s</xliff:g>. Można je przywrócić, zmieniając PIN lub hasło ekranu blokady. Zmienić je teraz?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Trwa wymazywanie z urządzenia danych konta <xliff:g id="ACCOUNT">%s</xliff:g>. Można je przywrócić, zmieniając kod PIN lub hasło ekranu blokady. Zmienić je teraz?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Odrzucić niezapisane zmiany?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Nie można się zalogować"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Nazwa użytkownika lub hasło dla konta <xliff:g id="ACCOUNT">%s</xliff:g> są nieprawidłowe. Chcesz je poprawić?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Nazwa użytkownika lub hasło dla konta <xliff:g id="ACCOUNT">%s</xliff:g> są niepoprawne. Zaktualizować je teraz?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Domyślne konto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Domyślnie wysyłaj wiadomości e-mail z tego konta"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Pobieraj załączniki"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automatycznie pobieraj załączniki najnowszych wiadomości przez Wi-Fi."</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Powiadomienia e-mail"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Częstotliwość synchronizacji, powiadomienia itd."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Wyślij powiadomienie, gdy przychodzi e-mail."</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Powiadamiaj na pasku systemu o otrzymaniu wiadomości e-mail"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Sprawdzaj pocztę"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Poczta przychodząca"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Użytkownik, hasło i inne ustawienia serwera poczty przychodzącej"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Poczta wychodząca"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Użytkownik, hasło i inne ustawienia serwera poczty wychodzącej"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Egzekwowane zasady"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Brak"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nieobsługiwane zasady"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Brak"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Próba synchronizacji"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Dotknij tutaj, aby zsynchronizować to konto."</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nazwa konta"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Imię i nazwisko"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Podpis"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Szybkie odpowiedzi"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edytuj tekst, który często wstawiasz do e-maili."</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edytuj tekst, który często wstawiasz do wiadomości e-mail."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Dołącz tekst do wysyłanych wiadomości"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Ustawienia powiadomień"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Wykorzystanie transmisji danych"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Zasady bezpieczeństwa"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Edytuj szybką odpowiedź"</string> <string name="save_action" msgid="1988862706623227093">"Zapisz"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synchronizuj kontakty"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synchronizuj kontakty dla tego konta"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synchronizuj kalendarz"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synch. kalendarz dla tego konta."</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synchronizuj kalendarz"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synchronizuj kalendarz dla tego konta"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synchronizuj e-maile"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synchronizuj wiadomości e-mail dla tego konta"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Wibracje"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Oczekiwanie na wyniki"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Niektóre serwery mogą zwracać wyniki po dłuższym czasie."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Foldery"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Nie zezwalaj na używanie aparatu"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Wymagaj hasła do urządzenia"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Nie zezwalaj na używanie poprzednich haseł"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Wymagaj, by hasła miały datę ważności"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Wymagaj blokowania ekranu nieużywanych urz."</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ogranicz liczbę synchronizowanych wydarzeń z kalendarza"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ogranicz liczbę synchronizowanych e-maili"</string> - <string name="quick_1" msgid="3426057697353380951">"Dziękuję."</string> - <string name="quick_2" msgid="4188036352885736617">"Brzmi dobrze."</string> - <string name="quick_3" msgid="8061819976353395585">"Przeczytam to później i skontaktuję się."</string> - <string name="quick_4" msgid="3988974084396883051">"Spotkajmy się, aby to omówić."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Synchronizacja w tle z tym kontem jest podczas roamingu wyłączona."</string> </resources> diff --git a/res/values-pl/uploader.xml b/res/values-pl/uploader.xml index 5c7a8ee58..c4096831c 100644 --- a/res/values-pl/uploader.xml +++ b/res/values-pl/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ukryj szczegóły"</string> <string name="menu_settings" msgid="5088116127086866634">"Ustawienia"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Przesłano: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Prześlij"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index c0da67096..5df6f33dc 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Ler anexos de e-mail"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permite à aplicação ler os anexos de e-mail."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permite que esta aplicação leia os seus anexos de e-mail."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Aceder a dados do fornecedor de e-mail"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permite que a aplicação aceda à base de dados do e-mail, incluindo às mensagens recebidas, mensagens enviadas, nomes de utilizadores e palavras-passe."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permite que esta aplicação aceda à base de dados do e-mail, incluindo às mensagens recebidas, mensagens enviadas, nomes de utilizadores e palavras-passe."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Redigir"</string> <string name="debug_title" msgid="5175710493691536719">"Depuração"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Concluído"</string> <string name="create_action" msgid="3062715563215392251">"Criar nova"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Eliminar"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Sem respostas rápidas."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Sem respostas rápidas"</string> <string name="discard_action" msgid="6532206074859505968">"Rejeitar"</string> <string name="save_draft_action" msgid="6413714270991417223">"Guardar rascunho"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Inserir resposta rápida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> escreveu:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Incluir texto citado"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Incluir texto"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Adicione, pelo menos, um destinatário."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Tem de adicionar pelo menos um destinatário."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Alguns endereços de e-mail são inválidos."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Ficheiro demasiado grande para anexar."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Inserir resposta rápida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Guardado"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Parar"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Anexo guardado como <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Não foi possível guardar o anexo."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Um ou mais anexos da mensagem que encaminhou serão transferidos antes do envio."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Impossível guardar anexo."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Nota: um ou mais anexos da mensagem que encaminhou serão transferidos antes do envio."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mensagem"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Convidar"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Não foi possível encaminhar um ou mais anexos."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"O anexo não foi encaminhado"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Início de sessão de <xliff:g id="ACCOUNT_NAME">%s</xliff:g> sem êxito."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Falha no início de sessão de <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Impossível iniciar sessão"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Pode configurar uma conta Exchange ActiveSync em apenas alguns passos."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Endereço de e-mail"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Palavra-passe"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Enviar e-mail a partir desta conta por predefinição"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Enviar e-mail a partir desta conta por predefinição."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuração manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Introduza um endereço de e-mail e palavra-passe válidos."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Conta duplicada"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"A verificar definições do servidor de recepção..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"A verificar definições do servidor de envio..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuração da conta"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"A sua conta está configurada e o e-mail vai a caminho!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"A sua conta está configurada e o e-mail vai a caminho!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Dar um nome a esta conta (opcional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"O seu nome (apresentado nas mensagens enviadas)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Este campo não pode estar em branco."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Servidor SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Porta"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipo de segurança"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Requerer início de sessão"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Solicitar início de sessão."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nome de utilizador"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Palavra-passe"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuração da conta"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"De 15 em 15 minutos"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"De 30 em 30 minutos"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"De hora em hora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Enviar e-mail a partir desta conta por predefinição"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Receber notificação de e-mails novos"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronizar contactos a partir desta conta."</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronizar o calendário a partir desta conta."</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronizar e-mail a partir desta conta."</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Enviar e-mail a partir desta conta por predefinição."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Notificar-me quando chega e-mail."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronizar contactos a partir desta conta."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronizar o calendário a partir desta conta."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronizar e-mail a partir desta conta."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Transferir automaticamente anexos quando ligado a uma rede Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Não foi possível concluir"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dias para sincronização"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Um mês"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Todas"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Utilizar predef. da conta"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"O nome de utilizador ou a palavra-passe estão incorretos."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"O nome de utilizador ou a palavra-passe estão incorretos."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nome de utilizador ou palavra passe incorrectos."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nome de utilizador ou palavra-passe incorretos."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Não é possível ligar ao servidor em segurança."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Não é possível ligar ao servidor em segurança."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"É necessário um certificado de cliente. Pretende ligar ao servidor com um certificado de cliente?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"O certificado é inválido ou inacessível."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"O servidor respondeu com um erro. Verifique o nome de utilizador e a palavra-passe e tente novamente."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Certificado de cliente necessário. Ligar ao servidor com o certificado de cliente?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificado inválido ou inacessível."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"O servidor respondeu com um erro. Verifique o nome de utilizador e a palavra-passe e tente novamente."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Não é possível ligar ao servidor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Não é possível ligar ao servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS necessário mas não suportado pelo servidor."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AVISO: a desativação da autorização da aplicação E-mail para administrar o aparelho eliminará todas as contas de e-mail que necessitam desta, juntamente com o respetivo e-mail, contactos, eventos de agenda e outros dados."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Atualização de segurança"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> requer a atualização das definições de segurança."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Não é possível sincronizar a conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" devido a requisitos de segurança."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requer a atualização das definições de segurança."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" alterou as definições de segurança; não é necessária qualquer ação do utilizador."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Necessária atualiz. segurança"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Políticas segurança alteradas"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Impossível cumprir polít. seg."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requer a actualização das definições de segurança."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"É necessária uma atualização da segurança"</string> <string name="account_security_title" msgid="3511543138560418587">"Segurança do dispositivo"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"O servidor <xliff:g id="SERVER">%s</xliff:g> requer permissão para controlar remotamente algumas das funcionalidades de segurança do aparelho Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Editar detalhes"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"O seu PIN ou palavra-passe de bloqueio do ecrã expirou."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"A palavra-passe de bloq. do ecrã expirou"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Palavra-passe de bloq. do ecrã a expirar"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Tem de alterar o PIN ou a palavra-passe de bloqueio do ecrã ou os dados de <xliff:g id="ACCOUNT">%s</xliff:g> serão apagados. Pretende alterar agora?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Tem de alterar em breve o PIN ou palavra-passe de bloqueio do ecrã ou os dados para <xliff:g id="ACCOUNT">%s</xliff:g> serão apagados. Quer alterar agora?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"A palavra-passe de bloq. do ecrã expirou"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Os dados de <xliff:g id="ACCOUNT">%s</xliff:g> estão a ser apagados do aparelho. Pode restaurá-los alterando o PIN ou a palavra-passe de bloqueio do ecrã. Pretende alterar agora?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Os dados para <xliff:g id="ACCOUNT">%s</xliff:g> estão a ser apagados do seu aparelho. Pode restaurá-los alterando o PIN ou palavra-passe de bloqueio do ecrã. Alterar agora?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Rejeitar alterações não guardadas?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Não foi possível iniciar sessão."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"O nome de utilizador ou a palavra-passe para <xliff:g id="ACCOUNT">%s</xliff:g> estão incorretos. Pretende atualizá-los agora?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"O nome de utilizador ou palavra-passe para <xliff:g id="ACCOUNT">%s</xliff:g> estão incorretos. Quer atualizá-los agora?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Conta predefinida"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Enviar e-mail a partir desta conta por predefinição"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Transferir anexos"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Transferir automaticamente anexos de mensagens recentes p/ Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificações de e-mail"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frequência da sincronização, notificações, etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Enviar notificação quando chegar um e-mail"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notificar na barra de sistema quando chegar e-mail"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frequência de verificação de caixa de entrada"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Definições de recepção"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nome de utiliz., palavra-passe e outras def. do serv. de receção"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Definições de envio"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nome de utiliz., palavra-passe e outras def. do serv. de envio"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Políticas aplicadas"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nenhum"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Políticas não suportadas"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nenhum"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Tentar sincronizar"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Toque aqui para sincronizar esta conta"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nome da conta"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"O seu nome"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Assinatura"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respostas rápidas"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Editar o texto que insere frequentemente ao compor e-mails"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Editar o texto que insere frequentemente ao compor e-mails"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Acrescente texto às mensagens que enviar"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Definições de notificação"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Utilização de dados"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Políticas de segurança"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Editar resposta rápida"</string> <string name="save_action" msgid="1988862706623227093">"Guardar"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizar contactos"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronizar contactos para esta conta"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizar calendário"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinc. evento do cal. p. esta conta"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronizar agenda"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronizar a agenda para esta conta"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronizar e-mail"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronizar e-mail para esta conta"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrar"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"A aguardar resultados"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Alguns servidores podem demorar algum tempo."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Pastas"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Não perm. utilização câmara do aparelho"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Solicitar palavra-passe do aparelho"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Limitar reutilização pal.-passe recentes"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Solicitar validade das palavras-passe"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Necessário apar. inat. para bloq. ecrã"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitar n.º de eventos de calendário sincronizados"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitar n.º de e-mails sincronizados"</string> - <string name="quick_1" msgid="3426057697353380951">"Obrigado!"</string> - <string name="quick_2" msgid="4188036352885736617">"Parece-me bem!"</string> - <string name="quick_3" msgid="8061819976353395585">"Vou ler isto mais tarde e voltarei a contactá-lo."</string> - <string name="quick_4" msgid="3988974084396883051">"Vamos marcar uma reunião para discutir isso."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"A sincronização em segundo plano desta conta está desativada quando está em roaming."</string> </resources> diff --git a/res/values-pt-rPT/uploader.xml b/res/values-pt-rPT/uploader.xml index 84218149c..fe226aa27 100644 --- a/res/values-pt-rPT/uploader.xml +++ b/res/values-pt-rPT/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ocultar Detalhes"</string> <string name="menu_settings" msgid="5088116127086866634">"Configurações"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Carregados: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Conta"</string> <string name="upload" msgid="2615541458361216022">"fazer upload"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index c56130e67..faa774c5c 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Ler os anexos do e-mail"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permite que o aplicativo leia seus anexos de e-mail."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permite que este aplicativo leia os anexos do seu e-mail."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Acessar dados do provedor de e-mail"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permite que o aplicativo acesse o banco de dados de seu e-mail, incluindo mensagens recebidas e enviadas, nomes de usuário e senhas."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permite que este aplicativo acesse o banco de dados do e-mail, incluindo mensagens recebidas e enviadas, nomes de usuário e senhas."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Escrever"</string> <string name="debug_title" msgid="5175710493691536719">"Depurar"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Concluído"</string> <string name="create_action" msgid="3062715563215392251">"Criar nova"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Excluir"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nenhuma resposta rápida."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Sem respostas rápidas"</string> <string name="discard_action" msgid="6532206074859505968">"Descartar"</string> <string name="save_draft_action" msgid="6413714270991417223">"Salvar rascunho"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Inserir resposta rápida"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> escreveu:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Incluir texto das mensagens anteriores"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Incluir texto"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Adicione pelo menos um destinatário."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Você deve adicionar pelo menos um destinatário."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Alguns endereços de e-mail são inválidos."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Arquivo muito grande para ser anexado."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Inserir resposta rápida"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Salvo"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Parar"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Anexo salvo como <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Não foi possível salvar anexo."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Um ou mais anexos de sua mensagem encaminhada serão transferidos antes do envio."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Não é possível salvar o anexo."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Obs.: um ou mais anexos de sua mensagem encaminhada serão carregados antes do envio."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mensagem"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Convidar"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Não foi possível encaminhar todos os anexos."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Anexo não encaminhado"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Falha no login de <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Falha no login de <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Não foi possível fazer login"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> b"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"É possível configurar uma conta do Exchange ActiveSync em apenas algumas etapas."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Endereço de e-mail"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Senha"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Enviar e-mail desta conta por padrão"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Enviar e-mail desta conta por padrão."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuração manual"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Digite um endereço de e-mail e senha válidos."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Conta duplicada"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Verificando as configurações de entrada do servidor..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Verificando as configurações de saída do servidor..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configuração da conta"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Sua conta está configurada e o e-mail está a caminho!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Sua conta está configurada e o e-mail está a caminho!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Dar nome a esta conta (opcional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Seu nome (exibido nas mensagens enviadas)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Este campo não pode ficar em branco."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Servidor SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Porta"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipo de segurança"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Exigir login"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Requer login."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nome de usuário"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Senha"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configuração da conta"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"A cada 15 minutos"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"A cada 30 minutos"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"De hora em hora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Enviar e-mail desta conta por padrão"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Receber notificação quando um e-mail chegar"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sincronizar contatos desta conta"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sincronizar agenda desta conta"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sincronizar e-mail desta conta."</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Enviar e-mail desta conta por padrão."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Receber notificação quando chegar um e-mail"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronizar contatos desta conta."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronizar agenda desta conta."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronizar e-mail desta conta."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Fazer download de anexos automaticamente ao conectar ao Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Não foi possível concluir"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dias para sincronizar"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Um mês"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Todos"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Usar padrão da conta"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Nome de usuário ou senha incorretos."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Nome de usuário ou senha estão incorretos."\n" (<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nome de usuário ou senha incorretos."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nome de usuário ou senha incorretos. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Não é possível se conectar ao servidor com segurança."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Não é possível se conectar ao servidor com segurança."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"É necessário um certificado de cliente. Deseja se conectar ao servidor com um certificado de cliente?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"O certificado é inválido ou inacessível."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"O servidor respondeu com um erro. Verifique seu nome de usuário e senha e tente novamente."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"O certificado do cliente é necessário. Conectar-se ao servidor com o certificado do cliente?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"O certificado é inválido ou inacessível."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"O servidor respondeu com um erro. Verifique seu nome de usuário e senha e tente novamente."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Não é possível se conectar ao servidor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Não é possível se conectar ao servidor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS solicitado, mas não suportado pelo servidor."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AVISO: ao desativar a autoridade do aplicativo de e-mail para administrar seu dispositivo, todas as contas de e-mail vinculadas serão excluídas, assim como e-mails, contatos, eventos da agenda e outros dados."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Atualização de segurança"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> solicita que você atualize suas configurações de segurança."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" não pode ser sincronizada devido a solicitações de segurança."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" exige a atualização das configurações de segurança."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"As configurações de segurança da conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" foram alteradas. Nenhuma ação do usuário é necessária."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Necessária atualiz. segurança"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Polít. segurança alteradas"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Polít. de seg. não podem ser cumpridas"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"A conta \"<xliff:g id="ACCOUNT">%s</xliff:g>\" requer a atualização das configurações de segurança."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Necessária atualização de segurança"</string> <string name="account_security_title" msgid="3511543138560418587">"Segurança do dispositivo"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"O servidor <xliff:g id="SERVER">%s</xliff:g> requer a permissão de controle remoto de alguns recursos de segurança do seu dispositivo Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Editar detalhes"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Sua senha ou PIN da tela de bloqueio expirou."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Senha da tela de bloqueio expirada"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Senha da tela de bloqueio expirando"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"É necessário alterar o PIN ou a senha de sua tela de bloqueio logo, ou os dados da <xliff:g id="ACCOUNT">%s</xliff:g> serão apagados. Deseja mudar isso agora?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"É necessário alterar sua senha ou PIN da tela de bloqueio, senão os dados de <xliff:g id="ACCOUNT">%s</xliff:g> serão apagados. Alterar agora?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Senha da tela de bloqueio expirada"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Os dados da <xliff:g id="ACCOUNT">%s</xliff:g> estão sendo apagados de seu dispositivo. Você pode restaurá-los alterando o PIN ou a senha de sua tela de bloqueio. Deseja mudar isso agora?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Os dados de <xliff:g id="ACCOUNT">%s</xliff:g> estão sendo apagados de seu dispositivo. Você pode restaurá-los alterando sua senha ou PIN da tela de bloqueio. Alterar agora?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Descartar as alterações não salvas?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Não foi possível fazer login"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"O nome de usuário ou senha da <xliff:g id="ACCOUNT">%s</xliff:g> está incorreto. Deseja atualizar agora?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"O nome de usuário ou a senha de <xliff:g id="ACCOUNT">%s</xliff:g> estão incorretos. Atualizar agora?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Conta padrão"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Enviar e-mail desta conta por padrão"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Fazer download dos anexos"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Fazer download automát. dos anexos de mens. recentes via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificações de e-mail"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frequência de sincronização, notificações etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Enviar notificação quando chegarem e-mails"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Notificar sobre chegada de e-mails na barra de sistema"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frequência de verificação da caixa de entrada"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Configurações recebidas"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nome de usuário, senha e outras configurações do servidor de entrada"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Configurações enviadas"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nome de usuário, senha e outras configurações do servidor de saída"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Políticas aplicadas"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Nenhuma"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Políticas não suportadas"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Nenhuma"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Tentativa de sincronização"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Toque aqui para sincronizar esta conta"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Nome da conta"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Seu nome"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Assinatura"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Respostas rápidas"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Edite o texto que você costuma inserir ao compor e-mails"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Edite o texto que você costuma inserir ao compor e-mails"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Acrescentar texto às mensagens que você envia"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Configurações de notificação"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Uso de dados"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Políticas de segurança"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Editar resposta rápida"</string> <string name="save_action" msgid="1988862706623227093">"Salvar"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizar contatos"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronizar contatos para esta conta"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizar agenda"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinc. evento agenda p/ esta conta"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronizar agenda"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronizar agenda para esta conta"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincronizar e-mail"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronizar e-mail para esta conta"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrar"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Aguardando resultados"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Alguns servidores podem levar um longo tempo."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Pastas"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Desativar o uso da câmera do dispositivo"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Exigir senha para o dispositivo"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Restringir reutiliz. de senhas recentes"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Exigir que as senhas expirem"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Exigir dispositivo inativo p/ bloq. tela"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitar número de eventos de agenda sincronizados"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitar número de e-mails sincronizados"</string> - <string name="quick_1" msgid="3426057697353380951">"Obrigado!"</string> - <string name="quick_2" msgid="4188036352885736617">"Parece uma boa ideia!"</string> - <string name="quick_3" msgid="8061819976353395585">"Lerei isso mais tarde e darei uma resposta a você."</string> - <string name="quick_4" msgid="3988974084396883051">"Podemos marcar uma reunião para discutir isso."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"A sincronização em segundo plano para essa conta é desativada durante o roaming."</string> </resources> diff --git a/res/values-pt/uploader.xml b/res/values-pt/uploader.xml index f23616485..bf9b37971 100644 --- a/res/values-pt/uploader.xml +++ b/res/values-pt/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ocultar detalhes"</string> <string name="menu_settings" msgid="5088116127086866634">"Configurações"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Enviado %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Conta"</string> <string name="upload" msgid="2615541458361216022">"Enviar"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml index e399b7ffc..6327cd10a 100644 --- a/res/values-rm/strings.xml +++ b/res/values-rm/strings.xml @@ -18,11 +18,11 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- no translation found for permission_read_attachment_label (9208086010625033590) --> <skip /> - <!-- no translation found for permission_read_attachment_desc (3394721085306308972) --> + <!-- no translation found for permission_read_attachment_desc (6592948507403743153) --> <skip /> <!-- no translation found for permission_access_provider_label (378256653525377586) --> <skip /> - <!-- no translation found for permission_access_provider_desc (6296566558584670348) --> + <!-- no translation found for permission_access_provider_desc (2221907862438022705) --> <skip /> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Nov messadi"</string> @@ -44,7 +44,7 @@ <skip /> <!-- no translation found for delete_quick_response_action (3076922270182841978) --> <skip /> - <!-- no translation found for quick_responses_empty_view (3960050972306132367) --> + <!-- no translation found for quick_responses_empty_view (1693308598242828422) --> <skip /> <string name="discard_action" msgid="6532206074859505968">"Sbittar"</string> <!-- no translation found for save_draft_action (6413714270991417223) --> @@ -177,8 +177,7 @@ <skip /> <!-- no translation found for message_compose_include_quoted_text_checkbox_label (8165567368956050390) --> <skip /> - <!-- no translation found for message_compose_error_no_recipients (140299472517968199) --> - <skip /> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Vus stuais agiuntar almain in destinatur."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Tschertas adressas dad e-mail èn nuncorrectas."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"L\'agiunta è memia gronda."</string> <!-- no translation found for message_compose_insert_quick_response_list_title (5314107302508728189) --> @@ -207,10 +206,9 @@ <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Fermar"</string> <!-- no translation found for message_view_status_attachment_saved (8878790392556284868) --> <skip /> - <!-- no translation found for message_view_status_attachment_not_saved (4013475734255421939) --> - <skip /> - <!-- no translation found for message_view_attachment_background_load (7906875687519445185) --> + <!-- no translation found for message_view_status_attachment_not_saved (2433097334272991035) --> <skip /> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Remartga: Ina u pliras agiuntas en Voss messadi renvià vegn(an) telechargiada(s) avant la spediziun."</string> <!-- no translation found for message_view_show_message_action (5134222901019191436) --> <skip /> <!-- no translation found for message_view_show_invite_action (8862797393776226777) --> @@ -289,7 +287,7 @@ <skip /> <!-- no translation found for forward_download_failed_title (6139701848515572511) --> <skip /> - <!-- no translation found for login_failed_ticker (2169365211566829350) --> + <!-- no translation found for login_failed_ticker (5749227022559285302) --> <skip /> <!-- no translation found for login_failed_title (7624349996212476176) --> <skip /> @@ -331,8 +329,7 @@ <skip /> <!-- no translation found for account_setup_basics_password_label (9133549799291519298) --> <skip /> - <!-- no translation found for account_setup_basics_default_label (8896222991837026736) --> - <skip /> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Trametter ils e-mails tenor standard cun quest conto"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configuraziun manuala"</string> <!-- no translation found for account_setup_username_password_toast (3968270274727947460) --> <skip /> @@ -347,7 +344,7 @@ <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Ils parameters dil server da sortida vegnan controllads…"</string> <!-- no translation found for account_setup_names_title (8483517350241119291) --> <skip /> - <!-- no translation found for account_setup_names_headline (914858472109729140) --> + <!-- no translation found for account_setup_names_headline (2413440250372658881) --> <skip /> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Dar in num al conto (facultativ)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Voss num (vegn mussà en messadis che sortan)"</string> @@ -389,8 +386,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tip da segirezza"</string> - <!-- no translation found for account_setup_outgoing_require_login_label (7779484127897397562) --> - <skip /> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Annunzia obligatorica"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Num d\'utilisader"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Pled-clav"</string> <!-- no translation found for account_setup_exchange_title (396004732514751781) --> @@ -425,16 +421,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Mintga 15 minutas"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Mintga 30 minutas"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Mintga ura"</string> - <!-- no translation found for account_setup_options_default_label (2617227194283720914) --> - <skip /> - <!-- no translation found for account_setup_options_notify_label (7046146571560728829) --> - <skip /> - <!-- no translation found for account_setup_options_sync_contacts_label (276492345599531778) --> - <skip /> - <!-- no translation found for account_setup_options_sync_calendar_label (3222151135467189411) --> - <skip /> - <!-- no translation found for account_setup_options_sync_email_label (8585177128405004068) --> - <skip /> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"\"Trametter ils e-mails da quest conto, tenor standard.\""</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Mussar in avis cura ch\'in e-mail arriva"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sincronisar ils contacts da quest conto"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronisar il chalender da quest conto"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincronisar ils e-mails da quest conto."</string> <!-- no translation found for account_setup_options_background_attachments_label (5247749298276451846) --> <skip /> <!-- no translation found for account_setup_failed_dlg_title (9083263347962940552) --> @@ -452,19 +443,17 @@ <skip /> <!-- no translation found for account_setup_options_mail_window_default (8321351926520165832) --> <skip /> - <!-- no translation found for account_setup_failed_dlg_auth_message (426627755590431364) --> - <skip /> - <!-- no translation found for account_setup_failed_dlg_auth_message_fmt (737111956772240007) --> - <skip /> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Num d\'utilisader u pled-clav nuncorrect."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Num d\'utilisader u pled-clav nuncorrect."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <!-- no translation found for account_setup_failed_dlg_certificate_message (3836152264696108805) --> <skip /> <!-- no translation found for account_setup_failed_dlg_certificate_message_fmt (2121921642915593041) --> <skip /> - <!-- no translation found for account_setup_failed_certificate_required (2689944595775206006) --> + <!-- no translation found for account_setup_failed_certificate_required (1280569002588325367) --> <skip /> - <!-- no translation found for account_setup_failed_certificate_inaccessible (3563840279690749547) --> + <!-- no translation found for account_setup_failed_certificate_inaccessible (7245835883180762722) --> <skip /> - <!-- no translation found for account_setup_failed_check_credentials_message (6531658092540248067) --> + <!-- no translation found for account_setup_failed_check_credentials_message (222908719765968691) --> <skip /> <!-- no translation found for account_setup_failed_dlg_server_message (4942810054116129684) --> <skip /> @@ -494,17 +483,8 @@ <skip /> <!-- no translation found for account_security_dialog_content_fmt (8843806143923278214) --> <skip /> - <!-- no translation found for security_unsupported_ticker_fmt (5166579214529283975) --> - <skip /> - <!-- no translation found for security_needed_ticker_fmt (2120499087897133665) --> - <skip /> - <!-- no translation found for security_changed_ticker_fmt (2609435447352755285) --> - <skip /> - <!-- no translation found for security_notification_content_update_title (2429762903228690154) --> - <skip /> - <!-- no translation found for security_notification_content_change_title (443490921895642130) --> - <skip /> - <!-- no translation found for security_notification_content_unsupported_title (7315219208043169233) --> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Il conto «<xliff:g id="ACCOUNT">%s</xliff:g>» basegna ina actualisaziun dals parameters da segirezza."</string> + <!-- no translation found for security_notification_content_title (3352841884304076235) --> <skip /> <!-- no translation found for account_security_title (3511543138560418587) --> <skip /> @@ -521,17 +501,17 @@ <skip /> <!-- no translation found for password_expire_warning_dialog_title (1687074175399798189) --> <skip /> - <!-- no translation found for password_expire_warning_dialog_content_fmt (4293446611405084436) --> + <!-- no translation found for password_expire_warning_dialog_content_fmt (4595246020880351045) --> <skip /> <!-- no translation found for password_expired_dialog_title (2186547998125938084) --> <skip /> - <!-- no translation found for password_expired_dialog_content_fmt (6538210092073931079) --> + <!-- no translation found for password_expired_dialog_content_fmt (5982207349002500211) --> <skip /> <!-- no translation found for account_settings_exit_server_settings (8006323251094711431) --> <skip /> <!-- no translation found for account_settings_login_dialog_title (4024422579146302775) --> <skip /> - <!-- no translation found for account_settings_login_dialog_content_fmt (8849649646111167377) --> + <!-- no translation found for account_settings_login_dialog_content_fmt (3492735234999710234) --> <skip /> <string name="account_settings_default_label" msgid="3575963379680943640">"Conto predefinì"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Trametter ils e-mails tenor standard cun quest conto"</string> @@ -541,7 +521,7 @@ <skip /> <string name="account_settings_notify_label" msgid="1630001017303007974">"Avis ad e-mails"</string> <string name="account_settings_summary" msgid="8403582255413830007">"\"Frequenza da sincronisaziun, avis, etc.\""</string> - <!-- no translation found for account_settings_notify_summary (8134339460923068254) --> + <!-- no translation found for account_settings_notify_summary (6301122709602752038) --> <skip /> <!-- no translation found for account_settings_mail_check_frequency_label (8271462919214560616) --> <skip /> @@ -551,40 +531,25 @@ <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Parameters da sortida"</string> <!-- no translation found for account_settings_outgoing_summary (3572093624332724311) --> <skip /> - <!-- no translation found for account_settings_enforced_label (7429582254433588882) --> - <skip /> - <!-- no translation found for account_settings_enforced_summary (8140860420440447771) --> - <skip /> - <!-- no translation found for account_settings_unsupported_label (1954091071454235577) --> - <skip /> - <!-- no translation found for account_settings_unsupported_summary (2107633813351863608) --> - <skip /> - <!-- no translation found for account_settings_retry_label (1104680719299842829) --> - <skip /> - <!-- no translation found for account_settings_retry_summary (2703599639846201913) --> - <skip /> <string name="account_settings_description_label" msgid="8894815221204511715">"Num dal conto"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Voss num"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signatura"</string> <!-- no translation found for account_settings_edit_quick_responses_label (3106019627675996480) --> <skip /> - <!-- no translation found for account_settings_edit_quick_responses_summary (8056686122888722591) --> + <!-- no translation found for account_settings_edit_quick_responses_summary (5284435342418252369) --> <skip /> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Agiuntar in text als messadis che sortan"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Parameters dad avis"</string> <!-- no translation found for account_settings_data_usage (6669107430575866736) --> <skip /> - <!-- no translation found for account_settings_policies (6292833636418641840) --> - <skip /> <!-- no translation found for edit_quick_response_dialog (4322494050816995390) --> <skip /> <!-- no translation found for save_action (1988862706623227093) --> <skip /> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronisar ils contacts"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincronisar ils contacts per quest conto"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronisar il chalender"</string> - <!-- no translation found for account_settings_sync_calendar_summary (7606340353079301703) --> - <skip /> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincronisar il chalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincronisar il chalender per quest conto"</string> <!-- no translation found for account_settings_sync_email_enable (3754115565685222477) --> <skip /> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincronisar ils e-mails per quest conto"</string> @@ -719,28 +684,6 @@ <skip /> <!-- no translation found for action_bar_mailbox_list_title (7484457755531286333) --> <skip /> - <!-- no translation found for policy_dont_allow_camera (5744573062306937302) --> - <skip /> - <!-- no translation found for policy_require_password (7177274900480984702) --> - <skip /> - <!-- no translation found for policy_password_history (5743544498302303181) --> - <skip /> - <!-- no translation found for policy_password_expiration (1248123255253649199) --> - <skip /> - <!-- no translation found for policy_screen_timeout (414869965358468080) --> - <skip /> - <!-- no translation found for policy_calendar_age (627405158087482302) --> - <skip /> - <!-- no translation found for policy_email_age (7144148367145424963) --> - <skip /> - <!-- no translation found for quick_1 (3426057697353380951) --> - <skip /> - <!-- no translation found for quick_2 (4188036352885736617) --> - <skip /> - <!-- no translation found for quick_3 (8061819976353395585) --> - <skip /> - <!-- no translation found for quick_4 (3988974084396883051) --> - <skip /> <!-- no translation found for require_manual_sync_message (7777357288642785955) --> <skip /> </resources> diff --git a/res/values-rm/uploader.xml b/res/values-rm/uploader.xml index 1f6568e08..1faf9ef95 100644 --- a/res/values-rm/uploader.xml +++ b/res/values-rm/uploader.xml @@ -49,7 +49,7 @@ <skip /> <!-- no translation found for format_date_uploaded (803752037646090928) --> <skip /> - <!-- no translation found for format_progress_percent (4347398038122210157) --> + <!-- no translation found for format_progress_percent (1420459750508777491) --> <skip /> <!-- no translation found for account (5199161365824352613) --> <skip /> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 928c1b3b7..dafedab69 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Citiţi ataşamentele e-mailurilor"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Permite aplicaţiei citirea ataşamentelor de e-mail."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Permite aplicaţiei citirea ataşamentelor de e-mail."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Accesaţi datele furnizorului de e-mail"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Permite aplicaţiei să acceseze baza de date a adresei de e-mail, incluzând mesajele primite, mesajele trimise, numele de utilizator şi parolele."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Permite acestei aplicaţii accesul la baza de date a adresei de e-mail, incluzând mesajele primite, mesajele trimise, numele de utilizatori şi parolele."</string> <string name="app_name" msgid="5815426892327290362">"E-mail"</string> <string name="compose_title" msgid="427986915662706899">"Scrieţi"</string> <string name="debug_title" msgid="5175710493691536719">"Remediaţi erorile"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Terminat"</string> <string name="create_action" msgid="3062715563215392251">"Creaţi unul nou"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Ştergeţi"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Nu există răspunsuri rapide."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Nu există răspunsuri rapide"</string> <string name="discard_action" msgid="6532206074859505968">"Renunţaţi"</string> <string name="save_draft_action" msgid="6413714270991417223">"Salvaţi m. nef."</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Introd. un răspuns rapid"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> a scris:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Includeţi textul citat"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Includeţi textul"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Adăugaţi cel puţin un destinatar."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Trebuie să adăugaţi cel puţin un destinatar."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Unele adrese de e-mail sunt nevalide."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Fişierul este prea mare pentru a fi ataşat."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Introduceţi un răspuns rapid"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Salvat"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Opriţi"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Ataşament salvat ca <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Ataşamentul nu s-a salvat."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Unul sau mai multe ataşamente din mesajul dvs. redirecţionat vor fi descărcate înainte de a fi trimise."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Nu s-a salvat ataşamentul."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Notă: unul sau mai multe ataşamente din mesajul dvs. redirecţionat vor fi descărcate înainte de a fi trimise."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mesaj"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Invitaţi"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Nu se pot redirecţiona unul sau mai multe ataşamente."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Ataşamentul nu a fost trimis"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Conectare eşuată pentru <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Conectare eşuată la <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Nu s-a putut conecta"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> O"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Puteţi să configuraţi un cont Exchange ActiveSync urmând doar câţiva paşi."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Adresă de e-mail"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Parolă"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Trimiteţi e-mailuri de pe acest cont în mod prestabilit"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Trimiteţi e-mailuri din acest cont în mod prestabilit."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Configurare manuală"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Introduceţi o adresă de e-mail şi o parolă valide."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Cont duplicat"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Se verifică setările pentru serverul mesajelor de intrare..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Se verifică setările serverului de mesaje de ieşire..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Configurare cont"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Contul este configurat, iar e-mailul funcţionează corect!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Contul este configurat, iar e-mailul funcţionează corect!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Daţi un nume acestui cont (opţional)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Numele dvs. (afişat în mesajele de trimitere)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Acest câmp nu poate rămâne necompletat."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Tipul de securitate"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Necesită conectare"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Solicitaţi conectarea."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Nume de utilizator"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Parolă"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Configurare cont"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"La fiecare 15 minute"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"La fiecare 30 de minute"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"La fiecare oră"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Trimiteţi e-mailuri de pe acest cont în mod prestabilit"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Doresc să fiu notificat(ă) la primirea de e-mailuri"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Doresc sincronizarea agendei acestui cont"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Doresc sincronizarea calendarului acestui cont"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Doresc sincronizarea mesajelor de e-mail din acest cont"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Trimiteţi e-mailuri din acest cont"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Doresc să primesc notificare la primirea de e-mailuri."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Doresc sincronizarea agendei acestui cont."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sincronizaţi calendarul acestui cont."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sincron. e-mail din acest cont."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Doresc să se descarce automat ataşamentele când sunt conectat(ă) la Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nu s-a putut finaliza"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Zile pentru sincronizare"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"O lună"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Toate"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Setări prestabilite cont"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Numele de utilizator sau parola sunt incorecte."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Numele de utilizator sau parola sunt incorecte."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nume de utilizator sau parolă incorectă."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nume de utilizator sau parolă incorectă."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nu se poate conecta în siguranţă la server."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nu se poate conecta în siguranţă la server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Este necesar un certificat de client. Doriţi să vă conectaţi la server cu un certificat de client?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certificat nevalid sau inaccesibil."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Serverul a răspuns cu o eroare. Verificaţi numele de utilizator şi parola şi încercaţi din nou."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Este necesar un certificat de client. Vă conectaţi la server cu un certificat de client?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certificat nevalid sau inaccesibil."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Serverul a răspuns cu o eroare. Verificaţi numele de utilizator şi parola şi încercaţi din nou."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nu se poate conecta la server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nu se poate conecta la server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS solicitat, dar neacceptat de către server."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"AVERTISMENT: dacă dezactivaţi autoritatea aplicaţiei E-mail de administrare a dispozitivului dvs. se şterg toate conturile de e-mail care au nevoie de aceasta, împreună cu e-mailurile, agenda, evenimentele din calendar şi alte date pe care aceste conturi le conţin."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Actualizare de securitate"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> vă solicită actualizarea setărilor dvs. de securitate."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Contul „<xliff:g id="ACCOUNT">%s</xliff:g>” nu poate fi sincronizat din cauza cerinţelor de securitate."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Contul „<xliff:g id="ACCOUNT">%s</xliff:g>” necesită actualizarea setărilor de securitate."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Contul „<xliff:g id="ACCOUNT">%s</xliff:g>” şi-a schimbat setările de securitate. Nu este necesară nicio acţiune din partea utilizatorului."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Actualizare de securitate obligatorie"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Pol. securitate s-au schimbat"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Politici securitate nerespect."</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Contul „<xliff:g id="ACCOUNT">%s</xliff:g>” necesită actualizarea setărilor de securitate."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Actual. de securitate necesară"</string> <string name="account_security_title" msgid="3511543138560418587">"Securitatea dispozitivului"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Serverul <xliff:g id="SERVER">%s</xliff:g> vă solicită permisiunea de a controla de la distanţă unele caracteristici de securitate ale dispozitivului dvs. Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Modificaţi detaliile"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Codul PIN sau parola de blocare a ecranului a expirat."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Parolă bloc. ecran. expirată"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Parola de blocare ecran expiră în curând"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Este necesar să modificaţi curând codul PIN sau parola ecranului de blocare; în caz contrar datele pentru <xliff:g id="ACCOUNT">%s</xliff:g> vor fi şterse. Modificaţi acum?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Este necesar să modificaţi în curând codul PIN sau parola de blocare a ecranului. În caz contrar, datele pentru <xliff:g id="ACCOUNT">%s</xliff:g> vor fi şterse. Modificaţi acum?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Parola de blocare ecran expirată"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Datele pentru <xliff:g id="ACCOUNT">%s</xliff:g> sunt şterse de pe dispozitiv, dar le puteţi restabili modificând codul PIN sau parola de blocare a ecranului. Modificaţi acum?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Datele pentru <xliff:g id="ACCOUNT">%s</xliff:g> sunt şterse de pe dispozitiv, dar le puteţi restabili modificând codul PIN sau parola de blocare a ecranului. Modificaţi acum?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Renunţaţi la modificările nesalvate?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Nu s-a putut conecta"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Numele de utilizator sau parola pentru <xliff:g id="ACCOUNT">%s</xliff:g> sunt incorecte. Doriţi să le actualizaţi acum?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Numele de utilizator sau parola pentru <xliff:g id="ACCOUNT">%s</xliff:g> este incorectă. Le actualizaţi acum?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Cont prestabilit"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Trimiteţi e-mailuri de pe acest cont în mod prestabilit"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Descărcaţi ataşamentele"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Descărcaţi în mod automat prin Wi-Fi ataşam. mesaj. recente"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Notificările de e-mail"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frecvenţa sincronizării, notificări etc."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Trimiteţi notificare la primire e-mail"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Doresc să fiu notificat(ă) în bara de sistem la primirea e-mailurilor"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frecvenţa verificării mesajelor primite"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Setări pentru mesajele primite"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Nume utilizator, parolă şi alte setări pt. serverul de primire"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Setări pentru mesajele de trimitere"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Nume utilizator, parolă şi alte setări pt. server de trimitere"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Politicile puse în aplicare"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Niciunul"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Politici neacceptate"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Niciunul"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Încercaţi sincronizarea"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Atingeţi aici pentru a sincroniza acest cont"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Numele contului"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Numele dvs."</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Semnătura"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Răspunsuri rapide"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Editaţi textul introdus frecvent când scrieţi e-mailuri"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Editaţi textul introdus frecvent când scrieţi e-mailuri"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Adăugaţi text la mesajele trimise"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Setări pentru notificări"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Utilizarea datelor"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Politici de securitate"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Editaţi răspunsul rapid"</string> <string name="save_action" msgid="1988862706623227093">"Salvaţi"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sincronizaţi persoanele din agendă"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sincron. agenda pt. acest cont"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sincronizaţi calendarul"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sincron. evenim. calendar pt. cont"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sincron. Calendar"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sincron. calendarul pt. acest cont"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sincroniz. e-mailul"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sincron. e-mail pt. acest cont"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrare"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Se aşteaptă rezultatele"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Pentru unele servere poate fi necesar un interval mare de timp."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Dosare"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Nu permiteţi utilizarea camerei foto"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Solicitaţi parola dispozitivului"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Limitaţi reutilizarea parolelor recente"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Solicitaţi expirarea parolelor"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Disp. inactiv necesar pt. blocare ecran"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitare număr evenimente de calendar sincronizate"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitare număr de e-mailuri sincronizate"</string> - <string name="quick_1" msgid="3426057697353380951">"Vă mulţumim!"</string> - <string name="quick_2" msgid="4188036352885736617">"Sună bine!"</string> - <string name="quick_3" msgid="8061819976353395585">"Voi citi mai târziu acest mesaj şi vă voi contacta."</string> - <string name="quick_4" msgid="3988974084396883051">"Să stabilim o întâlnire pentru a discuta această acţiune."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Sincronizarea în fundal pentru acest cont este dezactivată în roaming."</string> </resources> diff --git a/res/values-ro/uploader.xml b/res/values-ro/uploader.xml index a3af219b1..b06fe413a 100644 --- a/res/values-ro/uploader.xml +++ b/res/values-ro/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ascundeţi detaliile"</string> <string name="menu_settings" msgid="5088116127086866634">"Setări"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Încărcat pe %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Cont"</string> <string name="upload" msgid="2615541458361216022">"Încărcaţi"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index ab7bc690f..3fb838781 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Открывать прикрепленные файлы"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Приложение получит доступ к прикрепленным файлам в сообщениях электронной почты."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Приложение получит доступ к прикрепленным файлам в сообщениях эл. почты."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Доступ к данным сервиса эл. почты"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Приложение получит доступ к базе данных электронной почты, которая содержит полученные и отправленные сообщения, имена пользователей и пароли."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Приложение получит доступ к базе данных программы электронной почты, которая включает полученные и отправленные письма, имена пользователей и пароли."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Новое сообщение"</string> <string name="debug_title" msgid="5175710493691536719">"Выполнить отладку"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Готово"</string> <string name="create_action" msgid="3062715563215392251">"Создать"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Удалить"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Нет шаблонов"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Нет шаблонов SMS-ответов"</string> <string name="discard_action" msgid="6532206074859505968">"Отменить"</string> <string name="save_draft_action" msgid="6413714270991417223">"Сохранить черновик"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Вставить быстрый ответ"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"Пользователь <xliff:g id="SENDER">%s</xliff:g> писал:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Включить цитируемый текст"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Включить исходный текст в ответ"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Укажите получателя."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Добавьте хотя бы одного получателя."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Некоторые адреса электронной почты являются недопустимыми."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Файл имеет слишком большой размер и не может быть приложен."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Вставка быстрого ответа"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Сохранено"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Стоп"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Вложение сохранено как <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Файл не сохранен."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Один или несколько прикрепленных файлов в пересылаемом сообщении будут загружены перед отправкой."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Файл не сохранен."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Примечание. Несколько прикрепленных файлов в переадресованном сообщении будут загружены перед отправкой."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Сообщение"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Пригласить"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Сбой при пересылке прикрепленных файлов."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Не удалось переслать вложение"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Ошибка при входе в аккаунт <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Ошибка авторизации <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Вход не выполнен"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> Б"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Настроить аккаунт Exchange ActiveSync очень просто."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Адрес электронной почты"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Пароль"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"По умолчанию отправлять письма с этого адреса"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Сделать аккаунтом электронной почты по умолчанию для отправки сообщений."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Вручную"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Введите действительный адрес электронной почты и пароль."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Копировать аккаунт"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Проверка настроек сервера входящих сообщений..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Проверка настроек сервера исходящих сообщений..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Настройка аккаунта"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Аккаунт добавлен!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ваш аккаунт настроен, ждите сообщений!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Присвойте этому аккаунту название (по желанию)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Ваше имя (показывается в исходящих сообщениях)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Это поле должно быть заполнено."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Сервер SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Порт"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Тип безопасности"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Выполнять вход в систему"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Требовать входа в аккаунт."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Имя пользователя"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Пароль"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Настройка аккаунта"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Каждые 15 минут"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Каждые 30 минут"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Каждый час"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"По умолчанию отправлять письма с этого адреса"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Показывать уведомление при получении новых писем"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Синхронизировать контакты из этого аккаунта"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Синхронизировать календарь из этого аккаунта"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Синхронизировать электронную почту из этого аккаунта"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Сделать аккаунтом электронной почты по умолчанию для отправки сообщений."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Уведомлять при получении сообщения по электронной почте."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Синхронизировать контакты из этого аккаунта."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Синхронизировать календарь из этого аккаунта."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Синхронизировать почту из этого аккаунта"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Автоматически загружать прикрепленные файлы при подключении к Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Настройка не закончена"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Период синхронизации"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Один месяц"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Все"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Параметры по умолчанию"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Неверное имя пользователя или пароль."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Неверное имя пользователя или пароль."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Неверное имя пользователя или пароль."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Неверное имя пользователя или пароль."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Не удалось установить защищенное подключение к серверу."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Не удалось установить защищенное подключение к серверу."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Требуется сертификат клиента. Подключиться к серверу с таким сертификатом?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Сертификат недействителен или недоступен."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Ошибка сервера. Проверьте имя пользователя и пароль и повторите попытку."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Необходим сертификат клиента. Подключиться к серверу?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Сертификат недействителен или недоступен."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Ошибка сервера. Проверьте имя пользователя и пароль и повторите попытку."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Не удалось подключиться к серверу."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Не удалось подключиться к серверу."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS не поддерживается сервером."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ВНИМАНИЕ! Отключение прав на администрирование вашего устройства для приложения Email приведет к удалению всех аккаунтов электронной почты, которые используют эти права. Кроме того, будут удалены все письма, контакты, календари и другие данные, связанные с этими аккаунтами."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Обновления безопасности"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Для аккаунта <xliff:g id="ACCOUNT">%s</xliff:g> требуется обновить настройки безопасности."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Настройки безопасности не позволяют синхронизировать аккаунт <xliff:g id="ACCOUNT">%s</xliff:g>."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"В аккаунте <xliff:g id="ACCOUNT">%s</xliff:g> требуется обновить настройки безопасности."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"В аккаунте <xliff:g id="ACCOUNT">%s</xliff:g> обновлены настройки безопасности. Ничего делать не нужно."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Обновите систему безопасности"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Политики безопасности изменены"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Политики не выполнены"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Аккаунт \"<xliff:g id="ACCOUNT">%s</xliff:g>\" требует обновления настроек безопасности."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Обновите систему безопасности"</string> <string name="account_security_title" msgid="3511543138560418587">"Безопасность устройства"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Серверу <xliff:g id="SERVER">%s</xliff:g> требуется разрешение на удаленное управление некоторыми функциями безопасности устройства Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Изменить сведения"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Срок действия вашего PIN-кода или пароля блокировки экрана истек."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Пароль блок. экрана устарел"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Истекает срок действия пароля"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Скоро вам потребуется изменить PIN-код или пароль для блокировки экрана, иначе данные аккаунта <xliff:g id="ACCOUNT">%s</xliff:g> будут удалены. Изменить PIN-код или пароль сейчас?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Вам следует в ближайшее время изменить PIN-код или пароль блокировки экрана, иначе данные аккаунта <xliff:g id="ACCOUNT">%s</xliff:g> будут удалены. Изменить сейчас?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Пароль блокировки экрана устарел"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Данные аккаунта <xliff:g id="ACCOUNT">%s</xliff:g> удаляются с устройства. Вы можете восстановить их, изменив свой PIN-код или пароль блокировки экрана. Сделать это сейчас?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Данные аккаунта <xliff:g id="ACCOUNT">%s</xliff:g> удаляются с вашего устройства. Вы можете восстановить их, изменив свой PIN-код или пароль блокировки экрана. Изменить его сейчас?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Отменить несохраненные изменения?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Не удалось войти в аккаунт."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Неверное имя пользователя или пароль для доступа в аккаунт <xliff:g id="ACCOUNT">%s</xliff:g>. Изменить их?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Неверное имя пользователя или пароль аккаунта <xliff:g id="ACCOUNT">%s</xliff:g>. Обновить их сейчас?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Аккаунт по умолчанию"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Сделать аккаунтом электронной почты по умолчанию для отправки сообщений"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Загружать прикрепленные файлы"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Автоматически загружать файлы из новых сообщений через Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Уведомления электронной почты"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Частота синхронизации, уведомления и другие настройки"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Показывать уведомление при получении новых писем"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"При получении почты показывать оповещение в строке состояния системы"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Частота проверки папки \"Входящие\""</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Настройки входящих сообщений"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Имя пользователя, пароль и др. настройки сервера входящей почты"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Настройки исходящих сообщений"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Имя пользователя, пароль и др. настройки сервера исходящей почты"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Политики применены"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Нет"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Неподдерживаемые политики"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Нет"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Синхронизировать"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Нажмите, чтобы синхронизировать данные"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Название аккаунта"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Ваше имя"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Подпись"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Быстрые ответы"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Использовать шаблоны для стандартных ответов"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Изменить текст, который часто используется в ваших письмах"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Добавлять текст к отправляемым сообщениям"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Настройки уведомлений"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Использование данных"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Политики безопасности"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Изменить быстрый ответ"</string> <string name="save_action" msgid="1988862706623227093">"Сохранить"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Синхронизировать контакты"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Синхронизировать контакты этого аккаунта"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Синхронизировать календарь"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Синхронизация мероприятий"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Синхронизировать календарь"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Синхронизировать календарь этого аккаунта"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Синхр. почту"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Синхронизировать почту этого аккаунта"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Вибросигнал"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Ожидание результатов"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Ожидание ответа от сервера может занять много времени."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Папки"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Запрещать использовать камеру"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Запрашивать пароль для разблокировки"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Запрещать использовать прежние пароли"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Ограничивать время действия паролей"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Блокировать экран при простое"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ограничить число синхр. событий календаря"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ограничить число синхр. сообщений эл. почты"</string> - <string name="quick_1" msgid="3426057697353380951">"Спасибо!"</string> - <string name="quick_2" msgid="4188036352885736617">"Отличная идея!"</string> - <string name="quick_3" msgid="8061819976353395585">"Я отвечу позже."</string> - <string name="quick_4" msgid="3988974084396883051">"Это нужно обсудить при встрече."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Для этого аккаунта отключена фоновая синхронизация в роуминге."</string> </resources> diff --git a/res/values-ru/uploader.xml b/res/values-ru/uploader.xml index 247ac0180..08dbd9e8c 100644 --- a/res/values-ru/uploader.xml +++ b/res/values-ru/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Скрыть подробности"</string> <string name="menu_settings" msgid="5088116127086866634">"Настройки"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Загружено %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Аккаунт"</string> <string name="upload" msgid="2615541458361216022">"Загрузить"</string> <string name="ok" msgid="2516349681897895312">"ОК"</string> diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index a68e96601..0d62114e8 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Čítať e-mailové prílohy"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Povoľuje aplikácii čítať prílohy vašich e-mailov."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Umožňuje tejto aplikácii čítať prílohy vašich e-mailov."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Prístup k údajom poskytovateľa e-mailu"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Povoľuje aplikácii prístup do databázy e-mailu vrátane prijatých a odoslaných správ, používateľských mien a hesiel."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Povoľuje tejto aplikácii prístup do databázy e-mailu, vrátane prijatých a odoslaných správ, používateľských mien a hesiel."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Napísať správu"</string> <string name="debug_title" msgid="5175710493691536719">"Ladiť"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Hotovo"</string> <string name="create_action" msgid="3062715563215392251">"Vytvoriť novú"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Odstrániť"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Žiadne rýchle odpovede."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Žiadne rýchle odpovede"</string> <string name="discard_action" msgid="6532206074859505968">"Zahodiť"</string> <string name="save_draft_action" msgid="6413714270991417223">"Uložiť koncept"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Vložiť rýchlu odpoveď"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>napísal/a:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Zahrnúť citovaný text"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Zahrnúť text"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Pridajte aspoň jedného príjemcu."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Musíte pridať aspoň jedného príjemcu."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Niektoré e-mailové adresy sú neplatné."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Súbor nie je možné priložiť, pretože je príliš veľký."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Vložiť rýchlu odpoveď"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Uložené"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Zastaviť"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Príloha uložená ako <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Prílohu sa nepodarilo uložiť."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Pred odoslaním sa prevezme jedna alebo viacero príloh zo správy posielanej ďalej."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Prílohu sa nepodarilo uložiť."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Poznámka: Pred odoslaním sa prevezme jedna alebo viac príloh zo správy posielanej ďalej."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Správa"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Pozvať"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Nepodarilo sa poslať ďalej jednu alebo viac príloh."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Príloha nebola poslaná ďalej"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Prihlásenie do účtu <xliff:g id="ACCOUNT_NAME">%s</xliff:g> zlyhalo."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Prihlásenie do účtu <xliff:g id="ACCOUNT_NAME">%s</xliff:g> zlyhalo."</string> <string name="login_failed_title" msgid="7624349996212476176">"Prihlásenie sa nepodarilo"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Účet služby Exchange ActiveSync môžete nastaviť pomocou niekoľkých krokov."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-mailová adresa"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Heslo"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"V predvolenom nastavení odosielať e-maily z tohto účtu"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"V predvolenom nastavení odosielať e-maily z tohto účtu."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ručné nastavenie"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Zadajte platnú e-mailovú adresu a heslo."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplikovať účet"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Kontrola nastavení servera prichádzajúcej pošty…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kontrola nastavení servera odchádzajúcej pošty…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Nastavenie účtu"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Váš účet je nastavený a e-mail je na ceste!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Váš účet je nastavený, e-mail je na ceste!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Pomenovať tento účet (nepovinné)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Vaše meno (zobrazované na odchádzajúcich správach)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Toto pole nesmie byť prázdne."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Server SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Typ zabezpečenia"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Vyžadovať prihlásenie"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Požadovať prihlásenie"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Používateľské meno"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Heslo"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Nastavenie účtu"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Každých 15 minút"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Každých 30 minút"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Každú hodinu"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"V predvolenom nastavení odosielať e-maily z tohto účtu"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Upozorniť ma na príchod e-mailu"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synchronizovať kontakty z tohto účtu"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synchronizovať kalendár z tohto účtu"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synchronizovať e-mail z tohto účtu"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"V predvolenom nastavení odosielať e-maily z tohto účtu."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Upozorniť ma na príchod e-mailu"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synchronizovať kontakty z tohto účtu."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synchronizovať kalendár z tohto účtu."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synchronizovať e-mail z tohto účtu."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Automaticky preberať prílohy počas pripojenia k sieti Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Nepodarilo sa dokončiť"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Počet dní na synchronizáciu"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Jeden mesiac"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Všetky"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Použiť predv. nast. účtu"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Používateľské meno alebo heslo je nesprávne."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Používateľské meno alebo heslo je nesprávne."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Používateľské meno alebo heslo nie je správne."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Používateľské meno alebo heslo nie je správne."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Nepodarilo sa bezpečne pripojiť k serveru."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Nepodarilo sa bezpečne pripojiť k serveru."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Vyžaduje sa certifikát klienta. Chcete sa pripojiť k serveru pomocou certifikátu klienta?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certifikát je neplatný alebo neprístupný."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Server odpovedal s chybou. Skontrolujte používateľské meno a heslo a skúste to znova."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Vyžaduje sa certifikát klienta. Pripojiť sa k serveru pomocou certifikátu klienta?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certifikát je neplatný alebo neprístupný."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Server odpovedal s chybou. Skontrolujte používateľské meno a heslo a skúste to znova."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Nepodarilo sa pripojiť k serveru."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Nepodarilo sa pripojiť k serveru."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Vyžaduje sa služba TLS, ale server ju nepodporuje."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"UPOZORNENIE: Ak deaktivujete oprávnenie aplikácie E-mail spravovať toto zariadenie, budú odstránené všetky účty aplikácie E-mail, ktoré toto oprávnenie vyžadujú. Spoločne s týmito účtami budú odstránené aj všetky ich e-maily, kontakty, udalosti kalendára a ďalšie údaje."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Bezpečnostná aktualizácia"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Účet <xliff:g id="ACCOUNT">%s</xliff:g> vyžaduje, aby ste zmenili nastavenia zabezpečenia."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Účet „<xliff:g id="ACCOUNT">%s</xliff:g>“ sa nedá synchronizovať z dôvodu požiadaviek zabezpečenia."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Účet „<xliff:g id="ACCOUNT">%s</xliff:g>“ vyžaduje aktualizáciu nastavení zabezpečenia."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Účet „<xliff:g id="ACCOUNT">%s</xliff:g>“ zmenil svoje nastavenia zabezpečenia. Od používateľa sa nevyžaduje žiadna akcia."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Vyžaduje sa bezp. aktualizácia"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Pravidlá zabezp. sa zmenili"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Prav. zabezp. sa nedajú splniť"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Účet <xliff:g id="ACCOUNT">%s</xliff:g> požaduje aktualizáciu nastavení zabezpečenia."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Vyžaduje sa bezpečnostná akt."</string> <string name="account_security_title" msgid="3511543138560418587">"Zabezpečenie zariadenia"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Server <xliff:g id="SERVER">%s</xliff:g> vyžaduje povolenie, aby mohol vzdialene ovládať niektoré funkcie zabezpečenia vášho zariadenia so systémom Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Upraviť podrobnosti"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Platnosť kódu PIN alebo hesla na uzamknutie obrazovky vypršala."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Heslo na uzamknutie vypršalo"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Heslo na uzamknutie obr. čoskoro vyprší"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Váš kód PIN alebo heslo na uzamknutie obrazovky musíte čoskoro zmeniť, ináč budú údaje účtu <xliff:g id="ACCOUNT">%s</xliff:g> vymazané. Chcete ho zmeniť teraz?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Čoskoro musíte zmeniť kód PIN alebo heslo na uzamknutie obrazovky, inak budú údaje účtu <xliff:g id="ACCOUNT">%s</xliff:g> vymazané. Chcete ho zmeniť teraz?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Heslo na uzamknutie obrazovky vypršalo"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"V zariadení prebieha vymazanie údajov účtu <xliff:g id="ACCOUNT">%s</xliff:g>. Môžete ich obnoviť zmenou kódu PIN alebo hesla na uzamknutie obrazovky. Chcete to zmeniť teraz?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"V zariadení prebieha vymazanie údajov účtu <xliff:g id="ACCOUNT">%s</xliff:g>. Môžete ich obnoviť zmenou kódu PIN alebo hesla na uzamknutie obrazovky. Chcete to zmeniť teraz?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Zahodiť neuložené zmeny?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Prihlásenie sa nepodarilo"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Používateľské meno alebo heslo pre účet <xliff:g id="ACCOUNT">%s</xliff:g> je nesprávne. Chcete ich aktualizovať?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Používateľské meno alebo heslo pre účet <xliff:g id="ACCOUNT">%s</xliff:g> je nesprávne. Chcete ich aktualizovať?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Predvolený účet"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"V predvolenom nastavení odosielať e-maily z tohto účtu"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Preberať všetky prílohy"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Automaticky preberať prílohy najnovších správ prostredníctvom siete Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-mailové upozornenia"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Frekvencia synchronizácie, oznámení atď."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Poslať upozornenie na príchod e-mailu"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Zobraziť upozornenie na príchod e-mailu v systémovom paneli"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Frekvencia kontroly doručenej pošty"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Nastavenia prichádzajúcej pošty"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Používateľské meno, heslo a ďalšie nastavenia servera (prich.)"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Nastavenia odchádzajúcej pošty"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Používateľské meno, heslo a ďalšie nastavenia servera (odchádz.)"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Vynútené pravidlá"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Žiadne"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nepodporované pravidlá"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Žiadne"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Synchronizovať"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Ak chcete tento účet synchronizovať, dotknite sa tu"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Názov účtu"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Vaše meno"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Podpis"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Rýchle odpovede"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Upraviť text, ktorý často vkladáte pri písaní e-mailu"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Upraviť text, ktorý často vkladáte pri písaní e-mailov."</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Text pripojiť k odosielaným správam"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Nastavenia upozornení"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Spotreba dát"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Pravidlá zabezpečenia"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Upraviť rýchlu odpoveď"</string> <string name="save_action" msgid="1988862706623227093">"Uložiť"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synchronizovať kontakty"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synchr. kontakty pre tento účet."</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synchronizovať kalendár"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synchr. udalosť kalendára pre účet"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synchr. kalendár"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synchr. kalendár pre tento účet"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synchroniz. e-mail"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synchr. e-mail pre tento účet"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrovať"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Čakanie na výsledky"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Niektorým serverom môže tento proces trvať dlho."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Priečinky"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Zakázať použitie fotoaparátu zariadenia"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Vyžadovať heslo zariadenia"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Obmedziť opak. použitie nedávnych hesiel"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Vyžadovať časovo obmedz. platnosť hesiel"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Uzamk. obrazovky nečinného zariadenia"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Obmedziť počet synchroniz. udalostí kalendára"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Obmedziť počet synchronizovaných e-mailov"</string> - <string name="quick_1" msgid="3426057697353380951">"Ďakujeme!"</string> - <string name="quick_2" msgid="4188036352885736617">"To znie dobre!"</string> - <string name="quick_3" msgid="8061819976353395585">"Prečítam si to neskôr a dám vám vedieť."</string> - <string name="quick_4" msgid="3988974084396883051">"Dohodnime si schôdzku a prediskutujme to."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Synchronizácia na pozadí je pre tento účet v roamingu zakázaná."</string> </resources> diff --git a/res/values-sk/uploader.xml b/res/values-sk/uploader.xml index a12915af4..ffbdfd627 100644 --- a/res/values-sk/uploader.xml +++ b/res/values-sk/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Skryť podrobnosti"</string> <string name="menu_settings" msgid="5088116127086866634">"Nastavenia"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Odovzdané: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Účet"</string> <string name="upload" msgid="2615541458361216022">"Odovzdať"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index cf7e4bbc9..79fe3a6ef 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Branje e-poštnih prilog"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Dovoli temu programu branje e-poštnih prilog."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Programu omogoča branje e-poštnih prilog."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Dostop do podatkov e-poštnega ponudnika"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Programu omogoča dostop do vaše e-poštne zbirke podatkov, vključno s prejetimi in poslanimi sporočili, uporabniškimi imeni in gesli."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Temu programu omogoča dostop do vaše e-poštne podatkovne zbirke, vključno s prejetimi in poslanimi sporočili, uporabniškimi imeni in gesli."</string> <string name="app_name" msgid="5815426892327290362">"E-pošta"</string> <string name="compose_title" msgid="427986915662706899">"Novo"</string> <string name="debug_title" msgid="5175710493691536719">"Odpravljanje napak"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Dokončano"</string> <string name="create_action" msgid="3062715563215392251">"Ustvari nov"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Izbriši"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Ni hitrih odzivov."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Ni hitrih odzivov"</string> <string name="discard_action" msgid="6532206074859505968">"Zavrzi"</string> <string name="save_draft_action" msgid="6413714270991417223">"Shrani osnutek"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Vstavi hiter odgovor"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> je napisal:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Vključite citirano besedilo"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Vključi besedilo"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Dodajte vsaj enega prejemnika."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Dodati morate vsaj enega prejemnika."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Nekateri e-poštni naslovi niso veljavni."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Datoteke ni mogoče pripeti, ker je prevelika."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Vstavi hiter odgovor"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Shranjeno"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Ustavi"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Priloga je shranjena kot <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Priloge ni mogoče shraniti."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Ena ali več prilog v posredovanem sporočilu bo pred pošiljanjem prenesena iz strežnika."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Priloge ni bilo mogoče shraniti."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Opomba: Ena ali več prilog v posredovanem sporočilu bo pred pošiljanjem prenesena iz strežnika."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Sporočilo"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Povabi"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Ene ali več prilog ni bilo mogoče posredovati."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Priloga ni bila posredovana"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Prijava v <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ni uspela."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Prijava v račun <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ni uspela."</string> <string name="login_failed_title" msgid="7624349996212476176">"Prijava ni uspela"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Za nastavitev računa za Exchange ActiveSync je potrebno le nekaj korakov."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-poštni naslov"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Geslo"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Privzeto pošiljaj e-pošto iz tega računa"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Privzeto pošiljaj e-pošto iz tega računa"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ročna nastavitev"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Vnesite veljaven e-poštni naslov in geslo."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Podvojeni račun"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Preverjanje nastavitev strežnika za dohodno pošto..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Preverjanje nastavitev strežnika za odhodno pošto..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Nastavitev računa"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Vaš račun je pripravljen in e-pošta je poslana."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Vaš račun je nastavljen, e-pošta je na poti."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Poimenujte račun (neobvezno)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Vaše ime (prikazano v odhodnih sporočilih)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"To polje ne sme biti prazno."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Strežnik SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Vrata"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Vrsta varnosti"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Zahtevaj prijavo"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Potrebna je prijava."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Uporabniško ime"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Geslo"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Nastavitev računa"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Vsakih 15 minut"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Vsakih 30 minut"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Vsako uro"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Privzeto pošiljaj e-pošto iz tega računa"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Obvesti me o novi e-pošti"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Sinhroniziraj stike iz tega računa"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Sinhroniziraj koledar iz tega računa"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Sinhroniziraj e-pošto iz tega računa"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Privzeto pošiljaj e-pošto iz tega računa"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Obvesti me, ko prispe e-pošta"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sinhroniziraj stike iz tega računa."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sinhroniziraj koledar iz tega računa"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sinhroniziraj e-pošto iz tega računa"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Samodejni prenos prilog, ko je na voljo povezava Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Ni mogoče končati"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dnevi za sinhronizacijo"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"En mesec"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Vse"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Uporabi privzeto v računu"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Uporabniško ime ali geslo ni pravilno."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Uporabniško ime ali geslo ni pravilno."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Nepravilno uporabniško ime ali geslo."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Nepravilno uporabniško ime ali geslo."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"S strežnikom se ni mogoče varno povezati."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"S strežnikom se ni bilo mogoče varno povezati."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Potrebno je potrdilo odjemalca. Ali se želite povezati s strežnikom s potrdilom odjemalca?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Potrdilo ni veljavno ali na voljo."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Strežnik je odgovoril z napako. Preverite uporabniško ime in geslo in poskusite znova."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Potrebujete potrdilo odjemalca. Želite povezavo s strežnikom vzpostaviti s potrdilom odjemalca?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Potrdilo je neveljavno ali nedostopno."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Strežnik je odgovoril z napako. Preverite uporabniško ime in geslo in poskusite znova."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Ni se mogoče povezati s strežnikom."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"S strežnikom se ni mogoče povezati."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Zahtevan je bil TLS, vendar ga strežnik ne podpira."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"Opozorilo: Če onemogočite pravico e-poštnega programa za upravljanja naprave, boste izbrisali vse e-poštne račune, ki jo potrebujejo, skupaj z e-pošto, stiki, dogodki koledarja in drugimi podatki."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Varnostna posodobitev"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Za račun <xliff:g id="ACCOUNT">%s</xliff:g> morate posodobiti varnostne nastavitve."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Računa »<xliff:g id="ACCOUNT">%s</xliff:g>« zaradi varnostnih zahtev ni mogoče sinhronizirati."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Varnostne nastavitve za račun »<xliff:g id="ACCOUNT">%s</xliff:g>« je potrebno posodobiti."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Varnostne nastavitve za račun »<xliff:g id="ACCOUNT">%s</xliff:g>« so bile spremenjene. Uporabniku ni treba storiti nič."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Potrebna je varn. posodobitev"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Varn. pravilnik je spremenjen"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Ne ustreza varn. pravilnikom"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Varnostne nastavitve računa »<xliff:g id="ACCOUNT">%s</xliff:g>« je treba posodobiti."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Potrebna je varnostna posodobitev"</string> <string name="account_security_title" msgid="3511543138560418587">"Varnost naprave"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Strežniku <xliff:g id="SERVER">%s</xliff:g> morate dovoliti, da na daljavo nadzira nekatere varnostne funkcije vaše naprave Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Urejanje podrobnosti"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN ali geslo za zaklepanje zaslona sta potekla."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Geslo za zaklepanje zaslona je poteklo"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Geslo za zaklepanje zaslona bo poteklo"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Čim prej spremenite PIN ali geslo za zaklepanje zaslona, sicer bodo podatki za <xliff:g id="ACCOUNT">%s</xliff:g> izbrisani. Ali ga želite spremeniti zdaj?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"PIN ali geslo za zaklepanje zaslona morate kmalu spremeniti, sicer bodo podatki za <xliff:g id="ACCOUNT">%s</xliff:g> izbrisani. Ga želite spremeniti zdaj?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Geslo za zaklepanje zaslona je poteklo"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Podatki za <xliff:g id="ACCOUNT">%s</xliff:g> bodo izbrisani iz naprave. Če jih želite obnoviti, spremenite PIN ali geslo za zaklepanje zaslona. Ali ga želite spremeniti zdaj?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Podatki za <xliff:g id="ACCOUNT">%s</xliff:g> se brišejo iz naprave. Lahko jih obnovite tako, da spremenite PIN ali geslo za zaklepanje zaslona. Ga želite spremeniti?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Želite zavreči neshranjene spremembe?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Prijava ni uspela"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Ime ali geslo za <xliff:g id="ACCOUNT">%s</xliff:g> ni pravilno. Ali ga želite posodobiti zdaj?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Uporabniško ime ali geslo za <xliff:g id="ACCOUNT">%s</xliff:g> je napačno. Ali ju želite posodobiti?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Privzeti račun"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Privzeto pošiljaj e-pošto iz tega računa"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Prenesi priloge"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Samodejni prenos prilog k nedavnim sporočilom s povezavo Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-poštna obvestila"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Pogostost sinhronizacije, obvestila itd."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Pošlji obvestilo o novi e-pošti"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Ko pride e-pošta, obvesti v sistemski vrstici"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Pogostost preverjanja mape »Prejeto«"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Nastavitve dohodne pošte"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Uporabniško ime, geslo in druge nastavitve dohodnega strežnika"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Nastavitve odhodne pošte"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Uporabniško ime, geslo in druge nastavitve odhodnega strežnika"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Pravilniki so uveljavljeni"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Brez"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Nepodprti pravilniki"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Brez"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Poskusi sinhronizacijo"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Za sinhronizacijo računa se dotaknite tukaj"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Ime računa"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Vaše ime"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Podpis"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Hitri odgovori"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Uredite besedilo, ki ga pogosto vstavite v e-pošto"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Uredite besedilo, ki ga pogosto vstavite, ko sestavljate e-pošto"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Pripni besedilo k poslanim sporočilom"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Nastavitve obvestil"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Uporaba podatkov"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Varnostni pravilniki"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Uredi hiter odgovor"</string> <string name="save_action" msgid="1988862706623227093">"Shrani"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sinhroniziranje stikov"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sinhroniziraj stike za ta račun"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sinhroniziraj koledar"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sinhr. dogodek iz kol. za ta račun"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sinhroniziraj koledar"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sinhroniziraj koledar za ta račun"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Sinhroniz. e-pošte"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sinhroniziraj e-pošto za ta račun"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibriranje"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Čakanje na rezultate"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Odziv nekaterih strežnikov je lahko počasen."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mape"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Ne dovoli uporabe kamere naprave"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Zahtevaj geslo naprave"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Omeji vnovično uporabo nedavnih gesel"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Zahtevaj, da gesla potečejo"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Zahtevaj, da nedej. napr. zaklene zaslon"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Omejitev števila sinhroniziranih koledarskih dogodkov"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Omejitev števila sinhroniziranih e-poštnih sporočil"</string> - <string name="quick_1" msgid="3426057697353380951">"Hvala!"</string> - <string name="quick_2" msgid="4188036352885736617">"Velja!"</string> - <string name="quick_3" msgid="8061819976353395585">"Trenutno nimam časa. Odgovorim pozneje."</string> - <string name="quick_4" msgid="3988974084396883051">"Skličimo sestanek in se pogovorimo."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Sinhronizacija v ozadju je za ta račun med gostovanjem onemogočena."</string> </resources> diff --git a/res/values-sl/uploader.xml b/res/values-sl/uploader.xml index 0e6e81344..d7b659175 100644 --- a/res/values-sl/uploader.xml +++ b/res/values-sl/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Skrij podrobnosti"</string> <string name="menu_settings" msgid="5088116127086866634">"Nastavitve"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Preneseno: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Račun"</string> <string name="upload" msgid="2615541458361216022">"Prenesi"</string> <string name="ok" msgid="2516349681897895312">"V redu"</string> diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index cc039face..6f62415d4 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Читање прилога из порука е-поште"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Омогућава апликацији да чита прилоге у порукама е-поште."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Омогућава овој апликацији да чита прилоге у порукама е-поште."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Приступ подацима о добављачу е-поште"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Омогућава да ова апликација приступа бази података е-поште, укључујући примљене поруке, послате поруке, корисничка имена и лозинке."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Омогућава овој апликацији да приступа бази података е-поште, укључујући примљене поруке, послате поруке, корисничка имена и лозинке."</string> <string name="app_name" msgid="5815426892327290362">"Пошаљи е-поштом"</string> <string name="compose_title" msgid="427986915662706899">"Нова порука"</string> <string name="debug_title" msgid="5175710493691536719">"Отклањање грешака"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Готово"</string> <string name="create_action" msgid="3062715563215392251">"Направи нови"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Избриши"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Нема брзих одговора."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Нема брзих одговора"</string> <string name="discard_action" msgid="6532206074859505968">"Одбаци"</string> <string name="save_draft_action" msgid="6413714270991417223">"Сачувај недов. пор."</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Уметни брзи одговор"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> је написао/ла:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Уврсти наведени текст"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Укључи текст"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Додајте најмање једног примаоца."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Потребно је да додате бар једног примаоца."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Поједине адресе е-поште су неважеће."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Датотека је превелика за прилог."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Уметање брзих одговора"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Сачувано"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Заустави"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Прилог је сачуван као <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Није могуће сачувати прилог."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Неки од прилога у прослеђеној поруци ће бити преузети пре слања."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Није могуће сачувати прилог."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Напомена: неки од прилога у прослеђеној поруци ће бити преузети пре слања."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Порука"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Позови"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Није могуће проследити један или више прилога."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Прилог није прослеђен"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Пријављивање на налог <xliff:g id="ACCOUNT_NAME">%s</xliff:g> није успело."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Пријављивање на налог <xliff:g id="ACCOUNT_NAME">%s</xliff:g> није успело."</string> <string name="login_failed_title" msgid="7624349996212476176">"Пријављивање није могуће"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Можете да подесите Exchange ActiveSync налог у свега неколико корака."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Адреса е-поште"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Лозинка"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Подразумевано шаљи е-пошту са овог налога"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Подразумевано шаљи поруке е-поште са овог налога."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ручно подешавање"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Унесите важећу адресу е-поште и лозинку."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Дуплирани налог"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"У току је провера подешавања сервера за долазну пошту…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"У току је провера подешавања одлазног сервера…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Подешавање налога"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Налог је подешен и е-пошта стиже!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Налог је подешен и е-пошта стиже!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Именујте овај налог (опционално)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Ваше име (приказано у одлазним порукама)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Ово поље не сме да буде празно."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP сервер"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Порт"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Тип безбедности"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Захтевај пријављивање"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Захтева пријављивање."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Корисничко име"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Лозинка"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Подешавање налога"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Сваких 15 минута"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Сваких 30 минута"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"На сваких сат времена"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Подразумевано шаљи е-пошту са овог налога"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Обавести ме о пријему е-поште"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Синхронизуј контакте са овог налога"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Синхронизуј календар са овог налога"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Синхронизуј е-пошту са овог налога"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Подразумевано шаљи поруке е-поште са овог налога."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Обавести ме о пријему поруке е-поште."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Синхронизуј контакте са овог налога."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Синхронизуј календар са овог налога."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Синхронизуј е-пошту са овог налога."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Аутоматски преузми прилоге када је успостављена веза са Wi-Fi мрежом"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Није могуће довршити"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Дани за синхронизацију"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Месец дана"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Све"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Користи подр. под. налога"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Корисничко име или лозинка су нетачни."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Корисничко име или лозинка нису тачни."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Корисничко име или лозинка нису тачни."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Корисничко име или лозинка нису тачни."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Безбедно повезивање са сервером није могуће."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Безбедно повезивање са сервером није могуће."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Сертификат клијента је обавезан. Да ли желите да се повежете са сервером са сертификатом клијента?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Сертификат је неважећи или недоступан."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Сервер је одговорио грешком. Проверите корисничко име и лозинку, а затим покушајте поново."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Потребан је сертификат клијента. Желите ли да се повежете са сервером помоћу сертификата клијента?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Сертификат је неважећи или недоступан."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Сервер је одговорио грешком. Проверите корисничко име и лозинку, а затим покушајте поново."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Повезивање са сервером није могуће."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Повезивање са сервером није могуће."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS је захтеван, али га сервер не подржава."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"УПОЗОРЕЊЕ: Деактивирањем овлашћења апликације Е-пошта за управљање уређајем избрисаћете све налоге е-поште који то·захтевају, заједно са адресом е-поште, контактима, догађајима календара и другим подацима."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Безбедносно ажурирање"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> захтева да ажурирате безбедносна подешавања."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Налог „<xliff:g id="ACCOUNT">%s</xliff:g>“ не може да се синхронизује због безбедносних захтева."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Потребно је ажурирати безбедносна подешавања за налог „<xliff:g id="ACCOUNT">%s</xliff:g>“."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Промењена су безбедносна подешавања налога „<xliff:g id="ACCOUNT">%s</xliff:g>“; није потребна ниједна радња корисника."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Потребно је безбедн. ажурирање"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Безбедн. смернице су промењене"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Безбед. смернице нису испуњене"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Потребно је ажурирати безбедносна подешавања за налог „<xliff:g id="ACCOUNT">%s</xliff:g>“."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Потребно је безбедносно ажур."</string> <string name="account_security_title" msgid="3511543138560418587">"Безбедност уређаја"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Сервер <xliff:g id="SERVER">%s</xliff:g> захтева да му омогућите удаљену контролу појединих безбедносних функција Android уређаја."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Измени детаље"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN или лозинка за закључавање екрана су истекли."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Лозинка за екран је истекла"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Лозинка за закључавање екрана истиче"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Потребно је да ускоро промените PIN или лозинку за закључавање екрана или ће подаци за налог <xliff:g id="ACCOUNT">%s</xliff:g> бити избрисани. Да ли желите да их сада промените?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Потребно је да ускоро промените PIN или лозинку за закључавање екрана или ће подаци за <xliff:g id="ACCOUNT">%s</xliff:g> бити избрисани. Желите ли да их промените сада?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Лозинка за закључавање екрана је истекла"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Подаци за налог <xliff:g id="ACCOUNT">%s</xliff:g> се бришу са уређаја. Можете да их вратите ако промените PIN или лозинку за закључавање екрана. Желите ли да их промените сада?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Подаци за <xliff:g id="ACCOUNT">%s</xliff:g> се бришу са уређаја. Можете да их вратите уколико промените PIN или лозинку за закључавање екрана. Желите ли да их промените сада?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Желите ли да одбаците несачуване промене?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Пријављивање није могуће"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Корисничко име или лозинка за налог <xliff:g id="ACCOUNT">%s</xliff:g> нису тачни. Да ли желите да их ажурирате сада?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Корисничко име или лозинка за <xliff:g id="ACCOUNT">%s</xliff:g> су нетачни. Желите ли да их ажурирате сада?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Подразумевани налог"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Подразумевано шаљи поруке е-поште са овог налога"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Преузми прилоге"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Аутоматско преузимање прилога за недавне поруке преко Wi-Fi-ја"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Обавештења е-поштом"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Синхронизација учесталости, обавештења итд."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Пошаљи обавештење када стигне е-пошта"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Обавештавање на системској траци када стигне порука е-поште"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Учесталост провере пријемног сандучета"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Подешавања долазећих"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Корисничко име, лозинка и друга подешавања серв. долазне поште"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Подешавања одлазних"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Корисничко име, лозинка и друга подешавања серв. одлазне поште"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Примењене смернице"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Ниједно"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Неподржане смернице"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Ниједно"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Покушај да синхронизујеш"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Додирните овде да бисте синхронизовали налог"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Име налога"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Ваше име"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Потпис"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Брзи одговори"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Измените текст који често умећете при писању е-поште"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Измените текст који често умећете при писању порука е-поште"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Додајте текст порукама које шаљете"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Подешавања обавештења"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Коришћење података"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Безбедносне смернице"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Измена брзог одговора"</string> <string name="save_action" msgid="1988862706623227093">"Сачувај"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Синхронизација контаката"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Синхронизуј контакте за овај налог"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Синхронизација календара"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Синхр. дог. календара за овај налог"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Синхронизуј календар"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Синхронизуј календар за овај налог"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Синхронизуј е-пошту"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Синхронизуј е-пошту за овај налог"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Вибрација"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Чека се на резултате"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Неким серверима је потребно доста времена."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Директоријуми"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Онемогући коришћење камере уређаја"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Захтевај лозинку за уређај"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Ограничи пон. коришћење недавних лозинки"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Захтевај да лозинке истекну"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Захтевај неакт. уређај за закљ. екрана"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Ограничи број синхронизованих догађаја календара"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Ограничи број синхронизованих порука е-поште"</string> - <string name="quick_1" msgid="3426057697353380951">"Хвала!"</string> - <string name="quick_2" msgid="4188036352885736617">"Добра идеја!"</string> - <string name="quick_3" msgid="8061819976353395585">"Прочитаћу ово касније и јавити вам."</string> - <string name="quick_4" msgid="3988974084396883051">"Хајде да организујемо састанак како бисмо о овоме разговарали."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Синхронизација у позадини за овај налог је онемогућена у ромингу."</string> </resources> diff --git a/res/values-sr/uploader.xml b/res/values-sr/uploader.xml index 752d7d033..43f162d7a 100644 --- a/res/values-sr/uploader.xml +++ b/res/values-sr/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Сакриј детаље"</string> <string name="menu_settings" msgid="5088116127086866634">"Подешавања"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Отпремљено %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Налог"</string> <string name="upload" msgid="2615541458361216022">"Отпреми"</string> <string name="ok" msgid="2516349681897895312">"Потврди"</string> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index d01e2a8fa..0df8f2b0b 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Läs bilagor i e-postmeddelanden"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Tillåter att appen läser bilagor i e-postmeddelanden."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Tillåter att appen läser bilagor i e-postmeddelanden."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Använd data från e-postleverantören"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Tillåter att appen kommer åt e-postdatabasen med bland annat mottagna meddelanden, skickade meddelanden, användarnamn och lösenord."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Tillåter att appen kommer åt e-postdatabasen med bland annat mottagna meddelanden, skickade meddelanden, användarnamn och lösenord."</string> <string name="app_name" msgid="5815426892327290362">"E-post"</string> <string name="compose_title" msgid="427986915662706899">"Skriv"</string> <string name="debug_title" msgid="5175710493691536719">"Felsökning"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Klar"</string> <string name="create_action" msgid="3062715563215392251">"Skapa nytt"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Ta bort"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Inga snabba svar."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Inga snabba svar"</string> <string name="discard_action" msgid="6532206074859505968">"Släng"</string> <string name="save_draft_action" msgid="6413714270991417223">"Spara utkast"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Infoga snabbsvar"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> skrev:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Inkludera citerad text"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Inkludera text"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Lägg till minst en mottagare."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Du måste lägga till minst en mottagare."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Några av e-postadresserna är ogiltiga."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Filen är för stor för att bifogas."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Infoga snabbsvar"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Sparad"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Stoppa"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Bilagan har sparats som <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Kunde inte spara bilagan."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"En eller flera bilagor i det vidarebefordrade meddelandet hämtas innan de skickas."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Det gick inte att spara bilagan."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Obs! En eller flera bilagor i det vidarebefordrade meddelandet hämtas innan de skickas."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Meddelande"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Bjud in"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Det gick inte att vidarebefordra en eller flera bilagor."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Bilagan vidarebefordrades inte"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Det gick inte att logga in <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Inloggning på <xliff:g id="ACCOUNT_NAME">%s</xliff:g> misslyckades."</string> <string name="login_failed_title" msgid="7624349996212476176">"Det gick inte att logga in."</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Du kan konfigurera ett Exchange ActiveSync-konto med några få steg."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-postadress"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Lösenord"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Skicka e-post från det här kontot som standard"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Skicka e-post från det här kontot som standard"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuell inställning"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Ange en giltig e-postadress och lösenord."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Dubblettkonto"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Kontrollerar inkommande serverinställningar…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Kontrollerar utgående serverinställningar…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Kontoinställningar"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Ditt konto är färdigt och snart kan du skicka och ta emot e-postmeddelanden."</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ditt konto är färdigt och snart kan du skicka och ta emot e-postmeddelanden."</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Ge kontot ett namn (valfritt)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Ditt namn (visas för utgående meddelanden)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Fältet får inte vara tomt."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP-server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Säkerhetstyp"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Kräv inloggning"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Kräv inloggning"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Användarnamn"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Lösenord"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Kontoinställningar"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Var 15:e minut"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Var 30:e minut"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Varje timme"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Skicka e-post från det här kontot som standard"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Meddela mig när jag får e-post"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Synkronisera kontakter från det här kontot"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Synkronisera kalendern från det här kontot"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Synkronisera e-post från det här kontot"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Skicka e-post från det här kontot som standard"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Meddela mig när jag får e-post"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Synkronisera kontakter från det här kontot."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Synkronisera kalendrar från det här kontot."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Synkronisera e-post från det här kontot."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Hämta bilagor automatiskt när enheten är ansluten till Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Det gick inte att avsluta"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Dagar för synkronisering"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"En månad"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Alla"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Använd standardinställning"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Användarnamnet eller lösenordet är felaktigt."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Felaktigt användarnamn eller lösenord."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Fel användarnamn eller lösenord."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Fel användarnamn eller lösenord."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Det går inte att upprätta en säker anslutning till servern."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Det går inte att upprätta en säker anslutning till servern."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Ett klientcertifikat måste anges. Vill du ansluta till servern med ett klientcertifikat?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Certifikatet är ogiltigt eller otillgängligt."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Servern svarade med ett fel. Kontrollera ditt användarnamn och lösenord och försök igen."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Klientcertifikat krävs. Vill du ansluta till servern med klientcertifikatet?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Certifikatet är ogiltigt eller otillgängligt."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Servern svarade med ett fel. Kontrollera ditt användarnamn och lösenord och försök igen."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Det går inte att ansluta till servern."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Det går inte att ansluta till servern."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS krävs men stöds inte av servern."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"VARNING! Om du inaktiverar e-postappens behörighet att administrera enheten raderas alla e-postkonton som behöver behörigheten. Även e-post, kontakter, kalenderhändelser och andra data raderas."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Säkerhetsuppdatering"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Enligt <xliff:g id="ACCOUNT">%s</xliff:g> måste du uppdatera säkerhetsinställningarna."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Det går inte att synkronisera kontot <xliff:g id="ACCOUNT">%s</xliff:g> på grund av säkerhetskrav."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Säkerhetsinställningarna måste uppdateras för kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Säkerhetsinställningarna ändrades för kontot <xliff:g id="ACCOUNT">%s</xliff:g>. Inga åtgärder krävs från användaren."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Säkerhetsuppdatering krävs"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Säkerhetspolicyer har ändrats"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Säkerhetspolicy kan ej följas"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Kontot \"<xliff:g id="ACCOUNT">%s</xliff:g>\" kräver att säkerhetsinställningarna uppdateras."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Säkerhetsuppdatering krävs"</string> <string name="account_security_title" msgid="3511543138560418587">"Säkerhet för enhet"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Servern <xliff:g id="SERVER">%s</xliff:g> måste kunna fjärrkontrollera vissa säkerhetsfunktioner i din Android-enhet."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Redigera information"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN-koden eller lösenordet till skärmlåset har gått ut."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Skärmlösenordet har gått ut"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Skärmlåslösenordet går ut inom kort"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Du måste ändra PIN-kod eller lösenord för skärmlåset snart, annars raderas data för kontot <xliff:g id="ACCOUNT">%s</xliff:g>. Vill du ändra nu?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Om du inte ändrar PIN-kod eller lösenord till skärmlåset inom kort raderas alla data för <xliff:g id="ACCOUNT">%s</xliff:g>. Vill du göra det nu?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Skärmlåslösenordet har gått ut"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Alla data för <xliff:g id="ACCOUNT">%s</xliff:g> tas bort från enheten. Du kan återställa dem genom att ändra PIN-koden eller lösenordet för skärmlåset. Vill du göra det nu?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Alla data för <xliff:g id="ACCOUNT">%s</xliff:g> tas bort från enheten. Du kan återställa dem genom att ändra PIN-koden eller lösenordet till skärmlåset. Vill du göra det nu?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Vill du ignorera ändringar som inte har sparats?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Det gick inte att logga in."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Användarnamnet eller lösenordet för <xliff:g id="ACCOUNT">%s</xliff:g> är felaktigt. Vill du uppdatera dem nu?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Du har angett ett felaktigt användarnamn eller lösenord for <xliff:g id="ACCOUNT">%s</xliff:g>. Vill du uppdatera dem nu?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Standardkonto"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Skicka e-post från det här kontot som standard"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Hämta bilagor"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Hämta automatiskt bilagor för de senaste meddelandena via Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-postaviseringar"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Synkroniseringsfrekvens, aviseringar osv."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Skicka meddelande när du får e-post"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Avisera i systemfältet vid e-postmeddelande"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Intervall för e-postkontroll"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Inkommande inställningar"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Användarnamn, lösenord och andra inkommande serverinställningar"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Utgående inställningar"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Användarnamn, lösenord och andra utgående serverinställningar"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Verkställda policyer"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Inga"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Policyer som inte stöds"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Inga"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Synkroniseringsförsök"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Tryck här för att synkronisera kontot"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Kontonamn"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Ditt namn"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Signatur"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Snabbsvar"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Redigera text som du ofta infogar när du skriver e-post"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Redigera text som du ofta infogar när du skriver e-post"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Lägg till text i meddelanden som du skickar"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Meddelandeinställningar"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Dataanvändning"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Säkerhetspolicyer"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Redigera snabbsvar"</string> <string name="save_action" msgid="1988862706623227093">"Spara"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Synkronisera kontakter"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Synkronisera kontakter för det här kontot"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Synkronisera kalender"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Synka kalenderhändelse för kontot"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Synkronisera kalender"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Synkronisera kalendern för det här kontot"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Synkronisera e-post"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Synkronisera e-post för det här kontot"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Vibrera"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Väntar på resultat"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Vissa servrar kan ta lång tid."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mappar"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Tillåt inte användning av kameran"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Kräv lösenord för enheten"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Begränsa återanvändning av lösenord"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Kräv att lösenord upphör att gälla"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Kräv låst skärm på inaktiva enheter"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Begränsa antalet kalenderhändelser som synkas"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Begränsa antalet e-postmeddelanden som synkas"</string> - <string name="quick_1" msgid="3426057697353380951">"Tack!"</string> - <string name="quick_2" msgid="4188036352885736617">"Låter bra!"</string> - <string name="quick_3" msgid="8061819976353395585">"Jag läser detta senare och återkommer till dig."</string> - <string name="quick_4" msgid="3988974084396883051">"Vi kan diskutera detta på ett möte."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Bakgrundssynkronisering för det här kontot har inaktiverats vid roaming."</string> </resources> diff --git a/res/values-sv/uploader.xml b/res/values-sv/uploader.xml index f3b3b1ee7..af8cfcb6f 100644 --- a/res/values-sv/uploader.xml +++ b/res/values-sv/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Dölj detaljer"</string> <string name="menu_settings" msgid="5088116127086866634">"Inställningar"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Överförde %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Konto"</string> <string name="upload" msgid="2615541458361216022">"Överför"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 3ea6829e4..d222eac17 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Soma viambatisho vya barua pepe"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Inaruhusu programu kusoma viambatisho vya barua pepe yako."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Inaruhusu programu hii kusoma viambatisho vyako vya barua pepe."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Fikia data ya mtoa huduma wa barua pepe"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Inaruhusu programu hii kufikia hifadhidata yako ya barua pepe, ikiwa ni pamoja na jumbe zilizopokewa, jumbe zilizotumwa, majina ya mtumiaji na manenosiri."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Huruhusu programu hii kufikia hifadhidata yako ya barua pepe, pamoja na ujumbe uliopokewa, ujumbe uliotumwa, majina ya mtumiaji na nenosiri."</string> <string name="app_name" msgid="5815426892327290362">"Barua pepe"</string> <string name="compose_title" msgid="427986915662706899">"Tunga"</string> <string name="debug_title" msgid="5175710493691536719">"Tatua"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Kwisha"</string> <string name="create_action" msgid="3062715563215392251">"Unda mpya"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Futa"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Hakuna majibu ya haraka."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Hakuna majibu ya haraka"</string> <string name="discard_action" msgid="6532206074859505968">"Tupa"</string> <string name="save_draft_action" msgid="6413714270991417223">"Hifadhi rasimu"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Ingiza jibu la haraka"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> aliandika:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Jumuisha maandishi yaliyonukuliwa"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Jumuisha maandishi"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Ongeza angalau mpokeaji mmoja."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Ni lazima uongeze angalau mpokeaji mmoja"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Anwani zingine za barua pepe ni batili."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Faili ni kubwa sana kuambatishwa."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Ingiza majibu ya haraka"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Imehifadhiwa"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Simamisha"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Kiambatisho kimehifadhiwa kama <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Haikuweza kuhifadhi kiambatisho."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Kiambatisho kimoja au zaidi katika ujumbe wako uliosambazwa kitapakuliwa kabla ya kutumwa."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Haikuweza kuhifadhi kiambatisho."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Zingatia: Moja au zaidi ya viambatisho katika ujumbe wako uliosambazwa vitapakuliwa kabla ya kutumwa."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Ujumbe"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Alika"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Haikuweza kusambaza kiambatisho kimoja au zaidi."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Kiambatishho hakijasambazwa"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Kuingia <xliff:g id="ACCOUNT_NAME">%s</xliff:g> hakujafaulu."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> ilishindwa kuingia."</string> <string name="login_failed_title" msgid="7624349996212476176">"Haingeweza kuingia"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"B <xliff:g id="SIZE_IN_BYTES">%d</xliff:g>"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Unaweza kusanidi akaunti ya Exchange ActiveSync kwa hatua chache tu."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Anwani ya barua pepe"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Nenosiri"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Tuma barua pepe kutoka kwa akaunti hii kama chaguo-msingi"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Tuma barua pepe kutoka kwa akaunti hii kama chaguo-msingi"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Usanidi wa mkono"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Tafadhali andika anwani na nenosiri halali ya barua pepe."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Akaunti Rudufu"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Inakagua mipangilio ya seva inayoingia..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Inakagua mipangilio ya seva inayotoka nje..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Usanidi wa akaunti"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Akaunti yako imesanidiwa, na barua pepe iko njiani!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Akaunti yako imesanidiwa, na barua pepe iko njiani!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Ipe akaunti hii jina (ya hiari)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Jina lako (linaloonyeshwa kwenye ujumbe unaotoka)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Uga hii haiwezi kuwa tupu."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Seva ya SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Mlango"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Aina ya usalama"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Inahitaji kuingia"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Inahitaji uingie"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Jina la mtumiaji"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Nenosiri"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Usanidi wa akaunti"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Kila dakika 15"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Kila dakika 30"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Kila saa"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Tuma barua pepe kutoka kwa akaunti hii kama chaguo-msingi"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Niarifu wakati barua pepe inapowasili"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Landanisha anwani kutoka kwa akaunti hii"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Landanisha kalenda kutoka kwa akaunti hii"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Landanisha barua pepe kutoka kwa akaunti hii"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Tuma barua pepe kutoka kwa akaunti hii kama chaguo-msingi"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Niarifu wakati barua pepe inpoingia"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Sawazisha anwani kutoka kwa akaunti hii."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Sawazisha kalenda kutoka kwa akaunti hii."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Sawazisha barua pepe kutoka kwa akaunti hii."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Pakua viambatisho kiotomatiki wakati umeunganishwa kwenye mtandao-hewa"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Imeshindwa kumaliza"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Siku hadi Usawazishaji"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Mwezi mmoja"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Zote"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Tumia akaunti chaguo-msingi"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Jina la mtumiaji au nenosiri sio sahihi."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Jina la mtumiaji au nenosiri si sahihi."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Jina la mtumiaji na nenosiri sio sahihi."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Jina la mtumiaji au nenosiri sio sahihi."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Haiwezi kuunganisha kwa seva kwa usalama."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Haiwezi kuunganisha kwa seva kwa usalama."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Cheti cha mteja kinahitajika. Je, unataka kuunganisha kwenye seva na cheti cha mteja?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Cheti ni batili au hakiwezi kufikiwa."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Seva ilijibu na hitilafu. Kagua jina lako la mtumiaji na nenosiri, kisha ujaribu tena."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Cheti cha mteja kinahitajika. Unganisha kwa seva na cheti cha mteja?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Cheti ni batili au hakiwezi kufikiwa."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Seva iliitikia na hitilafu; Kagua jina lako la mtumiaji na nenosiri na ujaribu tena."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Haiwezi kuunganisha kwa seva."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Haiwezi kuunganisha kwa seva."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS inahitajika lakini haihimiliwi na seva."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ILANI: Kuamilishua kibali cha programu ya Barua pepe ili kudhibiti kifaa chako itafuta akaunti zote za Barua pepe ambazo zinakihitaji, pamoja na barua pepe zake, anwani, matukio ya kalenda, na data nyingine."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Usasisho wa usalama"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> inahitaji usasihe mipangilio yako ya usallama."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Akaunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" haiwezi kulandanishwa kwa sababu ya mahitaji ya usalama."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Akaunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" inahitaji kusasisha mipangilio ya usalama."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Akaunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ilibadilisha mipangilio yakeya usalama; hakunahatuaya usalama inayohitajika."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Uboreshaji wa usalama unahitajika"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Sera za kiusalama zimebadilishwa"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Sera za kiusalama haziwezi kufikiwa"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Akaunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" inahitaji kusasisha mipangilio ya usalama."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Uboreshaji wa usalama unahitajika"</string> <string name="account_security_title" msgid="3511543138560418587">"Usalama wa kifaa"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Seva <xliff:g id="SERVER">%s</xliff:g>inahitaji uiruhusu kudhibiti kwa umbali baadhi ya vipengele vya usalama vya simu yako."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Hariri maelezo"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN au nenosiri lako la kufunga skrini yako limekwisha muda."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Nenosiri la kufunga skrini limekwisha muda"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Nenosiri la kufunga skrini linaisha muda"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Unahitaji kubadilisha PIN au nenosiri la kifungio skrini chako hivi karibuni, au data ya <xliff:g id="ACCOUNT">%s</xliff:g> itafutwa. Je, unataka kuibadilisha sasa?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Lazima ubadilishe PIN yako ya skrini au nenosiri hivi karibuni, ama data ya <xliff:g id="ACCOUNT">%s</xliff:g> itafutwa. Ibadilishe saa hii?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Nenosiri la kufunga skrini limekwisha muda"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Data ya <xliff:g id="ACCOUNT">%s</xliff:g> inafutwa kutoka kwenye kifaa chako. Unaweza kuirejesha kwa kubadilisha PIN au nenosiri lako la kifungio skrini. Unataka kuibadilisha sasa?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Data ya <xliff:g id="ACCOUNT">%s</xliff:g> inafutwa kutoka kwenye kifaa chako. Unaweza kuirejesha kwa kubadilisha PIN au nenosiri lako la kufunga skrini. Ibadilishe sasa?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Tupa mabadiliko yasiyohifadhiwa?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Haingeweza kuinga ndani"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Jina la mtumiaji au nenosiri la <xliff:g id="ACCOUNT">%s</xliff:g> sio sahihi. Je, unataka kusasisha sasa hivi?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Jina la mtumiaji au nenosiri la <xliff:g id="ACCOUNT">%s</xliff:g> si sahihi. Yasasishe saa hii?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Akaunti chaguo-msingi"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Tuma barua pepe kutoka kwa akaunti hii kwa chaguo-msingi"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Pakua viambatisho"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Pakua-otomatiki viambatisho kwa ujumbe wa hivi karibuni kupitia Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Arifa za barua pepe"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Mara za kusawazisha, kutuma arifa, n.k."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Tuma arifa wakati barua pepe inafika"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Arifu katika upau wa hali barua pepe inapofika"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Mazoea ya kukagua kikasha"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Mipangilio inayoingia"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Jina la mtumiaji, nenosiri, na mipangilio mingine ya seva inayoingia"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Mipangilio ya kutoka"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Jina la mmtumiaji, neneosiri na mipangilio mingine ya seva ya kutoka."</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Sera zimetekelezwa"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Hamna"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Sera zisizokubaliwa"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Hamna"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Jaribu usawazishi"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Gusa hapa ili kulandanisha akaunti hii"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Jina la akaunti"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Jina lako"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Sahihi"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Majibu ya haraka"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Hariri maandishi unayoyaingiza mara kwa mara unapoandika barua pepe"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Hariri maandishi unayoyaingiza mara kwa mara unapoandika barua pepe"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Ambatisha maandishi kwa ujumbe unaotuma"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Mipangilio ya Arifa"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Matumizi ya data"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Sera za kiusalama"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Hariri majibu ya haraka"</string> <string name="save_action" msgid="1988862706623227093">"Hifadhi"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Sawazisha anwani"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sawazisha anwani za akaunti hii"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Sawazisha kalenda"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Landanisha tukio la kalenda la akaunti hii"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sawazisha Kalenda"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Sawazisha kalenda ya akaunti hii"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Landanisha barua pepe"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Sawazisha barua pepe za akaunti hii"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Tetema"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Inasubiri matokeo"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Seva zingine zinaweza kuchukua muda mrefu."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Folda"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Usiruhusu matumizi ya kamera ya kifaa"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Zinahitaji nenosiri la kifaa"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Zuia matumizi mapya ya nywila ya hivi karibuni"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Inahitaji nywila kumalizika"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Inahitaji kifaa bwete ili kufunga skrini yake"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Wekea kikomo idadi ya matukio ya kalenda yanayolandanishwa"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Wekea kikomo idadi ya barua pepe zinazolandanishwa"</string> - <string name="quick_1" msgid="3426057697353380951">"Asante!"</string> - <string name="quick_2" msgid="4188036352885736617">"Iko sawa kwangu!"</string> - <string name="quick_3" msgid="8061819976353395585">"Nitasoma hii baadaye na nitawasiliana na wewe."</string> - <string name="quick_4" msgid="3988974084396883051">"Tupange mkutano wa kujadili hii."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Ulandanishi wa mandharinyuma ya akaunti hii imelemazwa wakati wa kuzurura."</string> </resources> diff --git a/res/values-sw/uploader.xml b/res/values-sw/uploader.xml index 42789ca3e..9544b3e40 100644 --- a/res/values-sw/uploader.xml +++ b/res/values-sw/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ficha Maelezo"</string> <string name="menu_settings" msgid="5088116127086866634">"Mipangilio"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Imepakia %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"Kishika nafasi<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Akaunti"</string> <string name="upload" msgid="2615541458361216022">"Pakia"</string> <string name="ok" msgid="2516349681897895312">"Sawa"</string> diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml index d690add63..21230f6ae 100644 --- a/res/values-sw600dp/styles.xml +++ b/res/values-sw600dp/styles.xml @@ -132,6 +132,18 @@ <item name="android:layout_alignParentRight">true</item> </style> + <style name="action_bar_spinner_primary_text"> + <item name="android:includeFontPadding">false</item> + <item name="android:textSize">18sp</item> + <item name="android:textColor">@color/text_primary_color</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">end</item> + </style> + + <style name="action_bar_spinner_secondary_text"> + <item name="android:visibility">gone</item> + </style> + <style name="Attachment.Button" parent="@android:style/Widget.Holo.Button.Borderless"> <item name="android:layout_width">0dip</item> <item name="android:layout_weight">1</item> diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 3c643c58c..a7ccc7cd2 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"อ่านไฟล์แนบของอีเมล"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"อนุญาตให้แอปพลิเคชันนี้อ่านไฟล์แนบในอีเมลของคุณ"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"อนุญาตให้แอปพลิเคชันนี้อ่านไฟล์แนบในอีเมลของคุณ"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"เข้าถึงข้อมูลผู้ให้บริการอีเมล"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"อนุญาตให้แอปพลิเคชันนี้เข้าถึงฐานข้อมูลอีเมลของคุณ ซึ่งรวมถึงข้อความที่ได้รับ ข้อความที่ส่ง ชื่อผู้ใช้ และรหัสผ่าน"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"อนุญาตให้แอปพลิเคชันนี้เข้าถึงฐานข้อมูลอีเมลของคุณ ซึ่งรวมถึงข้อความที่ได้รับ ข้อความที่ส่ง ชื่อผู้ใช้ และรหัสผ่าน"</string> <string name="app_name" msgid="5815426892327290362">"อีเมล"</string> <string name="compose_title" msgid="427986915662706899">"เขียน"</string> <string name="debug_title" msgid="5175710493691536719">"ดีบัก"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"เสร็จสิ้น"</string> <string name="create_action" msgid="3062715563215392251">"สร้างใหม่"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"ลบ"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"ไม่มีคำตอบด่วน"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"ไม่มีคำตอบด่วน"</string> <string name="discard_action" msgid="6532206074859505968">"ยกเลิก"</string> <string name="save_draft_action" msgid="6413714270991417223">"บันทึกร่างจดหมาย"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"ใส่คำตอบด่วน"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> เขียนว่า:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"รวมข้อความที่ยกมา"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"รวมข้อความ"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"เพิ่มผู้รับอย่างน้อยหนึ่งราย"</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"คุณต้องเพิ่มผู้รับอย่างน้อยหนึ่งราย"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"ที่อยู่อีเมลบางที่อยู่ไม่ถูกต้อง"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"ไฟล์ใหญ่เกินไปที่จะแนบ"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"ใส่คำตอบด่วน"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"บันทึกแล้ว"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"หยุด"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"เอกสารแนบถูกบันทึกเป็น <xliff:g id="FILENAME">%s</xliff:g>"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"ไม่สามารถบันทึกไฟล์แนบ"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"หมายเหตุ: ไฟล์แนบอย่างน้อยหนึ่งรายการในข้อความที่ส่งต่อของคุณจะมีการดาวน์โหลดก่อนส่ง"</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"ไม่สามารถบันทึกไฟล์แนบ"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"หมายเหตุ: เอกสารแนบอย่างน้อยหนึ่งรายการในข้อความที่ส่งต่อของคุณจะมีการดาวน์โหลดก่อนส่ง"</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"ข้อความ"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"เชิญ"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"ไม่สามารถส่งต่อไฟล์แนบอย่างน้อยหนึ่งรายการ"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"ไม่ได้ส่งต่อเอกสารแนบ"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"ลงชื่อเข้าใช้ <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ไม่สำเร็จ"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"การลงชื่อเข้าใช้ <xliff:g id="ACCOUNT_NAME">%s</xliff:g> ล้มเหลว"</string> <string name="login_failed_title" msgid="7624349996212476176">"ไม่สามารถลงชื่อเข้าใช้"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>ไบต์"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"คุณสามารถตั้งค่าบัญชี Exchange ActiveSync ได้ในไม่กี่ขั้นตอน"</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"ที่อยู่อีเมล"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"รหัสผ่าน"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"ส่งอีเมลจากบัญชีนี้เป็นค่าเริ่มต้น"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"ส่งอีเมลจากบัญชีนี้เป็นค่าเริ่มต้น"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"ตั้งค่าด้วยตนเอง"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"พิมพ์ที่อยู่อีเมลและรหัสผ่านที่ถูกต้อง"</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"บัญชีซ้ำ"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"กำลังตรวจสอบการตั้งค่าเซิร์ฟเวอร์ขาเข้า..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"กำลังตรวจสอบการตั้งค่าเซิร์ฟเวอร์ขาออก..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"การตั้งค่าบัญชี"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"ตั้งค่าบัญชีของคุณแล้ว และอีเมลกำลังมาถึง!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"ตั้งค่าบัญชีของคุณแล้ว และอีเมลกำลังมาถึง"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"ตั้งชื่อให้กับบัญชีนี้ (เป็นตัวเลือก)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"ชื่อของคุณ (แสดงในข้อความขาออก)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"ต้องกรอกข้อมูลในฟิลด์นี้"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"เซิร์ฟเวอร์ SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"พอร์ต"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"ประเภทการรักษาความปลอดภัย"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"จำเป็นต้องลงชื่อเข้าใช้"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"ต้องลงชื่อเข้าใช้"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"ชื่อผู้ใช้"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"รหัสผ่าน"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"การตั้งค่าบัญชี"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"ทุก 15 นาที"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"ทุก 30 นาที"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"ทุกชั่วโมง"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"ส่งอีเมลจากบัญชีนี้เป็นค่าเริ่มต้น"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"แจ้งให้ฉันทราบเมื่อมีอีเมลเข้า"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"ซิงค์รายชื่อจากบัญชีนี้"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"ซิงค์ปฏิทินจากบัญชีนี้"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"ซิงค์อีเมลจากบัญชีนี้"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"ส่งอีเมลจากบัญชีนี้เป็นค่าเริ่มต้น"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"แจ้งให้ฉันทราบเมื่อมีอีเมลเข้า"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"ซิงค์รายชื่อจากบัญชีนี้"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"ซิงค์ปฏิทินจากบัญชีนี้"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"ซิงค์อีเมลจากบัญชีนี้"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"ดาวน์โหลดไฟล์แนบโดยอัตโนมัติเมื่อเชื่อมต่อ Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"ไม่สามารถดำเนินการให้เสร็จสิ้น"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"วันที่จะซิงค์"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"1 เดือน"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"ทั้งหมด"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"ใช้ค่าเริ่มต้นของบัญชี"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้อย่างปลอดภัย"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้อย่างปลอดภัย"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"ต้องมีใบรับรองไคลเอ็นต์ คุณต้องการเชื่อมต่อกับเซิร์ฟเวอร์ด้วยใบรับรองไคลเอ็นต์หรือไม่"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"ใบรับรองไม่ถูกต้องหรือไม่สามารถเข้าถึงได้"</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"เซิร์ฟเวอร์ตอบสนองโดยมีข้อผิดพลาด โปรดตรวจสอบชื่อผู้ใช้และรหัสผ่านของคุณ แล้วลองอีกครั้ง"</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"ต้องใช้ใบรับรองไคลเอ็นต์ ต้องการเชื่อมต่อกับเซิร์ฟเวอร์ที่มีใบรับรองไคลเอ็นต์หรือไม่"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"ใบรับรองไม่ถูกต้องหรือไม่สามารถเข้าถึงได้"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"เซิร์ฟเวอร์ตอบสนองโดยมีข้อผิดพลาด โปรดตรวจสอบชื่อผู้ใช้และรหัสผ่านของคุณ แล้วลองอีกครั้ง"</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์"</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"ต้องใช้ TLS แต่เซิร์ฟเวอร์ไม่สนับสนุน"</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"คำเตือน: การปิดใช้งานสิทธิ์ของแอปพลิเคชันอีเมลในการดูแลอุปกรณ์ของคุณจะเป็นการลบบัญชีอีเมลทั้งหมดที่จำเป็นต้องใช้สิทธิ์นั้น พร้อมทั้งอีเมล สมุดโทรศัพท์ กิจกรรมในปฏิทิน และข้อมูลอื่นๆ"</string> <string name="account_security_dialog_title" msgid="430041952584831904">"การอัปเดตความปลอดภัย"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> กำหนดให้คุณต้องอัปเดตการตั้งค่าความปลอดภัย"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"ไม่สามารถซิงค์บัญชี \"<xliff:g id="ACCOUNT">%s</xliff:g>\" เนื่องจากข้อกำหนดด้านความปลอดภัย"</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"บัญชี \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ต้องมีการอัปเดตการตั้งค่าความปลอดภัย"</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"เปลี่ยนการตั้งค่าความปลอดภัยของบัญชี \"<xliff:g id="ACCOUNT">%s</xliff:g>\" แล้ว ผู้ใช้ไม่จำเป็นต้องดำเนินการใดๆ"</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"ต้องอัปเดตการรักษาความปลอดภัย"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"เปลี่ยนนโยบายความปลอดภัยแล้ว"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"ไม่ตรงกับนโยบายความปลอดภัย"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"บัญชี \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ต้องการการอัปเดตการตั้งค่าความปลอดภัย"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"ต้องมีการอัปเดตการรักษาความปลอดภัย"</string> <string name="account_security_title" msgid="3511543138560418587">"ความปลอดภัยของอุปกรณ์"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"เซิร์ฟเวอร์ <xliff:g id="SERVER">%s</xliff:g> ต้องการให้คุณอนุญาตให้ควบคุมคุณลักษณะความปลอดภัยบางอย่างของอุปกรณ์ Android ของคุณได้จากระยะไกล"</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"แก้ไขรายละเอียด"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"PIN หรือรหัสผ่านล็อกหน้าจอของคุณหมดอายุแล้ว"</string> <string name="password_expired_content_title" msgid="4349518706602252979">"รหัสผ่านล็อกหน้าจอหมดอายุแล้ว"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"รหัสผ่านล็อกหน้าจอใกล้หมดอายุ"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"คุณต้องเปลี่ยน PIN หรือรหัสผ่านสำหรับการล็อกหน้าจอโดยเร็ว ไม่เช่นนั้นข้อมูลของ <xliff:g id="ACCOUNT">%s</xliff:g> จะถูกลบ คุณต้องการเปลี่ยนตอนนี้หรือไม่"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"คุณต้องเปลี่ยน PIN หรือรหัสผ่านล็อกหน้าจอของคุณโดยเร็ว มิฉะนั้นข้อมูลสำหรับ <xliff:g id="ACCOUNT">%s</xliff:g> จะถูกลบ เปลี่ยนรหัสตอนนี้หรือไม่"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"รหัสผ่านล็อกหน้าจอหมดอายุแล้ว"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"ข้อมูลสำหรับ <xliff:g id="ACCOUNT">%s</xliff:g> กำลังถูกลบออกจากอุปกรณ์ของคุณ คุณสามารถคืนค่าข้อมูลได้โดยเปลี่ยน PIN หรือรหัสผ่านล็อกหน้าจอของคุณ เปลี่ยนรหัสตอนนี้หรือไม่"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"ข้อมูลสำหรับ <xliff:g id="ACCOUNT">%s</xliff:g> กำลังถูกลบออกจากอุปกรณ์ของคุณ คุณสามารถคืนค่าข้อมูลได้โดยเปลี่ยน PIN หรือรหัสผ่านล็อกหน้าจอของคุณ เปลี่ยนรหัสตอนนี้หรือไม่"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"ยกเลิกการเปลี่ยนแปลงที่ยังไม่ได้บันทึกหรือไม่"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"ลงชื่อเข้าใช้ไม่ได้"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"ชื่อผู้ใช้หรือรหัสผ่านสำหรับ <xliff:g id="ACCOUNT">%s</xliff:g> ไม่ถูกต้อง คุณต้องการอัปเดตตอนนี้หรือไม่"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"ชื่อผู้ใช้หรือรหัสผ่านสำหรับ <xliff:g id="ACCOUNT">%s</xliff:g> ไม่ถูกต้อง อัปเดตชื่อผู้ใช้และรหัสผ่านตอนนี้หรือไม่"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"บัญชีเริ่มต้น"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"ส่งอีเมลจากบัญชีนี้เป็นค่าเริ่มต้น"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"ดาวน์โหลดไฟล์แนบ"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"ดาวน์โหลดไฟล์แนบของข้อความล่าสุดผ่าน WiFi โดยอัตโนมัติ"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"การแจ้งเตือนทางอีเมล"</string> <string name="account_settings_summary" msgid="8403582255413830007">"ความถี่ในการซิงค์ การแจ้งเตือน ฯลฯ"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"ส่งการแจ้งเตือนเมื่อมีอีเมลเข้า"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"แจ้งในแถบระบบเมื่อได้รับอีเมล"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"ความถี่ในการตรวจสอบกล่องจดหมาย"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"การตั้งค่าข้อความขาเข้า"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"ชื่อผู้ใช้ รหัสผ่าน และการตั้งค่าเซิร์ฟเวอร์ขาเข้าอื่นๆ"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"การตั้งค่าข้อความขาออก"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"ชื่อผู้ใช้ รหัสผ่าน และการตั้งค่าเซิร์ฟเวอร์ขาออกอื่นๆ"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"บังคับใช้นโยบายแล้ว"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"ไม่มี"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"นโยบายที่ไม่สนับสนุน"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"ไม่มี"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"พยายามซิงค์"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"แตะที่นี่เพื่อซิงค์บัญชีนี้"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"ชื่อบัญชี"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"ชื่อของคุณ"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"ลายเซ็น"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"คำตอบด่วน"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"แก้ไขข้อความที่คุณใช้เป็นประจำเมื่อเขียนอีเมล"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"แก้ไขข้อความที่คุณใช้เป็นประจำเมื่อเขียนอีเมล"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"เพิ่มข้อความต่อท้ายจดหมายที่คุณส่ง"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"การตั้งค่าการแจ้งเตือน"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"การใช้ข้อมูล"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"นโยบายความปลอดภัย"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"แก้ไขคำตอบด่วน"</string> <string name="save_action" msgid="1988862706623227093">"บันทึก"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"ซิงค์รายชื่อในสมุดโทรศัพท์"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"ซิงค์สมุดโทรศัพท์สำหรับบัญชีนี้"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"ซิงค์ปฏิทิน"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"ซิงค์กิจกรรมในปฏิทินสำหรับบัญชีนี้"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"ซิงค์ปฏิทิน"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"ซิงค์ปฏิทินสำหรับบัญชีนี้"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"ซิงค์อีเมล"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"ซิงค์อีเมลสำหรับบัญชีนี้"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"สั่น"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"กำลังรอผลลัพธ์"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"เซิร์ฟเวอร์บางอย่างอาจใช้เวลานาน"</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"โฟลเดอร์"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"ไม่อนุญาตให้ใช้กล้องถ่ายรูปของอุปกรณ์"</string> - <string name="policy_require_password" msgid="7177274900480984702">"ต้องมีรหัสผ่านของอุปกรณ์"</string> - <string name="policy_password_history" msgid="5743544498302303181">"จำกัดการนำรหัสผ่านล่าสุดมาใช้ใหม่"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"รหัสผ่านต้องมีวันหมดอายุ"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"อุปกรณ์ต้องไม่มีการทำงานเพื่อล็อกหน้าจอ"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"จำกัดจำนวนกิจกรรมในปฏิทินที่ซิงค์"</string> - <string name="policy_email_age" msgid="7144148367145424963">"จำกัดจำนวนอีเมลที่ซิงค์"</string> - <string name="quick_1" msgid="3426057697353380951">"ขอบคุณ!"</string> - <string name="quick_2" msgid="4188036352885736617">"น่าสนใจนะ!"</string> - <string name="quick_3" msgid="8061819976353395585">"ฉันจะอ่านและตอบกลับทีหลัง"</string> - <string name="quick_4" msgid="3988974084396883051">"จัดการประชุมเพื่อคุยเรื่องนี้กัน"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"การซิงค์พื้นหลังสำหรับบัญชีนี้ถูกปิดใช้งานขณะโรมมิ่ง"</string> </resources> diff --git a/res/values-th/uploader.xml b/res/values-th/uploader.xml index 9849adfe8..3c4cd2d10 100644 --- a/res/values-th/uploader.xml +++ b/res/values-th/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"ซ่อนรายละเอียด"</string> <string name="menu_settings" msgid="5088116127086866634">"การตั้งค่า"</string> <string name="format_date_uploaded" msgid="803752037646090928">"อัปโหลดแล้ว %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"บัญชี"</string> <string name="upload" msgid="2615541458361216022">"อัปโหลด"</string> <string name="ok" msgid="2516349681897895312">"ตกลง"</string> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 5a44641be..3ffabddb2 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Basahin ang mga attachment sa email"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Binibigyang-daan ang app na basahin ang iyong mga attachment sa email."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Binibigyang-daan ang application na ito na basahin ang iyong mga attachment sa email."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"I-access ang data ng provider ng email"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Binibigyang-daan ang application na i-access ang database ng iyong email, kabilang ang mga natanggap na mensahe, naipadalang mensahe, username, at password."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Binibigyang-daan ang application na ito na i-access ang database ng iyong email, kabilang ang mga natanggap na mensahe, ipinadalang mensahe, username, at password."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Bumuo"</string> <string name="debug_title" msgid="5175710493691536719">"Debug"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Tapos na"</string> <string name="create_action" msgid="3062715563215392251">"Lumikha ng bago"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Tanggalin"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Walang mga mabilisang pagtugon."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Walang mga mabilisang pagtugon"</string> <string name="discard_action" msgid="6532206074859505968">"Itapon"</string> <string name="save_draft_action" msgid="6413714270991417223">"I-save ang draft"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Ipasok mabilisang tugon"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">"Si "\n\n"<xliff:g id="SENDER">%s</xliff:g> ay sumulat:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Isama ang naka-quote na teksto"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Isama ang teksto"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Magdagdag ng hindi bababa sa isang recipient."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Dapat kang magdagdag ng hindi bababa sa isang recipient."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Di-wasto ang ilang email address."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Masyadong malaki ang file upang i-attach."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Ipasok ang mabilisang tugon"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Na-save"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Huminto"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Na-save attachment na <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Hindi ma-save ang attachment."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Ida-download ang isa o higit pang mga attachment sa iyong ipinasang mensahe bago ang pagpapadala."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Hindi mai-save ang attachment."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Paalala: Ida-download bago ang pagpapadala ang isa o higit pang mga attachment sa iyong ipinasang mensahe."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Mensahe"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Imbitahan"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Hindi makapagpasa ng isa o higit pang mga attachment."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Hindi napasa ang attachment"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Hindi matagumpay ang pag-signin ng <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Nabigo sa pag-signin sa <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Hindi makapag-sign in"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Maaari kang mag-set up ng isang Exchange ActiveSync account sa ilang hakbang lamang."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Email address"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Password"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Magpadala ng email mula sa account na ito bilang default"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Magpadala ng email mula sa account na ito bilang default."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manu-manong pag-setup"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Mag-type ng wastong email address at password."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Duplicate na account"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Sinusuri ang mga setting ng papasok na server…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Sinusuri ang mga setting ng papalabas na server…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Setup ng account"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Naka-set up na ang iyong account at paparating na ang email!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Naka-set up ang iyong account, at paparating na ang email!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Bigyan ng pangalan ang account na ito (opsyonal)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Iyong pangalan (na ipinapakita sa mga papalabas na mensahe)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Hindi maaaring blangko ang field na ito."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP server"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Port"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Uri ng seguridad"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Hingin ang pag-signin"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Nangangailangan ng pag-sign-in."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Username"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Password"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Setup ng account"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Tuwing 15 minuto"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Tuwing 30 minuto"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Oras-oras"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Magpadala ng email mula sa account na ito bilang default"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"I-notify ako kapag may dumating na email"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"I-sync ang mga contact mula sa account na ito"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"I-sync ang kalendaryo mula sa account na ito"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"I-sync ang email mula sa account na ito"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Magpadala ng email mula sa account na ito bilang default."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"I-notify ako kapag dumating ang email."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"I-sync ang mga contact mula sa account na ito."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"I-sync ang kalendaryo mula sa account na ito"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"I-sync ang email mula sa account na ito."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Awtomatikong i-download ang mga attachment kapag nakakonekta sa Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Hindi matapos"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Mga araw upang i-sync"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Isang buwan"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Lahat"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Gamitin ang default ng account"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Hindi tama ang username o password."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Hindi tama ang username o password."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Mali ang username o password."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Mali ang username o password."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Hindi makakonekta nang ligtas sa server."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Hindi makakonekta nang ligtas sa server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Kinakailangan ng certificate ng client. Nais mo bang kumonekta sa server gamit ang isang certificate ng client?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Di-wasto o hindi naa-access ang certificate."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Tumugon ang server nang may error. Suriin ang iyong username at password, pagkatapos ay subukang muli."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Kinakailangan ang certificate ng client. Kumonekta sa server gamit ang certificate ng client?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Di-wasto o hindi naa-access ang certificate."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Tumugon ang server nang may error. Suriin ang iyong username at password pagkatapos ay subukang muli."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Hindi makakonekta sa server."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Hindi makakonekta sa server."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"Kinakailangan ang TLS ngunit hindi suportado ng server."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"BABALA: Ang pag-deactivate sa awtoridad ng Email app na pangasiwaan ang iyong device ay magtatanggal sa lahat ng email account na nangangailangan nito, kasama ang email, mga contact, mga kaganapan sa kalendaryo, at iba pang data ng mga ito."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Update sa seguridad"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Kinakailangan ng <xliff:g id="ACCOUNT">%s</xliff:g> na i-update mo ang iyong mga setting ng seguridad."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Hindi ma-sync ang account na \"<xliff:g id="ACCOUNT">%s</xliff:g>\" dahil sa mga kinakailangan sa seguridad."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Kinakailangan ng account na \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ng update sa mga setting ng seguridad."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Binago ng account na \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ang mga setting ng seguridad nito; walang kinakailangang pagkilos ng user."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Kailangan update sa seguridad"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Nabago patakaran sa seguridad"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Di masunod patakaran seguridad"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Nangangailangan ang account na \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ng pag-update ng mga setting ng seguridad."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Kailangan update sa seguridad"</string> <string name="account_security_title" msgid="3511543138560418587">"Seguridad ng device"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Kinakailangan ng server na <xliff:g id="SERVER">%s</xliff:g> na payagan mo itong malayuang kontrolin ang ilang tampok sa seguridad ng iyong Android device."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"I-edit ang mga detalye"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Nag-expire na ang iyong PIN o password sa pag-lock ng screen."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Expire na passw. pg-lock scr"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Nag-e-expire password pag-lock ng screen"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Kailangan mong baguhin ang iyong PIN o password para sa screen ng lock sa lalong madaling panahon, o mabubura ang data para sa <xliff:g id="ACCOUNT">%s</xliff:g>. Nais mo ba itong baguhin ngayon?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Dapat mong palitan ang iyong PIN o password sa pag-lock ng screen, o mabubura ang data para sa <xliff:g id="ACCOUNT">%s</xliff:g>. Palitan ito ngayon?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Nag-expire na password pag-lock screen"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Binubura ang data para sa <xliff:g id="ACCOUNT">%s</xliff:g> mula sa iyong device. Maipapanumbalik mo ito sa pamamagitan ng pagbabago sa iyong PIN o password para sa screen ng lock. Nais mo ba itong baguhin ngayon?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Binubura ang data para sa <xliff:g id="ACCOUNT">%s</xliff:g> mula sa iyong device. Maaari mo itong ibalik sa pamamagitan ng pagbabago ng iyong PIN o password sa pag-lock ng screen. Palitan ito ngayon?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Itapon ang hindi naka-save na mga pagbabago?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Hindi makapag-sign in"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Hindi tama ang username o password para sa <xliff:g id="ACCOUNT">%s</xliff:g>. Nais mo bang i-update ang mga ito ngayon?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Hindi tama ang username o password para sa <xliff:g id="ACCOUNT">%s</xliff:g>. I-update ang mga ito ngayon?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Default na account"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Magpadala ng email mula sa account na ito bilang default"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Mag-download ng mga attachment"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Awto i-download mga attachment sa mga bagong mensahe sa Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Mga notification sa email"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Dalas ng pag-sync, mga notification, atbp."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Magpadala ng notification kapag may dumating na email"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"I-notify sa System bar kapag dumating ang email"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Dalas ng pagtingin sa inbox"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Mga setting ng papasok"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Mga setting ng username, password, at ibang papasok na server"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Mga setting ng papalabas"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Mga setting ng username, password, at ibang papalabas na server"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Ipinapatupad na mga patakaran"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Wala"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Mga hindi sinusuportahang patakaran"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Wala"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Magtangkang i-sync"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Pumindot dito upang i-sync ang account na ito"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Pangalan ng account"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Iyong pangalan"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Lagda"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Mga mabilisang tugon"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"I-edit tekstong madalas mong pinapasok kapag nagsusulat ng email"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"I-edit ang teksto na madalas mong ipasok kapag nag-i-email"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Magsama ng teksto sa mga mensaheng iyong ipinapadala"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Mga setting ng notification"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Paggamit ng data"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Mga patakaran sa seguridad"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"I-edit ang mabilisang tugon"</string> <string name="save_action" msgid="1988862706623227093">"I-save"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"I-sync ang mga contact"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Sync ang contact sa account na ito"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"I-sync ang kalendaryo"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Sync ganap kalendaryo para ito acct"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Sync ang Kalendaryo"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"I-sync kalendaryo sa account na ito"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"I-sync ang email"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"I-sync ang email sa account na ito"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"I-vibrate"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Naghihintay ng mga resulta"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Maaaring magtagal ang ilang server."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Mga Folder"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Wag payag paggamit ng camera ng device"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Hilingin ang password ng device"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Paghigpitan gamit muli dating password"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Hinging mag-expire ang mga password"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Hilingin idle device i-lock screen nito"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Limitahan ang bilang ng mga kaganapan sa kalendaryo na sini-sync"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Limitahan ang bilang ng mga email na sini-sync"</string> - <string name="quick_1" msgid="3426057697353380951">"Salamat!"</string> - <string name="quick_2" msgid="4188036352885736617">"Magaling sa akin!"</string> - <string name="quick_3" msgid="8061819976353395585">"Babasahin ko ito sa ibang pagkakataon at babalik sa iyo."</string> - <string name="quick_4" msgid="3988974084396883051">"Magtakda tayo ng pulong upang talakayin ito."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Hindi pinapagana ang background na pag-sync para sa account na ito habang nagro-roam."</string> </resources> diff --git a/res/values-tl/uploader.xml b/res/values-tl/uploader.xml index b21305c42..157de852d 100644 --- a/res/values-tl/uploader.xml +++ b/res/values-tl/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Itago ang Mga Detalye"</string> <string name="menu_settings" msgid="5088116127086866634">"Mga Setting"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Na-upload %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Account"</string> <string name="upload" msgid="2615541458361216022">"I-upload"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 6fe3fb823..5e3c2e5d9 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"E-posta eklerini oku"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Uygulamaya e-posta eklerinizi okuma izni verir."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Bu uygulamaya, e-posta eklerinizi okuma izni verir."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"E-posta sağlayıcı verilerine eriş"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Uygulamaya, alınan iletiler, gönderilen iletiler, kullanıcı adları ve şifreler de dahil olmak üzere e-posta veritabanınıza erişme izni verir."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Bu uygulamaya, alınan iletiler, gönderilen iletiler, kullanıcı adları ve şifreler de dahil olmak üzere e-posta veritabanınıza erişme izni verir."</string> <string name="app_name" msgid="5815426892327290362">"E-posta"</string> <string name="compose_title" msgid="427986915662706899">"E-Posta Yaz"</string> <string name="debug_title" msgid="5175710493691536719">"Hata Ayıklama"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Bitti"</string> <string name="create_action" msgid="3062715563215392251">"Yeni oluştur"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Sil"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Hızlı yanıt yok."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Hızlı yanıt yok"</string> <string name="discard_action" msgid="6532206074859505968">"Sil"</string> <string name="save_draft_action" msgid="6413714270991417223">"Taslak kaydet"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Hızlı yanıt ekle"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> şunu yazdı:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Alıntılanan metni dahil et"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Metni ekle"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"En az bir alıcı ekleyin."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"En az bir alıcı eklemelisiniz."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Bazı e-posta adresleri geçersiz."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Dosya eklenemeyecek kadar büyük."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Hızlı yanıt ekle"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Kaydedildi"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Durdur"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Ek <xliff:g id="FILENAME">%s</xliff:g> olarak kaydedildi."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Ek kaydedilemedi."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Yönlendirilen iletinizdeki bir veya daha fazla ek, gönderme işleminden önce indirilecek."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Ek kaydedilemedi."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Not: Yönlendirilen iletinizdeki bir veya daha fazla ek, gönderme işleminden önce indirilecek."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"İleti"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Davet Et"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Bir veya birden fazla ek yönlendirilemedi."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Ek yönlendirilmedi"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> oturumu açılamadı."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> oturumu açılamadı"</string> <string name="login_failed_title" msgid="7624349996212476176">"Oturum açılamadı"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Yalnızca birkaç adımda Exchange ActiveSync hesabı oluşturabilirsiniz."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"E-posta adresi"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Şifre"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"E-postaları varsayılan olarak bu hesaptan gönder"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"E-postayı varsayılan olarak bu hesaptan gönder."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Manuel kurulum"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Geçerli bir e-posta adresi ve şifre yazın."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Yinelenen hesap"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Gelen sunucu ayarları denetleniyor..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Giden sunucu ayarları denetleniyor..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Hesap kurulumu"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Hesabınız ayarlandı ve e-posta gönderildi!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Hesabınız ayarlandı ve e-posta gönderildi!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Bu hesaba bir ad ver (isteğe bağlı)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Adınız (giden iletilerde görüntülenir)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Bu alan boş olamaz."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP sunucusu"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Bağlantı Noktası"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Güvenlik türü"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Oturum açmayı gerektir"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Oturum açılmasını gerektiriyor."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Kullanıcı adı"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Şifre"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Hesap kurulumu"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Her 15 dakikada bir"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Her 30 dakikada bir"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Saatte bir"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"E-postaları varsayılan olarak bu hesaptan gönder"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"E-posta geldiğinde bana bildir"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Bu hesaptaki kişileri senkronize et"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Bu hesaptaki takvimi senkronize et"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"E-postayı bu hesaptan senkronize et"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"E-postayı varsayılan olarak bu hesaptan gönder."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"E-posta geldiğinde bana bildir."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Bu hesaptaki kişileri senkronize et."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Bu hesaptaki takvimi senkronize et"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"E-postayı bu hesaptan senkronize et."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Kablosuz\'a bağlandığında ekleri otomatik olarak indir"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Tamamlanamadı"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Senkronize edilecek gün sayısı"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Bir ay"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Tümü"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Varsayılanı kullan"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Kullanıcı adı veya şifre hatalı."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Kullanıcı adı veya şifre yanlış."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Kullanıcı adı veya şifre hatalı."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Kullanıcı adı veya şifre hatalı."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Sunucuya güvenli biçimde bağlanılamıyor."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Sunucuya güvenli biçimde bağlanılamıyor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"İstemci sertifikası gerekli. Sunucuya bir istemci sertifikası ile bağlanmak ister misiniz?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Sertifika geçersiz veya erişilemez."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Sunucu hata gönderdi. Kullanıcı adınızı ve şifrenizi kontrol ettikten sonra tekrar deneyin."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"İstemci sertifikası gerekli. Sunucuya istemci sertifikasıyla bağlanılsın mı?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Sertifika geçersiz veya erişilemiyor."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Sunucu hata gönderdi. Kullanıcı adınızı ve şifrenizi kontrol ettikten sonra tekrar deneyin."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Sunucuya bağlanılamıyor."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Sunucuya bağlanılamıyor."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS gerekli ancak sunucu tarafından desteklenmiyor."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"UYARI: E-posta uygulamasının cihazınızı yönetme yetkisinin devre dışı bırakılması, bunu gerektiren tüm e-posta hesaplarının yanı sıra bu hesaplar ait e-postaları, kişileri, takvim olaylarını ve diğer verileri siler."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Güvenlik güncellemesi"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> için güvenlik ayarlarınızı güncellemeniz gerekiyor."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" hesabı güvenlik gereksinimleri nedeniyle senkronize edilemez."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" hesabı, güvenlik ayarları güncellemesi gerektiriyor."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" hesabının güvenlik ayarları değiştirildi; kullanıcının işlem yapmasına gerek yok."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Güvenlik güncellemesi gerekli"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Güvenlik politikaları değişti"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Güvenlik politikaları karşılanamıyor"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" hesabı, güvenlik ayarları güncellemesi gerektiriyor."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Güvenlik güncellemesi gerekli"</string> <string name="account_security_title" msgid="3511543138560418587">"Cihaz güvenliği"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"<xliff:g id="SERVER">%s</xliff:g> sunucusu, Android telefonunuzdaki bazı güvenlik özelliklerini uzaktan kontrol etmesine izin vermenizi gerektiriyor."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Ayrıntıları düzenle"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Ekran kilidinizin PIN veya şifresinin süresi doldu."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Ekr kilidi şifr süresi doldu"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Ekran kilidi şifresinin süresi doluyor"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Ekran kilidi PIN\'inizi veya şifrenizi kısa süre içinde değiştirmeniz gerekiyor, aksi takdirde <xliff:g id="ACCOUNT">%s</xliff:g> hesabına ait veriler silinecek. Bunu şimdi değiştirmek ister misiniz?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Ekran kilidi PIN\'inizi veya şifrenizi yakında değiştirmeniz gerekiyor, aksi takdirde <xliff:g id="ACCOUNT">%s</xliff:g> hesabına ait veriler silinecek. Şimdi değiştirmek ister misiniz?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Ekran kilidi şifresinin süresi doldu"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g> hesabına ait veriler cihazınızdan siliniyor. Ekran kilidi PIN\'inizi veya şifrenizi değiştirerek bu verileri geri yükleyebilirsiniz. Bunu şimdi değiştirmek ister misiniz?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g> kullanıcısının verileri cihazınızdan siliniyor. Ekran kilidi PIN\'inizi veya şifrenizi değiştirerek bu verileri geri yükleyebilirsiniz. Şimdi değiştirmek ister misiniz?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Kaydedilmeyen değişiklikler silinsin mi?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Oturum açılamadı."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g> için kullanıcı adı veya şifre yanlış. Bunları şimdi güncellemek ister misiniz?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g> için kullanıcı adı veya şifre yanlış. Şimdi güncellemek ister misiniz?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Varsayılan hesap"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"E-postaları varsayılan olarak bu hesaptan gönder"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Ekleri indir"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Son iletilerin eklerini Kablosuz üzerinden otomatik indir"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"E-posta bildirimleri"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Sıklığı, bildirimleri vs. senkronize et"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"E-posta geldiğinde bildirim gönder"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"E-posta geldiğinde Sistem çubuğunda bildir"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Gelen kutusunu denetleme sıklığı"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Gelen ayarlar"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Kullanıcı adı, şifre ve diğer gelen sunucu ayarları"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Giden ayarlar"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Kullanıcı adı, şifre ve diğer giden sunucu ayarları"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Politikalar uygulandı"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Hiçbiri"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Desteklenmeyen politikalar"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Hiçbiri"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Senkronize etmeyi dene"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Bu hesabı senkronize etmek için buraya dokunun"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Hesap adı"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Adınız"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"İmza"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Hızlı yanıtlar"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"E-posta oluştururken sık girdiğiniz metinleri düzenleyin"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"E-posta oluştururken sık girdiğiniz metinleri düzenleyin"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Gönderdiğiniz iletilere metin ekleyin"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Bildirim ayarları"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Veri kullanımı"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Güvenlik politikaları"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Hızlı yanıtı düzenle"</string> <string name="save_action" msgid="1988862706623227093">"Kaydet"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Kişileri senkronize et"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Bu hesaba ilişkin kişileri senkronize et"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Takvimi senkronize et"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Bu hesabın takvim etkinliğini senkronize et"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Takvim\'i Senkronize Et"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Bu hesaba ilişkin takvimi senkronize et"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"E-postayı senk. et"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Bu hesaba ilişkin e-postaları senkronize et"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Titreşim"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Sonuçlar bekleniyor"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Bazı sunucularda uzun sürebilir."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Klasörler"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Cihaz kamerasının kullanımına izin verme"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Cihaz şifresi gerektir"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Son şifrelerin tekrar kullanılmasını kısıtla"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Şifrelerde son kullanım tarihi gerektir"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Boştaki cihazın ekranını kilitlemesini gerektir"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Senk. edilen takvim etkinliği sayısını sınırlandır"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Senkronize edilen e-posta sayısını sınırlandır"</string> - <string name="quick_1" msgid="3426057697353380951">"Teşekkür ederiz!"</string> - <string name="quick_2" msgid="4188036352885736617">"Benim için uygun görünüyor!"</string> - <string name="quick_3" msgid="8061819976353395585">"Bunu daha sonra okuyup size geri döneceğim."</string> - <string name="quick_4" msgid="3988974084396883051">"Bu konuyu tartışmak üzere bir toplantı ayarlayalım."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Dolaşımdayken bu hesabın arka plan senkronizasyonu devre dışı bırakılır."</string> </resources> diff --git a/res/values-tr/uploader.xml b/res/values-tr/uploader.xml index a7a307625..1c367db16 100644 --- a/res/values-tr/uploader.xml +++ b/res/values-tr/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ayrıntıları Gizle"</string> <string name="menu_settings" msgid="5088116127086866634">"Ayarlar"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Yükleme tarihi: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="PERCENTSIGN">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Hesap"</string> <string name="upload" msgid="2615541458361216022">"Yükle"</string> <string name="ok" msgid="2516349681897895312">"TAMAM"</string> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 167af9e81..578e4092f 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Читати вкладені файли пошти"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Дозволяє програмі читати вкладені файли вашої пошти."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Дозволяє програмі читати вкладені файли вашої пошти."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Доступ до даних постачальника послуг електронної пошти"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Дозволяє програмі отримувати доступ до бази даних вашої пошти, зокрема отриманих і надісланих повідомлень, імен користувачів та паролів."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Дозволяє програмі отримувати доступ до бази даних вашої пошти, зокрема отриманих і надісланих повідомлень, імен користувачів та паролів."</string> <string name="app_name" msgid="5815426892327290362">"Ел.пошта"</string> <string name="compose_title" msgid="427986915662706899">"Написати"</string> <string name="debug_title" msgid="5175710493691536719">"Налагодж."</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Готово"</string> <string name="create_action" msgid="3062715563215392251">"Створити"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Видалити"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Швидких відповідей немає."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Швидких відповідей немає"</string> <string name="discard_action" msgid="6532206074859505968">"Відхилити"</string> <string name="save_draft_action" msgid="6413714270991417223">"Зберег. чернетку"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Вставити швидк.відповідь"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> напис.:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Додати цитований текст"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Включити текст"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Додайте принаймні одного отримувача."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Потрібно додати принаймні 1 отримувача."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Деякі електронні адреси недійсні."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Файл завеликий для вклад."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Вставити швидку відповідь"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Збережено"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Зупинити"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Вклад. файл збереж. як <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Вкладений файл не збережено."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Перед надсиланням буде завантажено один або кілька вкладених файлів із повідомлення, яке ви пересилаєте."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Вкладений файл не збережено."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Примітка. Перед надсиланням буде завантажено один або кілька вкладених файлів із повідомлення, яке ви пересилаєте."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Повідомлення"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Запрошення"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Не вдалося переслати один або кілька вкладених файлів."</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Вкладений файл не переслано"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Помилка входу в обліковий запис <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"Помилка входу в обліковий запис <xliff:g id="ACCOUNT_NAME">%s</xliff:g>."</string> <string name="login_failed_title" msgid="7624349996212476176">"Не вдалося ввійти"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> Б"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Можна налаштувати обліковий запис Exchange ActiveSync за допомогою лише кількох дій."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Електронна адреса"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Пароль"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Надсилати електронні листи з цього облікового запису за умовчанням"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Надс. ел.листи з цього обл. зап. за умовч."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Налашт-ня вручну"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Введіть дійсну електронну адресу та пароль."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Копія облікового запису"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Перевірка налашт-нь вихід. сервера…"</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Перевірка налашт-нь вихід. сервера…"</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Налаштування облікового запису"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Ваш обліковий запис налаштовано. Скоро надійдуть листи!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Ваш обліковий запис налаштовано. Скоро надійдуть листи!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Назвіть цей обл. запис. (додатково)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Ваше ім\'я (відображено у вихідних повідомл.)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Це поле не може бути порожнім."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Сервер SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Порт"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Тип безпеки"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Потрібно ввійти"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Необхідно ввійти."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Ім\'я корист."</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Пароль"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Налаштування облікового запису"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Кожні 15 хвилин"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Кожні 30 хвилин"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Щогодини"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Надсилати електронні листи з цього облікового запису за умовчанням"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Сповіщати мене, коли надходить лист"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Синхронізувати контакти з цього облікового запису"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Синхронізувати календар із цього облікового запису"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Синхронізувати електронну пошту з цього облікового запису"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Надс. ел.листи з цього обл. зап. за умовч."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Сповіщ. мене, коли надійде лист"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Синхрон. контакти з цього обл. зап."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Синхроніз. календ. з обл. запису."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Синхр. ел. пошту з обл. запису."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Автоматично завантажувати вкладення, коли є з\'єднання з Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Не вдалося закінчити"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Синхронізувати за стільки днів:"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Один місяць"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Усі"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Парам. обл.зап. за умовч."</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Ім’я користувача чи пароль неправильні."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Ім’я користувача або пароль неправильні."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Ім\'я кор. або пароль неправильн."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Ім\'я корист. чи пароль неправильн."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Неможливо безпечно з’єднатись із сервером."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Неможливо безпечно з’єднатися із сервером."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Потрібен сертифікат клієнта. Під’єднатися до сервера із сертифікатом клієнта?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Сертифікат недійсний або недоступний."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Сервер повідомив про помилку. Перевірте своє ім’я користувача та пароль і повторіть спробу."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Потрібен сертифікат клієнта. Під’єднатися до сервера із сертифікатом клієнта?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Сертифікат недійсний або недоступний."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Сервер повідомив про помилку. Перевірте своє ім’я користувача та пароль і повторіть спробу."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Неможливо з’єднатись із сервером."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Неможливо з’єднатись із сервером."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS обов\'язк., але не підтрм. цим сервером."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ЗАСТЕРЕЖЕННЯ. Дезактивація повноважень програми електронної пошти на адміністрування вашого пристрою призведе до видалення всіх облікових записів електронної пошти, що потребують адміністрування, разом з їхніми електронними листами, контактами, подіями календаря й іншими даними."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Оновлення системи безпеки"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"Потрібно оновити налаштування безпеки для облікового запису <xliff:g id="ACCOUNT">%s</xliff:g>."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Обліковий запис \"<xliff:g id="ACCOUNT">%s</xliff:g>\" неможливо синхронізувати через вимоги безпеки."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Для облікового запису \"<xliff:g id="ACCOUNT">%s</xliff:g>\" потрібно оновити налаштування безпеки."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Налаштування безпеки облікового запису \"<xliff:g id="ACCOUNT">%s</xliff:g>\" змінено. Користувачу не потрібно нічого робити."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Потрібно оновити прав. безпеки"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Правила безпеки змінено"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Неможл. дотрим. правил безпеки"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Облік. запис \"<xliff:g id="ACCOUNT">%s</xliff:g>\" потреб. оновл. налашт-нь безпеки"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Потрібне оновл. сист. безпеки"</string> <string name="account_security_title" msgid="3511543138560418587">"Безпека пристрою"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Сервер <xliff:g id="SERVER">%s</xliff:g> потребує вашого дозволу віддалено контролювати деякі функції безпеки вашого пристрою Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Редаг. деталі"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Термін дії PIN-коду чи пароля блокування екрана закінчився."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Пароль блок. екр. вже не діє"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Терм. дії пароля блок. екр. закінчується"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Незабаром потрібно буде змінити PIN-код або пароль блокування екрана, інакше дані для облікового запису <xliff:g id="ACCOUNT">%s</xliff:g> буде стерто. Змінити зараз?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Незабаром потрібно буде змінити PIN-код або пароль блокування екрана, інакше дані для <xliff:g id="ACCOUNT">%s</xliff:g> буде стерто. Змінити зараз?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Терм. дії пароля блок. екрана закінчився"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Дані для облікового запису <xliff:g id="ACCOUNT">%s</xliff:g> стираються з вашого пристрою. Їх можна відновити, змінивши PIN-код або пароль блокування екрана. Змінити зараз?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Дані для <xliff:g id="ACCOUNT">%s</xliff:g> стираються з вашого пристрою. Їх можна відновити, змінивши PIN-код або пароль блокування екрана. Змінити зараз?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Відхилити незбережені зміни?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Не вдалося ввійти"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Ім’я користувача чи пароль для облікового запису <xliff:g id="ACCOUNT">%s</xliff:g> неправильні. Оновити зараз?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Ім’я користувача чи пароль для <xliff:g id="ACCOUNT">%s</xliff:g> неправильні. Оновити зараз?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Обл. зап. за умовч."</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Надіс. ел.листи з цього обл. зап. за умовч."</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Завантажити вкладені файли"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Автом. завантажувати вклад. файли з останніх повідом. через WiFi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Сповіщення ел. пошти"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Синхронізуйте частоту, сповіщення тощо"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Надсилати сповіщення, коли надходить лист"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Сповіщати в системному рядку про надходження листа"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Частота перевірки вхідн."</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Налашт. вхід. повід."</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Ім’я корист., пароль й інші налашт-ня сервера вхідних повідомл."</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Налашт-ня вихідних"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Ім’я корист., пароль й інші налашт-ня сервера вихідних повідомл."</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Правила, які застосовуються"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Немає"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Правила, які не підтримуються"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Немає"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Спробувати синхронізувати"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Торкніться тут, щоб синхронізувати цей обліковий запис"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Назва обл. зап."</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Ваше ім\'я"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Підпис"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Швидкі відповіді"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Редагувати текст, що часто вставляється під час створення листів"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Змінити текст, який часто вставляється під час створення листів"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Додав. текст у надісл. повідомл."</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Налаштування сповіщень"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Використання даних"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Правила безпеки"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Редагувати швидку відповідь"</string> <string name="save_action" msgid="1988862706623227093">"Зберегти"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Синхрон. контакти"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Синхрон. контакти для облік. запису"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Синхрон. календ."</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Синхроніз. календар із цим обл.зап."</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Синхроніз. Календар"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Синхроніз. календар для обл. запису"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Синхроніз. ел.пошту"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Синхрон. ел. пошту для обл. запису"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Вібросигнал"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Очікування результатів"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Деяким серверам потрібно багато часу."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Папки"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Забороняти використання камери пристрою"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Вимагати пароль пристрою"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Обмежувати повторне викор. остан.паролів"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Вимагати закінчення терміну дії пароля"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Вимаг. блок-ня екрана неактивн. пристрою"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Обмежувати к-сть синхронізованих подій календаря"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Обмежувати к-сть синхронізованих електрон. листів"</string> - <string name="quick_1" msgid="3426057697353380951">"Дякую!"</string> - <string name="quick_2" msgid="4188036352885736617">"Мені підходить!"</string> - <string name="quick_3" msgid="8061819976353395585">"Я прочитаю це пізніше, а потім дам знати."</string> - <string name="quick_4" msgid="3988974084396883051">"Потрібно зустрітися, щоб це обговорити."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"У роумінгу фонову синхронізацію для цього облікового запису вимкнено."</string> </resources> diff --git a/res/values-uk/uploader.xml b/res/values-uk/uploader.xml index 6f6af5bb9..f894c08dc 100644 --- a/res/values-uk/uploader.xml +++ b/res/values-uk/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Сховати деталі"</string> <string name="menu_settings" msgid="5088116127086866634">"Налаштування"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Завантажено: %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Обліковий запис"</string> <string name="upload" msgid="2615541458361216022">"Завантажити"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 617df4e6a..686e910b3 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Đọc tệp đính kèm trong email"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Cho phép ứng dụng đọc tệp đính kèm trong email của bạn."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Cho phép ứng dụng này đọc tệp đính kèm trong email của bạn."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Truy cập dữ liệu của nhà cung cấp email"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Cho phép ứng dụng truy cập cơ sở dữ liệu email của bạn, bao gồm thư đã nhận, thư đã gửi, tên người dùng và mật khẩu."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Cho phép ứng dụng này truy cập cơ sở dữ liệu email của bạn, bao gồm thư đã nhận, thư đã gửi, tên người dùng và mật khẩu."</string> <string name="app_name" msgid="5815426892327290362">"Email"</string> <string name="compose_title" msgid="427986915662706899">"Soạn"</string> <string name="debug_title" msgid="5175710493691536719">"Gỡ lỗi"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Xong"</string> <string name="create_action" msgid="3062715563215392251">"Tạo mới"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Xóa"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Không có câu trả lời nhanh nào."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Không có câu trả lời nhanh nào"</string> <string name="discard_action" msgid="6532206074859505968">"Hủy"</string> <string name="save_draft_action" msgid="6413714270991417223">"Lưu thư nháp"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Chèn trả lời nhanh"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g> đã viết:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Bao gồm nội dung được trích dẫn"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Bao gồm văn bản"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Thêm ít nhất một người nhận."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Bạn phải thêm ít nhất một người nhận."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Một số địa chỉ email không hợp lệ."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Tệp quá lớn để có thể đính kèm."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Chèn trả lời nhanh"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Đã lưu"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Dừng"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Đã lưu tệp đính kèm với tên <xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Không thể lưu tệp đính kèm."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Một hoặc nhiều tệp đính kèm trong thư chuyển tiếp của bạn sẽ được tải xuống trước khi gửi."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Không thể lưu tệp đính kèm."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Lưu ý: Một hoặc nhiều tệp đính kèm trong thư chuyển tiếp của bạn sẽ được tải xuống trước khi gửi."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Thư"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Mời"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Không thể chuyển tiếp một hoặc nhiều tệp đính kèm"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Tệp đính kèm không được chuyển tiếp"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"Đăng nhập vào <xliff:g id="ACCOUNT_NAME">%s</xliff:g> không thành công."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> đăng nhập không thành công."</string> <string name="login_failed_title" msgid="7624349996212476176">"Không thể đăng nhập"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Bạn có thể thiết lập tài khoản Exchange ActiveSync chỉ bằng vài bước."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Địa chỉ email"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Mật khẩu"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Gửi email từ tài khoản này theo mặc định"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Gửi email từ tài khoản này theo mặc định."</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Thiết lập thủ công"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Hãy nhập địa chỉ email và mật khẩu hợp lệ."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"Tài khoản trùng lặp"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Đang kiểm tra cài đặt máy chủ thư đến..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Đang kiểm tra cài đặt máy chủ thư đi..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Thiết lập tài khoản"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"Tài khoản của bạn đã được thiết lập và email đang được gửi!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"Tài khoản của bạn đã được thiết lập và email đang được gửi!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Đặt tên cho tài khoản này (tùy chọn)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Tên bạn (được hiển thị trong tin nhắn đi)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Không được để trống trường này."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Máy chủ SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Cổng"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Loại bảo mật"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Yêu cầu đăng nhập"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Yêu cầu đăng nhập."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Tên người dùng"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Mật khẩu"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Thiết lập tài khoản"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"15 phút một lần"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"30 phút một lần"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Hàng giờ"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Gửi email từ tài khoản này theo mặc định"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Thông báo cho tôi khi email đến"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Đồng bộ hóa danh bạ từ tài khoản này"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Đồng bộ hóa lịch từ tài khoản này"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Đồng bộ hóa email từ tài khoản này"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Gửi email từ tài khoản này theo mặc định."</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Thông báo cho tôi khi email đến."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Đồng bộ hóa danh bạ từ tài khoản này."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Đồng bộ hóa lịch từ tài khoản này."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Đồng bộ hóa email từ tài khoản này."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Tự động tải xuống tệp đính kèm khi được kết nối Wi-Fi"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Không thể kết thúc"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Số ngày đồng bộ hóa"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Một tháng"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Tất cả"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Sử dụng mặc định của tài khoản"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Tên người dùng hoặc mật khẩu không chính xác."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Tên người dùng hoặc mật khẩu không chính xác."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Tên người dùng hoặc mật khẩu không chính xác."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Tên người dùng hoặc mật khẩu không chính xác."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Không thể kết nối an toàn với máy chủ."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Không thể kết nối an toàn với máy chủ."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Cần chứng chỉ ứng dụng khách. Bạn có muốn kết nối với máy chủ bằng chứng chỉ ứng dụng khách không?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Chứng chỉ không hợp lệ hoặc không thể truy cập được."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Máy chủ trả về lỗi. Hãy kiểm tra tên người dùng và mật khẩu rồi thử lại."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Yêu cầu chứng chỉ ứng dụng khách. Kết nối với máy chủ có chứng chỉ ứng dụng khách?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Chứng chỉ không hợp lệ hoặc không thể truy cập được."</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Máy chủ trả về lỗi. Hãy kiểm tra tên người dùng và mật khẩu rồi thử lại."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Không thể kết nối với máy chủ."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Không thể kết nối với máy chủ."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"TLS được yêu cầu nhưng không được máy chủ hỗ trợ."</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"CẢNH BÁO: Việc vô hiệu hóa quyền quản lý điện thoại của bạn của ứng dụng Email sẽ xóa tất cả tài khoản email yêu cầu quyền đó, cùng với email, địa chỉ liên hệ, sự kiện lịch và các dữ liệu khác."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Cập nhật bảo mật"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> yêu cầu bạn cập nhật cài đặt bảo mật của mình."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"Không thể đồng bộ hóa tài khoản \"<xliff:g id="ACCOUNT">%s</xliff:g>\" do các yêu cầu về bảo mật."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"Tài khoản \"<xliff:g id="ACCOUNT">%s</xliff:g>\" yêu cầu cập nhật cài đặt bảo mật."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"Tài khoản \"<xliff:g id="ACCOUNT">%s</xliff:g>\" đã thay đổi cài đặt bảo mật; không yêu cầu bất kỳ tác vụ người dùng nào."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Yêu cầu cập nhật bảo mật"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Chính sách bảo mật đã thay đổi"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Ko thể đáp ứng c.sách bảo mật"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"Tài khoản \"<xliff:g id="ACCOUNT">%s</xliff:g>\" yêu cầu cập nhật cài đặt bảo mật."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Yêu cầu cập nhật bảo mật"</string> <string name="account_security_title" msgid="3511543138560418587">"Bảo mật thiết bị"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Máy chủ <xliff:g id="SERVER">%s</xliff:g> yêu cầu bạn cho phép kiểm soát từ xa một số tính năng bảo mật của thiết bị Android của bạn."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Chỉnh sửa chi tiết"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"Mật khẩu hoặc mã PIN khóa màn hình của bạn đã hết hạn."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Mật khẩu khóa màn hình đã hết hạn"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Mật khẩu khóa màn hình sắp hết hạn"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Bạn cần phải sớm thay đổi PIN khóa màn hình hoặc mật khẩu, nếu không dữ liệu của <xliff:g id="ACCOUNT">%s</xliff:g> sẽ bị xóa. Bạn có muốn thay đổi ngay bây giờ không?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Bạn phải sớm thay đổi mã PIN hoặc mật khẩu khóa màn hình của mình, nếu không dữ liệu cho <xliff:g id="ACCOUNT">%s</xliff:g> sẽ bị xóa. Thay đổi ngay bây giờ?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Mật khẩu khóa màn hình đã hết hạn"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Dữ liệu của <xliff:g id="ACCOUNT">%s</xliff:g> đang bị xóa khỏi thiết bị của bạn. Bạn có thể khôi phục dữ liệu bằng cách thay đổi PIN khóa màn hình hoặc mật khẩu của mình. Bạn có muốn thay đổi ngay bây giờ không?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Dữ liệu của <xliff:g id="ACCOUNT">%s</xliff:g> đang bị xóa khỏi thiết bị của bạn. Bạn có thể khôi phục dữ liệu đó bằng cách thay đổi mật khẩu hoặc mã PIN khóa màn hình của mình. Bạn có muốn thay đổi ngay bây giờ không?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Hủy những thay đổi chưa lưu?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Không thể đăng nhập"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Tên người dùng hoặc mật khẩu của <xliff:g id="ACCOUNT">%s</xliff:g> không chính xác. Bạn có muốn cập nhật các thông tin này ngay bây giờ không?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Tên người dùng hoặc mật khẩu của <xliff:g id="ACCOUNT">%s</xliff:g> không đúng. Cập nhật tên người dùng hoặc mật khẩu ngay bây giờ?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"Tài khoản mặc định"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Gửi email từ tài khoản này theo mặc định"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Tải xuống tệp đính kèm"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Tự động tải xuống tệp đính kèm tin nhắn gần đây qua Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Thông báo qua email"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Đồng bộ hóa tần suất, thông báo, v.v."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Gửi thông báo khi email đến"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Thông báo trên thanh Hệ thống khi email đến"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Tần suất kiểm tra hộp thư đến"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Cài đặt thư đến"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Tên người dùng, mật khẩu và các cài đặt máy chủ thư đến khác"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Cài đặt thư đi"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Tên người dùng, mật khẩu và cài đặt máy chủ thư đi khác"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Chính sách bắt buộc"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Bỏ chọn tất cả"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Chính sách không được hỗ trợ"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Bỏ chọn tất cả"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Thử đồng bộ hóa"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Chạm vào đây để đồng bộ hóa tài khoản này"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Tên tài khoản"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Tên bạn"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Chữ ký"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Trả lời nhanh"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Chỉnh sửa văn bản mà bạn thường xuyên chèn khi soạn email"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Chỉnh sửa văn bản mà bạn thường xuyên chèn khi soạn email"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Thêm văn bản vào tin nhắn bạn gửi"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Cài đặt thông báo"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Sử dụng dữ liệu"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Chính sách bảo mật"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Chỉnh sửa trả lời nhanh"</string> <string name="save_action" msgid="1988862706623227093">"Lưu"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Đồng bộ hóa danh bạ"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Đồng bộ hóa danh bạ cho tài khoản này"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Đồng bộ hóa lịch"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Đ.bộ hóa sự kiện lịch cho TK này"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Đồng bộ hóa lịch"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Đồng bộ hóa lịch cho tài khoản này"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Đồng bộ hóa email"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Đồng bộ hóa email cho tài khoản này"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Rung"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Đang chờ kết quả"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Một số máy chủ có thể xử lý lâu."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Thư mục"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Ko cho phép sử dụng máy ảnh của thiết bị"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Yêu cầu mật khẩu của thiết bị"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Hạn chế sử dụng lại các mật khẩu gần đây"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Buộc mật khẩu hết hạn"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Thiết bị cần ở chế độ rảnh để khóa màn hình"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Giới hạn số lượng sự kiện lịch được đồng bộ hóa"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Giới hạn số lượng email được đồng bộ hóa"</string> - <string name="quick_1" msgid="3426057697353380951">"Cảm ơn bạn!"</string> - <string name="quick_2" msgid="4188036352885736617">"Tôi thấy được đấy!"</string> - <string name="quick_3" msgid="8061819976353395585">"Tôi sẽ đọc thư này sau và sẽ liên hệ lại với bạn."</string> - <string name="quick_4" msgid="3988974084396883051">"Chúng ta hãy cùng tổ chức một cuộc họp để thảo luận về vấn đề này."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Đồng bộ hóa nền cho tài khoản này bị tắt trong khi chuyển vùng."</string> </resources> diff --git a/res/values-vi/uploader.xml b/res/values-vi/uploader.xml index 66c63744e..f8ad2a055 100644 --- a/res/values-vi/uploader.xml +++ b/res/values-vi/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Ẩn chi tiết"</string> <string name="menu_settings" msgid="5088116127086866634">"Cài đặt"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Đã tải lên %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"Tài khoản"</string> <string name="upload" msgid="2615541458361216022">"Tải lên"</string> <string name="ok" msgid="2516349681897895312">"OK"</string> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 00a7116ca..fb1d4d2a6 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"读取电子邮件附件"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"允许此应用读取您的电子邮件附件。"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"允许此应用程序读取您的电子邮件附件。"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"访问电子邮件服务提供商数据"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"允许此应用访问您的电子邮件数据库,包括已收邮件、已发邮件、用户名和密码。"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"允许此应用程序访问您的电子邮件数据库,包括已收邮件、已发邮件、用户名和密码。"</string> <string name="app_name" msgid="5815426892327290362">"电子邮件"</string> <string name="compose_title" msgid="427986915662706899">"写邮件"</string> <string name="debug_title" msgid="5175710493691536719">"调试"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"完成"</string> <string name="create_action" msgid="3062715563215392251">"新建"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"删除"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"没有快速回复。"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"没有快速回复"</string> <string name="discard_action" msgid="6532206074859505968">"放弃"</string> <string name="save_draft_action" msgid="6413714270991417223">"保存草稿"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"插入快速回复"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>编写:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"包含引用文字"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"包含原文"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"请至少添加一位收件人。"</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"必须至少添加一个收件人。"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"某些电子邮件地址无效。"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"文件太大,无法附加。"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"插入快速回复"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"已保存"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"停止"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"附件已另存为“<xliff:g id="FILENAME">%s</xliff:g>”。"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"无法保存附件。"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"您转发的邮件中有一个或多个附件需要先下载,然后才能发送。"</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"无法保存该附件。"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"注意:您的转发邮件中有一个或多个附件会先下载再发送。"</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"邮件"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"邀请"</string> <plurals name="message_view_show_attachments_action"> @@ -179,14 +179,14 @@ <string name="attachment_info_dialog_default_title" msgid="4995755709689009622">"附件信息"</string> <string name="attachment_info_dialog_wifi_title" msgid="3174350153882915382">"需要使用 Wi-Fi 连接"</string> <string name="attachment_info_wifi_settings" msgid="96432970927503597">"Wi-Fi 设置"</string> - <string name="attachment_info_application_settings" msgid="4124655487276125596">"应用设置"</string> + <string name="attachment_info_application_settings" msgid="4124655487276125596">"应用程序设置"</string> <string name="attachment_info_unknown" msgid="8342655396805943320">"无法打开附件。"</string> <string name="attachment_info_malware" msgid="6576029010855055528">"该类型的附件中可能包含恶意软件,因此您无法保存或打开此文件。"</string> <string name="attachment_info_policy" msgid="3560422300127587508">"由于此帐户安全政策的限制,因此无法保存或打开此附件。"</string> <string name="attachment_info_wifi_only" msgid="1481120960014563617">"附件过大,无法通过移动网络下载。您可以在下次连接到 Wi-Fi 网络时下载。"</string> - <string name="attachment_info_no_intent" msgid="8139209405745777924">"已安装的应用都无法打开此附件。请尝试从 Android 电子市场下载一个合适的应用。"</string> - <string name="attachment_info_sideload_disabled" msgid="3270731101769840006">"此附件是应用。要想安装该应用,您需要在“设置”>“应用”中选中“未知来源”。"</string> - <string name="attachment_info_apk_install_disabled" msgid="2817790592227462682">"无法直接从电子邮件中安装应用。请先保存此应用,然后使用“下载内容”应用进行安装。"</string> + <string name="attachment_info_no_intent" msgid="8139209405745777924">"已安装的应用程序都无法打开此附件。请尝试从 Android 电子市场下载一个合适的应用程序。"</string> + <string name="attachment_info_sideload_disabled" msgid="3270731101769840006">"此附件是应用程序。要想安装该应用程序,您需要在“设置”>“应用程序”中选中“未知来源”。"</string> + <string name="attachment_info_apk_install_disabled" msgid="2817790592227462682">"无法直接从电子邮件中安装应用程序。请先保存此应用程序,然后使用“下载内容”应用程序进行安装。"</string> <string name="attachment_not_found" msgid="7155322700141145123">"无法下载该附件。"</string> <string name="message_decode_error" msgid="5016042255170947834">"解码邮件时出错。"</string> <string name="eml_view_title" msgid="8827210108543430336">"查看 <xliff:g id="FILENAME">%s</xliff:g>"</string> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"一个或多个附件无法转发。"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"无法转发附件"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> 登录失败。"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> 登录失败。"</string> <string name="login_failed_title" msgid="7624349996212476176">"无法登录"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g> B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"您只需执行几个步骤,即可设置 Exchange ActiveSync 帐户。"</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"电子邮件地址"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"密码"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"默认情况下从此帐户发送电子邮件"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"默认情况下从此帐户发送电子邮件。"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"手动设置"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"请键入有效的电子邮件地址和密码。"</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"帐户重复"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"正在检查接收服务器设置..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"正在检查外发服务器设置..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"帐户设置"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"您的帐户已设置完毕,可以收发电子邮件了!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"您的帐户已设置完毕,可以收发电子邮件了!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"为此帐户创建名称(可选)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"您的姓名(显示在外发邮件上)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"此字段不能为空。"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP 服务器"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"端口"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"安全类型"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"要求登录"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"需要登录。"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"用户名"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"密码"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"帐户设置"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"每隔 15 分钟"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"每隔 30 分钟"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"每小时"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"默认情况下从此帐户发送电子邮件"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"收到电子邮件时通知我。"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"同步此帐户中的联系人"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"同步此帐户中的日历"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"同步此帐户中的电子邮件"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"默认情况下从此帐户发送电子邮件。"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"收到电子邮件时通知我。"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"同步此帐户下的联系人。"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"同步此帐户下的日历。"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"同步此帐户中的电子邮件。"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"连接到 Wi-Fi 后自动下载附件"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"无法完成"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"要同步的天数"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"一个月"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"全部"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"使用帐户的默认设置"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"用户名或密码不正确。"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"用户名或密码不正确。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"用户名或密码不正确。"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"用户名或密码不正确。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"无法安全地连接到服务器。"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"无法安全地连接到服务器。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"需要客户端证书。要通过客户端证书连接到服务器吗?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"证书无效或无法使用。"</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"该服务器返回了包含错误讯息的响应。请检查您的用户名和密码,然后重试。"</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"需要客户端证书。要通过客户端证书连接到服务器吗?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"证书无效或无法使用。"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"该服务器返回了包含错误讯息的响应。请检查您的用户名和密码,然后重试。"</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"无法连接到服务器。"</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"无法连接到服务器。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"需要 TLS,但服务器不支持 TLS。"</string> @@ -340,15 +340,11 @@ <string name="account_setup_security_policies_required_fmt" msgid="5410714107656671761">"“<xliff:g id="SERVER">%s</xliff:g>”服务器要求您允许其远程控制您 Android 设备的某些安全功能。您想要完成此帐户设置吗?"</string> <string name="account_setup_failed_security_policies_unsupported" msgid="3210264746877120355">"您的 Android 设备不支持此服务器要求使用的安全功能,其中包括:<xliff:g id="ERROR">%s</xliff:g>"</string> <string name="account_setup_username_uneditable_error" msgid="1618869759801584109">"您无法更改帐户的用户名。要添加使用其他用户名的帐户,请触摸“添加帐户”。"</string> - <string name="disable_admin_warning" msgid="6196985268695592382">"警告:撤消“电子邮件”应用管理您设备的权限会删除所有需要此权限的电子邮件帐户,以及这些帐户中的电子邮件、联系人、日历活动和其他数据。"</string> + <string name="disable_admin_warning" msgid="6196985268695592382">"警告:撤消“电子邮件”应用程序管理您设备的权限会删除所有需要此权限的电子邮件帐户,以及这些帐户中的电子邮件、联系人、日历活动和其他数据。"</string> <string name="account_security_dialog_title" msgid="430041952584831904">"安全更新"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> 要求更新您的安全设置。"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"帐户“<xliff:g id="ACCOUNT">%s</xliff:g>”由于安全要求而无法同步。"</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"帐户“<xliff:g id="ACCOUNT">%s</xliff:g>”需要更新安全设置。"</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"帐户“<xliff:g id="ACCOUNT">%s</xliff:g>”已更改其安全设置,用户无需进行任何操作。"</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"需要进行安全更新"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"安全政策已更改"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"无法满足安全政策的要求"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"帐户“<xliff:g id="ACCOUNT">%s</xliff:g>”要求更新安全设置。"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"需要进行安全更新"</string> <string name="account_security_title" msgid="3511543138560418587">"设备安全性"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"“<xliff:g id="SERVER">%s</xliff:g>”服务器要求您允许其远程控制您 Android 设备的某些安全功能。"</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"编辑详情"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"您的锁定屏幕 PIN 或密码已过期。"</string> <string name="password_expired_content_title" msgid="4349518706602252979">"锁定屏幕密码已过期"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"锁定屏幕密码即将过期"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"您需要尽快更改锁定屏幕 PIN 或密码,否则系统将会清除 <xliff:g id="ACCOUNT">%s</xliff:g> 的数据。要立即更改吗?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"您必须尽快更改锁定屏幕 PIN 或密码,否则系统会清除 <xliff:g id="ACCOUNT">%s</xliff:g> 的数据。要立即更改吗?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"锁定屏幕密码已过期"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g> 的数据已从设备中清除。您可以通过更改锁定屏幕 PIN 或密码来还原这些数据。要立即更改吗?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g> 的数据已从设备中清除。您可以通过更改锁定屏幕 PIN 或密码还原这些数据。要立即更改吗?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"要舍弃未保存的更改?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"无法登录"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g> 的用户名或密码不正确。要立即更新吗?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g> 的用户名或密码错误。要立即更新吗?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"默认帐户"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"默认情况下从此帐户发送电子邮件"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"下载附件"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"通过 Wi-Fi 自动下载最新邮件的附件"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"电子邮件通知"</string> <string name="account_settings_summary" msgid="8403582255413830007">"同步频率、通知等。"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"收到电子邮件时发送通知"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"收到电子邮件时在系统栏中显示通知"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"收件箱检查频率"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"接收设置"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"用户名、密码和其他接收服务器设置"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"外发设置"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"用户名、密码和其他外发服务器设置"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"政策已执行"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"无"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"不支持的政策"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"无"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"尝试同步"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"触摸此处以同步此帐户"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"帐户名称"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"您的姓名"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"签名"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"快速回复"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"编辑您在撰写电子邮件时经常插入的文本"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"编辑撰写电子邮件时经常插入的文本"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"在您发送的邮件中附加文本"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"通知设置"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"数据使用"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"安全政策"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"编辑快速回复"</string> <string name="save_action" msgid="1988862706623227093">"保存"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"同步联系人"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"同步此帐户的联系人"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"同步日历"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"同步此帐户的日历活动"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"同步日历"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"同步此帐户的日历"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"同步电子邮件"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"同步此帐户的电子邮件"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"振动"</string> @@ -434,7 +423,7 @@ </plurals> <string name="settings_activity_title" msgid="5185915603716333904">"设置"</string> <string name="header_label_general_preferences" msgid="9204600297009680176">"常规"</string> - <string name="category_general_preferences" msgid="2742423840964045801">"应用"</string> + <string name="category_general_preferences" msgid="2742423840964045801">"应用程序"</string> <string name="general_preference_auto_advance_label" msgid="213945004511666631">"自动跳转"</string> <string name="general_preference_auto_advance_summary" msgid="6483439980032715119">"选择要在删除邮件后显示的屏幕"</string> <string name="general_preference_auto_advance_dialog_title" msgid="5405052109452503909">"跳转至"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"正在等待结果"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"有些服务器可能会花费较长的时间。"</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"文件夹"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"不允许使用设备的相机"</string> - <string name="policy_require_password" msgid="7177274900480984702">"需要设备密码"</string> - <string name="policy_password_history" msgid="5743544498302303181">"限制重复使用近期所用密码"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"强制密码在一段时间后过期"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"要求闲置设备锁定其屏幕"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"限制同步的日历活动数"</string> - <string name="policy_email_age" msgid="7144148367145424963">"限制同步的电子邮件数"</string> - <string name="quick_1" msgid="3426057697353380951">"非常感谢!"</string> - <string name="quick_2" msgid="4188036352885736617">"我觉得不错!"</string> - <string name="quick_3" msgid="8061819976353395585">"稍后我会阅读此邮件并给您回复。"</string> - <string name="quick_4" msgid="3988974084396883051">"让我们通过会议讨论一下这个问题。"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"漫游时停用了此帐户的后台同步功能。"</string> </resources> diff --git a/res/values-zh-rCN/uploader.xml b/res/values-zh-rCN/uploader.xml index 3dc5046fe..e227885cd 100644 --- a/res/values-zh-rCN/uploader.xml +++ b/res/values-zh-rCN/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"隐藏详情"</string> <string name="menu_settings" msgid="5088116127086866634">"设置"</string> <string name="format_date_uploaded" msgid="803752037646090928">"上传时间:%s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"帐户"</string> <string name="upload" msgid="2615541458361216022">"上传"</string> <string name="ok" msgid="2516349681897895312">"确定"</string> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 101c25607..292a16d9e 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"讀取電子郵件附件"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"允許這個應用程式讀取您的電子郵件附件。"</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"允許這個應用程式讀取您的電子郵件附件。"</string> <string name="permission_access_provider_label" msgid="378256653525377586">"存取電子郵件供應商資料"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"允許這個應用程式存取您的電子郵件資料庫,包括收到的郵件、寄件備份、使用者名稱和密碼。"</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"允許這個應用程式存取您的電子郵件資料庫,包括收到的郵件、送出的郵件、使用者名稱和密碼。"</string> <string name="app_name" msgid="5815426892327290362">"電子郵件"</string> <string name="compose_title" msgid="427986915662706899">"撰寫郵件"</string> <string name="debug_title" msgid="5175710493691536719">"偵錯"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"完成"</string> <string name="create_action" msgid="3062715563215392251">"建立新回應"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"刪除"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"沒有任何快速回應。"</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"沒有快速回應"</string> <string name="discard_action" msgid="6532206074859505968">"捨棄"</string> <string name="save_draft_action" msgid="6413714270991417223">"儲存草稿"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"插入快速回應"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>提到:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"包含引用文字"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"包含文字"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"請至少新增一個收件者。"</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"您必須新增至少一位收件者。"</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"部分電子郵件地址無效。"</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"檔案過大,超過附件大小限制。"</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"插入快速回應"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"已儲存"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"停止"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"已將附件另存為 <xliff:g id="FILENAME">%s</xliff:g>。"</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"無法儲存附件。"</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"傳送轉寄的郵件之前,系統會先下載郵件中一或多個附件。"</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"無法儲存附件。"</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"請注意:在傳送轉寄的郵件之前,系統會先下載郵件中一或多個附件。"</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"郵件"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"邀請"</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"無法轉寄一或多個附件。"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"無法轉寄附件"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> 登入失敗。"</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> 登入失敗。"</string> <string name="login_failed_title" msgid="7624349996212476176">"無法登入"</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"只要幾個步驟,就可以設定 Exchange ActiveSync 帳戶。"</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"電子郵件地址"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"密碼"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"預設使用這個帳戶傳送電子郵件"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"預設使用這個帳戶傳送電子郵件。"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"手動設定"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"輸入有效的電子郵件地址和密碼。"</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"複製帳戶"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"正在檢查收信伺服器設定..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"正在檢查外寄伺服器設定..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"帳戶設定"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"您的帳戶已設定完成,可以開始收發電子郵件了!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"您的帳戶已設定完成,可以收發電子郵件了!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"設定帳戶名稱 (選擇性)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"您的姓名 (顯示於外寄郵件)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"這個欄位不能留空。"</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"SMTP 伺服器"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"通訊埠"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"安全性類型"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"要求登入"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"必須登入。"</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"使用者名稱"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"密碼"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"帳戶設定"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"每 15 分鐘檢查一次"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"每 30 分鐘檢查一次"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"每小時檢查一次"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"預設使用這個帳戶傳送電子郵件"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"收到電子郵件時通知我"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"同步處理這個帳戶的聯絡人資訊"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"同步處理這個帳戶的日曆"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"同步處理這個帳戶的電子郵件"</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"設為傳送電子郵件的預設帳戶。"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"收到電子郵件時通知我。"</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"同步處理此帳戶的聯絡人。"</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"同步處理此帳戶的日曆。"</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"同步處理此帳戶所寄的電子郵件。"</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"連上 Wi-Fi 時自動下載附件。"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"無法完成"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"同步處理的天數"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"1 個月"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"全部"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"使用帳戶預設值"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"使用者名稱或密碼不正確。"</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"使用者名稱或密碼不正確。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"使用者名稱或密碼不正確。"</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"使用者名稱或密碼不正確。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"無法安全連線至伺服器。"</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"無法安全連線至伺服器。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"需要用戶端憑證,您要透過用戶端憑證連線到伺服器嗎?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"憑證無效或無法使用。"</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"伺服器傳回錯誤,請檢查您的使用者名稱和密碼,然後再試一次。"</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"需要用戶端憑證。您要透過用戶端憑證連線至伺服器嗎?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"憑證無效或無法使用。"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"伺服器傳回錯誤,請檢查您的使用者名稱和密碼,然後再試一次。"</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"無法連線至伺服器。"</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"無法連線至伺服器。"\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"必須使用 TLS,但此伺服器不支援。"</string> @@ -343,12 +343,8 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"警告:如果停用「電子郵件」應用程式的裝置管理權限,系統將刪除所有需要使用這項權限的「電子郵件」帳戶,以及帳戶中所有的電子郵件、聯絡人、日曆活動和其他資料。"</string> <string name="account_security_dialog_title" msgid="430041952584831904">"安全性更新"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"您必須更新 <xliff:g id="ACCOUNT">%s</xliff:g> 的安全性設定。"</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"因為不符合安全性需求,系統無法同步處理「<xliff:g id="ACCOUNT">%s</xliff:g>」帳戶。"</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"「<xliff:g id="ACCOUNT">%s</xliff:g>」帳戶的安全性設定必須更新。"</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"「<xliff:g id="ACCOUNT">%s</xliff:g>」帳戶已自行變更安全性設定,使用者不需採取任何行動。"</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"安全性必須更新"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"安全性政策已變更"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"不符合安全性政策標準"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"「<xliff:g id="ACCOUNT">%s</xliff:g>」帳戶必須進行安全性設定更新。"</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"必須更新安全性"</string> <string name="account_security_title" msgid="3511543138560418587">"裝置安全性"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"<xliff:g id="SERVER">%s</xliff:g> 伺服器要求您的授權,使其可遠端控制 Android 裝置的一些安全性功能。"</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"請編輯資料"</string> @@ -357,45 +353,38 @@ <string name="password_expired_ticker" msgid="4230570412974108968">"您的螢幕上鎖 PIN 或密碼已過期。"</string> <string name="password_expired_content_title" msgid="4349518706602252979">"螢幕上鎖密碼已過期"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"螢幕上鎖密碼即將過期"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"您必須儘快變更螢幕上鎖 PIN 或密碼,否則 <xliff:g id="ACCOUNT">%s</xliff:g> 的資料將遭到清除,要立即變更嗎?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"您必須儘快變更螢幕上鎖 PIN 或密碼,否則 <xliff:g id="ACCOUNT">%s</xliff:g> 的資料將遭到清除,要立即變更嗎?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"螢幕鎖定密碼已過期"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"<xliff:g id="ACCOUNT">%s</xliff:g> 的資料已從您的裝置中清除,如要還原這些資料,請變更螢幕上鎖 PIN 或密碼,要立即變更嗎?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"<xliff:g id="ACCOUNT">%s</xliff:g> 的資料已從您的裝置中清除,如要還原這些資料,請變更螢幕上鎖 PIN 或密碼,要立即變更嗎?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"要捨棄尚未儲存的變更?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"無法登入"</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"<xliff:g id="ACCOUNT">%s</xliff:g> 的使用者名稱或密碼不正確。您要現在更新嗎?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"<xliff:g id="ACCOUNT">%s</xliff:g> 的使用者名稱或密碼不正確,要立即更新嗎?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"預設帳戶"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"預設使用這個帳戶傳送電子郵件"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"下載附件"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"透過 WiFi 自動下載最新郵件的附件"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"電子郵件通知"</string> <string name="account_settings_summary" msgid="8403582255413830007">"同步處理頻率和通知等其他設定"</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"收到電子郵件時傳送通知"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"收到電子郵件時,在系統列中顯示通知"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"收件匣檢查頻率"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"內收設定"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"使用者名稱、密碼和其他內送伺服器設定"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"外寄設定"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"使用者名稱、密碼和其他外寄伺服器設定"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"強制執行的政策"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"無"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"不支援的政策"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"無"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"嘗試同步處理"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"輕觸這裡即可同步處理這個帳戶"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"帳戶名稱"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"您的姓名"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"簽名檔"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"快速回應"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"編輯您撰寫電子郵件時經常插入的文字"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"編輯您撰寫電子郵件時經常插入的文字"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"在送出的郵件後面附加文字"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"通知設定"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"資料用量"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"安全性政策"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"編輯快速回應"</string> <string name="save_action" msgid="1988862706623227093">"儲存"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"同步處理聯絡人"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"同步處理此帳戶的聯絡人"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"同步處理日曆"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"同步處理這個帳戶的日曆活動"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"同步處理日曆"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"同步處理此帳戶的日曆"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"同步處理電子郵件"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"同步處理此帳戶的電子郵件"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"震動"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"正在等待結果"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"有些伺服器可能需要較長的時間。"</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"資料夾"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"不允許使用裝置相機"</string> - <string name="policy_require_password" msgid="7177274900480984702">"需要裝置密碼"</string> - <string name="policy_password_history" msgid="5743544498302303181">"限制重複使用最近用過的密碼"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"強制密碼到期"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"要求裝置在閒置時鎖定螢幕"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"限制同步處理的日曆活動數量"</string> - <string name="policy_email_age" msgid="7144148367145424963">"限制同步處理的電子郵件數量"</string> - <string name="quick_1" msgid="3426057697353380951">"感謝您!"</string> - <string name="quick_2" msgid="4188036352885736617">"這主意不錯!"</string> - <string name="quick_3" msgid="8061819976353395585">"我稍晚看過後回覆您。"</string> - <string name="quick_4" msgid="3988974084396883051">"開會討論吧。"</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"系統會在漫遊時停用這個帳戶的背景同步處理。"</string> </resources> diff --git a/res/values-zh-rTW/uploader.xml b/res/values-zh-rTW/uploader.xml index 3fd744b66..4b32be321 100644 --- a/res/values-zh-rTW/uploader.xml +++ b/res/values-zh-rTW/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"隱藏詳細資料"</string> <string name="menu_settings" msgid="5088116127086866634">"設定"</string> <string name="format_date_uploaded" msgid="803752037646090928">"上傳日期:%s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"帳戶"</string> <string name="upload" msgid="2615541458361216022">"上傳"</string> <string name="ok" msgid="2516349681897895312">"確定"</string> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 5d508f528..0c7ca0b0b 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -17,9 +17,9 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permission_read_attachment_label" msgid="9208086010625033590">"Funda okunamathiselwe kwi-imeyili"</string> - <string name="permission_read_attachment_desc" msgid="3394721085306308972">"Ivumela i-app ukufunda okunamathiselwe kwe-imeyili yakho."</string> + <string name="permission_read_attachment_desc" msgid="6592948507403743153">"Ivumela lolu hlelo lokusebenza ukuba lufunde izinamathiseli zakho ze-imeyli."</string> <string name="permission_access_provider_label" msgid="378256653525377586">"Finyelela kwimininingo yomhlinzeki we-imeyli"</string> - <string name="permission_access_provider_desc" msgid="6296566558584670348">"Ivumela lolu hlelo lokusebenza ukufinyelela kumininingo yakho egciniwe ye-Imeyili, kuhlanganise imiyalezo etholiwe, imiyalezo ethunyelwe, amagama abasebenzisi kanye namaphasiwedi."</string> + <string name="permission_access_provider_desc" msgid="2221907862438022705">"Ivumela lolu hlelo lokusebenza ukufinyelela kumininingo yakho egciniwe ye-Imeyili, kuhlanganise imiyalezo etholiwe, imiyalezo ethunyelwe, amagama abasebenzisi kanye namaphasiwedi."</string> <string name="app_name" msgid="5815426892327290362">"I-imeyli"</string> <string name="compose_title" msgid="427986915662706899">"Bhala"</string> <string name="debug_title" msgid="5175710493691536719">"Lungisa iphutha"</string> @@ -36,7 +36,7 @@ <string name="done_action" msgid="7497990549515580249">"Kwenziwe"</string> <string name="create_action" msgid="3062715563215392251">"Yenza okusha"</string> <string name="delete_quick_response_action" msgid="3076922270182841978">"Susa"</string> - <string name="quick_responses_empty_view" msgid="3960050972306132367">"Azikho izimpendulo ezisheshayo."</string> + <string name="quick_responses_empty_view" msgid="1693308598242828422">"Azikho izimpendulo ezisheshayo"</string> <string name="discard_action" msgid="6532206074859505968">"Lahla"</string> <string name="save_draft_action" msgid="6413714270991417223">"Londoloza okusazolungiswa"</string> <string name="show_quick_text_list_dialog_action" msgid="4136018559611145202">"Faka impendulo esheshayo"</string> @@ -133,7 +133,7 @@ <string name="message_compose_reply_header_fmt" msgid="8815624773273454573">\n\n"<xliff:g id="SENDER">%s</xliff:g>ubhale:"\n\n</string> <string name="message_compose_quoted_text_label" msgid="6950097435198536165">"Hlanganisa umbhalo ocashuniwe"</string> <string name="message_compose_include_quoted_text_checkbox_label" msgid="8165567368956050390">"Hlanganisa umbhalo"</string> - <string name="message_compose_error_no_recipients" msgid="140299472517968199">"Ngeza okungenani umamukeli oyedwa."</string> + <string name="message_compose_error_no_recipients" msgid="4903715888250785486">"Kumelwe wengeze okungenani umamukeli oyedwa."</string> <string name="message_compose_error_invalid_email" msgid="1817633338629885643">"Amanye amakheli e-imeyili awalungile."</string> <string name="message_compose_attachment_size" msgid="4401081828287333647">"Ifayela inkulu kakhulu ukuba inamathiselwe."</string> <string name="message_compose_insert_quick_response_list_title" msgid="5314107302508728189">"Faka izimpendulo ezisheshayo"</string> @@ -153,8 +153,8 @@ <string name="message_view_attachment_saved" msgid="3432810414785232025">"Kulondoloziwe"</string> <string name="message_view_attachment_cancel_action" msgid="316700885943712101">"Misa"</string> <string name="message_view_status_attachment_saved" msgid="8878790392556284868">"Isinamathiseli silondolozwe njenge-<xliff:g id="FILENAME">%s</xliff:g>."</string> - <string name="message_view_status_attachment_not_saved" msgid="4013475734255421939">"Ayikwazanga ukugcina okunamathiselwe."</string> - <string name="message_view_attachment_background_load" msgid="7906875687519445185">"Eyodwa noma eyengeziwe yezinamathiseli kumlayezo wakho odluliselwe izolandwa ngaphambi kokuthumelwa."</string> + <string name="message_view_status_attachment_not_saved" msgid="2433097334272991035">"Yehlulekile ukulondoloza okuxhunyiwe."</string> + <string name="message_view_attachment_background_load" msgid="756797444835526487">"Yazi: Eyodwa noma eyengeziwe yezinamathiseli kumyalezo wakho odluliselwe izolandwa ngaphambi kokuthumelwa."</string> <string name="message_view_show_message_action" msgid="5134222901019191436">"Umyalezo"</string> <string name="message_view_show_invite_action" msgid="8862797393776226777">"Mema..."</string> <plurals name="message_view_show_attachments_action"> @@ -210,7 +210,7 @@ </plurals> <string name="forward_download_failed_ticker" msgid="6176608320359303255">"Ayikwazi ukudlulisa isinamathiseli esisodwa noma ezengeziwe"</string> <string name="forward_download_failed_title" msgid="6139701848515572511">"Okunamathiselwa kwi-imeyli akuthunyelwanga"</string> - <string name="login_failed_ticker" msgid="2169365211566829350">"I-<xliff:g id="ACCOUNT_NAME">%s</xliff:g> ingene ngemvume ngempumelelo."</string> + <string name="login_failed_ticker" msgid="5749227022559285302">"<xliff:g id="ACCOUNT_NAME">%s</xliff:g> ukungena ngemvume kwehlulekile"</string> <string name="login_failed_title" msgid="7624349996212476176">"Ayikwazanga ukungena ngemvume."</string> <plurals name="message_view_attachment_bytes"> <item quantity="one" msgid="8914124732074848509">"<xliff:g id="SIZE_IN_BYTES">%d</xliff:g>B"</item> @@ -240,7 +240,7 @@ <string name="accounts_welcome_exchange_alternate" msgid="1319376442032224845">"Ungamisa i-akhawunti ye-Exchange ActiveSync ngezinyathelo ezimbalwa nje."</string> <string name="account_setup_basics_email_label" msgid="3454164053624112047">"Ikheli le-imeyli"</string> <string name="account_setup_basics_password_label" msgid="9133549799291519298">"Iphasiwedi"</string> - <string name="account_setup_basics_default_label" msgid="8896222991837026736">"Thumela i-imeyli kusuka kule akhawunti ngokwakhona"</string> + <string name="account_setup_basics_default_label" msgid="5924790142029806711">"Thumela i-imeyli kusuka kule akhawunti ngokuzenzakalelayo"</string> <string name="account_setup_basics_manual_setup_action" msgid="8053852205391155912">"Ukumisela"</string> <string name="account_setup_username_password_toast" msgid="3968270274727947460">"Sicela uthayiphe ikheli le-imeyili elilungile kanye nephasiwedi."</string> <string name="account_duplicate_dlg_title" msgid="8089732986912704425">"I-akhawunti Ephindiwe"</string> @@ -250,7 +250,7 @@ <string name="account_setup_check_settings_check_incoming_msg" msgid="5356212700221438863">"Ihlola izilungiselelo zesiphakeli ezingenayo..."</string> <string name="account_setup_check_settings_check_outgoing_msg" msgid="4033015234096725343">"Ihlola izilungiselelo zesiphakeli eziphumayo..."</string> <string name="account_setup_names_title" msgid="8483517350241119291">"Ukumisa i-akhawunti"</string> - <string name="account_setup_names_headline" msgid="914858472109729140">"I-akhawunti yakho imisiwe, futhi i-imeyli isendleleni!"</string> + <string name="account_setup_names_headline" msgid="2413440250372658881">"I-akhawunti yakho imisiwe, futhi i-imeyli isendleleni!"</string> <string name="account_setup_names_account_name_label" msgid="8033895024273259196">"Nike le-akhawunti igama (okokuzikhethela)"</string> <string name="account_setup_names_user_name_label" msgid="8967410178488604770">"Igama lakho (liboniswa emiyalezweni ephumayo)"</string> <string name="account_setup_names_user_name_empty_error" msgid="6791427018325367364">"Lesi sikhundla akumele singabi nalutho."</string> @@ -280,7 +280,7 @@ <string name="account_setup_outgoing_smtp_server_label" msgid="6035137446691195177">"Iseva ye-SMTP"</string> <string name="account_setup_outgoing_port_label" msgid="7573207437835827876">"Imbobo yokuxhuma"</string> <string name="account_setup_outgoing_security_label" msgid="911398071120720589">"Uhlobo lokuphepha"</string> - <string name="account_setup_outgoing_require_login_label" msgid="7779484127897397562">"Kudingeka ukungena ngemvume"</string> + <string name="account_setup_outgoing_require_login_label" msgid="6371514297854287948">"Dinga ukungena."</string> <string name="account_setup_outgoing_username_label" msgid="3309680794731596981">"Igama lomsebenzisi"</string> <string name="account_setup_outgoing_password_label" msgid="227844585493317550">"Iphasiwedi"</string> <string name="account_setup_exchange_title" msgid="396004732514751781">"Ukuhlela i-akhawunti"</string> @@ -305,11 +305,11 @@ <string name="account_setup_options_mail_check_frequency_15min" msgid="5052776740089741793">"Njalo ngamaminithi angu-15"</string> <string name="account_setup_options_mail_check_frequency_30min" msgid="1097088928685931864">"Njalo ngamaminithi angu-30"</string> <string name="account_setup_options_mail_check_frequency_1hour" msgid="3767715356039692899">"Njalo ngehora"</string> - <string name="account_setup_options_default_label" msgid="2617227194283720914">"Thumela i-imeyli kusuka kule akhawunti ngokuzenzakalelayo"</string> - <string name="account_setup_options_notify_label" msgid="7046146571560728829">"Ngazise lapho i-imeyli ifika"</string> - <string name="account_setup_options_sync_contacts_label" msgid="276492345599531778">"Vumelanisa othintana nabo kusuka kule akhawunti"</string> - <string name="account_setup_options_sync_calendar_label" msgid="3222151135467189411">"Vumelanisa ikhalenda kule akhawunti"</string> - <string name="account_setup_options_sync_email_label" msgid="8585177128405004068">"Vumelanisa i-imeyli kule akhawunti."</string> + <string name="account_setup_options_default_label" msgid="8869166381331276697">"Thumela i-imeyli kusuka kule akhawunti ngokuzenzakalelayo"</string> + <string name="account_setup_options_notify_label" msgid="1247525794828820038">"Ngazise lapho i-imeyli ifika."</string> + <string name="account_setup_options_sync_contacts_label" msgid="7467467090023434271">"Vumelanisa othintana nabo kusuka kule akhawunti."</string> + <string name="account_setup_options_sync_calendar_label" msgid="3195979658426293931">"Vumelanisa ikhalenda kule akhawunti."</string> + <string name="account_setup_options_sync_email_label" msgid="3930927721878987383">"Vumelanisa i-imeyli kule akhawunti."</string> <string name="account_setup_options_background_attachments_label" msgid="5247749298276451846">"Layisha okunamathiselwa kwi-imeyili ngokuzenzakalelayo uma uxhunyiwe kukuxhuma kungenazintambo"</string> <string name="account_setup_failed_dlg_title" msgid="9083263347962940552">"Ayikwazanga ukuqeda"</string> <string name="account_setup_options_mail_window_label" msgid="7582247646138987328">"Izinsuku zokuvumelanisa"</string> @@ -321,13 +321,13 @@ <string name="account_setup_options_mail_window_1month" msgid="5846359669750047081">"Inyanga eyodwa"</string> <string name="account_setup_options_mail_window_all" msgid="5372861827683632364">"Konke"</string> <string name="account_setup_options_mail_window_default" msgid="8321351926520165832">"Sebenzisa okuzenzakalelayo kwe-akhawunti"</string> - <string name="account_setup_failed_dlg_auth_message" msgid="426627755590431364">"Igama lakho lomsebenzisi noma iphasiwedi ayilungile."</string> - <string name="account_setup_failed_dlg_auth_message_fmt" msgid="737111956772240007">"Igama lomsebenzisi noma iphasiwedi ayilungile."\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> + <string name="account_setup_failed_dlg_auth_message" msgid="42827150104879570">"Igama lomsebenzisi noma iphasiwedi ayilungile."</string> + <string name="account_setup_failed_dlg_auth_message_fmt" msgid="8598560266430207606">"Igama lomsebenzisi noma iphasiwedi ayilungile."\n"<xliff:g id="ERROR">%s</xliff:g>"</string> <string name="account_setup_failed_dlg_certificate_message" msgid="3836152264696108805">"Ayikwazi ukuxhuma ngokuphephile kwiseva."</string> <string name="account_setup_failed_dlg_certificate_message_fmt" msgid="2121921642915593041">"Ayikwazi ukuxhuma ngokuphephile kwiseva. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> - <string name="account_setup_failed_certificate_required" msgid="2689944595775206006">"Isititiketi seklayenti siyadingeka. Ingabe ufuna ukuxhuma kuseva ngesitifiketi seklayenti?"</string> - <string name="account_setup_failed_certificate_inaccessible" msgid="3563840279690749547">"Isitifiketi asivumelekile noma asifinyeleleki."</string> - <string name="account_setup_failed_check_credentials_message" msgid="6531658092540248067">"Iseva iphendule ngephutha, sicela uhlole igama lakho lomsebenzisi nephasiwedi bese uzama futhi."</string> + <string name="account_setup_failed_certificate_required" msgid="1280569002588325367">"Kudingeka isitifiketi sekhasimende. Xhuma esiphakelini ngesitifiketi sekhasimende?"</string> + <string name="account_setup_failed_certificate_inaccessible" msgid="7245835883180762722">"Isitifiketi asivumelekile noma asingeneki"</string> + <string name="account_setup_failed_check_credentials_message" msgid="222908719765968691">"Iseva iphendule ngephutha, sicela uhlole igama lakho lomsebenzisi nephasiwedi bese uzama futhi."</string> <string name="account_setup_failed_dlg_server_message" msgid="4942810054116129684">"Ayikwazi ukuxhuma kwiseva."</string> <string name="account_setup_failed_dlg_server_message_fmt" msgid="2525425638303883232">"Ayikwazi ukuxhuma kwiseva. "\n"(<xliff:g id="ERROR">%s</xliff:g>)"</string> <string name="account_setup_failed_tls_required" msgid="307030406688611327">"I-TLS iyadingeka kodwa ayisekelwa iseva."</string> @@ -343,59 +343,48 @@ <string name="disable_admin_warning" msgid="6196985268695592382">"ISEXWAYISO: Yenza kungasebenzi imvume yohlelo lokusebenza lwe-Imeyli ukubhalisa idivaysi yakho kuzosusa wonke ama-akhawunti e-Imeyli ayidingayo, kuhlanganise ne-imeyli yayo, othintana nabo, amakhalenda, izenzakalo, neminye imininingo."</string> <string name="account_security_dialog_title" msgid="430041952584831904">"Okwakamuva kwezokuphepha"</string> <string name="account_security_dialog_content_fmt" msgid="8843806143923278214">"<xliff:g id="ACCOUNT">%s</xliff:g> idinga ukuba ubuyekeze izilungiselelo zakho zokuzivikela."</string> - <string name="security_unsupported_ticker_fmt" msgid="5166579214529283975">"I-Akhawuni \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ayikwazi ukuvumelanisa ngenxa yezimfuneko sokuphepha."</string> - <string name="security_needed_ticker_fmt" msgid="2120499087897133665">"I-Akhawunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" idinga ukubuyekeza izilungiselelo zokuphepha."</string> - <string name="security_changed_ticker_fmt" msgid="2609435447352755285">"I-Akhawunti \"<xliff:g id="ACCOUNT">%s</xliff:g>\" ishintshe izilungiselelo zayo zokuphepha; asikho isenzo somsebenzisi esidingekayo."</string> - <string name="security_notification_content_update_title" msgid="2429762903228690154">"Ukubuyekeza ezokuphepha kuyadingeka"</string> - <string name="security_notification_content_change_title" msgid="443490921895642130">"Izinqubomgomo zokuphepha zishintshiwe"</string> - <string name="security_notification_content_unsupported_title" msgid="7315219208043169233">"Izinqubomgomo zokuphepha azikwazi ukuhlangabezwa"</string> + <string name="security_notification_ticker_fmt" msgid="1108023476125276507">"i-Akhawunti \" <xliff:g id="ACCOUNT">%s</xliff:g> \" idinga ukubuyekeza izilungiselelo zokuphepha."</string> + <string name="security_notification_content_title" msgid="3352841884304076235">"Ukubuyekeza kwezokuphepha kuyadingeka"</string> <string name="account_security_title" msgid="3511543138560418587">"Ukuphepha kweDivaysi"</string> <string name="account_security_policy_explanation_fmt" msgid="6932627044314460766">"Iseva <xliff:g id="SERVER">%s</xliff:g> idinga ukuba uyivumele ukuba ilawule kude ezinye izici zokuphepha kwedivayisi ye-Android."</string> <string name="account_setup_failed_dlg_edit_details_action" msgid="5355993309841479360">"Hlela imininingwane"</string> - <string name="password_expire_warning_ticker_fmt" msgid="2459977229180023773">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" idinga ukuba ushintshe iphinikhodi yokuvala isikrini noma iphasiwedi"</string> + <string name="password_expire_warning_ticker_fmt" msgid="2459977229180023773">"\"<xliff:g id="ACCOUNT">%s</xliff:g>\" idinga ukuba ushintshe iphinikhodi yokuvala isikrini noma i-password"</string> <string name="password_expire_warning_content_title" msgid="7174669014074849304">"Iphasiwedi yokuvala isikrini iphelelwa isikhathi"</string> <string name="password_expired_ticker" msgid="4230570412974108968">"Iphinikhodi noma iphasiwedi yakho yokuvala isikrini iphelelwe isikhathi."</string> <string name="password_expired_content_title" msgid="4349518706602252979">"Iphasiwedi yokuvala isikrini iphelelwe isikhathi"</string> <string name="password_expire_warning_dialog_title" msgid="1687074175399798189">"Iphasiwedi yesikrini yokuvala iphelelwa isikhathi"</string> - <string name="password_expire_warning_dialog_content_fmt" msgid="4293446611405084436">"Udinga ukushintsha i-PIN yesikrini sakho sokukhuya noma iphasiwedi ngokushesha, noma idatha ye-<xliff:g id="ACCOUNT">%s</xliff:g> izosulwa. Ufuna ukuyishintsha manje?"</string> + <string name="password_expire_warning_dialog_content_fmt" msgid="4595246020880351045">"Kumele ushintshe iphinikhodi noma iphasiwedi yokuvala isikrini maduze, noma idatha ye-<xliff:g id="ACCOUNT">%s</xliff:g> izosulwa. Ishintshe manje?"</string> <string name="password_expired_dialog_title" msgid="2186547998125938084">"Iphasiwedi yokuvala isikrini iphelelwe isikhathi"</string> - <string name="password_expired_dialog_content_fmt" msgid="6538210092073931079">"Idatha le-<xliff:g id="ACCOUNT">%s</xliff:g> lisuliwe kudivayisi. Ungalibuyisa ngokushintsha i-PIN yakho yokukhiya isikrini noma iphasiwedi. Ufuna ukuyishintsha manje?"</string> + <string name="password_expired_dialog_content_fmt" msgid="5982207349002500211">"Idatha ye-<xliff:g id="ACCOUNT">%s</xliff:g> iyasulwa kudivayisi yakho. Ungayibuyisa ngokushintsha iphinikhodi yakho yokuvala isikrini noma iphasiwedi. Ishintshe manje?"</string> <string name="account_settings_exit_server_settings" msgid="8006323251094711431">"Lahla izinguquko ezingagciniwe?"</string> <string name="account_settings_login_dialog_title" msgid="4024422579146302775">"Ayikwazanga ukungena ngemvume."</string> - <string name="account_settings_login_dialog_content_fmt" msgid="8849649646111167377">"Igama lomsebenzisi noma iphasiwedi ye-<xliff:g id="ACCOUNT">%s</xliff:g> ayilungile. Ufuna ukuzivuselela manje?"</string> + <string name="account_settings_login_dialog_content_fmt" msgid="3492735234999710234">"Igama lomsebenzisi noma iphasiwedi ye-<xliff:g id="ACCOUNT">%s</xliff:g> ayilungile. Wabuyekeze manje?"</string> <string name="account_settings_default_label" msgid="3575963379680943640">"I-akhawunti ezenzakalelayo"</string> <string name="account_settings_default_summary" msgid="1531901438624688482">"Thumela i-imeyli kusuka kule akhawunti ngokuzenzakalelayo"</string> <string name="account_settings_background_attachments_label" msgid="2980317599840958688">"Layisha ngokungenisa okunamathelayo"</string> <string name="account_settings_background_attachments_summary" msgid="5954218549226189376">"Dawuniloda ngokuzenzakalla ukunamathiseleka emiyalezweni yakamuva nge-Wi-Fi"</string> <string name="account_settings_notify_label" msgid="1630001017303007974">"Izaziso ze-Imeyli"</string> <string name="account_settings_summary" msgid="8403582255413830007">"Ukuvama kokuvumelanisa, isaziso, nokunye."</string> - <string name="account_settings_notify_summary" msgid="8134339460923068254">"Thumela isaziso uma i-imeyili ifika"</string> + <string name="account_settings_notify_summary" msgid="6301122709602752038">"Ngazise Kusistimu ochaza ngesimo uma i-imeyli ifika"</string> <string name="account_settings_mail_check_frequency_label" msgid="8271462919214560616">"Ukuvama ukuhlola ibhokisi lemiyalezo engenayo"</string> <string name="account_settings_incoming_label" msgid="7858928031806297542">"Izilungiselelo ezingenayo"</string> <string name="account_settings_incoming_summary" msgid="2923044634831881068">"Igama lombebenzisi, iphasiwedi, nezinye izilungiselelo zeseva ezingenayo"</string> <string name="account_settings_outgoing_label" msgid="4464829249980026745">"Izilungiselelo eziphumayo"</string> <string name="account_settings_outgoing_summary" msgid="3572093624332724311">"Igama lomsebenzisi, iphasiwedi, nezinye izilungiselelo zeseva eziphumayo"</string> - <string name="account_settings_enforced_label" msgid="7429582254433588882">"Izinqubomgomo ziphoqiwe"</string> - <string name="account_settings_enforced_summary" msgid="8140860420440447771">"Lutho"</string> - <string name="account_settings_unsupported_label" msgid="1954091071454235577">"Izinqubomo ezingasekelwe"</string> - <string name="account_settings_unsupported_summary" msgid="2107633813351863608">"Lutho"</string> - <string name="account_settings_retry_label" msgid="1104680719299842829">"Zama ukuvumelanisa"</string> - <string name="account_settings_retry_summary" msgid="2703599639846201913">"Thinta lapha ukuze uvumelanise le akhawunti"</string> <string name="account_settings_description_label" msgid="8894815221204511715">"Igama le-akhawunti"</string> <string name="account_settings_name_label" msgid="8186406122590008449">"Igama lakho"</string> <string name="account_settings_signature_label" msgid="4091969938785803201">"Isiginesha"</string> <string name="account_settings_edit_quick_responses_label" msgid="3106019627675996480">"Izimpendulo ezisheshayo"</string> - <string name="account_settings_edit_quick_responses_summary" msgid="8056686122888722591">"Hlela umbhalo owusebenzisa njalo uma ubhala ama-imeyli"</string> + <string name="account_settings_edit_quick_responses_summary" msgid="5284435342418252369">"Hlela umbhalo owusebenzisa njalo uma ubhala ama-imeyli"</string> <string name="account_settings_signature_hint" msgid="7262183168962779403">"Jobelela umbhalo emiyalezweni oyithumelayo"</string> <string name="account_settings_notifications" msgid="1042620094281375043">"Izilungiselelo zesaziso"</string> <string name="account_settings_data_usage" msgid="6669107430575866736">"Ukusebenzisa idatha"</string> - <string name="account_settings_policies" msgid="6292833636418641840">"Izinqubomgomo zokuphepha"</string> <string name="edit_quick_response_dialog" msgid="4322494050816995390">"Hlela izimpendulo ezisheshayo"</string> <string name="save_action" msgid="1988862706623227093">"Londoloza"</string> <string name="account_settings_sync_contacts_enable" msgid="1369272986009573218">"Vumelanisa othintana nabo"</string> <string name="account_settings_sync_contacts_summary" msgid="816919452270997919">"Vumelanisa othintana nabo bale akhawunti"</string> - <string name="account_settings_sync_calendar_enable" msgid="6855333393468628003">"Vumelanisa ikhalenda"</string> - <string name="account_settings_sync_calendar_summary" msgid="7606340353079301703">"Vumelanisa umcimbi wekhalenda kule akhawunti"</string> + <string name="account_settings_sync_calendar_enable" msgid="3039820725699412208">"Vumelanisa Ikhalenda"</string> + <string name="account_settings_sync_calendar_summary" msgid="5241995538395965804">"Vumelanisa ikhalenda yale akhawunti"</string> <string name="account_settings_sync_email_enable" msgid="3754115565685222477">"Vumelanisa i-imeyli"</string> <string name="account_settings_sync_email_summary" msgid="262964076412310990">"Vumelanisa i-imeyli yale akhawunti"</string> <string name="account_settings_vibrate_when_label" msgid="708477308761702671">"Dlidliza"</string> @@ -477,16 +466,5 @@ <string name="search_slow_warning_title" msgid="2826118321880530239">"Ilinde imiphumela"</string> <string name="search_slow_warning_message" msgid="8494483410797387903">"Amanye amaseva angathatha isikhathi eside."</string> <string name="action_bar_mailbox_list_title" msgid="7484457755531286333">"Amafolda"</string> - <string name="policy_dont_allow_camera" msgid="5744573062306937302">"Ungavumeli ukusebenza kwekhamera yedivayisi"</string> - <string name="policy_require_password" msgid="7177274900480984702">"Idinga iphasiwedi yedivayisi"</string> - <string name="policy_password_history" msgid="5743544498302303181">"Khawulela ukusetshenziswa kabusha kwamaphasiwedi wakamuva"</string> - <string name="policy_password_expiration" msgid="1248123255253649199">"Cela ukuthi amaphasiwedi aphalwe isikhathi"</string> - <string name="policy_screen_timeout" msgid="414869965358468080">"Dinga idivayisi yokumisa ukukhiya isikrini sayo"</string> - <string name="policy_calendar_age" msgid="627405158087482302">"Khawulela inombolo yemicimbi yekhalenda evunyelanisiwe"</string> - <string name="policy_email_age" msgid="7144148367145424963">"Khawulela inombolo yama-imeyili avumelanisiwe"</string> - <string name="quick_1" msgid="3426057697353380951">"Siyabonga!"</string> - <string name="quick_2" msgid="4188036352885736617">"Kuzwaka kukuhle kimi!"</string> - <string name="quick_3" msgid="8061819976353395585">"Ngizofunda lokho emvakwesikhashana."</string> - <string name="quick_4" msgid="3988974084396883051">"Masihlele umhlangano ukuxoxisana ngalokhu."</string> <string name="require_manual_sync_message" msgid="7777357288642785955">"Ukuvumelaniswa okungemumva kule-akhawunti ayisebenzi ngesikhathi usazula zula."</string> </resources> diff --git a/res/values-zu/uploader.xml b/res/values-zu/uploader.xml index 60a78f11a..47750deb7 100644 --- a/res/values-zu/uploader.xml +++ b/res/values-zu/uploader.xml @@ -26,7 +26,7 @@ <string name="menu_hide_completed_items" msgid="6126007571523662799">"Fihla imininingwane"</string> <string name="menu_settings" msgid="5088116127086866634">"Izilungiselelo"</string> <string name="format_date_uploaded" msgid="803752037646090928">"Kulayishiwe %s"</string> - <string name="format_progress_percent" msgid="4347398038122210157">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> + <string name="format_progress_percent" msgid="1420459750508777491">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENTSIGN">%%</xliff:g>"</string> <string name="account" msgid="5199161365824352613">"I-akhawunti"</string> <string name="upload" msgid="2615541458361216022">"Layisha"</string> <string name="ok" msgid="2516349681897895312">"KULUNGILE"</string> diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 6232e6527..c881e6eb9 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -185,14 +185,6 @@ <item>@string/mailbox_name_display_junk</item> </string-array> - <!-- A small number of default quick responses --> - <string-array name="default_quick_responses"> - <item>@string/quick_1</item> - <item>@string/quick_2</item> - <item>@string/quick_3</item> - <item>@string/quick_4</item> - </string-array> - <!-- Arrays "mailbox_display_names" and "mailbox_display_icons" MUST match the order of the types of mailboxes defined in EmailContent --> <array name="mailbox_display_icons" translatable="false"> diff --git a/res/values/strings.xml b/res/values/strings.xml index 67fcb3dd6..3a89687b5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -19,12 +19,12 @@ <!-- Permissions label for reading attachments --> <string name="permission_read_attachment_label">Read email attachments</string> <!-- Permissions description for reading attachments --> - <string name="permission_read_attachment_desc">Allows the app to read your email + <string name="permission_read_attachment_desc">Allows this application to read your email attachments.</string> <!-- Permissions label for accessing the main provider --> <string name="permission_access_provider_label">Access email provider data</string> <!-- Permissions description for accessing the main provider --> - <string name="permission_access_provider_desc">Allows the app to access your email + <string name="permission_access_provider_desc">Allows this application to access your email database, including received messages, sent messages, usernames, and passwords.</string> <!-- Name of application on Home screen --> @@ -66,7 +66,7 @@ <string name="delete_quick_response_action">Delete</string> <!-- Message informing user when a list that would contain quick responses is empty [CHAR_LIMIT=80] --> - <string name="quick_responses_empty_view">No quick responses.</string> + <string name="quick_responses_empty_view">No quick responses</string> <!-- Menu item/button name --> <string name="discard_action">Discard</string> <!-- Menu item/button name [CHAR_LIMIT=16] --> @@ -315,7 +315,7 @@ [CHAR_LIMIT=32] --> <string name="message_compose_include_quoted_text_checkbox_label">Include text</string> <!-- Toast that appears if you try to send with no recipients. --> - <string name="message_compose_error_no_recipients">Add at least one recipient.</string> + <string name="message_compose_error_no_recipients">You must add at least one recipient.</string> <!-- An address field contains invalid email addresses. --> <string name="message_compose_error_invalid_email">Some email addresses are invalid.</string> <!-- Toast that appears when an attachment is too big to send. --> @@ -357,10 +357,10 @@ <string name="message_view_status_attachment_saved">Attachment saved as <xliff:g id="filename">%s</xliff:g>.</string> <!-- Toast after attachment could not be saved [CHAR LIMIT=30] --> - <string name="message_view_status_attachment_not_saved">Couldn\'t save attachment.</string> + <string name="message_view_status_attachment_not_saved">Couldn\'t save the attachment.</string> <!-- Toast upon using "send" when one or more attachments will need to be background loaded [CHAR LIMIT=none]--> - <string name="message_view_attachment_background_load">One or more attachments in your + <string name="message_view_attachment_background_load">Note: One or more attachments in your forwarded message will be downloaded prior to sending.</string> <!--Button on the message view screen to show the message content [CHAR LIMIT=16] --> <string name="message_view_show_message_action">Message</string> @@ -495,7 +495,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <!-- Notification ticker when email account authentication fails [CHAR LIMIT=none] --> <string name="login_failed_ticker"> - <xliff:g id="account_name">%s</xliff:g> signin unsuccessful.</string> + <xliff:g id="account_name">%s</xliff:g> signin failed.</string> <!-- Notification title when email account authentication fails [CHAR LIMIT=30]--> <string name="login_failed_title">Couldn\'t sign in</string> @@ -555,7 +555,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <string name="account_setup_basics_password_label">Password</string> <!-- On "Set up email" screen, checkbox label for making the new account the default account --> <string name="account_setup_basics_default_label"> - Send email from this account by default</string> + Send email from this account by default.</string> <!-- Button name on "Set up email" screen --> <string name="account_setup_basics_manual_setup_action">Manual setup</string> <!-- Toast when we can't build a URI from the given email & password --> @@ -590,7 +590,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <!-- Text that appears on "Set up email" screen after successfully setting up an account [CHAR LIMIT=none] --> <string name="account_setup_names_headline"> - Your account is set up and email is on its way!</string> + Your account is set up, and email is on its way!</string> <!-- On "Set up email" screen, label of text field --> <string name="account_setup_names_account_name_label"> Give this account a name (optional)</string> @@ -681,7 +681,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <!-- On "Outgoing server settings" screen, label for pop-up menu --> <string name="account_setup_outgoing_security_label">Security type</string> <!-- On "Outgoing server settings" screen, label for check box --> - <string name="account_setup_outgoing_require_login_label">Require signin</string> + <string name="account_setup_outgoing_require_login_label">Require sign-in.</string> <!-- On "Outgoing server settings" screen, label for text field --> <string name="account_setup_outgoing_username_label">Username</string> <!-- On "Outgoing server settings" screen, label for text field --> @@ -735,16 +735,20 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <string name="account_setup_options_mail_check_frequency_1hour">Every hour</string> <!-- Check box label on "Set up email" screen to make this the default account --> <!-- Note, this should usually match the default account summary preference string --> - <string name="account_setup_options_default_label">Send email from this account by default</string> + <string name="account_setup_options_default_label">Send email from this account by default.</string> <!-- In Account setup options & Account Settings screens, check box for new-mail notification --> - <string name="account_setup_options_notify_label">Notify me when email arrives</string> + <string name="account_setup_options_notify_label">Notify me when email arrives.</string> <!-- In Account setup options screen, optional check box to also sync contacts --> - <string name="account_setup_options_sync_contacts_label">Sync contacts from this account</string> + <string name="account_setup_options_sync_contacts_label">Sync contacts from this account. + </string> <!-- In Account setup options screen, optional check box to also sync contacts --> - <string name="account_setup_options_sync_calendar_label">Sync calendar from this account</string> + <string name="account_setup_options_sync_calendar_label">Sync calendar from this account. + </string> <!-- In Account setup options screen, check box to sync email --> - <string name="account_setup_options_sync_email_label">Sync email from this account</string> - <!-- In Account setup options screen, check box to auto-download attachments [CHAR LIMIT=none] --> + <string name="account_setup_options_sync_email_label">Sync email from this account. + </string> + <!-- In Account setup options screen, check box to auto-download attachments [CHAR LIMIT=none] + --> <string name="account_setup_options_background_attachments_label"> Automatically download attachments when connected to Wi-Fi</string> <!-- Dialog title when "setup" could not finish --> @@ -770,9 +774,9 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <string name="account_setup_options_mail_window_default">Use account\'s default</string> <!-- "Setup could not finish" dialog text; e.g., Username or password incorrect --> - <string name="account_setup_failed_dlg_auth_message">Username or password is incorrect.</string> + <string name="account_setup_failed_dlg_auth_message">Username or password incorrect.</string> <!-- "Setup could not finish" dialog text; e.g., Username or password incorrect\n(ERR01 Account does not exist) --> - <string name="account_setup_failed_dlg_auth_message_fmt">Username or password is incorrect.\n(<xliff:g id="error">%s</xliff:g>)</string> + <string name="account_setup_failed_dlg_auth_message_fmt">Username or password incorrect.\n(<xliff:g id="error">%s</xliff:g>)</string> <!-- An error message presented to the user when the server's identity cannot be established or trusted [CHAR LIMIT=NONE] --> @@ -785,15 +789,16 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <!-- An error message presented to the user when the server requires a client certificate to connect [CHAR LIMIT=NONE] --> <string name="account_setup_failed_certificate_required" - >A client certificate is required. Do you want to connect to the server with a client certificate?</string> + >Client certificate is required. Connect to server with client certificate?</string> <!-- An error message presented to the user when the certificate they specified for connecting to a server is inaccessible [CHAR LIMIT=NONE] --> <string name="account_setup_failed_certificate_inaccessible" - >The certificate is invalid or inaccessible.</string> + >Certificate is invalid or inaccessible.</string> <!-- Dialog text for ambiguous setup failure; server error/bad credentials [CHAR LIMIT=none] --> <string name="account_setup_failed_check_credentials_message"> - The server responded with an error. Check your username and password, then try again.</string> + The server responded with an error. Check your username and password + then try again.</string> <!-- "Setup could not finish" dialog text; e.g., Cannot connect to server --> <string name="account_setup_failed_dlg_server_message">Can\'t connect to server.</string> @@ -827,7 +832,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> [CHAR LIMIT=none] --> <string name="account_setup_security_policies_required_fmt"> The server <xliff:g id="server">%s</xliff:g> requires that you allow it to remotely control - some security features of your Android device. Do you want to finish setting up this + some security features of your Android device. Do you want to finish setting up this account?</string> <!-- Additional diagnostic text when validation failed due to required provisioning not being supported [CHAR LIMIT=none] --> @@ -851,30 +856,14 @@ as <xliff:g id="filename">%s</xliff:g>.</string> provisioning, just before jumping into system settings such as Device Policy grant, PIN/password, or encryption setup. [CHAR LIMIT=none] --> <string name="account_security_dialog_content_fmt"> - <xliff:g id="account">%s</xliff:g> requires that you update your security - settings.</string> + <xliff:g id="account">%s</xliff:g> requires that you update your security settings.</string> <!-- Notification ticker when device security required (note: unused in Holo XL) --> - <string name="security_unsupported_ticker_fmt"> - Account \"<xliff:g id="account">%s</xliff:g>\" can\'t be synced due to security - requirements.</string> - <!-- Notification ticker when device security required (note: unused in Holo XL) --> - <string name="security_needed_ticker_fmt"> + <string name="security_notification_ticker_fmt"> Account \"<xliff:g id="account">%s</xliff:g>\" requires security settings update. </string> - <!-- Notification ticker when device security required (note: unused in Holo XL) --> - <string name="security_changed_ticker_fmt"> - Account \"<xliff:g id="account">%s</xliff:g>\" changed its security settings; no user - action is required. - </string> <!-- Notification content title when device security required [CHAR_LIMIT=30] --> - <string name="security_notification_content_update_title">Security update required</string> - <!-- Notification content title when device security policies have changed [CHAR_LIMIT=36] --> - <string name="security_notification_content_change_title">Security policies have - changed</string> - <!-- Notification content title when device security policies cannot be met [CHAR_LIMIT=30] --> - <string name="security_notification_content_unsupported_title">Security policies can\'t be - met</string> + <string name="security_notification_content_title">Security update required</string> <!-- Title of the activity that dispatches changes to device security. Not normally seen. --> <string name="account_security_title">Device security</string> <!-- Additional diagnostic text when the email app asserts control of the phone. @@ -903,15 +892,15 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <string name="password_expire_warning_dialog_title">Lock screen password expiring</string> <!-- Dialog content device pin/password is going to expire soon. [CHAR_LIMIT=none] --> <string name="password_expire_warning_dialog_content_fmt"> - You need to change your lock screen PIN or password soon, or the data for - <xliff:g id="account">%s</xliff:g> will be erased. Do you want to change it now?</string> + You must change your lock screen PIN or password soon, or the data for + <xliff:g id="account">%s</xliff:g> will be erased. Change it now?</string> <!-- Dialog title if device pin/password has already expired. [CHAR_LIMIT=40] --> <string name="password_expired_dialog_title">Lock screen password expired</string> <!-- Dialog content device pin/password has already expired. [CHAR_LIMIT=none] --> <string name="password_expired_dialog_content_fmt"> The data for <xliff:g id="account">%s</xliff:g> is being erased from your device. - You can restore it by changing your lock screen PIN or password. Do you want to change it now?</string> + You can restore it by changing your lock screen PIN or password. Change it now?</string> <!-- On AccountSettingsXL, dialog text if you try to exit in/out/eas fragment (server settings) without checking/saving [CHAR LIMIT=none]--> @@ -924,7 +913,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> [CHAR_LIMIT=none] --> <string name="account_settings_login_dialog_content_fmt"> The username or password for <xliff:g id="account">%s</xliff:g> is incorrect. - Do you want to update them now?</string> + Update them now?</string> <!-- On Settings screen, setting option name --> <string name="account_settings_default_label">Default account</string> @@ -943,32 +932,20 @@ as <xliff:g id="filename">%s</xliff:g>.</string> [CHAR LIMIT=50] --> <string name="account_settings_summary">Sync frequency, notifications, etc.</string> <!-- On Settings screen, setting summary text --> - <string name="account_settings_notify_summary">Send notification when email arrives</string> + <string name="account_settings_notify_summary">Notify in System bar when email arrives</string> <!-- On Settings screen, setting option name and title of dialog box that opens --> <string name="account_settings_mail_check_frequency_label">Inbox check frequency</string> <!-- On Settings screen, setting option name --> <string name="account_settings_incoming_label">Incoming settings</string> - <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> + <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> <string name="account_settings_incoming_summary"> Username, password, and other incoming server settings</string> <!-- On Settings screen, setting option name --> <string name="account_settings_outgoing_label">Outgoing settings</string> - <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> + <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> <string name="account_settings_outgoing_summary"> Username, password, and other outgoing server settings</string> <!-- On Settings screen, setting option name --> - <string name="account_settings_enforced_label">Policies enforced</string> - <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> - <string name="account_settings_enforced_summary">None</string> - <!-- On Settings screen, setting option name --> - <string name="account_settings_unsupported_label">Unsupported policies</string> - <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> - <string name="account_settings_unsupported_summary">None</string> - <!-- On Settings screen, label for button that attempts to sync the account --> - <string name="account_settings_retry_label">Attempt sync</string> - <!-- On Settings screen, summmary for button that attempts to sync an account [CHAR LIMIT=64] --> - <string name="account_settings_retry_summary">Touch here to sync this account</string> - <!-- On Settings screen, setting option name --> <string name="account_settings_description_label">Account name</string> <!-- On Settings screen, setting option name --> <string name="account_settings_name_label">Your name</string> @@ -979,15 +956,13 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <string name="account_settings_edit_quick_responses_label">Quick responses</string> <!-- On Settings screen, setting option summary [CHAR LIMIT=64] --> <string name="account_settings_edit_quick_responses_summary"> - Edit text that you frequently insert when composing email</string> + Edit text that you frequently insert when composing emails</string> <!-- On Settings screen, setting option name --> <string name="account_settings_signature_hint">Append text to messages you send</string> <!-- On Settings screen, section heading --> <string name="account_settings_notifications">Notification settings</string> <!-- On Settings screen, section heading for data usage [CHAR LIMIT=70] --> <string name="account_settings_data_usage">Data usage</string> - <!-- On Settings screen, section heading --> - <string name="account_settings_policies">Security policies</string> <!-- On settings screen, dialog heading informing user to edit a quick response --> <string name="edit_quick_response_dialog">Edit quick response</string> @@ -999,9 +974,9 @@ as <xliff:g id="filename">%s</xliff:g>.</string> <!-- On settings screen, sync contacts summary text [CHAR LIMIT=35] --> <string name="account_settings_sync_contacts_summary">Sync contacts for this account</string> <!-- On settings screen, sync calendar check box label [CHAR LIMIT=20]--> - <string name="account_settings_sync_calendar_enable">Sync calendar</string> - <!-- On settings screen, sync calendar summary text [CHAR LIMIT=50] --> - <string name="account_settings_sync_calendar_summary">Sync calendar event for this account</string> + <string name="account_settings_sync_calendar_enable">Sync Calendar</string> + <!-- On settings screen, sync calendar summary text [CHAR LIMIT=35] --> + <string name="account_settings_sync_calendar_summary">Sync calendar for this account</string> <!-- On settings screen, sync email check box label [CHAR LIMIT=20]--> <string name="account_settings_sync_email_enable">Sync email</string> <!-- On settings screen, sync email summary text [CHAR LIMIT=35] --> @@ -1251,38 +1226,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string> Used only in layout computation, and never actually exposed to the user. --> <string name="long_string" translatable="false">looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</string> - <!-- A policy disallowing the user of the device's camera [CHAR LIMIT=50] --> - <string name="policy_dont_allow_camera">Disallow use of the device\'s camera</string> - <!-- A policy requiring a device lock screen password [CHAR LIMIT=50] --> - <string name="policy_require_password">Require device password</string> - <!-- A policy disallowing the reuse of recent passwords [CHAR LIMIT=50] --> - <string name="policy_password_history">Restrict the reuse of recent passwords</string> - <!-- A policy that forces a password to expire after a set period of time [CHAR LIMIT=50] --> - <string name="policy_password_expiration">Require passwords to expire</string> - <!-- A policy requiring a maximum amount of time the device can sit idle before the lock screen - is activated [CHAR LIMIT=50] --> - <string name="policy_screen_timeout">Require an idle device to lock its screen</string> - <!-- A policy limiting the number of old calendar events synced [CHAR LIMIT=50] --> - <string name="policy_calendar_age">Limit the number of calendar events synced</string> - <!-- A policy limiting the number of emails synced [CHAR LIMIT=50] --> - <string name="policy_email_age">Limit the number of emails synced</string> - - <!-- The four strings below represent "quick responses" which the user can insert into a - message being composed with just a couple of taps. These four responses MUST be defined, - but need not include a string (i.e. they are optional). Further, the responses can be - customized as necessary by the translator, in case one or more of these is inappropriate in - a particular locale or if there are better options available. --> - <!-- A "quick response", i.e. a quick reply to a received mail [CHAR LIMIT=NONE] --> - <string name="quick_1">Thanks!</string> - <!-- A "quick response", i.e. a quick reply to a received mail [CHAR LIMIT=NONE] --> - <string name="quick_2">Sounds good to me!</string> - <!-- A "quick response", i.e. a quick reply to a received mail [CHAR LIMIT=NONE] --> - <string name="quick_3">I\'ll read this later and get back to you.</string> - <!-- A "quick response", i.e. a quick reply to a received mail [CHAR LIMIT=NONE] --> - <string name="quick_4">Let\'s set up a meeting to discuss this.</string> - <!-- This is the message warning the user that they must sync manually when roaming. [CHAR LIMIT=none]--> <string name="require_manual_sync_message">Background sync for this account is disabled while\ roaming.</string> </resources> - diff --git a/res/values/styles.xml b/res/values/styles.xml index a9af812bb..c88ff5976 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -169,6 +169,21 @@ <item name="android:ellipsize">end</item> </style> + <style name="action_bar_spinner_primary_text"> + <item name="android:textSize">16sp</item> + <item name="android:textColor">@color/text_primary_color</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">end</item> + </style> + + <style name="action_bar_spinner_secondary_text"> + <item name="android:textSize">14sp</item> + <item name="android:textColor">@color/text_secondary_color</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">end</item> + <item name="android:layout_marginTop">-4dip</item> + </style> + <style name="search_header"> <item name="android:layout_height">32dip</item> <item name="android:layout_width">match_parent</item> diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index e55386356..7b6fa9bd6 100755..100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -136,26 +136,6 @@ </PreferenceCategory> <PreferenceCategory - android:key="account_policies" - android:title="@string/account_settings_policies"> - - <com.android.email.activity.setup.PolicyListPreference - android:key="policies_enforced" - android:title="@string/account_settings_enforced_label" - android:summary="@string/account_settings_enforced_summary" /> - - <com.android.email.activity.setup.PolicyListPreference - android:key="policies_unsupported" - android:title="@string/account_settings_unsupported_label" - android:summary="@string/account_settings_unsupported_summary" /> - - <Preference - android:key="policies_retry_account" - android:title="@string/account_settings_retry_label" - android:summary="@string/account_settings_retry_summary" /> - </PreferenceCategory> - - <PreferenceCategory android:title="@string/account_settings_category_delete_account"> <PreferenceScreen diff --git a/res/xml/syncadapter_pop_imap.xml b/res/xml/syncadapter_pop_imap.xml index f4a7120fc..c1c0734ea 100644 --- a/res/xml/syncadapter_pop_imap.xml +++ b/res/xml/syncadapter_pop_imap.xml @@ -23,6 +23,5 @@ <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.android.email.provider" android:accountType="com.android.email" - android:supportsUploading="true" - android:allowParallelSyncs="true" + android:supportsUploading="false" /> diff --git a/src/com/android/email/Controller.java b/src/com/android/email/Controller.java index ac9a76d5a..93a7d160e 100644 --- a/src/com/android/email/Controller.java +++ b/src/com/android/email/Controller.java @@ -16,31 +16,38 @@ package com.android.email; +import android.app.Service; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; import com.android.email.mail.store.Pop3Store.Pop3Message; -import com.android.email.provider.Utilities; +import com.android.email.provider.AccountBackupRestore; import com.android.email.service.EmailServiceUtils; +import com.android.email.service.MailService; +import com.android.emailcommon.Api; import com.android.emailcommon.Logging; import com.android.emailcommon.mail.AuthenticationFailedException; +import com.android.emailcommon.mail.Folder.MessageRetrievalListener; import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Attachment; +import com.android.emailcommon.provider.EmailContent.Body; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.EmailContent.MessageColumns; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.EmailServiceProxy; import com.android.emailcommon.service.EmailServiceStatus; import com.android.emailcommon.service.IEmailService; import com.android.emailcommon.service.IEmailServiceCallback; @@ -66,9 +73,12 @@ import java.util.concurrent.ConcurrentHashMap; * to IMAP, POP3, and EAS by AttachmentDownloadService */ public class Controller { + private static final String TAG = "Controller"; private static Controller sInstance; private final Context mContext; private Context mProviderContext; + private final MessagingController mLegacyController; + private final LegacyListener mLegacyListener = new LegacyListener(); private final ServiceCallback mServiceCallback = new ServiceCallback(); private final HashSet<Result> mListeners = new HashSet<Result>(); /*package*/ final ConcurrentHashMap<Long, Boolean> mLegacyControllerMap = @@ -91,6 +101,17 @@ public class Controller { }; private static final int MESSAGEID_TO_ACCOUNTID_COLUMN_ACCOUNTID = 1; + private static final String[] BODY_SOURCE_KEY_PROJECTION = + new String[] {Body.SOURCE_MESSAGE_KEY}; + private static final int BODY_SOURCE_KEY_COLUMN = 0; + private static final String WHERE_MESSAGE_KEY = Body.MESSAGE_KEY + "=?"; + + private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?"; + private static final String MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION = + MAILBOXES_FOR_ACCOUNT_SELECTION + " AND " + MailboxColumns.TYPE + "!=" + + Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; + private static final String MESSAGES_FOR_ACCOUNT_SELECTION = MessageColumns.ACCOUNT_KEY + "=?"; + // Service callbacks as set up via setCallback private static RemoteCallbackList<IEmailServiceCallback> sCallbackList = new RemoteCallbackList<IEmailServiceCallback>(); @@ -100,6 +121,8 @@ public class Controller { protected Controller(Context _context) { mContext = _context.getApplicationContext(); mProviderContext = _context; + mLegacyController = MessagingController.getInstance(mProviderContext, this); + mLegacyController.addListener(mLegacyListener); } /** @@ -112,6 +135,16 @@ public class Controller { } /** + * Cleanup for test. Mustn't be called for the regular {@link Controller}, as it's a + * singleton and lives till the process finishes. + * + * <p>However, this method MUST be called for mock instances. + */ + public void cleanupForTest() { + mLegacyController.removeListener(mLegacyListener); + } + + /** * Gets or creates the singleton instance of Controller. */ public synchronized static Controller getInstance(Context _context) { @@ -275,8 +308,8 @@ public class Controller { // Commit the message to the local store msg.save(mProviderContext); // Setup the rest of the message and mark it completely loaded - Utilities.copyOneMessageToProvider(mProviderContext, pop3Message, msg, - Message.FLAG_LOADED_COMPLETE); + mLegacyController.copyOneMessageToProvider(pop3Message, msg, + Message.FLAG_LOADED_COMPLETE, mProviderContext); // Restore the complete message and return it return Message.restoreMessageWithId(mProviderContext, msg.mId); } catch (MessagingException e) { @@ -306,9 +339,7 @@ public class Controller { /** * Request a remote update of mailboxes for an account. */ - @SuppressWarnings("deprecation") public void updateMailboxList(final long accountId) { - if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) return; Utility.runAsync(new Runnable() { @Override public void run() { @@ -323,13 +354,44 @@ public class Controller { Log.d("updateMailboxList", "RemoteException" + e); } } else { - throw new IllegalStateException("No service for updateMailboxList?"); + // MessagingController implementation + mLegacyController.listFolders(accountId, mLegacyListener); } } }); } /** + * Request a remote update of a mailbox. For use by the timed service. + * + * Functionally this is quite similar to updateMailbox(), but it's a separate API and + * separate callback in order to keep UI callbacks from affecting the service loop. + */ + public void serviceCheckMail(final long accountId, final long mailboxId, final long tag) { + IEmailService service = getServiceForAccount(accountId); + if (service != null) { + // Service implementation +// try { + // TODO this isn't quite going to work, because we're going to get the + // generic (UI) callbacks and not the ones we need to restart the ol' service. + // service.startSync(mailboxId, tag); + mLegacyListener.checkMailFinished(mContext, accountId, mailboxId, tag); +// } catch (RemoteException e) { + // TODO Change exception handling to be consistent with however this method + // is implemented for other protocols +// Log.d("updateMailbox", "RemoteException" + e); +// } + } else { + // MessagingController implementation + Utility.runAsync(new Runnable() { + public void run() { + mLegacyController.checkMail(accountId, tag, mLegacyListener); + } + }); + } + } + + /** * Request a remote update of a mailbox. * * The contract here should be to try and update the headers ASAP, in order to populate @@ -347,9 +409,23 @@ public class Controller { // is implemented for other protocols Log.d("updateMailbox", "RemoteException" + e); } - } else { - throw new IllegalStateException("No service for loadMessageForView?"); - } + } else { + // MessagingController implementation + Utility.runAsync(new Runnable() { + public void run() { + // TODO shouldn't be passing fully-build accounts & mailboxes into APIs + Account account = + Account.restoreAccountWithId(mProviderContext, accountId); + Mailbox mailbox = + Mailbox.restoreMailboxWithId(mProviderContext, mailboxId); + if (account == null || mailbox == null || + mailbox.mType == Mailbox.TYPE_SEARCH) { + return; + } + mLegacyController.synchronizeMailbox(account, mailbox, mLegacyListener); + } + }); + } } /** @@ -365,15 +441,15 @@ public class Controller { public void loadMessageForView(final long messageId) { // Split here for target type (Service or MessagingController) - EmailServiceProxy service = getServiceForMessage(messageId); - if (service.isRemote()) { + IEmailService service = getServiceForMessage(messageId); + if (service != null) { // There is no service implementation, so we'll just jam the value, log the error, // and get out of here. Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, messageId); ContentValues cv = new ContentValues(); cv.put(MessageColumns.FLAG_LOADED, Message.FLAG_LOADED_COMPLETE); mProviderContext.getContentResolver().update(uri, cv, null, null); - Log.d(Logging.LOG_TAG, "Unexpected loadMessageForView() for remote service message."); + Log.d(Logging.LOG_TAG, "Unexpected loadMessageForView() for service-based message."); final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); synchronized (mListeners) { for (Result listener : mListeners) { @@ -381,10 +457,12 @@ public class Controller { } } } else { - try { - service.loadMore(messageId); - } catch (RemoteException e) { - } + // MessagingController implementation + Utility.runAsync(new Runnable() { + public void run() { + mLegacyController.loadMessageForView(messageId, mLegacyListener); + } + }); } } @@ -515,12 +593,48 @@ public class Controller { sendPendingMessages(accountId); } + private void sendPendingMessagesSmtp(long accountId) { + // for IMAP & POP only, (attempt to) send the message now + final Account account = + Account.restoreAccountWithId(mProviderContext, accountId); + if (account == null) { + return; + } + final long sentboxId = findOrCreateMailboxOfType(accountId, Mailbox.TYPE_SENT); + Utility.runAsync(new Runnable() { + public void run() { + mLegacyController.sendPendingMessages(account, sentboxId, mLegacyListener); + } + }); + } + + /** + * Try to send all pending messages for a given account + * + * @param accountId the account for which to send messages + */ public void sendPendingMessages(long accountId) { - EmailServiceProxy service = - EmailServiceUtils.getServiceForAccount(mContext, null, accountId); - try { - service.sendMail(accountId); - } catch (RemoteException e) { + // 1. make sure we even have an outbox, exit early if not + final long outboxId = + Mailbox.findMailboxOfType(mProviderContext, accountId, Mailbox.TYPE_OUTBOX); + if (outboxId == Mailbox.NO_MAILBOX) { + return; + } + + // 2. dispatch as necessary + IEmailService service = getServiceForAccount(accountId); + if (service != null) { + // Service implementation + try { + service.startSync(outboxId, false); + } catch (RemoteException e) { + // TODO Change exception handling to be consistent with however this method + // is implemented for other protocols + Log.d("updateMailbox", "RemoteException" + e); + } + } else { + // MessagingController implementation + sendPendingMessagesSmtp(accountId); } } @@ -530,10 +644,8 @@ public class Controller { * look up limit * write limit into all mailboxes for that account */ - @SuppressWarnings("deprecation") public void resetVisibleLimits() { Utility.runAsync(new Runnable() { - @Override public void run() { ContentResolver resolver = mProviderContext.getContentResolver(); Cursor c = null; @@ -570,7 +682,6 @@ public class Controller { */ public void loadMoreMessages(final long mailboxId) { EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override public void run() { Mailbox mailbox = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId); if (mailbox == null) { @@ -597,7 +708,7 @@ public class Controller { mProviderContext.getContentResolver().update(uri, cv, null, null); // Trigger a refresh using the new, longer limit mailbox.mVisibleLimit += Email.VISIBLE_LIMIT_INCREMENT; - updateMailbox(account.mId, mailboxId, true); + mLegacyController.synchronizeMailbox(account, mailbox, mLegacyListener); } }); } @@ -635,7 +746,6 @@ public class Controller { */ public void deleteMessage(final long messageId) { EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override public void run() { deleteMessageSync(messageId); } @@ -650,7 +760,6 @@ public class Controller { throw new IllegalArgumentException(); } EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override public void run() { for (long messageId: messageIds) { deleteMessageSync(messageId); @@ -700,6 +809,10 @@ public class Controller { cv.put(EmailContent.MessageColumns.MAILBOX_KEY, trashMailboxId); resolver.update(uri, cv, null, null); } + + if (isMessagingController(account)) { + mLegacyController.processPendingActions(account.mId); + } } /** @@ -721,7 +834,6 @@ public class Controller { throw new IllegalArgumentException(); } return EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override public void run() { Account account = Account.getAccountForMessageId(mProviderContext, messageIds[0]); if (account != null) { @@ -733,6 +845,9 @@ public class Controller { EmailContent.Message.SYNCED_CONTENT_URI, messageId); resolver.update(uri, cv, null, null); } + if (isMessagingController(account)) { + mLegacyController.processPendingActions(account.mId); + } } } }); @@ -773,6 +888,13 @@ public class Controller { private void updateMessageSync(long messageId, ContentValues cv) { Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); mProviderContext.getContentResolver().update(uri, cv, null, null); + + // Service runs automatically, MessagingController needs a kick + long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); + if (accountId == Account.NO_ACCOUNT) return; + if (isMessagingController(accountId)) { + mLegacyController.processPendingActions(accountId); + } } /** @@ -784,7 +906,6 @@ public class Controller { public void setMessageAnsweredOrForwarded(final long messageId, final int flag) { EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override public void run() { Message msg = Message.restoreMessageWithId(mProviderContext, messageId); if (msg == null) { @@ -884,13 +1005,22 @@ public class Controller { // TODO Change exception handling to be consistent with however this method // is implemented for other protocols Log.e("searchMessages", "RemoteException", e); + return 0; } + } else { + // This is the actual mailbox we'll be searching + Mailbox actualMailbox = Mailbox.restoreMailboxWithId(mContext, searchParams.mMailboxId); + if (actualMailbox == null) { + Log.e(Logging.LOG_TAG, "Unable to find mailbox " + searchParams.mMailboxId + + " to search in with " + searchParams); + return 0; + } + // Do the search + if (Email.DEBUG) { + Log.d(Logging.LOG_TAG, "Search: " + searchParams.mFilter); + } + return mLegacyController.searchMailbox(accountId, searchParams, searchMailboxId); } - return 0; - } - - private EmailServiceProxy getServiceForAccount(long accountId) { - return EmailServiceUtils.getServiceForAccount(mContext, mServiceCallback, accountId); } /** @@ -955,7 +1085,7 @@ public class Controller { * @param messageId the message of interest * @result service proxy, or null if n/a */ - private EmailServiceProxy getServiceForMessage(long messageId) { + private IEmailService getServiceForMessage(long messageId) { // TODO make this more efficient, caching the account, smaller lookup here, etc. Message message = Message.restoreMessageWithId(mProviderContext, messageId); if (message == null) { @@ -965,6 +1095,133 @@ public class Controller { } /** + * For a given account id, return a service proxy if applicable, or null. + * + * @param accountId the message of interest + * @result service proxy, or null if n/a + */ + private IEmailService getServiceForAccount(long accountId) { + if (isMessagingController(accountId)) return null; + return getExchangeEmailService(); + } + + private IEmailService getExchangeEmailService() { + return EmailServiceUtils.getExchangeService(mContext, mServiceCallback); + } + + /** + * Simple helper to determine if legacy MessagingController should be used + */ + public boolean isMessagingController(Account account) { + if (account == null) return false; + return isMessagingController(account.mId); + } + + public boolean isMessagingController(long accountId) { + Boolean isLegacyController = mLegacyControllerMap.get(accountId); + if (isLegacyController == null) { + String protocol = Account.getProtocol(mProviderContext, accountId); + isLegacyController = ("pop3".equals(protocol) || "imap".equals(protocol)); + mLegacyControllerMap.put(accountId, isLegacyController); + } + return isLegacyController; + } + + /** + * Delete an account. + */ + public void deleteAccount(final long accountId) { + EmailAsyncTask.runAsyncParallel(new Runnable() { + @Override + public void run() { + deleteAccountSync(accountId, mProviderContext); + } + }); + } + + /** + * Delete an account synchronously. + */ + public void deleteAccountSync(long accountId, Context context) { + try { + mLegacyControllerMap.remove(accountId); + // Get the account URI. + final Account account = Account.restoreAccountWithId(context, accountId); + if (account == null) { + return; // Already deleted? + } + + // Delete account data, attachments, PIM data, etc. + deleteSyncedDataSync(accountId); + + // Now delete the account itself + Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); + context.getContentResolver().delete(uri, null, null); + + // For unit tests, don't run backup, security, and ui pieces. + if (mInUnitTests) { + return; + } + + // Clean up + AccountBackupRestore.backup(context); + SecurityPolicy.getInstance(context).reducePolicies(); + Email.setServicesEnabledSync(context); + Email.setNotifyUiAccountsChanged(true); + MailService.actionReschedule(context); + } catch (Exception e) { + Log.w(Logging.LOG_TAG, "Exception while deleting account", e); + } + } + + /** + * Delete all synced data, but don't delete the actual account. This is used when security + * policy requirements are not met, and we don't want to reveal any synced data, but we do + * wish to keep the account configured (e.g. to accept remote wipe commands). + * + * The only mailbox not deleted is the account mailbox (if any) + * Also, clear the sync keys on the remaining account, since the data is gone. + * + * SYNCHRONOUS - do not call from UI thread. + * + * @param accountId The account to wipe. + */ + public void deleteSyncedDataSync(long accountId) { + try { + // Delete synced attachments + AttachmentUtilities.deleteAllAccountAttachmentFiles(mProviderContext, + accountId); + + // Delete synced email, leaving only an empty inbox. We do this in two phases: + // 1. Delete all non-inbox mailboxes (which will delete all of their messages) + // 2. Delete all remaining messages (which will be the inbox messages) + ContentResolver resolver = mProviderContext.getContentResolver(); + String[] accountIdArgs = new String[] { Long.toString(accountId) }; + resolver.delete(Mailbox.CONTENT_URI, + MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION, + accountIdArgs); + resolver.delete(Message.CONTENT_URI, MESSAGES_FOR_ACCOUNT_SELECTION, accountIdArgs); + + // Delete sync keys on remaining items + ContentValues cv = new ContentValues(); + cv.putNull(Account.SYNC_KEY); + resolver.update(Account.CONTENT_URI, cv, Account.ID_SELECTION, accountIdArgs); + cv.clear(); + cv.putNull(Mailbox.SYNC_KEY); + resolver.update(Mailbox.CONTENT_URI, cv, + MAILBOXES_FOR_ACCOUNT_SELECTION, accountIdArgs); + + // Delete PIM data (contacts, calendar), stop syncs, etc. if applicable + IEmailService service = getServiceForAccount(accountId); + if (service != null) { + service.deleteAccountPIMData(accountId); + } + } catch (Exception e) { + Log.w(Logging.LOG_TAG, "Exception while deleting account synced data", e); + } + } + + /** * Simple callback for synchronous commands. For many commands, this can be largely ignored * and the result is observed via provider cursors. The callback will *not* necessarily be * made from the UI thread, so you may need further handlers to safely make UI updates. @@ -1042,6 +1299,281 @@ public class Controller { public void serviceCheckMailCallback(MessagingException result, long accountId, long mailboxId, int progress, long tag) { } + + /** + * Callback for sending pending messages. This will be called once to start the + * group, multiple times for messages, and once to complete the group. + * + * Unfortunately this callback works differently on SMTP and EAS. + * + * On SMTP: + * + * First, we get this. + * result == null, messageId == -1, progress == 0: start batch send + * + * Then we get these callbacks per message. + * (Exchange backend may skip "start sending one message".) + * result == null, messageId == xx, progress == 0: start sending one message + * result == xxxx, messageId == xx, progress == 0; failed sending one message + * + * Finally we get this. + * result == null, messageId == -1, progres == 100; finish sending batch + * + * On EAS: Almost same as above, except: + * + * - There's no first ("start batch send") callback. + * - accountId is always -1. + * + * @param result If null, the operation completed without error + * @param accountId The account being operated on + * @param messageId The being sent (may be unknown at start) + * @param progress 0 for "starting", 100 for complete + */ + public void sendMailCallback(MessagingException result, long accountId, + long messageId, int progress) { + } + } + + /** + * Bridge to intercept {@link MessageRetrievalListener#loadAttachmentProgress} and + * pass down to {@link Result}. + */ + public class MessageRetrievalListenerBridge implements MessageRetrievalListener { + private final long mMessageId; + private final long mAttachmentId; + private final long mAccountId; + + public MessageRetrievalListenerBridge(long messageId, long attachmentId) { + mMessageId = messageId; + mAttachmentId = attachmentId; + mAccountId = Account.getAccountIdForMessageId(mProviderContext, mMessageId); + } + + @Override + public void loadAttachmentProgress(int progress) { + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadAttachmentCallback(null, mAccountId, mMessageId, mAttachmentId, + progress); + } + } + } + + @Override + public void messageRetrieved(com.android.emailcommon.mail.Message message) { + } + } + + /** + * Support for receiving callbacks from MessagingController and dealing with UI going + * out of scope. + */ + public class LegacyListener extends MessagingListener { + public LegacyListener() { + } + + @Override + public void listFoldersStarted(long accountId) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxListCallback(null, accountId, 0); + } + } + } + + @Override + public void listFoldersFailed(long accountId, String message) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxListCallback(new MessagingException(message), accountId, 0); + } + } + } + + @Override + public void listFoldersFinished(long accountId) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxListCallback(null, accountId, 100); + } + } + } + + @Override + public void synchronizeMailboxStarted(long accountId, long mailboxId) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxCallback(null, accountId, mailboxId, 0, 0, null); + } + } + } + + @Override + public void synchronizeMailboxFinished(long accountId, long mailboxId, + int totalMessagesInMailbox, int numNewMessages, ArrayList<Long> addedMessages) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxCallback(null, accountId, mailboxId, 100, numNewMessages, + addedMessages); + } + } + } + + @Override + public void synchronizeMailboxFailed(long accountId, long mailboxId, Exception e) { + MessagingException me; + if (e instanceof MessagingException) { + me = (MessagingException) e; + } else { + me = new MessagingException(e.toString()); + } + synchronized (mListeners) { + for (Result l : mListeners) { + l.updateMailboxCallback(me, accountId, mailboxId, 0, 0, null); + } + } + } + + @Override + public void checkMailStarted(Context context, long accountId, long tag) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.serviceCheckMailCallback(null, accountId, -1, 0, tag); + } + } + } + + @Override + public void checkMailFinished(Context context, long accountId, long folderId, long tag) { + synchronized (mListeners) { + for (Result l : mListeners) { + l.serviceCheckMailCallback(null, accountId, folderId, 100, tag); + } + } + } + + @Override + public void loadMessageForViewStarted(long messageId) { + final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadMessageForViewCallback(null, accountId, messageId, 0); + } + } + } + + @Override + public void loadMessageForViewFinished(long messageId) { + final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadMessageForViewCallback(null, accountId, messageId, 100); + } + } + } + + @Override + public void loadMessageForViewFailed(long messageId, String message) { + final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadMessageForViewCallback(new MessagingException(message), + accountId, messageId, 0); + } + } + } + + @Override + public void loadAttachmentStarted(long accountId, long messageId, long attachmentId, + boolean requiresDownload) { + try { + mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, + EmailServiceStatus.IN_PROGRESS, 0); + } catch (RemoteException e) { + } + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 0); + } + } + } + + @Override + public void loadAttachmentFinished(long accountId, long messageId, long attachmentId) { + try { + mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, + EmailServiceStatus.SUCCESS, 100); + } catch (RemoteException e) { + } + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 100); + } + } + } + + @Override + public void loadAttachmentFailed(long accountId, long messageId, long attachmentId, + MessagingException me, boolean background) { + try { + // If the cause of the MessagingException is an IOException, we send a status of + // CONNECTION_ERROR; in this case, AttachmentDownloadService will try again to + // download the attachment. Otherwise, the error is considered non-recoverable. + int status = EmailServiceStatus.ATTACHMENT_NOT_FOUND; + if (me != null && me.getCause() instanceof IOException) { + status = EmailServiceStatus.CONNECTION_ERROR; + } + mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, status, 0); + } catch (RemoteException e) { + } + synchronized (mListeners) { + for (Result listener : mListeners) { + // TODO We are overloading the exception here. The UI listens for this + // callback and displays a toast if the exception is not null. Since we + // want to avoid displaying toast for background operations, we force + // the exception to be null. This needs to be re-worked so the UI will + // only receive (or at least pays attention to) responses for requests + // it explicitly cares about. Then we would not need to overload the + // exception parameter. + listener.loadAttachmentCallback(background ? null : me, accountId, messageId, + attachmentId, 0); + } + } + } + + @Override + synchronized public void sendPendingMessagesStarted(long accountId, long messageId) { + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.sendMailCallback(null, accountId, messageId, 0); + } + } + } + + @Override + synchronized public void sendPendingMessagesCompleted(long accountId) { + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.sendMailCallback(null, accountId, -1, 100); + } + } + } + + @Override + synchronized public void sendPendingMessagesFailed(long accountId, long messageId, + Exception reason) { + MessagingException me; + if (reason instanceof MessagingException) { + me = (MessagingException) reason; + } else { + me = new MessagingException(reason.toString()); + } + synchronized (mListeners) { + for (Result listener : mListeners) { + listener.sendMailCallback(me, accountId, messageId, 0); + } + } + } } /** @@ -1049,7 +1581,8 @@ public class Controller { */ private class ServiceCallback extends IEmailServiceCallback.Stub { - @Override + private final static boolean DEBUG_FAIL_DOWNLOADS = false; // do not check in "true" + public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode, int progress) { MessagingException result = mapStatusToException(statusCode); @@ -1058,6 +1591,10 @@ public class Controller { progress = 100; break; case EmailServiceStatus.IN_PROGRESS: + if (DEBUG_FAIL_DOWNLOADS && progress > 75) { + result = new MessagingException( + String.valueOf(EmailServiceStatus.CONNECTION_ERROR)); + } // discard progress reports that look like sentinels if (progress < 0 || progress >= 100) { return; @@ -1074,21 +1611,13 @@ public class Controller { } /** - * Unused - */ - @Override - public void sendMessageStatus(long messageId, String subject, int statusCode, - int progress) { - } - - /** * Note, this is an incomplete implementation of this callback, because we are * not getting things back from Service in quite the same way as from MessagingController. * However, this is sufficient for basic "progress=100" notification that message send * has just completed. */ - @Override - public void loadMessageStatus(long messageId, int statusCode, int progress) { + public void sendMessageStatus(long messageId, String subject, int statusCode, + int progress) { long accountId = -1; // This should be in the callback MessagingException result = mapStatusToException(statusCode); switch (statusCode) { @@ -1104,12 +1633,11 @@ public class Controller { } synchronized(mListeners) { for (Result listener : mListeners) { - listener.loadMessageForViewCallback(result, accountId, messageId, progress); + listener.sendMailCallback(result, accountId, messageId, progress); } } } - @Override public void syncMailboxListStatus(long accountId, int statusCode, int progress) { MessagingException result = mapStatusToException(statusCode); switch (statusCode) { @@ -1130,7 +1658,6 @@ public class Controller { } } - @Override public void syncMailboxStatus(long mailboxId, int statusCode, int progress) { MessagingException result = mapStatusToException(statusCode); switch (statusCode) { @@ -1202,7 +1729,8 @@ public class Controller { * Proxy that can be used to broadcast service callbacks; we currently use this only for * loadAttachment callbacks */ - private final IEmailServiceCallback.Stub mCallbackProxy = new IEmailServiceCallback.Stub() { + private final IEmailServiceCallback.Stub mCallbackProxy = + new IEmailServiceCallback.Stub() { /** * Broadcast a callback to the everyone that's registered @@ -1224,7 +1752,6 @@ public class Controller { } } - @Override public void loadAttachmentStatus(final long messageId, final long attachmentId, final int status, final int progress) { broadcastCallback(new ServiceCallbackWrapper() { @@ -1236,23 +1763,127 @@ public class Controller { } @Override - public void syncMailboxListStatus(long accountId, int statusCode, int progress) - throws RemoteException { + public void sendMessageStatus(long messageId, String subject, int statusCode, int progress){ } @Override - public void syncMailboxStatus(final long mailboxId, final int statusCode, - final int progress) throws RemoteException { + public void syncMailboxListStatus(long accountId, int statusCode, int progress) { } @Override - public void sendMessageStatus(long messageId, String subject, int statusCode, int progress) - throws RemoteException { + public void syncMailboxStatus(long mailboxId, int statusCode, int progress) { } + }; + + public static class ControllerService extends Service { + /** + * Create our EmailService implementation here. For now, only loadAttachment is supported; + * the intention, however, is to move more functionality to the service interface + */ + private final IEmailService.Stub mBinder = new IEmailService.Stub() { + + public Bundle validate(HostAuth hostAuth) { + return null; + } + + public Bundle autoDiscover(String userName, String password) { + return null; + } + + public void startSync(long mailboxId, boolean userRequest) { + } + + public void stopSync(long mailboxId) { + } + + public void loadAttachment(long attachmentId, boolean background) + throws RemoteException { + Attachment att = Attachment.restoreAttachmentWithId(ControllerService.this, + attachmentId); + if (att != null) { + if (Email.DEBUG) { + Log.d(TAG, "loadAttachment " + attachmentId + ": " + att.mFileName); + } + Message msg = Message.restoreMessageWithId(ControllerService.this, + att.mMessageKey); + if (msg != null) { + // If the message is a forward and the attachment needs downloading, we need + // to retrieve the message from the source, rather than from the message + // itself + if ((msg.mFlags & Message.FLAG_TYPE_FORWARD) != 0) { + String[] cols = Utility.getRowColumns(ControllerService.this, + Body.CONTENT_URI, BODY_SOURCE_KEY_PROJECTION, WHERE_MESSAGE_KEY, + new String[] {Long.toString(msg.mId)}); + if (cols != null) { + msg = Message.restoreMessageWithId(ControllerService.this, + Long.parseLong(cols[BODY_SOURCE_KEY_COLUMN])); + if (msg == null) { + // TODO: We can try restoring from the deleted table here... + return; + } + } + } + MessagingController legacyController = sInstance.mLegacyController; + LegacyListener legacyListener = sInstance.mLegacyListener; + legacyController.loadAttachment(msg.mAccountKey, msg.mId, msg.mMailboxKey, + attachmentId, legacyListener, background); + } else { + // Send back the specific error status for this case + sInstance.mCallbackProxy.loadAttachmentStatus(att.mMessageKey, attachmentId, + EmailServiceStatus.MESSAGE_NOT_FOUND, 0); + } + } + } + + public void updateFolderList(long accountId) { + } + + public void hostChanged(long accountId) { + } + + public void setLogging(int flags) { + } + + public void sendMeetingResponse(long messageId, int response) { + } + + public void loadMore(long messageId) { + } + + // The following three methods are not implemented in this version + public boolean createFolder(long accountId, String name) { + return false; + } + + public boolean deleteFolder(long accountId, String name) { + return false; + } + + public boolean renameFolder(long accountId, String oldName, String newName) { + return false; + } + + public void setCallback(IEmailServiceCallback cb) { + sCallbackList.register(cb); + } + + public void deleteAccountPIMData(long accountId) { + } + + public int searchMessages(long accountId, SearchParams searchParams, + long destMailboxId) { + return 0; + } + + @Override + public int getApiLevel() { + return Api.LEVEL; + } + }; @Override - public void loadMessageStatus(long messageId, int statusCode, int progress) - throws RemoteException { + public IBinder onBind(Intent intent) { + return mBinder; } - }; + } } diff --git a/src/com/android/email/ControllerResultUiThreadWrapper.java b/src/com/android/email/ControllerResultUiThreadWrapper.java index 89a2e30e7..f87c0525d 100644 --- a/src/com/android/email/ControllerResultUiThreadWrapper.java +++ b/src/com/android/email/ControllerResultUiThreadWrapper.java @@ -85,6 +85,17 @@ public class ControllerResultUiThreadWrapper<T extends Result> extends Result { } @Override + public void sendMailCallback(final MessagingException result, final long accountId, + final long messageId, final int progress) { + run(new Runnable() { + public void run() { + if (!isRegistered()) return; + mWrappee.sendMailCallback(result, accountId, messageId, progress); + } + }); + } + + @Override public void serviceCheckMailCallback(final MessagingException result, final long accountId, final long mailboxId, final int progress, final long tag) { run(new Runnable() { diff --git a/src/com/android/email/Email.java b/src/com/android/email/Email.java index 970373b33..1ef55cf2a 100644 --- a/src/com/android/email/Email.java +++ b/src/com/android/email/Email.java @@ -28,6 +28,7 @@ import com.android.email.activity.MessageCompose; import com.android.email.activity.ShortcutPicker; import com.android.email.service.AttachmentDownloadService; import com.android.email.service.MailService; +import com.android.email.widget.WidgetConfiguration; import com.android.emailcommon.Logging; import com.android.emailcommon.TempDirectory; import com.android.emailcommon.provider.Account; @@ -126,6 +127,15 @@ public class Email extends Application { private static void setServicesEnabled(Context context, boolean enabled) { PackageManager pm = context.getPackageManager(); + if (!enabled && pm.getComponentEnabledSetting( + new ComponentName(context, MailService.class)) == + PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + /* + * If no accounts now exist but the service is still enabled we're about to disable it + * so we'll reschedule to kill off any existing alarms. + */ + MailService.actionReschedule(context); + } pm.setComponentEnabledSetting( new ComponentName(context, MessageCompose.class), enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : @@ -146,6 +156,21 @@ public class Email extends Application { enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + if (enabled && pm.getComponentEnabledSetting( + new ComponentName(context, MailService.class)) == + PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + /* + * And now if accounts do exist then we've just enabled the service and we want to + * schedule alarms for the new accounts. + */ + MailService.actionReschedule(context); + } + + pm.setComponentEnabledSetting( + new ComponentName(context, WidgetConfiguration.class), + enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); // Start/stop the various services depending on whether there are any accounts startOrStopService(enabled, context, new Intent(context, AttachmentDownloadService.class)); diff --git a/src/com/android/email/GroupMessagingListener.java b/src/com/android/email/GroupMessagingListener.java new file mode 100644 index 000000000..a7b87c288 --- /dev/null +++ b/src/com/android/email/GroupMessagingListener.java @@ -0,0 +1,203 @@ +/* + * 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 com.android.email; + +import com.android.emailcommon.mail.MessagingException; + +import android.content.Context; + +import java.util.ArrayList; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class GroupMessagingListener extends MessagingListener { + /* The synchronization of the methods in this class + is not needed because we use ConcurrentHashMap. + + Nevertheless, let's keep the "synchronized" for a while in the case + we may want to change the implementation to use something else + than ConcurrentHashMap. + */ + + private ConcurrentHashMap<MessagingListener, Object> mListenersMap = + new ConcurrentHashMap<MessagingListener, Object>(); + + private Set<MessagingListener> mListeners = mListenersMap.keySet(); + + synchronized public void addListener(MessagingListener listener) { + // we use "this" as a dummy non-null value + mListenersMap.put(listener, this); + } + + synchronized public void removeListener(MessagingListener listener) { + mListenersMap.remove(listener); + } + + synchronized public boolean isActiveListener(MessagingListener listener) { + return mListenersMap.containsKey(listener); + } + + @Override + synchronized public void listFoldersStarted(long accountId) { + for (MessagingListener l : mListeners) { + l.listFoldersStarted(accountId); + } + } + + @Override + synchronized public void listFoldersFailed(long accountId, String message) { + for (MessagingListener l : mListeners) { + l.listFoldersFailed(accountId, message); + } + } + + @Override + synchronized public void listFoldersFinished(long accountId) { + for (MessagingListener l : mListeners) { + l.listFoldersFinished(accountId); + } + } + + @Override + synchronized public void synchronizeMailboxStarted(long accountId, long mailboxId) { + for (MessagingListener l : mListeners) { + l.synchronizeMailboxStarted(accountId, mailboxId); + } + } + + @Override + synchronized public void synchronizeMailboxFinished(long accountId, long mailboxId, + int totalMessagesInMailbox, int numNewMessages, ArrayList<Long> addedMessages) { + for (MessagingListener l : mListeners) { + l.synchronizeMailboxFinished(accountId, mailboxId, + totalMessagesInMailbox, numNewMessages, addedMessages); + } + } + + @Override + synchronized public void synchronizeMailboxFailed(long accountId, long mailboxId, Exception e) { + for (MessagingListener l : mListeners) { + l.synchronizeMailboxFailed(accountId, mailboxId, e); + } + } + + @Override + synchronized public void loadMessageForViewStarted(long messageId) { + for (MessagingListener l : mListeners) { + l.loadMessageForViewStarted(messageId); + } + } + + @Override + synchronized public void loadMessageForViewFinished(long messageId) { + for (MessagingListener l : mListeners) { + l.loadMessageForViewFinished(messageId); + } + } + + @Override + synchronized public void loadMessageForViewFailed(long messageId, String message) { + for (MessagingListener l : mListeners) { + l.loadMessageForViewFailed(messageId, message); + } + } + + @Override + synchronized public void checkMailStarted(Context context, long accountId, long tag) { + for (MessagingListener l : mListeners) { + l.checkMailStarted(context, accountId, tag); + } + } + + @Override + synchronized public void checkMailFinished(Context context, long accountId, long folderId, + long tag) { + for (MessagingListener l : mListeners) { + l.checkMailFinished(context, accountId, folderId, tag); + } + } + + @Override + synchronized public void sendPendingMessagesStarted(long accountId, long messageId) { + for (MessagingListener l : mListeners) { + l.sendPendingMessagesStarted(accountId, messageId); + } + } + + @Override + synchronized public void sendPendingMessagesCompleted(long accountId) { + for (MessagingListener l : mListeners) { + l.sendPendingMessagesCompleted(accountId); + } + } + + @Override + synchronized public void sendPendingMessagesFailed(long accountId, long messageId, + Exception reason) { + for (MessagingListener l : mListeners) { + l.sendPendingMessagesFailed(accountId, messageId, reason); + } + } + + @Override + synchronized public void messageUidChanged(long accountId, long mailboxId, + String oldUid, String newUid) { + for (MessagingListener l : mListeners) { + l.messageUidChanged(accountId, mailboxId, oldUid, newUid); + } + } + + @Override + synchronized public void loadAttachmentStarted( + long accountId, + long messageId, + long attachmentId, + boolean requiresDownload) { + for (MessagingListener l : mListeners) { + l.loadAttachmentStarted(accountId, messageId, attachmentId, requiresDownload); + } + } + + @Override + synchronized public void loadAttachmentFinished( + long accountId, + long messageId, + long attachmentId) { + for (MessagingListener l : mListeners) { + l.loadAttachmentFinished(accountId, messageId, attachmentId); + } + } + + @Override + synchronized public void loadAttachmentFailed( + long accountId, + long messageId, + long attachmentId, + MessagingException me, + boolean background) { + for (MessagingListener l : mListeners) { + l.loadAttachmentFailed(accountId, messageId, attachmentId, me, background); + } + } + + @Override + synchronized public void controllerCommandCompleted(boolean moreCommandsToRun) { + for (MessagingListener l : mListeners) { + l.controllerCommandCompleted(moreCommandsToRun); + } + } +} diff --git a/src/com/android/email/LegacyConversions.java b/src/com/android/email/LegacyConversions.java index d45447d41..fdefd3c4f 100644 --- a/src/com/android/email/LegacyConversions.java +++ b/src/com/android/email/LegacyConversions.java @@ -41,7 +41,6 @@ import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.AttachmentUtilities; -import com.android.mail.providers.UIProvider; import org.apache.commons.io.IOUtils; @@ -317,7 +316,6 @@ public class LegacyConversions { ContentValues cv = new ContentValues(); cv.put(AttachmentColumns.SIZE, copySize); cv.put(AttachmentColumns.CONTENT_URI, contentUriString); - cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED); Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); context.getContentResolver().update(uri, cv, null, null); } diff --git a/src/com/android/email/service/ImapService.java b/src/com/android/email/MessagingController.java index 6dcfbebd4..6a0f1e1d8 100644 --- a/src/com/android/email/service/ImapService.java +++ b/src/com/android/email/MessagingController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2008 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. @@ -14,30 +14,26 @@ * limitations under the License. */ -package com.android.email.service; +package com.android.email; -import android.app.Service; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.net.TrafficStats; import android.net.Uri; -import android.os.IBinder; -import android.os.RemoteCallbackList; -import android.os.RemoteException; +import android.os.Process; import android.text.TextUtils; import android.util.Log; -import com.android.email.Email; -import com.android.email.LegacyConversions; -import com.android.email.NotificationController; +import com.android.email.mail.Sender; import com.android.email.mail.Store; -import com.android.email.provider.Utilities; import com.android.emailcommon.Logging; import com.android.emailcommon.TrafficFlags; +import com.android.emailcommon.internet.MimeBodyPart; +import com.android.emailcommon.internet.MimeHeader; +import com.android.emailcommon.internet.MimeMultipart; import com.android.emailcommon.internet.MimeUtility; import com.android.emailcommon.mail.AuthenticationFailedException; import com.android.emailcommon.mail.FetchProfile; @@ -52,23 +48,59 @@ import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.mail.Part; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; +import com.android.emailcommon.provider.EmailContent.Attachment; +import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.EmailContent.MessageColumns; import com.android.emailcommon.provider.EmailContent.SyncColumns; import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.EmailServiceStatus; -import com.android.emailcommon.service.IEmailServiceCallback; import com.android.emailcommon.service.SearchParams; import com.android.emailcommon.utility.AttachmentUtilities; +import com.android.emailcommon.utility.ConversionUtilities; +import com.android.emailcommon.utility.Utility; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Starts a long running (application) Thread that will run through commands + * that require remote mailbox access. This class is used to serialize and + * prioritize these commands. Each method that will submit a command requires a + * MessagingListener instance to be provided. It is expected that that listener + * has also been added as a registered listener using addListener(). When a + * command is to be executed, if the listener that was provided with the command + * is no longer registered the command is skipped. The design idea for the above + * is that when an Activity starts it registers as a listener. When it is paused + * it removes itself. Thus, any commands that that activity submitted are + * removed from the queue once the activity is no longer active. + */ +public class MessagingController implements Runnable { -public class ImapService extends Service { - private static final String TAG = "ImapService"; + /** + * The maximum message size that we'll consider to be "small". A small message is downloaded + * in full immediately instead of in pieces. Anything over this size will be downloaded in + * pieces with attachments being left off completely and downloaded on demand. + * + * + * 25k for a "small" message was picked by educated trial and error. + * http://answers.google.com/answers/threadview?id=312463 claims that the + * average size of an email is 59k, which I feel is too large for our + * blind download. The following tests were performed on a download of + * 25 random messages. + * <pre> + * 5k - 61 seconds, + * 25k - 51 seconds, + * 55k - 53 seconds, + * </pre> + * So 25k gives good performance and a reasonable data footprint. Sounds good to me. + */ private static final int MAX_SMALL_MESSAGE_SIZE = (25 * 1024); private static final Flag[] FLAG_LIST_SEEN = new Flag[] { Flag.SEEN }; @@ -76,12 +108,9 @@ public class ImapService extends Service { private static final Flag[] FLAG_LIST_ANSWERED = new Flag[] { Flag.ANSWERED }; /** - * Simple cache for last search result mailbox by account and serverId, since the most common - * case will be repeated use of the same mailbox + * We write this into the serverId field of messages that will never be upsynced. */ - private static long mLastSearchAccountKey = Account.NO_ACCOUNT; - private static String mLastSearchServerId = null; - private static Mailbox mLastSearchRemoteMailbox = null; + private static final String LOCAL_SERVERID_PREFIX = "Local-"; /** * Cache search results by account; this allows for "load more" support without having to @@ -91,149 +120,226 @@ public class ImapService extends Service { private static final HashMap<Long, SortableMessage[]> sSearchResults = new HashMap<Long, SortableMessage[]>(); + private static final ContentValues PRUNE_ATTACHMENT_CV = new ContentValues(); + static { + PRUNE_ATTACHMENT_CV.putNull(AttachmentColumns.CONTENT_URI); + } + + private static MessagingController sInstance = null; + private final BlockingQueue<Command> mCommands = new LinkedBlockingQueue<Command>(); + private final Thread mThread; + /** - * We write this into the serverId field of messages that will never be upsynced. + * All access to mListeners *must* be synchronized */ - private static final String LOCAL_SERVERID_PREFIX = "Local-"; + private final GroupMessagingListener mListeners = new GroupMessagingListener(); + private boolean mBusy; + private final Context mContext; + private final Controller mController; - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return Service.START_STICKY; + /** + * Simple cache for last search result mailbox by account and serverId, since the most common + * case will be repeated use of the same mailbox + */ + private long mLastSearchAccountKey = Account.NO_ACCOUNT; + private String mLastSearchServerId = null; + private Mailbox mLastSearchRemoteMailbox = null; + + protected MessagingController(Context _context, Controller _controller) { + mContext = _context.getApplicationContext(); + mController = _controller; + mThread = new Thread(this); + mThread.start(); } - // Callbacks as set up via setCallback - private static final RemoteCallbackList<IEmailServiceCallback> mCallbackList = - new RemoteCallbackList<IEmailServiceCallback>(); - - private interface ServiceCallbackWrapper { - public void call(IEmailServiceCallback cb) throws RemoteException; + /** + * Gets or creates the singleton instance of MessagingController. Application is used to + * provide a Context to classes that need it. + */ + public synchronized static MessagingController getInstance(Context _context, + Controller _controller) { + if (sInstance == null) { + sInstance = new MessagingController(_context, _controller); + } + return sInstance; } /** - * Proxy that can be used by various sync adapters to tie into ExchangeService's callback system - * Used this way: ExchangeService.callback().callbackMethod(args...); - * The proxy wraps checking for existence of a ExchangeService instance - * Failures of these callbacks can be safely ignored. + * Inject a mock controller. Used only for testing. Affects future calls to getInstance(). */ - static private final IEmailServiceCallback.Stub sCallbackProxy = - new IEmailServiceCallback.Stub() { + public static void injectMockController(MessagingController mockController) { + sInstance = mockController; + } - /** - * Broadcast a callback to the everyone that's registered - * - * @param wrapper the ServiceCallbackWrapper used in the broadcast - */ - private synchronized void broadcastCallback(ServiceCallbackWrapper wrapper) { - RemoteCallbackList<IEmailServiceCallback> callbackList = mCallbackList; - if (callbackList != null) { - // Call everyone on our callback list - int count = callbackList.beginBroadcast(); - try { - for (int i = 0; i < count; i++) { - try { - wrapper.call(callbackList.getBroadcastItem(i)); - } catch (RemoteException e) { - // Safe to ignore - } catch (RuntimeException e) { - // We don't want an exception in one call to prevent other calls, so - // we'll just log this and continue - Log.e(TAG, "Caught RuntimeException in broadcast", e); - } - } - } finally { - // No matter what, we need to finish the broadcast - callbackList.finishBroadcast(); - } + // TODO: seems that this reading of mBusy isn't thread-safe + public boolean isBusy() { + return mBusy; + } + + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + // TODO: add an end test to this infinite loop + while (true) { + Command command; + try { + command = mCommands.take(); + } catch (InterruptedException e) { + continue; //re-test the condition on the eclosing while + } + if (command.listener == null || isActiveListener(command.listener)) { + mBusy = true; + command.runnable.run(); + mListeners.controllerCommandCompleted(mCommands.size() > 0); } + mBusy = false; } + } - @Override - public void loadAttachmentStatus(final long messageId, final long attachmentId, - final int status, final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.loadAttachmentStatus(messageId, attachmentId, status, progress); - } - }); + private void put(String description, MessagingListener listener, Runnable runnable) { + try { + Command command = new Command(); + command.listener = listener; + command.runnable = runnable; + command.description = description; + mCommands.add(command); } - - @Override - public void loadMessageStatus(final long messageId, final int status, final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.loadMessageStatus(messageId, status, progress); - } - }); + catch (IllegalStateException ie) { + throw new Error(ie); } + } - @Override - public void sendMessageStatus(final long messageId, final String subject, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.sendMessageStatus(messageId, subject, status, progress); - } - }); - } + public void addListener(MessagingListener listener) { + mListeners.addListener(listener); + } - @Override - public void syncMailboxListStatus(final long accountId, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.syncMailboxListStatus(accountId, status, progress); - } - }); - } + public void removeListener(MessagingListener listener) { + mListeners.removeListener(listener); + } - @Override - public void syncMailboxStatus(final long mailboxId, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.syncMailboxStatus(mailboxId, status, progress); - } - }); - } + private boolean isActiveListener(MessagingListener listener) { + return mListeners.isActiveListener(listener); + } + + private static final int MAILBOX_COLUMN_ID = 0; + private static final int MAILBOX_COLUMN_SERVER_ID = 1; + private static final int MAILBOX_COLUMN_TYPE = 2; + + /** Small projection for just the columns required for a sync. */ + private static final String[] MAILBOX_PROJECTION = new String[] { + MailboxColumns.ID, + MailboxColumns.SERVER_ID, + MailboxColumns.TYPE, }; /** - * Create our EmailService implementation here. + * Synchronize the folder list with the remote server. Synchronization occurs in the + * background and results are passed through the {@link MessagingListener}. If the + * given listener is not {@code null}, it must have been previously added to the set + * of listeners using the {@link #addListener(MessagingListener)}. Otherwise, no + * actions will be performed. + * + * TODO this needs to cache the remote folder list + * TODO break out an inner listFoldersSynchronized which could simplify checkMail + * + * @param accountId ID of the account for which to list the folders + * @param listener A listener to notify */ - private final EmailServiceStub mBinder = new EmailServiceStub() { - - @Override - public void setCallback(IEmailServiceCallback cb) throws RemoteException { - mCallbackList.register(cb); + void listFolders(final long accountId, MessagingListener listener) { + final Account account = Account.restoreAccountWithId(mContext, accountId); + if (account == null) { + Log.i(Logging.LOG_TAG, "Could not load account id " + accountId + + ". Has it been removed?"); + return; } + mListeners.listFoldersStarted(accountId); + put("listFolders", listener, new Runnable() { + // TODO For now, mailbox addition occurs in the server-dependent store implementation, + // but, mailbox removal occurs here. Instead, each store should be responsible for + // content synchronization (addition AND removal) since each store will likely need + // to implement it's own, unique synchronization methodology. + public void run() { + TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); + Cursor localFolderCursor = null; + try { + // Step 1: Get remote mailboxes + Store store = Store.getInstance(account, mContext); + Folder[] remoteFolders = store.updateFolders(); + HashSet<String> remoteFolderNames = new HashSet<String>(); + for (int i = 0, count = remoteFolders.length; i < count; i++) { + remoteFolderNames.add(remoteFolders[i].getName()); + } - @Override - public int searchMessages(long accountId, SearchParams searchParams, long destMailboxId) { - try { - return searchMailboxImpl(getApplicationContext(), accountId, searchParams, - destMailboxId); - } catch (MessagingException e) { - } - return 0; - } - }; + // Step 2: Get local mailboxes + localFolderCursor = mContext.getContentResolver().query( + Mailbox.CONTENT_URI, + MAILBOX_PROJECTION, + EmailContent.MailboxColumns.ACCOUNT_KEY + "=?", + new String[] { String.valueOf(account.mId) }, + null); + + // Step 3: Remove any local mailbox not on the remote list + while (localFolderCursor.moveToNext()) { + String mailboxPath = localFolderCursor.getString(MAILBOX_COLUMN_SERVER_ID); + // Short circuit if we have a remote mailbox with the same name + if (remoteFolderNames.contains(mailboxPath)) { + continue; + } - @Override - public IBinder onBind(Intent intent) { - mBinder.init(this, sCallbackProxy); - return mBinder; + int mailboxType = localFolderCursor.getInt(MAILBOX_COLUMN_TYPE); + long mailboxId = localFolderCursor.getLong(MAILBOX_COLUMN_ID); + switch (mailboxType) { + case Mailbox.TYPE_INBOX: + case Mailbox.TYPE_DRAFTS: + case Mailbox.TYPE_OUTBOX: + case Mailbox.TYPE_SENT: + case Mailbox.TYPE_TRASH: + case Mailbox.TYPE_SEARCH: + // Never, ever delete special mailboxes + break; + default: + // Drop all attachment files related to this mailbox + AttachmentUtilities.deleteAllMailboxAttachmentFiles( + mContext, accountId, mailboxId); + // Delete the mailbox; database triggers take care of related + // Message, Body and Attachment records + Uri uri = ContentUris.withAppendedId( + Mailbox.CONTENT_URI, mailboxId); + mContext.getContentResolver().delete(uri, null, null); + break; + } + } + mListeners.listFoldersFinished(accountId); + } catch (Exception e) { + mListeners.listFoldersFailed(accountId, e.toString()); + } finally { + if (localFolderCursor != null) { + localFolderCursor.close(); + } + } + } + }); } - private static void sendMailboxStatus(Mailbox mailbox, int status) { - try { - sCallbackProxy.syncMailboxStatus(mailbox.mId, status, 0); - } catch (RemoteException e) { + /** + * Start background synchronization of the specified folder. + * @param account + * @param folder + * @param listener + */ + public void synchronizeMailbox(final Account account, + final Mailbox folder, MessagingListener listener) { + /* + * We don't ever sync the Outbox. + */ + if (folder.mType == Mailbox.TYPE_OUTBOX) { + return; } + mListeners.synchronizeMailboxStarted(account.mId, folder.mId); + put("synchronizeMailbox", listener, new Runnable() { + public void run() { + synchronizeMailboxSynchronous(account, folder); + } + }); } /** @@ -242,23 +348,30 @@ public class ImapService extends Service { * TODO this should use ID's instead of fully-restored objects * @param account * @param folder - * @throws MessagingException */ - public static void synchronizeMailboxSynchronous(Context context, final Account account, - final Mailbox folder) throws MessagingException { - sendMailboxStatus(folder, EmailServiceStatus.IN_PROGRESS); - - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account)); + private void synchronizeMailboxSynchronous(final Account account, + final Mailbox folder) { + TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); + mListeners.synchronizeMailboxStarted(account.mId, folder.mId); if ((folder.mFlags & Mailbox.FLAG_HOLDS_MAIL) == 0) { - sendMailboxStatus(folder, EmailServiceStatus.SUCCESS); + // We don't hold messages, so, nothing to synchronize + mListeners.synchronizeMailboxFinished(account.mId, folder.mId, 0, 0, null); + return; } - NotificationController nc = NotificationController.getInstance(context); + NotificationController nc = NotificationController.getInstance(mContext); try { - processPendingActionsSynchronous(context, account); - synchronizeMailboxGeneric(context, account, folder); + processPendingActionsSynchronous(account); + + // Select generic sync or store-specific sync + SyncResults results = synchronizeMailboxGeneric(account, folder); + // The account might have been deleted + if (results == null) return; + mListeners.synchronizeMailboxFinished(account.mId, folder.mId, + results.mTotalMessages, + results.mAddedMessages.size(), + results.mAddedMessages); // Clear authentication notification for this account nc.cancelLoginFailedNotification(account.mId); - sendMailboxStatus(folder, EmailServiceStatus.SUCCESS); } catch (MessagingException e) { if (Logging.LOGD) { Log.v(Logging.LOG_TAG, "synchronizeMailbox", e); @@ -267,8 +380,7 @@ public class ImapService extends Service { // Generate authentication notification nc.showLoginFailedNotification(account.mId); } - sendMailboxStatus(folder, e.getExceptionType()); - throw e; + mListeners.synchronizeMailboxFailed(account.mId, folder.mId, e); } } @@ -309,6 +421,14 @@ public class ImapService extends Service { } } + private void saveOrUpdate(EmailContent content, Context context) { + if (content.isSaved()) { + content.update(context, content.toContentValues()); + } else { + content.save(context); + } + } + /** * Load the structure and body of messages not yet synced * @param account the account we're syncing @@ -317,8 +437,8 @@ public class ImapService extends Service { * @param toMailbox the destination mailbox we're syncing * @throws MessagingException */ - static void loadUnsyncedMessages(final Context context, final Account account, - Folder remoteFolder, ArrayList<Message> unsyncedMessages, final Mailbox toMailbox) + void loadUnsyncedMessages(final Account account, Folder remoteFolder, + ArrayList<Message> unsyncedMessages, final Mailbox toMailbox) throws MessagingException { // 1. Divide the unsynced messages into small & large (by size) @@ -350,10 +470,9 @@ public class ImapService extends Service { fp.add(FetchProfile.Item.BODY); remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]), fp, new MessageRetrievalListener() { - @Override public void messageRetrieved(Message message) { // Store the updated message locally and mark it fully loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, + copyOneMessageToProvider(message, account, toMailbox, EmailContent.Message.FLAG_LOADED_COMPLETE); } @@ -380,7 +499,7 @@ public class ImapService extends Service { remoteFolder.fetch(new Message[] { message }, fp, null); // Store the partially-loaded message and mark it partially loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, + copyOneMessageToProvider(message, account, toMailbox, EmailContent.Message.FLAG_LOADED_PARTIAL); } else { // We have a structure to deal with, from which @@ -399,15 +518,15 @@ public class ImapService extends Service { remoteFolder.fetch(new Message[] { message }, fp, null); } // Store the updated message locally and mark it fully loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, + copyOneMessageToProvider(message, account, toMailbox, EmailContent.Message.FLAG_LOADED_COMPLETE); } } } - public static void downloadFlagAndEnvelope(final Context context, final Account account, - final Mailbox mailbox, Folder remoteFolder, ArrayList<Message> unsyncedMessages, + public void downloadFlagAndEnvelope(final Account account, final Mailbox mailbox, + Folder remoteFolder, ArrayList<Message> unsyncedMessages, HashMap<String, LocalMessageInfo> localMessageMap, final ArrayList<Long> unseenMessages) throws MessagingException { FetchProfile fp = new FetchProfile(); @@ -435,7 +554,7 @@ public class ImapService extends Service { localMessage = new EmailContent.Message(); } else { localMessage = EmailContent.Message.restoreMessageWithId( - context, localMessageInfo.mId); + mContext, localMessageInfo.mId); } if (localMessage != null) { @@ -444,7 +563,7 @@ public class ImapService extends Service { LegacyConversions.updateMessageFields(localMessage, message, account.mId, mailbox.mId); // Commit the message to the local store - Utilities.saveOrUpdate(localMessage, context); + saveOrUpdate(localMessage, mContext); // Track the "new" ness of the downloaded message if (!message.isSet(Flag.SEEN) && unseenMessages != null) { unseenMessages.add(localMessage.mId); @@ -470,7 +589,135 @@ public class ImapService extends Service { } /** - * Synchronizer for IMAP. + * A message and numeric uid that's easily sortable + */ + private static class SortableMessage { + private final Message mMessage; + private final long mUid; + + SortableMessage(Message message, long uid) { + mMessage = message; + mUid = uid; + } + } + + public int searchMailbox(long accountId, SearchParams searchParams, long destMailboxId) + throws MessagingException { + try { + return searchMailboxImpl(accountId, searchParams, destMailboxId); + } finally { + // Tell UI that we're done loading any search results (no harm calling this even if we + // encountered an error or never sent a "started" message) + mListeners.synchronizeMailboxFinished(accountId, destMailboxId, 0, 0, null); + } + } + + private int searchMailboxImpl(long accountId, SearchParams searchParams, + final long destMailboxId) throws MessagingException { + final Account account = Account.restoreAccountWithId(mContext, accountId); + final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, searchParams.mMailboxId); + final Mailbox destMailbox = Mailbox.restoreMailboxWithId(mContext, destMailboxId); + if (account == null || mailbox == null || destMailbox == null) { + Log.d(Logging.LOG_TAG, "Attempted search for " + searchParams + + " but account or mailbox information was missing"); + return 0; + } + + // Tell UI that we're loading messages + mListeners.synchronizeMailboxStarted(accountId, destMailbox.mId); + + Store remoteStore = Store.getInstance(account, mContext); + Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); + remoteFolder.open(OpenMode.READ_WRITE); + + SortableMessage[] sortableMessages = new SortableMessage[0]; + if (searchParams.mOffset == 0) { + // Get the "bare" messages (basically uid) + Message[] remoteMessages = remoteFolder.getMessages(searchParams, null); + int remoteCount = remoteMessages.length; + if (remoteCount > 0) { + sortableMessages = new SortableMessage[remoteCount]; + int i = 0; + for (Message msg : remoteMessages) { + sortableMessages[i++] = new SortableMessage(msg, Long.parseLong(msg.getUid())); + } + // Sort the uid's, most recent first + // Note: Not all servers will be nice and return results in the order of request; + // those that do will see messages arrive from newest to oldest + Arrays.sort(sortableMessages, new Comparator<SortableMessage>() { + @Override + public int compare(SortableMessage lhs, SortableMessage rhs) { + return lhs.mUid > rhs.mUid ? -1 : lhs.mUid < rhs.mUid ? 1 : 0; + } + }); + sSearchResults.put(accountId, sortableMessages); + } + } else { + sortableMessages = sSearchResults.get(accountId); + } + + final int numSearchResults = sortableMessages.length; + final int numToLoad = + Math.min(numSearchResults - searchParams.mOffset, searchParams.mLimit); + if (numToLoad <= 0) { + return 0; + } + + final ArrayList<Message> messageList = new ArrayList<Message>(); + for (int i = searchParams.mOffset; i < numToLoad + searchParams.mOffset; i++) { + messageList.add(sortableMessages[i].mMessage); + } + // Get everything in one pass, rather than two (as in sync); this starts getting us + // usable results quickly. + FetchProfile fp = new FetchProfile(); + fp.add(FetchProfile.Item.FLAGS); + fp.add(FetchProfile.Item.ENVELOPE); + fp.add(FetchProfile.Item.STRUCTURE); + fp.add(FetchProfile.Item.BODY_SANE); + remoteFolder.fetch(messageList.toArray(new Message[0]), fp, + new MessageRetrievalListener() { + public void messageRetrieved(Message message) { + try { + // Determine if the new message was already known (e.g. partial) + // And create or reload the full message info + EmailContent.Message localMessage = new EmailContent.Message(); + try { + // Copy the fields that are available into the message + LegacyConversions.updateMessageFields(localMessage, + message, account.mId, mailbox.mId); + // Commit the message to the local store + saveOrUpdate(localMessage, mContext); + localMessage.mMailboxKey = destMailboxId; + // We load 50k or so; maybe it's complete, maybe not... + int flag = EmailContent.Message.FLAG_LOADED_COMPLETE; + // We store the serverId of the source mailbox into protocolSearchInfo + // This will be used by loadMessageForView, etc. to use the proper remote + // folder + localMessage.mProtocolSearchInfo = mailbox.mServerId; + if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) { + flag = EmailContent.Message.FLAG_LOADED_PARTIAL; + } + copyOneMessageToProvider(message, localMessage, flag, mContext); + } catch (MessagingException me) { + Log.e(Logging.LOG_TAG, + "Error while copying downloaded message." + me); + } + } catch (Exception e) { + Log.e(Logging.LOG_TAG, + "Error while storing downloaded message." + e.toString()); + } + } + + @Override + public void loadAttachmentProgress(int progress) { + } + }); + return numSearchResults; + } + + + /** + * Generic synchronizer - used for POP3 and IMAP. * * TODO Break this method up into smaller chunks. * @@ -479,8 +726,8 @@ public class ImapService extends Service { * @return results of the sync pass * @throws MessagingException */ - private static void synchronizeMailboxGeneric(final Context context, - final Account account, final Mailbox mailbox) throws MessagingException { + private SyncResults synchronizeMailboxGeneric(final Account account, final Mailbox mailbox) + throws MessagingException { /* * A list of IDs for messages that were downloaded and did not have the seen flag set. @@ -488,11 +735,13 @@ public class ImapService extends Service { */ final ArrayList<Long> unseenMessages = new ArrayList<Long>(); - ContentResolver resolver = context.getContentResolver(); + Log.d(Logging.LOG_TAG, "*** synchronizeMailboxGeneric ***"); + ContentResolver resolver = mContext.getContentResolver(); // 0. We do not ever sync DRAFTS or OUTBOX (down or up) if (mailbox.mType == Mailbox.TYPE_DRAFTS || mailbox.mType == Mailbox.TYPE_OUTBOX) { - return; + int totalMessages = EmailContent.count(mContext, mailbox.getUri(), null, null); + return new SyncResults(totalMessages, unseenMessages); } // 1. Get the message list from the local store and create an index of the uids @@ -523,9 +772,9 @@ public class ImapService extends Service { // 2. Open the remote folder and create the remote folder if necessary - Store remoteStore = Store.getInstance(account, context); + Store remoteStore = Store.getInstance(account, mContext); // The account might have been deleted - if (remoteStore == null) return; + if (remoteStore == null) return null; Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); /* @@ -539,7 +788,7 @@ public class ImapService extends Service { || mailbox.mType == Mailbox.TYPE_DRAFTS) { if (!remoteFolder.exists()) { if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { - return; + return new SyncResults(0, unseenMessages); } } } @@ -552,9 +801,6 @@ public class ImapService extends Service { // 5. Get the remote message count. int remoteMessageCount = remoteFolder.getMessageCount(); - ContentValues values = new ContentValues(); - values.put(MailboxColumns.TOTAL_COUNT, remoteMessageCount); - mailbox.update(context, values); // 6. Determine the limit # of messages to download int visibleLimit = mailbox.mVisibleLimit; @@ -567,6 +813,7 @@ public class ImapService extends Service { final ArrayList<Message> unsyncedMessages = new ArrayList<Message>(); HashMap<String, Message> remoteUidMap = new HashMap<String, Message>(); + int newMessageCount = 0; if (remoteMessageCount > 0) { /* * Message numbers start at 1. @@ -589,6 +836,9 @@ public class ImapService extends Service { */ for (Message message : remoteMessages) { LocalMessageInfo localMessage = localMessageMap.get(message.getUid()); + if (localMessage == null) { + newMessageCount++; + } // localMessage == null -> message has never been created (not even headers) // mFlagLoaded = UNLOADED -> message created, but none of body loaded // mFlagLoaded = PARTIAL -> message created, a "sane" amt of body has been loaded @@ -608,7 +858,7 @@ public class ImapService extends Service { * critical data as fast as possible, and then we'll fill in the details. */ if (unsyncedMessages.size() > 0) { - downloadFlagAndEnvelope(context, account, mailbox, remoteFolder, unsyncedMessages, + downloadFlagAndEnvelope(account, mailbox, remoteFolder, unsyncedMessages, localMessageMap, unseenMessages); } @@ -672,7 +922,7 @@ public class ImapService extends Service { // Delete associated data (attachment files) // Attachment & Body records are auto-deleted when we delete the Message record - AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, + AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId, infoToDelete.mId); // Delete the message itself @@ -689,10 +939,134 @@ public class ImapService extends Service { resolver.delete(deletERowToDelete, null, null); } - loadUnsyncedMessages(context, account, remoteFolder, unsyncedMessages, mailbox); + loadUnsyncedMessages(account, remoteFolder, unsyncedMessages, mailbox); // 14. Clean up and report results remoteFolder.close(false); + + return new SyncResults(remoteMessageCount, unseenMessages); + } + + /** + * Copy one downloaded message (which may have partially-loaded sections) + * into a newly created EmailProvider Message, given the account and mailbox + * + * @param message the remote message we've just downloaded + * @param account the account it will be stored into + * @param folder the mailbox it will be stored into + * @param loadStatus when complete, the message will be marked with this status (e.g. + * EmailContent.Message.LOADED) + */ + public void copyOneMessageToProvider(Message message, Account account, + Mailbox folder, int loadStatus) { + EmailContent.Message localMessage = null; + Cursor c = null; + try { + c = mContext.getContentResolver().query( + EmailContent.Message.CONTENT_URI, + EmailContent.Message.CONTENT_PROJECTION, + EmailContent.MessageColumns.ACCOUNT_KEY + "=?" + + " AND " + MessageColumns.MAILBOX_KEY + "=?" + + " AND " + SyncColumns.SERVER_ID + "=?", + new String[] { + String.valueOf(account.mId), + String.valueOf(folder.mId), + String.valueOf(message.getUid()) + }, + null); + if (c.moveToNext()) { + localMessage = EmailContent.getContent(c, EmailContent.Message.class); + localMessage.mMailboxKey = folder.mId; + localMessage.mAccountKey = account.mId; + copyOneMessageToProvider(message, localMessage, loadStatus, mContext); + } + } finally { + if (c != null) { + c.close(); + } + } + } + + /** + * Copy one downloaded message (which may have partially-loaded sections) + * into an already-created EmailProvider Message + * + * @param message the remote message we've just downloaded + * @param localMessage the EmailProvider Message, already created + * @param loadStatus when complete, the message will be marked with this status (e.g. + * EmailContent.Message.LOADED) + * @param context the context to be used for EmailProvider + */ + public void copyOneMessageToProvider(Message message, EmailContent.Message localMessage, + int loadStatus, Context context) { + try { + + EmailContent.Body body = EmailContent.Body.restoreBodyWithMessageId(context, + localMessage.mId); + if (body == null) { + body = new EmailContent.Body(); + } + try { + // Copy the fields that are available into the message object + LegacyConversions.updateMessageFields(localMessage, message, + localMessage.mAccountKey, localMessage.mMailboxKey); + + // Now process body parts & attachments + ArrayList<Part> viewables = new ArrayList<Part>(); + ArrayList<Part> attachments = new ArrayList<Part>(); + MimeUtility.collectParts(message, viewables, attachments); + + ConversionUtilities.updateBodyFields(body, localMessage, viewables); + + // Commit the message & body to the local store immediately + saveOrUpdate(localMessage, context); + saveOrUpdate(body, context); + + // process (and save) attachments + LegacyConversions.updateAttachments(context, localMessage, attachments); + + // One last update of message with two updated flags + localMessage.mFlagLoaded = loadStatus; + + ContentValues cv = new ContentValues(); + cv.put(EmailContent.MessageColumns.FLAG_ATTACHMENT, localMessage.mFlagAttachment); + cv.put(EmailContent.MessageColumns.FLAG_LOADED, localMessage.mFlagLoaded); + Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, + localMessage.mId); + context.getContentResolver().update(uri, cv, null, null); + + } catch (MessagingException me) { + Log.e(Logging.LOG_TAG, "Error while copying downloaded message." + me); + } + + } catch (RuntimeException rte) { + Log.e(Logging.LOG_TAG, "Error while storing downloaded message." + rte.toString()); + } catch (IOException ioe) { + Log.e(Logging.LOG_TAG, "Error while storing attachment." + ioe.toString()); + } + } + + public void processPendingActions(final long accountId) { + put("processPendingActions", null, new Runnable() { + public void run() { + try { + Account account = Account.restoreAccountWithId(mContext, accountId); + if (account == null) { + return; + } + processPendingActionsSynchronous(account); + } + catch (MessagingException me) { + if (Logging.LOGD) { + Log.v(Logging.LOG_TAG, "processPendingActions", me); + } + /* + * Ignore any exceptions from the commands. Commands will be processed + * on the next round. + */ + } + } + }); } /** @@ -710,19 +1084,20 @@ public class ImapService extends Service { * @param account the account to scan for pending actions * @throws MessagingException */ - private static void processPendingActionsSynchronous(Context context, Account account) + private void processPendingActionsSynchronous(Account account) throws MessagingException { - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account)); + TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); + ContentResolver resolver = mContext.getContentResolver(); String[] accountIdArgs = new String[] { Long.toString(account.mId) }; // Handle deletes first, it's always better to get rid of things first - processPendingDeletesSynchronous(context, account, accountIdArgs); + processPendingDeletesSynchronous(account, resolver, accountIdArgs); // Handle uploads (currently, only to sent messages) - processPendingUploadsSynchronous(context, account, accountIdArgs); + processPendingUploadsSynchronous(account, resolver, accountIdArgs); // Now handle updates / upsyncs - processPendingUpdatesSynchronous(context, account, accountIdArgs); + processPendingUpdatesSynchronous(account, resolver, accountIdArgs); } /** @@ -732,8 +1107,7 @@ public class ImapService extends Service { * @param message the message in question * @return the mailbox in which the message resides on the server */ - private static Mailbox getRemoteMailboxForMessage(Context context, - EmailContent.Message message) { + private Mailbox getRemoteMailboxForMessage(EmailContent.Message message) { // If this is a search result, use the protocolSearchInfo field to get the server info if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) { long accountKey = message.mAccountKey; @@ -742,7 +1116,7 @@ public class ImapService extends Service { protocolSearchInfo.equals(mLastSearchServerId)) { return mLastSearchRemoteMailbox; } - Cursor c = context.getContentResolver().query(Mailbox.CONTENT_URI, + Cursor c = mContext.getContentResolver().query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, Mailbox.PATH_AND_ACCOUNT_SELECTION, new String[] {protocolSearchInfo, Long.toString(accountKey)}, null); @@ -761,7 +1135,7 @@ public class ImapService extends Service { c.close(); } } else { - return Mailbox.restoreMailboxWithId(context, message.mMailboxKey); + return Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); } } @@ -773,10 +1147,9 @@ public class ImapService extends Service { * @param resolver * @param accountIdArgs */ - private static void processPendingDeletesSynchronous(Context context, Account account, - String[] accountIdArgs) { - Cursor deletes = context.getContentResolver().query( - EmailContent.Message.DELETED_CONTENT_URI, + private void processPendingDeletesSynchronous(Account account, + ContentResolver resolver, String[] accountIdArgs) { + Cursor deletes = resolver.query(EmailContent.Message.DELETED_CONTENT_URI, EmailContent.Message.CONTENT_PROJECTION, EmailContent.MessageColumns.ACCOUNT_KEY + "=?", accountIdArgs, EmailContent.MessageColumns.MAILBOX_KEY); @@ -794,7 +1167,7 @@ public class ImapService extends Service { if (oldMessage != null) { lastMessageId = oldMessage.mId; - Mailbox mailbox = getRemoteMailboxForMessage(context, oldMessage); + Mailbox mailbox = getRemoteMailboxForMessage(oldMessage); if (mailbox == null) { continue; // Mailbox removed. Move to the next message. } @@ -802,21 +1175,20 @@ public class ImapService extends Service { // Load the remote store if it will be needed if (remoteStore == null && deleteFromTrash) { - remoteStore = Store.getInstance(account, context); + remoteStore = Store.getInstance(account, mContext); } // Dispatch here for specific change types if (deleteFromTrash) { // Move message to trash - processPendingDeleteFromTrash(context, remoteStore, account, mailbox, - oldMessage); + processPendingDeleteFromTrash(remoteStore, account, mailbox, oldMessage); } } // Finally, delete the update Uri uri = ContentUris.withAppendedId(EmailContent.Message.DELETED_CONTENT_URI, oldMessage.mId); - context.getContentResolver().delete(uri, null, null); + resolver.delete(uri, null, null); } } catch (MessagingException me) { // Presumably an error here is an account connection failure, so there is @@ -845,9 +1217,8 @@ public class ImapService extends Service { * @param resolver * @param accountIdArgs */ - private static void processPendingUploadsSynchronous(Context context, Account account, - String[] accountIdArgs) { - ContentResolver resolver = context.getContentResolver(); + private void processPendingUploadsSynchronous(Account account, + ContentResolver resolver, String[] accountIdArgs) { // Find the Sent folder (since that's all we're uploading for now Cursor mailboxes = resolver.query(Mailbox.CONTENT_URI, Mailbox.ID_PROJECTION, MailboxColumns.ACCOUNT_KEY + "=?" @@ -875,11 +1246,11 @@ public class ImapService extends Service { while (upsyncs1.moveToNext()) { // Load the remote store if it will be needed if (remoteStore == null) { - remoteStore = Store.getInstance(account, context); + remoteStore = Store.getInstance(account, mContext); } // Load the mailbox if it will be needed if (mailbox == null) { - mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); + mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); if (mailbox == null) { continue; // Mailbox removed. Move to the next message. } @@ -887,7 +1258,7 @@ public class ImapService extends Service { // upsync the message long id = upsyncs1.getLong(EmailContent.Message.ID_PROJECTION_COLUMN); lastMessageId = id; - processUploadMessage(context, remoteStore, account, mailbox, id); + processUploadMessage(resolver, remoteStore, account, mailbox, id); } } finally { if (upsyncs1 != null) { @@ -904,11 +1275,11 @@ public class ImapService extends Service { while (upsyncs2.moveToNext()) { // Load the remote store if it will be needed if (remoteStore == null) { - remoteStore = Store.getInstance(account, context); + remoteStore = Store.getInstance(account, mContext); } // Load the mailbox if it will be needed if (mailbox == null) { - mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); + mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); if (mailbox == null) { continue; // Mailbox removed. Move to the next message. } @@ -916,7 +1287,7 @@ public class ImapService extends Service { // upsync the message long id = upsyncs2.getLong(EmailContent.Message.ID_PROJECTION_COLUMN); lastMessageId = id; - processUploadMessage(context, remoteStore, account, mailbox, id); + processUploadMessage(resolver, remoteStore, account, mailbox, id); } } finally { if (upsyncs2 != null) { @@ -946,9 +1317,8 @@ public class ImapService extends Service { * @param resolver * @param accountIdArgs */ - private static void processPendingUpdatesSynchronous(Context context, Account account, - String[] accountIdArgs) { - ContentResolver resolver = context.getContentResolver(); + private void processPendingUpdatesSynchronous(Account account, + ContentResolver resolver, String[] accountIdArgs) { Cursor updates = resolver.query(EmailContent.Message.UPDATED_CONTENT_URI, EmailContent.Message.CONTENT_PROJECTION, EmailContent.MessageColumns.ACCOUNT_KEY + "=?", accountIdArgs, @@ -971,9 +1341,9 @@ public class ImapService extends Service { EmailContent.getContent(updates, EmailContent.Message.class); lastMessageId = oldMessage.mId; EmailContent.Message newMessage = - EmailContent.Message.restoreMessageWithId(context, oldMessage.mId); + EmailContent.Message.restoreMessageWithId(mContext, oldMessage.mId); if (newMessage != null) { - mailbox = Mailbox.restoreMailboxWithId(context, newMessage.mMailboxKey); + mailbox = Mailbox.restoreMailboxWithId(mContext, newMessage.mMailboxKey); if (mailbox == null) { continue; // Mailbox removed. Move to the next message. } @@ -994,17 +1364,17 @@ public class ImapService extends Service { if (remoteStore == null && (changeMoveToTrash || changeRead || changeFlagged || changeMailbox || changeAnswered)) { - remoteStore = Store.getInstance(account, context); + remoteStore = Store.getInstance(account, mContext); } // Dispatch here for specific change types if (changeMoveToTrash) { // Move message to trash - processPendingMoveToTrash(context, remoteStore, account, mailbox, oldMessage, + processPendingMoveToTrash(remoteStore, account, mailbox, oldMessage, newMessage); } else if (changeRead || changeFlagged || changeMailbox || changeAnswered) { - processPendingDataChange(context, remoteStore, mailbox, changeRead, - changeFlagged, changeMailbox, changeAnswered, oldMessage, newMessage); + processPendingDataChange(remoteStore, mailbox, changeRead, changeFlagged, + changeMailbox, changeAnswered, oldMessage, newMessage); } // Finally, delete the update @@ -1043,11 +1413,11 @@ public class ImapService extends Service { * @param mailbox the actual mailbox * @param messageId */ - private static void processUploadMessage(Context context, Store remoteStore, + private void processUploadMessage(ContentResolver resolver, Store remoteStore, Account account, Mailbox mailbox, long messageId) throws MessagingException { EmailContent.Message newMessage = - EmailContent.Message.restoreMessageWithId(context, messageId); + EmailContent.Message.restoreMessageWithId(mContext, messageId); boolean deleteUpdate = false; if (newMessage == null) { deleteUpdate = true; @@ -1065,15 +1435,14 @@ public class ImapService extends Service { deleteUpdate = false; Log.d(Logging.LOG_TAG, "Upsync skipped; mailbox changed, id=" + messageId); } else { -// Log.d(Logging.LOG_TAG, "Upsyc triggered for message id=" + messageId); -// deleteUpdate = processPendingAppend(context, remoteStore, account, mailbox, - //newMessage); + Log.d(Logging.LOG_TAG, "Upsyc triggered for message id=" + messageId); + deleteUpdate = processPendingAppend(remoteStore, account, mailbox, newMessage); } if (deleteUpdate) { // Finally, delete the update (if any) Uri uri = ContentUris.withAppendedId( EmailContent.Message.UPDATED_CONTENT_URI, messageId); - context.getContentResolver().delete(uri, null, null); + resolver.delete(uri, null, null); } } @@ -1088,15 +1457,15 @@ public class ImapService extends Service { * @param oldMessage the message in it's pre-change state * @param newMessage the current version of the message */ - private static void processPendingDataChange(final Context context, Store remoteStore, - Mailbox mailbox, boolean changeRead, boolean changeFlagged, boolean changeMailbox, - boolean changeAnswered, EmailContent.Message oldMessage, - final EmailContent.Message newMessage) throws MessagingException { + private void processPendingDataChange(Store remoteStore, Mailbox mailbox, boolean changeRead, + boolean changeFlagged, boolean changeMailbox, boolean changeAnswered, + EmailContent.Message oldMessage, final EmailContent.Message newMessage) + throws MessagingException { // New mailbox is the mailbox this message WILL be in (same as the one it WAS in if it isn't // being moved Mailbox newMailbox = mailbox; // Mailbox is the original remote mailbox (the one we're acting on) - mailbox = getRemoteMailboxForMessage(context, oldMessage); + mailbox = getRemoteMailboxForMessage(oldMessage); // 0. No remote update if the message is local-only if (newMessage.mServerId == null || newMessage.mServerId.equals("") @@ -1159,7 +1528,7 @@ public class ImapService extends Service { cv.put(EmailContent.Message.SERVER_ID, newUid); // We only have one message, so, any updates _must_ be for it. Otherwise, // we'd have to cycle through to find the one with the same server ID. - context.getContentResolver().update(ContentUris.withAppendedId( + mContext.getContentResolver().update(ContentUris.withAppendedId( EmailContent.Message.CONTENT_URI, newMessage.mId), cv, null, null); } @Override @@ -1182,7 +1551,7 @@ public class ImapService extends Service { * @param oldMessage The message copy that was saved in the updates shadow table * @param newMessage The message that was moved to the mailbox */ - private static void processPendingMoveToTrash(final Context context, Store remoteStore, + private void processPendingMoveToTrash(Store remoteStore, Account account, Mailbox newMailbox, EmailContent.Message oldMessage, final EmailContent.Message newMessage) throws MessagingException { @@ -1194,7 +1563,7 @@ public class ImapService extends Service { // 1. Escape early if we can't find the local mailbox // TODO smaller projection here - Mailbox oldMailbox = getRemoteMailboxForMessage(context, oldMessage); + Mailbox oldMailbox = getRemoteMailboxForMessage(oldMessage); if (oldMailbox == null) { // can't find old mailbox, it may have been deleted. just return. return; @@ -1217,7 +1586,7 @@ public class ImapService extends Service { sentinel.mFlagLoaded = EmailContent.Message.FLAG_LOADED_DELETED; sentinel.mFlagRead = true; sentinel.mServerId = oldMessage.mServerId; - sentinel.save(context); + sentinel.save(mContext); return; } @@ -1267,13 +1636,12 @@ public class ImapService extends Service { remoteFolder.copyMessages(new Message[] { remoteMessage }, remoteTrashFolder, new Folder.MessageUpdateCallbacks() { - @Override public void onMessageUidChange(Message message, String newUid) { // update the UID in the local trash folder, because some stores will // have to change it when copying to remoteTrashFolder ContentValues cv = new ContentValues(); cv.put(EmailContent.Message.SERVER_ID, newUid); - context.getContentResolver().update(newMessage.getUri(), cv, null, null); + mContext.getContentResolver().update(newMessage.getUri(), cv, null, null); } /** @@ -1281,9 +1649,8 @@ public class ImapService extends Service { * deleted (e.g. it was already deleted from the server.) In this case, * attempt to delete the local copy as well. */ - @Override public void onMessageNotFound(Message message) { - context.getContentResolver().delete(newMessage.getUri(), null, null); + mContext.getContentResolver().delete(newMessage.getUri(), null, null); } }); remoteTrashFolder.close(false); @@ -1303,7 +1670,7 @@ public class ImapService extends Service { * @param oldMailbox The local trash mailbox * @param oldMessage The message that was deleted from the trash */ - private static void processPendingDeleteFromTrash(Context context, Store remoteStore, + private void processPendingDeleteFromTrash(Store remoteStore, Account account, Mailbox oldMailbox, EmailContent.Message oldMessage) throws MessagingException { @@ -1338,127 +1705,482 @@ public class ImapService extends Service { } /** - * A message and numeric uid that's easily sortable + * Process a pending append message command. This command uploads a local message to the + * server, first checking to be sure that the server message is not newer than + * the local message. + * + * @param remoteStore the remote store we're working in + * @param account The account in which we are working + * @param newMailbox The mailbox we're appending to + * @param message The message we're appending + * @return true if successfully uploaded */ - private static class SortableMessage { - private final Message mMessage; - private final long mUid; + private boolean processPendingAppend(Store remoteStore, Account account, + Mailbox newMailbox, EmailContent.Message message) + throws MessagingException { - SortableMessage(Message message, long uid) { - mMessage = message; - mUid = uid; - } - } + boolean updateInternalDate = false; + boolean updateMessage = false; + boolean deleteMessage = false; - public int searchMailbox(Context context, long accountId, SearchParams searchParams, - long destMailboxId) throws MessagingException { - try { - return searchMailboxImpl(context, accountId, searchParams, destMailboxId); - } finally { - // Tell UI + // 1. Find the remote folder that we're appending to and create and/or open it + Folder remoteFolder = remoteStore.getFolder(newMailbox.mServerId); + if (!remoteFolder.exists()) { + if (!remoteFolder.canCreate(FolderType.HOLDS_MESSAGES)) { + // This is POP3, we cannot actually upload. Instead, we'll update the message + // locally with a fake serverId (so we don't keep trying here) and return. + if (message.mServerId == null || message.mServerId.length() == 0) { + message.mServerId = LOCAL_SERVERID_PREFIX + message.mId; + Uri uri = + ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, message.mId); + ContentValues cv = new ContentValues(); + cv.put(EmailContent.Message.SERVER_ID, message.mServerId); + mContext.getContentResolver().update(uri, cv, null, null); + } + return true; + } + if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { + // This is a (hopefully) transient error and we return false to try again later + return false; + } + } + remoteFolder.open(OpenMode.READ_WRITE); + if (remoteFolder.getMode() != OpenMode.READ_WRITE) { + return false; } - } - private int searchMailboxImpl(final Context context, long accountId, SearchParams searchParams, - final long destMailboxId) throws MessagingException { - final Account account = Account.restoreAccountWithId(context, accountId); - final Mailbox mailbox = Mailbox.restoreMailboxWithId(context, searchParams.mMailboxId); - final Mailbox destMailbox = Mailbox.restoreMailboxWithId(context, destMailboxId); - if (account == null || mailbox == null || destMailbox == null) { - Log.d(Logging.LOG_TAG, "Attempted search for " + searchParams - + " but account or mailbox information was missing"); - return 0; + // 2. If possible, load a remote message with the matching UID + Message remoteMessage = null; + if (message.mServerId != null && message.mServerId.length() > 0) { + remoteMessage = remoteFolder.getMessage(message.mServerId); } - // Tell UI that we're loading messages + // 3. If a remote message could not be found, upload our local message + if (remoteMessage == null) { + // 3a. Create a legacy message to upload + Message localMessage = LegacyConversions.makeMessage(mContext, message); + + // 3b. Upload it + FetchProfile fp = new FetchProfile(); + fp.add(FetchProfile.Item.BODY); + remoteFolder.appendMessages(new Message[] { localMessage }); + + // 3b. And record the UID from the server + message.mServerId = localMessage.getUid(); + updateInternalDate = true; + updateMessage = true; + } else { + // 4. If the remote message exists we need to determine which copy to keep. + FetchProfile fp = new FetchProfile(); + fp.add(FetchProfile.Item.ENVELOPE); + remoteFolder.fetch(new Message[] { remoteMessage }, fp, null); + Date localDate = new Date(message.mServerTimeStamp); + Date remoteDate = remoteMessage.getInternalDate(); + if (remoteDate != null && remoteDate.compareTo(localDate) > 0) { + // 4a. If the remote message is newer than ours we'll just + // delete ours and move on. A sync will get the server message + // if we need to be able to see it. + deleteMessage = true; + } else { + // 4b. Otherwise we'll upload our message and then delete the remote message. - Store remoteStore = Store.getInstance(account, context); - Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); - remoteFolder.open(OpenMode.READ_WRITE); + // Create a legacy message to upload + Message localMessage = LegacyConversions.makeMessage(mContext, message); - SortableMessage[] sortableMessages = new SortableMessage[0]; - if (searchParams.mOffset == 0) { - // Get the "bare" messages (basically uid) - Message[] remoteMessages = remoteFolder.getMessages(searchParams, null); - int remoteCount = remoteMessages.length; - if (remoteCount > 0) { - sortableMessages = new SortableMessage[remoteCount]; - int i = 0; - for (Message msg : remoteMessages) { - sortableMessages[i++] = new SortableMessage(msg, Long.parseLong(msg.getUid())); + // 4c. Upload it + fp.clear(); + fp = new FetchProfile(); + fp.add(FetchProfile.Item.BODY); + remoteFolder.appendMessages(new Message[] { localMessage }); + + // 4d. Record the UID and new internalDate from the server + message.mServerId = localMessage.getUid(); + updateInternalDate = true; + updateMessage = true; + + // 4e. And delete the old copy of the message from the server + remoteMessage.setFlag(Flag.DELETED, true); + } + } + + // 5. If requested, Best-effort to capture new "internaldate" from the server + if (updateInternalDate && message.mServerId != null) { + try { + Message remoteMessage2 = remoteFolder.getMessage(message.mServerId); + if (remoteMessage2 != null) { + FetchProfile fp2 = new FetchProfile(); + fp2.add(FetchProfile.Item.ENVELOPE); + remoteFolder.fetch(new Message[] { remoteMessage2 }, fp2, null); + message.mServerTimeStamp = remoteMessage2.getInternalDate().getTime(); + updateMessage = true; } - // Sort the uid's, most recent first - // Note: Not all servers will be nice and return results in the order of request; - // those that do will see messages arrive from newest to oldest - Arrays.sort(sortableMessages, new Comparator<SortableMessage>() { - @Override - public int compare(SortableMessage lhs, SortableMessage rhs) { - return lhs.mUid > rhs.mUid ? -1 : lhs.mUid < rhs.mUid ? 1 : 0; - } - }); - sSearchResults.put(accountId, sortableMessages); + } catch (MessagingException me) { + // skip it - we can live without this } - } else { - sortableMessages = sSearchResults.get(accountId); } - final int numSearchResults = sortableMessages.length; - final int numToLoad = - Math.min(numSearchResults - searchParams.mOffset, searchParams.mLimit); - if (numToLoad <= 0) { - return 0; + // 6. Perform required edits to local copy of message + if (deleteMessage || updateMessage) { + Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, message.mId); + ContentResolver resolver = mContext.getContentResolver(); + if (deleteMessage) { + resolver.delete(uri, null, null); + } else if (updateMessage) { + ContentValues cv = new ContentValues(); + cv.put(EmailContent.Message.SERVER_ID, message.mServerId); + cv.put(EmailContent.Message.SERVER_TIMESTAMP, message.mServerTimeStamp); + resolver.update(uri, cv, null, null); + } } - final ArrayList<Message> messageList = new ArrayList<Message>(); - for (int i = searchParams.mOffset; i < numToLoad + searchParams.mOffset; i++) { - messageList.add(sortableMessages[i].mMessage); + return true; + } + + /** + * Finish loading a message that have been partially downloaded. + * + * @param messageId the message to load + * @param listener the callback by which results will be reported + */ + public void loadMessageForView(final long messageId, MessagingListener listener) { + mListeners.loadMessageForViewStarted(messageId); + put("loadMessageForViewRemote", listener, new Runnable() { + public void run() { + try { + // 1. Resample the message, in case it disappeared or synced while + // this command was in queue + EmailContent.Message message = + EmailContent.Message.restoreMessageWithId(mContext, messageId); + if (message == null) { + mListeners.loadMessageForViewFailed(messageId, "Unknown message"); + return; + } + if (message.mFlagLoaded == EmailContent.Message.FLAG_LOADED_COMPLETE) { + mListeners.loadMessageForViewFinished(messageId); + return; + } + + // 2. Open the remote folder. + // TODO combine with common code in loadAttachment + Account account = Account.restoreAccountWithId(mContext, message.mAccountKey); + Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); + if (account == null || mailbox == null) { + mListeners.loadMessageForViewFailed(messageId, "null account or mailbox"); + return; + } + TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); + + Store remoteStore = Store.getInstance(account, mContext); + String remoteServerId = mailbox.mServerId; + // If this is a search result, use the protocolSearchInfo field to get the + // correct remote location + if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) { + remoteServerId = message.mProtocolSearchInfo; + } + Folder remoteFolder = remoteStore.getFolder(remoteServerId); + remoteFolder.open(OpenMode.READ_WRITE); + + // 3. Set up to download the entire message + Message remoteMessage = remoteFolder.getMessage(message.mServerId); + FetchProfile fp = new FetchProfile(); + fp.add(FetchProfile.Item.BODY); + remoteFolder.fetch(new Message[] { remoteMessage }, fp, null); + + // 4. Write to provider + copyOneMessageToProvider(remoteMessage, account, mailbox, + EmailContent.Message.FLAG_LOADED_COMPLETE); + + // 5. Notify UI + mListeners.loadMessageForViewFinished(messageId); + + } catch (MessagingException me) { + if (Logging.LOGD) Log.v(Logging.LOG_TAG, "", me); + mListeners.loadMessageForViewFailed(messageId, me.getMessage()); + } catch (RuntimeException rte) { + mListeners.loadMessageForViewFailed(messageId, rte.getMessage()); + } + } + }); + } + + /** + * Attempts to load the attachment specified by id from the given account and message. + */ + public void loadAttachment(final long accountId, final long messageId, final long mailboxId, + final long attachmentId, MessagingListener listener, final boolean background) { + mListeners.loadAttachmentStarted(accountId, messageId, attachmentId, true); + + put("loadAttachment", listener, new Runnable() { + public void run() { + try { + //1. Check if the attachment is already here and return early in that case + Attachment attachment = + Attachment.restoreAttachmentWithId(mContext, attachmentId); + if (attachment == null) { + mListeners.loadAttachmentFailed(accountId, messageId, attachmentId, + new MessagingException("The attachment is null"), + background); + return; + } + if (Utility.attachmentExists(mContext, attachment)) { + mListeners.loadAttachmentFinished(accountId, messageId, attachmentId); + return; + } + + // 2. Open the remote folder. + // TODO all of these could be narrower projections + Account account = Account.restoreAccountWithId(mContext, accountId); + Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); + EmailContent.Message message = + EmailContent.Message.restoreMessageWithId(mContext, messageId); + + if (account == null || mailbox == null || message == null) { + mListeners.loadAttachmentFailed(accountId, messageId, attachmentId, + new MessagingException( + "Account, mailbox, message or attachment are null"), + background); + return; + } + TrafficStats.setThreadStatsTag( + TrafficFlags.getAttachmentFlags(mContext, account)); + + Store remoteStore = Store.getInstance(account, mContext); + Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); + remoteFolder.open(OpenMode.READ_WRITE); + + // 3. Generate a shell message in which to retrieve the attachment, + // and a shell BodyPart for the attachment. Then glue them together. + Message storeMessage = remoteFolder.createMessage(message.mServerId); + MimeBodyPart storePart = new MimeBodyPart(); + storePart.setSize((int)attachment.mSize); + storePart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, + attachment.mLocation); + storePart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, + String.format("%s;\n name=\"%s\"", + attachment.mMimeType, + attachment.mFileName)); + // TODO is this always true for attachments? I think we dropped the + // true encoding along the way + storePart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); + + MimeMultipart multipart = new MimeMultipart(); + multipart.setSubType("mixed"); + multipart.addBodyPart(storePart); + + storeMessage.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed"); + storeMessage.setBody(multipart); + + // 4. Now ask for the attachment to be fetched + FetchProfile fp = new FetchProfile(); + fp.add(storePart); + remoteFolder.fetch(new Message[] { storeMessage }, fp, + mController.new MessageRetrievalListenerBridge( + messageId, attachmentId)); + + // If we failed to load the attachment, throw an Exception here, so that + // AttachmentDownloadService knows that we failed + if (storePart.getBody() == null) { + throw new MessagingException("Attachment not loaded."); + } + + // 5. Save the downloaded file and update the attachment as necessary + LegacyConversions.saveAttachmentBody(mContext, storePart, attachment, + accountId); + + // 6. Report success + mListeners.loadAttachmentFinished(accountId, messageId, attachmentId); + } + catch (MessagingException me) { + if (Logging.LOGD) Log.v(Logging.LOG_TAG, "", me); + mListeners.loadAttachmentFailed( + accountId, messageId, attachmentId, me, background); + } catch (IOException ioe) { + Log.e(Logging.LOG_TAG, "Error while storing attachment." + ioe.toString()); + } + }}); + } + + /** + * Attempt to send any messages that are sitting in the Outbox. + * @param account + * @param listener + */ + public void sendPendingMessages(final Account account, final long sentFolderId, + MessagingListener listener) { + put("sendPendingMessages", listener, new Runnable() { + public void run() { + sendPendingMessagesSynchronous(account, sentFolderId); + } + }); + } + + /** + * Attempt to send all messages sitting in the given account's outbox. Optionally, + * if the server requires it, the message will be moved to the given sent folder. + */ + public void sendPendingMessagesSynchronous(final Account account, + long sentFolderId) { + TrafficStats.setThreadStatsTag(TrafficFlags.getSmtpFlags(mContext, account)); + NotificationController nc = NotificationController.getInstance(mContext); + // 1. Loop through all messages in the account's outbox + long outboxId = Mailbox.findMailboxOfType(mContext, account.mId, Mailbox.TYPE_OUTBOX); + if (outboxId == Mailbox.NO_MAILBOX) { + return; } - // Get everything in one pass, rather than two (as in sync); this starts getting us - // usable results quickly. - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.FLAGS); - fp.add(FetchProfile.Item.ENVELOPE); - fp.add(FetchProfile.Item.STRUCTURE); - fp.add(FetchProfile.Item.BODY_SANE); - remoteFolder.fetch(messageList.toArray(new Message[0]), fp, - new MessageRetrievalListener() { - @Override - public void messageRetrieved(Message message) { + ContentResolver resolver = mContext.getContentResolver(); + Cursor c = resolver.query(EmailContent.Message.CONTENT_URI, + EmailContent.Message.ID_COLUMN_PROJECTION, + EmailContent.Message.MAILBOX_KEY + "=?", new String[] { Long.toString(outboxId) }, + null); + try { + // 2. exit early + if (c.getCount() <= 0) { + return; + } + // 3. do one-time setup of the Sender & other stuff + mListeners.sendPendingMessagesStarted(account.mId, -1); + + Sender sender = Sender.getInstance(mContext, account); + Store remoteStore = Store.getInstance(account, mContext); + boolean requireMoveMessageToSentFolder = remoteStore.requireCopyMessageToSentFolder(); + ContentValues moveToSentValues = null; + if (requireMoveMessageToSentFolder) { + moveToSentValues = new ContentValues(); + moveToSentValues.put(MessageColumns.MAILBOX_KEY, sentFolderId); + } + + // 4. loop through the available messages and send them + while (c.moveToNext()) { + long messageId = -1; try { - // Determine if the new message was already known (e.g. partial) - // And create or reload the full message info - EmailContent.Message localMessage = new EmailContent.Message(); - try { - // Copy the fields that are available into the message - LegacyConversions.updateMessageFields(localMessage, - message, account.mId, mailbox.mId); - // Commit the message to the local store - Utilities.saveOrUpdate(localMessage, context); - localMessage.mMailboxKey = destMailboxId; - // We load 50k or so; maybe it's complete, maybe not... - int flag = EmailContent.Message.FLAG_LOADED_COMPLETE; - // We store the serverId of the source mailbox into protocolSearchInfo - // This will be used by loadMessageForView, etc. to use the proper remote - // folder - localMessage.mProtocolSearchInfo = mailbox.mServerId; - if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) { - flag = EmailContent.Message.FLAG_LOADED_PARTIAL; + messageId = c.getLong(0); + mListeners.sendPendingMessagesStarted(account.mId, messageId); + // Don't send messages with unloaded attachments + if (Utility.hasUnloadedAttachments(mContext, messageId)) { + if (Email.DEBUG) { + Log.d(Logging.LOG_TAG, "Can't send #" + messageId + + "; unloaded attachments"); } - Utilities.copyOneMessageToProvider(context, message, localMessage, flag); - } catch (MessagingException me) { - Log.e(Logging.LOG_TAG, - "Error while copying downloaded message." + me); + continue; } - } catch (Exception e) { - Log.e(Logging.LOG_TAG, - "Error while storing downloaded message." + e.toString()); + sender.sendMessage(messageId); + } catch (MessagingException me) { + // report error for this message, but keep trying others + if (me instanceof AuthenticationFailedException) { + nc.showLoginFailedNotification(account.mId); + } + mListeners.sendPendingMessagesFailed(account.mId, messageId, me); + continue; } + // 5. move to sent, or delete + Uri syncedUri = + ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); + if (requireMoveMessageToSentFolder) { + // If this is a forwarded message and it has attachments, delete them, as they + // duplicate information found elsewhere (on the server). This saves storage. + EmailContent.Message msg = + EmailContent.Message.restoreMessageWithId(mContext, messageId); + if (msg != null && + ((msg.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0)) { + AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId, + messageId); + } + resolver.update(syncedUri, moveToSentValues, null, null); + } else { + AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId, + messageId); + Uri uri = + ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, messageId); + resolver.delete(uri, null, null); + resolver.delete(syncedUri, null, null); + } + } + // 6. report completion/success + mListeners.sendPendingMessagesCompleted(account.mId); + nc.cancelLoginFailedNotification(account.mId); + } catch (MessagingException me) { + if (me instanceof AuthenticationFailedException) { + nc.showLoginFailedNotification(account.mId); } + mListeners.sendPendingMessagesFailed(account.mId, -1, me); + } finally { + c.close(); + } + } - @Override - public void loadAttachmentProgress(int progress) { + /** + * Checks mail for an account. + * This entry point is for use by the mail checking service only, because it + * gives slightly different callbacks (so the service doesn't get confused by callbacks + * triggered by/for the foreground UI. + * + * TODO clean up the execution model which is unnecessarily threaded due to legacy code + * + * @param accountId the account to check + * @param listener + */ + public void checkMail(final long accountId, final long tag, final MessagingListener listener) { + mListeners.checkMailStarted(mContext, accountId, tag); + + // This puts the command on the queue (not synchronous) + listFolders(accountId, null); + + // Put this on the queue as well so it follows listFolders + put("checkMail", listener, new Runnable() { + public void run() { + // send any pending outbound messages. note, there is a slight race condition + // here if we somehow don't have a sent folder, but this should never happen + // because the call to sendMessage() would have built one previously. + long inboxId = -1; + Account account = Account.restoreAccountWithId(mContext, accountId); + if (account != null) { + long sentboxId = Mailbox.findMailboxOfType(mContext, accountId, + Mailbox.TYPE_SENT); + if (sentboxId != Mailbox.NO_MAILBOX) { + sendPendingMessagesSynchronous(account, sentboxId); + } + // find mailbox # for inbox and sync it. + // TODO we already know this in Controller, can we pass it in? + inboxId = Mailbox.findMailboxOfType(mContext, accountId, Mailbox.TYPE_INBOX); + if (inboxId != Mailbox.NO_MAILBOX) { + Mailbox mailbox = + Mailbox.restoreMailboxWithId(mContext, inboxId); + if (mailbox != null) { + synchronizeMailboxSynchronous(account, mailbox); + } + } + } + mListeners.checkMailFinished(mContext, accountId, inboxId, tag); } }); - return numSearchResults; } -}
\ No newline at end of file + + private static class Command { + public Runnable runnable; + + public MessagingListener listener; + + public String description; + + @Override + public String toString() { + return description; + } + } + + /** Results of the latest synchronization. */ + private static class SyncResults { + /** The total # of messages in the folder */ + public final int mTotalMessages; + /** A list of new message IDs; must not be {@code null} */ + public final ArrayList<Long> mAddedMessages; + + public SyncResults(int totalMessages, ArrayList<Long> addedMessages) { + if (addedMessages == null) { + throw new IllegalArgumentException("addedMessages must not be null"); + } + mTotalMessages = totalMessages; + mAddedMessages = addedMessages; + } + } +} diff --git a/src/com/android/email/NotificationController.java b/src/com/android/email/NotificationController.java index 4dfed5a47..991f3ba73 100644 --- a/src/com/android/email/NotificationController.java +++ b/src/com/android/email/NotificationController.java @@ -46,11 +46,12 @@ import com.android.emailcommon.Logging; import com.android.emailcommon.mail.Address; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; +import com.android.emailcommon.provider.EmailContent.AccountColumns; import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.EmailContent.Message; +import com.android.emailcommon.provider.EmailContent.MessageColumns; import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.utility.EmailAsyncTask; import com.android.emailcommon.utility.Utility; import com.google.common.annotations.VisibleForTesting; @@ -61,6 +62,7 @@ import java.util.HashSet; * Class that manages notifications. */ public class NotificationController { + private static final int NOTIFICATION_ID_SECURITY_NEEDED = 1; /** Reserved for {@link com.android.exchange.CalendarSyncEnabler} */ @SuppressWarnings("unused") private static final int NOTIFICATION_ID_EXCHANGE_CALENDAR_ADDED = 2; @@ -68,11 +70,8 @@ public class NotificationController { private static final int NOTIFICATION_ID_PASSWORD_EXPIRING = 4; private static final int NOTIFICATION_ID_PASSWORD_EXPIRED = 5; - private static final int NOTIFICATION_ID_BASE_MASK = 0xF0000000; private static final int NOTIFICATION_ID_BASE_NEW_MESSAGES = 0x10000000; private static final int NOTIFICATION_ID_BASE_LOGIN_WARNING = 0x20000000; - private static final int NOTIFICATION_ID_BASE_SECURITY_NEEDED = 0x30000000; - private static final int NOTIFICATION_ID_BASE_SECURITY_CHANGED = 0x40000000; /** Selection to retrieve accounts that should we notify user for changes */ private final static String NOTIFIED_ACCOUNT_SELECTION = @@ -87,15 +86,18 @@ public class NotificationController { private final Bitmap mGenericSenderIcon; private final Bitmap mGenericMultipleSenderIcon; private final Clock mClock; - /** Maps account id to its observer */ + // TODO We're maintaining all of our structures based upon the account ID. This is fine + // for now since the assumption is that we only ever look for changes in an account's + // INBOX. We should adjust our logic to use the mailbox ID instead. + /** Maps account id to the message data */ private final HashMap<Long, ContentObserver> mNotificationMap; private ContentObserver mAccountObserver; /** - * Suspend notifications for this mailbox. If {@link Mailbox.NO_MAILBOX}, no - * account notifications are suspended. If {@link Mailbox.COMBINED_INBOX}, - * notifications for all inboxes are suspended. + * Suspend notifications for this account. If {@link Account#NO_ACCOUNT}, no + * account notifications are suspended. If {@link Account#ACCOUNT_ID_COMBINED_VIEW}, + * notifications for all accounts are suspended. */ - private long mSuspendMailboxId = Mailbox.NO_MAILBOX; + private long mSuspendAccountId = Account.NO_ACCOUNT; /** * Timestamp indicating when the last message notification sound was played. @@ -142,7 +144,7 @@ public class NotificationController { private boolean needsOngoingNotification(int notificationId) { // "Security needed" must be ongoing so that the user doesn't close it; otherwise, sync will // be prevented until a reboot. Consider also doing this for password expired. - return (notificationId & NOTIFICATION_ID_BASE_MASK) == NOTIFICATION_ID_BASE_SECURITY_NEEDED; + return notificationId == NOTIFICATION_ID_SECURITY_NEEDED; } /** @@ -162,7 +164,7 @@ public class NotificationController { * to the settings for the given account. * @return A {@link Notification} that can be sent to the notification service. */ - private Notification createMailboxNotification(Mailbox mailbox, String ticker, + private Notification createAccountNotification(Account account, String ticker, CharSequence title, String contentText, Intent intent, Bitmap largeIcon, Integer number, boolean enableAudio, boolean ongoing) { // Pending Intent @@ -185,7 +187,6 @@ public class NotificationController { .setOngoing(ongoing); if (enableAudio) { - Account account = Account.restoreAccountWithId(mContext, mailbox.mAccountKey); setupSoundAndVibration(builder, account); } @@ -203,9 +204,9 @@ public class NotificationController { * @param intent The intent to start if the user clicks on the notification. * @param notificationId The ID of the notification to register with the service. */ - private void showMailboxNotification(Mailbox mailbox, String ticker, String title, + private void showAccountNotification(Account account, String ticker, String title, String contentText, Intent intent, int notificationId) { - Notification notification = createMailboxNotification(mailbox, ticker, title, contentText, + Notification notification = createAccountNotification(account, ticker, title, contentText, intent, null, null, true, needsOngoingNotification(notificationId)); mNotificationManager.notify(notificationId, notification); } @@ -213,9 +214,9 @@ public class NotificationController { /** * Returns a notification ID for new message notifications for the given account. */ - private int getNewMessageNotificationId(long mailboxId) { + private int getNewMessageNotificationId(long accountId) { // We assume accountId will always be less than 0x0FFFFFFF; is there a better way? - return (int) (NOTIFICATION_ID_BASE_NEW_MESSAGES + mailboxId); + return (int) (NOTIFICATION_ID_BASE_NEW_MESSAGES + accountId); } /** @@ -268,40 +269,36 @@ public class NotificationController { } /** - * Temporarily suspend a single mailbox from receiving notifications. NOTE: only a single - * mailbox may ever be suspended at a time. So, if this method is invoked a second time, - * notifications for the previously mailbox will automatically be re-activated. - * @param suspend If {@code true}, suspend notifications for the given mailbox. Otherwise, - * re-activate notifications for the previously suspended mailbox. - * @param mailboxId The ID of the mailbox. If this is the special mailbox ID - * {@link Account#ACCOUNT_ID_COMBINED_VIEW}, notifications for all inboxes are - * suspended. If {@code suspend} is {@code false}, the mailbox ID is ignored. + * Temporarily suspend a single account from receiving notifications. NOTE: only a single + * account may ever be suspended at a time. So, if this method is invoked a second time, + * notifications for the previously suspended account will automatically be re-activated. + * @param suspend If {@code true}, suspend notifications for the given account. Otherwise, + * re-activate notifications for the previously suspended account. + * @param accountId The ID of the account. If this is the special account ID + * {@link Account#ACCOUNT_ID_COMBINED_VIEW}, notifications for all accounts are + * suspended. If {@code suspend} is {@code false}, the account ID is ignored. */ - public void suspendMessageNotification(boolean suspend, long mailboxId) { - if (mSuspendMailboxId != Mailbox.NO_MAILBOX) { - // we're already suspending a mailbox; un-suspend it - mSuspendMailboxId = Mailbox.NO_MAILBOX; + public void suspendMessageNotification(boolean suspend, long accountId) { + if (mSuspendAccountId != Account.NO_ACCOUNT) { + // we're already suspending an account; un-suspend it + mSuspendAccountId = Account.NO_ACCOUNT; } - if (suspend && mailboxId != Mailbox.NO_MAILBOX) { - mSuspendMailboxId = mailboxId; - } - if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { - // Only go onto the notification handler if we really, absolutely need to - ensureHandlerExists(); - sNotificationHandler.post(new Runnable() { - @Override - public void run() { - for (long accountId: mNotificationMap.keySet()) { - long mailboxId = - Mailbox.findMailboxOfType(mContext, accountId, Mailbox.TYPE_INBOX); - if (mailboxId != Mailbox.NO_MAILBOX) { - mNotificationManager.cancel(getNewMessageNotificationId(mailboxId)); + if (suspend && accountId != Account.NO_ACCOUNT && accountId > 0L) { + mSuspendAccountId = accountId; + if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) { + // Only go onto the notification handler if we really, absolutely need to + ensureHandlerExists(); + sNotificationHandler.post(new Runnable() { + @Override + public void run() { + for (long accountId : mNotificationMap.keySet()) { + mNotificationManager.cancel(getNewMessageNotificationId(accountId)); } } - } - }); - } else { - mNotificationManager.cancel(getNewMessageNotificationId(mailboxId)); + }); + } else { + mNotificationManager.cancel(getNewMessageNotificationId(accountId)); + } } } @@ -316,7 +313,8 @@ public class NotificationController { } /** - * Registers an observer for changes to mailboxes in the given account. + * Registers an observer for changes to the INBOX for the given account. Since accounts + * may only have a single INBOX, we will never have more than one observer for an account. * NOTE: This must be called on the notification handler thread. * @param accountId The ID of the account to register the observer for. May be * {@link Account#ACCOUNT_ID_COMBINED_VIEW} to register observers for all @@ -339,11 +337,17 @@ public class NotificationController { } else { ContentObserver obs = mNotificationMap.get(accountId); if (obs != null) return; // we're already observing; nothing to do + + Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, accountId, Mailbox.TYPE_INBOX); + if (mailbox == null) { + Log.w(Logging.LOG_TAG, "Could not load INBOX for account id: " + accountId); + return; + } if (Email.DEBUG) { Log.i(Logging.LOG_TAG, "Registering for notifications for account " + accountId); } ContentObserver observer = new MessageContentObserver( - sNotificationHandler, mContext, accountId); + sNotificationHandler, mContext, mailbox.mId, accountId); resolver.registerContentObserver(Message.NOTIFIER_URI, true, observer); mNotificationMap.put(accountId, observer); // Now, ping the observer for any initial notifications @@ -405,18 +409,9 @@ public class NotificationController { * NOTE: DO NOT CALL THIS METHOD FROM THE UI THREAD (DATABASE ACCESS) */ @VisibleForTesting - Notification createNewMessageNotification(long mailboxId, long messageId, + Notification createNewMessageNotification(long accountId, long mailboxId, long messageId, int unseenMessageCount, int unreadCount) { - final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); - if (mailbox == null) { - return null; - } - // No notification if we're suspended... - if (mSuspendMailboxId == mailboxId || (mSuspendMailboxId == Mailbox.QUERY_ALL_INBOXES && - mailbox.mType == Mailbox.TYPE_INBOX)) { - return null; - } - final Account account = Account.restoreAccountWithId(mContext, mailbox.mAccountKey); + final Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) { return null; } @@ -437,24 +432,22 @@ public class NotificationController { final SpannableString title = getNewMessageTitle(senderName, unseenMessageCount); // TODO: add in display name on the second line for the text, once framework supports // multiline texts. - // Show account name if an inbox; otherwise mailbox name final String text = multipleUnseen - ? ((mailbox.mType == Mailbox.TYPE_INBOX) ? account.mDisplayName : - mailbox.mDisplayName) + ? account.mDisplayName : message.mSubject; final Bitmap largeIcon = senderPhoto != null ? senderPhoto : mGenericSenderIcon; final Integer number = unreadCount > 1 ? unreadCount : null; final Intent intent; if (unseenMessageCount > 1) { - intent = Welcome.createOpenAccountInboxIntent(mContext, account.mId); + intent = Welcome.createOpenAccountInboxIntent(mContext, accountId); } else { - intent = Welcome.createOpenMessageIntent(mContext, account.mId, mailboxId, messageId); + intent = Welcome.createOpenMessageIntent(mContext, accountId, mailboxId, messageId); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); long now = mClock.getTime(); boolean enableAudio = (now - mLastMessageNotifyTime) > MIN_SOUND_INTERVAL_MS; - Notification notification = createMailboxNotification( - mailbox, title.toString(), title, text, + Notification notification = createAccountNotification( + account, title.toString(), title, text, intent, largeIcon, number, enableAudio, false); mLastMessageNotifyTime = now; return notification; @@ -509,10 +502,9 @@ public class NotificationController { * NOTE: DO NOT CALL THIS METHOD FROM THE UI THREAD (DATABASE ACCESS) */ public void showDownloadForwardFailedNotification(Attachment attachment) { - Message message = Message.restoreMessageWithId(mContext, attachment.mMessageKey); - if (message == null) return; - Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); - showMailboxNotification(mailbox, + final Account account = Account.restoreAccountWithId(mContext, attachment.mAccountKey); + if (account == null) return; + showAccountNotification(account, mContext.getString(R.string.forward_download_failed_ticker), mContext.getString(R.string.forward_download_failed_title), attachment.mFileName, @@ -535,10 +527,7 @@ public class NotificationController { public void showLoginFailedNotification(long accountId) { final Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) return; - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; - showMailboxNotification(mailbox, + showAccountNotification(account, mContext.getString(R.string.login_failed_ticker, account.mDisplayName), mContext.getString(R.string.login_failed_title), account.getDisplayName(), @@ -563,9 +552,6 @@ public class NotificationController { public void showPasswordExpiringNotification(long accountId) { Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) return; - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(mContext, accountId, false); @@ -573,7 +559,7 @@ public class NotificationController { String ticker = mContext.getString(R.string.password_expire_warning_ticker_fmt, accountName); String title = mContext.getString(R.string.password_expire_warning_content_title); - showMailboxNotification(mailbox, ticker, title, accountName, intent, + showAccountNotification(account, ticker, title, accountName, intent, NOTIFICATION_ID_PASSWORD_EXPIRING); } @@ -586,16 +572,13 @@ public class NotificationController { public void showPasswordExpiredNotification(long accountId) { Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) return; - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(mContext, accountId, true); String accountName = account.getDisplayName(); String ticker = mContext.getString(R.string.password_expired_ticker); String title = mContext.getString(R.string.password_expired_content_title); - showMailboxNotification(mailbox, ticker, title, accountName, intent, + showAccountNotification(account, ticker, title, accountName, intent, NOTIFICATION_ID_PASSWORD_EXPIRED); } @@ -608,138 +591,129 @@ public class NotificationController { } /** - * Show (or update) a security needed notification. If tapped, the user is taken to a - * dialog asking whether he wants to update his settings. + * Show (or update) a security needed notification. The given account is used to update + * the display text, but, all accounts share the same notification ID. */ public void showSecurityNeededNotification(Account account) { - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; Intent intent = AccountSecurity.actionUpdateSecurityIntent(mContext, account.mId, true); String accountName = account.getDisplayName(); String ticker = - mContext.getString(R.string.security_needed_ticker_fmt, accountName); - String title = mContext.getString(R.string.security_notification_content_update_title); - showMailboxNotification(mailbox, ticker, title, accountName, intent, - (int)(NOTIFICATION_ID_BASE_SECURITY_NEEDED + account.mId)); - } - - /** - * Show (or update) a security changed notification. If tapped, the user is taken to the - * account settings screen where he can view the list of enforced policies - */ - public void showSecurityChangedNotification(Account account) { - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; - Intent intent = AccountSettings.createAccountSettingsIntent(mContext, account.mId, null); - String accountName = account.getDisplayName(); - String ticker = - mContext.getString(R.string.security_changed_ticker_fmt, accountName); - String title = mContext.getString(R.string.security_notification_content_change_title); - showMailboxNotification(mailbox, ticker, title, accountName, intent, - (int)(NOTIFICATION_ID_BASE_SECURITY_CHANGED + account.mId)); + mContext.getString(R.string.security_notification_ticker_fmt, accountName); + String title = mContext.getString(R.string.security_notification_content_title); + showAccountNotification(account, ticker, title, accountName, intent, + NOTIFICATION_ID_SECURITY_NEEDED); } /** - * Show (or update) a security unsupported notification. If tapped, the user is taken to the - * account settings screen where he can view the list of unsupported policies - */ - public void showSecurityUnsupportedNotification(Account account) { - final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, - Mailbox.TYPE_INBOX); - if (mailbox == null) return; - Intent intent = AccountSettings.createAccountSettingsIntent(mContext, account.mId, null); - String accountName = account.getDisplayName(); - String ticker = - mContext.getString(R.string.security_unsupported_ticker_fmt, accountName); - String title = mContext.getString(R.string.security_notification_content_unsupported_title); - showMailboxNotification(mailbox, ticker, title, accountName, intent, - (int)(NOTIFICATION_ID_BASE_SECURITY_NEEDED + account.mId)); - } - - /** - * Cancels all security needed notifications. + * Cancels the security needed notification. */ public void cancelSecurityNeededNotification() { - EmailAsyncTask.runAsyncParallel(new Runnable() { - @Override - public void run() { - Cursor c = mContext.getContentResolver().query(Account.CONTENT_URI, - Account.ID_PROJECTION, null, null, null); - try { - while (c.moveToNext()) { - long id = c.getLong(Account.ID_PROJECTION_COLUMN); - mNotificationManager.cancel( - (int)(NOTIFICATION_ID_BASE_SECURITY_NEEDED + id)); - } - } - finally { - c.close(); - } - }}); + mNotificationManager.cancel(NOTIFICATION_ID_SECURITY_NEEDED); } /** * Observer invoked whenever a message we're notifying the user about changes. */ private static class MessageContentObserver extends ContentObserver { + /** A selection to get messages the user hasn't seen before */ + private final static String MESSAGE_SELECTION = + MessageColumns.MAILBOX_KEY + "=? AND " + + MessageColumns.ID + ">? AND " + + MessageColumns.FLAG_READ + "=0 AND " + + Message.FLAG_LOADED_SELECTION; private final Context mContext; + private final long mMailboxId; private final long mAccountId; public MessageContentObserver( - Handler handler, Context context, long accountId) { + Handler handler, Context context, long mailboxId, long accountId) { super(handler); mContext = context; + mMailboxId = mailboxId; mAccountId = accountId; } @Override public void onChange(boolean selfChange) { + if (mAccountId == sInstance.mSuspendAccountId + || sInstance.mSuspendAccountId == Account.ACCOUNT_ID_COMBINED_VIEW) { + return; + } + ContentObserver observer = sInstance.mNotificationMap.get(mAccountId); + if (observer == null) { + // Notification for a mailbox that we aren't observing; account is probably + // being deleted. + Log.w(Logging.LOG_TAG, "Received notification when observer data was null"); + return; + } Account account = Account.restoreAccountWithId(mContext, mAccountId); - if (observer == null || account == null) { + if (account == null) { Log.w(Logging.LOG_TAG, "Couldn't find account for changed message notification"); return; } + long oldMessageId = account.mNotifiedMessageId; + int oldMessageCount = account.mNotifiedMessageCount; ContentResolver resolver = mContext.getContentResolver(); - Cursor c = resolver.query(ContentUris.withAppendedId( - EmailContent.MAILBOX_NOTIFICATION_URI, mAccountId), - EmailContent.NOTIFICATION_PROJECTION, null, null, null); + Long lastSeenMessageId = Utility.getFirstRowLong( + mContext, ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailboxId), + new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY }, + null, null, null, 0); + if (lastSeenMessageId == null) { + // Mailbox got nuked. Could be that the account is in the process of being deleted + Log.w(Logging.LOG_TAG, "Couldn't find mailbox for changed message notification"); + return; + } + + Cursor c = resolver.query( + Message.CONTENT_URI, EmailContent.ID_PROJECTION, + MESSAGE_SELECTION, + new String[] { Long.toString(mMailboxId), Long.toString(lastSeenMessageId) }, + MessageColumns.ID + " DESC"); + if (c == null) { + // Couldn't find message info - things may be getting deleted in bulk. + Log.w(Logging.LOG_TAG, "#onChange(); NULL response for message id query"); + return; + } try { - while (c.moveToNext()) { - long mailboxId = c.getLong(EmailContent.NOTIFICATION_MAILBOX_ID_COLUMN); - if (mailboxId == 0) continue; - int messageCount = - c.getInt(EmailContent.NOTIFICATION_MAILBOX_MESSAGE_COUNT_COLUMN); - int unreadCount = - c.getInt(EmailContent.NOTIFICATION_MAILBOX_UNREAD_COUNT_COLUMN); - - Mailbox m = Mailbox.restoreMailboxWithId(mContext, mailboxId); - long newMessageId = Utility.getFirstRowLong(mContext, - ContentUris.withAppendedId( - EmailContent.MAILBOX_MOST_RECENT_MESSAGE_URI, mailboxId), - Message.ID_COLUMN_PROJECTION, null, null, null, - Message.ID_MAILBOX_COLUMN_ID, -1L); - // TODO: Remove debug logging - Log.d(Logging.LOG_TAG, "Changes to " + account.mDisplayName + "/" + - m.mDisplayName + ", count: " + messageCount + ", lastNotified: " + - m.mLastNotifiedMessageKey + ", mostRecent: " + newMessageId); - Notification n = sInstance.createNewMessageNotification(mailboxId, newMessageId, - messageCount, unreadCount); + int newMessageCount = c.getCount(); + long newMessageId = 0L; + if (c.moveToNext()) { + newMessageId = c.getLong(EmailContent.ID_PROJECTION_COLUMN); + } + + if (newMessageCount == 0) { + // No messages to notify for; clear the notification + int notificationId = sInstance.getNewMessageNotificationId(mAccountId); + sInstance.mNotificationManager.cancel(notificationId); + } else if (newMessageCount != oldMessageCount + || (newMessageId != 0 && newMessageId != oldMessageId)) { + // Either the count or last message has changed; update the notification + Integer unreadCount = Utility.getFirstRowInt( + mContext, ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailboxId), + new String[] { MailboxColumns.UNREAD_COUNT }, + null, null, null, 0); + if (unreadCount == null) { + Log.w(Logging.LOG_TAG, "Couldn't find unread count for mailbox"); + return; + } + + Notification n = sInstance.createNewMessageNotification( + mAccountId, mMailboxId, newMessageId, + newMessageCount, unreadCount); if (n != null) { // Make the notification visible sInstance.mNotificationManager.notify( - sInstance.getNewMessageNotificationId(mailboxId), n); + sInstance.getNewMessageNotificationId(mAccountId), n); } - // Save away the new values - ContentValues cv = new ContentValues(); - cv.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, newMessageId); - cv.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT, messageCount); - resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), cv, - null, null); } + // Save away the new values + ContentValues cv = new ContentValues(); + cv.put(AccountColumns.NOTIFIED_MESSAGE_ID, newMessageId); + cv.put(AccountColumns.NOTIFIED_MESSAGE_COUNT, newMessageCount); + resolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId), cv, + null, null); } finally { c.close(); } @@ -760,7 +734,8 @@ public class NotificationController { @Override public void onChange(boolean selfChange) { final ContentResolver resolver = mContext.getContentResolver(); - final Cursor c = resolver.query(Account.CONTENT_URI, EmailContent.ID_PROJECTION, + final Cursor c = resolver.query( + Account.CONTENT_URI, EmailContent.ID_PROJECTION, NOTIFIED_ACCOUNT_SELECTION, null, null); final HashSet<Long> newAccountList = new HashSet<Long>(); final HashSet<Long> removedAccountList = new HashSet<Long>(); diff --git a/src/com/android/email/RecipientAdapter.java b/src/com/android/email/RecipientAdapter.java index bfa2cbe92..5312a771d 100644 --- a/src/com/android/email/RecipientAdapter.java +++ b/src/com/android/email/RecipientAdapter.java @@ -16,12 +16,12 @@ package com.android.email; -import com.android.ex.chips.BaseRecipientAdapter; -import com.android.ex.chips.RecipientEditTextView; - import android.accounts.Account; import android.content.Context; +import com.android.ex.chips.BaseRecipientAdapter; +import com.android.ex.chips.RecipientEditTextView; + public class RecipientAdapter extends BaseRecipientAdapter { public RecipientAdapter(Context context, RecipientEditTextView list) { super(context); @@ -31,6 +31,7 @@ public class RecipientAdapter extends BaseRecipientAdapter { * Set the account when known. Causes the search to prioritize contacts from * that account. */ + @Override public void setAccount(Account account) { if (account != null) { // TODO: figure out how to infer the contacts account @@ -38,4 +39,19 @@ public class RecipientAdapter extends BaseRecipientAdapter { super.setAccount(new android.accounts.Account(account.name, "unknown")); } } + + @Override + protected int getDefaultPhotoResource() { + return R.drawable.ic_contact_picture; + } + + @Override + protected int getItemLayout() { + return R.layout.chips_recipient_dropdown_item; + } + + @Override + protected int getWaitingForDirectorySearchLayout() { + return R.layout.chips_waiting_for_directory_search; + } } diff --git a/src/com/android/email/RefreshManager.java b/src/com/android/email/RefreshManager.java index 0fe5847d5..4e5fd5876 100644 --- a/src/com/android/email/RefreshManager.java +++ b/src/com/android/email/RefreshManager.java @@ -16,15 +16,15 @@ package com.android.email; +import com.android.emailcommon.Logging; +import com.android.emailcommon.mail.MessagingException; +import com.android.emailcommon.utility.Utility; + import android.content.Context; import android.os.AsyncTask; import android.os.Handler; import android.util.Log; -import com.android.emailcommon.Logging; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.utility.Utility; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -107,12 +107,10 @@ public class RefreshManager { private long mLastRefreshTime; public boolean isRefreshing() { - // NOTE: For now, we're always allowing refresh (during service refactor) return mIsRefreshRequested || mIsRefreshing; } public boolean canRefresh() { - // NOTE: For now, we're always allowing refresh (during service refactor) return !isRefreshing(); } @@ -355,6 +353,7 @@ public class RefreshManager { } private class ControllerResult extends Controller.Result { + private boolean mSendMailExceptionReported = false; private String exceptionToString(MessagingException exception) { if (exception == null) { @@ -425,5 +424,33 @@ public class RefreshManager { } notifyRefreshStatusChanged(accountId, mailboxId); } + + + /** + * Send message progress callback. + * + * We don't keep track of the status of outboxes, but we monitor this to catch + * errors. + */ + @Override + public void sendMailCallback(MessagingException exception, long accountId, long messageId, + int progress) { + if (LOG_ENABLED) { + Log.d(Logging.LOG_TAG, "sendMailCallback " + accountId + ", " + + messageId + ", " + progress + ", " + exceptionToString(exception)); + } + if (progress == 0 && messageId == -1) { + mSendMailExceptionReported = false; + } + if (exception != null && !mSendMailExceptionReported) { + // Only the first error in a batch will be reported. + mSendMailExceptionReported = true; + reportError(accountId, messageId, + MessagingExceptionStrings.getErrorString(mContext, exception)); + } + if (progress == 100) { + mSendMailExceptionReported = false; + } + } } } diff --git a/src/com/android/email/SecurityPolicy.java b/src/com/android/email/SecurityPolicy.java index 9c2ed8b49..f571e8ad4 100644 --- a/src/com/android/email/SecurityPolicy.java +++ b/src/com/android/email/SecurityPolicy.java @@ -20,19 +20,13 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; -import android.content.ContentProviderOperation; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.OperationApplicationException; import android.database.Cursor; -import android.net.Uri; -import android.os.RemoteException; import android.util.Log; -import com.android.email.provider.EmailProvider; import com.android.email.service.EmailBroadcastProcessorService; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; @@ -40,12 +34,9 @@ import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.AccountColumns; import com.android.emailcommon.provider.EmailContent.PolicyColumns; import com.android.emailcommon.provider.Policy; -import com.android.emailcommon.utility.TextUtilities; import com.android.emailcommon.utility.Utility; import com.google.common.annotations.VisibleForTesting; -import java.util.ArrayList; - /** * Utility functions to support reading and writing security policies, and handshaking the device * into and out of various security states. @@ -213,12 +204,11 @@ public class SecurityPolicy { } /** - * API: Report that policies may have been updated due to rewriting values in an Account; we - * clear the aggregate policy (so it can be recomputed) and set the policies in the DPM + * API: Report that policies may have been updated due to rewriting values in an Account. + * @param accountId the account that has been updated, -1 if unknown/deleted */ - public synchronized void policiesUpdated() { + public synchronized void policiesUpdated(long accountId) { mAggregatePolicy = null; - setActivePolicies(); } /** @@ -231,7 +221,58 @@ public class SecurityPolicy { if (Email.DEBUG) { Log.d(TAG, "reducePolicies"); } - policiesUpdated(); + policiesUpdated(-1); + setActivePolicies(); + } + + /** + * API: Query if the proposed set of policies are supported on the device. + * + * @param policy the polices that were requested + * @return boolean if supported + */ + public boolean isSupported(Policy policy) { + // IMPLEMENTATION: At this time, the only policy which might not be supported is + // encryption (which requires low-level systems support). Other policies are fully + // supported by the framework and do not need to be checked. + if (policy.mRequireEncryption) { + int encryptionStatus = getDPM().getStorageEncryptionStatus(); + if (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) { + return false; + } + } + + // If we ever support devices that can't disable cameras for any reason, we should + // indicate as such in the mDontAllowCamera policy + + return true; + } + + /** + * API: Remove any unsupported policies + * + * This is used when we have a set of polices that have been requested, but the server + * is willing to allow unsupported policies to be considered optional. + * + * @param policy the polices that were requested + * @return the same PolicySet if all are supported; A replacement PolicySet if any + * unsupported policies were removed + */ + public Policy clearUnsupportedPolicies(Policy policy) { + // IMPLEMENTATION: At this time, the only policy which might not be supported is + // encryption (which requires low-level systems support). Other policies are fully + // supported by the framework and do not need to be checked. + if (policy.mRequireEncryption) { + int encryptionStatus = getDPM().getStorageEncryptionStatus(); + if (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) { + policy.mRequireEncryption = false; + } + } + + // If we ever support devices that can't disable cameras for any reason, we should + // clear the mDontAllowCamera policy + + return policy; } /** @@ -262,9 +303,6 @@ public class SecurityPolicy { if ((reasons & INACTIVE_NEED_ENCRYPTION) != 0) { sb.append("encryption "); } - if ((reasons & INACTIVE_PROTOCOL_POLICIES) != 0) { - sb.append("protocol "); - } Log.d(TAG, sb.toString()); } return reasons == 0; @@ -291,11 +329,6 @@ public class SecurityPolicy { public final static int INACTIVE_NEED_ENCRYPTION = 8; /** - * Return bits from isActive: Protocol-specific policies cannot be enforced - */ - public final static int INACTIVE_PROTOCOL_POLICIES = 16; - - /** * API: Query used to determine if a given policy is "active" (the device is operating at * the required security level). * @@ -385,10 +418,6 @@ public class SecurityPolicy { // password failures are counted locally - no test required here // no check required for remote wipe (it's supported, if we're the admin) - if (policy.mProtocolPoliciesUnsupported != null) { - reasons |= INACTIVE_PROTOCOL_POLICIES; - } - // If we made it all the way, reasons == 0 here. Otherwise it's a list of grievances. return reasons; } @@ -485,123 +514,24 @@ public class SecurityPolicy { Account account = Account.restoreAccountWithId(mContext, accountId); // In case the account has been deleted, just return if (account == null) return; - if (account.mPolicyKey == 0) return; - Policy policy = Policy.restorePolicyWithId(mContext, account.mPolicyKey); - if (policy == null) return; if (Email.DEBUG) { - Log.d(TAG, "policiesRequired for " + account.mDisplayName + ": " + policy); + if (account.mPolicyKey == 0) { + Log.d(TAG, "policiesRequired for " + account.mDisplayName + ": none"); + } else { + Policy policy = Policy.restorePolicyWithId(mContext, account.mPolicyKey); + if (policy == null) { + Log.w(TAG, "No policy??"); + } else { + Log.d(TAG, "policiesRequired for " + account.mDisplayName + ": " + policy); + } + } } // Mark the account as "on hold". setAccountHoldFlag(mContext, account, true); - // Put up an appropriate notification - if (policy.mProtocolPoliciesUnsupported == null) { - NotificationController.getInstance(mContext).showSecurityNeededNotification(account); - } else { - NotificationController.getInstance(mContext).showSecurityUnsupportedNotification( - account); - } - } - - public static void clearAccountPolicy(Context context, Account account) { - setAccountPolicy(context, account, null, null); - } - - /** - * Set the policy for an account atomically; this also removes any other policy associated with - * the account and sets the policy key for the account. If policy is null, the policyKey is - * set to 0 and the securitySyncKey to null. Also, update the account object to reflect the - * current policyKey and securitySyncKey - * @param context the caller's context - * @param account the account whose policy is to be set - * @param policy the policy to set, or null if we're clearing the policy - * @param securitySyncKey the security sync key for this account (ignored if policy is null) - */ - public static void setAccountPolicy(Context context, Account account, Policy policy, - String securitySyncKey) { - ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); - - // Make sure this is a valid policy set - if (policy != null) { - policy.normalize(); - // Add the new policy (no account will yet reference this) - ops.add(ContentProviderOperation.newInsert( - Policy.CONTENT_URI).withValues(policy.toContentValues()).build()); - // Make the policyKey of the account our newly created policy, and set the sync key - ops.add(ContentProviderOperation.newUpdate( - ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) - .withValueBackReference(AccountColumns.POLICY_KEY, 0) - .withValue(AccountColumns.SECURITY_SYNC_KEY, securitySyncKey) - .build()); - } else { - ops.add(ContentProviderOperation.newUpdate( - ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) - .withValue(AccountColumns.SECURITY_SYNC_KEY, null) - .withValue(AccountColumns.POLICY_KEY, 0) - .build()); - } - - // Delete the previous policy associated with this account, if any - if (account.mPolicyKey > 0) { - ops.add(ContentProviderOperation.newDelete( - ContentUris.withAppendedId( - Policy.CONTENT_URI, account.mPolicyKey)).build()); - } - - try { - context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops); - account.refresh(context); - } catch (RemoteException e) { - // This is fatal to a remote process - throw new IllegalStateException("Exception setting account policy."); - } catch (OperationApplicationException e) { - // Can't happen; our provider doesn't throw this exception - } - } - - public void setAccountPolicy(long accountId, Policy policy, String securityKey) { - Account account = Account.restoreAccountWithId(mContext, accountId); - Policy oldPolicy = null; - if (account.mPolicyKey > 0) { - oldPolicy = Policy.restorePolicyWithId(mContext, account.mPolicyKey); - } - boolean policyChanged = (oldPolicy == null) || !oldPolicy.equals(policy); - if (!policyChanged && (TextUtilities.stringOrNullEquals(securityKey, - account.mSecuritySyncKey))) { - Log.d(Logging.LOG_TAG, "setAccountPolicy; policy unchanged"); - } else { - setAccountPolicy(mContext, account, policy, securityKey); - policiesUpdated(); - } - - boolean setHold = false; - if (policy.mProtocolPoliciesUnsupported != null) { - // We can't support this, reasons in unsupportedRemotePolicies - Log.d(Logging.LOG_TAG, - "Notify policies for " + account.mDisplayName + " not supported."); - setHold = true; - NotificationController.getInstance(mContext).showSecurityUnsupportedNotification( - account); - // Erase data - Uri uri = EmailProvider.uiUri("uiaccountdata", accountId); - mContext.getContentResolver().delete(uri, null, null); - } else if (isActive(policy)) { - if (policyChanged) { - Log.d(Logging.LOG_TAG, "Notify policies for " + account.mDisplayName + " changed."); - // Notify that policies changed - NotificationController.getInstance(mContext).showSecurityChangedNotification( - account); - } - } else { - setHold = true; - Log.d(Logging.LOG_TAG, "Notify policies for " + account.mDisplayName + - " are not being enforced."); - // Put up a notification - NotificationController.getInstance(mContext).showSecurityNeededNotification(account); - } - // Set/clear the account hold. - setAccountHoldFlag(mContext, account, setHold); + // Put up a notification + NotificationController.getInstance(mContext).showSecurityNeededNotification(account); } /** @@ -664,14 +594,13 @@ public class SecurityPolicy { Log.w(TAG, "Email administration disabled; deleting " + c.getCount() + " secured account(s)"); while (c.moveToNext()) { - long accountId = c.getLong(EmailContent.ID_PROJECTION_COLUMN); - Uri uri = EmailProvider.uiUri("uiaccountdata", accountId); - cr.delete(uri, null, null); + Controller.getInstance(context).deleteAccountSync( + c.getLong(EmailContent.ID_PROJECTION_COLUMN), context); } } finally { c.close(); } - policiesUpdated(); + policiesUpdated(-1); } /** @@ -758,8 +687,7 @@ public class SecurityPolicy { // Mark the account as "on hold". setAccountHoldFlag(context, account, true); // Erase data - Uri uri = EmailProvider.uiUri("uiaccountdata", accountId); - context.getContentResolver().delete(uri, null, null); + controller.deleteSyncedDataSync(accountId); // Report one or more were found result = true; } diff --git a/src/com/android/email/SingleRunningTask.java b/src/com/android/email/SingleRunningTask.java index 2f40b6272..ae628a049 100644 --- a/src/com/android/email/SingleRunningTask.java +++ b/src/com/android/email/SingleRunningTask.java @@ -16,10 +16,10 @@ package com.android.email; -import android.util.Log; - import com.android.emailcommon.Logging; +import android.util.Log; + import java.util.concurrent.atomic.AtomicBoolean; /** @@ -45,8 +45,12 @@ public abstract class SingleRunningTask<Param> { try { runInternal(param); } finally { + Log.i(Logging.LOG_TAG, mLogTaskName + ": done"); mIsRunning.set(false); } + } else { + // Already running -- do nothing. + Log.i(Logging.LOG_TAG, mLogTaskName + ": already running"); } } diff --git a/src/com/android/email/activity/AccountSelectorAdapter.java b/src/com/android/email/activity/AccountSelectorAdapter.java index 104010bd5..231c2705c 100644 --- a/src/com/android/email/activity/AccountSelectorAdapter.java +++ b/src/com/android/email/activity/AccountSelectorAdapter.java @@ -215,13 +215,13 @@ public class AccountSelectorAdapter extends CursorAdapter { } @Override - public boolean isEnabled(int position) { - return (getItemViewType(position) != AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER); + public boolean areAllItemsEnabled() { + return false; } @Override - public boolean areAllItemsEnabled() { - return false; + public boolean isEnabled(int position) { + return (getItemViewType(position) != AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER); } public boolean isAccountItem(int position) { diff --git a/src/com/android/email/activity/EmailActivity.java b/src/com/android/email/activity/EmailActivity.java index a87690bb6..50667cbff 100644 --- a/src/com/android/email/activity/EmailActivity.java +++ b/src/com/android/email/activity/EmailActivity.java @@ -19,6 +19,7 @@ package com.android.email.activity; import android.app.Activity; import android.app.Fragment; import android.content.Intent; +import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; @@ -350,6 +351,12 @@ public class EmailActivity extends Activity implements View.OnClickListener, Fra */ private class ControllerResult extends Controller.Result { @Override + public void sendMailCallback( + MessagingException result, long accountId, long messageId, int progress) { + handleError(result, accountId, progress); + } + + @Override public void serviceCheckMailCallback( MessagingException result, long accountId, long mailboxId, int progress, long tag) { handleError(result, accountId, progress); diff --git a/src/com/android/email/activity/MailboxMoveToAdapter.java b/src/com/android/email/activity/MailboxMoveToAdapter.java index 0e4702851..bbcb8560a 100644 --- a/src/com/android/email/activity/MailboxMoveToAdapter.java +++ b/src/com/android/email/activity/MailboxMoveToAdapter.java @@ -83,12 +83,12 @@ class MailboxMoveToAdapter extends CursorAdapter { private static final String MOVE_TO_ORDER_BY_SERVER_ID = MOVE_TO_ORDER_BY_STATIC // All other mailboxes are shown in alphabetical order. - + ", " + MailboxColumns.SERVER_ID + " COLLATE LOCALIZED ASC"; + + ", " + MailboxColumns.SERVER_ID; /** Display name sort order */ private static final String MOVE_TO_ORDER_BY_DISPLAY_NAME = MOVE_TO_ORDER_BY_STATIC // All other mailboxes are shown in alphabetical order. - + ", " + MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; + + ", " + MailboxColumns.DISPLAY_NAME; // Column 0 is only for ListView; we don't use it in our code. private static final int COLUMN_ID = 1; diff --git a/src/com/android/email/activity/MessageListFragment.java b/src/com/android/email/activity/MessageListFragment.java index 1571d278b..8ece5ed60 100644 --- a/src/com/android/email/activity/MessageListFragment.java +++ b/src/com/android/email/activity/MessageListFragment.java @@ -69,6 +69,7 @@ import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.EmailAsyncTask; import com.android.emailcommon.utility.Utility; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; import java.util.HashMap; import java.util.Set; @@ -979,7 +980,7 @@ public class MessageListFragment extends ListFragment return; } - final HashMap<Long, Boolean> setValues = new HashMap<Long, Boolean>(); + final HashMap<Long, Boolean> setValues = Maps.newHashMap(); boolean allWereSet = true; c.moveToPosition(-1); @@ -1220,13 +1221,14 @@ public class MessageListFragment extends ListFragment * viewed mailbox will be updated. */ private void adjustMessageNotification(boolean updateLastSeenKey) { + final long accountId = getAccountId(); final long mailboxId = getMailboxId(); if (mailboxId == Mailbox.QUERY_ALL_INBOXES || mailboxId > 0) { if (updateLastSeenKey) { - Utility.updateLastNotifiedMessageKey(mActivity, mailboxId); + Utility.updateLastSeenMessageKey(mActivity, accountId); } NotificationController notifier = NotificationController.getInstance(mActivity); - notifier.suspendMessageNotification(mResumed, mailboxId); + notifier.suspendMessageNotification(mResumed, accountId); } } diff --git a/src/com/android/email/activity/RecentMailboxManager.java b/src/com/android/email/activity/RecentMailboxManager.java index b3f2414dd..c11e6fe2f 100644 --- a/src/com/android/email/activity/RecentMailboxManager.java +++ b/src/com/android/email/activity/RecentMailboxManager.java @@ -42,8 +42,7 @@ public class RecentMailboxManager { @VisibleForTesting static RecentMailboxManager sInstance; - public static String RECENT_MAILBOXES_SORT_ORDER = - MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; + public static String RECENT_MAILBOXES_SORT_ORDER = MailboxColumns.DISPLAY_NAME; /** The maximum number of results to retrieve */ private static final int LIMIT_RESULTS = 5; diff --git a/src/com/android/email/activity/ShortcutPickerFragment.java b/src/com/android/email/activity/ShortcutPickerFragment.java index 76442b5a4..2cc41abd1 100644 --- a/src/com/android/email/activity/ShortcutPickerFragment.java +++ b/src/com/android/email/activity/ShortcutPickerFragment.java @@ -380,7 +380,7 @@ public abstract class ShortcutPickerFragment extends ListFragment final String selection; if (recvAuth.isEasConnection()) { projection = EAS_PROJECTION; - orderBy = MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; + orderBy = MailboxColumns.DISPLAY_NAME; } else { projection = IMAP_PROJECTION; orderBy = MailboxColumns.SERVER_ID; diff --git a/src/com/android/email/activity/Welcome.java b/src/com/android/email/activity/Welcome.java index 828073263..e77746129 100644 --- a/src/com/android/email/activity/Welcome.java +++ b/src/com/android/email/activity/Welcome.java @@ -41,7 +41,6 @@ import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.provider.Policy; import com.android.emailcommon.utility.EmailAsyncTask; import com.android.emailcommon.utility.IntentUtilities; import com.android.emailcommon.utility.Utility; @@ -415,19 +414,7 @@ public class Welcome extends Activity { @Override public void onAccountSecurityHold(long accountId) { cleanUp(); - // If we can't find the account, we know what to do - Account account = Account.restoreAccountWithId(Welcome.this, accountId); - if (account == null) { - onAccountNotFound(); - return; - } - // If there's no policy or it's "unsupported", act like the account doesn't exist - Policy policy = Policy.restorePolicyWithId(Welcome.this, account.mPolicyKey); - if (policy == null || (policy.mProtocolPoliciesUnsupported != null)) { - onAccountNotFound(); - return; - } - // Otherwise, try advancing security + ActivityHelper.showSecurityHoldDialog(Welcome.this, accountId); finish(); } diff --git a/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java b/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java index 24715f123..64d4f3d3c 100644 --- a/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java +++ b/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java @@ -469,10 +469,8 @@ public class AccountCheckSettingsFragment extends Fragment { EmailServiceProxy.VALIDATE_BUNDLE_POLICY_SET)); return new MessagingException(resultCode, mStoreHost); } else if (resultCode == MessagingException.SECURITY_POLICIES_UNSUPPORTED) { - Policy policy = (Policy)bundle.getParcelable( - EmailServiceProxy.VALIDATE_BUNDLE_POLICY_SET); - String unsupported = policy.mProtocolPoliciesUnsupported; - String[] data = unsupported.split("" + Policy.POLICY_STRING_DELIMITER); + String[] data = bundle.getStringArray( + EmailServiceProxy.VALIDATE_BUNDLE_UNSUPPORTED_POLICIES); return new MessagingException(resultCode, mStoreHost, data); } else if (resultCode != MessagingException.NO_ERROR) { String errorMessage = diff --git a/src/com/android/email/activity/setup/AccountSecurity.java b/src/com/android/email/activity/setup/AccountSecurity.java index ec336d528..8c8ce5a62 100644 --- a/src/com/android/email/activity/setup/AccountSecurity.java +++ b/src/com/android/email/activity/setup/AccountSecurity.java @@ -119,7 +119,6 @@ public class AccountSecurity extends Activity { finish(); return; } - // Special handling for password expiration events if (passwordExpiring || passwordExpired) { FragmentManager fm = getFragmentManager(); diff --git a/src/com/android/email/activity/setup/AccountServerBaseFragment.java b/src/com/android/email/activity/setup/AccountServerBaseFragment.java index b1df7474e..abc31a135 100644 --- a/src/com/android/email/activity/setup/AccountServerBaseFragment.java +++ b/src/com/android/email/activity/setup/AccountServerBaseFragment.java @@ -22,9 +22,6 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; @@ -145,14 +142,6 @@ public abstract class AccountServerBaseFragment extends Fragment if (getArguments() != null) { mSettingsMode = getArguments().getBoolean(BUNDLE_KEY_SETTINGS); } - setHasOptionsMenu(true); - } - - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - MenuItem item = menu.findItem(R.id.add_new_account); - if (item != null && !UiUtilities.useTwoPane(getActivity())) { - item.setVisible(false); - } } /** diff --git a/src/com/android/email/activity/setup/AccountSettings.java b/src/com/android/email/activity/setup/AccountSettings.java index 9a88e629c..a0e117485 100644 --- a/src/com/android/email/activity/setup/AccountSettings.java +++ b/src/com/android/email/activity/setup/AccountSettings.java @@ -37,11 +37,11 @@ import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; +import com.android.email.Controller; import com.android.email.R; import com.android.email.activity.ActivityHelper; import com.android.email.mail.Sender; import com.android.email.mail.Store; -import com.android.email.provider.EmailProvider; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent.AccountColumns; @@ -245,6 +245,11 @@ public class AccountSettings extends PreferenceActivity { } @Override + public boolean onPrepareOptionsMenu(Menu menu) { + return shouldShowNewAccount(); + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: @@ -302,11 +307,40 @@ public class AccountSettings extends PreferenceActivity { super.onBackPressed(); } + /** + * If the caller requested a specific account to be edited, switch to it. This is a one-shot, + * so the user is free to edit another account as well. + */ + @Override + public Header onGetNewHeader() { + Header result = mRequestedAccountHeader; + mRequestedAccountHeader = null; + return result; + } + private void enableDebugMenu() { mShowDebugMenu = true; invalidateHeaders(); } + /** + * Decide if "add account" should be shown + */ + private boolean shouldShowNewAccount() { + // If in single pane mode, only add accounts at top level + if (!onIsMultiPane()) { + return hasHeaders(); + } else { + // If in multi pane mode, only add accounts when showing a top level fragment + // Note: null is OK; This is the case when we first launch the activity + if ((mCurrentFragment != null) + && !(mCurrentFragment instanceof GeneralPreferences) + && !(mCurrentFragment instanceof DebugFragment) + && !(mCurrentFragment instanceof AccountSettingsFragment)) return false; + } + return true; + } + private void onAddNewAccount() { AccountSetupBasics.actionNewAccount(this); } @@ -678,16 +712,11 @@ public class AccountSettings extends PreferenceActivity { /** * Delete the selected account */ - public void deleteAccount(final Account account) { + public void deleteAccount(Account account) { // Kick off the work to actually delete the account - new Thread(new Runnable() { - @Override - public void run() { - Uri uri = EmailProvider.uiUri("uiaccount", account.mId); - getContentResolver().delete(uri, null, null); - }}).start(); + // Delete the account (note, this is async. Would be nice to get a callback. + Controller.getInstance(this).deleteAccount(account.mId); - // TODO: Remove ui glue for unified // Then update the UI as appropriate: // If single pane, return to the header list. If multi, rebuild header list if (onIsMultiPane()) { @@ -732,7 +761,7 @@ public class AccountSettings extends PreferenceActivity { * Dialog fragment to show "exit with unsaved changes?" dialog */ /* package */ static class UnsavedChangesDialogFragment extends DialogFragment { - final static String TAG = "UnsavedChangesDialogFragment"; + private final static String TAG = "UnsavedChangesDialogFragment"; // Argument bundle keys private final static String BUNDLE_KEY_HEADER = "UnsavedChangesDialogFragment.Header"; diff --git a/src/com/android/email/activity/setup/AccountSettingsFragment.java b/src/com/android/email/activity/setup/AccountSettingsFragment.java index e955dd43d..7e19076f4 100644 --- a/src/com/android/email/activity/setup/AccountSettingsFragment.java +++ b/src/com/android/email/activity/setup/AccountSettingsFragment.java @@ -27,7 +27,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; import android.os.Vibrator; @@ -44,7 +43,6 @@ import android.util.Log; import com.android.email.Email; import com.android.email.R; -import com.android.email.SecurityPolicy; import com.android.email.mail.Sender; import com.android.emailcommon.AccountManagerTypes; import com.android.emailcommon.CalendarProviderStub; @@ -53,11 +51,8 @@ import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.provider.Policy; import com.android.emailcommon.utility.Utility; -import java.util.ArrayList; - /** * Fragment containing the main logic for account settings. This also calls out to other * fragments for server settings. @@ -66,8 +61,7 @@ import java.util.ArrayList; * TODO: Can we defer calling addPreferencesFromResource() until after we load the account? This * could reduce flicker. */ -public class AccountSettingsFragment extends EmailPreferenceFragment - implements Preference.OnPreferenceChangeListener { +public class AccountSettingsFragment extends PreferenceFragment { // Keys used for arguments bundle private static final String BUNDLE_KEY_ACCOUNT_ID = "AccountSettingsFragment.AccountId"; @@ -87,10 +81,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment private static final String PREFERENCE_VIBRATE_WHEN = "account_settings_vibrate_when"; private static final String PREFERENCE_RINGTONE = "account_ringtone"; private static final String PREFERENCE_CATEGORY_SERVER = "account_servers"; - private static final String PREFERENCE_CATEGORY_POLICIES = "account_policies"; - private static final String PREFERENCE_POLICIES_ENFORCED = "policies_enforced"; - private static final String PREFERENCE_POLICIES_UNSUPPORTED = "policies_unsupported"; - private static final String PREFERENCE_POLICIES_RETRY_ACCOUNT = "policies_retry_account"; private static final String PREFERENCE_INCOMING = "incoming"; private static final String PREFERENCE_OUTGOING = "outgoing"; private static final String PREFERENCE_SYNC_CONTACTS = "account_sync_contacts"; @@ -285,65 +275,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment } /** - * Listen to all preference changes in this class. - * @param preference - * @param newValue - * @return - */ - @Override - public boolean onPreferenceChange(Preference preference, Object newValue){ - // Can't use a switch here. Falling back to a giant conditional. - final String key = preference.getKey(); - if (key.equals(PREFERENCE_DESCRIPTION)){ - String summary = newValue.toString().trim(); - if (TextUtils.isEmpty(summary)) { - summary = mAccount.mEmailAddress; - } - mAccountDescription.setSummary(summary); - mAccountDescription.setText(summary); - preferenceChanged(PREFERENCE_DESCRIPTION, summary); - return false; - } else if (key.equals(PREFERENCE_FREQUENCY)) { - final String summary = newValue.toString(); - final int index = mCheckFrequency.findIndexOfValue(summary); - mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]); - mCheckFrequency.setValue(summary); - preferenceChanged(PREFERENCE_FREQUENCY, newValue); - return false; - } else if (key.equals(PREFERENCE_SIGNATURE)) { - // Clean up signature if it's only whitespace (which is easy to do on a - // soft keyboard) but leave whitespace in place otherwise, to give the user - // maximum flexibility, e.g. the ability to indent - String signature = newValue.toString(); - if (signature.trim().isEmpty()) { - signature = ""; - } - mAccountSignature.setText(signature); - preferenceChanged(PREFERENCE_SIGNATURE, signature); - return false; - } else if (key.equals(PREFERENCE_NAME)) { - final String summary = newValue.toString().trim(); - if (!TextUtils.isEmpty(summary)) { - mAccountName.setSummary(summary); - mAccountName.setText(summary); - preferenceChanged(PREFERENCE_NAME, summary); - } - return false; - } else if (key.equals(PREFERENCE_VIBRATE_WHEN)) { - final String vibrateSetting = newValue.toString(); - final int index = mAccountVibrateWhen.findIndexOfValue(vibrateSetting); - mAccountVibrateWhen.setSummary(mAccountVibrateWhen.getEntries()[index]); - mAccountVibrateWhen.setValue(vibrateSetting); - preferenceChanged(PREFERENCE_VIBRATE_WHEN, newValue); - return false; - } else { - // Default behavior, just indicate that the preferences were written - preferenceChanged(key, newValue); - return true; - } - } - - /** * Called when the fragment is no longer in use. */ @Override @@ -421,52 +352,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment } /** - * From a Policy, create and return an ArrayList of Strings that describe (simply) those - * policies that are supported by the OS. At the moment, the strings are simple (e.g. - * "password required"); we should probably add more information (# characters, etc.), though - */ - private ArrayList<String> getSystemPoliciesList(Policy policy) { - Resources res = mContext.getResources(); - ArrayList<String> policies = new ArrayList<String>(); - if (policy.mPasswordMode != Policy.PASSWORD_MODE_NONE) { - policies.add(res.getString(R.string.policy_require_password)); - } - if (policy.mPasswordHistory > 0) { - policies.add(res.getString(R.string.policy_password_history)); - } - if (policy.mPasswordExpirationDays > 0) { - policies.add(res.getString(R.string.policy_password_expiration)); - } - if (policy.mMaxScreenLockTime > 0) { - policies.add(res.getString(R.string.policy_screen_timeout)); - } - if (policy.mDontAllowCamera) { - policies.add(res.getString(R.string.policy_dont_allow_camera)); - } - if (policy.mMaxEmailLookback != 0) { - policies.add(res.getString(R.string.policy_email_age)); - } - if (policy.mMaxCalendarLookback != 0) { - policies.add(res.getString(R.string.policy_calendar_age)); - } - return policies; - } - - private void setPolicyListSummary(ArrayList<String> policies, String policiesToAdd, - String preferenceName) { - Policy.addPolicyStringToList(policiesToAdd, policies); - if (policies.size() > 0) { - Preference p = findPreference(preferenceName); - StringBuilder sb = new StringBuilder(); - for (String desc: policies) { - sb.append(desc); - sb.append('\n'); - } - p.setSummary(sb.toString()); - } - } - - /** * Load account data into preference UI */ private void loadSettings() { @@ -478,7 +363,20 @@ public class AccountSettingsFragment extends EmailPreferenceFragment mAccountDescription = (EditTextPreference) findPreference(PREFERENCE_DESCRIPTION); mAccountDescription.setSummary(mAccount.getDisplayName()); mAccountDescription.setText(mAccount.getDisplayName()); - mAccountDescription.setOnPreferenceChangeListener(this); + mAccountDescription.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + String summary = newValue.toString().trim(); + if (TextUtils.isEmpty(summary)) { + summary = mAccount.mEmailAddress; + } + mAccountDescription.setSummary(summary); + mAccountDescription.setText(summary); + onPreferenceChanged(PREFERENCE_DESCRIPTION, summary); + return false; + } + } + ); mAccountName = (EditTextPreference) findPreference(PREFERENCE_NAME); String senderName = mAccount.getSenderName(); @@ -486,11 +384,36 @@ public class AccountSettingsFragment extends EmailPreferenceFragment if (senderName == null) senderName = ""; mAccountName.setSummary(senderName); mAccountName.setText(senderName); - mAccountName.setOnPreferenceChangeListener(this); + mAccountName.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String summary = newValue.toString().trim(); + if (!TextUtils.isEmpty(summary)) { + mAccountName.setSummary(summary); + mAccountName.setText(summary); + onPreferenceChanged(PREFERENCE_NAME, summary); + } + return false; + } + }); mAccountSignature = (EditTextPreference) findPreference(PREFERENCE_SIGNATURE); + String signature = mAccount.getSignature(); mAccountSignature.setText(mAccount.getSignature()); - mAccountSignature.setOnPreferenceChangeListener(this); + mAccountSignature.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + // Clean up signature if it's only whitespace (which is easy to do on a + // soft keyboard) but leave whitespace in place otherwise, to give the user + // maximum flexibility, e.g. the ability to indent + String signature = newValue.toString(); + if (signature.trim().isEmpty()) { + signature = ""; + } + mAccountSignature.setText(signature); + onPreferenceChanged(PREFERENCE_SIGNATURE, signature); + return false; + } + }); mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY); @@ -503,7 +426,16 @@ public class AccountSettingsFragment extends EmailPreferenceFragment mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval())); mCheckFrequency.setSummary(mCheckFrequency.getEntry()); - mCheckFrequency.setOnPreferenceChangeListener(this); + mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String summary = newValue.toString(); + int index = mCheckFrequency.findIndexOfValue(summary); + mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]); + mCheckFrequency.setValue(summary); + onPreferenceChanged(PREFERENCE_FREQUENCY, newValue); + return false; + } + }); findPreference(PREFERENCE_QUICK_RESPONSES).setOnPreferenceClickListener( new Preference.OnPreferenceClickListener() { @@ -530,13 +462,12 @@ public class AccountSettingsFragment extends EmailPreferenceFragment // Must correspond to the hole in the XML file that's reserved. mSyncWindow.setOrder(2); mSyncWindow.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final String summary = newValue.toString(); int index = mSyncWindow.findIndexOfValue(summary); mSyncWindow.setSummary(mSyncWindow.getEntries()[index]); mSyncWindow.setValue(summary); - preferenceChanged(preference.getKey(), newValue); + onPreferenceChanged(preference.getKey(), newValue); return false; } }); @@ -551,19 +482,19 @@ public class AccountSettingsFragment extends EmailPreferenceFragment } else { mAccountBackgroundAttachments.setChecked( 0 != (mAccount.getFlags() & Account.FLAGS_BACKGROUND_ATTACHMENTS)); - mAccountBackgroundAttachments.setOnPreferenceChangeListener(this); + mAccountBackgroundAttachments.setOnPreferenceChangeListener(mPreferenceChangeListener); } mAccountDefault = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT); mAccountDefault.setChecked(mAccount.mId == mDefaultAccountId); - mAccountDefault.setOnPreferenceChangeListener(this); + mAccountDefault.setOnPreferenceChangeListener(mPreferenceChangeListener); mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY); mAccountNotify.setChecked(0 != (mAccount.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL)); - mAccountNotify.setOnPreferenceChangeListener(this); + mAccountNotify.setOnPreferenceChangeListener(mPreferenceChangeListener); mAccountRingtone = (RingtonePreference) findPreference(PREFERENCE_RINGTONE); - mAccountRingtone.setOnPreferenceChangeListener(this); + mAccountRingtone.setOnPreferenceChangeListener(mPreferenceChangeListener); // The following two lines act as a workaround for the RingtonePreference // which does not let us set/get the value programmatically @@ -589,7 +520,18 @@ public class AccountSettingsFragment extends EmailPreferenceFragment mAccountVibrateWhen.setSummary(mAccountVibrateWhen.getEntries()[index]); // When the value is changed, update the summary in addition to the setting. - mAccountVibrateWhen.setOnPreferenceChangeListener(this); + mAccountVibrateWhen.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String vibrateSetting = newValue.toString(); + final int index = mAccountVibrateWhen.findIndexOfValue(vibrateSetting); + mAccountVibrateWhen.setSummary(mAccountVibrateWhen.getEntries()[index]); + mAccountVibrateWhen.setValue(vibrateSetting); + onPreferenceChanged(PREFERENCE_VIBRATE_WHEN, newValue); + return false; + } + }); } else { // No vibrator present. Remove the preference altogether. PreferenceCategory notificationsCategory = (PreferenceCategory) @@ -597,49 +539,8 @@ public class AccountSettingsFragment extends EmailPreferenceFragment notificationsCategory.removePreference(mAccountVibrateWhen); } - final Preference retryAccount = findPreference(PREFERENCE_POLICIES_RETRY_ACCOUNT); - final PreferenceCategory policiesCategory = (PreferenceCategory) findPreference( - PREFERENCE_CATEGORY_POLICIES); - if (mAccount.mPolicyKey > 0) { - // Make sure we have most recent data from account - mAccount.refresh(mContext); - Policy policy = Policy.restorePolicyWithId(mContext, mAccount.mPolicyKey); - if (policy == null) { - // The account has been deleted? Crazy, but not impossible - return; - } - if (policy.mProtocolPoliciesEnforced != null) { - ArrayList<String> policies = getSystemPoliciesList(policy); - setPolicyListSummary(policies, policy.mProtocolPoliciesEnforced, - PREFERENCE_POLICIES_ENFORCED); - } - if (policy.mProtocolPoliciesUnsupported != null) { - ArrayList<String> policies = new ArrayList<String>(); - setPolicyListSummary(policies, policy.mProtocolPoliciesUnsupported, - PREFERENCE_POLICIES_UNSUPPORTED); - } else { - // Don't show "retry" unless we have unsupported policies - policiesCategory.removePreference(retryAccount); - } - } else { - // Remove the category completely if there are no policies - getPreferenceScreen().removePreference(policiesCategory); - } - - retryAccount.setOnPreferenceClickListener( - new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - // Release the account - SecurityPolicy.setAccountHoldFlag(mContext, mAccount, false); - // Remove the preference - policiesCategory.removePreference(retryAccount); - return true; - } - }); findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener( new Preference.OnPreferenceClickListener() { - @Override public boolean onPreferenceClick(Preference preference) { mAccountDirty = true; mCallback.onIncomingSettings(mAccount); @@ -662,7 +563,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment if (showOutgoing) { prefOutgoing.setOnPreferenceClickListener( new Preference.OnPreferenceClickListener() { - @Override public boolean onPreferenceClick(Preference preference) { mAccountDirty = true; mCallback.onOutgoingSettings(mAccount); @@ -683,13 +583,13 @@ public class AccountSettingsFragment extends EmailPreferenceFragment AccountManagerTypes.TYPE_EXCHANGE); mSyncContacts.setChecked(ContentResolver .getSyncAutomatically(acct, ContactsContract.AUTHORITY)); - mSyncContacts.setOnPreferenceChangeListener(this); + mSyncContacts.setOnPreferenceChangeListener(mPreferenceChangeListener); mSyncCalendar.setChecked(ContentResolver .getSyncAutomatically(acct, CalendarProviderStub.AUTHORITY)); - mSyncCalendar.setOnPreferenceChangeListener(this); + mSyncCalendar.setOnPreferenceChangeListener(mPreferenceChangeListener); mSyncEmail.setChecked(ContentResolver .getSyncAutomatically(acct, EmailContent.AUTHORITY)); - mSyncEmail.setOnPreferenceChangeListener(this); + mSyncEmail.setOnPreferenceChangeListener(mPreferenceChangeListener); } else { dataUsageCategory.removePreference(mSyncContacts); dataUsageCategory.removePreference(mSyncCalendar); @@ -700,7 +600,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment Preference prefDeleteAccount = findPreference(PREFERENCE_DELETE_ACCOUNT); prefDeleteAccount.setOnPreferenceClickListener( new Preference.OnPreferenceClickListener() { - @Override public boolean onPreferenceClick(Preference preference) { DeleteAccountFragment dialogFragment = DeleteAccountFragment.newInstance( mAccount, AccountSettingsFragment.this); @@ -713,9 +612,21 @@ public class AccountSettingsFragment extends EmailPreferenceFragment } /** + * Generic onPreferenceChanged listener for the preferences (above) that just need + * to be written, without extra tweaks + */ + private final Preference.OnPreferenceChangeListener mPreferenceChangeListener = + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + onPreferenceChanged(preference.getKey(), newValue); + return true; + } + }; + + /** * Called any time a preference is changed. */ - private void preferenceChanged(String preference, Object value) { + private void onPreferenceChanged(String preference, Object value) { mCallback.onSettingsChanged(mAccount, preference, value); mSaveOnExit = true; } @@ -780,7 +691,7 @@ public class AccountSettingsFragment extends EmailPreferenceFragment * Dialog fragment to show "remove account?" dialog */ public static class DeleteAccountFragment extends DialogFragment { - final static String TAG = "DeleteAccountFragment"; + private final static String TAG = "DeleteAccountFragment"; // Argument bundle keys private final static String BUNDLE_KEY_ACCOUNT_NAME = "DeleteAccountFragment.Name"; @@ -809,7 +720,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment .setPositiveButton( R.string.okay_action, new DialogInterface.OnClickListener() { - @Override public void onClick(DialogInterface dialog, int whichButton) { Fragment f = getTargetFragment(); if (f instanceof AccountSettingsFragment) { @@ -821,7 +731,6 @@ public class AccountSettingsFragment extends EmailPreferenceFragment .setNegativeButton( R.string.cancel_action, new DialogInterface.OnClickListener() { - @Override public void onClick(DialogInterface dialog, int whichButton) { dismiss(); } diff --git a/src/com/android/email/activity/setup/AccountSettingsUtils.java b/src/com/android/email/activity/setup/AccountSettingsUtils.java index 8265bf7b3..9ff519b6c 100644 --- a/src/com/android/email/activity/setup/AccountSettingsUtils.java +++ b/src/com/android/email/activity/setup/AccountSettingsUtils.java @@ -16,12 +16,10 @@ package com.android.email.activity.setup; -import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.res.XmlResourceParser; import android.text.Editable; -import android.text.TextUtils; import android.util.Log; import android.widget.EditText; @@ -31,7 +29,6 @@ import com.android.email.provider.AccountBackupRestore; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent.AccountColumns; -import com.android.emailcommon.provider.QuickResponse; import com.google.common.annotations.VisibleForTesting; import java.io.Serializable; @@ -54,26 +51,10 @@ public class AccountSettingsUtils { public static void commitSettings(Context context, Account account) { if (!account.isSaved()) { account.save(context); - - // Set up default quick responses here... - String[] defaultQuickResponses = - context.getResources().getStringArray(R.array.default_quick_responses); - ContentValues cv = new ContentValues(); - cv.put(QuickResponse.ACCOUNT_KEY, account.mId); - ContentResolver resolver = context.getContentResolver(); - for (String quickResponse: defaultQuickResponses) { - // Allow empty entries (some localizations may not want to have the maximum - // number) - if (!TextUtils.isEmpty(quickResponse)) { - cv.put(QuickResponse.TEXT, quickResponse); - resolver.insert(QuickResponse.CONTENT_URI, cv); - } - } } else { ContentValues cv = getAccountContentValues(account); account.update(context, cv); } - // Update the backup (side copy) of the accounts AccountBackupRestore.backup(context); } diff --git a/src/com/android/email/activity/setup/AccountSetupBasics.java b/src/com/android/email/activity/setup/AccountSetupBasics.java index 69b502947..cc48a7a7b 100644 --- a/src/com/android/email/activity/setup/AccountSetupBasics.java +++ b/src/com/android/email/activity/setup/AccountSetupBasics.java @@ -701,7 +701,7 @@ public class AccountSetupBasics extends AccountSetupActivity * Dialog fragment to show "setup note" dialog */ public static class NoteDialogFragment extends DialogFragment { - final static String TAG = "NoteDialogFragment"; + private final static String TAG = "NoteDialogFragment"; // Argument bundle keys private final static String BUNDLE_KEY_NOTE = "NoteDialogFragment.Note"; diff --git a/src/com/android/email/activity/setup/DebugFragment.java b/src/com/android/email/activity/setup/DebugFragment.java index d2b8409fe..f7cd8d31c 100644 --- a/src/com/android/email/activity/setup/DebugFragment.java +++ b/src/com/android/email/activity/setup/DebugFragment.java @@ -21,6 +21,7 @@ import com.android.email.Preferences; import com.android.email.R; import com.android.email.activity.UiUtilities; import com.android.email.service.EmailServiceUtils; +import com.android.email.service.MailService; import com.android.emailcommon.Logging; import android.app.Fragment; @@ -43,6 +44,7 @@ public class DebugFragment extends Fragment implements OnCheckedChangeListener, private CheckBox mEnableExchangeLoggingView; private CheckBox mEnableExchangeFileLoggingView; private CheckBox mInhibitGraphicsAccelerationView; + private CheckBox mForceOneMinuteRefreshView; private CheckBox mEnableStrictModeView; private Preferences mPreferences; @@ -90,6 +92,11 @@ public class DebugFragment extends Fragment implements OnCheckedChangeListener, mInhibitGraphicsAccelerationView.setChecked(Email.sDebugInhibitGraphicsAcceleration); mInhibitGraphicsAccelerationView.setOnCheckedChangeListener(this); + mForceOneMinuteRefreshView = (CheckBox) + UiUtilities.getView(view, R.id.debug_force_one_minute_refresh); + mForceOneMinuteRefreshView.setChecked(mPreferences.getForceOneMinuteRefresh()); + mForceOneMinuteRefreshView.setOnCheckedChangeListener(this); + mEnableStrictModeView = (CheckBox) UiUtilities.getView(view, R.id.debug_enable_strict_mode); mEnableStrictModeView.setChecked(mPreferences.getEnableStrictMode()); @@ -118,6 +125,10 @@ public class DebugFragment extends Fragment implements OnCheckedChangeListener, Email.sDebugInhibitGraphicsAcceleration = isChecked; mPreferences.setInhibitGraphicsAcceleration(isChecked); break; + case R.id.debug_force_one_minute_refresh: + mPreferences.setForceOneMinuteRefresh(isChecked); + MailService.actionReschedule(getActivity()); + break; case R.id.debug_enable_strict_mode: mPreferences.setEnableStrictMode(isChecked); Email.enableStrictMode(isChecked); diff --git a/src/com/android/email/activity/setup/EditQuickResponseDialog.java b/src/com/android/email/activity/setup/EditQuickResponseDialog.java index e3ef21cfb..1a3031429 100644 --- a/src/com/android/email/activity/setup/EditQuickResponseDialog.java +++ b/src/com/android/email/activity/setup/EditQuickResponseDialog.java @@ -30,8 +30,6 @@ import android.content.DialogInterface; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; import android.view.WindowManager; import android.widget.EditText; @@ -73,9 +71,8 @@ public class EditQuickResponseDialog extends DialogFragment public Dialog onCreateDialog(Bundle savedInstanceState) { final Context context = getActivity(); mQuickResponse = (QuickResponse) getArguments().getParcelable(QUICK_RESPONSE); - View wrapper = LayoutInflater.from(context) - .inflate(R.layout.quick_response_edit_dialog, null); - mQuickResponseEditText = (EditText) wrapper.findViewById(R.id.quick_response_text); + + mQuickResponseEditText = new EditText(context); if (savedInstanceState != null) { String quickResponseSavedString = savedInstanceState.getString(QUICK_RESPONSE_EDITED_STRING); @@ -90,7 +87,7 @@ public class EditQuickResponseDialog extends DialogFragment final AlertDialog.Builder b = new AlertDialog.Builder(context); b.setTitle(getResources().getString(R.string.edit_quick_response_dialog)) - .setView(wrapper) + .setView(mQuickResponseEditText) .setNegativeButton(R.string.cancel_action, this) .setPositiveButton(R.string.save_action, this); mDialog = b.create(); diff --git a/src/com/android/email/activity/setup/EmailPreferenceFragment.java b/src/com/android/email/activity/setup/EmailPreferenceFragment.java deleted file mode 100644 index 0c7c1e4a7..000000000 --- a/src/com/android/email/activity/setup/EmailPreferenceFragment.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -package com.android.email.activity.setup; - -import com.android.email.activity.UiUtilities; - -import android.os.Bundle; -import android.preference.PreferenceFragment; -import android.view.Menu; -import android.view.MenuInflater; - -public class EmailPreferenceFragment extends PreferenceFragment { - - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (!UiUtilities.useTwoPane(getActivity())) { - menu.clear(); - } - } -} diff --git a/src/com/android/email/activity/setup/GeneralPreferences.java b/src/com/android/email/activity/setup/GeneralPreferences.java index a9c296c5e..b7c1cee11 100644 --- a/src/com/android/email/activity/setup/GeneralPreferences.java +++ b/src/com/android/email/activity/setup/GeneralPreferences.java @@ -21,6 +21,7 @@ import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.widget.Toast; @@ -28,8 +29,7 @@ import com.android.email.Preferences; import com.android.email.R; import com.android.email.activity.UiUtilities; -public class GeneralPreferences extends EmailPreferenceFragment implements - OnPreferenceChangeListener { +public class GeneralPreferences extends PreferenceFragment implements OnPreferenceChangeListener { private static final String PREFERENCE_CATEGORY_KEY = "category_general_preferences"; diff --git a/src/com/android/email/activity/setup/PolicyListPreference.java b/src/com/android/email/activity/setup/PolicyListPreference.java deleted file mode 100644 index 3a32438e7..000000000 --- a/src/com/android/email/activity/setup/PolicyListPreference.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package com.android.email.activity.setup; - -import android.content.Context; -import android.preference.Preference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * Simple text preference allowing a large number of lines - */ -public class PolicyListPreference extends Preference { - // Arbitrary, but large number (we don't, and won't, have nearly this many) - public static final int MAX_POLICIES = 24; - - public PolicyListPreference(Context ctx, AttributeSet attrs, int defStyle) { - super(ctx, attrs, defStyle); - } - - public PolicyListPreference(Context ctx, AttributeSet attrs) { - super(ctx, attrs); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - ((TextView)view.findViewById(android.R.id.summary)).setMaxLines(MAX_POLICIES); - } -} diff --git a/src/com/android/email/provider/AccountReconciler.java b/src/com/android/email/provider/AccountReconciler.java index d564c6623..fec881faa 100644 --- a/src/com/android/email/provider/AccountReconciler.java +++ b/src/com/android/email/provider/AccountReconciler.java @@ -21,9 +21,9 @@ import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; -import android.net.Uri; import android.util.Log; +import com.android.email.Controller; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; import com.google.common.annotations.VisibleForTesting; @@ -119,8 +119,8 @@ public class AccountReconciler { Log.d(Logging.LOG_TAG, "Account deleted in AccountManager; deleting from provider: " + providerAccountName); - Uri uri = EmailProvider.uiUri("uiaccount", providerAccount.mId); - context.getContentResolver().delete(uri, null, null); + Controller.getInstance(context).deleteAccountSync(providerAccount.mId, + providerContext); } } } diff --git a/src/com/android/email/provider/ContentCache.java b/src/com/android/email/provider/ContentCache.java index 041f296c8..d18c3ee87 100644 --- a/src/com/android/email/provider/ContentCache.java +++ b/src/com/android/email/provider/ContentCache.java @@ -167,7 +167,7 @@ public final class ContentCache { /** * For Debugging Only - not efficient */ - synchronized Set<Map.Entry<T, Integer>> entrySet() { + synchronized Set<HashMap.Entry<T, Integer>> entrySet() { return mMap.entrySet(); } } diff --git a/src/com/android/email/provider/DBHelper.java b/src/com/android/email/provider/DBHelper.java deleted file mode 100644 index 791adc2df..000000000 --- a/src/com/android/email/provider/DBHelper.java +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * Copyright (C) 2012 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.email.provider; - -import android.accounts.AccountManager; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.provider.ContactsContract; -import android.util.Log; - -import com.android.email.Email; -import com.android.emailcommon.AccountManagerTypes; -import com.android.emailcommon.CalendarProviderStub; -import com.android.emailcommon.mail.Address; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.AccountColumns; -import com.android.emailcommon.provider.EmailContent.Attachment; -import com.android.emailcommon.provider.EmailContent.AttachmentColumns; -import com.android.emailcommon.provider.EmailContent.Body; -import com.android.emailcommon.provider.EmailContent.BodyColumns; -import com.android.emailcommon.provider.EmailContent.HostAuthColumns; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.provider.EmailContent.PolicyColumns; -import com.android.emailcommon.provider.EmailContent.QuickResponseColumns; -import com.android.emailcommon.provider.EmailContent.SyncColumns; -import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.provider.Policy; -import com.android.emailcommon.provider.QuickResponse; -import com.android.emailcommon.service.LegacyPolicySet; -import com.android.mail.providers.UIProvider; -import com.google.common.annotations.VisibleForTesting; - -public final class DBHelper { - private static final String TAG = "EmailProvider"; - - private static final String WHERE_ID = EmailContent.RECORD_ID + "=?"; - - private static final String TRIGGER_MAILBOX_DELETE = - "create trigger mailbox_delete before delete on " + Mailbox.TABLE_NAME + - " begin" + - " delete from " + Message.TABLE_NAME + - " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + - "; delete from " + Message.UPDATED_TABLE_NAME + - " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + - "; delete from " + Message.DELETED_TABLE_NAME + - " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + - "; end"; - - private static final String TRIGGER_ACCOUNT_DELETE = - "create trigger account_delete before delete on " + Account.TABLE_NAME + - " begin delete from " + Mailbox.TABLE_NAME + - " where " + MailboxColumns.ACCOUNT_KEY + "=old." + EmailContent.RECORD_ID + - "; delete from " + HostAuth.TABLE_NAME + - " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_RECV + - "; delete from " + HostAuth.TABLE_NAME + - " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_SEND + - "; delete from " + Policy.TABLE_NAME + - " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.POLICY_KEY + - "; end"; - - // Any changes to the database format *must* include update-in-place code. - // Original version: 3 - // Version 4: Database wipe required; changing AccountManager interface w/Exchange - // Version 5: Database wipe required; changing AccountManager interface w/Exchange - // Version 6: Adding Message.mServerTimeStamp column - // Version 7: Replace the mailbox_delete trigger with a version that removes orphaned messages - // from the Message_Deletes and Message_Updates tables - // Version 8: Add security flags column to accounts table - // Version 9: Add security sync key and signature to accounts table - // Version 10: Add meeting info to message table - // Version 11: Add content and flags to attachment table - // Version 12: Add content_bytes to attachment table. content is deprecated. - // Version 13: Add messageCount to Mailbox table. - // Version 14: Add snippet to Message table - // Version 15: Fix upgrade problem in version 14. - // Version 16: Add accountKey to Attachment table - // Version 17: Add parentKey to Mailbox table - // Version 18: Copy Mailbox.displayName to Mailbox.serverId for all IMAP & POP3 mailboxes. - // Column Mailbox.serverId is used for the server-side pathname of a mailbox. - // Version 19: Add Policy table; add policyKey to Account table and trigger to delete an - // Account's policy when the Account is deleted - // Version 20: Add new policies to Policy table - // Version 21: Add lastSeenMessageKey column to Mailbox table - // Version 22: Upgrade path for IMAP/POP accounts to integrate with AccountManager - // Version 23: Add column to mailbox table for time of last access - // Version 24: Add column to hostauth table for client cert alias - // Version 25: Added QuickResponse table - // Version 26: Update IMAP accounts to add FLAG_SUPPORTS_SEARCH flag - // Version 27: Add protocolSearchInfo to Message table - // Version 28: Add notifiedMessageId and notifiedMessageCount to Account - // Version 29: Add protocolPoliciesEnforced and protocolPoliciesUnsupported to Policy - // Version 30: Use CSV of RFC822 addresses instead of "packed" values - // Version 31: Add columns to mailbox for ui status/last result - // Version 32: Add columns to mailbox for last notified message key/count; insure not null - // for "notified" columns - // Version 33: Add columns to attachment for ui provider columns - // Version 34: Add total count to mailbox - - public static final int DATABASE_VERSION = 34; - - // Any changes to the database format *must* include update-in-place code. - // Original version: 2 - // Version 3: Add "sourceKey" column - // Version 4: Database wipe required; changing AccountManager interface w/Exchange - // Version 5: Database wipe required; changing AccountManager interface w/Exchange - // Version 6: Adding Body.mIntroText column - public static final int BODY_DATABASE_VERSION = 6; - - /* - * Internal helper method for index creation. - * Example: - * "create index message_" + MessageColumns.FLAG_READ - * + " on " + Message.TABLE_NAME + " (" + MessageColumns.FLAG_READ + ");" - */ - /* package */ - static String createIndex(String tableName, String columnName) { - return "create index " + tableName.toLowerCase() + '_' + columnName - + " on " + tableName + " (" + columnName + ");"; - } - - static void createMessageTable(SQLiteDatabase db) { - String messageColumns = MessageColumns.DISPLAY_NAME + " text, " - + MessageColumns.TIMESTAMP + " integer, " - + MessageColumns.SUBJECT + " text, " - + MessageColumns.FLAG_READ + " integer, " - + MessageColumns.FLAG_LOADED + " integer, " - + MessageColumns.FLAG_FAVORITE + " integer, " - + MessageColumns.FLAG_ATTACHMENT + " integer, " - + MessageColumns.FLAGS + " integer, " - + MessageColumns.CLIENT_ID + " integer, " - + MessageColumns.MESSAGE_ID + " text, " - + MessageColumns.MAILBOX_KEY + " integer, " - + MessageColumns.ACCOUNT_KEY + " integer, " - + MessageColumns.FROM_LIST + " text, " - + MessageColumns.TO_LIST + " text, " - + MessageColumns.CC_LIST + " text, " - + MessageColumns.BCC_LIST + " text, " - + MessageColumns.REPLY_TO_LIST + " text, " - + MessageColumns.MEETING_INFO + " text, " - + MessageColumns.SNIPPET + " text, " - + MessageColumns.PROTOCOL_SEARCH_INFO + " text" - + ");"; - - // This String and the following String MUST have the same columns, except for the type - // of those columns! - String createString = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + SyncColumns.SERVER_ID + " text, " - + SyncColumns.SERVER_TIMESTAMP + " integer, " - + messageColumns; - - // For the updated and deleted tables, the id is assigned, but we do want to keep track - // of the ORDER of updates using an autoincrement primary key. We use the DATA column - // at this point; it has no other function - String altCreateString = " (" + EmailContent.RECORD_ID + " integer unique, " - + SyncColumns.SERVER_ID + " text, " - + SyncColumns.SERVER_TIMESTAMP + " integer, " - + messageColumns; - - // The three tables have the same schema - db.execSQL("create table " + Message.TABLE_NAME + createString); - db.execSQL("create table " + Message.UPDATED_TABLE_NAME + altCreateString); - db.execSQL("create table " + Message.DELETED_TABLE_NAME + altCreateString); - - String indexColumns[] = { - MessageColumns.TIMESTAMP, - MessageColumns.FLAG_READ, - MessageColumns.FLAG_LOADED, - MessageColumns.MAILBOX_KEY, - SyncColumns.SERVER_ID - }; - - for (String columnName : indexColumns) { - db.execSQL(createIndex(Message.TABLE_NAME, columnName)); - } - - // Deleting a Message deletes all associated Attachments - // Deleting the associated Body cannot be done in a trigger, because the Body is stored - // in a separate database, and trigger cannot operate on attached databases. - db.execSQL("create trigger message_delete before delete on " + Message.TABLE_NAME + - " begin delete from " + Attachment.TABLE_NAME + - " where " + AttachmentColumns.MESSAGE_KEY + "=old." + EmailContent.RECORD_ID + - "; end"); - - // Add triggers to keep unread count accurate per mailbox - - // NOTE: SQLite's before triggers are not safe when recursive triggers are involved. - // Use caution when changing them. - - // Insert a message; if flagRead is zero, add to the unread count of the message's mailbox - db.execSQL("create trigger unread_message_insert before insert on " + Message.TABLE_NAME + - " when NEW." + MessageColumns.FLAG_READ + "=0" + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + - '=' + MailboxColumns.UNREAD_COUNT + "+1" + - " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Delete a message; if flagRead is zero, decrement the unread count of the msg's mailbox - db.execSQL("create trigger unread_message_delete before delete on " + Message.TABLE_NAME + - " when OLD." + MessageColumns.FLAG_READ + "=0" + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + - '=' + MailboxColumns.UNREAD_COUNT + "-1" + - " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Change a message's mailbox - db.execSQL("create trigger unread_message_move before update of " + - MessageColumns.MAILBOX_KEY + " on " + Message.TABLE_NAME + - " when OLD." + MessageColumns.FLAG_READ + "=0" + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + - '=' + MailboxColumns.UNREAD_COUNT + "-1" + - " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + - "; update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + - '=' + MailboxColumns.UNREAD_COUNT + "+1" + - " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Change a message's read state - db.execSQL("create trigger unread_message_read before update of " + - MessageColumns.FLAG_READ + " on " + Message.TABLE_NAME + - " when OLD." + MessageColumns.FLAG_READ + "!=NEW." + MessageColumns.FLAG_READ + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + - '=' + MailboxColumns.UNREAD_COUNT + "+ case OLD." + MessageColumns.FLAG_READ + - " when 0 then -1 else 1 end" + - " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Add triggers to update message count per mailbox - - // Insert a message. - db.execSQL("create trigger message_count_message_insert after insert on " + - Message.TABLE_NAME + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + - '=' + MailboxColumns.MESSAGE_COUNT + "+1" + - " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Delete a message; if flagRead is zero, decrement the unread count of the msg's mailbox - db.execSQL("create trigger message_count_message_delete after delete on " + - Message.TABLE_NAME + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + - '=' + MailboxColumns.MESSAGE_COUNT + "-1" + - " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + - "; end"); - - // Change a message's mailbox - db.execSQL("create trigger message_count_message_move after update of " + - MessageColumns.MAILBOX_KEY + " on " + Message.TABLE_NAME + - " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + - '=' + MailboxColumns.MESSAGE_COUNT + "-1" + - " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + - "; update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + - '=' + MailboxColumns.MESSAGE_COUNT + "+1" + - " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + - "; end"); - } - - static void resetMessageTable(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - db.execSQL("drop table " + Message.TABLE_NAME); - db.execSQL("drop table " + Message.UPDATED_TABLE_NAME); - db.execSQL("drop table " + Message.DELETED_TABLE_NAME); - } catch (SQLException e) { - } - createMessageTable(db); - } - - @SuppressWarnings("deprecation") - static void createAccountTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + AccountColumns.DISPLAY_NAME + " text, " - + AccountColumns.EMAIL_ADDRESS + " text, " - + AccountColumns.SYNC_KEY + " text, " - + AccountColumns.SYNC_LOOKBACK + " integer, " - + AccountColumns.SYNC_INTERVAL + " text, " - + AccountColumns.HOST_AUTH_KEY_RECV + " integer, " - + AccountColumns.HOST_AUTH_KEY_SEND + " integer, " - + AccountColumns.FLAGS + " integer, " - + AccountColumns.IS_DEFAULT + " integer, " - + AccountColumns.COMPATIBILITY_UUID + " text, " - + AccountColumns.SENDER_NAME + " text, " - + AccountColumns.RINGTONE_URI + " text, " - + AccountColumns.PROTOCOL_VERSION + " text, " - + AccountColumns.NEW_MESSAGE_COUNT + " integer, " - + AccountColumns.SECURITY_FLAGS + " integer, " - + AccountColumns.SECURITY_SYNC_KEY + " text, " - + AccountColumns.SIGNATURE + " text, " - + AccountColumns.POLICY_KEY + " integer" - + ");"; - db.execSQL("create table " + Account.TABLE_NAME + s); - // Deleting an account deletes associated Mailboxes and HostAuth's - db.execSQL(TRIGGER_ACCOUNT_DELETE); - } - - static void resetAccountTable(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - db.execSQL("drop table " + Account.TABLE_NAME); - } catch (SQLException e) { - } - createAccountTable(db); - } - - static void createPolicyTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + PolicyColumns.PASSWORD_MODE + " integer, " - + PolicyColumns.PASSWORD_MIN_LENGTH + " integer, " - + PolicyColumns.PASSWORD_EXPIRATION_DAYS + " integer, " - + PolicyColumns.PASSWORD_HISTORY + " integer, " - + PolicyColumns.PASSWORD_COMPLEX_CHARS + " integer, " - + PolicyColumns.PASSWORD_MAX_FAILS + " integer, " - + PolicyColumns.MAX_SCREEN_LOCK_TIME + " integer, " - + PolicyColumns.REQUIRE_REMOTE_WIPE + " integer, " - + PolicyColumns.REQUIRE_ENCRYPTION + " integer, " - + PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL + " integer, " - + PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING + " integer, " - + PolicyColumns.DONT_ALLOW_CAMERA + " integer, " - + PolicyColumns.DONT_ALLOW_ATTACHMENTS + " integer, " - + PolicyColumns.DONT_ALLOW_HTML + " integer, " - + PolicyColumns.MAX_ATTACHMENT_SIZE + " integer, " - + PolicyColumns.MAX_TEXT_TRUNCATION_SIZE + " integer, " - + PolicyColumns.MAX_HTML_TRUNCATION_SIZE + " integer, " - + PolicyColumns.MAX_EMAIL_LOOKBACK + " integer, " - + PolicyColumns.MAX_CALENDAR_LOOKBACK + " integer, " - + PolicyColumns.PASSWORD_RECOVERY_ENABLED + " integer, " - + PolicyColumns.PROTOCOL_POLICIES_ENFORCED + " text, " - + PolicyColumns.PROTOCOL_POLICIES_UNSUPPORTED + " text" - + ");"; - db.execSQL("create table " + Policy.TABLE_NAME + s); - } - - static void createHostAuthTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + HostAuthColumns.PROTOCOL + " text, " - + HostAuthColumns.ADDRESS + " text, " - + HostAuthColumns.PORT + " integer, " - + HostAuthColumns.FLAGS + " integer, " - + HostAuthColumns.LOGIN + " text, " - + HostAuthColumns.PASSWORD + " text, " - + HostAuthColumns.DOMAIN + " text, " - + HostAuthColumns.ACCOUNT_KEY + " integer," - + HostAuthColumns.CLIENT_CERT_ALIAS + " text" - + ");"; - db.execSQL("create table " + HostAuth.TABLE_NAME + s); - } - - static void resetHostAuthTable(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - db.execSQL("drop table " + HostAuth.TABLE_NAME); - } catch (SQLException e) { - } - createHostAuthTable(db); - } - - static void createMailboxTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + MailboxColumns.DISPLAY_NAME + " text, " - + MailboxColumns.SERVER_ID + " text, " - + MailboxColumns.PARENT_SERVER_ID + " text, " - + MailboxColumns.PARENT_KEY + " integer, " - + MailboxColumns.ACCOUNT_KEY + " integer, " - + MailboxColumns.TYPE + " integer, " - + MailboxColumns.DELIMITER + " integer, " - + MailboxColumns.SYNC_KEY + " text, " - + MailboxColumns.SYNC_LOOKBACK + " integer, " - + MailboxColumns.SYNC_INTERVAL + " integer, " - + MailboxColumns.SYNC_TIME + " integer, " - + MailboxColumns.UNREAD_COUNT + " integer, " - + MailboxColumns.FLAG_VISIBLE + " integer, " - + MailboxColumns.FLAGS + " integer, " - + MailboxColumns.VISIBLE_LIMIT + " integer, " - + MailboxColumns.SYNC_STATUS + " text, " - + MailboxColumns.MESSAGE_COUNT + " integer not null default 0, " - + MailboxColumns.LAST_TOUCHED_TIME + " integer default 0, " - + MailboxColumns.UI_SYNC_STATUS + " integer default 0, " - + MailboxColumns.UI_LAST_SYNC_RESULT + " integer default 0, " - + MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY + " integer not null default 0, " - + MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT + " integer not null default 0, " - + MailboxColumns.TOTAL_COUNT + " integer" - + ");"; - db.execSQL("create table " + Mailbox.TABLE_NAME + s); - db.execSQL("create index mailbox_" + MailboxColumns.SERVER_ID - + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.SERVER_ID + ")"); - db.execSQL("create index mailbox_" + MailboxColumns.ACCOUNT_KEY - + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.ACCOUNT_KEY + ")"); - // Deleting a Mailbox deletes associated Messages in all three tables - db.execSQL(TRIGGER_MAILBOX_DELETE); - } - - static void resetMailboxTable(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - db.execSQL("drop table " + Mailbox.TABLE_NAME); - } catch (SQLException e) { - } - createMailboxTable(db); - } - - static void createAttachmentTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + AttachmentColumns.FILENAME + " text, " - + AttachmentColumns.MIME_TYPE + " text, " - + AttachmentColumns.SIZE + " integer, " - + AttachmentColumns.CONTENT_ID + " text, " - + AttachmentColumns.CONTENT_URI + " text, " - + AttachmentColumns.MESSAGE_KEY + " integer, " - + AttachmentColumns.LOCATION + " text, " - + AttachmentColumns.ENCODING + " text, " - + AttachmentColumns.CONTENT + " text, " - + AttachmentColumns.FLAGS + " integer, " - + AttachmentColumns.CONTENT_BYTES + " blob, " - + AttachmentColumns.ACCOUNT_KEY + " integer, " - + AttachmentColumns.UI_STATE + " integer, " - + AttachmentColumns.UI_DESTINATION + " integer, " - + AttachmentColumns.UI_DOWNLOADED_SIZE + " integer" - + ");"; - db.execSQL("create table " + Attachment.TABLE_NAME + s); - db.execSQL(createIndex(Attachment.TABLE_NAME, AttachmentColumns.MESSAGE_KEY)); - } - - static void resetAttachmentTable(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - db.execSQL("drop table " + Attachment.TABLE_NAME); - } catch (SQLException e) { - } - createAttachmentTable(db); - } - - static void createQuickResponseTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + QuickResponseColumns.TEXT + " text, " - + QuickResponseColumns.ACCOUNT_KEY + " integer" - + ");"; - db.execSQL("create table " + QuickResponse.TABLE_NAME + s); - } - - static void createBodyTable(SQLiteDatabase db) { - String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " - + BodyColumns.MESSAGE_KEY + " integer, " - + BodyColumns.HTML_CONTENT + " text, " - + BodyColumns.TEXT_CONTENT + " text, " - + BodyColumns.HTML_REPLY + " text, " - + BodyColumns.TEXT_REPLY + " text, " - + BodyColumns.SOURCE_MESSAGE_KEY + " text, " - + BodyColumns.INTRO_TEXT + " text" - + ");"; - db.execSQL("create table " + Body.TABLE_NAME + s); - db.execSQL(createIndex(Body.TABLE_NAME, BodyColumns.MESSAGE_KEY)); - } - - static void upgradeBodyTable(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion < 5) { - try { - db.execSQL("drop table " + Body.TABLE_NAME); - createBodyTable(db); - } catch (SQLException e) { - } - } else if (oldVersion == 5) { - try { - db.execSQL("alter table " + Body.TABLE_NAME - + " add " + BodyColumns.INTRO_TEXT + " text"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProviderBody.db from v5 to v6", e); - } - oldVersion = 6; - } - } - - protected static class BodyDatabaseHelper extends SQLiteOpenHelper { - BodyDatabaseHelper(Context context, String name) { - super(context, name, null, BODY_DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - Log.d(TAG, "Creating EmailProviderBody database"); - createBodyTable(db); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - upgradeBodyTable(db, oldVersion, newVersion); - } - - @Override - public void onOpen(SQLiteDatabase db) { - } - } - - /** Counts the number of messages in each mailbox, and updates the message count column. */ - @VisibleForTesting - static void recalculateMessageCount(SQLiteDatabase db) { - db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + - "= (select count(*) from " + Message.TABLE_NAME + - " where " + Message.MAILBOX_KEY + " = " + - Mailbox.TABLE_NAME + "." + EmailContent.RECORD_ID + ")"); - } - - protected static class DatabaseHelper extends SQLiteOpenHelper { - Context mContext; - - DatabaseHelper(Context context, String name) { - super(context, name, null, DATABASE_VERSION); - mContext = context; - } - - @Override - public void onCreate(SQLiteDatabase db) { - Log.d(TAG, "Creating EmailProvider database"); - // Create all tables here; each class has its own method - createMessageTable(db); - createAttachmentTable(db); - createMailboxTable(db); - createHostAuthTable(db); - createAccountTable(db); - createPolicyTable(db); - createQuickResponseTable(db); - } - - @Override - @SuppressWarnings("deprecation") - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // For versions prior to 5, delete all data - // Versions >= 5 require that data be preserved! - if (oldVersion < 5) { - android.accounts.Account[] accounts = AccountManager.get(mContext) - .getAccountsByType(AccountManagerTypes.TYPE_EXCHANGE); - for (android.accounts.Account account: accounts) { - AccountManager.get(mContext).removeAccount(account, null, null); - } - resetMessageTable(db, oldVersion, newVersion); - resetAttachmentTable(db, oldVersion, newVersion); - resetMailboxTable(db, oldVersion, newVersion); - resetHostAuthTable(db, oldVersion, newVersion); - resetAccountTable(db, oldVersion, newVersion); - return; - } - if (oldVersion == 5) { - // Message Tables: Add SyncColumns.SERVER_TIMESTAMP - try { - db.execSQL("alter table " + Message.TABLE_NAME - + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); - db.execSQL("alter table " + Message.UPDATED_TABLE_NAME - + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); - db.execSQL("alter table " + Message.DELETED_TABLE_NAME - + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from v5 to v6", e); - } - oldVersion = 6; - } - if (oldVersion == 6) { - // Use the newer mailbox_delete trigger - db.execSQL("drop trigger mailbox_delete;"); - db.execSQL(TRIGGER_MAILBOX_DELETE); - oldVersion = 7; - } - if (oldVersion == 7) { - // add the security (provisioning) column - try { - db.execSQL("alter table " + Account.TABLE_NAME - + " add column " + AccountColumns.SECURITY_FLAGS + " integer" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 7 to 8 " + e); - } - oldVersion = 8; - } - if (oldVersion == 8) { - // accounts: add security sync key & user signature columns - try { - db.execSQL("alter table " + Account.TABLE_NAME - + " add column " + AccountColumns.SECURITY_SYNC_KEY + " text" + ";"); - db.execSQL("alter table " + Account.TABLE_NAME - + " add column " + AccountColumns.SIGNATURE + " text" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 8 to 9 " + e); - } - oldVersion = 9; - } - if (oldVersion == 9) { - // Message: add meeting info column into Message tables - try { - db.execSQL("alter table " + Message.TABLE_NAME - + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); - db.execSQL("alter table " + Message.UPDATED_TABLE_NAME - + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); - db.execSQL("alter table " + Message.DELETED_TABLE_NAME - + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 9 to 10 " + e); - } - oldVersion = 10; - } - if (oldVersion == 10) { - // Attachment: add content and flags columns - try { - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + AttachmentColumns.CONTENT + " text" + ";"); - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + AttachmentColumns.FLAGS + " integer" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 10 to 11 " + e); - } - oldVersion = 11; - } - if (oldVersion == 11) { - // Attachment: add content_bytes - try { - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + AttachmentColumns.CONTENT_BYTES + " blob" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 11 to 12 " + e); - } - oldVersion = 12; - } - if (oldVersion == 12) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.MESSAGE_COUNT - +" integer not null default 0" + ";"); - recalculateMessageCount(db); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 12 to 13 " + e); - } - oldVersion = 13; - } - if (oldVersion == 13) { - try { - db.execSQL("alter table " + Message.TABLE_NAME - + " add column " + Message.SNIPPET - +" text" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 13 to 14 " + e); - } - oldVersion = 14; - } - if (oldVersion == 14) { - try { - db.execSQL("alter table " + Message.DELETED_TABLE_NAME - + " add column " + Message.SNIPPET +" text" + ";"); - db.execSQL("alter table " + Message.UPDATED_TABLE_NAME - + " add column " + Message.SNIPPET +" text" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 14 to 15 " + e); - } - oldVersion = 15; - } - if (oldVersion == 15) { - try { - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + Attachment.ACCOUNT_KEY +" integer" + ";"); - // Update all existing attachments to add the accountKey data - db.execSQL("update " + Attachment.TABLE_NAME + " set " + - Attachment.ACCOUNT_KEY + "= (SELECT " + Message.TABLE_NAME + "." + - Message.ACCOUNT_KEY + " from " + Message.TABLE_NAME + " where " + - Message.TABLE_NAME + "." + Message.RECORD_ID + " = " + - Attachment.TABLE_NAME + "." + Attachment.MESSAGE_KEY + ")"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 15 to 16 " + e); - } - oldVersion = 16; - } - if (oldVersion == 16) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.PARENT_KEY + " integer;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 16 to 17 " + e); - } - oldVersion = 17; - } - if (oldVersion == 17) { - upgradeFromVersion17ToVersion18(db); - oldVersion = 18; - } - if (oldVersion == 18) { - try { - db.execSQL("alter table " + Account.TABLE_NAME - + " add column " + Account.POLICY_KEY + " integer;"); - db.execSQL("drop trigger account_delete;"); - db.execSQL(TRIGGER_ACCOUNT_DELETE); - createPolicyTable(db); - convertPolicyFlagsToPolicyTable(db); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 18 to 19 " + e); - } - oldVersion = 19; - } - if (oldVersion == 19) { - try { - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING + - " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.DONT_ALLOW_CAMERA + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.DONT_ALLOW_ATTACHMENTS + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.DONT_ALLOW_HTML + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.MAX_ATTACHMENT_SIZE + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.MAX_TEXT_TRUNCATION_SIZE + - " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.MAX_HTML_TRUNCATION_SIZE + - " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.MAX_EMAIL_LOOKBACK + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.MAX_CALENDAR_LOOKBACK + " integer;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + PolicyColumns.PASSWORD_RECOVERY_ENABLED + - " integer;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 19 to 20 " + e); - } - oldVersion = 20; - } - if (oldVersion == 20) { - oldVersion = 21; - } - if (oldVersion == 21) { - upgradeFromVersion21ToVersion22(db, mContext); - oldVersion = 22; - } - if (oldVersion == 22) { - upgradeFromVersion22ToVersion23(db); - oldVersion = 23; - } - if (oldVersion == 23) { - upgradeFromVersion23ToVersion24(db); - oldVersion = 24; - } - if (oldVersion == 24) { - upgradeFromVersion24ToVersion25(db); - oldVersion = 25; - } - if (oldVersion == 25) { - upgradeFromVersion25ToVersion26(db); - oldVersion = 26; - } - if (oldVersion == 26) { - try { - db.execSQL("alter table " + Message.TABLE_NAME - + " add column " + Message.PROTOCOL_SEARCH_INFO + " text;"); - db.execSQL("alter table " + Message.DELETED_TABLE_NAME - + " add column " + Message.PROTOCOL_SEARCH_INFO +" text" + ";"); - db.execSQL("alter table " + Message.UPDATED_TABLE_NAME - + " add column " + Message.PROTOCOL_SEARCH_INFO +" text" + ";"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 26 to 27 " + e); - } - oldVersion = 27; - } - if (oldVersion == 27) { - oldVersion = 28; - } - if (oldVersion == 28) { - try { - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + Policy.PROTOCOL_POLICIES_ENFORCED + " text;"); - db.execSQL("alter table " + Policy.TABLE_NAME - + " add column " + Policy.PROTOCOL_POLICIES_UNSUPPORTED + " text;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 28 to 29 " + e); - } - oldVersion = 29; - } - if (oldVersion == 29) { - upgradeFromVersion29ToVersion30(db); - oldVersion = 30; - } - if (oldVersion == 30) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.UI_SYNC_STATUS + " integer;"); - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.UI_LAST_SYNC_RESULT + " integer;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 30 to 31 " + e); - } - oldVersion = 31; - } - if (oldVersion == 31) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.LAST_NOTIFIED_MESSAGE_KEY + " integer;"); - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.LAST_NOTIFIED_MESSAGE_COUNT + " integer;"); - db.execSQL("update Mailbox set " + Mailbox.LAST_NOTIFIED_MESSAGE_KEY + - "=0 where " + Mailbox.LAST_NOTIFIED_MESSAGE_KEY + " IS NULL"); - db.execSQL("update Mailbox set " + Mailbox.LAST_NOTIFIED_MESSAGE_COUNT + - "=0 where " + Mailbox.LAST_NOTIFIED_MESSAGE_COUNT + " IS NULL"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 31 to 32 " + e); - } - oldVersion = 32; - } - if (oldVersion == 32) { - try { - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + Attachment.UI_STATE + " integer;"); - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + Attachment.UI_DESTINATION + " integer;"); - db.execSQL("alter table " + Attachment.TABLE_NAME - + " add column " + Attachment.UI_DOWNLOADED_SIZE + " integer;"); - // If we have a contentUri then the attachment is saved - // uiDestination of 0 = "cache", so we don't have to set this - db.execSQL("update " + Attachment.TABLE_NAME + " set " + Attachment.UI_STATE + - "=" + UIProvider.AttachmentState.SAVED + " where " + - AttachmentColumns.CONTENT_URI + " is not null;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 32 to 33 " + e); - } - oldVersion = 33; - } - if (oldVersion == 33) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + MailboxColumns.TOTAL_COUNT + " integer;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 33 to 34 " + e); - } - oldVersion = 34; - } - } - - @Override - public void onOpen(SQLiteDatabase db) { - } - } - - @VisibleForTesting - @SuppressWarnings("deprecation") - static void convertPolicyFlagsToPolicyTable(SQLiteDatabase db) { - Cursor c = db.query(Account.TABLE_NAME, - new String[] {EmailContent.RECORD_ID /*0*/, AccountColumns.SECURITY_FLAGS /*1*/}, - AccountColumns.SECURITY_FLAGS + ">0", null, null, null, null); - ContentValues cv = new ContentValues(); - String[] args = new String[1]; - while (c.moveToNext()) { - long securityFlags = c.getLong(1 /*SECURITY_FLAGS*/); - Policy policy = LegacyPolicySet.flagsToPolicy(securityFlags); - long policyId = db.insert(Policy.TABLE_NAME, null, policy.toContentValues()); - cv.put(AccountColumns.POLICY_KEY, policyId); - cv.putNull(AccountColumns.SECURITY_FLAGS); - args[0] = Long.toString(c.getLong(0 /*RECORD_ID*/)); - db.update(Account.TABLE_NAME, cv, EmailContent.RECORD_ID + "=?", args); - } - } - - /** Upgrades the database from v17 to v18 */ - @VisibleForTesting - static void upgradeFromVersion17ToVersion18(SQLiteDatabase db) { - // Copy the displayName column to the serverId column. In v18 of the database, - // we use the serverId for IMAP/POP3 mailboxes instead of overloading the - // display name. - // - // For posterity; this is the command we're executing: - //sqlite> UPDATE mailbox SET serverid=displayname WHERE mailbox._id in ( - // ...> SELECT mailbox._id FROM mailbox,account,hostauth WHERE - // ...> (mailbox.parentkey isnull OR mailbox.parentkey=0) AND - // ...> mailbox.accountkey=account._id AND - // ...> account.hostauthkeyrecv=hostauth._id AND - // ...> (hostauth.protocol='imap' OR hostauth.protocol='pop3')); - try { - db.execSQL( - "UPDATE " + Mailbox.TABLE_NAME + " SET " - + MailboxColumns.SERVER_ID + "=" + MailboxColumns.DISPLAY_NAME - + " WHERE " - + Mailbox.TABLE_NAME + "." + MailboxColumns.ID + " IN ( SELECT " - + Mailbox.TABLE_NAME + "." + MailboxColumns.ID + " FROM " - + Mailbox.TABLE_NAME + "," + Account.TABLE_NAME + "," - + HostAuth.TABLE_NAME + " WHERE " - + "(" - + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_KEY + " isnull OR " - + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_KEY + "=0 " - + ") AND " - + Mailbox.TABLE_NAME + "." + MailboxColumns.ACCOUNT_KEY + "=" - + Account.TABLE_NAME + "." + AccountColumns.ID + " AND " - + Account.TABLE_NAME + "." + AccountColumns.HOST_AUTH_KEY_RECV + "=" - + HostAuth.TABLE_NAME + "." + HostAuthColumns.ID + " AND ( " - + HostAuth.TABLE_NAME + "." + HostAuthColumns.PROTOCOL + "='imap' OR " - + HostAuth.TABLE_NAME + "." + HostAuthColumns.PROTOCOL + "='pop3' ) )"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 17 to 18 " + e); - } - ContentCache.invalidateAllCaches(); - } - - /** - * Upgrade the database from v21 to v22 - * This entails creating AccountManager accounts for all pop3 and imap accounts - */ - - private static final String[] V21_ACCOUNT_PROJECTION = - new String[] {AccountColumns.HOST_AUTH_KEY_RECV, AccountColumns.EMAIL_ADDRESS}; - private static final int V21_ACCOUNT_RECV = 0; - private static final int V21_ACCOUNT_EMAIL = 1; - - private static final String[] V21_HOSTAUTH_PROJECTION = - new String[] {HostAuthColumns.PROTOCOL, HostAuthColumns.PASSWORD}; - private static final int V21_HOSTAUTH_PROTOCOL = 0; - private static final int V21_HOSTAUTH_PASSWORD = 1; - - static private void createAccountManagerAccount(Context context, String login, - String password) { - AccountManager accountManager = AccountManager.get(context); - android.accounts.Account amAccount = - new android.accounts.Account(login, AccountManagerTypes.TYPE_POP_IMAP); - accountManager.addAccountExplicitly(amAccount, password, null); - ContentResolver.setIsSyncable(amAccount, EmailContent.AUTHORITY, 1); - ContentResolver.setSyncAutomatically(amAccount, EmailContent.AUTHORITY, true); - ContentResolver.setIsSyncable(amAccount, ContactsContract.AUTHORITY, 0); - ContentResolver.setIsSyncable(amAccount, CalendarProviderStub.AUTHORITY, 0); - } - - @VisibleForTesting - static void upgradeFromVersion21ToVersion22(SQLiteDatabase db, Context accountManagerContext) { - try { - // Loop through accounts, looking for pop/imap accounts - Cursor accountCursor = db.query(Account.TABLE_NAME, V21_ACCOUNT_PROJECTION, null, - null, null, null, null); - try { - String[] hostAuthArgs = new String[1]; - while (accountCursor.moveToNext()) { - hostAuthArgs[0] = accountCursor.getString(V21_ACCOUNT_RECV); - // Get the "receive" HostAuth for this account - Cursor hostAuthCursor = db.query(HostAuth.TABLE_NAME, - V21_HOSTAUTH_PROJECTION, HostAuth.RECORD_ID + "=?", hostAuthArgs, - null, null, null); - try { - if (hostAuthCursor.moveToFirst()) { - String protocol = hostAuthCursor.getString(V21_HOSTAUTH_PROTOCOL); - // If this is a pop3 or imap account, create the account manager account - if (HostAuth.SCHEME_IMAP.equals(protocol) || - HostAuth.SCHEME_POP3.equals(protocol)) { - if (Email.DEBUG) { - Log.d(TAG, "Create AccountManager account for " + protocol + - "account: " + - accountCursor.getString(V21_ACCOUNT_EMAIL)); - } - createAccountManagerAccount(accountManagerContext, - accountCursor.getString(V21_ACCOUNT_EMAIL), - hostAuthCursor.getString(V21_HOSTAUTH_PASSWORD)); - // If an EAS account, make Email sync automatically (equivalent of - // checking the "Sync Email" box in settings - } else if (HostAuth.SCHEME_EAS.equals(protocol)) { - android.accounts.Account amAccount = - new android.accounts.Account( - accountCursor.getString(V21_ACCOUNT_EMAIL), - AccountManagerTypes.TYPE_EXCHANGE); - ContentResolver.setIsSyncable(amAccount, EmailContent.AUTHORITY, 1); - ContentResolver.setSyncAutomatically(amAccount, - EmailContent.AUTHORITY, true); - - } - } - } finally { - hostAuthCursor.close(); - } - } - } finally { - accountCursor.close(); - } - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 20 to 21 " + e); - } - } - - /** Upgrades the database from v22 to v23 */ - private static void upgradeFromVersion22ToVersion23(SQLiteDatabase db) { - try { - db.execSQL("alter table " + Mailbox.TABLE_NAME - + " add column " + Mailbox.LAST_TOUCHED_TIME + " integer default 0;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 22 to 23 " + e); - } - } - - /** Adds in a column for information about a client certificate to use. */ - private static void upgradeFromVersion23ToVersion24(SQLiteDatabase db) { - try { - db.execSQL("alter table " + HostAuth.TABLE_NAME - + " add column " + HostAuth.CLIENT_CERT_ALIAS + " text;"); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 23 to 24 " + e); - } - } - - /** Upgrades the database from v24 to v25 by creating table for quick responses */ - private static void upgradeFromVersion24ToVersion25(SQLiteDatabase db) { - try { - createQuickResponseTable(db); - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 24 to 25 " + e); - } - } - - private static final String[] V25_ACCOUNT_PROJECTION = - new String[] {AccountColumns.ID, AccountColumns.FLAGS, AccountColumns.HOST_AUTH_KEY_RECV}; - private static final int V25_ACCOUNT_ID = 0; - private static final int V25_ACCOUNT_FLAGS = 1; - private static final int V25_ACCOUNT_RECV = 2; - - private static final String[] V25_HOSTAUTH_PROJECTION = new String[] {HostAuthColumns.PROTOCOL}; - private static final int V25_HOSTAUTH_PROTOCOL = 0; - - /** Upgrades the database from v25 to v26 by adding FLAG_SUPPORTS_SEARCH to IMAP accounts */ - private static void upgradeFromVersion25ToVersion26(SQLiteDatabase db) { - try { - // Loop through accounts, looking for imap accounts - Cursor accountCursor = db.query(Account.TABLE_NAME, V25_ACCOUNT_PROJECTION, null, - null, null, null, null); - ContentValues cv = new ContentValues(); - try { - String[] hostAuthArgs = new String[1]; - while (accountCursor.moveToNext()) { - hostAuthArgs[0] = accountCursor.getString(V25_ACCOUNT_RECV); - // Get the "receive" HostAuth for this account - Cursor hostAuthCursor = db.query(HostAuth.TABLE_NAME, - V25_HOSTAUTH_PROJECTION, HostAuth.RECORD_ID + "=?", hostAuthArgs, - null, null, null); - try { - if (hostAuthCursor.moveToFirst()) { - String protocol = hostAuthCursor.getString(V25_HOSTAUTH_PROTOCOL); - // If this is an imap account, add the search flag - if (HostAuth.SCHEME_IMAP.equals(protocol)) { - String id = accountCursor.getString(V25_ACCOUNT_ID); - int flags = accountCursor.getInt(V25_ACCOUNT_FLAGS); - cv.put(AccountColumns.FLAGS, flags | Account.FLAGS_SUPPORTS_SEARCH); - db.update(Account.TABLE_NAME, cv, Account.RECORD_ID + "=?", - new String[] {id}); - } - } - } finally { - hostAuthCursor.close(); - } - } - } finally { - accountCursor.close(); - } - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 25 to 26 " + e); - } - } - - /** Upgrades the database from v29 to v30 by updating all address fields in Message */ - private static final int[] ADDRESS_COLUMN_INDICES = new int[] { - Message.CONTENT_BCC_LIST_COLUMN, Message.CONTENT_CC_LIST_COLUMN, - Message.CONTENT_FROM_LIST_COLUMN, Message.CONTENT_REPLY_TO_COLUMN, - Message.CONTENT_TO_LIST_COLUMN - }; - private static final String[] ADDRESS_COLUMN_NAMES = new String[] { - Message.BCC_LIST, Message.CC_LIST, Message.FROM_LIST, Message.REPLY_TO_LIST, Message.TO_LIST - }; - - private static void upgradeFromVersion29ToVersion30(SQLiteDatabase db) { - try { - // Loop through all messages, updating address columns to new format (CSV, RFC822) - Cursor messageCursor = db.query(Message.TABLE_NAME, Message.CONTENT_PROJECTION, null, - null, null, null, null); - ContentValues cv = new ContentValues(); - String[] whereArgs = new String[1]; - try { - while (messageCursor.moveToNext()) { - for (int i = 0; i < ADDRESS_COLUMN_INDICES.length; i++) { - Address[] addrs = - Address.unpack(messageCursor.getString(ADDRESS_COLUMN_INDICES[i])); - cv.put(ADDRESS_COLUMN_NAMES[i], Address.pack(addrs)); - } - whereArgs[0] = messageCursor.getString(Message.CONTENT_ID_COLUMN); - db.update(Message.TABLE_NAME, cv, WHERE_ID, whereArgs); - } - } finally { - messageCursor.close(); - } - } catch (SQLException e) { - // Shouldn't be needed unless we're debugging and interrupt the process - Log.w(TAG, "Exception upgrading EmailProvider.db from 29 to 30 " + e); - } - } - -} diff --git a/src/com/android/email/provider/EmailProvider.java b/src/com/android/email/provider/EmailProvider.java index e9eb7fdf7..bbedfdb26 100644 --- a/src/com/android/email/provider/EmailProvider.java +++ b/src/com/android/email/provider/EmailProvider.java @@ -16,35 +16,35 @@ package com.android.email.provider; +import android.accounts.AccountManager; import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; +import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.ContentObserver; import android.database.Cursor; import android.database.MatrixCursor; +import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; -import android.os.RemoteException; -import android.provider.BaseColumns; +import android.provider.ContactsContract; import android.text.TextUtils; import android.util.Log; -import com.android.common.content.ProjectionMap; import com.android.email.Email; import com.android.email.Preferences; -import com.android.email.R; -import com.android.email.SecurityPolicy; import com.android.email.provider.ContentCache.CacheToken; import com.android.email.service.AttachmentDownloadService; -import com.android.email.service.EmailServiceUtils; +import com.android.emailcommon.AccountManagerTypes; +import com.android.emailcommon.CalendarProviderStub; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; @@ -53,24 +53,18 @@ import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.EmailContent.Body; import com.android.emailcommon.provider.EmailContent.BodyColumns; +import com.android.emailcommon.provider.EmailContent.HostAuthColumns; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.EmailContent.MessageColumns; import com.android.emailcommon.provider.EmailContent.PolicyColumns; +import com.android.emailcommon.provider.EmailContent.QuickResponseColumns; import com.android.emailcommon.provider.EmailContent.SyncColumns; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.provider.Policy; import com.android.emailcommon.provider.QuickResponse; -import com.android.emailcommon.service.EmailServiceProxy; -import com.android.emailcommon.service.IEmailService; -import com.android.emailcommon.service.IEmailServiceCallback; -import com.android.emailcommon.service.SearchParams; -import com.android.emailcommon.utility.AttachmentUtilities; -import com.android.mail.providers.UIProvider; -import com.android.mail.providers.UIProvider.AccountCapabilities; -import com.android.mail.providers.UIProvider.ConversationPriority; -import com.android.mail.providers.UIProvider.ConversationSendingState; +import com.android.emailcommon.service.LegacyPolicySet; import com.google.common.annotations.VisibleForTesting; import java.io.File; @@ -99,7 +93,7 @@ public class EmailProvider extends ContentProvider { * is NOT the preferred way of getting notification. */ public static final String ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED = - "com.android.email.MESSAGE_LIST_DATASET_CHANGED"; + "com.android.email.MESSAGE_LIST_DATASET_CHANGED"; public static final String EMAIL_MESSAGE_MIME_TYPE = "vnd.android.cursor.item/email-message"; @@ -110,10 +104,6 @@ public class EmailProvider extends ContentProvider { Uri.parse("content://" + EmailContent.AUTHORITY + "/integrityCheck"); public static final Uri ACCOUNT_BACKUP_URI = Uri.parse("content://" + EmailContent.AUTHORITY + "/accountBackup"); - public static final Uri FOLDER_STATUS_URI = - Uri.parse("content://" + EmailContent.AUTHORITY + "/status"); - public static final Uri FOLDER_REFRESH_URI = - Uri.parse("content://" + EmailContent.AUTHORITY + "/refresh"); /** Appended to the notification URI for delete operations */ public static final String NOTIFICATION_OP_DELETE = "delete"; @@ -149,6 +139,47 @@ public class EmailProvider extends ContentProvider { private final ContentCache mCachePolicy = new ContentCache("Policy", Policy.CONTENT_PROJECTION, MAX_CACHED_ACCOUNTS); + // Any changes to the database format *must* include update-in-place code. + // Original version: 3 + // Version 4: Database wipe required; changing AccountManager interface w/Exchange + // Version 5: Database wipe required; changing AccountManager interface w/Exchange + // Version 6: Adding Message.mServerTimeStamp column + // Version 7: Replace the mailbox_delete trigger with a version that removes orphaned messages + // from the Message_Deletes and Message_Updates tables + // Version 8: Add security flags column to accounts table + // Version 9: Add security sync key and signature to accounts table + // Version 10: Add meeting info to message table + // Version 11: Add content and flags to attachment table + // Version 12: Add content_bytes to attachment table. content is deprecated. + // Version 13: Add messageCount to Mailbox table. + // Version 14: Add snippet to Message table + // Version 15: Fix upgrade problem in version 14. + // Version 16: Add accountKey to Attachment table + // Version 17: Add parentKey to Mailbox table + // Version 18: Copy Mailbox.displayName to Mailbox.serverId for all IMAP & POP3 mailboxes. + // Column Mailbox.serverId is used for the server-side pathname of a mailbox. + // Version 19: Add Policy table; add policyKey to Account table and trigger to delete an + // Account's policy when the Account is deleted + // Version 20: Add new policies to Policy table + // Version 21: Add lastSeenMessageKey column to Mailbox table + // Version 22: Upgrade path for IMAP/POP accounts to integrate with AccountManager + // Version 23: Add column to mailbox table for time of last access + // Version 24: Add column to hostauth table for client cert alias + // Version 25: Added QuickResponse table + // Version 26: Update IMAP accounts to add FLAG_SUPPORTS_SEARCH flag + // Version 27: Add protocolSearchInfo to Message table + // Version 28: Add notifiedMessageId and notifiedMessageCount to Account + + public static final int DATABASE_VERSION = 28; + + // Any changes to the database format *must* include update-in-place code. + // Original version: 2 + // Version 3: Add "sourceKey" column + // Version 4: Database wipe required; changing AccountManager interface w/Exchange + // Version 5: Database wipe required; changing AccountManager interface w/Exchange + // Version 6: Adding Body.mIntroText column + public static final int BODY_DATABASE_VERSION = 6; + private static final int ACCOUNT_BASE = 0; private static final int ACCOUNT = ACCOUNT_BASE; private static final int ACCOUNT_ID = ACCOUNT_BASE + 1; @@ -161,9 +192,7 @@ public class EmailProvider extends ContentProvider { private static final int MAILBOX = MAILBOX_BASE; private static final int MAILBOX_ID = MAILBOX_BASE + 1; private static final int MAILBOX_ID_FROM_ACCOUNT_AND_TYPE = MAILBOX_BASE + 2; - private static final int MAILBOX_ID_ADD_TO_FIELD = MAILBOX_BASE + 3; - private static final int MAILBOX_NOTIFICATION = MAILBOX_BASE + 4; - private static final int MAILBOX_MOST_RECENT_MESSAGE = MAILBOX_BASE + 5; + private static final int MAILBOX_ID_ADD_TO_FIELD = MAILBOX_BASE + 2; private static final int MESSAGE_BASE = 0x2000; private static final int MESSAGE = MESSAGE_BASE; @@ -196,29 +225,8 @@ public class EmailProvider extends ContentProvider { private static final int QUICK_RESPONSE_ID = QUICK_RESPONSE_BASE + 1; private static final int QUICK_RESPONSE_ACCOUNT_ID = QUICK_RESPONSE_BASE + 2; - private static final int UI_BASE = 0x9000; - private static final int UI_FOLDERS = UI_BASE; - private static final int UI_SUBFOLDERS = UI_BASE + 1; - private static final int UI_MESSAGES = UI_BASE + 2; - private static final int UI_MESSAGE = UI_BASE + 3; - private static final int UI_SENDMAIL = UI_BASE + 4; - private static final int UI_UNDO = UI_BASE + 5; - private static final int UI_SAVEDRAFT = UI_BASE + 6; - private static final int UI_UPDATEDRAFT = UI_BASE + 7; - private static final int UI_SENDDRAFT = UI_BASE + 8; - private static final int UI_FOLDER_REFRESH = UI_BASE + 9; - private static final int UI_FOLDER = UI_BASE + 10; - private static final int UI_ACCOUNT = UI_BASE + 11; - private static final int UI_ACCTS = UI_BASE + 12; - private static final int UI_SETTINGS = UI_BASE + 13; - private static final int UI_ATTACHMENTS = UI_BASE + 14; - private static final int UI_ATTACHMENT = UI_BASE + 15; - private static final int UI_SEARCH = UI_BASE + 16; - private static final int UI_ACCOUNT_DATA = UI_BASE + 17; - private static final int UI_FOLDER_LOAD_MORE = UI_BASE + 18; - // MUST ALWAYS EQUAL THE LAST OF THE PREVIOUS BASE CONSTANTS - private static final int LAST_EMAIL_PROVIDER_DB_BASE = UI_BASE; + private static final int LAST_EMAIL_PROVIDER_DB_BASE = QUICK_RESPONSE_BASE; // DO NOT CHANGE BODY_BASE!! private static final int BODY_BASE = LAST_EMAIL_PROVIDER_DB_BASE + 0x1000; @@ -239,8 +247,7 @@ public class EmailProvider extends ContentProvider { Message.DELETED_TABLE_NAME, Policy.TABLE_NAME, QuickResponse.TABLE_NAME, - null, // UI - Body.TABLE_NAME, + Body.TABLE_NAME }; // CONTENT_CACHES MUST remain in the order of the BASE constants above @@ -254,8 +261,7 @@ public class EmailProvider extends ContentProvider { null, // Deleted message mCachePolicy, null, // Quick response - null, // Body - null // UI + null // Body }; // CACHE_PROJECTIONS MUST remain in the order of the BASE constants above @@ -269,8 +275,7 @@ public class EmailProvider extends ContentProvider { null, // Deleted message Policy.CONTENT_PROJECTION, null, // Quick response - null, // Body - null // UI + null // Body }; private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); @@ -304,19 +309,33 @@ public class EmailProvider extends ContentProvider { private static final String ID_EQUALS = EmailContent.RECORD_ID + "=?"; + private static final String TRIGGER_MAILBOX_DELETE = + "create trigger mailbox_delete before delete on " + Mailbox.TABLE_NAME + + " begin" + + " delete from " + Message.TABLE_NAME + + " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + + "; delete from " + Message.UPDATED_TABLE_NAME + + " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + + "; delete from " + Message.DELETED_TABLE_NAME + + " where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID + + "; end"; + + private static final String TRIGGER_ACCOUNT_DELETE = + "create trigger account_delete before delete on " + Account.TABLE_NAME + + " begin delete from " + Mailbox.TABLE_NAME + + " where " + MailboxColumns.ACCOUNT_KEY + "=old." + EmailContent.RECORD_ID + + "; delete from " + HostAuth.TABLE_NAME + + " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_RECV + + "; delete from " + HostAuth.TABLE_NAME + + " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_SEND + + "; delete from " + Policy.TABLE_NAME + + " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.POLICY_KEY + + "; end"; + private static final ContentValues CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT; - private static final ContentValues EMPTY_CONTENT_VALUES = new ContentValues(); public static final String MESSAGE_URI_PARAMETER_MAILBOX_ID = "mailboxId"; - // For undo handling - private int mLastSequence = -1; - private ArrayList<ContentProviderOperation> mLastSequenceOps = - new ArrayList<ContentProviderOperation>(); - - // Query parameter indicating the command came from UIProvider - private static final String IS_UIPROVIDER = "is_uiprovider"; - static { // Email URI matching table UriMatcher matcher = sURIMatcher; @@ -343,10 +362,6 @@ public class EmailProvider extends ContentProvider { matcher.addURI(EmailContent.AUTHORITY, "mailbox/#", MAILBOX_ID); matcher.addURI(EmailContent.AUTHORITY, "mailboxIdFromAccountAndType/#/#", MAILBOX_ID_FROM_ACCOUNT_AND_TYPE); - matcher.addURI(EmailContent.AUTHORITY, "mailboxNotification/#", MAILBOX_NOTIFICATION); - matcher.addURI(EmailContent.AUTHORITY, "mailboxMostRecentMessage/#", - MAILBOX_MOST_RECENT_MESSAGE); - // All messages matcher.addURI(EmailContent.AUTHORITY, "message", MESSAGE); // A specific message @@ -412,26 +427,6 @@ public class EmailProvider extends ContentProvider { // All quick responses associated with a particular account id matcher.addURI(EmailContent.AUTHORITY, "quickresponse/account/#", QUICK_RESPONSE_ACCOUNT_ID); - - matcher.addURI(EmailContent.AUTHORITY, "uifolders/#", UI_FOLDERS); - matcher.addURI(EmailContent.AUTHORITY, "uisubfolders/#", UI_SUBFOLDERS); - matcher.addURI(EmailContent.AUTHORITY, "uimessages/#", UI_MESSAGES); - matcher.addURI(EmailContent.AUTHORITY, "uimessage/#", UI_MESSAGE); - matcher.addURI(EmailContent.AUTHORITY, "uisendmail/#", UI_SENDMAIL); - matcher.addURI(EmailContent.AUTHORITY, "uiundo/#", UI_UNDO); - matcher.addURI(EmailContent.AUTHORITY, "uisavedraft/#", UI_SAVEDRAFT); - matcher.addURI(EmailContent.AUTHORITY, "uiupdatedraft/#", UI_UPDATEDRAFT); - matcher.addURI(EmailContent.AUTHORITY, "uisenddraft/#", UI_SENDDRAFT); - matcher.addURI(EmailContent.AUTHORITY, "uirefresh/#", UI_FOLDER_REFRESH); - matcher.addURI(EmailContent.AUTHORITY, "uifolder/#", UI_FOLDER); - matcher.addURI(EmailContent.AUTHORITY, "uiaccount/#", UI_ACCOUNT); - matcher.addURI(EmailContent.AUTHORITY, "uiaccts", UI_ACCTS); - matcher.addURI(EmailContent.AUTHORITY, "uisettings/#", UI_SETTINGS); - matcher.addURI(EmailContent.AUTHORITY, "uiattachments/#", UI_ATTACHMENTS); - matcher.addURI(EmailContent.AUTHORITY, "uiattachment/#", UI_ATTACHMENT); - matcher.addURI(EmailContent.AUTHORITY, "uisearch/#", UI_SEARCH); - matcher.addURI(EmailContent.AUTHORITY, "uiaccountdata/#", UI_ACCOUNT_DATA); - matcher.addURI(EmailContent.AUTHORITY, "uiloadmore/#", UI_FOLDER_LOAD_MORE); } /** @@ -449,17 +444,360 @@ public class EmailProvider extends ContentProvider { return match; } - private SQLiteDatabase mDatabase; - private SQLiteDatabase mBodyDatabase; + /* + * Internal helper method for index creation. + * Example: + * "create index message_" + MessageColumns.FLAG_READ + * + " on " + Message.TABLE_NAME + " (" + MessageColumns.FLAG_READ + ");" + */ + /* package */ + static String createIndex(String tableName, String columnName) { + return "create index " + tableName.toLowerCase() + '_' + columnName + + " on " + tableName + " (" + columnName + ");"; + } + + static void createMessageTable(SQLiteDatabase db) { + String messageColumns = MessageColumns.DISPLAY_NAME + " text, " + + MessageColumns.TIMESTAMP + " integer, " + + MessageColumns.SUBJECT + " text, " + + MessageColumns.FLAG_READ + " integer, " + + MessageColumns.FLAG_LOADED + " integer, " + + MessageColumns.FLAG_FAVORITE + " integer, " + + MessageColumns.FLAG_ATTACHMENT + " integer, " + + MessageColumns.FLAGS + " integer, " + + MessageColumns.CLIENT_ID + " integer, " + + MessageColumns.MESSAGE_ID + " text, " + + MessageColumns.MAILBOX_KEY + " integer, " + + MessageColumns.ACCOUNT_KEY + " integer, " + + MessageColumns.FROM_LIST + " text, " + + MessageColumns.TO_LIST + " text, " + + MessageColumns.CC_LIST + " text, " + + MessageColumns.BCC_LIST + " text, " + + MessageColumns.REPLY_TO_LIST + " text, " + + MessageColumns.MEETING_INFO + " text, " + + MessageColumns.SNIPPET + " text, " + + MessageColumns.PROTOCOL_SEARCH_INFO + " text" + + ");"; + + // This String and the following String MUST have the same columns, except for the type + // of those columns! + String createString = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + SyncColumns.SERVER_ID + " text, " + + SyncColumns.SERVER_TIMESTAMP + " integer, " + + messageColumns; + + // For the updated and deleted tables, the id is assigned, but we do want to keep track + // of the ORDER of updates using an autoincrement primary key. We use the DATA column + // at this point; it has no other function + String altCreateString = " (" + EmailContent.RECORD_ID + " integer unique, " + + SyncColumns.SERVER_ID + " text, " + + SyncColumns.SERVER_TIMESTAMP + " integer, " + + messageColumns; + + // The three tables have the same schema + db.execSQL("create table " + Message.TABLE_NAME + createString); + db.execSQL("create table " + Message.UPDATED_TABLE_NAME + altCreateString); + db.execSQL("create table " + Message.DELETED_TABLE_NAME + altCreateString); + + String indexColumns[] = { + MessageColumns.TIMESTAMP, + MessageColumns.FLAG_READ, + MessageColumns.FLAG_LOADED, + MessageColumns.MAILBOX_KEY, + SyncColumns.SERVER_ID + }; + + for (String columnName : indexColumns) { + db.execSQL(createIndex(Message.TABLE_NAME, columnName)); + } + + // Deleting a Message deletes all associated Attachments + // Deleting the associated Body cannot be done in a trigger, because the Body is stored + // in a separate database, and trigger cannot operate on attached databases. + db.execSQL("create trigger message_delete before delete on " + Message.TABLE_NAME + + " begin delete from " + Attachment.TABLE_NAME + + " where " + AttachmentColumns.MESSAGE_KEY + "=old." + EmailContent.RECORD_ID + + "; end"); + + // Add triggers to keep unread count accurate per mailbox + + // NOTE: SQLite's before triggers are not safe when recursive triggers are involved. + // Use caution when changing them. + + // Insert a message; if flagRead is zero, add to the unread count of the message's mailbox + db.execSQL("create trigger unread_message_insert before insert on " + Message.TABLE_NAME + + " when NEW." + MessageColumns.FLAG_READ + "=0" + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + + '=' + MailboxColumns.UNREAD_COUNT + "+1" + + " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Delete a message; if flagRead is zero, decrement the unread count of the msg's mailbox + db.execSQL("create trigger unread_message_delete before delete on " + Message.TABLE_NAME + + " when OLD." + MessageColumns.FLAG_READ + "=0" + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + + '=' + MailboxColumns.UNREAD_COUNT + "-1" + + " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Change a message's mailbox + db.execSQL("create trigger unread_message_move before update of " + + MessageColumns.MAILBOX_KEY + " on " + Message.TABLE_NAME + + " when OLD." + MessageColumns.FLAG_READ + "=0" + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + + '=' + MailboxColumns.UNREAD_COUNT + "-1" + + " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + + "; update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + + '=' + MailboxColumns.UNREAD_COUNT + "+1" + + " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Change a message's read state + db.execSQL("create trigger unread_message_read before update of " + + MessageColumns.FLAG_READ + " on " + Message.TABLE_NAME + + " when OLD." + MessageColumns.FLAG_READ + "!=NEW." + MessageColumns.FLAG_READ + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT + + '=' + MailboxColumns.UNREAD_COUNT + "+ case OLD." + MessageColumns.FLAG_READ + + " when 0 then -1 else 1 end" + + " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Add triggers to update message count per mailbox + + // Insert a message. + db.execSQL("create trigger message_count_message_insert after insert on " + + Message.TABLE_NAME + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + + '=' + MailboxColumns.MESSAGE_COUNT + "+1" + + " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Delete a message; if flagRead is zero, decrement the unread count of the msg's mailbox + db.execSQL("create trigger message_count_message_delete after delete on " + + Message.TABLE_NAME + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + + '=' + MailboxColumns.MESSAGE_COUNT + "-1" + + " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + + "; end"); + + // Change a message's mailbox + db.execSQL("create trigger message_count_message_move after update of " + + MessageColumns.MAILBOX_KEY + " on " + Message.TABLE_NAME + + " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + + '=' + MailboxColumns.MESSAGE_COUNT + "-1" + + " where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY + + "; update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + + '=' + MailboxColumns.MESSAGE_COUNT + "+1" + + " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY + + "; end"); + } + + static void resetMessageTable(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + db.execSQL("drop table " + Message.TABLE_NAME); + db.execSQL("drop table " + Message.UPDATED_TABLE_NAME); + db.execSQL("drop table " + Message.DELETED_TABLE_NAME); + } catch (SQLException e) { + } + createMessageTable(db); + } + + @SuppressWarnings("deprecation") + static void createAccountTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + AccountColumns.DISPLAY_NAME + " text, " + + AccountColumns.EMAIL_ADDRESS + " text, " + + AccountColumns.SYNC_KEY + " text, " + + AccountColumns.SYNC_LOOKBACK + " integer, " + + AccountColumns.SYNC_INTERVAL + " text, " + + AccountColumns.HOST_AUTH_KEY_RECV + " integer, " + + AccountColumns.HOST_AUTH_KEY_SEND + " integer, " + + AccountColumns.FLAGS + " integer, " + + AccountColumns.IS_DEFAULT + " integer, " + + AccountColumns.COMPATIBILITY_UUID + " text, " + + AccountColumns.SENDER_NAME + " text, " + + AccountColumns.RINGTONE_URI + " text, " + + AccountColumns.PROTOCOL_VERSION + " text, " + + AccountColumns.NEW_MESSAGE_COUNT + " integer, " + + AccountColumns.SECURITY_FLAGS + " integer, " + + AccountColumns.SECURITY_SYNC_KEY + " text, " + + AccountColumns.SIGNATURE + " text, " + + AccountColumns.POLICY_KEY + " integer, " + + AccountColumns.NOTIFIED_MESSAGE_ID + " integer, " + + AccountColumns.NOTIFIED_MESSAGE_COUNT + " integer" + + ");"; + db.execSQL("create table " + Account.TABLE_NAME + s); + // Deleting an account deletes associated Mailboxes and HostAuth's + db.execSQL(TRIGGER_ACCOUNT_DELETE); + } + + static void resetAccountTable(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + db.execSQL("drop table " + Account.TABLE_NAME); + } catch (SQLException e) { + } + createAccountTable(db); + } + + static void createPolicyTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + PolicyColumns.PASSWORD_MODE + " integer, " + + PolicyColumns.PASSWORD_MIN_LENGTH + " integer, " + + PolicyColumns.PASSWORD_EXPIRATION_DAYS + " integer, " + + PolicyColumns.PASSWORD_HISTORY + " integer, " + + PolicyColumns.PASSWORD_COMPLEX_CHARS + " integer, " + + PolicyColumns.PASSWORD_MAX_FAILS + " integer, " + + PolicyColumns.MAX_SCREEN_LOCK_TIME + " integer, " + + PolicyColumns.REQUIRE_REMOTE_WIPE + " integer, " + + PolicyColumns.REQUIRE_ENCRYPTION + " integer, " + + PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL + " integer, " + + PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING + " integer, " + + PolicyColumns.DONT_ALLOW_CAMERA + " integer, " + + PolicyColumns.DONT_ALLOW_ATTACHMENTS + " integer, " + + PolicyColumns.DONT_ALLOW_HTML + " integer, " + + PolicyColumns.MAX_ATTACHMENT_SIZE + " integer, " + + PolicyColumns.MAX_TEXT_TRUNCATION_SIZE + " integer, " + + PolicyColumns.MAX_HTML_TRUNCATION_SIZE + " integer, " + + PolicyColumns.MAX_EMAIL_LOOKBACK + " integer, " + + PolicyColumns.MAX_CALENDAR_LOOKBACK + " integer, " + + PolicyColumns.PASSWORD_RECOVERY_ENABLED + " integer" + + ");"; + db.execSQL("create table " + Policy.TABLE_NAME + s); + } + + static void createHostAuthTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + HostAuthColumns.PROTOCOL + " text, " + + HostAuthColumns.ADDRESS + " text, " + + HostAuthColumns.PORT + " integer, " + + HostAuthColumns.FLAGS + " integer, " + + HostAuthColumns.LOGIN + " text, " + + HostAuthColumns.PASSWORD + " text, " + + HostAuthColumns.DOMAIN + " text, " + + HostAuthColumns.ACCOUNT_KEY + " integer," + + HostAuthColumns.CLIENT_CERT_ALIAS + " text" + + ");"; + db.execSQL("create table " + HostAuth.TABLE_NAME + s); + } + + static void resetHostAuthTable(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + db.execSQL("drop table " + HostAuth.TABLE_NAME); + } catch (SQLException e) { + } + createHostAuthTable(db); + } + + static void createMailboxTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + MailboxColumns.DISPLAY_NAME + " text, " + + MailboxColumns.SERVER_ID + " text, " + + MailboxColumns.PARENT_SERVER_ID + " text, " + + MailboxColumns.PARENT_KEY + " integer, " + + MailboxColumns.ACCOUNT_KEY + " integer, " + + MailboxColumns.TYPE + " integer, " + + MailboxColumns.DELIMITER + " integer, " + + MailboxColumns.SYNC_KEY + " text, " + + MailboxColumns.SYNC_LOOKBACK + " integer, " + + MailboxColumns.SYNC_INTERVAL + " integer, " + + MailboxColumns.SYNC_TIME + " integer, " + + MailboxColumns.UNREAD_COUNT + " integer, " + + MailboxColumns.FLAG_VISIBLE + " integer, " + + MailboxColumns.FLAGS + " integer, " + + MailboxColumns.VISIBLE_LIMIT + " integer, " + + MailboxColumns.SYNC_STATUS + " text, " + + MailboxColumns.MESSAGE_COUNT + " integer not null default 0, " + + MailboxColumns.LAST_SEEN_MESSAGE_KEY + " integer, " + + MailboxColumns.LAST_TOUCHED_TIME + " integer default 0" + + ");"; + db.execSQL("create table " + Mailbox.TABLE_NAME + s); + db.execSQL("create index mailbox_" + MailboxColumns.SERVER_ID + + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.SERVER_ID + ")"); + db.execSQL("create index mailbox_" + MailboxColumns.ACCOUNT_KEY + + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.ACCOUNT_KEY + ")"); + // Deleting a Mailbox deletes associated Messages in all three tables + db.execSQL(TRIGGER_MAILBOX_DELETE); + } + + static void resetMailboxTable(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + db.execSQL("drop table " + Mailbox.TABLE_NAME); + } catch (SQLException e) { + } + createMailboxTable(db); + } + + static void createAttachmentTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + AttachmentColumns.FILENAME + " text, " + + AttachmentColumns.MIME_TYPE + " text, " + + AttachmentColumns.SIZE + " integer, " + + AttachmentColumns.CONTENT_ID + " text, " + + AttachmentColumns.CONTENT_URI + " text, " + + AttachmentColumns.MESSAGE_KEY + " integer, " + + AttachmentColumns.LOCATION + " text, " + + AttachmentColumns.ENCODING + " text, " + + AttachmentColumns.CONTENT + " text, " + + AttachmentColumns.FLAGS + " integer, " + + AttachmentColumns.CONTENT_BYTES + " blob, " + + AttachmentColumns.ACCOUNT_KEY + " integer" + + ");"; + db.execSQL("create table " + Attachment.TABLE_NAME + s); + db.execSQL(createIndex(Attachment.TABLE_NAME, AttachmentColumns.MESSAGE_KEY)); + } + + static void resetAttachmentTable(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + db.execSQL("drop table " + Attachment.TABLE_NAME); + } catch (SQLException e) { + } + createAttachmentTable(db); + } - public static Uri uiUri(String type, long id) { - return Uri.parse(uiUriString(type, id)); + static void createQuickResponseTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + QuickResponseColumns.TEXT + " text, " + + QuickResponseColumns.ACCOUNT_KEY + " integer" + + ");"; + db.execSQL("create table " + QuickResponse.TABLE_NAME + s); } - public static String uiUriString(String type, long id) { - return "content://" + EmailContent.AUTHORITY + "/" + type + ((id == -1) ? "" : ("/" + id)); + static void createBodyTable(SQLiteDatabase db) { + String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " + + BodyColumns.MESSAGE_KEY + " integer, " + + BodyColumns.HTML_CONTENT + " text, " + + BodyColumns.TEXT_CONTENT + " text, " + + BodyColumns.HTML_REPLY + " text, " + + BodyColumns.TEXT_REPLY + " text, " + + BodyColumns.SOURCE_MESSAGE_KEY + " text, " + + BodyColumns.INTRO_TEXT + " text" + + ");"; + db.execSQL("create table " + Body.TABLE_NAME + s); + db.execSQL(createIndex(Body.TABLE_NAME, BodyColumns.MESSAGE_KEY)); } + static void upgradeBodyTable(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion < 5) { + try { + db.execSQL("drop table " + Body.TABLE_NAME); + createBodyTable(db); + } catch (SQLException e) { + } + } else if (oldVersion == 5) { + try { + db.execSQL("alter table " + Body.TABLE_NAME + + " add " + BodyColumns.INTRO_TEXT + " text"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProviderBody.db from v5 to v6", e); + } + oldVersion = 6; + } + } + + private SQLiteDatabase mDatabase; + private SQLiteDatabase mBodyDatabase; + /** * Orphan record deletion utility. Generates a sqlite statement like: * delete from <table> where <column> not in (select <foreignColumn> from <foreignTable>) @@ -490,12 +828,13 @@ public class EmailProvider extends ContentProvider { // to corruption checkDatabases(); - DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, DATABASE_NAME); + DatabaseHelper helper = new DatabaseHelper(context, DATABASE_NAME); mDatabase = helper.getWritableDatabase(); - DBHelper.BodyDatabaseHelper bodyHelper = - new DBHelper.BodyDatabaseHelper(context, BODY_DATABASE_NAME); + mDatabase.setLockingEnabled(true); + BodyDatabaseHelper bodyHelper = new BodyDatabaseHelper(context, BODY_DATABASE_NAME); mBodyDatabase = bodyHelper.getWritableDatabase(); if (mBodyDatabase != null) { + mBodyDatabase.setLockingEnabled(true); String bodyFileName = mBodyDatabase.getPath(); mDatabase.execSQL("attach \"" + bodyFileName + "\" as BodyDatabase"); } @@ -614,7 +953,7 @@ public class EmailProvider extends ContentProvider { } /*package*/ static SQLiteDatabase getReadableDatabase(Context context) { - DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, DATABASE_NAME); + DatabaseHelper helper = new DatabaseHelper(context, DATABASE_NAME); return helper.getReadableDatabase(); } @@ -710,6 +1049,318 @@ public class EmailProvider extends ContentProvider { } } + private class BodyDatabaseHelper extends SQLiteOpenHelper { + BodyDatabaseHelper(Context context, String name) { + super(context, name, null, BODY_DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.d(TAG, "Creating EmailProviderBody database"); + createBodyTable(db); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + upgradeBodyTable(db, oldVersion, newVersion); + } + + @Override + public void onOpen(SQLiteDatabase db) { + } + } + + private static class DatabaseHelper extends SQLiteOpenHelper { + Context mContext; + + DatabaseHelper(Context context, String name) { + super(context, name, null, DATABASE_VERSION); + mContext = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.d(TAG, "Creating EmailProvider database"); + // Create all tables here; each class has its own method + createMessageTable(db); + createAttachmentTable(db); + createMailboxTable(db); + createHostAuthTable(db); + createAccountTable(db); + createPolicyTable(db); + createQuickResponseTable(db); + } + + @Override + @SuppressWarnings("deprecation") + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // For versions prior to 5, delete all data + // Versions >= 5 require that data be preserved! + if (oldVersion < 5) { + android.accounts.Account[] accounts = AccountManager.get(mContext) + .getAccountsByType(AccountManagerTypes.TYPE_EXCHANGE); + for (android.accounts.Account account: accounts) { + AccountManager.get(mContext).removeAccount(account, null, null); + } + resetMessageTable(db, oldVersion, newVersion); + resetAttachmentTable(db, oldVersion, newVersion); + resetMailboxTable(db, oldVersion, newVersion); + resetHostAuthTable(db, oldVersion, newVersion); + resetAccountTable(db, oldVersion, newVersion); + return; + } + if (oldVersion == 5) { + // Message Tables: Add SyncColumns.SERVER_TIMESTAMP + try { + db.execSQL("alter table " + Message.TABLE_NAME + + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); + db.execSQL("alter table " + Message.UPDATED_TABLE_NAME + + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); + db.execSQL("alter table " + Message.DELETED_TABLE_NAME + + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from v5 to v6", e); + } + oldVersion = 6; + } + if (oldVersion == 6) { + // Use the newer mailbox_delete trigger + db.execSQL("drop trigger mailbox_delete;"); + db.execSQL(TRIGGER_MAILBOX_DELETE); + oldVersion = 7; + } + if (oldVersion == 7) { + // add the security (provisioning) column + try { + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + AccountColumns.SECURITY_FLAGS + " integer" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 7 to 8 " + e); + } + oldVersion = 8; + } + if (oldVersion == 8) { + // accounts: add security sync key & user signature columns + try { + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + AccountColumns.SECURITY_SYNC_KEY + " text" + ";"); + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + AccountColumns.SIGNATURE + " text" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 8 to 9 " + e); + } + oldVersion = 9; + } + if (oldVersion == 9) { + // Message: add meeting info column into Message tables + try { + db.execSQL("alter table " + Message.TABLE_NAME + + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); + db.execSQL("alter table " + Message.UPDATED_TABLE_NAME + + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); + db.execSQL("alter table " + Message.DELETED_TABLE_NAME + + " add column " + MessageColumns.MEETING_INFO + " text" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 9 to 10 " + e); + } + oldVersion = 10; + } + if (oldVersion == 10) { + // Attachment: add content and flags columns + try { + db.execSQL("alter table " + Attachment.TABLE_NAME + + " add column " + AttachmentColumns.CONTENT + " text" + ";"); + db.execSQL("alter table " + Attachment.TABLE_NAME + + " add column " + AttachmentColumns.FLAGS + " integer" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 10 to 11 " + e); + } + oldVersion = 11; + } + if (oldVersion == 11) { + // Attachment: add content_bytes + try { + db.execSQL("alter table " + Attachment.TABLE_NAME + + " add column " + AttachmentColumns.CONTENT_BYTES + " blob" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 11 to 12 " + e); + } + oldVersion = 12; + } + if (oldVersion == 12) { + try { + db.execSQL("alter table " + Mailbox.TABLE_NAME + + " add column " + Mailbox.MESSAGE_COUNT + +" integer not null default 0" + ";"); + recalculateMessageCount(db); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 12 to 13 " + e); + } + oldVersion = 13; + } + if (oldVersion == 13) { + try { + db.execSQL("alter table " + Message.TABLE_NAME + + " add column " + Message.SNIPPET + +" text" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 13 to 14 " + e); + } + oldVersion = 14; + } + if (oldVersion == 14) { + try { + db.execSQL("alter table " + Message.DELETED_TABLE_NAME + + " add column " + Message.SNIPPET +" text" + ";"); + db.execSQL("alter table " + Message.UPDATED_TABLE_NAME + + " add column " + Message.SNIPPET +" text" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 14 to 15 " + e); + } + oldVersion = 15; + } + if (oldVersion == 15) { + try { + db.execSQL("alter table " + Attachment.TABLE_NAME + + " add column " + Attachment.ACCOUNT_KEY +" integer" + ";"); + // Update all existing attachments to add the accountKey data + db.execSQL("update " + Attachment.TABLE_NAME + " set " + + Attachment.ACCOUNT_KEY + "= (SELECT " + Message.TABLE_NAME + "." + + Message.ACCOUNT_KEY + " from " + Message.TABLE_NAME + " where " + + Message.TABLE_NAME + "." + Message.RECORD_ID + " = " + + Attachment.TABLE_NAME + "." + Attachment.MESSAGE_KEY + ")"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 15 to 16 " + e); + } + oldVersion = 16; + } + if (oldVersion == 16) { + try { + db.execSQL("alter table " + Mailbox.TABLE_NAME + + " add column " + Mailbox.PARENT_KEY + " integer;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 16 to 17 " + e); + } + oldVersion = 17; + } + if (oldVersion == 17) { + upgradeFromVersion17ToVersion18(db); + oldVersion = 18; + } + if (oldVersion == 18) { + try { + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + Account.POLICY_KEY + " integer;"); + db.execSQL("drop trigger account_delete;"); + db.execSQL(TRIGGER_ACCOUNT_DELETE); + createPolicyTable(db); + convertPolicyFlagsToPolicyTable(db); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 18 to 19 " + e); + } + oldVersion = 19; + } + if (oldVersion == 19) { + try { + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING + + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.DONT_ALLOW_CAMERA + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.DONT_ALLOW_ATTACHMENTS + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.DONT_ALLOW_HTML + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.MAX_ATTACHMENT_SIZE + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.MAX_TEXT_TRUNCATION_SIZE + + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.MAX_HTML_TRUNCATION_SIZE + + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.MAX_EMAIL_LOOKBACK + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.MAX_CALENDAR_LOOKBACK + " integer;"); + db.execSQL("alter table " + Policy.TABLE_NAME + + " add column " + PolicyColumns.PASSWORD_RECOVERY_ENABLED + + " integer;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 19 to 20 " + e); + } + oldVersion = 20; + } + if (oldVersion == 20) { + upgradeFromVersion20ToVersion21(db); + oldVersion = 21; + } + if (oldVersion == 21) { + upgradeFromVersion21ToVersion22(db, mContext); + oldVersion = 22; + } + if (oldVersion == 22) { + upgradeFromVersion22ToVersion23(db); + oldVersion = 23; + } + if (oldVersion == 23) { + upgradeFromVersion23ToVersion24(db); + oldVersion = 24; + } + if (oldVersion == 24) { + upgradeFromVersion24ToVersion25(db); + oldVersion = 25; + } + if (oldVersion == 25) { + upgradeFromVersion25ToVersion26(db); + oldVersion = 26; + } + if (oldVersion == 26) { + try { + db.execSQL("alter table " + Message.TABLE_NAME + + " add column " + Message.PROTOCOL_SEARCH_INFO + " text;"); + db.execSQL("alter table " + Message.DELETED_TABLE_NAME + + " add column " + Message.PROTOCOL_SEARCH_INFO +" text" + ";"); + db.execSQL("alter table " + Message.UPDATED_TABLE_NAME + + " add column " + Message.PROTOCOL_SEARCH_INFO +" text" + ";"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 26 to 27 " + e); + } + oldVersion = 27; + } + if (oldVersion == 27) { + try { + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + Account.NOTIFIED_MESSAGE_ID + " integer;"); + db.execSQL("alter table " + Account.TABLE_NAME + + " add column " + Account.NOTIFIED_MESSAGE_COUNT + " integer;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 27 to 27 " + e); + } + oldVersion = 28; + } + } + + @Override + public void onOpen(SQLiteDatabase db) { + } + } + @Override public int delete(Uri uri, String selection, String[] selectionArgs) { final int match = findMatch(uri, "delete"); @@ -729,18 +1380,7 @@ public class EmailProvider extends ContentProvider { int result = -1; try { - if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { - if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { - notifyUIConversation(uri); - } - } switch (match) { - case UI_MESSAGE: - return uiDeleteMessage(uri); - case UI_ACCOUNT_DATA: - return uiDeleteAccountData(uri); - case UI_ACCOUNT: - return uiDeleteAccount(uri); // These are cases in which one or more Messages might get deleted, either by // cascade or explicitly case MAILBOX_ID: @@ -938,19 +1578,6 @@ public class EmailProvider extends ContentProvider { } } - private static final Uri UIPROVIDER_CONVERSATION_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uimessages"); - private static final Uri UIPROVIDER_MAILBOX_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uifolder"); - private static final Uri UIPROVIDER_ACCOUNT_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uiaccount"); - private static final Uri UIPROVIDER_SETTINGS_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uisettings"); - private static final Uri UIPROVIDER_ATTACHMENT_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachment"); - private static final Uri UIPROVIDER_ATTACHMENTS_NOTIFIER = - Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachments"); - @Override public Uri insert(Uri uri, ContentValues values) { int match = findMatch(uri, "insert"); @@ -989,11 +1616,6 @@ public class EmailProvider extends ContentProvider { longId = db.insert(TABLE_NAMES[table], "foo", values); resultUri = ContentUris.withAppendedId(uri, longId); switch(match) { - case MESSAGE: - if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { - notifyUIConversationMailbox(values.getAsLong(Message.MAILBOX_KEY)); - } - break; case MAILBOX: if (values.containsKey(MailboxColumns.TYPE)) { // Only cache special mailbox types @@ -1107,6 +1729,7 @@ public class EmailProvider extends ContentProvider { bodyFile.delete(); } } + @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { @@ -1160,41 +1783,6 @@ public class EmailProvider extends ContentProvider { try { switch (match) { - // First, dispatch queries from UnfiedEmail - case UI_SEARCH: - return uiSearch(uri, projection); - case UI_ACCTS: - c = uiAccounts(projection); - return c; - case UI_UNDO: - return uiUndo(uri, projection); - case UI_SUBFOLDERS: - case UI_FOLDERS: - case UI_MESSAGES: - case UI_MESSAGE: - case UI_FOLDER: - case UI_ACCOUNT: - case UI_SETTINGS: - case UI_ATTACHMENT: - case UI_ATTACHMENTS: - // For now, we don't allow selection criteria within these queries - if (selection != null || selectionArgs != null) { - throw new IllegalArgumentException("UI queries can't have selection/args"); - } - c = uiQuery(match, uri, projection); - return c; - case UI_FOLDER_LOAD_MORE: - c = uiFolderLoadMore(uri); - return c; - case UI_FOLDER_REFRESH: - c = uiFolderRefresh(uri); - return c; - case MAILBOX_NOTIFICATION: - c = notificationQuery(uri); - return c; - case MAILBOX_MOST_RECENT_MESSAGE: - c = mostRecentMessageQuery(uri); - return c; case ACCOUNT_DEFAULT_ID: // Start with a snapshot of the cache Map<String, Cursor> accountCache = mCacheAccount.getSnapshot(); @@ -1454,7 +2042,7 @@ public class EmailProvider extends ContentProvider { } private static SQLiteDatabase getBackupDatabase(Context context) { - DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, BACKUP_DATABASE_NAME); + DatabaseHelper helper = new DatabaseHelper(context, BACKUP_DATABASE_NAME); return helper.getWritableDatabase(); } @@ -1539,17 +2127,8 @@ public class EmailProvider extends ContentProvider { String id = "0"; try { - if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { - if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { - notifyUIConversation(uri); - } - } outer: switch (match) { - case UI_ATTACHMENT: - return uiUpdateAttachment(uri, values); - case UI_MESSAGE: - return uiUpdateMessage(uri, values); case MAILBOX_ID_ADD_TO_FIELD: case ACCOUNT_ID_ADD_TO_FIELD: id = uri.getPathSegments().get(1); @@ -1627,30 +2206,11 @@ outer: } } if (match == ATTACHMENT_ID) { - long attId = Integer.parseInt(id); if (values.containsKey(Attachment.FLAGS)) { int flags = values.getAsInteger(Attachment.FLAGS); - mAttachmentService.attachmentChanged(context, attId, flags); - } - // Notify UI if necessary; there are only two columns we can change that - // would be worth a notification - if (values.containsKey(AttachmentColumns.UI_STATE) || - values.containsKey(AttachmentColumns.UI_DOWNLOADED_SIZE)) { - // Notify on individual attachment - notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); - Attachment att = Attachment.restoreAttachmentWithId(context, attId); - if (att != null) { - // And on owning Message - notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey); - } + mAttachmentService.attachmentChanged(getContext(), + Integer.parseInt(id), flags); } - } else if (match == MAILBOX_ID && values.containsKey(Mailbox.UI_SYNC_STATUS)) { - notifyUI(UIPROVIDER_MAILBOX_NOTIFIER, id); - // TODO: Remove logging - Log.d(TAG, "Notifying mailbox " + id + " status: " + - values.getAsInteger(Mailbox.UI_SYNC_STATUS)); - } else if (match == ACCOUNT_ID) { - notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); } break; case BODY: @@ -1825,1134 +2385,284 @@ outer: } } - /** - * For testing purposes, check whether a given row is cached - * @param baseUri the base uri of the EmailContent - * @param id the row id of the EmailContent - * @return whether or not the row is currently cached - */ + /** Counts the number of messages in each mailbox, and updates the message count column. */ @VisibleForTesting - protected boolean isCached(Uri baseUri, long id) { - int match = findMatch(baseUri, "isCached"); - int table = match >> BASE_SHIFT; - ContentCache cache = mContentCaches[table]; - if (cache == null) return false; - Cursor cc = cache.get(Long.toString(id)); - return (cc != null); + static void recalculateMessageCount(SQLiteDatabase db) { + db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.MESSAGE_COUNT + + "= (select count(*) from " + Message.TABLE_NAME + + " where " + Message.MAILBOX_KEY + " = " + + Mailbox.TABLE_NAME + "." + EmailContent.RECORD_ID + ")"); } - public static interface AttachmentService { - /** - * Notify the service that an attachment has changed. - */ - void attachmentChanged(Context context, long id, int flags); - } - - private final AttachmentService DEFAULT_ATTACHMENT_SERVICE = new AttachmentService() { - @Override - public void attachmentChanged(Context context, long id, int flags) { - // The default implementation delegates to the real service. - AttachmentDownloadService.attachmentChanged(context, id, flags); + @VisibleForTesting + @SuppressWarnings("deprecation") + static void convertPolicyFlagsToPolicyTable(SQLiteDatabase db) { + Cursor c = db.query(Account.TABLE_NAME, + new String[] {EmailContent.RECORD_ID /*0*/, AccountColumns.SECURITY_FLAGS /*1*/}, + AccountColumns.SECURITY_FLAGS + ">0", null, null, null, null); + ContentValues cv = new ContentValues(); + String[] args = new String[1]; + while (c.moveToNext()) { + long securityFlags = c.getLong(1 /*SECURITY_FLAGS*/); + Policy policy = LegacyPolicySet.flagsToPolicy(securityFlags); + long policyId = db.insert(Policy.TABLE_NAME, null, policy.toContentValues()); + cv.put(AccountColumns.POLICY_KEY, policyId); + cv.putNull(AccountColumns.SECURITY_FLAGS); + args[0] = Long.toString(c.getLong(0 /*RECORD_ID*/)); + db.update(Account.TABLE_NAME, cv, EmailContent.RECORD_ID + "=?", args); } - }; - private AttachmentService mAttachmentService = DEFAULT_ATTACHMENT_SERVICE; - - /** - * Injects a custom attachment service handler. If null is specified, will reset to the - * default service. - */ - public void injectAttachmentService(AttachmentService as) { - mAttachmentService = (as == null) ? DEFAULT_ATTACHMENT_SERVICE : as; } - // SELECT DISTINCT Boxes._id, Boxes.unreadCount count(Message._id) from Message, - // (SELECT _id, unreadCount, messageCount, lastNotifiedMessageCount, lastNotifiedMessageKey - // FROM Mailbox WHERE accountKey=6 AND ((type = 0) OR (syncInterval!=0 AND syncInterval!=-1))) - // AS Boxes - // WHERE Boxes.messageCount!=Boxes.lastNotifiedMessageCount - // OR (Boxes._id=Message.mailboxKey AND Message._id>Boxes.lastNotifiedMessageKey) - // TODO: This query can be simplified a bit - private static final String NOTIFICATION_QUERY = - "SELECT DISTINCT Boxes." + MailboxColumns.ID + ", Boxes." + MailboxColumns.UNREAD_COUNT + - ", count(" + Message.TABLE_NAME + "." + MessageColumns.ID + ")" + - " FROM " + - Message.TABLE_NAME + "," + - "(SELECT " + MailboxColumns.ID + "," + MailboxColumns.UNREAD_COUNT + "," + - MailboxColumns.MESSAGE_COUNT + "," + MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT + - "," + MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY + " FROM " + Mailbox.TABLE_NAME + - " WHERE " + MailboxColumns.ACCOUNT_KEY + "=?" + - " AND (" + MailboxColumns.TYPE + "=" + Mailbox.TYPE_INBOX + " OR (" - + MailboxColumns.SYNC_INTERVAL + "!=0 AND " + - MailboxColumns.SYNC_INTERVAL + "!=-1))) AS Boxes " + - "WHERE Boxes." + MailboxColumns.ID + '=' + Message.TABLE_NAME + "." + - MessageColumns.MAILBOX_KEY + " AND " + Message.TABLE_NAME + "." + - MessageColumns.ID + ">Boxes." + MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY + - " AND " + MessageColumns.FLAG_READ + "=0"; - - public Cursor notificationQuery(Uri uri) { - SQLiteDatabase db = getDatabase(getContext()); - String accountId = uri.getLastPathSegment(); - return db.rawQuery(NOTIFICATION_QUERY, new String[] {accountId}); - } - - public Cursor mostRecentMessageQuery(Uri uri) { - SQLiteDatabase db = getDatabase(getContext()); - String mailboxId = uri.getLastPathSegment(); - return db.rawQuery("select max(_id) from Message where mailboxKey=?", - new String[] {mailboxId}); - } - - /** - * Support for UnifiedEmail below - */ - - private static final String NOT_A_DRAFT_STRING = - Integer.toString(UIProvider.DraftType.NOT_A_DRAFT); - - /** - * Mapping of UIProvider columns to EmailProvider columns for the message list (called the - * conversation list in UnifiedEmail) - */ - private static final ProjectionMap sMessageListMap = ProjectionMap.builder() - .add(BaseColumns._ID, MessageColumns.ID) - .add(UIProvider.ConversationColumns.URI, uriWithId("uimessage")) - .add(UIProvider.ConversationColumns.MESSAGE_LIST_URI, uriWithId("uimessage")) - .add(UIProvider.ConversationColumns.SUBJECT, MessageColumns.SUBJECT) - .add(UIProvider.ConversationColumns.SNIPPET, MessageColumns.SNIPPET) - .add(UIProvider.ConversationColumns.SENDER_INFO, MessageColumns.FROM_LIST) - .add(UIProvider.ConversationColumns.DATE_RECEIVED_MS, MessageColumns.TIMESTAMP) - .add(UIProvider.ConversationColumns.HAS_ATTACHMENTS, MessageColumns.FLAG_ATTACHMENT) - .add(UIProvider.ConversationColumns.NUM_MESSAGES, "1") - .add(UIProvider.ConversationColumns.NUM_DRAFTS, "0") - .add(UIProvider.ConversationColumns.SENDING_STATE, - Integer.toString(ConversationSendingState.OTHER)) - .add(UIProvider.ConversationColumns.PRIORITY, Integer.toString(ConversationPriority.LOW)) - .add(UIProvider.ConversationColumns.READ, MessageColumns.FLAG_READ) - .add(UIProvider.ConversationColumns.STARRED, MessageColumns.FLAG_FAVORITE) - .add(UIProvider.ConversationColumns.FOLDER_LIST, - "'content://" + EmailContent.AUTHORITY + "/uifolder/' || " - + MessageColumns.MAILBOX_KEY) - .build(); - - /** - * Mapping of UIProvider columns to EmailProvider columns for a detailed message view in - * UnifiedEmail - */ - private static final ProjectionMap sMessageViewMap = ProjectionMap.builder() - .add(BaseColumns._ID, Message.TABLE_NAME + "." + EmailContent.MessageColumns.ID) - .add(UIProvider.MessageColumns.SERVER_ID, SyncColumns.SERVER_ID) - .add(UIProvider.MessageColumns.URI, uriWithFQId("uimessage", Message.TABLE_NAME)) - .add(UIProvider.MessageColumns.CONVERSATION_ID, - uriWithFQId("uimessage", Message.TABLE_NAME)) - .add(UIProvider.MessageColumns.SUBJECT, EmailContent.MessageColumns.SUBJECT) - .add(UIProvider.MessageColumns.SNIPPET, EmailContent.MessageColumns.SNIPPET) - .add(UIProvider.MessageColumns.FROM, EmailContent.MessageColumns.FROM_LIST) - .add(UIProvider.MessageColumns.TO, EmailContent.MessageColumns.TO_LIST) - .add(UIProvider.MessageColumns.CC, EmailContent.MessageColumns.CC_LIST) - .add(UIProvider.MessageColumns.BCC, EmailContent.MessageColumns.BCC_LIST) - .add(UIProvider.MessageColumns.REPLY_TO, EmailContent.MessageColumns.REPLY_TO_LIST) - .add(UIProvider.MessageColumns.DATE_RECEIVED_MS, EmailContent.MessageColumns.TIMESTAMP) - .add(UIProvider.MessageColumns.BODY_HTML, Body.HTML_CONTENT) - .add(UIProvider.MessageColumns.BODY_TEXT, Body.TEXT_CONTENT) - .add(UIProvider.MessageColumns.EMBEDS_EXTERNAL_RESOURCES, "0") - .add(UIProvider.MessageColumns.REF_MESSAGE_ID, "0") - .add(UIProvider.MessageColumns.DRAFT_TYPE, NOT_A_DRAFT_STRING) - .add(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT, "0") - .add(UIProvider.MessageColumns.HAS_ATTACHMENTS, EmailContent.MessageColumns.FLAG_ATTACHMENT) - .add(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, - uriWithFQId("uiattachments", Message.TABLE_NAME)) - .add(UIProvider.MessageColumns.MESSAGE_FLAGS, "0") - .add(UIProvider.MessageColumns.SAVE_MESSAGE_URI, - uriWithFQId("uiupdatedraft", Message.TABLE_NAME)) - .add(UIProvider.MessageColumns.SEND_MESSAGE_URI, - uriWithFQId("uisenddraft", Message.TABLE_NAME)) - // TODO(pwestbro): make this actually return valid results. - .add(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES, "0") - .build(); - - /** - * Mapping of UIProvider columns to EmailProvider columns for the folder list in UnifiedEmail - */ - private static String getFolderCapabilities() { - return "CASE WHEN (" + MailboxColumns.FLAGS + "&" + Mailbox.FLAG_ACCEPTS_MOVED_MAIL + - ") !=0 THEN " + UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES + - " ELSE 0 END"; - } - - private static final ProjectionMap sFolderListMap = ProjectionMap.builder() - .add(BaseColumns._ID, MailboxColumns.ID) - .add(UIProvider.FolderColumns.URI, uriWithId("uifolder")) - .add(UIProvider.FolderColumns.NAME, "displayName") - .add(UIProvider.FolderColumns.HAS_CHILDREN, - MailboxColumns.FLAGS + "&" + Mailbox.FLAG_HAS_CHILDREN) - .add(UIProvider.FolderColumns.CAPABILITIES, getFolderCapabilities()) - .add(UIProvider.FolderColumns.SYNC_WINDOW, "3") - .add(UIProvider.FolderColumns.CONVERSATION_LIST_URI, uriWithId("uimessages")) - .add(UIProvider.FolderColumns.CHILD_FOLDERS_LIST_URI, uriWithId("uisubfolders")) - .add(UIProvider.FolderColumns.UNREAD_COUNT, MailboxColumns.UNREAD_COUNT) - .add(UIProvider.FolderColumns.TOTAL_COUNT, MailboxColumns.MESSAGE_COUNT) - .add(UIProvider.FolderColumns.REFRESH_URI, uriWithId("uirefresh")) - .add(UIProvider.FolderColumns.SYNC_STATUS, MailboxColumns.UI_SYNC_STATUS) - .add(UIProvider.FolderColumns.LAST_SYNC_RESULT, MailboxColumns.UI_LAST_SYNC_RESULT) - .add(UIProvider.FolderColumns.TOTAL_COUNT, MailboxColumns.TOTAL_COUNT) - .build(); - - private static final ProjectionMap sAccountListMap = ProjectionMap.builder() - .add(BaseColumns._ID, AccountColumns.ID) - .add(UIProvider.AccountColumns.FOLDER_LIST_URI, uriWithId("uifolders")) - .add(UIProvider.AccountColumns.NAME, AccountColumns.DISPLAY_NAME) - .add(UIProvider.AccountColumns.SAVE_DRAFT_URI, uriWithId("uisavedraft")) - .add(UIProvider.AccountColumns.SEND_MAIL_URI, uriWithId("uisendmail")) - .add(UIProvider.AccountColumns.UNDO_URI, uriWithId("uiundo")) - .add(UIProvider.AccountColumns.URI, uriWithId("uiaccount")) - .add(UIProvider.AccountColumns.SEARCH_URI, uriWithId("uisearch")) - // TODO: Is this used? - .add(UIProvider.AccountColumns.PROVIDER_VERSION, "1") - .add(UIProvider.AccountColumns.SYNC_STATUS, "0") - .build(); - - /** - * The "ORDER BY" clause for top level folders - */ - private static final String MAILBOX_ORDER_BY = "CASE " + MailboxColumns.TYPE - + " WHEN " + Mailbox.TYPE_INBOX + " THEN 0" - + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN 1" - + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN 2" - + " WHEN " + Mailbox.TYPE_SENT + " THEN 3" - + " WHEN " + Mailbox.TYPE_TRASH + " THEN 4" - + " WHEN " + Mailbox.TYPE_JUNK + " THEN 5" - // Other mailboxes (i.e. of Mailbox.TYPE_MAIL) are shown in alphabetical order. - + " ELSE 10 END" - + " ," + MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; - - - /** - * Mapping of UIProvider columns to EmailProvider columns for the message list (called the - * conversation list in UnifiedEmail) - */ - private static final ProjectionMap sAccountSettingsMap = ProjectionMap.builder() - .add(UIProvider.AccountColumns.SettingsColumns.SIGNATURE, AccountColumns.SIGNATURE) - .add(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE, - Integer.toString(UIProvider.AutoAdvance.OLDER)) - .add(UIProvider.AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE, - Integer.toString(UIProvider.MessageTextSize.NORMAL)) - .add(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS, - Integer.toString(UIProvider.SnapHeaderValue.ALWAYS)) - .add(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR, - Integer.toString(UIProvider.DefaultReplyBehavior.REPLY)) - .add(UIProvider.AccountColumns.SettingsColumns.HIDE_CHECKBOXES, "0") - .add(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE, "0") - .add(UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, "0") - .add(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND, "0") - .build(); - - /** - * Mapping of UIProvider columns to EmailProvider columns for a message's attachments - */ - private static final ProjectionMap sAttachmentMap = ProjectionMap.builder() - .add(UIProvider.AttachmentColumns.NAME, AttachmentColumns.FILENAME) - .add(UIProvider.AttachmentColumns.SIZE, AttachmentColumns.SIZE) - .add(UIProvider.AttachmentColumns.URI, uriWithId("uiattachment")) - .add(UIProvider.AttachmentColumns.CONTENT_TYPE, AttachmentColumns.MIME_TYPE) - .add(UIProvider.AttachmentColumns.STATE, AttachmentColumns.UI_STATE) - .add(UIProvider.AttachmentColumns.DESTINATION, AttachmentColumns.UI_DESTINATION) - .add(UIProvider.AttachmentColumns.DOWNLOADED_SIZE, AttachmentColumns.UI_DOWNLOADED_SIZE) - .add(UIProvider.AttachmentColumns.CONTENT_URI, AttachmentColumns.CONTENT_URI) - .build(); - - /** - * Generate the SELECT clause using a specified mapping and the original UI projection - * @param map the ProjectionMap to use for this projection - * @param projection the projection as sent by UnifiedEmail - * @param values ContentValues to be used if the ProjectionMap entry is null - * @return a StringBuilder containing the SELECT expression for a SQLite query - */ - private StringBuilder genSelect(ProjectionMap map, String[] projection) { - return genSelect(map, projection, EMPTY_CONTENT_VALUES); - } - - private StringBuilder genSelect(ProjectionMap map, String[] projection, ContentValues values) { - StringBuilder sb = new StringBuilder("SELECT "); - boolean first = true; - for (String column: projection) { - if (first) { - first = false; - } else { - sb.append(','); - } - String val = null; - // First look at values; this is an override of default behavior - if (values.containsKey(column)) { - val = "'" + values.getAsString(column) + "' AS " + column; - } else { - // Now, get the standard value for the column from our projection map - val = map.get(column); - // If we don't have the column, return "NULL AS <column>", and warn - if (val == null) { - Log.w(TAG, "UIProvider column not found, returning NULL: " + column); - val = "NULL AS " + column; - } - } - sb.append(val); + /** Upgrades the database from v17 to v18 */ + @VisibleForTesting + static void upgradeFromVersion17ToVersion18(SQLiteDatabase db) { + // Copy the displayName column to the serverId column. In v18 of the database, + // we use the serverId for IMAP/POP3 mailboxes instead of overloading the + // display name. + // + // For posterity; this is the command we're executing: + //sqlite> UPDATE mailbox SET serverid=displayname WHERE mailbox._id in ( + // ...> SELECT mailbox._id FROM mailbox,account,hostauth WHERE + // ...> (mailbox.parentkey isnull OR mailbox.parentkey=0) AND + // ...> mailbox.accountkey=account._id AND + // ...> account.hostauthkeyrecv=hostauth._id AND + // ...> (hostauth.protocol='imap' OR hostauth.protocol='pop3')); + try { + db.execSQL( + "UPDATE " + Mailbox.TABLE_NAME + " SET " + + MailboxColumns.SERVER_ID + "=" + MailboxColumns.DISPLAY_NAME + + " WHERE " + + Mailbox.TABLE_NAME + "." + MailboxColumns.ID + " IN ( SELECT " + + Mailbox.TABLE_NAME + "." + MailboxColumns.ID + " FROM " + + Mailbox.TABLE_NAME + "," + Account.TABLE_NAME + "," + + HostAuth.TABLE_NAME + " WHERE " + + "(" + + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_KEY + " isnull OR " + + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_KEY + "=0 " + + ") AND " + + Mailbox.TABLE_NAME + "." + MailboxColumns.ACCOUNT_KEY + "=" + + Account.TABLE_NAME + "." + AccountColumns.ID + " AND " + + Account.TABLE_NAME + "." + AccountColumns.HOST_AUTH_KEY_RECV + "=" + + HostAuth.TABLE_NAME + "." + HostAuthColumns.ID + " AND ( " + + HostAuth.TABLE_NAME + "." + HostAuthColumns.PROTOCOL + "='imap' OR " + + HostAuth.TABLE_NAME + "." + HostAuthColumns.PROTOCOL + "='pop3' ) )"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 17 to 18 " + e); + } + ContentCache.invalidateAllCaches(); + } + + /** Upgrades the database from v20 to v21 */ + private static void upgradeFromVersion20ToVersion21(SQLiteDatabase db) { + try { + db.execSQL("alter table " + Mailbox.TABLE_NAME + + " add column " + Mailbox.LAST_SEEN_MESSAGE_KEY + " integer;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 20 to 21 " + e); } - return sb; - } - - /** - * Convenience method to create a Uri string given the "type" of query; we append the type - * of the query and the id column name (_id) - * - * @param type the "type" of the query, as defined by our UriMatcher definitions - * @return a Uri string - */ - private static String uriWithId(String type) { - return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || _id"; } /** - * Convenience method to create a Uri string given the "type" of query and the table name to - * which it applies; we append the type of the query and the fully qualified (FQ) id column - * (i.e. including the table name); we need this for join queries where _id would otherwise - * be ambiguous - * - * @param type the "type" of the query, as defined by our UriMatcher definitions - * @param tableName the name of the table whose _id is referred to - * @return a Uri string + * Upgrade the database from v21 to v22 + * This entails creating AccountManager accounts for all pop3 and imap accounts */ - private static String uriWithFQId(String type, String tableName) { - return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || " + tableName + "._id"; - } - - /** - * Generate the "view message" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryViewMessage(String[] uiProjection, String id) { - Context context = getContext(); - long messageId = Long.parseLong(id); - Message msg = Message.restoreMessageWithId(context, messageId); - if (msg != null && (msg.mFlagLoaded == Message.FLAG_LOADED_PARTIAL)) { - EmailServiceProxy service = - EmailServiceUtils.getServiceForAccount(context, null, msg.mAccountKey); - try { - service.loadMore(messageId); - } catch (RemoteException e) { - // Nothing to do - } - } - StringBuilder sb = genSelect(sMessageViewMap, uiProjection); - sb.append(" FROM " + Message.TABLE_NAME + "," + Body.TABLE_NAME + " WHERE " + - Body.MESSAGE_KEY + "=" + Message.TABLE_NAME + "." + Message.RECORD_ID + " AND " + - Message.TABLE_NAME + "." + Message.RECORD_ID + "=?"); - return sb.toString(); - } - /** - * Generate the "message list" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryMailboxMessages(String[] uiProjection) { - StringBuilder sb = genSelect(sMessageListMap, uiProjection); - // Make constant - sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + Message.MAILBOX_KEY + "=? ORDER BY " + - MessageColumns.TIMESTAMP + " DESC"); - return sb.toString(); - } + private static final String[] V21_ACCOUNT_PROJECTION = + new String[] {AccountColumns.HOST_AUTH_KEY_RECV, AccountColumns.EMAIL_ADDRESS}; + private static final int V21_ACCOUNT_RECV = 0; + private static final int V21_ACCOUNT_EMAIL = 1; - /** - * Generate the "top level folder list" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryAccountMailboxes(String[] uiProjection) { - StringBuilder sb = genSelect(sFolderListMap, uiProjection); - // Make constant - sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + - "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + - " AND " + MailboxColumns.PARENT_KEY + " < 0 ORDER BY "); - sb.append(MAILBOX_ORDER_BY); - return sb.toString(); - } + private static final String[] V21_HOSTAUTH_PROJECTION = + new String[] {HostAuthColumns.PROTOCOL, HostAuthColumns.PASSWORD}; + private static final int V21_HOSTAUTH_PROTOCOL = 0; + private static final int V21_HOSTAUTH_PASSWORD = 1; - /** - * Generate a "single mailbox" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryMailbox(String[] uiProjection, String id) { - long mailboxId = Long.parseLong(id); - ContentValues values = EMPTY_CONTENT_VALUES; - if (mSearchParams != null && mailboxId == mSearchParams.mSearchMailboxId) { - // This is the current search mailbox; use the total count - values = new ContentValues(); - values.put(UIProvider.FolderColumns.TOTAL_COUNT, mSearchParams.mTotalCount); - // "load more" is valid for search results - values.put(UIProvider.FolderColumns.LOAD_MORE_URI, - uiUriString("uiloadmore", mailboxId)); - } else { - Context context = getContext(); - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); - String protocol = Account.getProtocol(context, mailbox.mAccountKey); - // "load more" is valid for IMAP/POP3 - if (HostAuth.SCHEME_IMAP.equals(protocol) || HostAuth.SCHEME_POP3.equals(protocol)) { - values.put(UIProvider.FolderColumns.LOAD_MORE_URI, - uiUriString("uiloadmore", mailboxId)); - } - } - StringBuilder sb = genSelect(sFolderListMap, uiProjection, values); - sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ID + "=?"); - return sb.toString(); + static private void createAccountManagerAccount(Context context, String login, + String password) { + AccountManager accountManager = AccountManager.get(context); + android.accounts.Account amAccount = + new android.accounts.Account(login, AccountManagerTypes.TYPE_POP_IMAP); + accountManager.addAccountExplicitly(amAccount, password, null); + ContentResolver.setIsSyncable(amAccount, EmailContent.AUTHORITY, 1); + ContentResolver.setSyncAutomatically(amAccount, EmailContent.AUTHORITY, true); + ContentResolver.setIsSyncable(amAccount, ContactsContract.AUTHORITY, 0); + ContentResolver.setIsSyncable(amAccount, CalendarProviderStub.AUTHORITY, 0); } - private static final long IMAP_CAPABILITIES = - AccountCapabilities.SYNCABLE_FOLDERS | - AccountCapabilities.FOLDER_SERVER_SEARCH | - AccountCapabilities.UNDO; - - private static final long POP3_CAPABILITIES = 0; - - private static final long EAS_12_CAPABILITIES = - AccountCapabilities.SYNCABLE_FOLDERS | - AccountCapabilities.FOLDER_SERVER_SEARCH | - AccountCapabilities.SANITIZED_HTML | - AccountCapabilities.SMART_REPLY | - AccountCapabilities.SERVER_SEARCH | - AccountCapabilities.UNDO; - - private static final long EAS_2_CAPABILITIES = - AccountCapabilities.SYNCABLE_FOLDERS | - AccountCapabilities.SANITIZED_HTML | - AccountCapabilities.SMART_REPLY | - AccountCapabilities.UNDO; - - private static final Uri BASE_EXTERNAL_URI = Uri.parse("content://ui.email.android.com"); - - private static final Uri BASE_EXTERAL_URI2 = Uri.parse("content://ui.email2.android.com"); - - private static String getExternalUriString(String segment, String account) { - return BASE_EXTERNAL_URI.buildUpon().appendPath(segment) - .appendQueryParameter("account", account).build().toString(); - } - - private static String getExternalUriStringEmail2(String segment, String account) { - return BASE_EXTERAL_URI2.buildUpon().appendPath(segment) - .appendQueryParameter("account", account).build().toString(); - } - - /** - * Generate a "single account" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - // TODO: Get protocol specific stuff out of here (it should be in the account) - private String genQueryAccount(String[] uiProjection, String id) { - ContentValues values = new ContentValues(); - long accountId = Long.parseLong(id); - String protocol = Account.getProtocol(getContext(), accountId); - if (HostAuth.SCHEME_IMAP.equals(protocol)) { - values.put(UIProvider.AccountColumns.CAPABILITIES, IMAP_CAPABILITIES); - } else if (HostAuth.SCHEME_POP3.equals(protocol)) { - values.put(UIProvider.AccountColumns.CAPABILITIES, POP3_CAPABILITIES); - } else { - Account account = Account.restoreAccountWithId(getContext(), accountId); - String easVersion = account.mProtocolVersion; - Double easVersionDouble = 2.5D; - if (easVersion != null) { - try { - easVersionDouble = Double.parseDouble(easVersion); - } catch (NumberFormatException e) { - // Stick with 2.5 - } - } - if (easVersionDouble >= 12.0D) { - values.put(UIProvider.AccountColumns.CAPABILITIES, EAS_12_CAPABILITIES); - } else { - values.put(UIProvider.AccountColumns.CAPABILITIES, EAS_2_CAPABILITIES); - } - } - values.put(UIProvider.AccountColumns.SETTINGS_INTENT_URI, - getExternalUriString("settings", id)); - values.put(UIProvider.AccountColumns.COMPOSE_URI, - getExternalUriStringEmail2("compose", id)); - values.put(UIProvider.AccountColumns.MIME_TYPE, "application/email-ls"); - StringBuilder sb = genSelect(sAccountListMap, uiProjection, values); - sb.append(" FROM " + Account.TABLE_NAME + " WHERE " + AccountColumns.ID + "=?"); - return sb.toString(); - } - - /** - * Generate an "account settings" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQuerySettings(String[] uiProjection, String id) { - ContentValues values = new ContentValues(); - long accountId = Long.parseLong(id); - long mailboxId = Mailbox.findMailboxOfType(getContext(), accountId, Mailbox.TYPE_INBOX); - if (mailboxId != Mailbox.NO_MAILBOX) { - values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX, - uiUriString("uifolder", mailboxId)); - } - StringBuilder sb = genSelect(sAccountSettingsMap, uiProjection, values); - sb.append(" FROM " + Account.TABLE_NAME + " WHERE " + AccountColumns.ID + "=?"); - return sb.toString(); - } - - private Cursor uiAccounts(String[] uiProjection) { - Context context = getContext(); - SQLiteDatabase db = getDatabase(context); - Cursor accountIdCursor = - db.rawQuery("select _id from " + Account.TABLE_NAME, new String[0]); - MatrixCursor mc = new MatrixCursor(uiProjection, accountIdCursor.getCount()); - Object[] values = new Object[uiProjection.length]; + @VisibleForTesting + static void upgradeFromVersion21ToVersion22(SQLiteDatabase db, Context accountManagerContext) { try { - while (accountIdCursor.moveToNext()) { - String id = accountIdCursor.getString(0); - Cursor accountCursor = - db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); - if (accountCursor.moveToNext()) { - for (int i = 0; i < uiProjection.length; i++) { - values[i] = accountCursor.getString(i); + // Loop through accounts, looking for pop/imap accounts + Cursor accountCursor = db.query(Account.TABLE_NAME, V21_ACCOUNT_PROJECTION, null, + null, null, null, null); + try { + String[] hostAuthArgs = new String[1]; + while (accountCursor.moveToNext()) { + hostAuthArgs[0] = accountCursor.getString(V21_ACCOUNT_RECV); + // Get the "receive" HostAuth for this account + Cursor hostAuthCursor = db.query(HostAuth.TABLE_NAME, + V21_HOSTAUTH_PROJECTION, HostAuth.RECORD_ID + "=?", hostAuthArgs, + null, null, null); + try { + if (hostAuthCursor.moveToFirst()) { + String protocol = hostAuthCursor.getString(V21_HOSTAUTH_PROTOCOL); + // If this is a pop3 or imap account, create the account manager account + if (HostAuth.SCHEME_IMAP.equals(protocol) || + HostAuth.SCHEME_POP3.equals(protocol)) { + if (Email.DEBUG) { + Log.d(TAG, "Create AccountManager account for " + protocol + + "account: " + + accountCursor.getString(V21_ACCOUNT_EMAIL)); + } + createAccountManagerAccount(accountManagerContext, + accountCursor.getString(V21_ACCOUNT_EMAIL), + hostAuthCursor.getString(V21_HOSTAUTH_PASSWORD)); + // If an EAS account, make Email sync automatically (equivalent of + // checking the "Sync Email" box in settings + } else if (HostAuth.SCHEME_EAS.equals(protocol)) { + android.accounts.Account amAccount = + new android.accounts.Account( + accountCursor.getString(V21_ACCOUNT_EMAIL), + AccountManagerTypes.TYPE_EXCHANGE); + ContentResolver.setIsSyncable(amAccount, EmailContent.AUTHORITY, 1); + ContentResolver.setSyncAutomatically(amAccount, + EmailContent.AUTHORITY, true); + + } + } + } finally { + hostAuthCursor.close(); } - mc.addRow(values); } + } finally { accountCursor.close(); } - } finally { - accountIdCursor.close(); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 20 to 21 " + e); } - return mc; - } - - /** - * Generate the "attachment list" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryAttachments(String[] uiProjection) { - StringBuilder sb = genSelect(sAttachmentMap, uiProjection); - sb.append(" FROM " + Attachment.TABLE_NAME + " WHERE " + AttachmentColumns.MESSAGE_KEY + - " =? "); - return sb.toString(); - } - - /** - * Generate the "single attachment" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQueryAttachment(String[] uiProjection) { - StringBuilder sb = genSelect(sAttachmentMap, uiProjection); - sb.append(" FROM " + Attachment.TABLE_NAME + " WHERE " + AttachmentColumns.ID + " =? "); - return sb.toString(); } - /** - * Generate the "subfolder list" SQLite query, given a projection from UnifiedEmail - * - * @param uiProjection as passed from UnifiedEmail - * @return the SQLite query to be executed on the EmailProvider database - */ - private String genQuerySubfolders(String[] uiProjection) { - StringBuilder sb = genSelect(sFolderListMap, uiProjection); - sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.PARENT_KEY + - " =? ORDER BY "); - sb.append(MAILBOX_ORDER_BY); - return sb.toString(); - } - - /** - * Handle UnifiedEmail queries here (dispatched from query()) - * - * @param match the UriMatcher match for the original uri passed in from UnifiedEmail - * @param uri the original uri passed in from UnifiedEmail - * @param uiProjection the projection passed in from UnifiedEmail - * @return the result Cursor - */ - private Cursor uiQuery(int match, Uri uri, String[] uiProjection) { - Context context = getContext(); - ContentResolver resolver = context.getContentResolver(); - SQLiteDatabase db = getDatabase(context); - // Should we ever return null, or throw an exception?? - Cursor c = null; - String id = uri.getPathSegments().get(1); - Uri notifyUri = null; - switch(match) { - case UI_FOLDERS: - c = db.rawQuery(genQueryAccountMailboxes(uiProjection), new String[] {id}); - break; - case UI_SUBFOLDERS: - c = db.rawQuery(genQuerySubfolders(uiProjection), new String[] {id}); - break; - case UI_MESSAGES: - c = db.rawQuery(genQueryMailboxMessages(uiProjection), new String[] {id}); - notifyUri = UIPROVIDER_CONVERSATION_NOTIFIER.buildUpon().appendPath(id).build(); - break; - case UI_MESSAGE: - c = db.rawQuery(genQueryViewMessage(uiProjection, id), new String[] {id}); - break; - case UI_ATTACHMENTS: - c = db.rawQuery(genQueryAttachments(uiProjection), new String[] {id}); - notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build(); - break; - case UI_ATTACHMENT: - c = db.rawQuery(genQueryAttachment(uiProjection), new String[] {id}); - notifyUri = UIPROVIDER_ATTACHMENT_NOTIFIER.buildUpon().appendPath(id).build(); - break; - case UI_FOLDER: - c = db.rawQuery(genQueryMailbox(uiProjection, id), new String[] {id}); - notifyUri = UIPROVIDER_MAILBOX_NOTIFIER.buildUpon().appendPath(id).build(); - break; - case UI_ACCOUNT: - c = db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); - notifyUri = UIPROVIDER_ACCOUNT_NOTIFIER.buildUpon().appendPath(id).build(); - break; - case UI_SETTINGS: - c = db.rawQuery(genQuerySettings(uiProjection, id), new String[] {id}); - notifyUri = UIPROVIDER_SETTINGS_NOTIFIER.buildUpon().appendPath(id).build(); - break; - } - if (notifyUri != null) { - c.setNotificationUri(resolver, notifyUri); - } - return c; - } - - /** - * Create a mailbox given the account and mailboxType. - */ - private Mailbox createMailbox(long accountId, int mailboxType) { - Context context = getContext(); - int resId = -1; - switch (mailboxType) { - case Mailbox.TYPE_INBOX: - resId = R.string.mailbox_name_server_inbox; - break; - case Mailbox.TYPE_OUTBOX: - resId = R.string.mailbox_name_server_outbox; - break; - case Mailbox.TYPE_DRAFTS: - resId = R.string.mailbox_name_server_drafts; - break; - case Mailbox.TYPE_TRASH: - resId = R.string.mailbox_name_server_trash; - break; - case Mailbox.TYPE_SENT: - resId = R.string.mailbox_name_server_sent; - break; - case Mailbox.TYPE_JUNK: - resId = R.string.mailbox_name_server_junk; - break; - default: - throw new IllegalArgumentException("Illegal mailbox type"); - } - Log.d(TAG, "Creating mailbox of type " + mailboxType + " for account " + accountId); - Mailbox box = Mailbox.newSystemMailbox(accountId, mailboxType, context.getString(resId)); - // Make sure drafts and save will show up in recents... - // If these already exist (from old Email app), they will have touch times - switch (mailboxType) { - case Mailbox.TYPE_DRAFTS: - box.mLastTouchedTime = Mailbox.DRAFTS_DEFAULT_TOUCH_TIME; - break; - case Mailbox.TYPE_SENT: - box.mLastTouchedTime = Mailbox.SENT_DEFAULT_TOUCH_TIME; - break; - } - box.save(context); - return box; - } - - /** - * Given an account name and a mailbox type, return that mailbox, creating it if necessary - * @param accountName the account name to use - * @param mailboxType the type of mailbox we're trying to find - * @return the mailbox of the given type for the account in the uri, or null if not found - */ - private Mailbox getMailboxByAccountIdAndType(String accountId, int mailboxType) { - long id = Long.parseLong(accountId); - Mailbox mailbox = Mailbox.restoreMailboxOfType(getContext(), id, mailboxType); - if (mailbox == null) { - mailbox = createMailbox(id, mailboxType); - } - return mailbox; - } - - private Message getMessageFromPathSegments(List<String> pathSegments) { - Message msg = null; - if (pathSegments.size() > 2) { - msg = Message.restoreMessageWithId(getContext(), Long.parseLong(pathSegments.get(2))); - } - if (msg == null) { - msg = new Message(); - } - return msg; - } - - private void putIntegerLongOrBoolean(ContentValues values, String columnName, Object value) { - if (value instanceof Integer) { - Integer intValue = (Integer)value; - values.put(columnName, intValue); - } else if (value instanceof Boolean) { - Boolean boolValue = (Boolean)value; - values.put(columnName, boolValue ? 1 : 0); - } else if (value instanceof Long) { - Long longValue = (Long)value; - values.put(columnName, longValue); - } - } - - private int uiUpdateAttachment(Uri uri, ContentValues uiValues) { - Integer stateValue = uiValues.getAsInteger(UIProvider.AttachmentColumns.STATE); - if (stateValue != null) { - // This is a command from UIProvider - long attachmentId = Long.parseLong(uri.getLastPathSegment()); - Context context = getContext(); - Attachment attachment = - Attachment.restoreAttachmentWithId(context, attachmentId); - if (attachment == null) { - // Went away; ah, well... - return 0; - } - ContentValues values = new ContentValues(); - switch (stateValue.intValue()) { - case UIProvider.AttachmentState.NOT_SAVED: - // Set state, try to cancel request - values.put(AttachmentColumns.UI_STATE, stateValue); - values.put(AttachmentColumns.FLAGS, - attachment.mFlags &= ~Attachment.FLAG_DOWNLOAD_USER_REQUEST); - attachment.update(context, values); - return 1; - case UIProvider.AttachmentState.DOWNLOADING: - // Set state and destination; request download - values.put(AttachmentColumns.UI_STATE, stateValue); - Integer destinationValue = - uiValues.getAsInteger(UIProvider.AttachmentColumns.DESTINATION); - values.put(AttachmentColumns.UI_DESTINATION, - destinationValue == null ? 0 : destinationValue); - values.put(AttachmentColumns.FLAGS, - attachment.mFlags | Attachment.FLAG_DOWNLOAD_USER_REQUEST); - attachment.update(context, values); - return 1; - } + /** Upgrades the database from v22 to v23 */ + private static void upgradeFromVersion22ToVersion23(SQLiteDatabase db) { + try { + db.execSQL("alter table " + Mailbox.TABLE_NAME + + " add column " + Mailbox.LAST_TOUCHED_TIME + " integer default 0;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 22 to 23 " + e); } - return 0; } - private ContentValues convertUiMessageValues(ContentValues values) { - ContentValues ourValues = new ContentValues(); - for (String columnName: values.keySet()) { - Object val = values.get(columnName); - if (columnName.equals(UIProvider.ConversationColumns.STARRED)) { - putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_FAVORITE, val); - } else if (columnName.equals(UIProvider.ConversationColumns.READ)) { - putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_READ, val); - } else if (columnName.equals(MessageColumns.MAILBOX_KEY)) { - putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, val); - } else if (columnName.equals(UIProvider.ConversationColumns.FOLDER_LIST)) { - // Convert from folder list uri to mailbox key - Uri uri = Uri.parse((String)val); - Long mailboxId = Long.parseLong(uri.getLastPathSegment()); - putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, mailboxId); - } else { - throw new IllegalArgumentException("Can't update " + columnName + " in message"); - } + /** Adds in a column for information about a client certificate to use. */ + private static void upgradeFromVersion23ToVersion24(SQLiteDatabase db) { + try { + db.execSQL("alter table " + HostAuth.TABLE_NAME + + " add column " + HostAuth.CLIENT_CERT_ALIAS + " text;"); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 23 to 24 " + e); } - return ourValues; } - private Uri convertToEmailProviderUri(Uri uri, boolean asProvider) { - String idString = uri.getLastPathSegment(); + /** Upgrades the database from v24 to v25 by creating table for quick responses */ + private static void upgradeFromVersion24ToVersion25(SQLiteDatabase db) { try { - long id = Long.parseLong(idString); - Uri ourUri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, id); - if (asProvider) { - ourUri = ourUri.buildUpon().appendQueryParameter(IS_UIPROVIDER, "true").build(); - } - return ourUri; - } catch (NumberFormatException e) { - return null; + createQuickResponseTable(db); + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 24 to 25 " + e); } } - private Message getMessageFromLastSegment(Uri uri) { - long messageId = Long.parseLong(uri.getLastPathSegment()); - return Message.restoreMessageWithId(getContext(), messageId); - } - - /** - * Add an undo operation for the current sequence; if the sequence is newer than what we've had, - * clear out the undo list and start over - * @param uri the uri we're working on - * @param op the ContentProviderOperation to perform upon undo - */ - private void addToSequence(Uri uri, ContentProviderOperation op) { - String sequenceString = uri.getQueryParameter(UIProvider.SEQUENCE_QUERY_PARAMETER); - if (sequenceString != null) { - int sequence = Integer.parseInt(sequenceString); - if (sequence > mLastSequence) { - // Reset sequence - mLastSequenceOps.clear(); - mLastSequence = sequence; - } - // TODO: Need something to indicate a change isn't ready (undoable) - mLastSequenceOps.add(op); - } - } + private static final String[] V25_ACCOUNT_PROJECTION = + new String[] {AccountColumns.ID, AccountColumns.FLAGS, AccountColumns.HOST_AUTH_KEY_RECV}; + private static final int V25_ACCOUNT_ID = 0; + private static final int V25_ACCOUNT_FLAGS = 1; + private static final int V25_ACCOUNT_RECV = 2; - private int uiUpdateMessage(Uri uri, ContentValues values) { - Uri ourUri = convertToEmailProviderUri(uri, true); - if (ourUri == null) return 0; - ContentValues ourValues = convertUiMessageValues(values); - Message msg = getMessageFromLastSegment(uri); - if (msg == null) return 0; - ContentValues undoValues = new ContentValues(); - for (String columnName: ourValues.keySet()) { - if (columnName.equals(MessageColumns.MAILBOX_KEY)) { - undoValues.put(MessageColumns.MAILBOX_KEY, msg.mMailboxKey); - } else if (columnName.equals(MessageColumns.FLAG_READ)) { - undoValues.put(MessageColumns.FLAG_READ, msg.mFlagRead); - } else if (columnName.equals(MessageColumns.FLAG_FAVORITE)) { - undoValues.put(MessageColumns.FLAG_FAVORITE, msg.mFlagFavorite); - } - } - ContentProviderOperation op = - ContentProviderOperation.newUpdate(convertToEmailProviderUri(uri, false)) - .withValues(undoValues) - .build(); - addToSequence(uri, op); - return update(ourUri, ourValues, null, null); - } + private static final String[] V25_HOSTAUTH_PROJECTION = new String[] {HostAuthColumns.PROTOCOL}; + private static final int V25_HOSTAUTH_PROTOCOL = 0; - private int uiDeleteMessage(Uri uri) { - Context context = getContext(); - Message msg = getMessageFromLastSegment(uri); - if (msg == null) return 0; - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey); - if (mailbox == null) return 0; - if (mailbox.mType == Mailbox.TYPE_TRASH || mailbox.mType == Mailbox.TYPE_DRAFTS) { - // We actually delete these, including attachments - AttachmentUtilities.deleteAllAttachmentFiles(context, msg.mAccountKey, msg.mId); - return context.getContentResolver().delete( - ContentUris.withAppendedId(Message.CONTENT_URI, msg.mId), null, null); - } - Mailbox trashMailbox = - Mailbox.restoreMailboxOfType(context, msg.mAccountKey, Mailbox.TYPE_TRASH); - if (trashMailbox == null) return 0; - ContentValues values = new ContentValues(); - values.put(MessageColumns.MAILBOX_KEY, trashMailbox.mId); - return uiUpdateMessage(uri, values); - } - - private Cursor uiUndo(Uri uri, String[] projection) { - // First see if we have any operations saved - // TODO: Make sure seq matches - if (!mLastSequenceOps.isEmpty()) { + /** Upgrades the database from v25 to v26 by adding FLAG_SUPPORTS_SEARCH to IMAP accounts */ + private static void upgradeFromVersion25ToVersion26(SQLiteDatabase db) { + try { + // Loop through accounts, looking for imap accounts + Cursor accountCursor = db.query(Account.TABLE_NAME, V25_ACCOUNT_PROJECTION, null, + null, null, null, null); + ContentValues cv = new ContentValues(); try { - // TODO Always use this projection? Or what's passed in? - // Not sure if UI wants it, but I'm making a cursor of convo uri's - MatrixCursor c = new MatrixCursor( - new String[] {UIProvider.ConversationColumns.URI}, - mLastSequenceOps.size()); - for (ContentProviderOperation op: mLastSequenceOps) { - c.addRow(new String[] {op.getUri().toString()}); + String[] hostAuthArgs = new String[1]; + while (accountCursor.moveToNext()) { + hostAuthArgs[0] = accountCursor.getString(V25_ACCOUNT_RECV); + // Get the "receive" HostAuth for this account + Cursor hostAuthCursor = db.query(HostAuth.TABLE_NAME, + V25_HOSTAUTH_PROJECTION, HostAuth.RECORD_ID + "=?", hostAuthArgs, + null, null, null); + try { + if (hostAuthCursor.moveToFirst()) { + String protocol = hostAuthCursor.getString(V25_HOSTAUTH_PROTOCOL); + // If this is an imap account, add the search flag + if (HostAuth.SCHEME_IMAP.equals(protocol)) { + String id = accountCursor.getString(V25_ACCOUNT_ID); + int flags = accountCursor.getInt(V25_ACCOUNT_FLAGS); + cv.put(AccountColumns.FLAGS, flags | Account.FLAGS_SUPPORTS_SEARCH); + db.update(Account.TABLE_NAME, cv, Account.RECORD_ID + "=?", + new String[] {id}); + } + } + } finally { + hostAuthCursor.close(); + } } - // Just apply the batch and we're done! - applyBatch(mLastSequenceOps); - // But clear the operations - mLastSequenceOps.clear(); - // Tell the UI there are changes - getContext().getContentResolver().notifyChange(UIPROVIDER_CONVERSATION_NOTIFIER, - null); - Log.d(TAG, "[Notify UI: Undo]"); - return c; - } catch (OperationApplicationException e) { + } finally { + accountCursor.close(); } + } catch (SQLException e) { + // Shouldn't be needed unless we're debugging and interrupt the process + Log.w(TAG, "Exception upgrading EmailProvider.db from 25 to 26 " + e); } - return new MatrixCursor(projection, 0); } - private void notifyUIConversation(Uri uri) { - String id = uri.getLastPathSegment(); - Message msg = Message.restoreMessageWithId(getContext(), Long.parseLong(id)); - if (msg != null) { - notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, Long.toString(msg.mMailboxKey)); - } - } - - private void notifyUIConversationMailbox(long id) { - notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, Long.toString(id)); - } - - private void notifyUI(Uri uri, String id) { - Uri notifyUri = uri.buildUpon().appendPath(id).build(); - getContext().getContentResolver().notifyChange(notifyUri, null); - // Temporary - Log.d(TAG, "[Notify UI: " + notifyUri + "]"); + /** + * For testing purposes, check whether a given row is cached + * @param baseUri the base uri of the EmailContent + * @param id the row id of the EmailContent + * @return whether or not the row is currently cached + */ + @VisibleForTesting + protected boolean isCached(Uri baseUri, long id) { + int match = findMatch(baseUri, "isCached"); + int table = match >> BASE_SHIFT; + ContentCache cache = mContentCaches[table]; + if (cache == null) return false; + Cursor cc = cache.get(Long.toString(id)); + return (cc != null); } - private void notifyUI(Uri uri, long id) { - notifyUI(uri, Long.toString(id)); + public static interface AttachmentService { + /** + * Notify the service that an attachment has changed. + */ + void attachmentChanged(Context context, long id, int flags); } - /** - * Support for services and service notifications - */ - - private final IEmailServiceCallback.Stub mServiceCallback = - new IEmailServiceCallback.Stub() { - - @Override - public void syncMailboxListStatus(long accountId, int statusCode, int progress) - throws RemoteException { - } - - @Override - public void syncMailboxStatus(long mailboxId, int statusCode, int progress) - throws RemoteException { - // We'll get callbacks here from the services, which we'll pass back to the UI - Uri uri = ContentUris.withAppendedId(FOLDER_STATUS_URI, mailboxId); - EmailProvider.this.getContext().getContentResolver().notifyChange(uri, null); - } - - @Override - public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode, - int progress) throws RemoteException { - } - - @Override - public void sendMessageStatus(long messageId, String subject, int statusCode, int progress) - throws RemoteException { - } - + private final AttachmentService DEFAULT_ATTACHMENT_SERVICE = new AttachmentService() { @Override - public void loadMessageStatus(long messageId, int statusCode, int progress) - throws RemoteException { + public void attachmentChanged(Context context, long id, int flags) { + // The default implementation delegates to the real service. + AttachmentDownloadService.attachmentChanged(context, id, flags); } }; - - private Cursor uiFolderRefresh(Uri uri) { - Context context = getContext(); - String idString = uri.getLastPathSegment(); - long id = Long.parseLong(idString); - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, id); - if (mailbox == null) return null; - EmailServiceProxy service = EmailServiceUtils.getServiceForAccount(context, - mServiceCallback, mailbox.mAccountKey); - try { - service.startSync(id, true); - } catch (RemoteException e) { - } - return null; - } - - //Number of additional messages to load when a user selects "Load more..." in POP/IMAP boxes - public static final int VISIBLE_LIMIT_INCREMENT = 10; - //Number of additional messages to load when a user selects "Load more..." in a search - public static final int SEARCH_MORE_INCREMENT = 10; - - private Cursor uiFolderLoadMore(Uri uri) { - Context context = getContext(); - String idString = uri.getLastPathSegment(); - long id = Long.parseLong(idString); - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, id); - if (mailbox == null) return null; - if (mailbox.mType == Mailbox.TYPE_SEARCH) { - // Ask for 10 more messages - mSearchParams.mOffset += SEARCH_MORE_INCREMENT; - runSearchQuery(context, mailbox.mAccountKey, id); - } else { - ContentValues values = new ContentValues(); - values.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.VISIBLE_LIMIT); - values.put(EmailContent.ADD_COLUMN_NAME, VISIBLE_LIMIT_INCREMENT); - Uri mailboxUri = ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, id); - // Increase the limit - context.getContentResolver().update(mailboxUri, values, null, null); - // And order a refresh - uiFolderRefresh(uri); - } - return null; - } - - private static final String SEARCH_MAILBOX_SERVER_ID = "__search_mailbox__"; - private SearchParams mSearchParams; - - /** - * Returns the search mailbox for the specified account, creating one if necessary - * @return the search mailbox for the passed in account - */ - private Mailbox getSearchMailbox(long accountId) { - Context context = getContext(); - Mailbox m = Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_SEARCH); - if (m == null) { - m = new Mailbox(); - m.mAccountKey = accountId; - m.mServerId = SEARCH_MAILBOX_SERVER_ID; - m.mFlagVisible = false; - m.mDisplayName = SEARCH_MAILBOX_SERVER_ID; - m.mSyncInterval = Mailbox.CHECK_INTERVAL_NEVER; - m.mType = Mailbox.TYPE_SEARCH; - m.mFlags = Mailbox.FLAG_HOLDS_MAIL; - m.mParentKey = Mailbox.NO_MAILBOX; - m.save(context); - } - return m; - } - - private void runSearchQuery(final Context context, final long accountId, - final long searchMailboxId) { - // Start the search running in the background - new Thread(new Runnable() { - @Override - public void run() { - try { - EmailServiceProxy service = EmailServiceUtils.getServiceForAccount(context, - mServiceCallback, accountId); - if (service != null) { - try { - // Save away the total count - mSearchParams.mTotalCount = service.searchMessages(accountId, - mSearchParams, searchMailboxId); - Log.d(TAG, "TotalCount to UI: " + mSearchParams.mTotalCount); - notifyUI(UIPROVIDER_MAILBOX_NOTIFIER, searchMailboxId); - } catch (RemoteException e) { - Log.e("searchMessages", "RemoteException", e); - } - } - } finally { - } - }}).start(); - - } - - // TODO: Handle searching for more... - private Cursor uiSearch(Uri uri, String[] projection) { - final long accountId = Long.parseLong(uri.getLastPathSegment()); - - // TODO: Check the actual mailbox - Mailbox inbox = Mailbox.restoreMailboxOfType(getContext(), accountId, Mailbox.TYPE_INBOX); - if (inbox == null) return null; - - String filter = uri.getQueryParameter(UIProvider.SearchQueryParameters.QUERY); - if (filter == null) { - throw new IllegalArgumentException("No query parameter in search query"); - } - - // Find/create our search mailbox - Mailbox searchMailbox = getSearchMailbox(accountId); - final long searchMailboxId = searchMailbox.mId; - - mSearchParams = new SearchParams(inbox.mId, filter, searchMailboxId); - - final Context context = getContext(); - if (mSearchParams.mOffset == 0) { - // Delete existing contents of search mailbox - ContentResolver resolver = context.getContentResolver(); - resolver.delete(Message.CONTENT_URI, Message.MAILBOX_KEY + "=" + searchMailboxId, - null); - ContentValues cv = new ContentValues(); - // For now, use the actual query as the name of the mailbox - cv.put(Mailbox.DISPLAY_NAME, mSearchParams.mFilter); - resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), - cv, null, null); - } - - // Start the search running in the background - runSearchQuery(context, accountId, searchMailboxId); - - // This will look just like a "normal" folder - return uiQuery(UI_FOLDER, ContentUris.withAppendedId(Mailbox.CONTENT_URI, - searchMailbox.mId), projection); - } - - private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?"; - private static final String MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION = - MAILBOXES_FOR_ACCOUNT_SELECTION + " AND " + MailboxColumns.TYPE + "!=" + - Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; - private static final String MESSAGES_FOR_ACCOUNT_SELECTION = MessageColumns.ACCOUNT_KEY + "=?"; + private AttachmentService mAttachmentService = DEFAULT_ATTACHMENT_SERVICE; /** - * Delete an account and clean it up + * Injects a custom attachment service handler. If null is specified, will reset to the + * default service. */ - private int uiDeleteAccount(Uri uri) { - Context context = getContext(); - long accountId = Long.parseLong(uri.getLastPathSegment()); - try { - // Get the account URI. - final Account account = Account.restoreAccountWithId(context, accountId); - if (account == null) { - return 0; // Already deleted? - } - - deleteAccountData(context, accountId); - - // Now delete the account itself - uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); - context.getContentResolver().delete(uri, null, null); - - // Clean up - AccountBackupRestore.backup(context); - SecurityPolicy.getInstance(context).reducePolicies(); - Email.setServicesEnabledSync(context); - return 1; - } catch (Exception e) { - Log.w(Logging.LOG_TAG, "Exception while deleting account", e); - } - return 0; - } - - private int uiDeleteAccountData(Uri uri) { - Context context = getContext(); - long accountId = Long.parseLong(uri.getLastPathSegment()); - // Get the account URI. - final Account account = Account.restoreAccountWithId(context, accountId); - if (account == null) { - return 0; // Already deleted? - } - deleteAccountData(context, accountId); - return 1; - } - - private void deleteAccountData(Context context, long accountId) { - // Delete synced attachments - AttachmentUtilities.deleteAllAccountAttachmentFiles(context, accountId); - - // Delete synced email, leaving only an empty inbox. We do this in two phases: - // 1. Delete all non-inbox mailboxes (which will delete all of their messages) - // 2. Delete all remaining messages (which will be the inbox messages) - ContentResolver resolver = context.getContentResolver(); - String[] accountIdArgs = new String[] { Long.toString(accountId) }; - resolver.delete(Mailbox.CONTENT_URI, - MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION, - accountIdArgs); - resolver.delete(Message.CONTENT_URI, MESSAGES_FOR_ACCOUNT_SELECTION, accountIdArgs); - - // Delete sync keys on remaining items - ContentValues cv = new ContentValues(); - cv.putNull(Account.SYNC_KEY); - resolver.update(Account.CONTENT_URI, cv, Account.ID_SELECTION, accountIdArgs); - cv.clear(); - cv.putNull(Mailbox.SYNC_KEY); - resolver.update(Mailbox.CONTENT_URI, cv, - MAILBOXES_FOR_ACCOUNT_SELECTION, accountIdArgs); - - // Delete PIM data (contacts, calendar), stop syncs, etc. if applicable - IEmailService service = EmailServiceUtils.getServiceForAccount(context, null, accountId); - if (service != null) { - try { - service.deleteAccountPIMData(accountId); - } catch (RemoteException e) { - // Can't do anything about this - } - } + public void injectAttachmentService(AttachmentService as) { + mAttachmentService = (as == null) ? DEFAULT_ATTACHMENT_SERVICE : as; } } diff --git a/src/com/android/email/provider/Utilities.java b/src/com/android/email/provider/Utilities.java deleted file mode 100644 index ab175f666..000000000 --- a/src/com/android/email/provider/Utilities.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2012 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.email.provider; - -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -import com.android.email.LegacyConversions; -import com.android.emailcommon.Logging; -import com.android.emailcommon.internet.MimeUtility; -import com.android.emailcommon.mail.Message; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.mail.Part; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.provider.EmailContent.SyncColumns; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.utility.ConversionUtilities; - -import java.io.IOException; -import java.util.ArrayList; - -public class Utilities { - /** - * Copy one downloaded message (which may have partially-loaded sections) - * into a newly created EmailProvider Message, given the account and mailbox - * - * @param message the remote message we've just downloaded - * @param account the account it will be stored into - * @param folder the mailbox it will be stored into - * @param loadStatus when complete, the message will be marked with this status (e.g. - * EmailContent.Message.LOADED) - */ - public static void copyOneMessageToProvider(Context context, Message message, Account account, - Mailbox folder, int loadStatus) { - EmailContent.Message localMessage = null; - Cursor c = null; - try { - c = context.getContentResolver().query( - EmailContent.Message.CONTENT_URI, - EmailContent.Message.CONTENT_PROJECTION, - EmailContent.MessageColumns.ACCOUNT_KEY + "=?" + - " AND " + MessageColumns.MAILBOX_KEY + "=?" + - " AND " + SyncColumns.SERVER_ID + "=?", - new String[] { - String.valueOf(account.mId), - String.valueOf(folder.mId), - String.valueOf(message.getUid()) - }, - null); - if (c.moveToNext()) { - localMessage = EmailContent.getContent(c, EmailContent.Message.class); - localMessage.mMailboxKey = folder.mId; - localMessage.mAccountKey = account.mId; - copyOneMessageToProvider(context, message, localMessage, loadStatus); - } - } finally { - if (c != null) { - c.close(); - } - } - } - - /** - * Copy one downloaded message (which may have partially-loaded sections) - * into an already-created EmailProvider Message - * - * @param message the remote message we've just downloaded - * @param localMessage the EmailProvider Message, already created - * @param loadStatus when complete, the message will be marked with this status (e.g. - * EmailContent.Message.LOADED) - * @param context the context to be used for EmailProvider - */ - public static void copyOneMessageToProvider(Context context, Message message, - EmailContent.Message localMessage, int loadStatus) { - try { - - EmailContent.Body body = EmailContent.Body.restoreBodyWithMessageId(context, - localMessage.mId); - if (body == null) { - body = new EmailContent.Body(); - } - try { - // Copy the fields that are available into the message object - LegacyConversions.updateMessageFields(localMessage, message, - localMessage.mAccountKey, localMessage.mMailboxKey); - - // Now process body parts & attachments - ArrayList<Part> viewables = new ArrayList<Part>(); - ArrayList<Part> attachments = new ArrayList<Part>(); - MimeUtility.collectParts(message, viewables, attachments); - - ConversionUtilities.updateBodyFields(body, localMessage, viewables); - - // Commit the message & body to the local store immediately - saveOrUpdate(localMessage, context); - saveOrUpdate(body, context); - - // process (and save) attachments - LegacyConversions.updateAttachments(context, localMessage, attachments); - - // One last update of message with two updated flags - localMessage.mFlagLoaded = loadStatus; - - ContentValues cv = new ContentValues(); - cv.put(EmailContent.MessageColumns.FLAG_ATTACHMENT, localMessage.mFlagAttachment); - cv.put(EmailContent.MessageColumns.FLAG_LOADED, localMessage.mFlagLoaded); - Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, - localMessage.mId); - context.getContentResolver().update(uri, cv, null, null); - - } catch (MessagingException me) { - Log.e(Logging.LOG_TAG, "Error while copying downloaded message." + me); - } - - } catch (RuntimeException rte) { - Log.e(Logging.LOG_TAG, "Error while storing downloaded message." + rte.toString()); - } catch (IOException ioe) { - Log.e(Logging.LOG_TAG, "Error while storing attachment." + ioe.toString()); - } - } - - public static void saveOrUpdate(EmailContent content, Context context) { - if (content.isSaved()) { - content.update(context, content.toContentValues()); - } else { - content.save(context); - } - } - -} diff --git a/src/com/android/email/service/AttachmentDownloadService.java b/src/com/android/email/service/AttachmentDownloadService.java index 7a72b6d6a..18468fbb1 100644 --- a/src/com/android/email/service/AttachmentDownloadService.java +++ b/src/com/android/email/service/AttachmentDownloadService.java @@ -33,13 +33,13 @@ import android.text.format.DateUtils; import android.util.Log; import com.android.email.AttachmentInfo; +import com.android.email.Controller.ControllerService; import com.android.email.Email; import com.android.email.EmailConnectivityManager; import com.android.email.NotificationController; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Attachment; -import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.service.EmailServiceProxy; import com.android.emailcommon.service.EmailServiceStatus; @@ -155,7 +155,6 @@ public class AttachmentDownloadService extends Service implements Runnable { @Override public void onReceive(final Context context, Intent intent) { new Thread(new Runnable() { - @Override public void run() { watchdogAlarm(); } @@ -450,8 +449,8 @@ public class AttachmentDownloadService extends Service implements Runnable { * @return whether or not the download was started */ /*package*/ synchronized boolean tryStartDownload(DownloadRequest req) { - EmailServiceProxy service = EmailServiceUtils.getServiceForAccount( - AttachmentDownloadService.this, mServiceCallback, req.accountId); + Intent intent = getServiceIntentForAccount(req.accountId); + if (intent == null) return false; // Do not download the same attachment multiple times boolean alreadyInProgress = mDownloadsInProgress.get(req.attachmentId) != null; @@ -461,7 +460,7 @@ public class AttachmentDownloadService extends Service implements Runnable { if (Email.DEBUG) { Log.d(TAG, ">> Starting download for attachment #" + req.attachmentId); } - startDownload(service, req); + startDownload(intent, req); } catch (RemoteException e) { // TODO: Consider whether we need to do more in this case... // For now, fix up our data to reflect the failure @@ -478,16 +477,18 @@ public class AttachmentDownloadService extends Service implements Runnable { * Do the work of starting an attachment download using the EmailService interface, and * set our watchdog alarm * - * @param serviceClass the service handling the download + * @param serviceClass the class that will attempt the download * @param req the DownloadRequest * @throws RemoteException */ - private void startDownload(EmailServiceProxy service, DownloadRequest req) + private void startDownload(Intent intent, DownloadRequest req) throws RemoteException { req.startTime = System.currentTimeMillis(); req.inProgress = true; mDownloadsInProgress.put(req.attachmentId, req); - service.loadAttachment(req.attachmentId, req.priority != PRIORITY_FOREGROUND); + EmailServiceProxy proxy = + new EmailServiceProxy(mContext, intent, mServiceCallback); + proxy.loadAttachment(req.attachmentId, req.priority != PRIORITY_FOREGROUND); // Lazily initialize our (reusable) pending intent if (mWatchdogPendingIntent == null) { createWatchdogPendingIntent(mContext); @@ -651,7 +652,6 @@ public class AttachmentDownloadService extends Service implements Runnable { * single callback that's defined by the EmailServiceCallback interface. */ private class ServiceCallback extends IEmailServiceCallback.Stub { - @Override public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode, int progress) { // Record status and progress @@ -673,15 +673,6 @@ public class AttachmentDownloadService extends Service implements Runnable { req.lastStatusCode = statusCode; req.lastProgress = progress; req.lastCallbackTime = System.currentTimeMillis(); - Attachment attachment = Attachment.restoreAttachmentWithId(mContext, attachmentId); - if (attachment != null && statusCode == EmailServiceStatus.IN_PROGRESS) { - ContentValues values = new ContentValues(); - values.put(AttachmentColumns.UI_DOWNLOADED_SIZE, - attachment.mSize * progress / 100); - // Update UIProvider with updated download size - // Individual services will set contentUri and state when finished - attachment.update(mContext, values); - } } switch (statusCode) { case EmailServiceStatus.IN_PROGRESS: @@ -693,24 +684,40 @@ public class AttachmentDownloadService extends Service implements Runnable { } @Override - public void syncMailboxListStatus(long accountId, int statusCode, int progress) + public void sendMessageStatus(long messageId, String subject, int statusCode, int progress) throws RemoteException { } @Override - public void syncMailboxStatus(long mailboxId, int statusCode, int progress) + public void syncMailboxListStatus(long accountId, int statusCode, int progress) throws RemoteException { } @Override - public void sendMessageStatus(long messageId, String subject, int statusCode, int progress) + public void syncMailboxStatus(long mailboxId, int statusCode, int progress) throws RemoteException { } + } - @Override - public void loadMessageStatus(long messageId, int statusCode, int progress) - throws RemoteException { - } + /** + * Return an Intent to be used used based on the account type of the provided account id. We + * cache the results to avoid repeated database access + * @param accountId the id of the account + * @return the Intent to be used for the account or null (if the account no longer exists) + */ + private synchronized Intent getServiceIntentForAccount(long accountId) { + // TODO: We should have some more data-driven way of determining the service intent. + Intent serviceIntent = mAccountServiceMap.get(accountId); + if (serviceIntent == null) { + String protocol = Account.getProtocol(mContext, accountId); + if (protocol == null) return null; + serviceIntent = new Intent(mContext, ControllerService.class); + if (protocol.equals("eas")) { + serviceIntent = new Intent(EmailServiceProxy.EXCHANGE_INTENT); + } + mAccountServiceMap.put(accountId, serviceIntent); + } + return serviceIntent; } /*package*/ void addServiceIntentForTest(long accountId, Intent intent) { @@ -794,7 +801,6 @@ public class AttachmentDownloadService extends Service implements Runnable { */ public static void attachmentChanged(final Context context, final long id, final int flags) { Utility.runAsync(new Runnable() { - @Override public void run() { Attachment attachment = Attachment.restoreAttachmentWithId(context, id); if (attachment != null) { @@ -861,7 +867,6 @@ public class AttachmentDownloadService extends Service implements Runnable { } } - @Override public void run() { // These fields are only used within the service thread mContext = this; diff --git a/src/com/android/email/service/EmailBroadcastProcessorService.java b/src/com/android/email/service/EmailBroadcastProcessorService.java index 6c41ebb80..bfd4f3f33 100644 --- a/src/com/android/email/service/EmailBroadcastProcessorService.java +++ b/src/com/android/email/service/EmailBroadcastProcessorService.java @@ -29,6 +29,7 @@ import android.database.Cursor; import android.net.Uri; import android.util.Log; +import com.android.email.Email; import com.android.email.Preferences; import com.android.email.SecurityPolicy; import com.android.email.VendorPolicyLoader; @@ -105,7 +106,15 @@ public class EmailBroadcastProcessorService extends IntentService { if (Intent.ACTION_BOOT_COMPLETED.equals(broadcastAction)) { onBootCompleted(); - } else if (ACTION_SECRET_CODE.equals(broadcastAction) + + // TODO: Do a better job when we get ACTION_DEVICE_STORAGE_LOW. + // The code below came from very old code.... + } else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(broadcastAction)) { + // Stop IMAP/POP3 poll. + MailService.actionCancel(this); + } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(broadcastAction)) { + enableComponentsIfNecessary(); + } else if (ACTION_SECRET_CODE.equals(broadcastAction) && SECRET_CODE_HOST_DEBUG_SCREEN.equals(broadcastIntent.getData().getHost())) { AccountSettings.actionSettingsWithDebug(this); } else if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(broadcastAction)) { @@ -117,12 +126,22 @@ public class EmailBroadcastProcessorService extends IntentService { } } + private void enableComponentsIfNecessary() { + if (Email.setServicesEnabledSync(this)) { + // At least one account exists. + // TODO probably we should check if it's a POP/IMAP account. + MailService.actionReschedule(this); + } + } + /** * Handles {@link Intent#ACTION_BOOT_COMPLETED}. Called on a worker thread. */ private void onBootCompleted() { performOneTimeInitialization(); + enableComponentsIfNecessary(); + // Starts the service for Exchange, if supported. EmailServiceUtils.startExchangeService(this); } diff --git a/src/com/android/email/service/EmailServiceStub.java b/src/com/android/email/service/EmailServiceStub.java deleted file mode 100644 index 5957efefc..000000000 --- a/src/com/android/email/service/EmailServiceStub.java +++ /dev/null @@ -1,537 +0,0 @@ -/* Copyright (C) 2012 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.email.service; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.TrafficStats; -import android.net.Uri; -import android.os.Bundle; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.Log; - -import com.android.email.Controller.Result; -import com.android.email.Email; -import com.android.email.LegacyConversions; -import com.android.email.NotificationController; -import com.android.email.mail.Sender; -import com.android.email.mail.Store; -import com.android.email.provider.Utilities; -import com.android.emailcommon.AccountManagerTypes; -import com.android.emailcommon.Api; -import com.android.emailcommon.Logging; -import com.android.emailcommon.TrafficFlags; -import com.android.emailcommon.internet.MimeBodyPart; -import com.android.emailcommon.internet.MimeHeader; -import com.android.emailcommon.internet.MimeMultipart; -import com.android.emailcommon.mail.AuthenticationFailedException; -import com.android.emailcommon.mail.FetchProfile; -import com.android.emailcommon.mail.Folder; -import com.android.emailcommon.mail.Folder.MessageRetrievalListener; -import com.android.emailcommon.mail.Folder.OpenMode; -import com.android.emailcommon.mail.Message; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.Attachment; -import com.android.emailcommon.provider.EmailContent.AttachmentColumns; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.EmailServiceStatus; -import com.android.emailcommon.service.IEmailService; -import com.android.emailcommon.service.IEmailServiceCallback; -import com.android.emailcommon.service.SearchParams; -import com.android.emailcommon.utility.AttachmentUtilities; -import com.android.emailcommon.utility.Utility; -import com.android.mail.providers.UIProvider; - -import java.io.IOException; -import java.util.HashSet; - -/** - * EmailServiceStub is an abstract class representing an EmailService - * - * This class provides legacy support for a few methods that are common to both - * IMAP and POP3, including startSync, loadMore, loadAttachment, and sendMail - */ -public abstract class EmailServiceStub extends IEmailService.Stub implements IEmailService { - - private static final int MAILBOX_COLUMN_ID = 0; - private static final int MAILBOX_COLUMN_SERVER_ID = 1; - private static final int MAILBOX_COLUMN_TYPE = 2; - - public static final String SYNC_EXTRA_MAILBOX_ID = "__mailboxId__"; - - /** Small projection for just the columns required for a sync. */ - private static final String[] MAILBOX_PROJECTION = new String[] { - MailboxColumns.ID, - MailboxColumns.SERVER_ID, - MailboxColumns.TYPE, - }; - - private Context mContext; - private IEmailServiceCallback.Stub mCallback; - - protected void init(Context context, IEmailServiceCallback.Stub callbackProxy) { - mContext = context; - mCallback = callbackProxy; - } - - @Override - public Bundle validate(HostAuth hostauth) throws RemoteException { - // TODO Auto-generated method stub - return null; - } - - @Override - public void startSync(long mailboxId, boolean userRequest) throws RemoteException { - Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); - if (mailbox == null) return; - Account account = Account.restoreAccountWithId(mContext, mailbox.mAccountKey); - if (account == null) return; - android.accounts.Account acct = new android.accounts.Account(account.mEmailAddress, - AccountManagerTypes.TYPE_POP_IMAP); - Bundle extras = new Bundle(); - extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); - extras.putLong(SYNC_EXTRA_MAILBOX_ID, mailboxId); - ContentResolver.requestSync(acct, EmailContent.AUTHORITY, extras); - } - - @Override - public void stopSync(long mailboxId) throws RemoteException { - // Not required - } - - @Override - public void loadMore(long messageId) throws RemoteException { - // Load a message for view... - try { - // 1. Resample the message, in case it disappeared or synced while - // this command was in queue - EmailContent.Message message = - EmailContent.Message.restoreMessageWithId(mContext, messageId); - if (message == null) { - mCallback.loadMessageStatus(messageId, - EmailServiceStatus.MESSAGE_NOT_FOUND, 0); - return; - } - if (message.mFlagLoaded == EmailContent.Message.FLAG_LOADED_COMPLETE) { - // We should NEVER get here - mCallback.loadMessageStatus(messageId, 0, 100); - return; - } - - // 2. Open the remote folder. - // TODO combine with common code in loadAttachment - Account account = Account.restoreAccountWithId(mContext, message.mAccountKey); - Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); - if (account == null || mailbox == null) { - //mListeners.loadMessageForViewFailed(messageId, "null account or mailbox"); - return; - } - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); - - Store remoteStore = Store.getInstance(account, mContext); - String remoteServerId = mailbox.mServerId; - // If this is a search result, use the protocolSearchInfo field to get the - // correct remote location - if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) { - remoteServerId = message.mProtocolSearchInfo; - } - Folder remoteFolder = remoteStore.getFolder(remoteServerId); - remoteFolder.open(OpenMode.READ_WRITE); - - // 3. Set up to download the entire message - Message remoteMessage = remoteFolder.getMessage(message.mServerId); - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - remoteFolder.fetch(new Message[] { remoteMessage }, fp, null); - - // 4. Write to provider - Utilities.copyOneMessageToProvider(mContext, remoteMessage, account, mailbox, - EmailContent.Message.FLAG_LOADED_COMPLETE); - - // 5. Notify UI - mCallback.loadMessageStatus(messageId, 0, 100); - - } catch (MessagingException me) { - if (Logging.LOGD) Log.v(Logging.LOG_TAG, "", me); - mCallback.loadMessageStatus(messageId, EmailServiceStatus.REMOTE_EXCEPTION, 0); - } catch (RuntimeException rte) { - mCallback.loadMessageStatus(messageId, EmailServiceStatus.REMOTE_EXCEPTION, 0); - } - } - - private void doProgressCallback(long messageId, long attachmentId, int progress) { - try { - mCallback.loadAttachmentStatus(messageId, attachmentId, - EmailServiceStatus.IN_PROGRESS, progress); - } catch (RemoteException e) { - // No danger if the client is no longer around - } - } - - @Override - public void loadAttachment(long attachmentId, boolean background) throws RemoteException { - try { - //1. Check if the attachment is already here and return early in that case - Attachment attachment = - Attachment.restoreAttachmentWithId(mContext, attachmentId); - if (attachment == null) { - mCallback.loadAttachmentStatus(0, attachmentId, - EmailServiceStatus.ATTACHMENT_NOT_FOUND, 0); - return; - } - long messageId = attachment.mMessageKey; - - EmailContent.Message message = - EmailContent.Message.restoreMessageWithId(mContext, attachment.mMessageKey); - if (message == null) { - mCallback.loadAttachmentStatus(messageId, attachmentId, - EmailServiceStatus.MESSAGE_NOT_FOUND, 0); - } - - // If the message is loaded, just report that we're finished - if (Utility.attachmentExists(mContext, attachment)) { - mCallback.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.SUCCESS, - 0); - return; - } - - // Say we're starting... - doProgressCallback(messageId, attachmentId, 0); - - // 2. Open the remote folder. - // TODO all of these could be narrower projections - Account account = Account.restoreAccountWithId(mContext, message.mAccountKey); - Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); - - if (account == null || mailbox == null) { - // If the account/mailbox are gone, just report success; the UI handles this - mCallback.loadAttachmentStatus(messageId, attachmentId, - EmailServiceStatus.SUCCESS, 0); - return; - } - TrafficStats.setThreadStatsTag( - TrafficFlags.getAttachmentFlags(mContext, account)); - - Store remoteStore = Store.getInstance(account, mContext); - Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); - remoteFolder.open(OpenMode.READ_WRITE); - - // 3. Generate a shell message in which to retrieve the attachment, - // and a shell BodyPart for the attachment. Then glue them together. - Message storeMessage = remoteFolder.createMessage(message.mServerId); - MimeBodyPart storePart = new MimeBodyPart(); - storePart.setSize((int)attachment.mSize); - storePart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, - attachment.mLocation); - storePart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, - String.format("%s;\n name=\"%s\"", - attachment.mMimeType, - attachment.mFileName)); - // TODO is this always true for attachments? I think we dropped the - // true encoding along the way - storePart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - - MimeMultipart multipart = new MimeMultipart(); - multipart.setSubType("mixed"); - multipart.addBodyPart(storePart); - - storeMessage.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed"); - storeMessage.setBody(multipart); - - // 4. Now ask for the attachment to be fetched - FetchProfile fp = new FetchProfile(); - fp.add(storePart); - remoteFolder.fetch(new Message[] { storeMessage }, fp, - new MessageRetrievalListenerBridge(messageId, attachmentId)); - - // If we failed to load the attachment, throw an Exception here, so that - // AttachmentDownloadService knows that we failed - if (storePart.getBody() == null) { - throw new MessagingException("Attachment not loaded."); - } - - // 5. Save the downloaded file and update the attachment as necessary - LegacyConversions.saveAttachmentBody(mContext, storePart, attachment, - message.mAccountKey); - - // 6. Report success - mCallback.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.SUCCESS, 0); - } - catch (MessagingException me) { - if (Logging.LOGD) Log.v(Logging.LOG_TAG, "", me); - // TODO: Fix this up; consider the best approach - - ContentValues cv = new ContentValues(); - cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.FAILED); - Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); - mContext.getContentResolver().update(uri, cv, null, null); - - mCallback.loadAttachmentStatus(0, attachmentId, EmailServiceStatus.CONNECTION_ERROR, 0); - } catch (IOException ioe) { - Log.e(Logging.LOG_TAG, "Error while storing attachment." + ioe.toString()); - } - - } - - /** - * Bridge to intercept {@link MessageRetrievalListener#loadAttachmentProgress} and - * pass down to {@link Result}. - */ - public class MessageRetrievalListenerBridge implements MessageRetrievalListener { - private final long mMessageId; - private final long mAttachmentId; - - public MessageRetrievalListenerBridge(long messageId, long attachmentId) { - mMessageId = messageId; - mAttachmentId = attachmentId; - } - - @Override - public void loadAttachmentProgress(int progress) { - doProgressCallback(mMessageId, mAttachmentId, progress); - } - - @Override - public void messageRetrieved(com.android.emailcommon.mail.Message message) { - } - } - - // TODO: Implement callback - @Override - public void updateFolderList(long accountId) throws RemoteException { - Account account = Account.restoreAccountWithId(mContext, accountId); - if (account == null) return; - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account)); - Cursor localFolderCursor = null; - try { - // Step 1: Get remote mailboxes - Store store = Store.getInstance(account, mContext); - Folder[] remoteFolders = store.updateFolders(); - HashSet<String> remoteFolderNames = new HashSet<String>(); - for (int i = 0, count = remoteFolders.length; i < count; i++) { - remoteFolderNames.add(remoteFolders[i].getName()); - } - - // Step 2: Get local mailboxes - localFolderCursor = mContext.getContentResolver().query( - Mailbox.CONTENT_URI, - MAILBOX_PROJECTION, - EmailContent.MailboxColumns.ACCOUNT_KEY + "=?", - new String[] { String.valueOf(account.mId) }, - null); - - // Step 3: Remove any local mailbox not on the remote list - while (localFolderCursor.moveToNext()) { - String mailboxPath = localFolderCursor.getString(MAILBOX_COLUMN_SERVER_ID); - // Short circuit if we have a remote mailbox with the same name - if (remoteFolderNames.contains(mailboxPath)) { - continue; - } - - int mailboxType = localFolderCursor.getInt(MAILBOX_COLUMN_TYPE); - long mailboxId = localFolderCursor.getLong(MAILBOX_COLUMN_ID); - switch (mailboxType) { - case Mailbox.TYPE_INBOX: - case Mailbox.TYPE_DRAFTS: - case Mailbox.TYPE_OUTBOX: - case Mailbox.TYPE_SENT: - case Mailbox.TYPE_TRASH: - case Mailbox.TYPE_SEARCH: - // Never, ever delete special mailboxes - break; - default: - // Drop all attachment files related to this mailbox - AttachmentUtilities.deleteAllMailboxAttachmentFiles( - mContext, accountId, mailboxId); - // Delete the mailbox; database triggers take care of related - // Message, Body and Attachment records - Uri uri = ContentUris.withAppendedId( - Mailbox.CONTENT_URI, mailboxId); - mContext.getContentResolver().delete(uri, null, null); - break; - } - } - //mListeners.listFoldersFinished(accountId); - } catch (Exception e) { - //mListeners.listFoldersFailed(accountId, e.toString()); - } finally { - if (localFolderCursor != null) { - localFolderCursor.close(); - } - } - } - - @Override - public boolean createFolder(long accountId, String name) throws RemoteException { - // Not required - return false; - } - - @Override - public boolean deleteFolder(long accountId, String name) throws RemoteException { - // Not required - return false; - } - - @Override - public boolean renameFolder(long accountId, String oldName, String newName) - throws RemoteException { - // Not required - return false; - } - - @Override - public void setCallback(IEmailServiceCallback cb) throws RemoteException { - // Not required - } - - @Override - public void setLogging(int on) throws RemoteException { - // Not required - } - - @Override - public void hostChanged(long accountId) throws RemoteException { - // Not required - } - - @Override - public Bundle autoDiscover(String userName, String password) throws RemoteException { - // Not required - return null; - } - - @Override - public void sendMeetingResponse(long messageId, int response) throws RemoteException { - // Not required - } - - @Override - public void deleteAccountPIMData(long accountId) throws RemoteException { - MailService.reconcilePopImapAccountsSync(mContext); - } - - @Override - public int getApiLevel() throws RemoteException { - return Api.LEVEL; - } - - @Override - public int searchMessages(long accountId, SearchParams params, long destMailboxId) - throws RemoteException { - // Not required - return 0; - } - - @Override - public void sendMail(long accountId) throws RemoteException { - sendMailImpl(mContext, accountId); - } - - public static void sendMailImpl(Context context, long accountId) { - Account account = Account.restoreAccountWithId(context, accountId); - TrafficStats.setThreadStatsTag(TrafficFlags.getSmtpFlags(context, account)); - NotificationController nc = NotificationController.getInstance(context); - // 1. Loop through all messages in the account's outbox - long outboxId = Mailbox.findMailboxOfType(context, account.mId, Mailbox.TYPE_OUTBOX); - if (outboxId == Mailbox.NO_MAILBOX) { - return; - } - ContentResolver resolver = context.getContentResolver(); - Cursor c = resolver.query(EmailContent.Message.CONTENT_URI, - EmailContent.Message.ID_COLUMN_PROJECTION, - EmailContent.Message.MAILBOX_KEY + "=?", new String[] { Long.toString(outboxId) }, - null); - try { - // 2. exit early - if (c.getCount() <= 0) { - return; - } - Sender sender = Sender.getInstance(context, account); - Store remoteStore = Store.getInstance(account, context); - boolean requireMoveMessageToSentFolder = remoteStore.requireCopyMessageToSentFolder(); - ContentValues moveToSentValues = null; - if (requireMoveMessageToSentFolder) { - Mailbox sentFolder = - Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_SENT); - moveToSentValues = new ContentValues(); - moveToSentValues.put(MessageColumns.MAILBOX_KEY, sentFolder.mId); - } - - // 3. loop through the available messages and send them - while (c.moveToNext()) { - long messageId = -1; - try { - messageId = c.getLong(0); - // Don't send messages with unloaded attachments - if (Utility.hasUnloadedAttachments(context, messageId)) { - if (Email.DEBUG) { - Log.d(Logging.LOG_TAG, "Can't send #" + messageId + - "; unloaded attachments"); - } - continue; - } - sender.sendMessage(messageId); - } catch (MessagingException me) { - // report error for this message, but keep trying others - if (me instanceof AuthenticationFailedException) { - nc.showLoginFailedNotification(account.mId); - } - continue; - } - // 4. move to sent, or delete - Uri syncedUri = - ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); - if (requireMoveMessageToSentFolder) { - // If this is a forwarded message and it has attachments, delete them, as they - // duplicate information found elsewhere (on the server). This saves storage. - EmailContent.Message msg = - EmailContent.Message.restoreMessageWithId(context, messageId); - if (msg != null && - ((msg.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0)) { - AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, - messageId); - } - resolver.update(syncedUri, moveToSentValues, null, null); - } else { - AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, - messageId); - Uri uri = - ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, messageId); - resolver.delete(uri, null, null); - resolver.delete(syncedUri, null, null); - } - } - nc.cancelLoginFailedNotification(account.mId); - } catch (MessagingException me) { - if (me instanceof AuthenticationFailedException) { - nc.showLoginFailedNotification(account.mId); - } - } finally { - c.close(); - } - - } -} diff --git a/src/com/android/email/service/EmailServiceUtils.java b/src/com/android/email/service/EmailServiceUtils.java index e7b18bb32..38e35195d 100644 --- a/src/com/android/email/service/EmailServiceUtils.java +++ b/src/com/android/email/service/EmailServiceUtils.java @@ -16,14 +16,19 @@ package com.android.email.service; +import android.app.Service; import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; -import com.android.emailcommon.provider.Account; +import com.android.emailcommon.Api; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.service.EmailServiceProxy; import com.android.emailcommon.service.IEmailService; import com.android.emailcommon.service.IEmailServiceCallback; +import com.android.emailcommon.service.SearchParams; /** * Utility functions for EmailService support. @@ -43,7 +48,7 @@ public class EmailServiceUtils { * @param context * @param callback Object to get callback, or can be null */ - public static EmailServiceProxy getService(Context context, String intentAction, + public static IEmailService getService(Context context, String intentAction, IEmailServiceCallback callback) { return new EmailServiceProxy(context, intentAction, callback); } @@ -59,41 +64,92 @@ public class EmailServiceUtils { startService(context, EmailServiceProxy.EXCHANGE_INTENT); } - public static EmailServiceProxy getExchangeService(Context context, + public static IEmailService getExchangeService(Context context, IEmailServiceCallback callback) { return getService(context, EmailServiceProxy.EXCHANGE_INTENT, callback); } - public static EmailServiceProxy getImapService(Context context, - IEmailServiceCallback callback) { - return new EmailServiceProxy(context, ImapService.class, callback); - } - - public static EmailServiceProxy getPop3Service(Context context, - IEmailServiceCallback callback) { - return new EmailServiceProxy(context, Pop3Service.class, callback); - } - public static boolean isExchangeAvailable(Context context) { return isServiceAvailable(context, EmailServiceProxy.EXCHANGE_INTENT); } /** - * For a given account id, return a service proxy if applicable, or null. + * An empty {@link IEmailService} implementation which is used instead of + * {@link com.android.exchange.ExchangeService} on the build with no exchange support. * - * @param accountId the message of interest - * @result service proxy, or null if n/a + * <p>In theory, the service in question isn't used on the no-exchange-support build, + * because we won't have any exchange accounts in that case, so we wouldn't have to have this + * class. However, there are a few places we do use the service even if there's no exchange + * accounts (e.g. setLogging), so this class is added for safety and simplicity. */ - public static EmailServiceProxy getServiceForAccount(Context context, - IEmailServiceCallback callback, long accountId) { - String protocol = Account.getProtocol(context, accountId); - if (HostAuth.SCHEME_IMAP.equals(protocol)) { - return getImapService(context, callback); - } else if (HostAuth.SCHEME_POP3.equals(protocol)) { - return getPop3Service(context, callback); - } else if (HostAuth.SCHEME_EAS.equals(protocol)) { - return getExchangeService(context, callback); - } else { + public static class NullEmailService extends Service implements IEmailService { + public static final NullEmailService INSTANCE = new NullEmailService(); + + public int getApiLevel() { + return Api.LEVEL; + } + + public Bundle autoDiscover(String userName, String password) throws RemoteException { + return Bundle.EMPTY; + } + + public boolean createFolder(long accountId, String name) throws RemoteException { + return false; + } + + public boolean deleteFolder(long accountId, String name) throws RemoteException { + return false; + } + + public void hostChanged(long accountId) throws RemoteException { + } + + public void loadAttachment(long attachmentId, boolean background) throws RemoteException { + } + + public void loadMore(long messageId) throws RemoteException { + } + + public boolean renameFolder(long accountId, String oldName, String newName) + throws RemoteException { + return false; + } + + public void sendMeetingResponse(long messageId, int response) throws RemoteException { + } + + public void setCallback(IEmailServiceCallback cb) throws RemoteException { + } + + public void setLogging(int flags) throws RemoteException { + } + + public void startSync(long mailboxId, boolean userRequest) throws RemoteException { + } + + public void stopSync(long mailboxId) throws RemoteException { + } + + public void updateFolderList(long accountId) throws RemoteException { + } + + public Bundle validate(HostAuth hostAuth) throws RemoteException { + return null; + } + + public void deleteAccountPIMData(long accountId) throws RemoteException { + } + + public int searchMessages(long accountId, SearchParams searchParams, long destMailboxId) { + return 0; + } + + public IBinder asBinder() { + return null; + } + + @Override + public IBinder onBind(Intent intent) { return null; } } diff --git a/src/com/android/email/service/MailService.java b/src/com/android/email/service/MailService.java index c52dea91c..4b3f31a54 100644 --- a/src/com/android/email/service/MailService.java +++ b/src/com/android/email/service/MailService.java @@ -18,37 +18,108 @@ package com.android.email.service; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; +import android.app.AlarmManager; +import android.app.PendingIntent; import android.app.Service; +import android.content.ContentResolver; +import android.content.ContentUris; import android.content.Context; import android.content.Intent; +import android.content.SyncStatusObserver; import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import com.android.email.Controller; import com.android.email.Email; +import com.android.email.Preferences; import com.android.email.SingleRunningTask; import com.android.email.provider.AccountReconciler; import com.android.emailcommon.AccountManagerTypes; +import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.HostAuth; +import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.EmailAsyncTask; import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; /** - * Legacy service, now used mainly for account reconciliation + * Background service for refreshing non-push email accounts. + * + * TODO: Convert to IntentService to move *all* work off the UI thread, serialize work, and avoid + * possible problems with out-of-order startId processing. */ public class MailService extends Service { private static final String LOG_TAG = "Email-MailService"; + private static final String ACTION_CHECK_MAIL = + "com.android.email.intent.action.MAIL_SERVICE_WAKEUP"; + private static final String ACTION_RESCHEDULE = + "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE"; + private static final String ACTION_CANCEL = + "com.android.email.intent.action.MAIL_SERVICE_CANCEL"; private static final String ACTION_SEND_PENDING_MAIL = "com.android.email.intent.action.MAIL_SERVICE_SEND_PENDING"; + private static final String ACTION_DELETE_EXCHANGE_ACCOUNTS = + "com.android.email.intent.action.MAIL_SERVICE_DELETE_EXCHANGE_ACCOUNTS"; private static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT"; + private static final String EXTRA_ACCOUNT_INFO = "com.android.email.intent.extra.ACCOUNT_INFO"; + private static final String EXTRA_DEBUG_WATCHDOG = "com.android.email.intent.extra.WATCHDOG"; + + /** Time between watchdog checks; in milliseconds */ + private static final long WATCHDOG_DELAY = 10 * 60 * 1000; // 10 minutes + + /** Sentinel value asking to update mSyncReports if it's currently empty */ + @VisibleForTesting + static final int SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY = -1; + /** Sentinel value asking that mSyncReports be rebuilt */ + @VisibleForTesting + static final int SYNC_REPORTS_RESET = -2; + + @VisibleForTesting + Controller mController; + private final Controller.Result mControllerCallback = new ControllerResults(); + private ContentResolver mContentResolver; + private Context mContext; + + private int mStartId; + + /** + * Access must be synchronized, because there are accesses from the Controller callback + */ + /*package*/ static HashMap<Long,AccountSyncReport> mSyncReports = + new HashMap<Long,AccountSyncReport>(); + + public static void actionReschedule(Context context) { + Intent i = new Intent(); + i.setClass(context, MailService.class); + i.setAction(MailService.ACTION_RESCHEDULE); + context.startService(i); + } + + public static void actionCancel(Context context) { + Intent i = new Intent(); + i.setClass(context, MailService.class); + i.setAction(MailService.ACTION_CANCEL); + context.startService(i); + } + + public static void actionDeleteExchangeAccounts(Context context) { + Intent i = new Intent(); + i.setClass(context, MailService.class); + i.setAction(MailService.ACTION_DELETE_EXCHANGE_ACCOUNTS); + context.startService(i); + } /** * Entry point for AttachmentDownloadService to ask that pending mail be sent @@ -74,21 +145,126 @@ public class MailService extends Service { } }); + // TODO this needs to be passed through the controller and back to us + mStartId = startId; String action = intent.getAction(); final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1); - if (ACTION_SEND_PENDING_MAIL.equals(action)) { + mController = Controller.getInstance(this); + mController.addResultCallback(mControllerCallback); + mContentResolver = getContentResolver(); + mContext = this; + + final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + + if (ACTION_CHECK_MAIL.equals(action)) { + // DB access required to satisfy this intent, so offload from UI thread + EmailAsyncTask.runAsyncParallel(new Runnable() { + @Override + public void run() { + // If we have the data, restore the last-sync-times for each account + // These are cached in the wakeup intent in case the process was killed. + restoreSyncReports(intent); + + // Sync a specific account if given + if (Email.DEBUG) { + Log.d(LOG_TAG, "action: check mail for id=" + accountId); + } + if (accountId >= 0) { + setWatchdog(accountId, alarmManager); + } + + // Start sync if account is given && auto-sync is allowed + boolean syncStarted = false; + if (accountId != -1 && ContentResolver.getMasterSyncAutomatically()) { + synchronized(mSyncReports) { + for (AccountSyncReport report: mSyncReports.values()) { + if (report.accountId == accountId) { + if (report.syncEnabled) { + syncStarted = syncOneAccount(mController, accountId, + startId); + } + break; + } + } + } + } + + // Reschedule if we didn't start sync. + if (!syncStarted) { + // Prevent runaway on the current account by pretending it updated + if (accountId != -1) { + updateAccountReport(accountId, 0); + } + // Find next account to sync, and reschedule + reschedule(alarmManager); + // Stop the service, unless actually syncing (which will stop the service) + stopSelf(startId); + } + } + }); + } + else if (ACTION_CANCEL.equals(action)) { + if (Email.DEBUG) { + Log.d(LOG_TAG, "action: cancel"); + } + cancel(); + stopSelf(startId); + } + else if (ACTION_DELETE_EXCHANGE_ACCOUNTS.equals(action)) { + if (Email.DEBUG) { + Log.d(LOG_TAG, "action: delete exchange accounts"); + } + EmailAsyncTask.runAsyncParallel(new Runnable() { + @Override + public void run() { + Cursor c = mContentResolver.query(Account.CONTENT_URI, Account.ID_PROJECTION, + null, null, null); + try { + while (c.moveToNext()) { + long accountId = c.getLong(Account.ID_PROJECTION_COLUMN); + if ("eas".equals(Account.getProtocol(mContext, accountId))) { + // Always log this + Log.d(LOG_TAG, "Deleting EAS account: " + accountId); + mController.deleteAccountSync(accountId, mContext); + } + } + } finally { + c.close(); + } + } + }); + stopSelf(startId); + } + else if (ACTION_SEND_PENDING_MAIL.equals(action)) { if (Email.DEBUG) { Log.d(LOG_TAG, "action: send pending mail"); } EmailAsyncTask.runAsyncParallel(new Runnable() { @Override public void run() { - Controller.getInstance(getApplicationContext()).sendPendingMessages(accountId); + mController.sendPendingMessages(accountId); } }); stopSelf(startId); } + else if (ACTION_RESCHEDULE.equals(action)) { + if (Email.DEBUG) { + Log.d(LOG_TAG, "action: reschedule"); + } + // DB access required to satisfy this intent, so offload from UI thread + EmailAsyncTask.runAsyncParallel(new Runnable() { + @Override + public void run() { + // When called externally, we refresh the sync reports table to pick up + // any changes in the account list or account settings + refreshSyncReports(); + // Finally, scan for the next needing update, and set an alarm for it + reschedule(alarmManager); + stopSelf(startId); + } + }); + } // Returning START_NOT_STICKY means that if a mail check is killed (e.g. due to memory // pressure, there will be no explicit restart. This is OK; Note that we set a watchdog @@ -102,6 +278,390 @@ public class MailService extends Service { return null; } + @Override + public void onDestroy() { + super.onDestroy(); + Controller.getInstance(getApplication()).removeResultCallback(mControllerCallback); + } + + private void cancel() { + AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); + PendingIntent pi = createAlarmIntent(-1, null, false); + alarmMgr.cancel(pi); + } + + /** + * Refresh the sync reports, to pick up any changes in the account list or account settings. + */ + private void refreshSyncReports() { + synchronized (mSyncReports) { + // Make shallow copy of sync reports so we can recover the prev sync times + HashMap<Long,AccountSyncReport> oldSyncReports = + new HashMap<Long,AccountSyncReport>(mSyncReports); + + // Delete the sync reports to force a refresh from live account db data + setupSyncReportsLocked(SYNC_REPORTS_RESET, this); + + // Restore prev-sync & next-sync times for any reports in the new list + for (AccountSyncReport newReport : mSyncReports.values()) { + AccountSyncReport oldReport = oldSyncReports.get(newReport.accountId); + if (oldReport != null) { + newReport.prevSyncTime = oldReport.prevSyncTime; + newReport.setNextSyncTime(); + } + } + } + } + + /** + * Create and send an alarm with the entire list. This also sends a list of known last-sync + * times with the alarm, so if we are killed between alarms, we don't lose this info. + * + * @param alarmMgr passed in so we can mock for testing. + */ + private void reschedule(AlarmManager alarmMgr) { + // restore the reports if lost + setupSyncReports(SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY); + synchronized (mSyncReports) { + int numAccounts = mSyncReports.size(); + long[] accountInfo = new long[numAccounts * 2]; // pairs of { accountId, lastSync } + int accountInfoIndex = 0; + + long nextCheckTime = Long.MAX_VALUE; + AccountSyncReport nextAccount = null; + long timeNow = SystemClock.elapsedRealtime(); + + for (AccountSyncReport report : mSyncReports.values()) { + if (report.syncInterval <= 0) { // no timed checks - skip + continue; + } + long prevSyncTime = report.prevSyncTime; + long nextSyncTime = report.nextSyncTime; + + // select next account to sync + if ((prevSyncTime == 0) || (nextSyncTime < timeNow)) { // never checked, or overdue + nextCheckTime = 0; + nextAccount = report; + } else if (nextSyncTime < nextCheckTime) { // next to be checked + nextCheckTime = nextSyncTime; + nextAccount = report; + } + // collect last-sync-times for all accounts + // this is using pairs of {long,long} to simplify passing in a bundle + accountInfo[accountInfoIndex++] = report.accountId; + accountInfo[accountInfoIndex++] = report.prevSyncTime; + } + + // Clear out any unused elements in the array + while (accountInfoIndex < accountInfo.length) { + accountInfo[accountInfoIndex++] = -1; + } + + // set/clear alarm as needed + long idToCheck = (nextAccount == null) ? -1 : nextAccount.accountId; + PendingIntent pi = createAlarmIntent(idToCheck, accountInfo, false); + + if (nextAccount == null) { + alarmMgr.cancel(pi); + if (Email.DEBUG) { + Log.d(LOG_TAG, "reschedule: alarm cancel - no account to check"); + } + } else { + alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextCheckTime, pi); + if (Email.DEBUG) { + Log.d(LOG_TAG, "reschedule: alarm set at " + nextCheckTime + + " for " + nextAccount); + } + } + } + } + + /** + * Create a watchdog alarm and set it. This is used in case a mail check fails (e.g. we are + * killed by the system due to memory pressure.) Normally, a mail check will complete and + * the watchdog will be replaced by the call to reschedule(). + * @param accountId the account we were trying to check + * @param alarmMgr system alarm manager + */ + private void setWatchdog(long accountId, AlarmManager alarmMgr) { + PendingIntent pi = createAlarmIntent(accountId, null, true); + long timeNow = SystemClock.elapsedRealtime(); + long nextCheckTime = timeNow + WATCHDOG_DELAY; + alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextCheckTime, pi); + } + + /** + * Return a pending intent for use by this alarm. Most of the fields must be the same + * (in order for the intent to be recognized by the alarm manager) but the extras can + * be different, and are passed in here as parameters. + */ + private PendingIntent createAlarmIntent(long checkId, long[] accountInfo, boolean isWatchdog) { + Intent i = new Intent(); + i.setClass(this, MailService.class); + i.setAction(ACTION_CHECK_MAIL); + i.putExtra(EXTRA_ACCOUNT, checkId); + i.putExtra(EXTRA_ACCOUNT_INFO, accountInfo); + if (isWatchdog) { + i.putExtra(EXTRA_DEBUG_WATCHDOG, true); + } + PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); + return pi; + } + + /** + * Start a controller sync for a specific account + * + * @param controller The controller to do the sync work + * @param checkAccountId the account Id to try and check + * @param startId the id of this service launch + * @return true if mail checking has started, false if it could not (e.g. bad account id) + */ + private boolean syncOneAccount(Controller controller, long checkAccountId, int startId) { + long inboxId = Mailbox.findMailboxOfType(this, checkAccountId, Mailbox.TYPE_INBOX); + if (inboxId == Mailbox.NO_MAILBOX) { + return false; + } else { + controller.serviceCheckMail(checkAccountId, inboxId, startId); + return true; + } + } + + /** + * Note: Times are relative to SystemClock.elapsedRealtime() + * + * TODO: Look more closely at syncEnabled and see if we can simply coalesce it into + * syncInterval (e.g. if !syncEnabled, set syncInterval to -1). + */ + @VisibleForTesting + static class AccountSyncReport { + long accountId; + /** The time of the last sync, or, {@code 0}, the last sync time is unknown. */ + long prevSyncTime; + /** The time of the next sync. If {@code 0}, sync ASAP. If {@code 1}, don't sync. */ + long nextSyncTime; + /** Minimum time between syncs; in minutes. */ + int syncInterval; + /** If {@code true}, auto sync is enabled. */ + boolean syncEnabled; + + /** + * Sets the next sync time using the previous sync time and sync interval. + */ + private void setNextSyncTime() { + if (syncInterval > 0 && prevSyncTime != 0) { + nextSyncTime = prevSyncTime + (syncInterval * 1000 * 60); + } + } + + @Override + public String toString() { + return "id=" + accountId + " prevSync=" + prevSyncTime + " nextSync=" + nextSyncTime; + } + } + + /** + * scan accounts to create a list of { acct, prev sync, next sync, #new } + * use this to create a fresh copy. assumes all accounts need sync + * + * @param accountId -1 will rebuild the list if empty. other values will force loading + * of a single account (e.g if it was created after the original list population) + */ + private void setupSyncReports(long accountId) { + synchronized (mSyncReports) { + setupSyncReportsLocked(accountId, mContext); + } + } + + /** + * Handle the work of setupSyncReports. Must be synchronized on mSyncReports. + */ + @VisibleForTesting + void setupSyncReportsLocked(long accountId, Context context) { + ContentResolver resolver = context.getContentResolver(); + if (accountId == SYNC_REPORTS_RESET) { + // For test purposes, force refresh of mSyncReports + mSyncReports.clear(); + accountId = SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY; + } else if (accountId == SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY) { + // -1 == reload the list if empty, otherwise exit immediately + if (mSyncReports.size() > 0) { + return; + } + } else { + // load a single account if it doesn't already have a sync record + if (mSyncReports.containsKey(accountId)) { + return; + } + } + + // setup to add a single account or all accounts + Uri uri; + if (accountId == SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY) { + uri = Account.CONTENT_URI; + } else { + uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); + } + + final boolean oneMinuteRefresh + = Preferences.getPreferences(this).getForceOneMinuteRefresh(); + if (oneMinuteRefresh) { + Log.w(LOG_TAG, "One-minute refresh enabled."); + } + + // We use a full projection here because we'll restore each account object from it + Cursor c = resolver.query(uri, Account.CONTENT_PROJECTION, null, null, null); + try { + while (c.moveToNext()) { + Account account = Account.getContent(c, Account.class); + // The following sanity checks are primarily for the sake of ignoring non-user + // accounts that may have been left behind e.g. by failed unit tests. + // Properly-formed accounts will always pass these simple checks. + if (TextUtils.isEmpty(account.mEmailAddress) + || account.mHostAuthKeyRecv <= 0 + || account.mHostAuthKeySend <= 0) { + continue; + } + + // The account is OK, so proceed + AccountSyncReport report = new AccountSyncReport(); + int syncInterval = account.mSyncInterval; + + // If we're not using MessagingController (EAS at this point), don't schedule syncs + if (!mController.isMessagingController(account.mId)) { + syncInterval = Account.CHECK_INTERVAL_NEVER; + } else if (oneMinuteRefresh && syncInterval >= 0) { + syncInterval = 1; + } + + report.accountId = account.mId; + report.prevSyncTime = 0; + report.nextSyncTime = (syncInterval > 0) ? 0 : -1; // 0 == ASAP -1 == no sync + + report.syncInterval = syncInterval; + + // See if the account is enabled for sync in AccountManager + android.accounts.Account accountManagerAccount = + new android.accounts.Account(account.mEmailAddress, + AccountManagerTypes.TYPE_POP_IMAP); + report.syncEnabled = ContentResolver.getSyncAutomatically(accountManagerAccount, + EmailContent.AUTHORITY); + + // TODO lookup # new in inbox + mSyncReports.put(report.accountId, report); + } + } finally { + c.close(); + } + } + + /** + * Update list with a single account's sync times and unread count + * + * @param accountId the account being updated + * @param newCount the number of new messages, or -1 if not being reported (don't update) + * @return the report for the updated account, or null if it doesn't exist (e.g. deleted) + */ + private AccountSyncReport updateAccountReport(long accountId, int newCount) { + // restore the reports if lost + setupSyncReports(accountId); + synchronized (mSyncReports) { + AccountSyncReport report = mSyncReports.get(accountId); + if (report == null) { + // discard result - there is no longer an account with this id + Log.d(LOG_TAG, "No account to update for id=" + Long.toString(accountId)); + return null; + } + + // report found - update it (note - editing the report while in-place in the hashmap) + report.prevSyncTime = SystemClock.elapsedRealtime(); + report.setNextSyncTime(); + if (Email.DEBUG) { + Log.d(LOG_TAG, "update account " + report.toString()); + } + return report; + } + } + + /** + * when we receive an alarm, update the account sync reports list if necessary + * this will be the case when if we have restarted the process and lost the data + * in the global. + * + * @param restoreIntent the intent with the list + */ + private void restoreSyncReports(Intent restoreIntent) { + // restore the reports if lost + setupSyncReports(SYNC_REPORTS_ALL_ACCOUNTS_IF_EMPTY); + synchronized (mSyncReports) { + long[] accountInfo = restoreIntent.getLongArrayExtra(EXTRA_ACCOUNT_INFO); + if (accountInfo == null) { + Log.d(LOG_TAG, "no data in intent to restore"); + return; + } + int accountInfoIndex = 0; + int accountInfoLimit = accountInfo.length; + while (accountInfoIndex < accountInfoLimit) { + long accountId = accountInfo[accountInfoIndex++]; + long prevSync = accountInfo[accountInfoIndex++]; + AccountSyncReport report = mSyncReports.get(accountId); + if (report != null) { + if (report.prevSyncTime == 0) { + report.prevSyncTime = prevSync; + report.setNextSyncTime(); + } + } + } + } + } + + class ControllerResults extends Controller.Result { + @Override + public void updateMailboxCallback(MessagingException result, long accountId, + long mailboxId, int progress, int numNewMessages, + ArrayList<Long> addedMessages) { + // First, look for authentication failures and notify + //checkAuthenticationStatus(result, accountId); + if (result != null || progress == 100) { + // We only track the inbox here in the service - ignore other mailboxes + long inboxId = Mailbox.findMailboxOfType(MailService.this, + accountId, Mailbox.TYPE_INBOX); + if (mailboxId == inboxId) { + if (progress == 100) { + updateAccountReport(accountId, numNewMessages); + } else { + updateAccountReport(accountId, -1); + } + } + } + } + + @Override + public void serviceCheckMailCallback(MessagingException result, long accountId, + long mailboxId, int progress, long tag) { + if (result != null || progress == 100) { + if (result != null) { + // the checkmail ended in an error. force an update of the refresh + // time, so we don't just spin on this account + updateAccountReport(accountId, -1); + } + AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); + reschedule(alarmManager); + int serviceId = mStartId; + if (tag != 0) { + serviceId = (int) tag; + } + stopSelf(serviceId); + } + } + } + + public class EmailSyncStatusObserver implements SyncStatusObserver { + @Override + public void onStatusChanged(int which) { + // We ignore the argument (we can only get called in one case - when settings change) + } + } + public static ArrayList<Account> getPopImapAccountList(Context context) { ArrayList<Account> providerAccounts = new ArrayList<Account>(); Cursor c = context.getContentResolver().query(Account.CONTENT_URI, Account.ID_PROJECTION, diff --git a/src/com/android/email/service/PolicyService.java b/src/com/android/email/service/PolicyService.java index 2394eedd7..a97f65954 100644 --- a/src/com/android/email/service/PolicyService.java +++ b/src/com/android/email/service/PolicyService.java @@ -16,15 +16,15 @@ package com.android.email.service; +import com.android.email.SecurityPolicy; +import com.android.emailcommon.provider.Policy; +import com.android.emailcommon.service.IPolicyService; + import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; -import com.android.email.SecurityPolicy; -import com.android.emailcommon.provider.Policy; -import com.android.emailcommon.service.IPolicyService; - public class PolicyService extends Service { private SecurityPolicy mSecurityPolicy; @@ -35,16 +35,32 @@ public class PolicyService extends Service { return mSecurityPolicy.isActive(policy); } + public void policiesRequired(long accountId) { + mSecurityPolicy.policiesRequired(accountId); + } + + public void policiesUpdated(long accountId) { + mSecurityPolicy.policiesUpdated(accountId); + } + public void setAccountHoldFlag(long accountId, boolean newState) { SecurityPolicy.setAccountHoldFlag(mContext, accountId, newState); } + public boolean isActiveAdmin() { + return mSecurityPolicy.isActiveAdmin(); + } + public void remoteWipe() { mSecurityPolicy.remoteWipe(); } - public void setAccountPolicy(long accountId, Policy policy, String securityKey) { - mSecurityPolicy.setAccountPolicy(accountId, policy, securityKey); + public boolean isSupported(Policy policy) { + return mSecurityPolicy.isSupported(policy); + } + + public Policy clearUnsupportedPolicies(Policy policy) { + return mSecurityPolicy.clearUnsupportedPolicies(policy); } }; diff --git a/src/com/android/email/service/Pop3Service.java b/src/com/android/email/service/Pop3Service.java deleted file mode 100644 index d69641ad8..000000000 --- a/src/com/android/email/service/Pop3Service.java +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright (C) 2012 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.email.service; - -import android.app.Service; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.TrafficStats; -import android.net.Uri; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.util.Log; - -import com.android.email.Email; -import com.android.email.LegacyConversions; -import com.android.email.NotificationController; -import com.android.email.mail.Store; -import com.android.email.provider.Utilities; -import com.android.emailcommon.AccountManagerTypes; -import com.android.emailcommon.Logging; -import com.android.emailcommon.TrafficFlags; -import com.android.emailcommon.internet.MimeUtility; -import com.android.emailcommon.mail.AuthenticationFailedException; -import com.android.emailcommon.mail.FetchProfile; -import com.android.emailcommon.mail.Flag; -import com.android.emailcommon.mail.Folder; -import com.android.emailcommon.mail.Folder.FolderType; -import com.android.emailcommon.mail.Folder.MessageRetrievalListener; -import com.android.emailcommon.mail.Folder.OpenMode; -import com.android.emailcommon.mail.Message; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.mail.Part; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.provider.EmailContent.SyncColumns; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.EmailServiceStatus; -import com.android.emailcommon.service.IEmailServiceCallback; -import com.android.emailcommon.utility.AttachmentUtilities; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; - -public class Pop3Service extends Service { - private static final String TAG = "Pop3Service"; - private static final int MAX_SMALL_MESSAGE_SIZE = (25 * 1024); - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return Service.START_STICKY; - } - - // Callbacks as set up via setCallback - private static final RemoteCallbackList<IEmailServiceCallback> mCallbackList = - new RemoteCallbackList<IEmailServiceCallback>(); - - private interface ServiceCallbackWrapper { - public void call(IEmailServiceCallback cb) throws RemoteException; - } - - /** - * Proxy that can be used by various sync adapters to tie into ExchangeService's callback system - * Used this way: ExchangeService.callback().callbackMethod(args...); - * The proxy wraps checking for existence of a ExchangeService instance - * Failures of these callbacks can be safely ignored. - */ - static private final IEmailServiceCallback.Stub sCallbackProxy = - new IEmailServiceCallback.Stub() { - - /** - * Broadcast a callback to the everyone that's registered - * - * @param wrapper the ServiceCallbackWrapper used in the broadcast - */ - private synchronized void broadcastCallback(ServiceCallbackWrapper wrapper) { - RemoteCallbackList<IEmailServiceCallback> callbackList = mCallbackList; - if (callbackList != null) { - // Call everyone on our callback list - int count = callbackList.beginBroadcast(); - try { - for (int i = 0; i < count; i++) { - try { - wrapper.call(callbackList.getBroadcastItem(i)); - } catch (RemoteException e) { - // Safe to ignore - } catch (RuntimeException e) { - // We don't want an exception in one call to prevent other calls, so - // we'll just log this and continue - Log.e(TAG, "Caught RuntimeException in broadcast", e); - } - } - } finally { - // No matter what, we need to finish the broadcast - callbackList.finishBroadcast(); - } - } - } - - @Override - public void loadAttachmentStatus(final long messageId, final long attachmentId, - final int status, final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.loadAttachmentStatus(messageId, attachmentId, status, progress); - } - }); - } - - @Override - public void loadMessageStatus(final long messageId, final int status, final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.loadMessageStatus(messageId, status, progress); - } - }); - } - - @Override - public void sendMessageStatus(final long messageId, final String subject, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.sendMessageStatus(messageId, subject, status, progress); - } - }); - } - - @Override - public void syncMailboxListStatus(final long accountId, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.syncMailboxListStatus(accountId, status, progress); - } - }); - } - - @Override - public void syncMailboxStatus(final long mailboxId, final int status, - final int progress) { - broadcastCallback(new ServiceCallbackWrapper() { - @Override - public void call(IEmailServiceCallback cb) throws RemoteException { - cb.syncMailboxStatus(mailboxId, status, progress); - } - }); - } - }; - - /** - * Create our EmailService implementation here. - */ - private final EmailServiceStub mBinder = new EmailServiceStub() { - - @Override - public void startSync(long mailboxId, boolean userRequest) throws RemoteException { - Context context = getApplicationContext(); - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); - if (mailbox == null) return; - Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey); - if (account == null) return; - android.accounts.Account acct = new android.accounts.Account(account.mEmailAddress, - AccountManagerTypes.TYPE_POP_IMAP); - Log.d(TAG, "startSync API requesting sync"); - Bundle extras = new Bundle(); - extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - ContentResolver.requestSync(acct, EmailContent.AUTHORITY, extras); - } - - @Override - public void setCallback(IEmailServiceCallback cb) throws RemoteException { - mCallbackList.register(cb); - } - }; - - @Override - public IBinder onBind(Intent intent) { - mBinder.init(this, sCallbackProxy); - return mBinder; - } - - private static void sendMailboxStatus(Mailbox mailbox, int status) { - try { - sCallbackProxy.syncMailboxStatus(mailbox.mId, status, 0); - } catch (RemoteException e) { - } - } - - /** - * Start foreground synchronization of the specified folder. This is called by - * synchronizeMailbox or checkMail. - * TODO this should use ID's instead of fully-restored objects - * @param account - * @param folder - * @throws MessagingException - */ - public static void synchronizeMailboxSynchronous(Context context, final Account account, - final Mailbox folder) throws MessagingException { - sendMailboxStatus(folder, EmailServiceStatus.IN_PROGRESS); - - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account)); - if ((folder.mFlags & Mailbox.FLAG_HOLDS_MAIL) == 0) { - sendMailboxStatus(folder, EmailServiceStatus.SUCCESS); - } - NotificationController nc = NotificationController.getInstance(context); - try { - processPendingActionsSynchronous(context, account); - synchronizeMailboxGeneric(context, account, folder); - // Clear authentication notification for this account - nc.cancelLoginFailedNotification(account.mId); - sendMailboxStatus(folder, EmailServiceStatus.SUCCESS); - } catch (MessagingException e) { - if (Logging.LOGD) { - Log.v(Logging.LOG_TAG, "synchronizeMailbox", e); - } - if (e instanceof AuthenticationFailedException) { - // Generate authentication notification - nc.showLoginFailedNotification(account.mId); - } - sendMailboxStatus(folder, e.getExceptionType()); - throw e; - } - } - - /** - * Lightweight record for the first pass of message sync, where I'm just seeing if - * the local message requires sync. Later (for messages that need syncing) we'll do a full - * readout from the DB. - */ - private static class LocalMessageInfo { - private static final int COLUMN_ID = 0; - private static final int COLUMN_FLAG_READ = 1; - private static final int COLUMN_FLAG_FAVORITE = 2; - private static final int COLUMN_FLAG_LOADED = 3; - private static final int COLUMN_SERVER_ID = 4; - private static final int COLUMN_FLAGS = 7; - private static final String[] PROJECTION = new String[] { - EmailContent.RECORD_ID, - MessageColumns.FLAG_READ, MessageColumns.FLAG_FAVORITE, MessageColumns.FLAG_LOADED, - SyncColumns.SERVER_ID, MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY, - MessageColumns.FLAGS - }; - - final long mId; - final boolean mFlagRead; - final boolean mFlagFavorite; - final int mFlagLoaded; - final String mServerId; - final int mFlags; - - public LocalMessageInfo(Cursor c) { - mId = c.getLong(COLUMN_ID); - mFlagRead = c.getInt(COLUMN_FLAG_READ) != 0; - mFlagFavorite = c.getInt(COLUMN_FLAG_FAVORITE) != 0; - mFlagLoaded = c.getInt(COLUMN_FLAG_LOADED); - mServerId = c.getString(COLUMN_SERVER_ID); - mFlags = c.getInt(COLUMN_FLAGS); - // Note: mailbox key and account key not needed - they are projected for the SELECT - } - } - - private static void saveOrUpdate(EmailContent content, Context context) { - if (content.isSaved()) { - content.update(context, content.toContentValues()); - } else { - content.save(context); - } - } - - /** - * Load the structure and body of messages not yet synced - * @param account the account we're syncing - * @param remoteFolder the (open) Folder we're working on - * @param unsyncedMessages an array of Message's we've got headers for - * @param toMailbox the destination mailbox we're syncing - * @throws MessagingException - */ - static void loadUnsyncedMessages(final Context context, final Account account, - Folder remoteFolder, ArrayList<Message> unsyncedMessages, final Mailbox toMailbox) - throws MessagingException { - - // 1. Divide the unsynced messages into small & large (by size) - - // TODO doing this work here (synchronously) is problematic because it prevents the UI - // from affecting the order (e.g. download a message because the user requested it.) Much - // of this logic should move out to a different sync loop that attempts to update small - // groups of messages at a time, as a background task. However, we can't just return - // (yet) because POP messages don't have an envelope yet.... - - ArrayList<Message> largeMessages = new ArrayList<Message>(); - ArrayList<Message> smallMessages = new ArrayList<Message>(); - for (Message message : unsyncedMessages) { - if (message.getSize() > (MAX_SMALL_MESSAGE_SIZE)) { - largeMessages.add(message); - } else { - smallMessages.add(message); - } - } - - // 2. Download small messages - - // TODO Problems with this implementation. 1. For IMAP, where we get a real envelope, - // this is going to be inefficient and duplicate work we've already done. 2. It's going - // back to the DB for a local message that we already had (and discarded). - - // For small messages, we specify "body", which returns everything (incl. attachments) - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]), fp, - new MessageRetrievalListener() { - @Override - public void messageRetrieved(Message message) { - // Store the updated message locally and mark it fully loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, - EmailContent.Message.FLAG_LOADED_COMPLETE); - } - - @Override - public void loadAttachmentProgress(int progress) { - } - }); - - // 3. Download large messages. We ask the server to give us the message structure, - // but not all of the attachments. - fp.clear(); - fp.add(FetchProfile.Item.STRUCTURE); - remoteFolder.fetch(largeMessages.toArray(new Message[largeMessages.size()]), fp, null); - for (Message message : largeMessages) { - if (message.getBody() == null) { - // POP doesn't support STRUCTURE mode, so we'll just do a partial download - // (hopefully enough to see some/all of the body) and mark the message for - // further download. - fp.clear(); - fp.add(FetchProfile.Item.BODY_SANE); - // TODO a good optimization here would be to make sure that all Stores set - // the proper size after this fetch and compare the before and after size. If - // they equal we can mark this SYNCHRONIZED instead of PARTIALLY_SYNCHRONIZED - remoteFolder.fetch(new Message[] { message }, fp, null); - - // Store the partially-loaded message and mark it partially loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, - EmailContent.Message.FLAG_LOADED_PARTIAL); - } else { - // We have a structure to deal with, from which - // we can pull down the parts we want to actually store. - // Build a list of parts we are interested in. Text parts will be downloaded - // right now, attachments will be left for later. - ArrayList<Part> viewables = new ArrayList<Part>(); - ArrayList<Part> attachments = new ArrayList<Part>(); - MimeUtility.collectParts(message, viewables, attachments); - // Download the viewables immediately - for (Part part : viewables) { - fp.clear(); - fp.add(part); - // TODO what happens if the network connection dies? We've got partial - // messages with incorrect status stored. - remoteFolder.fetch(new Message[] { message }, fp, null); - } - // Store the updated message locally and mark it fully loaded - Utilities.copyOneMessageToProvider(context, message, account, toMailbox, - EmailContent.Message.FLAG_LOADED_COMPLETE); - } - } - - } - - public static void downloadFlagAndEnvelope(final Context context, final Account account, - final Mailbox mailbox, Folder remoteFolder, ArrayList<Message> unsyncedMessages, - HashMap<String, LocalMessageInfo> localMessageMap, final ArrayList<Long> unseenMessages) - throws MessagingException { - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.FLAGS); - fp.add(FetchProfile.Item.ENVELOPE); - - final HashMap<String, LocalMessageInfo> localMapCopy; - if (localMessageMap != null) - localMapCopy = new HashMap<String, LocalMessageInfo>(localMessageMap); - else { - localMapCopy = new HashMap<String, LocalMessageInfo>(); - } - - remoteFolder.fetch(unsyncedMessages.toArray(new Message[0]), fp, - new MessageRetrievalListener() { - @Override - public void messageRetrieved(Message message) { - try { - // Determine if the new message was already known (e.g. partial) - // And create or reload the full message info - LocalMessageInfo localMessageInfo = - localMapCopy.get(message.getUid()); - EmailContent.Message localMessage = null; - if (localMessageInfo == null) { - localMessage = new EmailContent.Message(); - } else { - localMessage = EmailContent.Message.restoreMessageWithId( - context, localMessageInfo.mId); - } - - if (localMessage != null) { - try { - // Copy the fields that are available into the message - LegacyConversions.updateMessageFields(localMessage, - message, account.mId, mailbox.mId); - // Commit the message to the local store - saveOrUpdate(localMessage, context); - // Track the "new" ness of the downloaded message - if (!message.isSet(Flag.SEEN) && unseenMessages != null) { - unseenMessages.add(localMessage.mId); - } - } catch (MessagingException me) { - Log.e(Logging.LOG_TAG, - "Error while copying downloaded message." + me); - } - - } - } - catch (Exception e) { - Log.e(Logging.LOG_TAG, - "Error while storing downloaded message." + e.toString()); - } - } - - @Override - public void loadAttachmentProgress(int progress) { - } - }); - - } - - /** - * Synchronizer for IMAP. - * - * TODO Break this method up into smaller chunks. - * - * @param account the account to sync - * @param mailbox the mailbox to sync - * @return results of the sync pass - * @throws MessagingException - */ - private static void synchronizeMailboxGeneric(final Context context, - final Account account, final Mailbox mailbox) throws MessagingException { - - /* - * A list of IDs for messages that were downloaded and did not have the seen flag set. - * This serves as the "true" new message count reported to the user via notification. - */ - final ArrayList<Long> unseenMessages = new ArrayList<Long>(); - - ContentResolver resolver = context.getContentResolver(); - - // 0. We do not ever sync DRAFTS or OUTBOX (down or up) - if (mailbox.mType == Mailbox.TYPE_DRAFTS || mailbox.mType == Mailbox.TYPE_OUTBOX) { - return; - } - - // 1. Get the message list from the local store and create an index of the uids - - Cursor localUidCursor = null; - HashMap<String, LocalMessageInfo> localMessageMap = new HashMap<String, LocalMessageInfo>(); - - try { - localUidCursor = resolver.query( - EmailContent.Message.CONTENT_URI, - LocalMessageInfo.PROJECTION, - EmailContent.MessageColumns.ACCOUNT_KEY + "=?" + - " AND " + MessageColumns.MAILBOX_KEY + "=?", - new String[] { - String.valueOf(account.mId), - String.valueOf(mailbox.mId) - }, - null); - while (localUidCursor.moveToNext()) { - LocalMessageInfo info = new LocalMessageInfo(localUidCursor); - localMessageMap.put(info.mServerId, info); - } - } finally { - if (localUidCursor != null) { - localUidCursor.close(); - } - } - - // 2. Open the remote folder and create the remote folder if necessary - - Store remoteStore = Store.getInstance(account, context); - // The account might have been deleted - if (remoteStore == null) return; - Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId); - - /* - * If the folder is a "special" folder we need to see if it exists - * on the remote server. It if does not exist we'll try to create it. If we - * can't create we'll abort. This will happen on every single Pop3 folder as - * designed and on Imap folders during error conditions. This allows us - * to treat Pop3 and Imap the same in this code. - */ - if (mailbox.mType == Mailbox.TYPE_TRASH || mailbox.mType == Mailbox.TYPE_SENT - || mailbox.mType == Mailbox.TYPE_DRAFTS) { - if (!remoteFolder.exists()) { - if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { - return; - } - } - } - - // 3, Open the remote folder. This pre-loads certain metadata like message count. - remoteFolder.open(OpenMode.READ_WRITE); - - // 4. Trash any remote messages that are marked as trashed locally. - // TODO - this comment was here, but no code was here. - - // 5. Get the remote message count. - int remoteMessageCount = remoteFolder.getMessageCount(); - ContentValues values = new ContentValues(); - values.put(MailboxColumns.TOTAL_COUNT, remoteMessageCount); - mailbox.update(context, values); - - // 6. Determine the limit # of messages to download - int visibleLimit = mailbox.mVisibleLimit; - if (visibleLimit <= 0) { - visibleLimit = Email.VISIBLE_LIMIT_DEFAULT; - } - - // 7. Create a list of messages to download - Message[] remoteMessages = new Message[0]; - final ArrayList<Message> unsyncedMessages = new ArrayList<Message>(); - HashMap<String, Message> remoteUidMap = new HashMap<String, Message>(); - - if (remoteMessageCount > 0) { - /* - * Message numbers start at 1. - */ - int remoteStart = Math.max(0, remoteMessageCount - visibleLimit) + 1; - int remoteEnd = remoteMessageCount; - remoteMessages = remoteFolder.getMessages(remoteStart, remoteEnd, null); - // TODO Why are we running through the list twice? Combine w/ for loop below - for (Message message : remoteMessages) { - remoteUidMap.put(message.getUid(), message); - } - - /* - * Get a list of the messages that are in the remote list but not on the - * local store, or messages that are in the local store but failed to download - * on the last sync. These are the new messages that we will download. - * Note, we also skip syncing messages which are flagged as "deleted message" sentinels, - * because they are locally deleted and we don't need or want the old message from - * the server. - */ - for (Message message : remoteMessages) { - LocalMessageInfo localMessage = localMessageMap.get(message.getUid()); - // localMessage == null -> message has never been created (not even headers) - // mFlagLoaded = UNLOADED -> message created, but none of body loaded - // mFlagLoaded = PARTIAL -> message created, a "sane" amt of body has been loaded - // mFlagLoaded = COMPLETE -> message body has been completely loaded - // mFlagLoaded = DELETED -> message has been deleted - // Only the first two of these are "unsynced", so let's retrieve them - if (localMessage == null || - (localMessage.mFlagLoaded == EmailContent.Message.FLAG_LOADED_UNLOADED)) { - unsyncedMessages.add(message); - } - } - } - - // 8. Download basic info about the new/unloaded messages (if any) - /* - * Fetch the flags and envelope only of the new messages. This is intended to get us - * critical data as fast as possible, and then we'll fill in the details. - */ - if (unsyncedMessages.size() > 0) { - downloadFlagAndEnvelope(context, account, mailbox, remoteFolder, unsyncedMessages, - localMessageMap, unseenMessages); - } - - // 9. Refresh the flags for any messages in the local store that we didn't just download. - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.FLAGS); - remoteFolder.fetch(remoteMessages, fp, null); - boolean remoteSupportsSeen = false; - boolean remoteSupportsFlagged = false; - boolean remoteSupportsAnswered = false; - for (Flag flag : remoteFolder.getPermanentFlags()) { - if (flag == Flag.SEEN) { - remoteSupportsSeen = true; - } - if (flag == Flag.FLAGGED) { - remoteSupportsFlagged = true; - } - if (flag == Flag.ANSWERED) { - remoteSupportsAnswered = true; - } - } - // Update SEEN/FLAGGED/ANSWERED (star) flags (if supported remotely - e.g. not for POP3) - if (remoteSupportsSeen || remoteSupportsFlagged || remoteSupportsAnswered) { - for (Message remoteMessage : remoteMessages) { - LocalMessageInfo localMessageInfo = localMessageMap.get(remoteMessage.getUid()); - if (localMessageInfo == null) { - continue; - } - boolean localSeen = localMessageInfo.mFlagRead; - boolean remoteSeen = remoteMessage.isSet(Flag.SEEN); - boolean newSeen = (remoteSupportsSeen && (remoteSeen != localSeen)); - boolean localFlagged = localMessageInfo.mFlagFavorite; - boolean remoteFlagged = remoteMessage.isSet(Flag.FLAGGED); - boolean newFlagged = (remoteSupportsFlagged && (localFlagged != remoteFlagged)); - int localFlags = localMessageInfo.mFlags; - boolean localAnswered = (localFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0; - boolean remoteAnswered = remoteMessage.isSet(Flag.ANSWERED); - boolean newAnswered = (remoteSupportsAnswered && (localAnswered != remoteAnswered)); - if (newSeen || newFlagged || newAnswered) { - Uri uri = ContentUris.withAppendedId( - EmailContent.Message.CONTENT_URI, localMessageInfo.mId); - ContentValues updateValues = new ContentValues(); - updateValues.put(MessageColumns.FLAG_READ, remoteSeen); - updateValues.put(MessageColumns.FLAG_FAVORITE, remoteFlagged); - if (remoteAnswered) { - localFlags |= EmailContent.Message.FLAG_REPLIED_TO; - } else { - localFlags &= ~EmailContent.Message.FLAG_REPLIED_TO; - } - updateValues.put(MessageColumns.FLAGS, localFlags); - resolver.update(uri, updateValues, null, null); - } - } - } - - // 10. Remove any messages that are in the local store but no longer on the remote store. - HashSet<String> localUidsToDelete = new HashSet<String>(localMessageMap.keySet()); - localUidsToDelete.removeAll(remoteUidMap.keySet()); - for (String uidToDelete : localUidsToDelete) { - LocalMessageInfo infoToDelete = localMessageMap.get(uidToDelete); - - // Delete associated data (attachment files) - // Attachment & Body records are auto-deleted when we delete the Message record - AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, - infoToDelete.mId); - - // Delete the message itself - Uri uriToDelete = ContentUris.withAppendedId( - EmailContent.Message.CONTENT_URI, infoToDelete.mId); - resolver.delete(uriToDelete, null, null); - - // Delete extra rows (e.g. synced or deleted) - Uri syncRowToDelete = ContentUris.withAppendedId( - EmailContent.Message.UPDATED_CONTENT_URI, infoToDelete.mId); - resolver.delete(syncRowToDelete, null, null); - Uri deletERowToDelete = ContentUris.withAppendedId( - EmailContent.Message.UPDATED_CONTENT_URI, infoToDelete.mId); - resolver.delete(deletERowToDelete, null, null); - } - - loadUnsyncedMessages(context, account, remoteFolder, unsyncedMessages, mailbox); - - // 14. Clean up and report results - remoteFolder.close(false); - } - - /** - * Find messages in the updated table that need to be written back to server. - * - * Handles: - * Read/Unread - * Flagged - * Append (upload) - * Move To Trash - * Empty trash - * TODO: - * Move - * - * @param account the account to scan for pending actions - * @throws MessagingException - */ - private static void processPendingActionsSynchronous(Context context, Account account) - throws MessagingException { - TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account)); - String[] accountIdArgs = new String[] { Long.toString(account.mId) }; - - // Handle deletes first, it's always better to get rid of things first - processPendingDeletesSynchronous(context, account, accountIdArgs); - } - - /** - * Scan for messages that are in the Message_Deletes table, look for differences that - * we can deal with, and do the work. - * - * @param account - * @param resolver - * @param accountIdArgs - */ - private static void processPendingDeletesSynchronous(Context context, Account account, - String[] accountIdArgs) { - Cursor deletes = context.getContentResolver().query( - EmailContent.Message.DELETED_CONTENT_URI, - EmailContent.Message.CONTENT_PROJECTION, - EmailContent.MessageColumns.ACCOUNT_KEY + "=?", accountIdArgs, - EmailContent.MessageColumns.MAILBOX_KEY); - try { - // loop through messages marked as deleted - while (deletes.moveToNext()) { - EmailContent.Message oldMessage = - EmailContent.getContent(deletes, EmailContent.Message.class); - - // Finally, delete the update - Uri uri = ContentUris.withAppendedId(EmailContent.Message.DELETED_CONTENT_URI, - oldMessage.mId); - context.getContentResolver().delete(uri, null, null); - } - } finally { - deletes.close(); - } - } -}
\ No newline at end of file diff --git a/src/com/android/email/service/PopImapSyncAdapterService.java b/src/com/android/email/service/PopImapSyncAdapterService.java index 627290694..ac47bbab5 100644 --- a/src/com/android/email/service/PopImapSyncAdapterService.java +++ b/src/com/android/email/service/PopImapSyncAdapterService.java @@ -16,32 +16,24 @@ package com.android.email.service; +import android.accounts.Account; import android.accounts.OperationCanceledException; import android.app.Service; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SyncResult; import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.util.Log; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.provider.Account; +import com.android.email.Controller; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.AccountColumns; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.EmailServiceProxy; - -import java.util.ArrayList; public class PopImapSyncAdapterService extends Service { private static final String TAG = "PopImapSyncAdapterService"; @@ -61,7 +53,7 @@ public class PopImapSyncAdapterService extends Service { } @Override - public void onPerformSync(android.accounts.Account account, Bundle extras, + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { try { PopImapSyncAdapterService.performSync(mContext, account, extras, @@ -86,137 +78,29 @@ public class PopImapSyncAdapterService extends Service { return sSyncAdapter.getSyncAdapterBinder(); } - private static void sync(Context context, long mailboxId, SyncResult syncResult, - boolean uiRefresh) { - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); - if (mailbox == null) return; - Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey); - if (account == null) return; - ContentResolver resolver = context.getContentResolver(); - String protocol = account.getProtocol(context); - if ((mailbox.mType != Mailbox.TYPE_OUTBOX) && !mailbox.loadsFromServer(protocol)) { - // This is an update to a message in a non-syncing mailbox; delete this from the - // updates table and return - resolver.delete(Message.UPDATED_CONTENT_URI, Message.MAILBOX_KEY + "=?", - new String[] {Long.toString(mailbox.mId)}); - return; - } - Log.d(TAG, "Mailbox: " + mailbox.mDisplayName); - - Uri mailboxUri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); - ContentValues values = new ContentValues(); - // Set mailbox sync state - values.put(Mailbox.UI_SYNC_STATUS, - uiRefresh ? EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND); - resolver.update(mailboxUri, values, null, null); - try { - try { - if (mailbox.mType == Mailbox.TYPE_OUTBOX) { - EmailServiceStub.sendMailImpl(context, account.mId); - } else if (protocol.equals(HostAuth.SCHEME_IMAP)) { - ImapService.synchronizeMailboxSynchronous(context, account, mailbox); - } else { - Pop3Service.synchronizeMailboxSynchronous(context, account, mailbox); - } - } catch (MessagingException e) { - int cause = e.getExceptionType(); - switch(cause) { - case MessagingException.IOERROR: - syncResult.stats.numIoExceptions++; - break; - case MessagingException.AUTHENTICATION_FAILED: - syncResult.stats.numAuthExceptions++; - break; - } - } - } finally { - // Always clear our sync state - values.put(Mailbox.UI_SYNC_STATUS, EmailContent.SYNC_STATUS_NONE); - resolver.update(mailboxUri, values, null, null); - } - } - /** * Partial integration with system SyncManager; we initiate manual syncs upon request */ - private static void performSync(Context context, android.accounts.Account account, - Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) - throws OperationCanceledException { - // Find an EmailProvider account with the Account's email address - Cursor c = null; - try { - c = provider.query(com.android.emailcommon.provider.Account.CONTENT_URI, - Account.CONTENT_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", - new String[] {account.name}, null); - if (c != null && c.moveToNext()) { - Account acct = new Account(); - acct.restore(c); - if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { - Log.d(TAG, "Upload sync request for " + acct.mDisplayName); - // See if any boxes have mail... - Cursor updatesCursor = provider.query(Message.UPDATED_CONTENT_URI, - new String[] {Message.MAILBOX_KEY}, - Message.ACCOUNT_KEY + "=?", - new String[] {Long.toString(acct.mId)}, - null); - if ((updatesCursor == null) || (updatesCursor.getCount() == 0)) return; - ArrayList<Long> mailboxesToUpdate = new ArrayList<Long>(); - while (updatesCursor.moveToNext()) { - Long mailboxId = updatesCursor.getLong(0); - if (!mailboxesToUpdate.contains(mailboxId)) { - mailboxesToUpdate.add(mailboxId); - } - } - for (long mailboxId: mailboxesToUpdate) { - sync(context, mailboxId, syncResult, false); - } - } else { - Log.d(TAG, "Sync request for " + acct.mDisplayName); - Log.d(TAG, extras.toString()); - long mailboxId = extras.getLong(EmailServiceStub.SYNC_EXTRA_MAILBOX_ID, - Mailbox.NO_MAILBOX); - boolean isInbox = false; - if (mailboxId == Mailbox.NO_MAILBOX) { - mailboxId = Mailbox.findMailboxOfType(context, acct.mId, - Mailbox.TYPE_INBOX); - if (mailboxId == Mailbox.NO_MAILBOX) { - // Update folders? - EmailServiceProxy service = - EmailServiceUtils.getServiceForAccount(context, null, acct.mId); - service.updateFolderList(acct.mId); - } - isInbox = true; - } - if (mailboxId == Mailbox.NO_MAILBOX) return; - boolean uiRefresh = - extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false); - sync(context, mailboxId, syncResult, uiRefresh); - - // Outbox is a special case here - Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); - if (mailbox.mType == Mailbox.TYPE_OUTBOX) { - return; - } - - // Convert from minutes to seconds - int syncFrequency = acct.mSyncInterval * 60; - // Values < 0 are for "never" or "push"; 0 is undefined - if (syncFrequency <= 0) return; - Bundle ex = new Bundle(); - if (!isInbox) { - ex.putLong(EmailServiceStub.SYNC_EXTRA_MAILBOX_ID, mailboxId); - } - Log.d(TAG, "Setting periodic sync for " + acct.mDisplayName + ": " + - syncFrequency + " seconds"); - ContentResolver.addPeriodicSync(account, authority, ex, syncFrequency); + private static void performSync(Context context, Account account, Bundle extras, + String authority, ContentProviderClient provider, SyncResult syncResult) + throws OperationCanceledException { + if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) { + String emailAddress = account.name; + // Find an EmailProvider account with the Account's email address + Cursor c = context.getContentResolver().query( + com.android.emailcommon.provider.Account.CONTENT_URI, + EmailContent.ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", + new String[] {emailAddress}, null); + if (c.moveToNext()) { + // If we have one, find the inbox and start it syncing + long accountId = c.getLong(EmailContent.ID_PROJECTION_COLUMN); + long mailboxId = Mailbox.findMailboxOfType(context, accountId, + Mailbox.TYPE_INBOX); + if (mailboxId > 0) { + Log.d(TAG, "Starting manual sync for account " + emailAddress); + Controller.getInstance(context).updateMailbox(accountId, mailboxId, false); } } - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (c != null) { - c.close(); - } } } }
\ No newline at end of file diff --git a/tests/src/com/android/email/ControllerProviderOpsTests.java b/tests/src/com/android/email/ControllerProviderOpsTests.java index cd74c848f..a0beb27c1 100644 --- a/tests/src/com/android/email/ControllerProviderOpsTests.java +++ b/tests/src/com/android/email/ControllerProviderOpsTests.java @@ -64,6 +64,12 @@ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> ContentCache.invalidateAllCaches(); } + @Override + public void tearDown() throws Exception { + super.tearDown(); + mTestController.cleanupForTest(); + } + /** * Lightweight subclass of the Controller class allows injection of mock context */ @@ -424,8 +430,7 @@ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> long message4Id = message.mId; // Now wipe account 1's data - Uri uri = EmailProvider.uiUri("uiaccount", account1Id); - mProviderContext.getContentResolver().delete(uri, null, null); + mTestController.deleteSyncedDataSync(account1Id); // Confirm: Mailboxes gone (except account box), all messages gone, account survives assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box1Id)); @@ -483,6 +488,44 @@ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> return hostAuth; } + public void testIsMessagingController() { + Account account1 = ProviderTestUtils.setupAccount("account1", false, + mProviderContext); + account1.mHostAuthRecv = setupSimpleHostAuth("eas"); + account1.save(mProviderContext); + assertFalse(mTestController.isMessagingController(account1)); + Account account2 = ProviderTestUtils.setupAccount("account2", false, + mProviderContext); + account2.mHostAuthRecv = setupSimpleHostAuth("imap"); + account2.save(mProviderContext); + assertTrue(mTestController.isMessagingController(account2)); + Account account3 = ProviderTestUtils.setupAccount("account3", false, + mProviderContext); + account3.mHostAuthRecv = setupSimpleHostAuth("pop3"); + account3.save(mProviderContext); + assertTrue(mTestController.isMessagingController(account3)); + Account account4 = ProviderTestUtils.setupAccount("account4", false, + mProviderContext); + account4.mHostAuthRecv = setupSimpleHostAuth("smtp"); + account4.save(mProviderContext); + assertFalse(mTestController.isMessagingController(account4)); + // There should be values for all of these accounts in the legacy map + assertNotNull(mTestController.mLegacyControllerMap.get(account1.mId)); + assertNotNull(mTestController.mLegacyControllerMap.get(account2.mId)); + assertNotNull(mTestController.mLegacyControllerMap.get(account3.mId)); + assertNotNull(mTestController.mLegacyControllerMap.get(account4.mId)); + // The map should have the expected values + assertFalse(mTestController.mLegacyControllerMap.get(account1.mId)); + assertTrue(mTestController.mLegacyControllerMap.get(account2.mId)); + assertTrue(mTestController.mLegacyControllerMap.get(account3.mId)); + assertFalse(mTestController.mLegacyControllerMap.get(account4.mId)); + // This second pass should pull values from the cache + assertFalse(mTestController.isMessagingController(account1)); + assertTrue(mTestController.isMessagingController(account2)); + assertTrue(mTestController.isMessagingController(account3)); + assertFalse(mTestController.isMessagingController(account4)); + } + /** * TODO: releasing associated data (e.g. attachments, embedded images) */ diff --git a/tests/src/com/android/email/GroupMessagingListenerUnitTests.java b/tests/src/com/android/email/GroupMessagingListenerUnitTests.java new file mode 100644 index 000000000..bf950cd01 --- /dev/null +++ b/tests/src/com/android/email/GroupMessagingListenerUnitTests.java @@ -0,0 +1,77 @@ +/* + * 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 com.android.email; + +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +/** + * This is a series of unit tests for the GroupMessagingListener class. + */ +@SmallTest +public class GroupMessagingListenerUnitTests extends TestCase { + + /** + * Tests adding and removing elements from the listener + */ + public void testAddRemove() { + GroupMessagingListener groupListener = new GroupMessagingListener(); + + MessagingListener listener1 = new MessagingListener(); + MessagingListener listener2 = new MessagingListener(); + + groupListener.addListener(listener1); + groupListener.addListener(listener2); + + groupListener.removeListener(listener1); + groupListener.removeListener(listener2); + } + + /** + * Tests isActiveListener() + */ + public void testIsActiveListener() { + GroupMessagingListener groupListener = new GroupMessagingListener(); + + MessagingListener listener1 = new MessagingListener(); + MessagingListener listener2 = new MessagingListener(); + + assertFalse(groupListener.isActiveListener(listener1)); + assertFalse(groupListener.isActiveListener(listener2)); + + groupListener.addListener(listener1); + assertTrue(groupListener.isActiveListener(listener1)); + assertFalse(groupListener.isActiveListener(listener2)); + + groupListener.addListener(listener2); + assertTrue(groupListener.isActiveListener(listener1)); + assertTrue(groupListener.isActiveListener(listener2)); + + groupListener.removeListener(listener1); + assertFalse(groupListener.isActiveListener(listener1)); + assertTrue(groupListener.isActiveListener(listener2)); + + groupListener.removeListener(listener2); + assertFalse(groupListener.isActiveListener(listener1)); + assertFalse(groupListener.isActiveListener(listener2)); + } + + /** + * TODO: Test that if you add a set of listeners, they will be called + */ +} diff --git a/tests/src/com/android/email/MessagingControllerUnitTests.java b/tests/src/com/android/email/MessagingControllerUnitTests.java new file mode 100644 index 000000000..c4372b8c3 --- /dev/null +++ b/tests/src/com/android/email/MessagingControllerUnitTests.java @@ -0,0 +1,85 @@ +/* + * 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 com.android.email; + +import com.android.emailcommon.mail.MockFolder; +import com.android.emailcommon.provider.Account; + +import android.content.ContentUris; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * This is a series of unit tests for the MessagingController class. + * + * Technically these are functional because they use the underlying provider framework. + */ +@SmallTest +public class MessagingControllerUnitTests extends AndroidTestCase { + + private long mAccountId; + private Account mAccount; + + /** + * Delete any dummy accounts we set up for this test + */ + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (mAccount != null) { + Uri uri = ContentUris.withAppendedId( + Account.CONTENT_URI, mAccountId); + getContext().getContentResolver().delete(uri, null, null); + } + } + + /** + * MockFolder allows setting and retrieving role & name + */ + private static class MyMockFolder extends MockFolder { + private FolderRole mRole; + private String mName; + + public MyMockFolder(FolderRole role, String name) { + mRole = role; + mName = name; + } + + @Override + public String getName() { + return mName; + } + + @Override + public FolderRole getRole() { + return mRole; + } + } + + /** + * Create a dummy account with minimal fields + */ + private void createTestAccount() { + mAccount = new Account(); + mAccount.save(getContext()); + + mAccountId = mAccount.mId; + } + +} diff --git a/tests/src/com/android/email/NotificationControllerTest.java b/tests/src/com/android/email/NotificationControllerTest.java index 0936eac38..ea5169fe3 100644 --- a/tests/src/com/android/email/NotificationControllerTest.java +++ b/tests/src/com/android/email/NotificationControllerTest.java @@ -213,7 +213,7 @@ public class NotificationControllerTest extends AndroidTestCase { Mailbox b1 = ProviderTestUtils.setupMailbox("inbox", a1.mId, true, c, Mailbox.TYPE_INBOX); Message m1 = ProviderTestUtils.setupMessage("message", a1.mId, b1.mId, true, true, c); - n = mTarget.createNewMessageNotification(b1.mId, m1.mId, 1, 1); + n = mTarget.createNewMessageNotification(a1.mId, b1.mId, m1.mId, 1, 1); assertEquals(R.drawable.stat_notify_email_generic, n.icon); assertEquals(mMockClock.mTime, n.when); @@ -223,7 +223,7 @@ public class NotificationControllerTest extends AndroidTestCase { // TODO Check content -- how? // Case 2: 1 account, 2 unseen message - n = mTarget.createNewMessageNotification(b1.mId, m1.mId, 2, 2); + n = mTarget.createNewMessageNotification(a1.mId, b1.mId, m1.mId, 2, 2); assertEquals(R.drawable.stat_notify_email_generic, n.icon); assertEquals(mMockClock.mTime, n.when); @@ -247,7 +247,7 @@ public class NotificationControllerTest extends AndroidTestCase { m1.save(c); // This shouldn't crash. - n = mTarget.createNewMessageNotification(b1.mId, m1.mId, 1, 1); + n = mTarget.createNewMessageNotification(a1.mId, b1.mId, m1.mId, 1, 1); // Minimum test for the result assertEquals(R.drawable.stat_notify_email_generic, n.icon); diff --git a/tests/src/com/android/email/RefreshManagerTest.java b/tests/src/com/android/email/RefreshManagerTest.java index 500279a9c..853c354b1 100644 --- a/tests/src/com/android/email/RefreshManagerTest.java +++ b/tests/src/com/android/email/RefreshManagerTest.java @@ -16,14 +16,16 @@ package com.android.email; +import com.android.email.provider.ProviderTestUtils; +import com.android.emailcommon.Logging; +import com.android.emailcommon.mail.MessagingException; +import com.android.emailcommon.provider.Account; + import android.content.Context; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; -import com.android.emailcommon.Logging; -import com.android.emailcommon.mail.MessagingException; - import junit.framework.Assert; @LargeTest @@ -60,6 +62,12 @@ public class RefreshManagerTest extends InstrumentationTestCase { mTarget.registerListener(mListener); } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + mController.cleanupForTest(); + } + public void testRegisterUnregisterListener() { // mListener is already registered assertEquals(1, mTarget.getListenersForTest().size()); @@ -309,6 +317,95 @@ public class RefreshManagerTest extends InstrumentationTestCase { assertFalse(mTarget.isRefreshingAnyMessageListForTest()); } + public void testSendPendingMessages() { + // request sending for account 1 + assertTrue(mTarget.sendPendingMessages(ACCOUNT_1)); + + assertTrue(mListener.mCalledOnRefreshStatusChanged); + assertFalse(mListener.mCalledOnConnectionError); + assertEquals(ACCOUNT_1, mListener.mAccountId); + assertEquals(-1, mListener.mMailboxId); + mListener.reset(); + assertTrue(mController.mCalledSendPendingMessages); + assertEquals(ACCOUNT_1, mController.mAccountId); + assertEquals(-1, mController.mMailboxId); + mController.reset(); + + // request sending for account 2 + assertTrue(mTarget.sendPendingMessages(ACCOUNT_2)); + + assertFalse(mListener.mCalledOnConnectionError); + assertEquals(ACCOUNT_2, mListener.mAccountId); + assertEquals(-1, mListener.mMailboxId); + mListener.reset(); + assertTrue(mController.mCalledSendPendingMessages); + assertEquals(ACCOUNT_2, mController.mAccountId); + assertEquals(-1, mController.mMailboxId); + mController.reset(); + + // Sending start for account 1... + // batch send start. (message id == -1, progress == 0) + mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 0); + + assertFalse(mListener.mCalledOnConnectionError); + mListener.reset(); + + // Per message callback + mController.mListener.sendMailCallback(null, ACCOUNT_1, 100, 0); + mController.mListener.sendMailCallback(null, ACCOUNT_1, 101, 0); + + assertFalse(mListener.mCalledOnConnectionError); + mListener.reset(); + + // Exception -- first error will be reported. + mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 102, 0); + + assertTrue(mListener.mCalledOnConnectionError); + assertEquals(MessagingExceptionStrings.getErrorString(mContext, EXCEPTION), + mListener.mMessage); + mListener.reset(); + + // Exception again -- no more error callbacks + mController.mListener.sendMailCallback(null, ACCOUNT_1, 103, 0); + mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 104, 0); + + assertFalse(mListener.mCalledOnConnectionError); + mListener.reset(); + + // Done. + Log.w(Logging.LOG_TAG, "" + mController.mListener.getClass()); + mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 100); + + assertFalse(mListener.mCalledOnConnectionError); + mListener.reset(); + } + + public void testSendPendingMessagesForAllAccounts() throws Throwable { + Account acct1 = ProviderTestUtils.setupAccount("acct1", true, mProviderContext); + Account acct2 = ProviderTestUtils.setupAccount("acct2", true, mProviderContext); + + // AsyncTask needs to be created on the UI thread. + runTestOnUiThread(new Runnable() { + @Override + public void run() { + mTarget.sendPendingMessagesForAllAccounts(); + } + }); + + // sendPendingMessagesForAllAccounts uses Utility.ForEachAccount, which has it's own test, + // so we don't really have to check everything. + // Here, we just check if sendPendingMessages() has been called at least for once, + // which is a enough check. + TestUtils.waitUntil(new TestUtils.Condition() { + @Override + public boolean isMet() { + // The write to this is done on the UI thread, but we're checking it here + // on the test thread, so mCalledSendPendingMessages needs to be volatile. + return mController.mCalledSendPendingMessages; + } + }, WAIT_UNTIL_TIMEOUT_SECONDS); + } + public void testLoadMoreMessages() { final long ACCOUNT_ID = 123; final long MAILBOX_ID = 456; @@ -325,6 +422,7 @@ public class RefreshManagerTest extends InstrumentationTestCase { private static class MockController extends Controller { public volatile long mAccountId = -1; public volatile long mMailboxId = -1; + public volatile boolean mCalledSendPendingMessages; public volatile boolean mCalledUpdateMailbox; public volatile boolean mCalledUpdateMailboxList; public volatile boolean mCalledLoadMoreMessages; @@ -337,12 +435,14 @@ public class RefreshManagerTest extends InstrumentationTestCase { public void reset() { mAccountId = -1; mMailboxId = -1; + mCalledSendPendingMessages = false; mCalledUpdateMailbox = false; mCalledUpdateMailboxList = false; } @Override public void sendPendingMessages(long accountId) { + mCalledSendPendingMessages = true; mAccountId = accountId; } diff --git a/tests/src/com/android/email/SecurityPolicyTests.java b/tests/src/com/android/email/SecurityPolicyTests.java index 1a9731be1..ed264859a 100755..100644 --- a/tests/src/com/android/email/SecurityPolicyTests.java +++ b/tests/src/com/android/email/SecurityPolicyTests.java @@ -142,7 +142,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a3 = ProviderTestUtils.setupAccount("sec-3", true, mMockContext); Policy p3ain = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, a3, p3ain, null); + Policy.setAccountPolicy(mMockContext, a3, p3ain, null); Policy p3aout = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p3aout); assertEquals(p3ain, p3aout); @@ -150,7 +150,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { // Repeat that test with fully-populated policies Policy p3bin = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, a3, p3bin, null); + Policy.setAccountPolicy(mMockContext, a3, p3bin, null); Policy p3bout = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p3bout); assertEquals(p3bin, p3bout); @@ -166,7 +166,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Policy p4in = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7, false, true); Account a4 = ProviderTestUtils.setupAccount("sec-4", true, mMockContext); - SecurityPolicy.setAccountPolicy(mMockContext, a4, p4in, null); + Policy.setAccountPolicy(mMockContext, a4, p4in, null); Policy p4out = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p4out); assertEquals(20, p4out.mPasswordMinLength); @@ -192,7 +192,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Policy p5in = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0, true, false); Account a5 = ProviderTestUtils.setupAccount("sec-5", true, mMockContext); - SecurityPolicy.setAccountPolicy(mMockContext, a5, p5in, null); + Policy.setAccountPolicy(mMockContext, a5, p5in, null); Policy p5out = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p5out); assertEquals(20, p5out.mPasswordMinLength); @@ -236,17 +236,17 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { long accountId = account.mId; Policy initial = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, account, initial, null); + Policy.setAccountPolicy(mMockContext, accountId, initial, null); long oldKey = assertAccountPolicyConsistent(account.mId, 0); Policy updated = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, account, updated, null); + Policy.setAccountPolicy(mMockContext, accountId, updated, null); oldKey = assertAccountPolicyConsistent(account.mId, oldKey); // Remove the policy - SecurityPolicy.clearAccountPolicy( + Policy.clearAccountPolicy( mMockContext, Account.restoreAccountWithId(mMockContext, accountId)); assertNull("old policy not cleaned up", Policy.restorePolicyWithId(mMockContext, oldKey)); @@ -306,15 +306,15 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a1 = ProviderTestUtils.setupAccount("disable-1", true, mMockContext); Policy p1 = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, a1, p1, "security-sync-key-1"); + Policy.setAccountPolicy(mMockContext, a1, p1, "security-sync-key-1"); Account a2 = ProviderTestUtils.setupAccount("disable-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0, false, false); - SecurityPolicy.setAccountPolicy(mMockContext, a2, p2, "security-sync-key-2"); + Policy.setAccountPolicy(mMockContext, a2, p2, "security-sync-key-2"); Account a3 = ProviderTestUtils.setupAccount("disable-3", true, mMockContext); - SecurityPolicy.clearAccountPolicy(mMockContext, a3); + Policy.clearAccountPolicy(mMockContext, a3); mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); @@ -359,7 +359,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { ProviderTestUtils.setupAccount("expiring-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0, false, true); - SecurityPolicy.setAccountPolicy(mMockContext, a2, p2, null); + Policy.setAccountPolicy(mMockContext, a2, p2, null); // The expiring account should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); @@ -369,7 +369,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a3 = ProviderTestUtils.setupAccount("expiring-3", true, mMockContext); Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0, false, true); - SecurityPolicy.setAccountPolicy(mMockContext, a3, p3, null); + Policy.setAccountPolicy(mMockContext, a3, p3, null); // The original expiring account (a2) should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); @@ -379,7 +379,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a4 = ProviderTestUtils.setupAccount("expiring-4", true, mMockContext); Policy p4 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0, false, true); - SecurityPolicy.setAccountPolicy(mMockContext, a4, p4, null); + Policy.setAccountPolicy(mMockContext, a4, p4, null); // The new expiring account (a4) should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); @@ -409,7 +409,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a2 = ProviderTestUtils.setupAccount("expired-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0, false, true); - SecurityPolicy.setAccountPolicy(mMockContext, a2, p2, null); + Policy.setAccountPolicy(mMockContext, a2, p2, null); // Add a mailbox & messages to each account long account1Id = a1.mId; @@ -435,7 +435,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { Account a3 = ProviderTestUtils.setupAccount("expired-3", true, mMockContext); Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0, false, true); - SecurityPolicy.setAccountPolicy(mMockContext, a3, p3, null); + Policy.setAccountPolicy(mMockContext, a3, p3, null); // Add mailbox & messages to 3rd account long account3Id = a3.mId; @@ -467,6 +467,38 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { } /** + * Test the code that clears unsupported policies + * TODO inject a mock DPM so we can directly control & test all cases, no matter what device + */ + public void testClearUnsupportedPolicies() { + Policy p1 = + setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false); + Policy p2 = + setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true, false); + + mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); + DevicePolicyManager dpm = mSecurityPolicy.getDPM(); + boolean hasEncryption = + dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED; + + Policy p1Result = mSecurityPolicy.clearUnsupportedPolicies(p1); + Policy p2Result = mSecurityPolicy.clearUnsupportedPolicies(p2); + + // No changes expected when encryptionRequested was false + assertEquals(p1, p1Result); + if (hasEncryption) { + // No changes expected + assertEquals(p2, p2Result); + } else { + // If encryption is unsupported, encryption policy bits are cleared + Policy policyExpect = + setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, + false); + assertEquals(policyExpect, p2Result); + } + } + + /** * Test the code that converts from exchange-style quality to DPM/Lockscreen style quality. */ public void testGetDPManagerPasswordQuality() { diff --git a/tests/src/com/android/email/activity/MailboxFinderTest.java b/tests/src/com/android/email/activity/MailboxFinderTest.java index 1eff6e420..6087081db 100644 --- a/tests/src/com/android/email/activity/MailboxFinderTest.java +++ b/tests/src/com/android/email/activity/MailboxFinderTest.java @@ -77,6 +77,7 @@ public class MailboxFinderTest extends InstrumentationTestCase { // MailboxFinder should unregister its listener when closed. checkControllerResultRemoved(mMockController); } + mMockController.cleanupForTest(); Controller.injectMockControllerForTest(null); } diff --git a/tests/src/com/android/email/provider/PolicyTests.java b/tests/src/com/android/email/provider/PolicyTests.java index e18b2c9e4..2903c45b4 100755..100644 --- a/tests/src/com/android/email/provider/PolicyTests.java +++ b/tests/src/com/android/email/provider/PolicyTests.java @@ -16,12 +16,6 @@ package com.android.email.provider; -import android.content.Context; -import android.os.Parcel; -import android.test.ProviderTestCase2; -import android.test.suitebuilder.annotation.MediumTest; - -import com.android.email.SecurityPolicy; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Attachment; @@ -30,6 +24,11 @@ import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.provider.Policy; +import android.content.Context; +import android.os.Parcel; +import android.test.ProviderTestCase2; +import android.test.suitebuilder.annotation.MediumTest; + import java.util.ArrayList; /** @@ -69,10 +68,10 @@ public class PolicyTests extends ProviderTestCase2<EmailProvider> { // Setup two accounts with policies Account account1 = ProviderTestUtils.setupAccount("acct1", true, mMockContext); Policy policy1 = new Policy(); - SecurityPolicy.setAccountPolicy(mMockContext, account1, policy1, securitySyncKey); + Policy.setAccountPolicy(mMockContext, account1, policy1, securitySyncKey); Account account2 = ProviderTestUtils.setupAccount("acct2", true, mMockContext); Policy policy2 = new Policy(); - SecurityPolicy.setAccountPolicy(mMockContext, account2, policy2, securitySyncKey); + Policy.setAccountPolicy(mMockContext, account2, policy2, securitySyncKey); // Get the accounts back from the database account1.refresh(mMockContext); account2.refresh(mMockContext); @@ -93,7 +92,7 @@ public class PolicyTests extends ProviderTestCase2<EmailProvider> { assertEquals(0, account.mPolicyKey); assertEquals(0, EmailContent.count(mMockContext, Policy.CONTENT_URI)); Policy policy = new Policy(); - SecurityPolicy.setAccountPolicy(mMockContext, account, policy, securitySyncKey); + Policy.setAccountPolicy(mMockContext, account, policy, securitySyncKey); account.refresh(mMockContext); // We should have a policyKey now assertTrue(account.mPolicyKey > 0); @@ -104,7 +103,7 @@ public class PolicyTests extends ProviderTestCase2<EmailProvider> { assertEquals(policy, dbPolicy); // The account should have the security sync key set assertEquals(securitySyncKey, account.mSecuritySyncKey); - SecurityPolicy.clearAccountPolicy(mMockContext, account); + Policy.clearAccountPolicy(mMockContext, account); account.refresh(mMockContext); // Make sure policyKey is cleared and policy is deleted assertEquals(0, account.mPolicyKey); @@ -119,12 +118,11 @@ public class PolicyTests extends ProviderTestCase2<EmailProvider> { att.mAccountKey = acct.mId; return att; } - public void testSetAttachmentFlagsForNewPolicy() { Account acct = ProviderTestUtils.setupAccount("acct1", true, mMockContext); Policy policy1 = new Policy(); policy1.mDontAllowAttachments = true; - SecurityPolicy.setAccountPolicy(mMockContext, acct, policy1, null); + Policy.setAccountPolicy(mMockContext, acct, policy1, null); Mailbox box = ProviderTestUtils.setupMailbox("box1", acct.mId, true, mMockContext); Message msg1 = ProviderTestUtils.setupMessage("message1", acct.mId, box.mId, false, false, mMockContext); diff --git a/tests/src/com/android/email/provider/ProviderTests.java b/tests/src/com/android/email/provider/ProviderTests.java index 12022c00e..ebf324399 100755..100644 --- a/tests/src/com/android/email/provider/ProviderTests.java +++ b/tests/src/com/android/email/provider/ProviderTests.java @@ -36,7 +36,6 @@ import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import com.android.email.SecurityPolicy; import com.android.email.provider.EmailProvider.AttachmentService; import com.android.emailcommon.AccountManagerTypes; import com.android.emailcommon.provider.Account; @@ -1691,7 +1690,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> { public void testCreateIndex() { String oldStr = "create index message_" + MessageColumns.TIMESTAMP + " on " + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");"; - String newStr = DBHelper.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP); + String newStr = EmailProvider.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP); assertEquals(newStr, oldStr); } @@ -2139,7 +2138,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> { // Batch update. SQLiteDatabase db = getProvider().getDatabase(mMockContext); - DBHelper.recalculateMessageCount(db); + EmailProvider.recalculateMessageCount(db); // Check message counts are valid again assertEquals(1, getMessageCount(b1.mId)); @@ -2267,7 +2266,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> { assertEquals(b34, testMailbox); SQLiteDatabase db = getProvider().getDatabase(mMockContext); - DBHelper.upgradeFromVersion17ToVersion18(db); + EmailProvider.upgradeFromVersion17ToVersion18(db); // Verify that only IMAP/POP3 mailboxes w/ a parent key of '0' are changed // Exchange mailboxes; none should be changed @@ -2489,7 +2488,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> { try { // Upgrade the database SQLiteDatabase db = getProvider().getDatabase(mMockContext); - DBHelper.upgradeFromVersion21ToVersion22(db, getContext()); + EmailProvider.upgradeFromVersion21ToVersion22(db, getContext()); // The pop3 and imap account should now be in account manager amAccountList = accountManager.getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP); @@ -2530,7 +2529,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> { Policy p2 = new Policy(); p2.save(mMockContext); Policy p3 = new Policy(); - SecurityPolicy.setAccountPolicy(mMockContext, a, p3, "0"); + Policy.setAccountPolicy(mMockContext, a.mId, p3, "0"); // We don't want anything cached or the tests below won't work. Note that // deleteUnlinked is only called by EmailProvider when the caches are empty diff --git a/tests/src/com/android/email/service/AttachmentDownloadServiceTests.java b/tests/src/com/android/email/service/AttachmentDownloadServiceTests.java index 21cc45436..4c182b9a0 100644 --- a/tests/src/com/android/email/service/AttachmentDownloadServiceTests.java +++ b/tests/src/com/android/email/service/AttachmentDownloadServiceTests.java @@ -24,6 +24,7 @@ import com.android.email.EmailConnectivityManager; import com.android.email.provider.ProviderTestUtils; import com.android.email.service.AttachmentDownloadService.DownloadRequest; import com.android.email.service.AttachmentDownloadService.DownloadSet; +import com.android.email.service.EmailServiceUtils.NullEmailService; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.Message; @@ -70,7 +71,7 @@ public class AttachmentDownloadServiceTests extends AccountTestCase { mService = new AttachmentDownloadService(); mService.mContext = mMockContext; mService.addServiceIntentForTest(mAccountId, new Intent(mContext, - EmailServiceStub.class)); + NullEmailService.class)); mAccountManagerStub = new AttachmentDownloadService.AccountManagerStub(null); mService.mAccountManagerStub = mAccountManagerStub; mService.mConnectivityManager = new MockConnectivityManager(mContext, "mock"); @@ -182,12 +183,10 @@ public class AttachmentDownloadServiceTests extends AccountTestCase { mUsableSpace = usable; } - @Override public long getTotalSpace() { return mTotalSpace; } - @Override public long getUsableSpace() { return mUsableSpace; } @@ -196,7 +195,6 @@ public class AttachmentDownloadServiceTests extends AccountTestCase { mMockFile.mLength = length; } - @Override public File[] listFiles() { return mFiles; } @@ -213,7 +211,6 @@ public class AttachmentDownloadServiceTests extends AccountTestCase { super("_mock"); } - @Override public long length() { return mLength; } diff --git a/tests/src/com/android/email/service/MailServiceTests.java b/tests/src/com/android/email/service/MailServiceTests.java new file mode 100644 index 000000000..f716e314a --- /dev/null +++ b/tests/src/com/android/email/service/MailServiceTests.java @@ -0,0 +1,331 @@ +/* + * 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.email.service; + +import android.accounts.AccountManager; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.pm.PackageManager; + +import com.android.email.AccountTestCase; +import com.android.email.Controller; +import com.android.email.provider.AccountReconciler; +import com.android.email.provider.EmailProvider; +import com.android.email.provider.ProviderTestUtils; +import com.android.email.service.MailService.AccountSyncReport; +import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.EmailContent; +import com.android.emailcommon.provider.HostAuth; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Tests of the Email provider. + * + * You can run this entire test case with: + * runtest -c com.android.email.service.MailServiceTests email + */ +public class MailServiceTests extends AccountTestCase { + + EmailProvider mProvider; + Context mMockContext; + + public MailServiceTests() { + super(); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + PackageManager pm = getContext().getPackageManager(); + pm.setComponentEnabledSetting( + new ComponentName(getContext(), EasTestAuthenticatorService.class), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + mMockContext = getMockContext(); + // Delete any test accounts we might have created earlier + deleteTemporaryAccountManagerAccounts(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + // Delete any test accounts we might have created earlier + deleteTemporaryAccountManagerAccounts(); + } + + /** + * Confirm that the test below is functional (and non-destructive) when there are + * prexisting (non-test) accounts in the account manager. + */ + public void testTestReconcileAccounts() { + Account firstAccount = null; + final String TEST_USER_ACCOUNT = "__user_account_test_1"; + Context context = getContext(); + try { + // Note: Unlike calls to setupProviderAndAccountManagerAccount(), we are creating + // *real* accounts here (not in the mock provider) + createAccountManagerAccount(TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX); + firstAccount = ProviderTestUtils.setupAccount(TEST_USER_ACCOUNT, true, context); + // Now run the test with the "user" accounts in place + testReconcileAccounts(); + } finally { + if (firstAccount != null) { + boolean firstAccountFound = false; + // delete the provider account + context.getContentResolver().delete(firstAccount.getUri(), null, null); + // delete the account manager account + android.accounts.Account[] accountManagerAccounts = AccountManager.get(context) + .getAccountsByType(TEST_ACCOUNT_TYPE); + for (android.accounts.Account accountManagerAccount: accountManagerAccounts) { + if ((TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX) + .equals(accountManagerAccount.name)) { + deleteAccountManagerAccount(accountManagerAccount); + firstAccountFound = true; + } + } + assertTrue(firstAccountFound); + } + } + } + + /** + * Note, there is some inherent risk in this test, as it creates *real* accounts in the + * system (it cannot use the mock context with the Account Manager). + */ + public void testReconcileAccounts() { + // Note that we can't use mMockContext for AccountManager interactions, as it isn't a fully + // functional Context. + Context context = getContext(); + + // Capture the baseline (account manager accounts) so we can measure the changes + // we're making, irrespective of the number of actual accounts, and not destroy them + android.accounts.Account[] baselineAccounts = + AccountManager.get(context).getAccountsByType(TEST_ACCOUNT_TYPE); + + // Set up three accounts, both in AccountManager and in EmailProvider + Account firstAccount = setupProviderAndAccountManagerAccount(getTestAccountName("1")); + setupProviderAndAccountManagerAccount(getTestAccountName("2")); + setupProviderAndAccountManagerAccount(getTestAccountName("3")); + + // Check that they're set up properly + assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); + android.accounts.Account[] accountManagerAccounts = + getAccountManagerAccounts(baselineAccounts); + assertEquals(3, accountManagerAccounts.length); + + // Delete account "2" from AccountManager + android.accounts.Account removedAccount = + makeAccountManagerAccount(getTestAccountEmailAddress("2")); + deleteAccountManagerAccount(removedAccount); + + // Confirm it's deleted + accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); + assertEquals(2, accountManagerAccounts.length); + + // Run the reconciler + ContentResolver resolver = mMockContext.getContentResolver(); + MailService.reconcileAccountsWithAccountManager(context, + makeExchangeServiceAccountList(), accountManagerAccounts, mMockContext); + + // There should now be only two EmailProvider accounts + assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); + + // Ok, now we've got two of each; let's delete a provider account + resolver.delete(ContentUris.withAppendedId(Account.CONTENT_URI, firstAccount.mId), + null, null); + // ...and then there was one + assertEquals(1, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); + + // Run the reconciler + MailService.reconcileAccountsWithAccountManager(context, + makeExchangeServiceAccountList(), accountManagerAccounts, mMockContext); + + // There should now be only one AccountManager account + accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); + assertEquals(1, accountManagerAccounts.length); + // ... and it should be account "3" + assertEquals(getTestAccountEmailAddress("3"), accountManagerAccounts[0].name); + } + + public void testReconcileDetection() { + Context context = getContext(); + List<Account> providerAccounts; + android.accounts.Account[] accountManagerAccounts; + + android.accounts.Account[] baselineAccounts = + AccountManager.get(context).getAccountsByType(TEST_ACCOUNT_TYPE); + + // Empty lists match. + providerAccounts = new ArrayList<Account>(); + accountManagerAccounts = new android.accounts.Account[0]; + assertFalse(AccountReconciler.accountsNeedReconciling( + context, providerAccounts, accountManagerAccounts)); + + setupProviderAndAccountManagerAccount(getTestAccountName("1")); + accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); + providerAccounts = makeExchangeServiceAccountList(); + + // A single account, but empty list on the other side is detected as needing reconciliation + assertTrue(AccountReconciler.accountsNeedReconciling( + context, new ArrayList<Account>(), accountManagerAccounts)); + assertTrue(AccountReconciler.accountsNeedReconciling( + context, providerAccounts, new android.accounts.Account[0])); + + // Note that no reconciliation should have happened though - we just wanted to detect it. + assertEquals(1, makeExchangeServiceAccountList().size()); + assertEquals(1, getAccountManagerAccounts(baselineAccounts).length); + + // Single account matches - no reconciliation should be detected. + assertFalse(AccountReconciler.accountsNeedReconciling( + context, providerAccounts, accountManagerAccounts)); + + // Provider: 1,2,3. AccountManager: 1, 3. + String username = getTestAccountName("2"); + ProviderTestUtils.setupAccount(getTestAccountName("2"), true, getMockContext()); + setupProviderAndAccountManagerAccount(getTestAccountName("3")); + + accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); + providerAccounts = makeExchangeServiceAccountList(); + assertTrue(AccountReconciler.accountsNeedReconciling( + context, providerAccounts, accountManagerAccounts)); + } + + + /** + * Lightweight subclass of the Controller class allows injection of mock context + */ + public static class TestController extends Controller { + + protected TestController(Context providerContext, Context systemContext) { + super(systemContext); + setProviderContext(providerContext); + } + } + + /** + * Create a simple HostAuth with protocol + */ + private HostAuth setupSimpleHostAuth(String protocol) { + HostAuth hostAuth = new HostAuth(); + hostAuth.mProtocol = protocol; + return hostAuth; + } + + /** + * Initial testing on setupSyncReportsLocked, making sure that EAS accounts aren't scheduled + */ + public void testSetupSyncReportsLocked() { + // TODO Test other functionality within setupSyncReportsLocked + // Setup accounts of each type, all with manual sync at different intervals + Account easAccount = ProviderTestUtils.setupAccount("account1", false, mMockContext); + easAccount.mHostAuthRecv = setupSimpleHostAuth("eas"); + easAccount.mHostAuthSend = easAccount.mHostAuthRecv; + easAccount.mSyncInterval = 30; + easAccount.save(mMockContext); + Account imapAccount = ProviderTestUtils.setupAccount("account2", false, mMockContext); + imapAccount.mHostAuthRecv = setupSimpleHostAuth("imap"); + imapAccount.mHostAuthSend = setupSimpleHostAuth("smtp"); + imapAccount.mSyncInterval = 60; + imapAccount.save(mMockContext); + Account pop3Account = ProviderTestUtils.setupAccount("account3", false, mMockContext); + pop3Account.mHostAuthRecv = setupSimpleHostAuth("pop3"); + pop3Account.mHostAuthSend = setupSimpleHostAuth("smtp"); + pop3Account.mSyncInterval = 90; + pop3Account.save(mMockContext); + + // Setup the SyncReport's for these Accounts + MailService mailService = new MailService(); + mailService.mController = new TestController(mMockContext, getContext()); + try { + mailService.setupSyncReportsLocked(MailService.SYNC_REPORTS_RESET, mMockContext); + + // Get back the map created by MailService + HashMap<Long, AccountSyncReport> syncReportMap = MailService.mSyncReports; + synchronized (syncReportMap) { + // Check the SyncReport's for correctness of sync interval + AccountSyncReport syncReport = syncReportMap.get(easAccount.mId); + assertNotNull(syncReport); + // EAS sync interval should have been changed to "never" + assertEquals(Account.CHECK_INTERVAL_NEVER, syncReport.syncInterval); + syncReport = syncReportMap.get(imapAccount.mId); + assertNotNull(syncReport); + assertEquals(60, syncReport.syncInterval); + syncReport = syncReportMap.get(pop3Account.mId); + assertNotNull(syncReport); + assertEquals(90, syncReport.syncInterval); + // Change the EAS account to push + ContentValues cv = new ContentValues(); + cv.put(Account.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH); + easAccount.update(mMockContext, cv); + syncReportMap.clear(); + mailService.setupSyncReportsLocked(easAccount.mId, mMockContext); + syncReport = syncReportMap.get(easAccount.mId); + assertNotNull(syncReport); + // EAS sync interval should be "never" in this case as well + assertEquals(Account.CHECK_INTERVAL_NEVER, syncReport.syncInterval); + } + } finally { + mailService.mController.cleanupForTest(); + } + } + + /** + * Test that setupSyncReports will skip over poorly-formed accounts which can be left + * over after unit tests. + */ + public void testSetupSyncReportsWithBadAccounts() { + // Setup accounts that trigger each skip-over case + // 1: no email address + Account account1 = ProviderTestUtils.setupAccount("account1", false, mMockContext); + account1.mHostAuthRecv = setupSimpleHostAuth("imap"); + account1.mHostAuthSend = setupSimpleHostAuth("smtp"); + account1.mSyncInterval = 30; + account1.mEmailAddress = null; + account1.save(mMockContext); + // 2: no receiver hostauth + Account account2 = ProviderTestUtils.setupAccount("account2", false, mMockContext); + account2.mHostAuthRecv = null; + account2.mHostAuthSend = setupSimpleHostAuth("smtp"); + account2.mSyncInterval = 30; + account2.save(mMockContext); + // 3: no sender hostauth + Account account3 = ProviderTestUtils.setupAccount("account3", false, mMockContext); + account3.mHostAuthRecv = setupSimpleHostAuth("imap"); + account3.mHostAuthSend = null; + account3.mSyncInterval = 30; + account3.save(mMockContext); + + // Setup the SyncReport's for these Accounts + MailService mailService = new MailService(); + mailService.mController = new TestController(mMockContext, getContext()); + try { + mailService.setupSyncReportsLocked(MailService.SYNC_REPORTS_RESET, mMockContext); + // Get back the map created by MailService - it should be empty + HashMap<Long, AccountSyncReport> syncReportMap = MailService.mSyncReports; + assertEquals(0, syncReportMap.size()); + } finally { + mailService.mController.cleanupForTest(); + } + + } +} diff --git a/tests/src/com/android/emailcommon/provider/MailboxTests.java b/tests/src/com/android/emailcommon/provider/MailboxTests.java index 8ab2a3392..9d9825c0e 100644 --- a/tests/src/com/android/emailcommon/provider/MailboxTests.java +++ b/tests/src/com/android/emailcommon/provider/MailboxTests.java @@ -16,6 +16,14 @@ package com.android.emailcommon.provider; +import com.android.email.provider.ContentCache; +import com.android.email.provider.EmailProvider; +import com.android.email.provider.ProviderTestUtils; +import com.android.emailcommon.provider.EmailContent.MailboxColumns; +import com.android.emailcommon.provider.EmailContent.Message; +import com.android.emailcommon.provider.EmailContent.MessageColumns; +import com.android.emailcommon.utility.Utility; + import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; @@ -25,14 +33,6 @@ import android.test.MoreAsserts; import android.test.ProviderTestCase2; import android.test.suitebuilder.annotation.SmallTest; -import com.android.email.provider.ContentCache; -import com.android.email.provider.EmailProvider; -import com.android.email.provider.ProviderTestUtils; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.utility.Utility; - import java.util.Arrays; /** @@ -520,6 +520,7 @@ public class MailboxTests extends ProviderTestCase2<EmailProvider> { testMailbox.mSyncTime = 6L; testMailbox.mType = 7; testMailbox.mVisibleLimit = 8; + testMailbox.mLastSeenMessageKey = 9L; testMailbox.mLastTouchedTime = 10L; return testMailbox; diff --git a/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java b/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java index a7c60ddf5..171ace1a9 100644 --- a/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java +++ b/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java @@ -16,10 +16,22 @@ package com.android.emailcommon.utility; +import com.android.email.DBTestHelper; +import com.android.email.R; +import com.android.email.TestUtils; +import com.android.email.provider.ProviderTestUtils; +import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.EmailContent.Attachment; +import com.android.emailcommon.provider.EmailContent.MailboxColumns; +import com.android.emailcommon.provider.EmailContent.Message; +import com.android.emailcommon.provider.Mailbox; +import com.android.emailcommon.utility.Utility.NewFileCreator; + import android.content.Context; import android.database.Cursor; import android.database.CursorWrapper; import android.database.MatrixCursor; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Environment; import android.test.AndroidTestCase; @@ -29,16 +41,6 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.widget.TextView; -import com.android.email.DBTestHelper; -import com.android.email.TestUtils; -import com.android.email.provider.ProviderTestUtils; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent.Attachment; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.utility.Utility.NewFileCreator; - import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -308,7 +310,7 @@ public class UtilityUnitTests extends AndroidTestCase { private long getLastUpdateKey(Context mockContext, long mailboxId) { return Utility.getFirstRowLong(mockContext, Mailbox.CONTENT_URI, - new String[] { MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY }, MailboxColumns.ID + "=?", + new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY }, MailboxColumns.ID + "=?", new String[] { Long.toString(mailboxId) }, null, 0, -1L); } @@ -379,7 +381,7 @@ public class UtilityUnitTests extends AndroidTestCase { assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId)); // Test account; only INBOX is modified - Utility.updateLastNotifiedMessageKey(mockContext, account1.mId).get(); + Utility.updateLastSeenMessageKey(mockContext, account1.mId).get(); assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId)); @@ -391,7 +393,7 @@ public class UtilityUnitTests extends AndroidTestCase { assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId)); // Missing INBOX - Utility.updateLastNotifiedMessageKey(mockContext, account2.mId).get(); + Utility.updateLastSeenMessageKey(mockContext, account2.mId).get(); assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId)); @@ -403,7 +405,7 @@ public class UtilityUnitTests extends AndroidTestCase { assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId)); // No messages in mailbox - Utility.updateLastNotifiedMessageKey(mockContext, account3.mId).get(); + Utility.updateLastSeenMessageKey(mockContext, account3.mId).get(); assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId)); @@ -415,7 +417,7 @@ public class UtilityUnitTests extends AndroidTestCase { assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId)); // Test combined accounts - Utility.updateLastNotifiedMessageKey(mockContext, 0x1000000000000000L).get(); + Utility.updateLastSeenMessageKey(mockContext, 0x1000000000000000L).get(); assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId)); assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId)); |
