mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
Merge remote branch 'k-9/master'
This commit is contained in:
commit
503b88e2fd
23
Android.mk
23
Android.mk
@ -1,10 +1,33 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += libcore
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += libdom
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += libio
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += libjutf
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += libjzlib
|
||||
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
LOCAL_PACKAGE_NAME := Email
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
##################################################
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += libcore:libs/apache-mime4j-core-0.7-SNAPSHOT.jar
|
||||
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += libdom:libs/apache-mime4j-dom-0.7-SNAPSHOT.jar
|
||||
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += libio:libs/commons-io-2.0.1.jar
|
||||
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += libjutf:libs/jutf7-1.0.1-SNAPSHOT.jar
|
||||
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += libjzlib:libs/jzlib-1.0.7.jar
|
||||
|
||||
include $(BUILD_MULTI_PREBUILT)
|
||||
|
||||
|
||||
# Use the folloing include to make our test apk.
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="13010"
|
||||
android:versionName="3.709" package="com.fsck.k9"
|
||||
android:versionCode="14001"
|
||||
android:versionName="3.900" package="com.fsck.k9"
|
||||
>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="3"
|
||||
@ -18,10 +18,6 @@
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
|
||||
|
||||
<!-- Needed to get the owner name which is used when the first mail account is created -->
|
||||
<uses-permission android:name="android.permission.READ_OWNER_DATA"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
<!-- Needed to mark a contact as contacted -->
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
|
||||
@ -319,7 +315,7 @@
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<!--
|
||||
<!--
|
||||
android.intent.action.MEDIA_MOUNTED
|
||||
|
||||
* Broadcast Action: External media is present and mounted at its mount point.
|
||||
@ -329,9 +325,9 @@ android.intent.action.MEDIA_MOUNTED
|
||||
|
||||
-->
|
||||
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
|
||||
<!--
|
||||
<!--
|
||||
|
||||
MEDIA_EJECT and MEDIA_UNMOUNTED are not defined here: they have to be dynamically registered
|
||||
MEDIA_EJECT and MEDIA_UNMOUNTED are not defined here: they have to be dynamically registered
|
||||
otherwise it would make K-9 start at the wrong time
|
||||
|
||||
-->
|
||||
|
@ -2,7 +2,7 @@
|
||||
<body bgcolor="white">
|
||||
<table width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="center">
|
||||
<td align="center" valign="middle">
|
||||
<font color="gray">Downloading...</font>
|
||||
<br/>
|
||||
<br/>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<body bgcolor="white">
|
||||
<table width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="center">
|
||||
<td align="center" valign="middle">
|
||||
<font color="gray">No text</font>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<body bgcolor="white">
|
||||
<table width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="center">
|
||||
<td align="center" valign="middle">
|
||||
<font color="gray">Loading...</font>
|
||||
<br/>
|
||||
<br/>
|
||||
|
29
k9mail.iml
29
k9mail.iml
@ -3,7 +3,6 @@
|
||||
<component name="FacetManager">
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="PLATFORM_NAME" value="Android 2.3.1 Platform" />
|
||||
<option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/gen" />
|
||||
<option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/gen" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/AndroidManifest.xml" />
|
||||
@ -17,7 +16,6 @@
|
||||
<option name="USE_CUSTOM_COMPILER_MANIFEST" value="false" />
|
||||
<option name="CUSTOM_COMPILER_MANIFEST" value="" />
|
||||
<option name="APK_PATH" value="" />
|
||||
<option name="ADD_ANDROID_LIBRARY" value="true" />
|
||||
<option name="LIBRARY_PROJECT" value="false" />
|
||||
<option name="RUN_PROCESS_RESOURCES_MAVEN_TASK" value="true" />
|
||||
<option name="GENERATE_UNSIGNED_APK" value="false" />
|
||||
@ -79,33 +77,6 @@
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="PROVIDED">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/compile-only-libs/commons-logging-1.1.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="PROVIDED">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/compile-only-libs/bcprov-jdk15-143.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="PROVIDED">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/compile-only-libs/commons-codec-1.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="TEST">
|
||||
<library>
|
||||
<CLASSES>
|
||||
|
@ -152,7 +152,6 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/userId"
|
||||
android:text=""
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
@ -161,7 +160,6 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/userIdRest"
|
||||
android:text=""
|
||||
android:textSize="10sp"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
@ -239,6 +237,17 @@
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/quoted_text_show"
|
||||
android:text="@string/message_compose_show_quoted_text_action"
|
||||
android:textSize="16dip"
|
||||
android:padding="0dip"
|
||||
android:layout_gravity="right"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true" />
|
||||
|
||||
<!-- Quoted text bar -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/quoted_text_bar"
|
||||
|
@ -83,7 +83,7 @@
|
||||
android:layout_marginRight="0dip"
|
||||
android:singleLine="false"
|
||||
android:bufferType="spannable"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -344,7 +344,7 @@ Benvingut a la configuració del K-9. El K-9 és un client de codi obert per An
|
||||
<string name="global_settings_confirm_action_archive">Arxiva</string>
|
||||
<string name="global_settings_confirm_action_delete">Esborra (només la vista del missatge)</string>
|
||||
<string name="global_settings_confirm_action_spam">Brossa</string>
|
||||
<!-- NEW: <string name="global_settings_confirm_action_mark_all_as_read">Mark all as read</string>-->
|
||||
<string name="global_settings_confirm_action_mark_all_as_read">Maca\'ls tots com a llegits</string>
|
||||
<string name="global_settings_confirm_action_send">Envia</string>
|
||||
|
||||
<string name="global_settings_privacy_mode_title">Bloca notificacions</string>
|
||||
@ -1001,7 +1001,7 @@ Benvingut a la configuració del K-9. El K-9 és un client de codi obert per An
|
||||
|
||||
<!-- APG related -->
|
||||
<string name="error_activity_not_found">No s’ha trobat cap aplicació idònia per a aquesta acció.</string>
|
||||
<string name="error_apg_version_not_supported">Versió APG instal lada no suportada.</string>
|
||||
<string name="error_apg_version_not_supported">Versió APG instal·lada no suportada.</string>
|
||||
<string name="btn_crypto_sign">Inicia</string>
|
||||
<string name="btn_encrypt">Encripta</string>
|
||||
<string name="btn_decrypt">Desencripta</string>
|
||||
@ -1025,10 +1025,10 @@ Benvingut a la configuració del K-9. El K-9 és un client de codi obert per An
|
||||
<string name="dialog_confirm_delete_confirm_button">Esborra</string>
|
||||
<string name="dialog_confirm_delete_cancel_button">No esborris</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_confirm_spam_title">Confirm move to spam folder</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_message">Do you really want to move this message to the spam folder?</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_confirm_button">Yes</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_cancel_button">No</string>-->
|
||||
<string name="dialog_confirm_spam_title">Confirma moure\'l carpeta brossa</string>
|
||||
<string name="dialog_confirm_spam_message">Realment vols moure aquest missatge a la carpeta brossa?</string>
|
||||
<string name="dialog_confirm_spam_confirm_button">Sí</string>
|
||||
<string name="dialog_confirm_spam_cancel_button">No</string>
|
||||
|
||||
<string name="dialog_attachment_progress_title">S\'està descarregant adjunt</string>
|
||||
|
||||
@ -1038,6 +1038,9 @@ Benvingut a la configuració del K-9. El K-9 és un client de codi obert per An
|
||||
<string name="messagelist_sent_cc_me_sigil">›</string>
|
||||
<string name="error_unable_to_connect">No es pot connectar.</string>
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
<string name="account_unavailable">Compte \"<xliff:g id="account">%s</xliff:g>\" no és disponible; comprova emmagatzematge</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Desa adjunts a...</string>
|
||||
<string name="attachment_save_title">Desa adjunt</string>
|
||||
<string name="attachment_save_desc">No s\'ha trobat l\'arxiu al navegador. On vols desar l\'adjunt?</string>
|
||||
</resources>
|
||||
|
@ -1047,4 +1047,7 @@ Vítejte v nastavení pošty K-9 Mail. K-9 je open source poštovní klient pro
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<string name="reply_action">Antworten</string>
|
||||
<string name="reply_all_action">Allen antworten</string>
|
||||
<string name="delete_action">Löschen</string>
|
||||
<string name="archive_action">Sichern</string>
|
||||
<string name="archive_action">Archivieren</string>
|
||||
<string name="spam_action">Spam</string>
|
||||
<string name="delete_all_action">Ordner leeren</string>
|
||||
<string name="forward_action">Weiterleiten</string>
|
||||
@ -341,7 +341,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="global_settings_confirm_action_archive">Archivieren</string>
|
||||
<string name="global_settings_confirm_action_delete">Löschen (nur in Nachrichtenansicht)</string>
|
||||
<string name="global_settings_confirm_action_spam">Spam</string>
|
||||
<!-- NEW: <string name="global_settings_confirm_action_mark_all_as_read">Mark all as read</string>-->
|
||||
<string name="global_settings_confirm_action_mark_all_as_read">Alle als gelesen markieren</string>
|
||||
<string name="global_settings_confirm_action_send">Senden</string>
|
||||
|
||||
<string name="global_settings_privacy_mode_title">Vertrauliche Benachrichtigung</string>
|
||||
@ -688,7 +688,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_add_account_label">Eine weiteres Konto hinzufügen</string>
|
||||
<string name="account_settings_description_label">Kontoname</string>
|
||||
<string name="account_settings_name_label">Ihr Name</string>
|
||||
<string name="notifications_title">Benachrichtigungseinstellungen</string>
|
||||
<string name="notifications_title">Benachrichtigungen</string>
|
||||
<string name="account_settings_ring_summary">Klingeln bei neuer Nachricht</string>
|
||||
<string name="account_settings_vibrate_enable">Vibration</string>
|
||||
<string name="account_settings_vibrate_summary">Vibration bei neuer Nachricht</string>
|
||||
@ -869,16 +869,16 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="date_format_common">dd.MMM yyyy</string>
|
||||
<string name="date_format_iso8601">yyyy-MM-dd</string>
|
||||
|
||||
<string name="batch_ops">Mehrfachauswahl</string>
|
||||
<string name="batch_delete_op">Ausgewählte löschen</string>
|
||||
<string name="batch_mark_read_op">Ausgewählte als gelesen markieren</string>
|
||||
<string name="batch_mark_unread_op">Ausgewählte als ungelesen markieren</string>
|
||||
<string name="batch_flag_op">Ausgewählte als wichtig markieren</string>
|
||||
<string name="batch_unflag_op">Markierung bei Ausgewählten entfernen</string>
|
||||
<string name="batch_archive_op">Ausgewählte sichern</string>
|
||||
<string name="batch_spam_op">Ausgewählte als Spam markieren</string>
|
||||
<string name="batch_move_op">Ausgewählte verschieben</string>
|
||||
<string name="batch_copy_op">Ausgewählte kopieren</string>
|
||||
<string name="batch_ops">Gruppenoperationen</string>
|
||||
<string name="batch_delete_op">Gewählte löschen</string>
|
||||
<string name="batch_mark_read_op">Gewählte als gelesen markieren</string>
|
||||
<string name="batch_mark_unread_op">Gewählte als ungelesen markieren</string>
|
||||
<string name="batch_flag_op">Gewählte als wichtig markieren</string>
|
||||
<string name="batch_unflag_op">Markierung bei Gewählten entfernen</string>
|
||||
<string name="batch_archive_op">Gewählte sichern</string>
|
||||
<string name="batch_spam_op">Gewählte als Spam markieren</string>
|
||||
<string name="batch_move_op">Gewählte verschieben</string>
|
||||
<string name="batch_copy_op">Gewählte kopieren</string>
|
||||
<string name="batch_flag_mode">Stern-Modus</string>
|
||||
<string name="batch_select_mode">Auswahl-Modus</string>
|
||||
<string name="batch_plain_mode">Normaler Modus</string>
|
||||
@ -1022,12 +1022,12 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="dialog_confirm_delete_confirm_button">Löschen</string>
|
||||
<string name="dialog_confirm_delete_cancel_button">Nicht löschen</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_confirm_spam_title">Confirm move to spam folder</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_message">Do you really want to move this message to the spam folder?</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_confirm_button">Yes</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_cancel_button">No</string>-->
|
||||
<string name="dialog_confirm_spam_title">Als Spam markieren</string>
|
||||
<string name="dialog_confirm_spam_message">Wollen Sie diese Nachricht in den Spam-Ordner verschieben?</string>
|
||||
<string name="dialog_confirm_spam_confirm_button">Ja</string>
|
||||
<string name="dialog_confirm_spam_cancel_button">Nein</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_attachment_progress_title">Downloading attachment</string>-->
|
||||
<string name="dialog_attachment_progress_title">Anhang wird heruntergeladen</string>
|
||||
|
||||
<string name="debug_logging_enabled">Debug-Meldungen werden mit Hilfe des Android-Logging-Systems aufgezeichnet.</string>
|
||||
|
||||
@ -1037,4 +1037,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
|
||||
<string name="account_unavailable">Konto \"<xliff:g id="account">%s</xliff:g>\" ist nicht verfügbar; Bitte SD-Karte prüfen.</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Anhang speichern unter...</string>
|
||||
<string name="attachment_save_title">Anhang speichern</string>
|
||||
<string name="attachment_save_desc">Es wurde kein Dateimanager gefunden. Wo soll der Anhang abgelegt werden?</string>
|
||||
</resources>
|
||||
|
@ -1037,4 +1037,7 @@ Bienvenido a la Configuración de K-9. K-9 es un cliente de correo OpenSource pa
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1034,4 +1034,7 @@ Tervetuloa K-9 Mail asennukseen. K-9 on avoimen lähdekoodin sähköpostiasiak
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1037,4 +1037,7 @@ Benvido á Configuración de K-9. K-9 é un cliente de correo OpenSource para An
|
||||
|
||||
<string name="account_unavailable">A conta \"<xliff:g id="account">%s</xliff:g>\" non está dispoñible; verifica o almacenamento</string>
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1041,4 +1041,7 @@ Benvenuto nella configurazione della posta di K-9. K-9 è un client di posta ope
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<string name="accounts_title">アカウント一覧</string>
|
||||
<string name="advanced">拡張機能</string>
|
||||
<string name="folder_list_title"><xliff:g id="account">%s</xliff:g> </string>
|
||||
<string name="shortcuts_title">K-9 Accounts</string>
|
||||
<string name="shortcuts_title">K-9 アカウント</string>
|
||||
|
||||
<string name="message_list_title"><xliff:g id="account">%s</xliff:g>:<xliff:g id="folder">%s</xliff:g> </string>
|
||||
|
||||
@ -133,7 +133,7 @@
|
||||
<string name="status_loading_folder">(取込中 <xliff:g id="folder">%s</xliff:g><xliff:g id="progress">%s</xliff:g>)</string>
|
||||
<string name="status_loading_more">メール取込中\u2026</string>
|
||||
<string name="status_network_error">接続エラー</string>
|
||||
<string name="status_invalid_id_error">新着メールなし</string>
|
||||
<string name="status_invalid_id_error">メッセージが見つかりません</string>
|
||||
<string name="status_error">エラー</string>
|
||||
<string name="status_sending">送信\u2026</string>
|
||||
|
||||
@ -188,13 +188,13 @@
|
||||
|
||||
<string name="send_failure_subject">メール送信に失敗しました</string>
|
||||
<string name="send_failure_body_abbrev"><xliff:g id="errorFolder">%s</xliff:g> フォルダ詳細を確認してください</string>
|
||||
<string name="send_failure_body_fmt">K-9 はメール送信中にトラブルが発生しました.
|
||||
メッセージが送信されたかどうかについては、トラブルに応じるため不明です.
|
||||
送信宛先は、メールを既に受信している場合があります.
|
||||
\u000a\u000a送信済みトレイにトラブルで発生したメールを格納します.
|
||||
フラグ解除されたメールを再送信することができます.
|
||||
送信済みトレイを長く押下することで「メール送信」メニューを表示させて送信することができます.\u000A\u000a
|
||||
<xliff:g id="errorFolder">%s</xliff:g> フォルダには失敗したエラーメッセージが含まれています.</string>
|
||||
<string name="send_failure_body_fmt">メール送信中に問題が発生しました。
|
||||
問題の性質により、メッセージが送信されたかどうかがわかりません。
|
||||
受信者は、そのメッセージを既に受信しているかもしれません。
|
||||
\u000a\u000a問題が発生したメールには送信トレイにスターが付いています。
|
||||
スターを取ることで、メールを再送することができます。
|
||||
他のメッセージを送信するには、「メール送信」メニューを表示させるために送信トレイを長押ししてください。\u000A\u000a
|
||||
<xliff:g id="errorFolder">%s</xliff:g> フォルダにはその問題に関するエラーメッセージが含まれています。</string>
|
||||
|
||||
<string name="alert_header">K-9 警告</string>
|
||||
<string name="no_connection_alert">送信ネットワークのリソース不足のため同期処理中断</string>
|
||||
@ -231,7 +231,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="debug_enable_debug_logging_title">拡張デバッグログ</string>
|
||||
<string name="debug_enable_debug_logging_summary">追加診断情報ログ</string>
|
||||
<string name="debug_enable_sensitive_logging_title">詳細情報ログ</string>
|
||||
<string name="debug_enable_sensitive_logging_summary">ログにパスワードが表示されるかもしれません</string>
|
||||
<string name="debug_enable_sensitive_logging_summary">ログにパスワードが表示される</string>
|
||||
|
||||
<string name="message_header_mua">K-9 for Android </string>
|
||||
|
||||
@ -259,16 +259,16 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_compose_content_hint">本文</string>
|
||||
<string name="message_compose_quote_header_separator">-------- 元メール --------</string>
|
||||
<string name="message_compose_quote_header_subject">件名:</string>
|
||||
<!-- NEW: <string name="message_compose_quote_header_send_date">Sent:</string>-->
|
||||
<string name="message_compose_quote_header_send_date">送信日:</string>
|
||||
<string name="message_compose_quote_header_from">送信者:</string>
|
||||
<string name="message_compose_quote_header_to">宛先:</string>
|
||||
<string name="message_compose_quote_header_cc">CC:</string>
|
||||
<string name="message_compose_reply_header_fmt"><xliff:g id="sender">%s</xliff:g> wrote:\n\n</string>
|
||||
<string name="message_compose_quoted_text_label">テキスト引用</string>
|
||||
<string name="message_compose_error_no_recipients">少なくとも1つの受信者を追加する必要があります</string>
|
||||
<!-- NEW: <string name="error_contact_address_not_found">No email address could be found.</string>-->
|
||||
<string name="message_compose_downloading_attachments_toast">一部の添付ファイルをダウンロードしていません.このメールが送信される前に自動的にダウンロードされます.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">ダウンロードしていないため、一部の添付ファイルを転送することはできません.</string>
|
||||
<string name="error_contact_address_not_found">メールアドレスが登録されていません</string>
|
||||
<string name="message_compose_downloading_attachments_toast">一部の添付ファイルをダウンロードしていません。このメールが送信される前に自動的にダウンロードされます。</string>
|
||||
<string name="message_compose_attachments_skipped_toast">ダウンロードしていないため、一部の添付ファイルを転送することはできません。</string>
|
||||
|
||||
|
||||
|
||||
@ -293,9 +293,9 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_view_download_remainder">すべてダウンロード</string>
|
||||
|
||||
<!-- NOTE: The following message refers to strings with id 'account_setup_incoming_save_all_headers_label' and 'account_setup_incoming_title' -->
|
||||
<string name="message_additional_headers_not_downloaded">一部のヘッダしか保存されていません.ヘッダをすべて保存するためには、アカウント設定の受信メールサーバ設定で「すべてのヘッダを端末に保存」をチェックしてください.</string>
|
||||
<string name="message_no_additional_headers_available">すべてのヘッダをダウンロードしましたが、表示すべき追加ヘッダはありませんでした.</string>
|
||||
<string name="message_additional_headers_retrieval_failed">追加ヘッダをデータベースまたはメールサーバから取得できませんでした.</string>
|
||||
<string name="message_additional_headers_not_downloaded">一部のヘッダしか保存されていません。ヘッダをすべて保存するためには、アカウント設定の受信メールサーバ設定で「ヘッダのダウンロード」をチェックしてください。</string>
|
||||
<string name="message_no_additional_headers_available">すべてのヘッダをダウンロードしましたが、表示すべき追加ヘッダはありませんでした。</string>
|
||||
<string name="message_additional_headers_retrieval_failed">追加ヘッダをデータベースまたはメールサーバから取得できませんでした。</string>
|
||||
|
||||
<string name="mailbox_select_dlg_title">フォルダ</string>
|
||||
<string name="mailbox_select_dlg_new_mailbox_action">新しいフォルダ</string>
|
||||
@ -318,7 +318,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
|
||||
<string name="global_settings_flag_label">スターを表示</string>
|
||||
<string name="global_settings_flag_summary">スターは印を付けたメッセージを示します</string>
|
||||
<string name="global_settings_flag_summary">スターは印の付いたメッセージを示す</string>
|
||||
<string name="global_settings_checkbox_label">複数選択チェックボックス</string>
|
||||
<string name="global_settings_checkbox_summary">複数選択チェックボックス常時表示</string>
|
||||
<string name="global_settings_touchable_label">メッセージプレビュー</string>
|
||||
@ -333,7 +333,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="global_settings_registered_name_color_changed">連絡先の名前の場合は色を付ける</string>
|
||||
|
||||
<string name="global_settings_messageview_fixedwidth_label">固定幅フォント</string>
|
||||
<string name="global_settings_messageview_fixedwidth_summary">プレーンテキストメッセージを表示する際、固定幅フォントを利用します.</string>
|
||||
<string name="global_settings_messageview_fixedwidth_summary">プレーンテキストメッセージの表示に固定幅フォントを利用</string>
|
||||
<string name="global_settings_messageview_return_to_list_label">削除後メッセージ一覧へ戻る</string>
|
||||
<string name="global_settings_messageview_return_to_list_summary">メッセージの削除後、メッセージ一覧に戻る</string>
|
||||
|
||||
@ -342,7 +342,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="global_settings_confirm_action_archive">アーカイブ</string>
|
||||
<string name="global_settings_confirm_action_delete">削除(メッセージ表示画面のみ)</string>
|
||||
<string name="global_settings_confirm_action_spam">迷惑メール</string>
|
||||
<!-- NEW: <string name="global_settings_confirm_action_mark_all_as_read">Mark all as read</string>-->
|
||||
<string name="global_settings_confirm_action_mark_all_as_read">すべて既読にする</string>
|
||||
<string name="global_settings_confirm_action_send">送信</string>
|
||||
|
||||
<string name="global_settings_privacy_mode_title">スクリーンロック時の通知</string>
|
||||
@ -350,7 +350,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
|
||||
<string name="quiet_time">夜間時間帯</string>
|
||||
<string name="quiet_time_description">夜間での各種通知や表示を抑制する時間帯を設定します.</string>
|
||||
<string name="quiet_time_description">夜間での各種通知や表示を抑制する時間帯を設定</string>
|
||||
<string name="quiet_time_starts">開始時刻</string>
|
||||
<string name="quiet_time_ends">終了時刻</string>
|
||||
|
||||
@ -491,7 +491,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="push_poll_on_connect_label">プッシュ接続時の同期</string>
|
||||
<string name="account_setup_options_enable_push_label">このアカウントにプッシュメールを有効化</string>
|
||||
<string name="account_setup_options_enable_push_summary">メールサーバがサポートしていれば新しいメッセージは即座に表示されます.当オプションはパフォーマンスが改善もしくは低下します.</string>
|
||||
<string name="account_setup_options_enable_push_summary">メールサーバがサポートしていれば新しいメッセージは即座に表示されます。当オプションはパフォーマンスが改善もしくは低下します。</string>
|
||||
<string name="idle_refresh_period_label">IMAP IDLE(プッシュ)接続のリフレッシュ</string>
|
||||
<string name="idle_refresh_period_1min">1分毎</string>
|
||||
<string name="idle_refresh_period_2min">2分毎</string>
|
||||
@ -584,7 +584,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="account_settings_crypto_app_none">なし</string>
|
||||
<string name="account_settings_crypto_app_not_available">利用不可</string>
|
||||
<string name="account_settings_crypto_auto_signature">自動署名</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">このアカウントのE-Mailアドレスから署名の鍵を自動的に決定する.</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">このアカウントのE-Mailアドレスから署名の鍵を自動的に決定する</string>
|
||||
|
||||
<string name="account_settings_mail_check_frequency_label">同期フォルダの同期間隔</string>
|
||||
<string name="account_settings_second_class_check_frequency_label">2nd クラス自動受信間隔</string>
|
||||
@ -600,7 +600,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="account_settings_mail_display_count_label">一度に表示するメール数</string>
|
||||
|
||||
<string name="account_settings_autodownload_message_size_label">ダウンロードするメッセージの上限</string>
|
||||
<string name="account_settings_autodownload_message_size_label">ダウンロードするメッセージサイズの上限</string>
|
||||
<string name="account_settings_autodownload_message_size_1">1Kb</string>
|
||||
<string name="account_settings_autodownload_message_size_2">2Kb</string>
|
||||
<string name="account_settings_autodownload_message_size_4">4Kb</string>
|
||||
@ -841,7 +841,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="settings_messageview_mobile_layout_label">1列レイアウト</string>
|
||||
<string name="settings_messageview_mobile_layout_summary">小さい画面用にHTMLメッセージを再構成</string>
|
||||
<string name="settings_messageview_zoom_controls_label">ズーム制御</string>
|
||||
<string name="settings_messageview_zoom_controls_summary">デバイスが対応するならば、ズームウィジェットやピンチズームを有効にします</string>
|
||||
<string name="settings_messageview_zoom_controls_summary">デバイスが対応するならば、ズームウィジェットやピンチズームを有効にする</string>
|
||||
|
||||
|
||||
|
||||
@ -910,13 +910,13 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="start_integrated_inbox_summary">起動後に統合フォルダを表示する</string>
|
||||
|
||||
<string name="measure_accounts_title">アカウントのサイズ表示</string>
|
||||
<string name="measure_accounts_summary">表示を早くしたい場合はチェックをはずしてください</string>
|
||||
<string name="measure_accounts_summary">表示を速くしたい場合はチェックしない</string>
|
||||
|
||||
<string name="count_search_title">検索結果の件数表示</string>
|
||||
<string name="count_search_summary">表示を早くしたい場合はチェックをはずしてください</string>
|
||||
<string name="count_search_summary">表示を速くしたい場合はチェックしない</string>
|
||||
|
||||
<!-- NEW: <string name="hide_special_accounts_title">Hide special accounts</string>-->
|
||||
<!-- NEW: <string name="hide_special_accounts_summary">Hide the unified inbox and all messages accounts</string>-->
|
||||
<string name="hide_special_accounts_title">特殊なアカウントを隠す</string>
|
||||
<string name="hide_special_accounts_summary">統合フォルダと全メッセージを隠す</string>
|
||||
|
||||
<string name="search_title"><xliff:g id="search_name">%s</xliff:g> <xliff:g id="modifier">%s</xliff:g></string>
|
||||
<string name="flagged_modifier"> - スター</string>
|
||||
@ -1018,12 +1018,12 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="dialog_confirm_delete_confirm_button">削除する</string>
|
||||
<string name="dialog_confirm_delete_cancel_button">削除しない</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_confirm_spam_title">Confirm move to spam folder</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_message">Do you really want to move this message to the spam folder?</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_confirm_button">Yes</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_cancel_button">No</string>-->
|
||||
<string name="dialog_confirm_spam_title">迷惑メールフォルダへの移動の確認</string>
|
||||
<string name="dialog_confirm_spam_message">本当にこのメッセージを迷惑メールフォルダに移動しますか?</string>
|
||||
<string name="dialog_confirm_spam_confirm_button">はい</string>
|
||||
<string name="dialog_confirm_spam_cancel_button">いいえ</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_attachment_progress_title">Downloading attachment</string>-->
|
||||
<string name="dialog_attachment_progress_title">添付ファイルをダウンロードしています</string>
|
||||
|
||||
<string name="debug_logging_enabled">Android のログにデバッグ用のログを出力するように設定しました。</string>
|
||||
|
||||
@ -1031,6 +1031,9 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="messagelist_sent_cc_me_sigil">\u203a</string>
|
||||
<string name="error_unable_to_connect">接続できません</string>
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
<string name="account_unavailable">アカウント \"<xliff:g id="account">%s</xliff:g>\" は利用できません。ストレージを確認してください。</string>
|
||||
|
||||
<string name="settings_attachment_default_path">添付ファイルの保存先</string>
|
||||
<string name="attachment_save_title">添付ファイルの保存先</string>
|
||||
<string name="attachment_save_desc">ファイルブラウザがインストールされていません。添付ファイルの保存場所を直接入力してください。</string>
|
||||
</resources>
|
||||
|
1043
res/values-ko/strings.xml
Normal file
1043
res/values-ko/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,14 +3,14 @@
|
||||
<string name="app_name">K-9 Mail</string>
|
||||
<string name="beta_app_name">K-9 Mail BETA</string>
|
||||
<string name="app_authors">Google, The K-9 Dog Walkers.</string>
|
||||
<!-- NEW: <string name="app_copyright_fmt">Copyright 2008-<xliff:g>%s</xliff:g> The K-9 Dog Walkers. Portions Copyright 2006-<xliff:g>%s</xliff:g> the Android Open Source Project.</string>-->
|
||||
<!-- NEW: <string name="app_license">Licensed under the Apache License, Version 2.0.</string>-->
|
||||
<string name="app_copyright_fmt">Copyright 2008-<xliff:g>%s</xliff:g> The K-9 Dog Walkers. Portions Copyright 2006-<xliff:g>%s</xliff:g> the Android Open Source Project.</string>
|
||||
<string name="app_license">Licensed under the Apache License, Version 2.0.</string>
|
||||
<string name="app_authors_fmt">Auteurs: <xliff:g id="app_authors">%s</xliff:g></string>
|
||||
<string name="app_revision_url">http://code.google.com/p/k9mail/wiki/ReleaseNotes</string>
|
||||
<string name="app_revision_fmt">Revisie Informatie: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_webpage_url">http://code.google.com/p/k9mail/</string>
|
||||
<!-- NEW: <string name="app_libraries">We\'re using the following third-party libraries: <xliff:g id="app_libraries_list">%s</xliff:g></string>-->
|
||||
<!-- NEW: <string name="app_emoji_icons">Emoji icons: <xliff:g id="app_emoji_icons_link">%s</xliff:g></string>-->
|
||||
<string name="app_libraries">De volgende externe bibliotheken worden gebruikt: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_emoji_icons">Emoji icons: <xliff:g id="app_emoji_icons_link">%s</xliff:g></string>
|
||||
|
||||
<string name="read_attachment_label">Lees Email bijlage</string>
|
||||
<string name="read_attachment_desc">Sta deze applicatie toe de bijlage van emails te lezen.</string>
|
||||
@ -42,15 +42,15 @@
|
||||
<string name="folder_progress">\u0020<xliff:g id="completed">%s</xliff:g>/<xliff:g id="total">%s</xliff:g></string>
|
||||
|
||||
<string name="status_next_poll">\u0020(Volgende poll @ <xliff:g id="nexttime">%s</xliff:g>)</string>
|
||||
<!-- NEW: <string name="status_syncing_off">\u0020(Syncing disabled)</string>-->
|
||||
<string name="status_syncing_off">\u0020(Synchroniseren uitgeschakeld)</string>
|
||||
|
||||
<!-- Actions will be used as buttons and in menu items -->
|
||||
<string name="next_action">Volgende</string> <!-- Used as part of a multi-step process -->
|
||||
<!-- NEW: <string name="previous_action">Previous</string>--> <!-- Used as part of a multi-step process -->
|
||||
<string name="previous_action">Vorige</string> <!-- Used as part of a multi-step process -->
|
||||
<string name="okay_action">OK</string> <!-- User to confirm acceptance of dialog boxes, warnings, errors, etc. -->
|
||||
<string name="cancel_action">Annuleer</string>
|
||||
<string name="send_action">Verzenden</string>
|
||||
<!-- NEW: <string name="send_again_action">Send Again</string>-->
|
||||
<string name="send_again_action">Opnieuw Verzenden</string>
|
||||
<string name="select_action">Selecteren</string>
|
||||
<string name="deselect_action">Annuleer selectie</string>
|
||||
<string name="reply_action">Antwoorden</string>
|
||||
@ -117,7 +117,7 @@
|
||||
<string name="dump_settings_action">Gooi instellingen weg</string>
|
||||
<string name="empty_trash_action">Prullenbak legen</string>
|
||||
<string name="expunge_action">Wissen</string>
|
||||
<!-- NEW: <string name="clear_local_folder_action">Clear local messages</string>-->
|
||||
<string name="clear_local_folder_action">Lokale berichten wissen</string>
|
||||
<string name="set_sort_action">Kies sortering</string>
|
||||
<string name="reverse_sort_action">Omgekeerd sorteren</string>
|
||||
<string name="about_action">Over</string>
|
||||
@ -127,7 +127,7 @@
|
||||
<string name="folder_context_menu_title">Map opties</string>
|
||||
|
||||
<string name="general_no_subject">(Geen onderwerp)</string> <!-- Shown in place of the subject when a message has no subject. Showing this in parentheses is customary. -->
|
||||
<!-- NEW: <string name="general_no_date">No date</string>-->
|
||||
<string name="general_no_date">Geen datum</string>
|
||||
<string name="general_no_sender">Geen afzender</string>
|
||||
<string name="status_loading">Polling</string>
|
||||
<string name="status_loading_folder">(Poll <xliff:g id="folder">%s</xliff:g><xliff:g id="progress">%s</xliff:g>)</string>
|
||||
@ -259,14 +259,14 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="message_compose_content_hint">Bericht tekst</string>
|
||||
<string name="message_compose_quote_header_separator">-------- Origineel bericht --------</string>
|
||||
<string name="message_compose_quote_header_subject">Subject:</string>
|
||||
<!-- NEW: <string name="message_compose_quote_header_send_date">Sent:</string>-->
|
||||
<string name="message_compose_quote_header_send_date">Verzonden:</string>
|
||||
<string name="message_compose_quote_header_from">From:</string>
|
||||
<string name="message_compose_quote_header_to">To:</string>
|
||||
<string name="message_compose_quote_header_cc">CC:</string>
|
||||
<string name="message_compose_reply_header_fmt"><xliff:g id="sender">%s</xliff:g> wrote:\n\n</string>
|
||||
<string name="message_compose_quoted_text_label">Ge-quote tekst</string>
|
||||
<string name="message_compose_error_no_recipients">Minimaal 1 ontvanger kiezen.</string>
|
||||
<!-- NEW: <string name="error_contact_address_not_found">No email address could be found.</string>-->
|
||||
<string name="error_contact_address_not_found">Geen email adres gevonden.</string>
|
||||
<string name="message_compose_downloading_attachments_toast">Sommige bijlage zijn niet gedownload. Deze worden automatisch gedownload voor dat dit bericht is verzonden.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Sommige bijlagen kunnen niet worden doorgestuurd, omdat ze niet zijn gedownload.</string>
|
||||
|
||||
@ -324,11 +324,11 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="global_settings_checkbox_summary">Laat altijd multi-selecteer selectieboxen zien</string>
|
||||
<string name="global_settings_touchable_label">Berichten voorbeelden</string>
|
||||
<string name="global_settings_touchable_summary">Ruimere lijst items met bericht voorbeelden</string>
|
||||
<!-- NEW: <string name="global_settings_preview_lines_label">Preview lines</string>-->
|
||||
<!-- NEW: <string name="global_settings_show_correspondent_names_label">Show correspondent names</string>-->
|
||||
<!-- NEW: <string name="global_settings_show_correspondent_names_summary">Show correspondent names rather than their email addresses</string>-->
|
||||
<!-- NEW: <string name="global_settings_show_contact_name_label">Show contact names</string>-->
|
||||
<!-- NEW: <string name="global_settings_show_contact_name_summary">Use recipient names from Contacts when available</string>-->
|
||||
<string name="global_settings_preview_lines_label">Preview regels</string>
|
||||
<string name="global_settings_show_correspondent_names_label">Toon naam bij bericht</string>
|
||||
<string name="global_settings_show_correspondent_names_summary">Geef bij voorkeur naam van afzender/geadresseerde weer i.p.v. email adres</string>
|
||||
<string name="global_settings_show_contact_name_label">Toon naam uit contactenlijst</string>
|
||||
<string name="global_settings_show_contact_name_summary">Geef de naam weer uit het adresboek</string>
|
||||
<string name="global_settings_registered_name_color_label">Kleuren contacten</string>
|
||||
<string name="global_settings_registered_name_color_default">Niet kleuren van namen in uw lijst met contactpersonen</string>
|
||||
<string name="global_settings_registered_name_color_changed">Kleuren van namen in uw lijst met contactpersonen</string>
|
||||
@ -343,17 +343,17 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="global_settings_confirm_action_archive">Archief</string>
|
||||
<string name="global_settings_confirm_action_delete">Verwijder (alleen berichten bekijken)</string>
|
||||
<string name="global_settings_confirm_action_spam">Spam</string>
|
||||
<!-- NEW: <string name="global_settings_confirm_action_mark_all_as_read">Mark all as read</string>-->
|
||||
<string name="global_settings_confirm_action_mark_all_as_read">Markeer alles als gelezen</string>
|
||||
<string name="global_settings_confirm_action_send">Verzonden</string>
|
||||
|
||||
<string name="global_settings_privacy_mode_title">Lock-screen meldingen</string>
|
||||
<string name="global_settings_privacy_mode_summary">Niet weergegeven onderwerp van het bericht in de notificatie bar als het systeem is vergrendeld</string>
|
||||
|
||||
|
||||
<!-- NEW: <string name="quiet_time">Quiet Time</string>-->
|
||||
<!-- NEW: <string name="quiet_time_description">Disable ringing, buzzing and flashing at night</string>-->
|
||||
<!-- NEW: <string name="quiet_time_starts">Quiet Time starts</string>-->
|
||||
<!-- NEW: <string name="quiet_time_ends">Quiet Time ends</string>-->
|
||||
<string name="quiet_time">Stilteperiode</string>
|
||||
<string name="quiet_time_description">Schakel beltoon, vibratie en leds uit gedurende de nacht</string>
|
||||
<string name="quiet_time_starts">Stilteperiode start</string>
|
||||
<string name="quiet_time_ends">Stilteperiode eindigt</string>
|
||||
|
||||
|
||||
<string name="account_setup_basics_title">Een nieuwe account instellen</string>
|
||||
@ -370,8 +370,8 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_setup_check_settings_retr_info_msg">Ophalen account informatie\u2026</string>
|
||||
<string name="account_setup_check_settings_check_incoming_msg">Controleren van inkomende serverinstellingen\u2026</string>
|
||||
<string name="account_setup_check_settings_check_outgoing_msg">Controleren van uitgaande serverinstellingen\u2026</string>
|
||||
<!-- NEW: <string name="account_setup_check_settings_authenticate">Authenticating\u2026</string>-->
|
||||
<!-- NEW: <string name="account_setup_check_settings_fetch">Fetching account settings\u2026</string>-->
|
||||
<string name="account_setup_check_settings_authenticate">Authenticatie\u2026</string>
|
||||
<string name="account_setup_check_settings_fetch">Accountinstellingen worden opgehaald\u2026</string>
|
||||
<string name="account_setup_check_settings_finishing_msg">Afronden\u2026</string>
|
||||
<string name="account_setup_check_settings_canceling_msg">Annuleren\u2026</string>
|
||||
|
||||
@ -417,10 +417,10 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_setup_incoming_save_all_headers_title">Downloaden van email headers</string>
|
||||
<string name="account_setup_incoming_save_all_headers_label">Sla alle headers lokaal op</string>
|
||||
|
||||
<!-- NEW: <string name="local_storage_provider_external_label">External storage (SD card)</string>-->
|
||||
<!-- NEW: <string name="local_storage_provider_internal_label">Regular internal storage</string>-->
|
||||
<!-- NEW: <string name="local_storage_provider_samsunggalaxy_label">%1$s additional internal storage</string>-->
|
||||
<!-- NEW: <string name="local_storage_provider_label">Storage location</string>-->
|
||||
<string name="local_storage_provider_external_label">Externe opslag (SD kaart)</string>
|
||||
<string name="local_storage_provider_internal_label">Reguliere interne opslag</string>
|
||||
<string name="local_storage_provider_samsunggalaxy_label">%1$s extra interne opslag</string>
|
||||
<string name="local_storage_provider_label">Opslag locatie</string>
|
||||
|
||||
<string name="account_setup_expunge_policy_label">Wissen berichten</string>
|
||||
<string name="account_setup_expunge_policy_immediately">Onmiddellijk na verwijderen of verplaatsen</string>
|
||||
@ -517,7 +517,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_setup_options_mail_display_count_250">250 berichten</string>
|
||||
<string name="account_setup_options_mail_display_count_500">500 berichten</string>
|
||||
<string name="account_setup_options_mail_display_count_1000">1000 berichten</string>
|
||||
<!-- NEW: <string name="account_setup_options_mail_display_count_all">all messages</string>-->
|
||||
<string name="account_setup_options_mail_display_count_all">alle berichten</string>
|
||||
|
||||
|
||||
<string name="move_copy_cannot_copy_unsynced_message">Kan bericht niet kopiëren of verplaatsen omdat deze niet gesynchroniseerd is met de server</string>
|
||||
@ -529,7 +529,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_setup_failed_dlg_edit_details_action">Aanpassen details</string>
|
||||
<string name="account_setup_failed_dlg_continue_action">Doorgaan</string>
|
||||
|
||||
<!-- NEW: <string name="account_settings_push_advanced_title">Advanced</string>-->
|
||||
<string name="account_settings_push_advanced_title">Geavanceerd</string>
|
||||
<string name="account_settings_title_fmt">Algemene instellingen</string>
|
||||
<string name="account_settings_default">Standaard account</string>
|
||||
<string name="account_settings_default_label">Standaard account</string>
|
||||
@ -544,8 +544,8 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_settings_notify_self_summary">Notificatie ook voor mail verzonden vanaf een identiteit</string>
|
||||
<string name="account_settings_notification_opens_unread_label">Notificatie opent ongelezen berichten</string>
|
||||
<string name="account_settings_notification_opens_unread_summary">Zoekt voor ongelezen berichten wanneer Notificatie is geopend</string>
|
||||
<!-- NEW: <string name="account_settings_notification_unread_count_label">Show unread count</string>-->
|
||||
<!-- NEW: <string name="account_settings_notification_unread_count_summary">Show the number of unread messages in the notification bar.</string>-->
|
||||
<string name="account_settings_notification_unread_count_label">Toon aantal ongelezen</string>
|
||||
<string name="account_settings_notification_unread_count_summary">Toon het aantal ongelezen berichten in de \'notification bar\'.</string>
|
||||
|
||||
<string name="account_settings_hide_buttons_label">Scroll navigatie knoppen</string>
|
||||
<string name="account_settings_hide_buttons_never">Nooit</string>
|
||||
@ -566,16 +566,16 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_settings_reply_after_quote_label">Antwoorden na quote</string>
|
||||
<string name="account_settings_reply_after_quote_summary">Wanneer u antwoord op berichten, zal het originele bericht boven uw antwoord staan.</string>
|
||||
|
||||
<!-- NEW: <string name="account_settings_message_format_label">Message Format</string>-->
|
||||
<!-- NEW: <string name="account_settings_message_format_text">Plain Text (images and formatting will be removed)</string>-->
|
||||
<!-- NEW: <string name="account_settings_message_format_html">HTML (images and formatting are preserved)</string>-->
|
||||
<string name="account_settings_message_format_label">Berichtopmaak</string>
|
||||
<string name="account_settings_message_format_text">Platte Tekst (plaatjes en formattering worden verwijderd)</string>
|
||||
<string name="account_settings_message_format_html">HTML (plaatjes en formattering blijven behouden)</string>
|
||||
|
||||
<!-- NEW: <string name="account_settings_quote_style_label">Reply quoting style</string>-->
|
||||
<!-- NEW: <string name="account_settings_quote_style_prefix">Prefix (like Gmail, Pine)</string>-->
|
||||
<!-- NEW: <string name="account_settings_quote_style_header">Header (like Outlook, Yahoo!, Hotmail)</string>-->
|
||||
<string name="account_settings_quote_style_label">Quotestijl bij antwoorden</string>
|
||||
<string name="account_settings_quote_style_prefix">Prefix (zoals Gmail, Pine)</string>
|
||||
<string name="account_settings_quote_style_header">Header (zoals Outlook, Yahoo!, Hotmail)</string>
|
||||
|
||||
<!-- NEW: <string name="account_settings_general_title">General settings</string>-->
|
||||
<!-- NEW: <string name="account_settings_display_prefs_title">Display</string>-->
|
||||
<string name="account_settings_general_title">Algemeen</string>
|
||||
<string name="account_settings_display_prefs_title">Scherm</string>
|
||||
<string name="account_settings_sync">Synchroniseren van mappen</string>
|
||||
<string name="account_settings_folders">Mappen</string>
|
||||
<string name="account_settings_message_lists">Lijst berichten</string>
|
||||
@ -591,7 +591,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="account_settings_mail_check_frequency_label">Mappen poll controleer frequentie</string>
|
||||
<string name="account_settings_second_class_check_frequency_label">2e klasse controleer frequentie</string>
|
||||
|
||||
<!-- NEW: <string name="account_settings_storage_title">Storage</string>-->
|
||||
<string name="account_settings_storage_title">Opslag</string>
|
||||
|
||||
|
||||
<string name="account_settings_color_label">Account kleur</string>
|
||||
@ -752,7 +752,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="choose_identity">Kies identiteit</string>
|
||||
<string name="choose_identity_title">Kies identiteit</string>
|
||||
<string name="choose_account_title">Kies account/identiteit</string>
|
||||
<!-- NEW: <string name="send_as">Send as</string>-->
|
||||
<string name="send_as">Verzenden als</string>
|
||||
|
||||
|
||||
<string name="no_identities">Ga naar Account Instellingen -> Beheer identiteiten om identiteiten aan te maken</string>
|
||||
@ -794,7 +794,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="provider_note_live">Alleen sommige \"Plus\" accounts staan POP access
|
||||
toe om verbinding te krijgen met dit programma. Als het niet mogelijk is om in te loggen met de juiste gebruikersnaam en wachtwoord, heb je misschien geen betaalde \"Plus\" account. Start de webbrowser om de toegang tot deze e-mailaccount te krijgen.</string>
|
||||
|
||||
<!-- NEW: <string name="provider_note_yahoojp">If you would like to use POP3 for this provider, You should permit to use POP3 on Yahoo mail settings page.</string>-->
|
||||
<string name="provider_note_yahoojp">Als je POP3 wilt gebruiken, moet je het geebruik van POP3 activeren op de Yahoo mail settings pagina.</string>
|
||||
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Onbekend Certificaat</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accepteer Sleutel</string>
|
||||
@ -831,21 +831,21 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="setting_theme_dark">Donker</string>
|
||||
<string name="setting_theme_light">Licht</string>
|
||||
<string name="display_preferences">Algemene instellingen</string>
|
||||
<!-- NEW: <string name="global_preferences">Global</string>-->
|
||||
<string name="global_preferences">Globaal</string>
|
||||
<string name="debug_preferences">Verwijderen van fouten</string>
|
||||
<!-- NEW: <string name="privacy_preferences">Privacy</string>-->
|
||||
<!-- NEW: <string name="network_preferences">Network</string>-->
|
||||
<!-- NEW: <string name="interaction_preferences">Interaction</string>-->
|
||||
<string name="privacy_preferences">Privacy</string>
|
||||
<string name="network_preferences">Netwerk</string>
|
||||
<string name="interaction_preferences">Interactie</string>
|
||||
<string name="accountlist_preferences">Account Lijst</string>
|
||||
<string name="messagelist_preferences">Berichten Lijst</string>
|
||||
<string name="messageview_preferences">Berichten</string>
|
||||
<string name="settings_theme_label">Thema</string>
|
||||
<string name="settings_language_label">Taal</string>
|
||||
|
||||
<!-- NEW: <string name="settings_messageview_mobile_layout_label">Single-column layout</string>-->
|
||||
<!-- NEW: <string name="settings_messageview_mobile_layout_summary">Reformat HTML messages for smaller screens</string>-->
|
||||
<!-- NEW: <string name="settings_messageview_zoom_controls_label">System zoom controls</string>-->
|
||||
<!-- NEW: <string name="settings_messageview_zoom_controls_summary">Enable zoom widgets or pinch-zoom if your device supports it</string>-->
|
||||
<string name="settings_messageview_mobile_layout_label">1-kolom layout</string>
|
||||
<string name="settings_messageview_mobile_layout_summary">Herschik HTML berichten voor kleinere schermen</string>
|
||||
<string name="settings_messageview_zoom_controls_label">Apparaat zoom</string>
|
||||
<string name="settings_messageview_zoom_controls_summary">Gebruik zoom widgets of pinch-zoom als het apparaat dat ondersteunt</string>
|
||||
|
||||
|
||||
|
||||
@ -899,8 +899,8 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="gestures_title">Gebaren</string>
|
||||
<string name="gestures_summary">Accepteer gebaren sturing</string>
|
||||
|
||||
<!-- NEW: <string name="compact_layouts_title">Compact layouts</string>-->
|
||||
<!-- NEW: <string name="compact_layouts_summary">Adjust layouts to display more on each page</string>-->
|
||||
<string name="compact_layouts_title">Compacte layout</string>
|
||||
<string name="compact_layouts_summary">Pas layout aan zodat er meer op een pagina past</string>
|
||||
|
||||
<string name="volume_navigation_title">Volume op/neer navigatie</string>
|
||||
<string name="volume_navigation_summary">Spring tussen items door gebruik van de volumeknoppen</string>
|
||||
@ -919,8 +919,8 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="count_search_title">Tel zoek resultaten</string>
|
||||
<string name="count_search_summary">Zet uit voor sneller beeldscherm</string>
|
||||
|
||||
<!-- NEW: <string name="hide_special_accounts_title">Hide special accounts</string>-->
|
||||
<!-- NEW: <string name="hide_special_accounts_summary">Hide the unified inbox and all messages accounts</string>-->
|
||||
<string name="hide_special_accounts_title">Verberg speciale accounts</string>
|
||||
<string name="hide_special_accounts_summary">Verberg de gecombineerde inbox and alle berichtaccounts</string>
|
||||
|
||||
<string name="search_title"><xliff:g id="search_name">%s</xliff:g> <xliff:g id="modifier">%s</xliff:g></string>
|
||||
<string name="flagged_modifier"> - Starred</string>
|
||||
@ -960,7 +960,7 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="font_size_message_list_subject">Bericht onderwerp</string>
|
||||
<string name="font_size_message_list_sender">bericht afzender</string>
|
||||
<string name="font_size_message_list_date">Bericht datum</string>
|
||||
<!-- NEW: <string name="font_size_message_list_preview">Preview</string>-->
|
||||
<string name="font_size_message_list_preview">Preview</string>
|
||||
|
||||
<string name="font_size_message_view">Beeld berichten</string>
|
||||
<string name="font_size_message_view_sender">bericht afzender</string>
|
||||
@ -1022,19 +1022,22 @@ Welkom bij K-9 Mail setup. K-9 is een open source mail cliënt voor Android, ge
|
||||
<string name="dialog_confirm_delete_confirm_button">Verwijder</string>
|
||||
<string name="dialog_confirm_delete_cancel_button">Niet verwijderen</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_confirm_spam_title">Confirm move to spam folder</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_message">Do you really want to move this message to the spam folder?</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_confirm_button">Yes</string>-->
|
||||
<!-- NEW: <string name="dialog_confirm_spam_cancel_button">No</string>-->
|
||||
<string name="dialog_confirm_spam_title">Bevestig verplaatsing naar spam map</string>
|
||||
<string name="dialog_confirm_spam_message">Wil je dit bericht echt verplaatsen naar de spam map?</string>
|
||||
<string name="dialog_confirm_spam_confirm_button">Ja</string>
|
||||
<string name="dialog_confirm_spam_cancel_button">Nee</string>
|
||||
|
||||
<!-- NEW: <string name="dialog_attachment_progress_title">Downloading attachment</string>-->
|
||||
<string name="dialog_attachment_progress_title">Bijlage wordt opgehaald</string>
|
||||
|
||||
<string name="debug_logging_enabled">Debug logging van Android logging systeem ingeschakeld</string>
|
||||
|
||||
<!-- NEW: <string name="messagelist_sent_to_me_sigil">»</string>-->
|
||||
<!-- NEW: <string name="messagelist_sent_cc_me_sigil">›</string>-->
|
||||
<!-- NEW: <string name="error_unable_to_connect">Unable to connect.</string>-->
|
||||
<string name="messagelist_sent_to_me_sigil">»</string> <!-- why is this language dependent? -->
|
||||
<string name="messagelist_sent_cc_me_sigil">›</string>
|
||||
<string name="error_unable_to_connect">Kan geen verbinding maken.</string>
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
<string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is niet beschikbaar; controleer opslag</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Sla bijlagen op naar...</string>
|
||||
<string name="attachment_save_title">Sla bijlage op</string>
|
||||
<string name="attachment_save_desc">Geen bestandsverkenner gevonden. Waar wil je deze bijlage opslaan?</string>
|
||||
</resources>
|
||||
|
@ -1049,4 +1049,7 @@ Witaj w K-9 Mail, darmowym programie pocztowym dla systemu Android. Najistotniej
|
||||
|
||||
<string name="account_unavailable">Konto \"<xliff:g id="account">%s</xliff:g>\" jest niedostępne; sprawdź pamięc</string>
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1034,4 +1034,7 @@ Bem-vindo à configuração do K-9 Mail. K-9 é um cliente de e-mail com código
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1031,4 +1031,7 @@
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1040,4 +1040,7 @@ Välkommen till installationen av K-9 E-post. K-9 är en e-postklient med öppen
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -1021,4 +1021,7 @@
|
||||
|
||||
<!-- NEW: <string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>-->
|
||||
|
||||
<!-- NEW: <string name="settings_attachment_default_path">Save attachments to...</string>-->
|
||||
<!-- NEW: <string name="attachment_save_title">Save attachment</string>-->
|
||||
<!-- NEW: <string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>-->
|
||||
</resources>
|
||||
|
@ -501,6 +501,7 @@
|
||||
<item>zh_CN</item>
|
||||
<item>fi</item>
|
||||
<item>sv</item>
|
||||
<item>ko</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="settings_theme_entries">
|
||||
|
@ -270,7 +270,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="error_contact_address_not_found">No email address could be found.</string>
|
||||
<string name="message_compose_downloading_attachments_toast">Some attachments were not downloaded. They will be downloaded automatically before this message is sent.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Some attachments cannot be forwarded because they have not been downloaded.</string>
|
||||
|
||||
<string name="message_compose_show_quoted_text_action">Quote message</string>
|
||||
|
||||
|
||||
<string name="message_view_from_format">From: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
@ -564,6 +564,9 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
|
||||
<string name="account_settings_composition">Sending mail</string>
|
||||
|
||||
<string name="account_settings_default_quoted_text_shown_label">Quote original message when replying</string>
|
||||
<string name="account_settings_default_quoted_text_shown_summary">When replying to messages, the original message is in your reply.</string>
|
||||
|
||||
<string name="account_settings_reply_after_quote_label">Reply after quoted text</string>
|
||||
<string name="account_settings_reply_after_quote_summary">When replying to messages, the original message will appear above your reply.</string>
|
||||
|
||||
@ -800,6 +803,11 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
|
||||
<string name="provider_note_yahoojp">If you would like to use POP3 for this provider, You should permit to use POP3 on Yahoo mail settings page.</string>
|
||||
|
||||
<string name="provider_note_naver">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Naver mail settings page.</string>
|
||||
<string name="provider_note_hanmail">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Hanmail(Daum) mail settings page.</string>
|
||||
<string name="provider_note_paran">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Paran mail settings page.</string>
|
||||
<string name="provider_note_nate">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Nate mail settings page.</string>
|
||||
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
@ -1041,4 +1049,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
|
||||
<string name="account_unavailable">Account \"<xliff:g id="account">%s</xliff:g>\" is unavailable; check storage</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Save attachments to...</string>
|
||||
<string name="attachment_save_title">Save attachment</string>
|
||||
<string name="attachment_save_desc">No file browser found. Where would you like to save this attachment?</string>
|
||||
|
||||
</resources>
|
||||
|
@ -239,6 +239,13 @@
|
||||
android:entries="@array/account_settings_quote_style_entries"
|
||||
android:entryValues="@array/account_settings_quote_style_values" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:persistent="false"
|
||||
android:key="default_quoted_text_shown"
|
||||
android:title="@string/account_settings_default_quoted_text_shown_label"
|
||||
android:defaultValue="true"
|
||||
android:summary="@string/account_settings_default_quoted_text_shown_summary" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:persistent="false"
|
||||
android:key="reply_after_quote"
|
||||
|
@ -231,7 +231,6 @@
|
||||
android:dialogTitle="@string/global_settings_confirm_actions_title"
|
||||
android:positiveButtonText="@android:string/ok"
|
||||
android:negativeButtonText="@android:string/cancel" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
@ -284,6 +283,11 @@
|
||||
android:title="@string/misc_preferences_attachment_title"
|
||||
android:summary="@string/misc_preferences_attachment_description" />
|
||||
|
||||
<Preference
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_attachment_default_path"
|
||||
android:key="attachment_default_path"
|
||||
android:summary="- PATH - set by activty -"/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
|
@ -276,6 +276,33 @@
|
||||
<outgoing uri="smtp://smtp.mail.yahoo.co.jp:587" username="$user" />
|
||||
</provider>
|
||||
|
||||
<!-- Korean -->
|
||||
<provider id="naver" label="Naver" domain="naver.com"
|
||||
note="@string/provider_note_naver">
|
||||
<incoming uri="imap+ssl://imap.naver.com" username="$user" />
|
||||
<outgoing uri="smtp+tls://smtp.naver.com:587" username="$user" />
|
||||
</provider>
|
||||
<provider id="hanmail" label="Hanmail" domain="hanmail.net"
|
||||
note="@string/provider_note_hanmail">
|
||||
<incoming uri="imap+ssl://imap.hanmail.net" username="$user" />
|
||||
<outgoing uri="smtp+ssl://smtp.hanmail.net" username="$user" />
|
||||
</provider>
|
||||
<provider id="daum" label="Hanmail" domain="daum.net"
|
||||
note="@string/provider_note_hanmail">
|
||||
<incoming uri="imap+ssl://imap.hanmail.net" username="$user" />
|
||||
<outgoing uri="smtp+ssl://smtp.hanmail.net" username="$user" />
|
||||
</provider>
|
||||
<provider id="paran" label="Paran" domain="paran.com"
|
||||
note="@string/provider_note_paran">
|
||||
<incoming uri="imap+ssl://imap.paran.com" username="$email" />
|
||||
<outgoing uri="smtp+tls://smtp.paran.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="nate" label="Nate" domain="nate.com"
|
||||
note="@string/provider_note_nate">
|
||||
<incoming uri="imap+ssl://imap.nate.com" username="$user" />
|
||||
<outgoing uri="smtp+tls://smtp.mail.nate.com" username="$user" />
|
||||
</provider>
|
||||
|
||||
<!-- Developers' vanity providers -->
|
||||
<provider id="fsck.com" label="Jesse's personal mail" domain="fsck.com" >
|
||||
<incoming uri="imap+ssl://fsck.com" username="$user" />
|
||||
|
@ -33,6 +33,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* and delete itself given a Preferences to work with. Each account is defined by a UUID.
|
||||
*/
|
||||
public class Account implements BaseAccount {
|
||||
/**
|
||||
* Default value for the inbox folder (never changes for POP3 and IMAP)
|
||||
*/
|
||||
public static final String INBOX = "INBOX";
|
||||
|
||||
/**
|
||||
* This local folder is used to store messages to be sent.
|
||||
*/
|
||||
public static final String OUTBOX = "OUTBOX";
|
||||
|
||||
public static final String EXPUNGE_IMMEDIATELY = "EXPUNGE_IMMEDIATELY";
|
||||
public static final String EXPUNGE_MANUALLY = "EXPUNGE_MANUALLY";
|
||||
public static final String EXPUNGE_ON_POLL = "EXPUNGE_ON_POLL";
|
||||
@ -50,6 +60,7 @@ public class Account implements BaseAccount {
|
||||
private static final MessageFormat DEFAULT_MESSAGE_FORMAT = MessageFormat.HTML;
|
||||
private static final QuoteStyle DEFAULT_QUOTE_STYLE = QuoteStyle.PREFIX;
|
||||
private static final String DEFAULT_QUOTE_PREFIX = ">";
|
||||
private static final boolean DEFAULT_QUOTED_TEXT_SHOWN = true;
|
||||
private static final boolean DEFAULT_REPLY_AFTER_QUOTE = false;
|
||||
|
||||
/**
|
||||
@ -80,6 +91,7 @@ public class Account implements BaseAccount {
|
||||
private long mLatestOldMessageSeenTime;
|
||||
private boolean mNotifyNewMail;
|
||||
private boolean mNotifySelfNewMail;
|
||||
private String mInboxFolderName;
|
||||
private String mDraftsFolderName;
|
||||
private String mSentFolderName;
|
||||
private String mTrashFolderName;
|
||||
@ -115,6 +127,7 @@ public class Account implements BaseAccount {
|
||||
private MessageFormat mMessageFormat;
|
||||
private QuoteStyle mQuoteStyle;
|
||||
private String mQuotePrefix;
|
||||
private boolean mDefaultQuotedTextShown;
|
||||
private boolean mReplyAfterQuote;
|
||||
private boolean mSyncRemoteDeletions;
|
||||
private String mCryptoApp;
|
||||
@ -180,7 +193,8 @@ public class Account implements BaseAccount {
|
||||
mEnableMoveButtons = false;
|
||||
mIsSignatureBeforeQuotedText = false;
|
||||
mExpungePolicy = EXPUNGE_IMMEDIATELY;
|
||||
mAutoExpandFolderName = "INBOX";
|
||||
mAutoExpandFolderName = INBOX;
|
||||
mInboxFolderName = INBOX;
|
||||
mMaxPushFolders = 10;
|
||||
mChipColor = (new Random()).nextInt(0xffffff) + 0xff000000;
|
||||
goToUnreadMessageSearch = false;
|
||||
@ -191,6 +205,7 @@ public class Account implements BaseAccount {
|
||||
mMessageFormat = DEFAULT_MESSAGE_FORMAT;
|
||||
mQuoteStyle = DEFAULT_QUOTE_STYLE;
|
||||
mQuotePrefix = DEFAULT_QUOTE_PREFIX;
|
||||
mDefaultQuotedTextShown = DEFAULT_QUOTED_TEXT_SHOWN;
|
||||
mReplyAfterQuote = DEFAULT_REPLY_AFTER_QUOTE;
|
||||
mSyncRemoteDeletions = true;
|
||||
mCryptoApp = Apg.NAME;
|
||||
@ -246,6 +261,7 @@ public class Account implements BaseAccount {
|
||||
mNotifySelfNewMail = prefs.getBoolean(mUuid + ".notifySelfNewMail", true);
|
||||
mNotifySync = prefs.getBoolean(mUuid + ".notifyMailCheck", false);
|
||||
mDeletePolicy = prefs.getInt(mUuid + ".deletePolicy", 0);
|
||||
mInboxFolderName = prefs.getString(mUuid + ".inboxFolderName", INBOX);
|
||||
mDraftsFolderName = prefs.getString(mUuid + ".draftsFolderName", "Drafts");
|
||||
mSentFolderName = prefs.getString(mUuid + ".sentFolderName", "Sent");
|
||||
mTrashFolderName = prefs.getString(mUuid + ".trashFolderName", "Trash");
|
||||
@ -263,6 +279,7 @@ public class Account implements BaseAccount {
|
||||
mMessageFormat = MessageFormat.valueOf(prefs.getString(mUuid + ".messageFormat", DEFAULT_MESSAGE_FORMAT.name()));
|
||||
mQuoteStyle = QuoteStyle.valueOf(prefs.getString(mUuid + ".quoteStyle", DEFAULT_QUOTE_STYLE.name()));
|
||||
mQuotePrefix = prefs.getString(mUuid + ".quotePrefix", DEFAULT_QUOTE_PREFIX);
|
||||
mDefaultQuotedTextShown = prefs.getBoolean(mUuid + ".defaultQuotedTextShown", DEFAULT_QUOTED_TEXT_SHOWN);
|
||||
mReplyAfterQuote = prefs.getBoolean(mUuid + ".replyAfterQuote", DEFAULT_REPLY_AFTER_QUOTE);
|
||||
for (String type : networkTypes) {
|
||||
Boolean useCompression = prefs.getBoolean(mUuid + ".useCompression." + type,
|
||||
@ -270,8 +287,7 @@ public class Account implements BaseAccount {
|
||||
compressionMap.put(type, useCompression);
|
||||
}
|
||||
|
||||
mAutoExpandFolderName = prefs.getString(mUuid + ".autoExpandFolderName",
|
||||
"INBOX");
|
||||
mAutoExpandFolderName = prefs.getString(mUuid + ".autoExpandFolderName", INBOX);
|
||||
|
||||
mAccountNumber = prefs.getInt(mUuid + ".accountNumber", 0);
|
||||
|
||||
@ -485,6 +501,7 @@ public class Account implements BaseAccount {
|
||||
editor.putBoolean(mUuid + ".notifySelfNewMail", mNotifySelfNewMail);
|
||||
editor.putBoolean(mUuid + ".notifyMailCheck", mNotifySync);
|
||||
editor.putInt(mUuid + ".deletePolicy", mDeletePolicy);
|
||||
editor.putString(mUuid + ".inboxFolderName", mInboxFolderName);
|
||||
editor.putString(mUuid + ".draftsFolderName", mDraftsFolderName);
|
||||
editor.putString(mUuid + ".sentFolderName", mSentFolderName);
|
||||
editor.putString(mUuid + ".trashFolderName", mTrashFolderName);
|
||||
@ -514,6 +531,7 @@ public class Account implements BaseAccount {
|
||||
editor.putString(mUuid + ".messageFormat", mMessageFormat.name());
|
||||
editor.putString(mUuid + ".quoteStyle", mQuoteStyle.name());
|
||||
editor.putString(mUuid + ".quotePrefix", mQuotePrefix);
|
||||
editor.putBoolean(mUuid + ".defaultQuotedTextShown", mDefaultQuotedTextShown);
|
||||
editor.putBoolean(mUuid + ".replyAfterQuote", mReplyAfterQuote);
|
||||
editor.putString(mUuid + ".cryptoApp", mCryptoApp);
|
||||
editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
|
||||
@ -762,7 +780,7 @@ public class Account implements BaseAccount {
|
||||
|
||||
|
||||
public boolean isSpecialFolder(String folderName) {
|
||||
if (folderName != null && (folderName.equalsIgnoreCase(K9.INBOX) ||
|
||||
if (folderName != null && (folderName.equalsIgnoreCase(getInboxFolderName()) ||
|
||||
folderName.equals(getTrashFolderName()) ||
|
||||
folderName.equals(getDraftsFolderName()) ||
|
||||
folderName.equals(getArchiveFolderName()) ||
|
||||
@ -824,7 +842,7 @@ public class Account implements BaseAccount {
|
||||
}
|
||||
|
||||
public synchronized String getOutboxFolderName() {
|
||||
return K9.OUTBOX;
|
||||
return OUTBOX;
|
||||
}
|
||||
|
||||
public synchronized String getAutoExpandFolderName() {
|
||||
@ -1270,6 +1288,14 @@ public class Account implements BaseAccount {
|
||||
mQuotePrefix = quotePrefix;
|
||||
}
|
||||
|
||||
public synchronized boolean isDefaultQuotedTextShown() {
|
||||
return mDefaultQuotedTextShown;
|
||||
}
|
||||
|
||||
public synchronized void setDefaultQuotedTextShown(boolean shown) {
|
||||
mDefaultQuotedTextShown = shown;
|
||||
}
|
||||
|
||||
public synchronized boolean isReplyAfterQuote() {
|
||||
return mReplyAfterQuote;
|
||||
}
|
||||
@ -1303,6 +1329,15 @@ public class Account implements BaseAccount {
|
||||
public void setCryptoAutoSignature(boolean cryptoAutoSignature) {
|
||||
mCryptoAutoSignature = cryptoAutoSignature;
|
||||
}
|
||||
|
||||
public String getInboxFolderName() {
|
||||
return mInboxFolderName;
|
||||
}
|
||||
|
||||
public void setInboxFolderName(String mInboxFolderName) {
|
||||
this.mInboxFolderName = mInboxFolderName;
|
||||
}
|
||||
|
||||
public synchronized boolean syncRemoteDeletions() {
|
||||
return mSyncRemoteDeletions;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
package com.fsck.k9;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -18,9 +19,11 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.format.Time;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.activity.MessageCompose;
|
||||
@ -65,6 +68,10 @@ public class K9 extends Application {
|
||||
*/
|
||||
private static List<ApplicationAware> observers = new ArrayList<ApplicationAware>();
|
||||
|
||||
/**
|
||||
* @see K9#createAbsoluteSizeSpan(int)
|
||||
*/
|
||||
private static Constructor<AbsoluteSizeSpan> sAbsoluteSizeSpanConstructor;
|
||||
|
||||
public enum BACKGROUND_OPS {
|
||||
WHEN_CHECKED, ALWAYS, NEVER, WHEN_CHECKED_AUTO_SYNC
|
||||
@ -143,7 +150,6 @@ public class K9 extends Application {
|
||||
public static boolean ENABLE_ERROR_FOLDER = true;
|
||||
public static String ERROR_FOLDER_NAME = "K9mail-errors";
|
||||
|
||||
|
||||
private static boolean mAnimations = true;
|
||||
|
||||
private static boolean mConfirmDelete = false;
|
||||
@ -177,7 +183,7 @@ public class K9 extends Application {
|
||||
private static String mQuietTimeStarts = null;
|
||||
private static String mQuietTimeEnds = null;
|
||||
private static boolean compactLayouts = false;
|
||||
|
||||
private static String mAttachmentDefaultPath = "";
|
||||
|
||||
|
||||
private static boolean useGalleryBugWorkaround = false;
|
||||
@ -210,17 +216,6 @@ public class K9 extends Application {
|
||||
public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
|
||||
};
|
||||
|
||||
/**
|
||||
* The special name "INBOX" is used throughout the application to mean "Whatever folder
|
||||
* the server refers to as the user's Inbox. Placed here to ease use.
|
||||
*/
|
||||
public static final String INBOX = "INBOX";
|
||||
|
||||
/**
|
||||
* This local folder is used to store messages to be sent.
|
||||
*/
|
||||
public static final String OUTBOX = "OUTBOX";
|
||||
|
||||
/**
|
||||
* For use when displaying that no folder is selected
|
||||
*/
|
||||
@ -452,7 +447,7 @@ public class K9 extends Application {
|
||||
editor.putBoolean("keyguardPrivacy", mKeyguardPrivacy);
|
||||
|
||||
editor.putBoolean("compactLayouts", compactLayouts);
|
||||
|
||||
editor.putString("attachmentdefaultpath", mAttachmentDefaultPath);
|
||||
fontSizes.save(editor);
|
||||
}
|
||||
|
||||
@ -507,7 +502,7 @@ public class K9 extends Application {
|
||||
mKeyguardPrivacy = sprefs.getBoolean("keyguardPrivacy", false);
|
||||
|
||||
compactLayouts = sprefs.getBoolean("compactLayouts", false);
|
||||
|
||||
mAttachmentDefaultPath = sprefs.getString("attachmentdefaultpath", Environment.getExternalStorageDirectory().toString());
|
||||
fontSizes.load(sprefs);
|
||||
|
||||
try {
|
||||
@ -942,11 +937,11 @@ public class K9 extends Application {
|
||||
}
|
||||
|
||||
public static boolean confirmSpam() {
|
||||
return mConfirmSpam;
|
||||
return mConfirmSpam;
|
||||
}
|
||||
|
||||
public static void setConfirmSpam(final boolean confirm) {
|
||||
mConfirmSpam = confirm;
|
||||
mConfirmSpam = confirm;
|
||||
}
|
||||
|
||||
public static boolean confirmMarkAllAsRead() {
|
||||
@ -995,4 +990,55 @@ public class K9 extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAttachmentDefaultPath() {
|
||||
return mAttachmentDefaultPath;
|
||||
}
|
||||
|
||||
public static void setAttachmentDefaultPath(String attachmentDefaultPath) {
|
||||
K9.mAttachmentDefaultPath = attachmentDefaultPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AbsoluteSizeSpan} object.
|
||||
*
|
||||
* <p>
|
||||
* Android versions prior to 2.0 don't support the constructor with two parameters
|
||||
* ({@link AbsoluteSizeSpan#AbsoluteSizeSpan(int, boolean)}). So we have to perform some
|
||||
* reflection magic to dynamically load the new constructor on devices that support it.
|
||||
* For devices with old Android versions we just use the size as pixels (instead of dip).
|
||||
* </p>
|
||||
*
|
||||
* @param size This is used as the {@code size} parameter for the AbsoluteSizeSpan constructor.
|
||||
* @return a AbsoluteSizeSpan object with the specified text size.
|
||||
*/
|
||||
public static AbsoluteSizeSpan createAbsoluteSizeSpan(int size) {
|
||||
if (Integer.parseInt(android.os.Build.VERSION.SDK) < 5) {
|
||||
// For Android 1.5/1.6 simply use the constructor with only the size parameter.
|
||||
// Yes, that will most likely look wrong!
|
||||
return new AbsoluteSizeSpan(size);
|
||||
}
|
||||
|
||||
if (sAbsoluteSizeSpanConstructor == null) {
|
||||
try {
|
||||
sAbsoluteSizeSpanConstructor = AbsoluteSizeSpan.class.getConstructor(int.class, boolean.class);
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't get the AbsoluteSizeSpan(int, boolean) constructor", e);
|
||||
|
||||
// Fallback
|
||||
return new AbsoluteSizeSpan(size);
|
||||
}
|
||||
}
|
||||
|
||||
AbsoluteSizeSpan result;
|
||||
try {
|
||||
result = sAbsoluteSizeSpanConstructor.newInstance(size, true);
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't call the AbsoluteSizeSpan(int, boolean) constructor", e);
|
||||
|
||||
// Fallback
|
||||
result = new AbsoluteSizeSpan(size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -457,66 +457,66 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_delete_dlg_title,
|
||||
getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
try {
|
||||
realAccount.getLocalStore().delete();
|
||||
} catch (Exception e) {
|
||||
// Ignore, this may lead to localStores on sd-cards that are
|
||||
// currently not inserted to be left
|
||||
}
|
||||
MessagingController.getInstance(getApplication())
|
||||
.notifyAccountCancel(Accounts.this, realAccount);
|
||||
Preferences.getPreferences(Accounts.this).deleteAccount(realAccount);
|
||||
K9.setServicesEnabled(Accounts.this);
|
||||
refresh();
|
||||
}
|
||||
R.string.account_delete_dlg_title,
|
||||
getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
try {
|
||||
realAccount.getLocalStore().delete();
|
||||
} catch (Exception e) {
|
||||
// Ignore, this may lead to localStores on sd-cards that are
|
||||
// currently not inserted to be left
|
||||
}
|
||||
});
|
||||
MessagingController.getInstance(getApplication())
|
||||
.notifyAccountCancel(Accounts.this, realAccount);
|
||||
Preferences.getPreferences(Accounts.this).deleteAccount(realAccount);
|
||||
K9.setServicesEnabled(Accounts.this);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
case DIALOG_CLEAR_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_clear_dlg_title,
|
||||
getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication()).clear(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
R.string.account_clear_dlg_title,
|
||||
getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication()).clear(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
case DIALOG_RECREATE_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_recreate_dlg_title,
|
||||
getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication()).recreate(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
R.string.account_recreate_dlg_title,
|
||||
getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication()).recreate(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import android.content.Context;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.AccountStats;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.service.MailService;
|
||||
@ -35,7 +34,7 @@ public class ActivityListener extends MessagingListener {
|
||||
|
||||
if (mLoadingFolderName != null || mLoadingHeaderFolderName != null) {
|
||||
String displayName = mLoadingFolderName;
|
||||
if (K9.INBOX.equalsIgnoreCase(displayName)) {
|
||||
if ((mAccount != null) && (mAccount.getInboxFolderName() != null) && mAccount.getInboxFolderName().equalsIgnoreCase(displayName)) {
|
||||
displayName = context.getString(R.string.special_mailbox_name_inbox);
|
||||
} else if ((mAccount != null) && mAccount.getOutboxFolderName().equals(displayName)) {
|
||||
displayName = context.getString(R.string.special_mailbox_name_outbox);
|
||||
|
@ -100,6 +100,7 @@ public class ChooseFolder extends K9ListActivity {
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
|
||||
mMode = mAccount.getFolderTargetMode();
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener);
|
||||
|
||||
|
||||
@ -248,7 +249,8 @@ public class ChooseFolder extends K9ListActivity {
|
||||
String name = folder.getName();
|
||||
|
||||
// Inbox needs to be compared case-insensitively
|
||||
if (hideCurrentFolder && (name.equals(mFolder) || (K9.INBOX.equalsIgnoreCase(mFolder) && K9.INBOX.equalsIgnoreCase(name)))) {
|
||||
if (hideCurrentFolder && (name.equals(mFolder) ||
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
@ -282,10 +284,10 @@ public class ChooseFolder extends K9ListActivity {
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(bName)) {
|
||||
return 1;
|
||||
}
|
||||
if (K9.INBOX.equalsIgnoreCase(aName)) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(aName)) {
|
||||
return -1;
|
||||
}
|
||||
if (K9.INBOX.equalsIgnoreCase(bName)) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(bName)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -298,7 +300,7 @@ public class ChooseFolder extends K9ListActivity {
|
||||
mAdapter.clear();
|
||||
int position = 0;
|
||||
for (String name : localFolders) {
|
||||
if (K9.INBOX.equalsIgnoreCase(name)) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
|
||||
mAdapter.add(getString(R.string.special_mailbox_name_inbox));
|
||||
heldInbox = name;
|
||||
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
|
||||
@ -315,7 +317,7 @@ public class ChooseFolder extends K9ListActivity {
|
||||
selectedFolder = position;
|
||||
}
|
||||
} else if (name.equals(mFolder) ||
|
||||
(K9.INBOX.equalsIgnoreCase(mFolder) && K9.INBOX.equalsIgnoreCase(name))) {
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
|
||||
selectedFolder = position;
|
||||
}
|
||||
position++;
|
||||
|
@ -20,27 +20,27 @@ public class ConfirmationDialog {
|
||||
* @return A confirmation dialog with the supplied arguments
|
||||
*/
|
||||
public static Dialog create(final Activity activity, final int dialogId, final int title,
|
||||
final String message, final int confirmButton, final int cancelButton,
|
||||
final Runnable action) {
|
||||
final String message, final int confirmButton, final int cancelButton,
|
||||
final Runnable action) {
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(message);
|
||||
builder.setPositiveButton(confirmButton,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.dismissDialog(dialogId);
|
||||
action.run();
|
||||
}
|
||||
});
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.dismissDialog(dialogId);
|
||||
action.run();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(cancelButton,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.dismissDialog(dialogId);
|
||||
}
|
||||
});
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.dismissDialog(dialogId);
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@ -58,10 +58,10 @@ public class ConfirmationDialog {
|
||||
* @see #create(Activity,int,int,String,int,int,Runnable)
|
||||
*/
|
||||
public static Dialog create(final Activity activity, final int dialogId, final int title,
|
||||
final int message, final int confirmButton, final int cancelButton,
|
||||
final Runnable action) {
|
||||
final int message, final int confirmButton, final int cancelButton,
|
||||
final Runnable action) {
|
||||
|
||||
return create(activity, dialogId, title, activity.getString(message), confirmButton,
|
||||
cancelButton, action);
|
||||
cancelButton, action);
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class FolderInfoHolder implements Comparable<FolderInfoHolder> {
|
||||
|
||||
this.status = truncateStatus(folder.getStatus());
|
||||
|
||||
if (this.name.equalsIgnoreCase(K9.INBOX)) {
|
||||
if (this.name.equalsIgnoreCase(account.getInboxFolderName())) {
|
||||
this.displayName = context.getString(R.string.special_mailbox_name_inbox);
|
||||
} else {
|
||||
this.displayName = folder.getName();
|
||||
|
@ -487,6 +487,7 @@ public class FolderList extends K9ListActivity {
|
||||
}
|
||||
}
|
||||
|
||||
onRefresh(!REFRESH_REMOTE);
|
||||
}
|
||||
|
||||
|
||||
@ -641,10 +642,12 @@ public class FolderList extends K9ListActivity {
|
||||
private void markAllAsRead() {
|
||||
try {
|
||||
MessagingController.getInstance(getApplication())
|
||||
.markAllMessagesRead(mAccount, mSelectedContextFolder.name);
|
||||
.markAllMessagesRead(mAccount, mSelectedContextFolder.name);
|
||||
mSelectedContextFolder.unreadMessageCount = 0;
|
||||
mHandler.dataChanged();
|
||||
} catch (Exception e) { /* Ignore */ }
|
||||
} catch (Exception e) {
|
||||
/* Ignore */
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -652,17 +655,17 @@ public class FolderList extends K9ListActivity {
|
||||
switch (id) {
|
||||
case DIALOG_MARK_ALL_AS_READ:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.mark_all_as_read_dlg_title,
|
||||
getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
||||
mSelectedContextFolder.displayName),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
markAllAsRead();
|
||||
}
|
||||
});
|
||||
R.string.mark_all_as_read_dlg_title,
|
||||
getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
||||
mSelectedContextFolder.displayName),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
markAllAsRead();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
@ -38,6 +38,7 @@ import android.view.View.OnFocusChangeListener;
|
||||
import android.view.Window;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.AutoCompleteTextView.Validator;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
@ -89,8 +90,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
"com.fsck.k9.activity.MessageCompose.ccShown";
|
||||
private static final String STATE_KEY_BCC_SHOWN =
|
||||
"com.fsck.k9.activity.MessageCompose.bccShown";
|
||||
private static final String STATE_KEY_QUOTED_TEXT_SHOWN =
|
||||
"com.fsck.k9.activity.MessageCompose.quotedTextShown";
|
||||
private static final String STATE_KEY_QUOTED_TEXT_MODE =
|
||||
"com.fsck.k9.activity.MessageCompose.QuotedTextShown";
|
||||
private static final String STATE_KEY_SOURCE_MESSAGE_PROCED =
|
||||
"com.fsck.k9.activity.MessageCompose.stateKeySourceMessageProced";
|
||||
private static final String STATE_KEY_DRAFT_UID =
|
||||
@ -161,6 +162,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
*/
|
||||
private boolean mSourceMessageProcessed = false;
|
||||
|
||||
private enum QuotedTextMode {
|
||||
NONE,
|
||||
SHOW,
|
||||
HIDE
|
||||
};
|
||||
|
||||
private QuotedTextMode mQuotedTextMode = QuotedTextMode.NONE;
|
||||
|
||||
private TextView mFromView;
|
||||
private LinearLayout mCcWrapper;
|
||||
@ -172,6 +180,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
private EditText mSignatureView;
|
||||
private EditText mMessageContentView;
|
||||
private LinearLayout mAttachments;
|
||||
private Button mQuotedTextShow;
|
||||
private View mQuotedTextBar;
|
||||
private ImageButton mQuotedTextEdit;
|
||||
private ImageButton mQuotedTextDelete;
|
||||
@ -391,6 +400,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mMessageContentView = (EditText)findViewById(R.id.message_content);
|
||||
mMessageContentView.getInputExtras(true).putBoolean("allowEmoji", true);
|
||||
mAttachments = (LinearLayout)findViewById(R.id.attachments);
|
||||
mQuotedTextShow = (Button)findViewById(R.id.quoted_text_show);
|
||||
mQuotedTextBar = findViewById(R.id.quoted_text_bar);
|
||||
mQuotedTextEdit = (ImageButton)findViewById(R.id.quoted_text_edit);
|
||||
mQuotedTextDelete = (ImageButton)findViewById(R.id.quoted_text_delete);
|
||||
@ -467,11 +477,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
* We set this to invisible by default. Other methods will turn it back on if it's
|
||||
* needed.
|
||||
*/
|
||||
mQuotedTextBar.setVisibility(View.GONE);
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
mQuotedTextEdit.setVisibility(View.GONE);
|
||||
|
||||
showOrHideQuotedText(QuotedTextMode.NONE);
|
||||
|
||||
mQuotedTextShow.setOnClickListener(this);
|
||||
mQuotedTextEdit.setOnClickListener(this);
|
||||
mQuotedTextDelete.setOnClickListener(this);
|
||||
|
||||
@ -801,7 +810,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
outState.putParcelableArrayList(STATE_KEY_ATTACHMENTS, attachments);
|
||||
outState.putBoolean(STATE_KEY_CC_SHOWN, mCcView.getVisibility() == View.VISIBLE);
|
||||
outState.putBoolean(STATE_KEY_BCC_SHOWN, mBccView.getVisibility() == View.VISIBLE);
|
||||
outState.putBoolean(STATE_KEY_QUOTED_TEXT_SHOWN, mQuotedTextBar.getVisibility() == View.VISIBLE);
|
||||
outState.putSerializable(STATE_KEY_QUOTED_TEXT_MODE, mQuotedTextMode);
|
||||
outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, mSourceMessageProcessed);
|
||||
outState.putString(STATE_KEY_DRAFT_UID, mDraftUid);
|
||||
outState.putSerializable(STATE_IDENTITY, mIdentity);
|
||||
@ -829,17 +838,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
: View.GONE);
|
||||
mBccWrapper.setVisibility(savedInstanceState
|
||||
.getBoolean(STATE_KEY_BCC_SHOWN) ? View.VISIBLE : View.GONE);
|
||||
if (mMessageFormat == MessageFormat.HTML) {
|
||||
showOrHideQuotedText((QuotedTextMode)savedInstanceState.getSerializable(STATE_KEY_QUOTED_TEXT_MODE));
|
||||
|
||||
if (mQuotedTextMode != QuotedTextMode.NONE && mMessageFormat == MessageFormat.HTML) {
|
||||
mQuotedHtmlContent = (InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
|
||||
mQuotedTextBar.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
|
||||
mQuotedHTML.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
|
||||
if (mQuotedHtmlContent != null && mQuotedHtmlContent.getQuotedContent() != null) {
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedTextEdit.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mQuotedTextBar.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
|
||||
mQuotedText.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
mDraftUid = savedInstanceState.getString(STATE_KEY_DRAFT_UID);
|
||||
mIdentity = (Identity)savedInstanceState.getSerializable(STATE_IDENTITY);
|
||||
@ -904,10 +909,27 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
|
||||
String text = mMessageContentView.getText().toString();
|
||||
|
||||
boolean discardQuotedText = false;
|
||||
if (!isDraft && !mQuotedTextMode.equals(QuotedTextMode.SHOW)) {
|
||||
discardQuotedText = true;
|
||||
}
|
||||
|
||||
if (discardQuotedText) {
|
||||
if (!isDraft) {
|
||||
text = appendSignature(text);
|
||||
}
|
||||
|
||||
// Build the body.
|
||||
TextBody body = new TextBody(text);
|
||||
body.setComposedMessageLength(text.length());
|
||||
body.setComposedMessageOffset(0);
|
||||
|
||||
return body;
|
||||
}
|
||||
// Handle HTML separate from the rest of the text content. HTML mode doesn't allow signature after the quoted
|
||||
// text, nor does it allow reply after quote. Users who want that functionality will need to stick with text
|
||||
// mode.
|
||||
if (mMessageFormat == MessageFormat.HTML) {
|
||||
else if (mMessageFormat == MessageFormat.HTML) {
|
||||
// Add the signature.
|
||||
if (!isDraft) {
|
||||
text = appendSignature(text);
|
||||
@ -917,10 +939,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (K9.DEBUG && mQuotedHtmlContent != null)
|
||||
Log.d(K9.LOG_TAG, "insertable: " + mQuotedHtmlContent.toDebugString());
|
||||
if (mQuotedHtmlContent != null) {
|
||||
// Remove the quoted part if it's no longer visible.
|
||||
if (mQuotedTextBar.getVisibility() != View.VISIBLE) {
|
||||
mQuotedHtmlContent.clearQuotedContent();
|
||||
}
|
||||
|
||||
// Set the insertion location based upon our reply after quote setting. Reply after
|
||||
// quote makes no sense for HEADER style replies. In addition, add some extra
|
||||
@ -965,7 +983,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
text = appendSignature(text);
|
||||
}
|
||||
|
||||
if (mQuotedTextBar.getVisibility() == View.VISIBLE) {
|
||||
if (mQuotedTextMode != QuotedTextMode.NONE) {
|
||||
if (replyAfterQuote) {
|
||||
composedMessageOffset = mQuotedText.getText().toString().length() + "\n".length();
|
||||
text = mQuotedText.getText().toString() + "\n" + text;
|
||||
@ -1121,7 +1139,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
*/
|
||||
bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, String.format(
|
||||
"attachment;\n filename=\"%s\";\n size=%d",
|
||||
EncoderUtil.encodeIfNecessary(attachment.name,
|
||||
EncoderUtil.encodeIfNecessary(attachment.name,
|
||||
EncoderUtil.Usage.WORD_ENTITY, 7),
|
||||
attachment.size));
|
||||
|
||||
@ -1139,7 +1157,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
NAME("n"),
|
||||
EMAIL("e"),
|
||||
// TODO - store a reference to the message being replied so we can mark it at the time of send.
|
||||
ORIGINAL_MESSAGE("m");
|
||||
ORIGINAL_MESSAGE("m"),
|
||||
CURSOR_POSITION("p"), // Where in the message your cursor was when you saved.
|
||||
QUOTED_TEXT_MODE("q");
|
||||
|
||||
private final String value;
|
||||
|
||||
@ -1202,6 +1222,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
uri.appendQueryParameter(IdentityField.ORIGINAL_MESSAGE.value(), mMessageReference.toIdentityString());
|
||||
}
|
||||
|
||||
uri.appendQueryParameter(IdentityField.CURSOR_POSITION.value(), Integer.toString(mMessageContentView.getSelectionStart()));
|
||||
|
||||
uri.appendQueryParameter(IdentityField.QUOTED_TEXT_MODE.value(), mQuotedTextMode.name());
|
||||
|
||||
String k9identity = IDENTITY_VERSION_1 + uri.build().getEncodedQuery();
|
||||
|
||||
if (K9.DEBUG) {
|
||||
@ -1276,6 +1300,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (tokens.hasMoreTokens()) {
|
||||
identity.put(IdentityField.EMAIL, Utility.base64Decode(tokens.nextToken()));
|
||||
}
|
||||
if (tokens.hasMoreTokens()) {
|
||||
identity.put(IdentityField.QUOTED_TEXT_MODE, Utility.base64Decode(tokens.nextToken()));
|
||||
}
|
||||
}
|
||||
|
||||
return identity;
|
||||
@ -1652,8 +1679,12 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mAttachments.removeView((View) view.getTag());
|
||||
mDraftNeedsSaving = true;
|
||||
break;
|
||||
case R.id.quoted_text_show:
|
||||
showOrHideQuotedText(QuotedTextMode.SHOW);
|
||||
mDraftNeedsSaving = true;
|
||||
break;
|
||||
case R.id.quoted_text_delete:
|
||||
deleteQuotedText();
|
||||
showOrHideQuotedText(QuotedTextMode.HIDE);
|
||||
mDraftNeedsSaving = true;
|
||||
break;
|
||||
case R.id.quoted_text_edit:
|
||||
@ -1670,15 +1701,37 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the quoted text.
|
||||
/*
|
||||
* Show or Hide the quoted text according to mQuotedTextMode.
|
||||
*/
|
||||
private void deleteQuotedText() {
|
||||
mQuotedTextBar.setVisibility(View.GONE);
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
if (mQuotedHtmlContent != null) {
|
||||
mQuotedHtmlContent.clearQuotedContent();
|
||||
private void showOrHideQuotedText(QuotedTextMode mode) {
|
||||
mQuotedTextMode = mode;
|
||||
if (mQuotedTextMode == QuotedTextMode.NONE) {
|
||||
mQuotedTextShow.setVisibility(View.GONE);
|
||||
mQuotedTextBar.setVisibility(View.GONE);
|
||||
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
mQuotedTextEdit.setVisibility(View.GONE);
|
||||
} else if (mQuotedTextMode == QuotedTextMode.SHOW) {
|
||||
mQuotedTextShow.setVisibility(View.GONE);
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
if (mMessageFormat == MessageFormat.HTML) {
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.VISIBLE);
|
||||
mQuotedTextEdit.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mQuotedText.setVisibility(View.VISIBLE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
mQuotedTextEdit.setVisibility(View.GONE);
|
||||
}
|
||||
} else if (mQuotedTextMode == QuotedTextMode.HIDE) {
|
||||
mQuotedTextShow.setVisibility(View.VISIBLE);
|
||||
mQuotedTextBar.setVisibility(View.GONE);
|
||||
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
mQuotedTextEdit.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1908,7 +1961,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
// Quote the message and setup the UI.
|
||||
populateUIWithQuotedMessage();
|
||||
populateUIWithQuotedMessage(mAccount.isDefaultQuotedTextShown());
|
||||
|
||||
if (ACTION_REPLY_ALL.equals(action) || ACTION_REPLY.equals(action)) {
|
||||
Identity useIdentity = null;
|
||||
@ -1963,7 +2016,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
// Quote the message and setup the UI.
|
||||
populateUIWithQuotedMessage();
|
||||
populateUIWithQuotedMessage(true);
|
||||
|
||||
if (!mSourceMessageProcessed) {
|
||||
if (!loadAttachments(message, 0)) {
|
||||
@ -1971,6 +2024,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
}
|
||||
} else if (ACTION_EDIT_DRAFT.equals(action)) {
|
||||
String showQuotedTextMode = "NONE";
|
||||
|
||||
mDraftUid = message.getUid();
|
||||
mSubjectView.setText(message.getSubject());
|
||||
addAddresses(mToView, message.getRecipients(RecipientType.TO));
|
||||
@ -2047,6 +2102,19 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
}
|
||||
|
||||
int cursorPosition = 0;
|
||||
if (k9identity.containsKey(IdentityField.CURSOR_POSITION)) {
|
||||
try {
|
||||
cursorPosition = Integer.valueOf(k9identity.get(IdentityField.CURSOR_POSITION)).intValue();
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Could not parse cursor position for MessageCompose; continuing.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (k9identity.containsKey(IdentityField.QUOTED_TEXT_MODE)) {
|
||||
showQuotedTextMode = k9identity.get(IdentityField.QUOTED_TEXT_MODE);
|
||||
}
|
||||
|
||||
mIdentity = newIdentity;
|
||||
|
||||
updateSignature();
|
||||
@ -2061,96 +2129,72 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
// Always respect the user's current composition format preference, even if the
|
||||
// draft was saved in a different format.
|
||||
// TODO - The current implementation doesn't allow a user in HTML mode to edit a draft that wasn't saved with K9mail.
|
||||
String messageFormat = k9identity.get(IdentityField.MESSAGE_FORMAT);
|
||||
if (messageFormat == null) {
|
||||
// This message probably wasn't created by us. The exception is legacy
|
||||
// drafts created before the advent of HTML composition. In those cases,
|
||||
// we'll display the whole message (including the quoted part) in the
|
||||
// composition window. If that's the case, try and convert it to text to
|
||||
// match the behavior in text mode.
|
||||
mMessageContentView.setText(getBodyTextFromMessage(message, MessageFormat.TEXT));
|
||||
mMessageFormat = MessageFormat.TEXT;
|
||||
showOrHideQuotedText(QuotedTextMode.valueOf(showQuotedTextMode));
|
||||
return;
|
||||
}
|
||||
|
||||
mMessageFormat = MessageFormat.valueOf(messageFormat);
|
||||
|
||||
if (mMessageFormat == MessageFormat.HTML) {
|
||||
if (k9identity.get(IdentityField.MESSAGE_FORMAT) == null || !MessageFormat.valueOf(k9identity.get(IdentityField.MESSAGE_FORMAT)).equals(MessageFormat.HTML)) {
|
||||
// This message probably wasn't created by us. The exception is legacy
|
||||
// drafts created before the advent of HTML composition. In those cases,
|
||||
// we'll display the whole message (including the quoted part) in the
|
||||
// composition window. If that's the case, try and convert it to text to
|
||||
// match the behavior in text mode.
|
||||
mMessageContentView.setText(getBodyTextFromMessage(message, MessageFormat.TEXT));
|
||||
} else {
|
||||
Part part = MimeUtility.findFirstPartByMimeType(message, "text/html");
|
||||
if (part != null) { // Shouldn't happen if we were the one who saved it.
|
||||
String text = MimeUtility.getTextFromPart(part);
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Loading message with offset " + bodyOffset + ", length " + bodyLength + ". Text length is " + text.length() + ".");
|
||||
}
|
||||
Part part = MimeUtility.findFirstPartByMimeType(message, "text/html");
|
||||
if (part != null) { // Shouldn't happen if we were the one who saved it.
|
||||
String text = MimeUtility.getTextFromPart(part);
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Loading message with offset " + bodyOffset + ", length " + bodyLength + ". Text length is " + text.length() + ".");
|
||||
}
|
||||
|
||||
// Grab our reply text.
|
||||
String bodyText = text.substring(bodyOffset, bodyOffset + bodyLength);
|
||||
mMessageContentView.setText(HtmlConverter.htmlToText(bodyText));
|
||||
// Grab our reply text.
|
||||
String bodyText = text.substring(bodyOffset, bodyOffset + bodyLength);
|
||||
mMessageContentView.setText(HtmlConverter.htmlToText(bodyText));
|
||||
|
||||
// Regenerate the quoted html without our user content in it.
|
||||
StringBuilder quotedHTML = new StringBuilder();
|
||||
quotedHTML.append(text.substring(0, bodyOffset)); // stuff before the reply
|
||||
quotedHTML.append(text.substring(bodyOffset + bodyLength));
|
||||
if (quotedHTML.length() > 0) {
|
||||
mQuotedHtmlContent = new InsertableHtmlContent();
|
||||
mQuotedHtmlContent.setQuotedContent(quotedHTML);
|
||||
mQuotedHtmlContent.setHeaderInsertionPoint(bodyOffset);
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setVisibility(View.VISIBLE);
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
mQuotedTextEdit.setVisibility(View.VISIBLE);
|
||||
}
|
||||
// Regenerate the quoted html without our user content in it.
|
||||
StringBuilder quotedHTML = new StringBuilder();
|
||||
quotedHTML.append(text.substring(0, bodyOffset)); // stuff before the reply
|
||||
quotedHTML.append(text.substring(bodyOffset + bodyLength));
|
||||
if (quotedHTML.length() > 0) {
|
||||
mQuotedHtmlContent = new InsertableHtmlContent();
|
||||
mQuotedHtmlContent.setQuotedContent(quotedHTML);
|
||||
mQuotedHtmlContent.setHeaderInsertionPoint(bodyOffset);
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
}
|
||||
}
|
||||
} else if (mMessageFormat == MessageFormat.TEXT) {
|
||||
MessageFormat format = k9identity.get(IdentityField.MESSAGE_FORMAT) != null
|
||||
? MessageFormat.valueOf(k9identity.get(IdentityField.MESSAGE_FORMAT))
|
||||
: null;
|
||||
if (format == null) {
|
||||
mMessageContentView.setText(getBodyTextFromMessage(message, MessageFormat.TEXT));
|
||||
} else if (format.equals(MessageFormat.HTML)) {
|
||||
// We are in text mode, but have an HTML message.
|
||||
Part htmlPart = MimeUtility.findFirstPartByMimeType(message, "text/html");
|
||||
if (htmlPart != null) { // Shouldn't happen if we were the one who saved it.
|
||||
String text = MimeUtility.getTextFromPart(htmlPart);
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Loading message with offset " + bodyOffset + ", length " + bodyLength + ". Text length is " + text.length() + ".");
|
||||
}
|
||||
Part textPart = MimeUtility.findFirstPartByMimeType(message, "text/plain");
|
||||
if (textPart != null) {
|
||||
String text = MimeUtility.getTextFromPart(textPart);
|
||||
// If we had a body length (and it was valid), separate the composition from the quoted text
|
||||
// and put them in their respective places in the UI.
|
||||
if (bodyLength != null && bodyLength + 1 < text.length()) { // + 1 to get rid of the newline we added when saving the draft
|
||||
String bodyText = text.substring(0, bodyLength);
|
||||
String quotedText = text.substring(bodyLength + 1, text.length());
|
||||
|
||||
// Grab our reply text.
|
||||
String bodyText = text.substring(bodyOffset, bodyOffset + bodyLength);
|
||||
mMessageContentView.setText(Html.fromHtml(bodyText).toString());
|
||||
|
||||
// Regenerate the quoted html without out content in it.
|
||||
StringBuilder quotedHTML = new StringBuilder();
|
||||
quotedHTML.append(text.substring(0, bodyOffset)); // stuff before the reply
|
||||
quotedHTML.append(text.substring(bodyOffset + bodyLength));
|
||||
// Convert it to text.
|
||||
mQuotedText.setText(HtmlConverter.htmlToText(quotedHTML.toString()));
|
||||
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
mQuotedText.setVisibility(View.VISIBLE);
|
||||
mMessageContentView.setText(bodyText);
|
||||
mQuotedText.setText(quotedText);
|
||||
} else {
|
||||
Log.e(K9.LOG_TAG, "Found an HTML draft but couldn't find the HTML part! Something's wrong.");
|
||||
mMessageContentView.setText(text);
|
||||
}
|
||||
} else if (format.equals(MessageFormat.TEXT)) {
|
||||
Part textPart = MimeUtility.findFirstPartByMimeType(message, "text/plain");
|
||||
if (textPart != null) {
|
||||
String text = MimeUtility.getTextFromPart(textPart);
|
||||
// If we had a body length (and it was valid), separate the composition from the quoted text
|
||||
// and put them in their respective places in the UI.
|
||||
if (bodyLength != null && bodyLength + 1 < text.length()) { // + 1 to get rid of the newline we added when saving the draft
|
||||
String bodyText = text.substring(0, bodyLength);
|
||||
String quotedText = text.substring(bodyLength + 1, text.length());
|
||||
|
||||
mMessageContentView.setText(bodyText);
|
||||
mQuotedText.setText(quotedText);
|
||||
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
mQuotedText.setVisibility(View.VISIBLE);
|
||||
mQuotedHTML.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mMessageContentView.setText(text);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(K9.LOG_TAG, "Unhandled message format.");
|
||||
}
|
||||
} else {
|
||||
Log.e(K9.LOG_TAG, "Unhandled message format.");
|
||||
}
|
||||
|
||||
// Set the cursor position if we have it.
|
||||
try {
|
||||
mMessageContentView.setSelection(cursorPosition);
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Could not set cursor position in MessageCompose; ignoring.", e);
|
||||
}
|
||||
|
||||
showOrHideQuotedText(QuotedTextMode.valueOf(showQuotedTextMode));
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
/**
|
||||
@ -2158,16 +2202,17 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
* the source message. Log it as an error, though.
|
||||
*/
|
||||
Log.e(K9.LOG_TAG, "Error while processing source message: ", me);
|
||||
} finally {
|
||||
mSourceMessageProcessed = true;
|
||||
mDraftNeedsSaving = false;
|
||||
}
|
||||
mSourceMessageProcessed = true;
|
||||
mDraftNeedsSaving = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and populate the UI with the quoted message.
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void populateUIWithQuotedMessage() throws MessagingException {
|
||||
private void populateUIWithQuotedMessage(boolean shown) throws MessagingException {
|
||||
// TODO -- I am assuming that mSourceMessageBody will always be a text part. Is this a safe assumption?
|
||||
|
||||
// Handle the original message in the reply
|
||||
@ -2181,20 +2226,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
// Load the message with the reply header.
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
mQuotedHTML.setVisibility(View.VISIBLE);
|
||||
mQuotedTextEdit.setVisibility(View.VISIBLE);
|
||||
|
||||
mQuotedText.setVisibility(View.GONE);
|
||||
} else if (mMessageFormat == MessageFormat.TEXT) {
|
||||
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage, content, mAccount.getQuoteStyle()));
|
||||
}
|
||||
|
||||
mQuotedTextBar.setVisibility(View.VISIBLE);
|
||||
mQuotedText.setVisibility(View.VISIBLE);
|
||||
|
||||
mQuotedHtmlContent = null;
|
||||
mQuotedTextEdit.setVisibility(View.GONE);
|
||||
mQuotedHTML.setVisibility(View.GONE);
|
||||
if (shown) {
|
||||
showOrHideQuotedText(QuotedTextMode.SHOW);
|
||||
} else {
|
||||
showOrHideQuotedText(QuotedTextMode.HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2406,10 +2445,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
// part).
|
||||
if (mSourceProcessed) {
|
||||
try {
|
||||
populateUIWithQuotedMessage();
|
||||
populateUIWithQuotedMessage(true);
|
||||
} catch (MessagingException e) {
|
||||
// Hm, if we couldn't populate the UI after source reprocessing, let's just delete it?
|
||||
deleteQuotedText();
|
||||
showOrHideQuotedText(QuotedTextMode.HIDE);
|
||||
Log.e(K9.LOG_TAG, "Could not re-process source message; deleting quoted text to be safe.", e);
|
||||
}
|
||||
} else {
|
||||
|
@ -12,13 +12,14 @@ import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.animation.Animation;
|
||||
@ -491,7 +492,7 @@ public class MessageList
|
||||
if (mFolderName != null) {
|
||||
displayName = mFolderName;
|
||||
|
||||
if (K9.INBOX.equalsIgnoreCase(displayName)) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(displayName)) {
|
||||
displayName = getString(R.string.special_mailbox_name_inbox);
|
||||
} else if (mAccount.getOutboxFolderName().equals(displayName)) {
|
||||
displayName = getString(R.string.special_mailbox_name_outbox);
|
||||
@ -565,9 +566,10 @@ public class MessageList
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Use mListView.getAdapter() to get the WrapperListAdapter that includes the footer view.
|
||||
if (mCurrentFolder != null && ((position + 1) == mListView.getAdapter().getCount())) {
|
||||
mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener);
|
||||
if (view == mFooterView) {
|
||||
if (mCurrentFolder != null) {
|
||||
mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -726,6 +728,9 @@ public class MessageList
|
||||
}
|
||||
|
||||
} else {
|
||||
// reread the selected date format preference in case it has changed
|
||||
mMessageHelper.refresh();
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -1139,7 +1144,7 @@ public class MessageList
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToSpamFolder(MessageInfoHolder holder){
|
||||
private void moveToSpamFolder(MessageInfoHolder holder) {
|
||||
if (!mController.isMoveCapable(holder.message)) {
|
||||
Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
@ -1283,31 +1288,31 @@ public class MessageList
|
||||
switch (id) {
|
||||
case DIALOG_MARK_ALL_AS_READ:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.mark_all_as_read_dlg_title,
|
||||
getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
||||
mCurrentFolder.displayName),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
markAllAsRead();
|
||||
}
|
||||
});
|
||||
R.string.mark_all_as_read_dlg_title,
|
||||
getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
||||
mCurrentFolder.displayName),
|
||||
R.string.okay_action,
|
||||
R.string.cancel_action,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
markAllAsRead();
|
||||
}
|
||||
});
|
||||
case R.id.dialog_confirm_spam:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.dialog_confirm_spam_title,
|
||||
R.string.dialog_confirm_spam_message,
|
||||
R.string.dialog_confirm_spam_confirm_button,
|
||||
R.string.dialog_confirm_spam_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
moveToSpamFolder(mSelectedMessage);
|
||||
// No further need for this reference
|
||||
mSelectedMessage = null;
|
||||
}
|
||||
});
|
||||
R.string.dialog_confirm_spam_title,
|
||||
R.string.dialog_confirm_spam_message,
|
||||
R.string.dialog_confirm_spam_confirm_button,
|
||||
R.string.dialog_confirm_spam_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
moveToSpamFolder(mSelectedMessage);
|
||||
// No further need for this reference
|
||||
mSelectedMessage = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
@ -2156,13 +2161,14 @@ public class MessageList
|
||||
holder.preview.setText(noSender, TextView.BufferType.SPANNABLE);
|
||||
Spannable str = (Spannable) holder.preview.getText();
|
||||
|
||||
ColorStateList color = holder.subject.getTextColors();
|
||||
ColorStateList linkColor = holder.subject.getLinkTextColors();
|
||||
str.setSpan(new TextAppearanceSpan(null, Typeface.NORMAL, mFontSizes.getMessageListSender(), color, linkColor),
|
||||
str.setSpan(new StyleSpan(Typeface.NORMAL),
|
||||
0,
|
||||
noSender.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
);
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
str.setSpan(K9.createAbsoluteSizeSpan(mFontSizes.getMessageListSender()),
|
||||
0,
|
||||
noSender.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
} else {
|
||||
holder.from.setText(noSender);
|
||||
holder.from.setTypeface(null, Typeface.NORMAL);
|
||||
@ -2244,13 +2250,20 @@ public class MessageList
|
||||
Spannable str = (Spannable)holder.preview.getText();
|
||||
|
||||
// Create a span section for the sender, and assign the correct font size and weight.
|
||||
ColorStateList color = holder.subject.getTextColors();
|
||||
ColorStateList linkColor = holder.subject.getLinkTextColors();
|
||||
str.setSpan(new TextAppearanceSpan(null, senderTypeface, mFontSizes.getMessageListSender(), color, linkColor),
|
||||
str.setSpan(new StyleSpan(senderTypeface),
|
||||
0,
|
||||
message.sender.length() + 1,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
);
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
str.setSpan(K9.createAbsoluteSizeSpan(mFontSizes.getMessageListSender()),
|
||||
0,
|
||||
message.sender.length() + 1,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
// set span for preview message.
|
||||
str.setSpan(new ForegroundColorSpan(Color.rgb(128, 128, 128)), // How do I can specify the android.R.attr.textColorTertiary
|
||||
message.sender.length() + 1,
|
||||
str.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
} else {
|
||||
holder.from.setText(new SpannableStringBuilder(recipientSigil(message)).append(message.sender));
|
||||
|
||||
|
@ -17,12 +17,16 @@ import com.fsck.k9.*;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.crypto.PgpData;
|
||||
import com.fsck.k9.helper.FileBrowserHelper;
|
||||
import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback;
|
||||
import com.fsck.k9.mail.*;
|
||||
import com.fsck.k9.mail.store.StorageManager;
|
||||
import com.fsck.k9.view.AttachmentView;
|
||||
import com.fsck.k9.view.ToggleScrollView;
|
||||
import com.fsck.k9.view.SingleMessageView;
|
||||
import com.fsck.k9.view.AttachmentView.AttachmentFileDownloadCallback;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class MessageView extends K9Activity implements OnClickListener {
|
||||
@ -33,7 +37,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
private static final String STATE_PGP_DATA = "pgpData";
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
|
||||
|
||||
private static final int ACTIVITY_CHOOSE_DIRECTORY = 3;
|
||||
|
||||
private SingleMessageView mMessageView;
|
||||
|
||||
@ -61,6 +65,12 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
private MessageViewHandler mHandler = new MessageViewHandler();
|
||||
private StorageManager.StorageListener mStorageListener = new StorageListenerImplementation();
|
||||
|
||||
/** this variable is used to save the calling AttachmentView
|
||||
* until the onActivityResult is called.
|
||||
* => with this reference we can identity the caller
|
||||
*/
|
||||
private AttachmentView attachmentTmpStore;
|
||||
|
||||
/**
|
||||
* Used to temporarily store the destination folder for refile operations if a confirmation
|
||||
* dialog is shown.
|
||||
@ -295,6 +305,32 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
mTopView = mToggleScrollView = (ToggleScrollView) findViewById(R.id.top_view);
|
||||
mMessageView = (SingleMessageView) findViewById(R.id.message_view);
|
||||
|
||||
//set a callback for the attachment view. With this callback the attachmentview
|
||||
//request the start of a filebrowser activity.
|
||||
mMessageView.setAttachmentCallback(new AttachmentFileDownloadCallback() {
|
||||
|
||||
@Override
|
||||
public void showFileBrowser(final AttachmentView caller) {
|
||||
FileBrowserHelper.getInstance()
|
||||
.showFileBrowserActivity(MessageView.this,
|
||||
null,
|
||||
MessageView.ACTIVITY_CHOOSE_DIRECTORY,
|
||||
callback);
|
||||
attachmentTmpStore = caller;
|
||||
}
|
||||
FileBrowserFailOverCallback callback = new FileBrowserFailOverCallback() {
|
||||
|
||||
@Override
|
||||
public void onPathEntered(String path) {
|
||||
attachmentTmpStore.writeFile(new File(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// canceled, do nothing
|
||||
}
|
||||
};
|
||||
});
|
||||
mMessageView.initialize(this);
|
||||
|
||||
setTitle("");
|
||||
@ -712,6 +748,19 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
if (resultCode != RESULT_OK)
|
||||
return;
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_CHOOSE_DIRECTORY:
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
// obtain the filename
|
||||
Uri fileUri = data.getData();
|
||||
if (fileUri != null) {
|
||||
String filePath = fileUri.getPath();
|
||||
if (filePath != null) {
|
||||
attachmentTmpStore.writeFile(new File(filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case ACTIVITY_CHOOSE_FOLDER_MOVE:
|
||||
case ACTIVITY_CHOOSE_FOLDER_COPY:
|
||||
if (data == null)
|
||||
@ -774,7 +823,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
|
||||
private void onMarkAsUnread() {
|
||||
if (mMessage != null) {
|
||||
mController.setFlag(mAccount, mMessageReference.folderName, new String[] { mMessage.getUid() }, Flag.SEEN, false);
|
||||
// (Issue 3319) mController.setFlag(mAccount, mMessageReference.folderName, new String[] { mMessage.getUid() }, Flag.SEEN, false);
|
||||
try {
|
||||
mMessage.setFlag(Flag.SEEN, false);
|
||||
mMessageView.setHeaders(mMessage, mAccount);
|
||||
@ -932,29 +981,29 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
switch (id) {
|
||||
case R.id.dialog_confirm_delete:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.dialog_confirm_delete_title,
|
||||
R.string.dialog_confirm_delete_message,
|
||||
R.string.dialog_confirm_delete_confirm_button,
|
||||
R.string.dialog_confirm_delete_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delete();
|
||||
}
|
||||
});
|
||||
R.string.dialog_confirm_delete_title,
|
||||
R.string.dialog_confirm_delete_message,
|
||||
R.string.dialog_confirm_delete_confirm_button,
|
||||
R.string.dialog_confirm_delete_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delete();
|
||||
}
|
||||
});
|
||||
case R.id.dialog_confirm_spam:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.dialog_confirm_spam_title,
|
||||
R.string.dialog_confirm_spam_message,
|
||||
R.string.dialog_confirm_spam_confirm_button,
|
||||
R.string.dialog_confirm_spam_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refileMessage(mDstFolder);
|
||||
mDstFolder = null;
|
||||
}
|
||||
});
|
||||
R.string.dialog_confirm_spam_title,
|
||||
R.string.dialog_confirm_spam_message,
|
||||
R.string.dialog_confirm_spam_confirm_button,
|
||||
R.string.dialog_confirm_spam_cancel_button,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refileMessage(mDstFolder);
|
||||
mDstFolder = null;
|
||||
}
|
||||
});
|
||||
case R.id.dialog_attachment_progress:
|
||||
ProgressDialog d = new ProgressDialog(this);
|
||||
d.setIndeterminate(true);
|
||||
|
@ -88,6 +88,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_MESSAGE_FORMAT = "message_format";
|
||||
private static final String PREFERENCE_QUOTE_PREFIX = "account_quote_prefix";
|
||||
private static final String PREFERENCE_QUOTE_STYLE = "quote_style";
|
||||
private static final String PREFERENCE_DEFAULT_QUOTED_TEXT_SHOWN = "default_quoted_text_shown";
|
||||
private static final String PREFERENCE_REPLY_AFTER_QUOTE = "reply_after_quote";
|
||||
private static final String PREFERENCE_SYNC_REMOTE_DELETIONS = "account_sync_remote_deletetions";
|
||||
private static final String PREFERENCE_CRYPTO_APP = "crypto_app";
|
||||
@ -145,6 +146,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private ListPreference mMessageFormat;
|
||||
private ListPreference mQuoteStyle;
|
||||
private EditTextPreference mAccountQuotePrefix;
|
||||
private CheckBoxPreference mAccountDefaultQuotedTextShown;
|
||||
private CheckBoxPreference mReplyAfterQuote;
|
||||
private CheckBoxPreference mSyncRemoteDeletions;
|
||||
private CheckBoxPreference mSaveAllHeaders;
|
||||
@ -226,6 +228,9 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
});
|
||||
|
||||
mAccountDefaultQuotedTextShown = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT_QUOTED_TEXT_SHOWN);
|
||||
mAccountDefaultQuotedTextShown.setChecked(mAccount.isDefaultQuotedTextShown());
|
||||
|
||||
mReplyAfterQuote = (CheckBoxPreference) findPreference(PREFERENCE_REPLY_AFTER_QUOTE);
|
||||
mReplyAfterQuote.setChecked(mAccount.isReplyAfterQuote());
|
||||
|
||||
@ -695,12 +700,19 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
mAccount.setMessageFormat(Account.MessageFormat.valueOf(mMessageFormat.getValue()));
|
||||
mAccount.setQuoteStyle(QuoteStyle.valueOf(mQuoteStyle.getValue()));
|
||||
mAccount.setQuotePrefix(mAccountQuotePrefix.getText());
|
||||
mAccount.setDefaultQuotedTextShown(mAccountDefaultQuotedTextShown.isChecked());
|
||||
mAccount.setReplyAfterQuote(mReplyAfterQuote.isChecked());
|
||||
mAccount.setCryptoApp(mCryptoApp.getValue());
|
||||
mAccount.setCryptoAutoSignature(mCryptoAutoSignature.isChecked());
|
||||
mAccount.setLocalStorageProviderId(mLocalStorageProvider.getValue());
|
||||
|
||||
mAccount.setAutoExpandFolderName(reverseTranslateFolder(mAutoExpandFolder.getValue()));
|
||||
// In webdav account we use the exact folder name also for inbox,
|
||||
// since it varies because of internationalization
|
||||
if (mAccount.getStoreUri().startsWith("webdav"))
|
||||
mAccount.setAutoExpandFolderName(mAutoExpandFolder.getValue());
|
||||
else
|
||||
mAccount.setAutoExpandFolderName(reverseTranslateFolder(mAutoExpandFolder.getValue()));
|
||||
|
||||
mAccount.setArchiveFolderName(mArchiveFolder.getValue());
|
||||
mAccount.setDraftsFolderName(mDraftsFolder.getValue());
|
||||
mAccount.setSentFolderName(mSentFolder.getValue());
|
||||
@ -826,7 +838,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
|
||||
private String translateFolder(String in) {
|
||||
if (K9.INBOX.equalsIgnoreCase(in)) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(in)) {
|
||||
return getString(R.string.special_mailbox_name_inbox);
|
||||
} else {
|
||||
return in;
|
||||
@ -835,7 +847,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
|
||||
private String reverseTranslateFolder(String in) {
|
||||
if (getString(R.string.special_mailbox_name_inbox).equals(in)) {
|
||||
return K9.INBOX;
|
||||
return mAccount.getInboxFolderName();
|
||||
} else {
|
||||
return in;
|
||||
}
|
||||
@ -867,7 +879,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
Iterator <? extends Folder > iter = folders.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Folder folder = iter.next();
|
||||
if (mAccount.getOutboxFolderName().equalsIgnoreCase(folder.getName())) {
|
||||
if (mAccount.getOutboxFolderName().equals(folder.getName())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import com.fsck.k9.*;
|
||||
import com.fsck.k9.activity.K9Activity;
|
||||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -134,17 +133,11 @@ public class AccountSetupBasics extends K9Activity
|
||||
private String getOwnerName() {
|
||||
String name = null;
|
||||
try {
|
||||
name = Contacts.getInstance(this).getOwnerName();
|
||||
name = getDefaultAccountName();
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Could not get owner name, using default account name", e);
|
||||
}
|
||||
if (name == null || name.length() == 0) {
|
||||
try {
|
||||
name = getDefaultAccountName();
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Could not get default account name", e);
|
||||
}
|
||||
Log.e(K9.LOG_TAG, "Could not get default account name", e);
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
@ -30,6 +31,8 @@ import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Checks the given settings to make sure that they can be used to send and
|
||||
@ -116,7 +119,7 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
|
||||
setMessage(R.string.account_setup_check_settings_fetch);
|
||||
}
|
||||
MessagingController.getInstance(getApplication()).listFoldersSynchronous(mAccount, true, null);
|
||||
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, K9.INBOX , null, null);
|
||||
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, mAccount.getInboxFolderName(), null, null);
|
||||
}
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
@ -249,8 +252,78 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
|
||||
}
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
// display certificate chain information
|
||||
//TODO: localize this strings
|
||||
chainInfo.append("Certificate chain[" + i + "]:\n");
|
||||
chainInfo.append("Subject: " + chain[i].getSubjectDN().toString() + "\n");
|
||||
|
||||
// display SubjectAltNames too
|
||||
// (the user may be mislead into mistrusting a certificate
|
||||
// by a subjectDN not matching the server even though a
|
||||
// SubjectAltName matches)
|
||||
try {
|
||||
final Collection < List<? >> subjectAlternativeNames = chain[i].getSubjectAlternativeNames();
|
||||
if (subjectAlternativeNames != null) {
|
||||
// The list of SubjectAltNames may be very long
|
||||
//TODO: localize this string
|
||||
StringBuffer altNamesText = new StringBuffer("Subject has " + subjectAlternativeNames.size() + " alternative names\n");
|
||||
|
||||
// we need these for matching
|
||||
String storeURIHost = (Uri.parse(mAccount.getStoreUri())).getHost();
|
||||
String transportURIHost = (Uri.parse(mAccount.getTransportUri())).getHost();
|
||||
|
||||
for (List<?> subjectAlternativeName : subjectAlternativeNames) {
|
||||
Integer type = (Integer)subjectAlternativeName.get(0);
|
||||
Object value = subjectAlternativeName.get(1);
|
||||
String name = "";
|
||||
switch (type.intValue()) {
|
||||
case 0:
|
||||
Log.w(K9.LOG_TAG, "SubjectAltName of type OtherName not supported.");
|
||||
continue;
|
||||
case 1: // RFC822Name
|
||||
name = (String)value;
|
||||
break;
|
||||
case 2: // DNSName
|
||||
name = (String)value;
|
||||
break;
|
||||
case 3:
|
||||
Log.w(K9.LOG_TAG, "unsupported SubjectAltName of type x400Address");
|
||||
continue;
|
||||
case 4:
|
||||
Log.w(K9.LOG_TAG, "unsupported SubjectAltName of type directoryName");
|
||||
continue;
|
||||
case 5:
|
||||
Log.w(K9.LOG_TAG, "unsupported SubjectAltName of type ediPartyName");
|
||||
continue;
|
||||
case 6: // Uri
|
||||
name = (String)value;
|
||||
break;
|
||||
case 7: // ip-address
|
||||
name = (String)value;
|
||||
break;
|
||||
default:
|
||||
Log.w(K9.LOG_TAG, "unsupported SubjectAltName of unknown type");
|
||||
continue;
|
||||
}
|
||||
|
||||
// if some of the SubjectAltNames match the store or transport -host,
|
||||
// display them
|
||||
if (name.equalsIgnoreCase(storeURIHost) || name.equalsIgnoreCase(transportURIHost)) {
|
||||
//TODO: localize this string
|
||||
altNamesText.append("Subject(alt): " + name + ",...\n");
|
||||
} else if (name.startsWith("*.")) {
|
||||
if (storeURIHost.endsWith(name.substring(2)) || transportURIHost.endsWith(name.substring(2))) {
|
||||
//TODO: localize this string
|
||||
altNamesText.append("Subject(alt): " + name + ",...\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
chainInfo.append(altNamesText);
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
// don't fail just because of subjectAltNames
|
||||
Log.w(K9.LOG_TAG, "cannot display SubjectAltNames in dialog", e1);
|
||||
}
|
||||
|
||||
chainInfo.append("Issuer: " + chain[i].getIssuerDN().toString() + "\n");
|
||||
if (sha1 != null) {
|
||||
sha1.reset();
|
||||
|
@ -65,10 +65,10 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
private Button mNextButton;
|
||||
private Account mAccount;
|
||||
private boolean mMakeDefault;
|
||||
private CheckBox compressionMobile;
|
||||
private CheckBox compressionWifi;
|
||||
private CheckBox compressionOther;
|
||||
private CheckBox subscribedFoldersOnly;
|
||||
private CheckBox mCompressionMobile;
|
||||
private CheckBox mCompressionWifi;
|
||||
private CheckBox mCompressionOther;
|
||||
private CheckBox mSubscribedFoldersOnly;
|
||||
|
||||
public static void actionIncomingSettings(Activity context, Account account, boolean makeDefault) {
|
||||
Intent i = new Intent(context, AccountSetupIncoming.class);
|
||||
@ -101,10 +101,10 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
mWebdavAuthPathView = (EditText)findViewById(R.id.webdav_auth_path);
|
||||
mWebdavMailboxPathView = (EditText)findViewById(R.id.webdav_mailbox_path);
|
||||
mNextButton = (Button)findViewById(R.id.next);
|
||||
compressionMobile = (CheckBox)findViewById(R.id.compression_mobile);
|
||||
compressionWifi = (CheckBox)findViewById(R.id.compression_wifi);
|
||||
compressionOther = (CheckBox)findViewById(R.id.compression_other);
|
||||
subscribedFoldersOnly = (CheckBox)findViewById(R.id.subscribed_folders_only);
|
||||
mCompressionMobile = (CheckBox)findViewById(R.id.compression_mobile);
|
||||
mCompressionWifi = (CheckBox)findViewById(R.id.compression_wifi);
|
||||
mCompressionOther = (CheckBox)findViewById(R.id.compression_other);
|
||||
mSubscribedFoldersOnly = (CheckBox)findViewById(R.id.subscribed_folders_only);
|
||||
|
||||
mNextButton.setOnClickListener(this);
|
||||
|
||||
@ -236,6 +236,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
findViewById(R.id.webdav_auth_path_section).setVisibility(View.GONE);
|
||||
findViewById(R.id.compression_section).setVisibility(View.GONE);
|
||||
findViewById(R.id.compression_label).setVisibility(View.GONE);
|
||||
mSubscribedFoldersOnly.setVisibility(View.GONE);
|
||||
mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER);
|
||||
} else if (uri.getScheme().startsWith("imap")) {
|
||||
serverLabelView.setText(R.string.account_setup_incoming_imap_server_label);
|
||||
@ -266,7 +267,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
findViewById(R.id.account_auth_type).setVisibility(View.GONE);
|
||||
findViewById(R.id.compression_section).setVisibility(View.GONE);
|
||||
findViewById(R.id.compression_label).setVisibility(View.GONE);
|
||||
subscribedFoldersOnly.setVisibility(View.GONE);
|
||||
mSubscribedFoldersOnly.setVisibility(View.GONE);
|
||||
if (uri.getPath() != null && uri.getPath().length() > 0) {
|
||||
String[] pathParts = uri.getPath().split("\\|");
|
||||
|
||||
@ -299,9 +300,9 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i);
|
||||
}
|
||||
}
|
||||
compressionMobile.setChecked(mAccount.useCompression(Account.TYPE_MOBILE));
|
||||
compressionWifi.setChecked(mAccount.useCompression(Account.TYPE_WIFI));
|
||||
compressionOther.setChecked(mAccount.useCompression(Account.TYPE_OTHER));
|
||||
mCompressionMobile.setChecked(mAccount.useCompression(Account.TYPE_MOBILE));
|
||||
mCompressionWifi.setChecked(mAccount.useCompression(Account.TYPE_WIFI));
|
||||
mCompressionOther.setChecked(mAccount.useCompression(Account.TYPE_OTHER));
|
||||
|
||||
if (uri.getHost() != null) {
|
||||
mServerView.setText(uri.getHost());
|
||||
@ -313,7 +314,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
updatePortFromSecurityType();
|
||||
}
|
||||
|
||||
subscribedFoldersOnly.setChecked(mAccount.subscribedFoldersOnly());
|
||||
mSubscribedFoldersOnly.setChecked(mAccount.subscribedFoldersOnly());
|
||||
|
||||
validateFields();
|
||||
} catch (Exception e) {
|
||||
@ -409,9 +410,9 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
} else {
|
||||
String authType = ((SpinnerOption)mAuthTypeView.getSelectedItem()).label;
|
||||
if (!authType.equalsIgnoreCase("plain")) {
|
||||
userInfo = authType + ":" + userEnc + ":" + passwordEnc;
|
||||
userInfo = authType + ":" + userEnc + ":" + passwordEnc;
|
||||
} else {
|
||||
userInfo = userEnc + ":" + passwordEnc;
|
||||
userInfo = userEnc + ":" + passwordEnc;
|
||||
}
|
||||
}
|
||||
URI uri = new URI(
|
||||
@ -425,10 +426,10 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
||||
mAccount.setStoreUri(uri.toString());
|
||||
|
||||
|
||||
mAccount.setCompression(Account.TYPE_MOBILE, compressionMobile.isChecked());
|
||||
mAccount.setCompression(Account.TYPE_WIFI, compressionWifi.isChecked());
|
||||
mAccount.setCompression(Account.TYPE_OTHER, compressionOther.isChecked());
|
||||
mAccount.setSubscribedFoldersOnly(subscribedFoldersOnly.isChecked());
|
||||
mAccount.setCompression(Account.TYPE_MOBILE, mCompressionMobile.isChecked());
|
||||
mAccount.setCompression(Account.TYPE_WIFI, mCompressionWifi.isChecked());
|
||||
mAccount.setCompression(Account.TYPE_OTHER, mCompressionOther.isChecked());
|
||||
mAccount.setSubscribedFoldersOnly(mSubscribedFoldersOnly.isChecked());
|
||||
|
||||
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
|
||||
} catch (Exception e) {
|
||||
|
@ -16,6 +16,8 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import com.fsck.k9.*;
|
||||
import com.fsck.k9.activity.K9Activity;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.transport.SmtpTransport;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@ -45,10 +47,13 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
|
||||
"webdav", "webdav+ssl", "webdav+ssl+", "webdav+tls", "webdav+tls+"
|
||||
};
|
||||
*/
|
||||
|
||||
private static final String authTypes[] = {
|
||||
"PLAIN", "CRAM_MD5"
|
||||
SmtpTransport.AUTH_AUTOMATIC,
|
||||
SmtpTransport.AUTH_LOGIN,
|
||||
SmtpTransport.AUTH_PLAIN,
|
||||
SmtpTransport.AUTH_CRAM_MD5,
|
||||
};
|
||||
|
||||
private EditText mUsernameView;
|
||||
private EditText mPasswordView;
|
||||
private EditText mServerView;
|
||||
@ -117,14 +122,10 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
|
||||
new SpinnerOption(4, getString(R.string.account_setup_incoming_security_tls_label)),
|
||||
};
|
||||
|
||||
// This needs to be kept in sync with the list at the top of the file.
|
||||
// that makes me somewhat unhappy
|
||||
SpinnerOption authTypeSpinnerOptions[] = {
|
||||
new SpinnerOption(0, "PLAIN"),
|
||||
new SpinnerOption(1, "CRAM_MD5")
|
||||
};
|
||||
|
||||
|
||||
SpinnerOption authTypeSpinnerOptions[] = new SpinnerOption[authTypes.length];
|
||||
for (int i = 0; i < authTypes.length; i++) {
|
||||
authTypeSpinnerOptions[i] = new SpinnerOption(i, authTypes[i]);
|
||||
}
|
||||
|
||||
ArrayAdapter<SpinnerOption> securityTypesAdapter = new ArrayAdapter<SpinnerOption>(this,
|
||||
android.R.layout.simple_spinner_item, securityTypes);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.fsck.k9.activity.setup;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Vector;
|
||||
@ -8,11 +9,13 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.view.KeyEvent;
|
||||
import android.widget.Toast;
|
||||
|
||||
@ -23,6 +26,8 @@ import com.fsck.k9.activity.Accounts;
|
||||
import com.fsck.k9.activity.ColorPickerDialog;
|
||||
import com.fsck.k9.activity.K9PreferenceActivity;
|
||||
import com.fsck.k9.helper.DateFormatter;
|
||||
import com.fsck.k9.helper.FileBrowserHelper;
|
||||
import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback;
|
||||
import com.fsck.k9.preferences.CheckBoxListPreference;
|
||||
import com.fsck.k9.preferences.TimePickerPreference;
|
||||
|
||||
@ -76,7 +81,9 @@ public class Prefs extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_DEBUG_LOGGING = "debug_logging";
|
||||
private static final String PREFERENCE_SENSITIVE_LOGGING = "sensitive_logging";
|
||||
|
||||
private static final String PREFERENCE_ATTACHMENT_DEF_PATH = "attachment_default_path";
|
||||
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER = 1;
|
||||
private ListPreference mLanguage;
|
||||
private ListPreference mTheme;
|
||||
private ListPreference mDateFormat;
|
||||
@ -110,7 +117,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
private CheckBoxPreference mQuietTimeEnabled;
|
||||
private com.fsck.k9.preferences.TimePickerPreference mQuietTimeStarts;
|
||||
private com.fsck.k9.preferences.TimePickerPreference mQuietTimeEnds;
|
||||
|
||||
private Preference mAttachmentPathPreference;
|
||||
|
||||
|
||||
public static void actionPrefs(Context context) {
|
||||
@ -182,15 +189,15 @@ public class Prefs extends K9PreferenceActivity {
|
||||
|
||||
mConfirmActions = (CheckBoxListPreference) findPreference(PREFERENCE_CONFIRM_ACTIONS);
|
||||
mConfirmActions.setItems(new CharSequence[] {
|
||||
getString(R.string.global_settings_confirm_action_delete),
|
||||
getString(R.string.global_settings_confirm_action_spam),
|
||||
getString(R.string.global_settings_confirm_action_mark_all_as_read)
|
||||
});
|
||||
getString(R.string.global_settings_confirm_action_delete),
|
||||
getString(R.string.global_settings_confirm_action_spam),
|
||||
getString(R.string.global_settings_confirm_action_mark_all_as_read)
|
||||
});
|
||||
mConfirmActions.setCheckedItems(new boolean[] {
|
||||
K9.confirmDelete(),
|
||||
K9.confirmSpam(),
|
||||
K9.confirmMarkAllAsRead()
|
||||
});
|
||||
K9.confirmDelete(),
|
||||
K9.confirmSpam(),
|
||||
K9.confirmMarkAllAsRead()
|
||||
});
|
||||
|
||||
mPrivacyMode = (CheckBoxPreference) findPreference(PREFERENCE_PRIVACY_MODE);
|
||||
mPrivacyMode.setChecked(K9.keyguardPrivacy());
|
||||
@ -298,6 +305,36 @@ public class Prefs extends K9PreferenceActivity {
|
||||
|
||||
mDebugLogging.setChecked(K9.DEBUG);
|
||||
mSensitiveLogging.setChecked(K9.DEBUG_SENSITIVE);
|
||||
|
||||
mAttachmentPathPreference = findPreference(PREFERENCE_ATTACHMENT_DEF_PATH);
|
||||
mAttachmentPathPreference.setSummary(K9.getAttachmentDefaultPath());
|
||||
mAttachmentPathPreference
|
||||
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
FileBrowserHelper
|
||||
.getInstance()
|
||||
.showFileBrowserActivity(Prefs.this,
|
||||
new File(K9.getAttachmentDefaultPath()),
|
||||
ACTIVITY_CHOOSE_FOLDER, callback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FileBrowserFailOverCallback callback = new FileBrowserFailOverCallback() {
|
||||
|
||||
@Override
|
||||
public void onPathEntered(String path) {
|
||||
mAttachmentPathPreference.setSummary(path);
|
||||
K9.setAttachmentDefaultPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// canceled, do nothing
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
@ -336,7 +373,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
|
||||
|
||||
K9.setZoomControlsEnabled(mZoomControlsEnabled.isChecked());
|
||||
|
||||
K9.setAttachmentDefaultPath(mAttachmentPathPreference.getSummary().toString());
|
||||
boolean needsRefresh = K9.setBackgroundOps(mBackgroundOps.getValue());
|
||||
K9.setUseGalleryBugWorkaround(mUseGalleryBugWorkaround.isChecked());
|
||||
|
||||
@ -381,4 +418,25 @@ public class Prefs extends K9PreferenceActivity {
|
||||
},
|
||||
K9.getContactNameColor()).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_CHOOSE_FOLDER:
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
// obtain the filename
|
||||
Uri fileUri = data.getData();
|
||||
if (fileUri != null) {
|
||||
String filePath = fileUri.getPath();
|
||||
if (filePath != null) {
|
||||
mAttachmentPathPreference.setSummary(filePath.toString());
|
||||
K9.setAttachmentDefaultPath(filePath.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
@ -719,7 +719,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
// Never exclude the INBOX (see issue 1817)
|
||||
else if (noSpecialFolders && !localFolderName.equalsIgnoreCase(K9.INBOX) &&
|
||||
else if (noSpecialFolders && !localFolderName.equalsIgnoreCase(account.getInboxFolderName()) &&
|
||||
!localFolderName.equals(account.getArchiveFolderName()) && account.isSpecialFolder(localFolderName)) {
|
||||
include = false;
|
||||
} else if (displayableOnly && modeMismatch(account.getFolderDisplayMode(), folder.getDisplayClass())) {
|
||||
@ -793,7 +793,7 @@ public class MessagingController implements Runnable {
|
||||
LocalStore localStore = account.getLocalStore();
|
||||
LocalFolder localFolder = localStore.getFolder(folder);
|
||||
if (localFolder.getVisibleLimit() > 0) {
|
||||
localFolder.setVisibleLimit(localFolder.getVisibleLimit() + account.getDisplayCount());
|
||||
localFolder.setVisibleLimit(localFolder.getVisibleLimit() + localFolder.getMessageCount());
|
||||
}
|
||||
synchronizeMailbox(account, folder, listener, null);
|
||||
} catch (MessagingException me) {
|
||||
@ -1161,12 +1161,32 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the messages described by inputMessages from the remote store and writes them to
|
||||
* local storage.
|
||||
*
|
||||
* @param account
|
||||
* The account the remote store belongs to.
|
||||
* @param remoteFolder
|
||||
* The remote folder to download messages from.
|
||||
* @param localFolder
|
||||
* The {@link LocalFolder} instance corresponding to the remote folder.
|
||||
* @param inputMessages
|
||||
* A list of messages objects that store the UIDs of which messages to download.
|
||||
* @param flagSyncOnly
|
||||
* Only flags will be fetched from the remote store if this is {@code true}.
|
||||
*
|
||||
* @return The number of downloaded messages that are not flagged as {@link Flag#SEEN}.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private int downloadMessages(final Account account, final Folder remoteFolder,
|
||||
final LocalFolder localFolder, List<Message> inputMessages, boolean flagSyncOnly) throws MessagingException {
|
||||
final LocalFolder localFolder, List<Message> inputMessages,
|
||||
boolean flagSyncOnly) throws MessagingException {
|
||||
|
||||
final Date earliestDate = account.getEarliestPollDate();
|
||||
Date downloadStarted = new Date(); // now
|
||||
|
||||
|
||||
if (earliestDate != null) {
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Only syncing messages after " + earliestDate);
|
||||
@ -1541,7 +1561,7 @@ public class MessagingController implements Runnable {
|
||||
remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]),
|
||||
fp, new MessageRetrievalListener() {
|
||||
@Override
|
||||
public void messageFinished(Message message, int number, int ofTotal) {
|
||||
public void messageFinished(final Message message, int number, int ofTotal) {
|
||||
try {
|
||||
|
||||
if (!shouldImportMessage(account, folder, message, progress, earliestDate)) {
|
||||
@ -1557,6 +1577,13 @@ public class MessagingController implements Runnable {
|
||||
progress.incrementAndGet();
|
||||
}
|
||||
});
|
||||
|
||||
// Increment the number of "new messages" if the newly downloaded message is
|
||||
// not marked as read.
|
||||
if (!localMessage.isSet(Flag.SEEN)) {
|
||||
newMessages.incrementAndGet();
|
||||
}
|
||||
|
||||
if (K9.DEBUG)
|
||||
Log.v(K9.LOG_TAG, "About to notify listeners that we got a new small message "
|
||||
+ account + ":" + folder + ":" + message.getUid());
|
||||
@ -1572,7 +1599,6 @@ public class MessagingController implements Runnable {
|
||||
// Send a notification of this message
|
||||
|
||||
if (shouldNotifyForMessage(account, localFolder, message)) {
|
||||
newMessages.incrementAndGet();
|
||||
notifyAccount(mApplication, account, message, unreadBeforeStart, newMessages);
|
||||
}
|
||||
|
||||
@ -1691,6 +1717,13 @@ public class MessagingController implements Runnable {
|
||||
// Update the listener with what we've found
|
||||
progress.incrementAndGet();
|
||||
Message localMessage = localFolder.getMessage(message.getUid());
|
||||
|
||||
// Increment the number of "new messages" if the newly downloaded message is
|
||||
// not marked as read.
|
||||
if (!localMessage.isSet(Flag.SEEN)) {
|
||||
newMessages.incrementAndGet();
|
||||
}
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.synchronizeMailboxAddOrUpdateMessage(account, folder, localMessage);
|
||||
l.synchronizeMailboxProgress(account, folder, progress.get(), todo);
|
||||
@ -1701,7 +1734,6 @@ public class MessagingController implements Runnable {
|
||||
|
||||
// Send a notification of this message
|
||||
if (shouldNotifyForMessage(account, localFolder, message)) {
|
||||
newMessages.incrementAndGet();
|
||||
notifyAccount(mApplication, account, message, unreadBeforeStart, newMessages);
|
||||
}
|
||||
|
||||
@ -2174,14 +2206,7 @@ public class MessagingController implements Runnable {
|
||||
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
Folder remoteFolder = remoteStore.getFolder(folder);
|
||||
if (!remoteFolder.exists() ||
|
||||
/*
|
||||
* Don't proceed if the remote folder doesn't support flags and
|
||||
* the flag to be changed isn't the deleted flag. This avoids
|
||||
* unnecessary connections to POP3 servers.
|
||||
*/
|
||||
// TODO: This should actually call a supportsSettingFlag(flag) method.
|
||||
(!remoteFolder.supportsFetchingFlags() && !Flag.DELETED.equals(flag))) {
|
||||
if (!remoteFolder.exists() || !remoteFolder.isFlagSupported(flag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2385,7 +2410,7 @@ public class MessagingController implements Runnable {
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
remoteFolder = remoteStore.getFolder(folder);
|
||||
|
||||
if (!remoteFolder.exists()) {
|
||||
if (!remoteFolder.exists() || !remoteFolder.isFlagSupported(Flag.SEEN)) {
|
||||
return;
|
||||
}
|
||||
remoteFolder.open(OpenMode.READ_WRITE);
|
||||
@ -2880,7 +2905,7 @@ public class MessagingController implements Runnable {
|
||||
(NotificationManager)mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
Notification notif = new Notification(R.drawable.ic_menu_refresh,
|
||||
mApplication.getString(R.string.notification_bg_send_ticker, account.getDescription()), System.currentTimeMillis());
|
||||
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, K9.INBOX);
|
||||
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, account.getInboxFolderName());
|
||||
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
||||
notif.setLatestEventInfo(mApplication, mApplication.getString(R.string.notification_bg_send_title),
|
||||
account.getDescription() , pi);
|
||||
@ -2922,7 +2947,7 @@ public class MessagingController implements Runnable {
|
||||
Notification notif = new Notification(R.drawable.ic_menu_refresh,
|
||||
mApplication.getString(R.string.notification_bg_sync_ticker, account.getDescription(), folder.getName()),
|
||||
System.currentTimeMillis());
|
||||
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, K9.INBOX);
|
||||
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, account.getInboxFolderName());
|
||||
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
||||
notif.setLatestEventInfo(mApplication, mApplication.getString(R.string.notification_bg_sync_title), account.getDescription()
|
||||
+ mApplication.getString(R.string.notification_bg_title_separator) + folder.getName(), pi);
|
||||
@ -3025,6 +3050,16 @@ public class MessagingController implements Runnable {
|
||||
|
||||
localFolder.fetch(new Message[] { message }, fp, null);
|
||||
try {
|
||||
|
||||
|
||||
if (message.getHeader(K9.IDENTITY_HEADER) != null) {
|
||||
Log.v(K9.LOG_TAG, "The user has set the Outbox and Drafts folder to the same thing. " +
|
||||
"This message appears to be a draft, so K-9 will not send it");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
|
||||
message.setFlag(Flag.X_SEND_IN_PROGRESS, true);
|
||||
if (K9.DEBUG)
|
||||
Log.i(K9.LOG_TAG, "Sending message with UID " + message.getUid());
|
||||
@ -3856,18 +3891,31 @@ public class MessagingController implements Runnable {
|
||||
|
||||
|
||||
private boolean shouldNotifyForMessage(Account account, LocalFolder localFolder, Message message) {
|
||||
// Do not notify if the user does not have notifications
|
||||
// enabled or if the message has been read
|
||||
if (!account.isNotifyNewMail() || message.isSet(Flag.SEEN) || (account.getName() == null)) {
|
||||
// If we don't even have an account name, don't show the notification.
|
||||
// (This happens during initial account setup)
|
||||
if (account.getName() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not notify if the user does not have notifications enabled or if the message has
|
||||
// been read.
|
||||
if (!account.isNotifyNewMail() || message.isSet(Flag.SEEN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the account is a POP3 account and the message is older than the oldest message we've
|
||||
// previously seen, then don't notify about it.
|
||||
if (account.getStoreUri().startsWith("pop3") &&
|
||||
message.olderThan(new Date(account.getLatestOldMessageSeenTime()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No notification for new messages in Trash, Drafts, Spam or Sent folder.
|
||||
// But do notify if it's the INBOX (see issue 1817).
|
||||
Folder folder = message.getFolder();
|
||||
if (folder != null) {
|
||||
// No notification for new messages in Trash, Drafts, Spam or Sent folder.
|
||||
// But do notify if it's the INBOX (see issue 1817).
|
||||
String folderName = folder.getName();
|
||||
if (!K9.INBOX.equals(folderName) &&
|
||||
if (!account.getInboxFolderName().equals(folderName) &&
|
||||
(account.getTrashFolderName().equals(folderName)
|
||||
|| account.getDraftsFolderName().equals(folderName)
|
||||
|| account.getSpamFolderName().equals(folderName)
|
||||
@ -3881,7 +3929,8 @@ public class MessagingController implements Runnable {
|
||||
Integer messageUid = Integer.parseInt(message.getUid());
|
||||
if (messageUid <= localFolder.getLastUid()) {
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Message uid is " + messageUid + ", max message uid is " + localFolder.getLastUid() + ". Skipping notification.");
|
||||
Log.d(K9.LOG_TAG, "Message uid is " + messageUid + ", max message uid is " +
|
||||
localFolder.getLastUid() + ". Skipping notification.");
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
@ -3889,31 +3938,22 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// Don't notify if the sender address matches one of our identities and the user chose not
|
||||
// to be notified for such messages.
|
||||
if (account.isAnIdentity(message.getFrom()) && !account.isNotifySelfNewMail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Creates a notification of new email messages
|
||||
* ringtone, lights, and vibration to be played
|
||||
*/
|
||||
private boolean notifyAccount(Context context, Account account, Message message, int previousUnreadMessageCount, AtomicInteger newMessageCount) {
|
||||
// If we don't even have an account name, don't show the notification
|
||||
// (This happens during initial account setup)
|
||||
//
|
||||
if (account.getName() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the account us a POP3 account and the message is older than
|
||||
// the oldest message we've previously seen then don't notify about it
|
||||
if (account.getStoreUri().startsWith("pop3")) {
|
||||
if (message.olderThan(new Date(account.getLatestOldMessageSeenTime()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification of a newly received message.
|
||||
*/
|
||||
private void notifyAccount(Context context, Account account, Message message,
|
||||
int previousUnreadMessageCount, AtomicInteger newMessageCount) {
|
||||
|
||||
// If we have a message, set the notification to "<From>: <Subject>"
|
||||
StringBuilder messageNotice = new StringBuilder();
|
||||
@ -3934,19 +3974,13 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
// show To: if the message was sent from me
|
||||
else {
|
||||
if (!account.isNotifySelfNewMail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Address[] rcpts = message.getRecipients(Message.RecipientType.TO);
|
||||
String to = rcpts.length > 0 ? rcpts[0].toFriendly().toString() : null;
|
||||
if (to != null) {
|
||||
messageNotice.append(String.format(context.getString(R.string.message_to_fmt), to)).append(": ").append(subject);
|
||||
} else {
|
||||
messageNotice.append(context.getString(R.string.general_no_sender)).append(": ").append(subject);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3972,7 +4006,8 @@ public class MessagingController implements Runnable {
|
||||
Intent i = FolderList.actionHandleNotification(context, account, message.getFolder().getName());
|
||||
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
|
||||
|
||||
String accountNotice = context.getString(R.string.notification_new_one_account_fmt, unreadCount, account.getDescription());
|
||||
String accountDescr = (account.getDescription() != null) ? account.getDescription() : account.getEmail();
|
||||
String accountNotice = context.getString(R.string.notification_new_one_account_fmt, unreadCount, accountDescr);
|
||||
notif.setLatestEventInfo(context, accountNotice, messageNotice, pi);
|
||||
|
||||
// Only ring or vibrate if we have not done so already on this
|
||||
@ -3988,7 +4023,6 @@ public class MessagingController implements Runnable {
|
||||
configureNotification(notif, (n.shouldRing() ? n.getRingtone() : null), (n.shouldVibrate() ? n.getVibration() : null), (n.isLed() ? n.getLedColor() : null), K9.NOTIFICATION_LED_BLINK_SLOW, ringAndVibrate);
|
||||
|
||||
notifMgr.notify(account.getAccountNumber(), notif);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,13 +97,6 @@ public abstract class Contacts {
|
||||
mContentResolver = context.getContentResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the device's owner.
|
||||
*
|
||||
* @return The name of the owner if available. <tt>null</tt>, otherwise.
|
||||
*/
|
||||
public abstract String getOwnerName();
|
||||
|
||||
/**
|
||||
* Start the activity to add information to an existing contact or add a
|
||||
* new one.
|
||||
@ -195,7 +188,7 @@ public abstract class Contacts {
|
||||
public boolean hasContactPicker() {
|
||||
if (mHasContactPicker == null) {
|
||||
mHasContactPicker = (mContext.getPackageManager().
|
||||
queryIntentActivities(contactPickerIntent(), 0).size() > 0);
|
||||
queryIntentActivities(contactPickerIntent(), 0).size() > 0);
|
||||
}
|
||||
return mHasContactPicker;
|
||||
}
|
||||
|
@ -85,27 +85,6 @@ public class ContactsSdk3_4 extends com.fsck.k9.helper.Contacts {
|
||||
mContext.startActivity(contactIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerName() {
|
||||
String name = null;
|
||||
final Cursor c = mContentResolver.query(
|
||||
Uri.withAppendedPath(Contacts.People.CONTENT_URI, "owner"),
|
||||
new String[] {Contacts.ContactMethods.DISPLAY_NAME},
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
if (c != null) {
|
||||
if (c.getCount() > 0) {
|
||||
c.moveToFirst();
|
||||
name = c.getString(0); // owner's display name
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContacts(final String emailAddress) {
|
||||
boolean result = false;
|
||||
@ -239,11 +218,11 @@ public class ContactsSdk3_4 extends com.fsck.k9.helper.Contacts {
|
||||
if (cursor.moveToFirst()) {
|
||||
String emailId = cursor.getString(cursor.getColumnIndex(Contacts.People.PRIMARY_EMAIL_ID));
|
||||
cursor2 = mContext.getContentResolver().query(
|
||||
ContactMethods.CONTENT_EMAIL_URI,
|
||||
new String[] { ContactMethods.DATA },
|
||||
"contact_methods._id=?",
|
||||
new String[] { emailId },
|
||||
null);
|
||||
ContactMethods.CONTENT_EMAIL_URI,
|
||||
new String[] { ContactMethods.DATA },
|
||||
"contact_methods._id=?",
|
||||
new String[] { emailId },
|
||||
null);
|
||||
|
||||
if (cursor2.moveToFirst()) {
|
||||
email = cursor2.getString(0);
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
@ -87,22 +85,6 @@ public class ContactsSdk5 extends com.fsck.k9.helper.Contacts {
|
||||
mContext.startActivity(contactIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerName() {
|
||||
String name = null;
|
||||
|
||||
// Get the name of the first account that has one.
|
||||
Account[] accounts = AccountManager.get(mContext).getAccounts();
|
||||
for (final Account account : accounts) {
|
||||
if (account.name != null) {
|
||||
name = account.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContacts(final String emailAddress) {
|
||||
boolean result = false;
|
||||
|
134
src/com/fsck/k9/helper/FileBrowserHelper.java
Normal file
134
src/com/fsck/k9/helper/FileBrowserHelper.java
Normal file
@ -0,0 +1,134 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.InputType;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
|
||||
public class FileBrowserHelper {
|
||||
/**
|
||||
* A string array that specifies the name of the intent to use, and the scheme to use with it
|
||||
* when setting the data for the intent.
|
||||
*/
|
||||
private static final String[][] PICK_DIRECTORY_INTENTS = {
|
||||
{ "org.openintents.action.PICK_DIRECTORY", "file://" }, // OI File Manager (maybe others)
|
||||
{ "com.estrongs.action.PICK_DIRECTORY", "file://" }, // ES File Explorer
|
||||
{ Intent.ACTION_PICK, "folder://" }, // Blackmoon File Browser (maybe others)
|
||||
{ "com.androidworkz.action.PICK_DIRECTORY", "file://" }
|
||||
}; // SystemExplorer
|
||||
|
||||
private static FileBrowserHelper sInstance;
|
||||
|
||||
/**
|
||||
* callback class to provide the result of the fallback textedit path dialog
|
||||
*/
|
||||
public interface FileBrowserFailOverCallback {
|
||||
/**
|
||||
* the user has entered a path
|
||||
* @param path the path as String
|
||||
*/
|
||||
public void onPathEntered(String path);
|
||||
/**
|
||||
* the user has cancel the inputtext dialog
|
||||
*/
|
||||
public void onCancel();
|
||||
}
|
||||
/**
|
||||
* factory method
|
||||
*
|
||||
*/
|
||||
private FileBrowserHelper() {
|
||||
}
|
||||
public synchronized static FileBrowserHelper getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new FileBrowserHelper();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tries to open known filebrowsers.
|
||||
* If no filebrowser is found and fallback textdialog is shown
|
||||
* @param c the context as activity
|
||||
* @param startPath: the default value, where the filebrowser will start.
|
||||
* if startPath = null => the default path is used
|
||||
* @param requestcode: the int you will get as requestcode in onActivityResult
|
||||
* (only used if there is a filebrowser installed)
|
||||
* @param callback: the callback (only used when no filebrowser is installed.
|
||||
* if a filebrowser is installed => override the onActivtyResult Method
|
||||
*
|
||||
* @return true: if a filebrowser has been found (the result will be in the onActivityResult
|
||||
* false: a fallback textinput has been shown. The Result will be sent with the callback method
|
||||
*
|
||||
*
|
||||
*/
|
||||
public boolean showFileBrowserActivity(Activity c, File startPath, int requestcode, FileBrowserFailOverCallback callback) {
|
||||
boolean success = false;
|
||||
|
||||
if (startPath == null) {
|
||||
startPath = new File(K9.getAttachmentDefaultPath());
|
||||
}
|
||||
|
||||
int listIndex = 0;
|
||||
do {
|
||||
String intentAction = PICK_DIRECTORY_INTENTS[listIndex][0];
|
||||
String uriPrefix = PICK_DIRECTORY_INTENTS[listIndex][1];
|
||||
Intent intent = new Intent(intentAction);
|
||||
intent.setData(Uri.parse(uriPrefix + startPath.getPath()));
|
||||
|
||||
try {
|
||||
c.startActivityForResult(intent, requestcode);
|
||||
success = true;
|
||||
} catch (ActivityNotFoundException e) {
|
||||
// Try the next intent in the list
|
||||
listIndex++;
|
||||
};
|
||||
} while (!success && (listIndex < PICK_DIRECTORY_INTENTS.length));
|
||||
|
||||
if (listIndex == PICK_DIRECTORY_INTENTS.length) {
|
||||
//No Filebrowser is installed => show a fallback textdialog
|
||||
showPathTextInput(c, startPath, callback);
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private void showPathTextInput(final Activity c, final File startPath, final FileBrowserFailOverCallback callback) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(c);
|
||||
|
||||
alert.setTitle(c.getString(R.string.attachment_save_title));
|
||||
alert.setMessage(c.getString(R.string.attachment_save_desc));
|
||||
final EditText input = new EditText(c);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
if (startPath != null)
|
||||
input.setText(startPath.toString());
|
||||
alert.setView(input);
|
||||
|
||||
alert.setPositiveButton(c.getString(R.string.okay_action), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String path = input.getText().toString();
|
||||
callback.onPathEntered(path);
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(c.getString(R.string.cancel_action),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
callback.onCancel();
|
||||
}
|
||||
});
|
||||
|
||||
alert.show();
|
||||
}
|
||||
}
|
@ -123,6 +123,45 @@ public class HtmlConverter {
|
||||
|
||||
private static final int MAX_SMART_HTMLIFY_MESSAGE_LENGTH = 1024 * 256 ;
|
||||
|
||||
/**
|
||||
* Naively convert a text string into an HTML document. This method avoids using regular expressions on the entire
|
||||
* message body to save memory.
|
||||
* @param text Plain text string.
|
||||
* @return HTML string.
|
||||
*/
|
||||
private static String simpleTextToHtml(String text) {
|
||||
// Encode HTML entities to make sure we don't display something evil.
|
||||
text = TextUtils.htmlEncode(text);
|
||||
|
||||
StringReader reader = new StringReader(text);
|
||||
StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH);
|
||||
buff.append("<html><head/><body>");
|
||||
|
||||
int c;
|
||||
try {
|
||||
while ((c = reader.read()) != -1) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
// pine treats <br> as two newlines, but <br/> as one newline. Use <br/> so our messages aren't
|
||||
// doublespaced.
|
||||
buff.append("<br />");
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
buff.append((char)c);
|
||||
}//switch
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//Should never happen
|
||||
Log.e(K9.LOG_TAG, "Could not read string to convert text to HTML:", e);
|
||||
}
|
||||
|
||||
buff.append("</body></html>");
|
||||
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a text string into an HTML document. Attempts to do smart replacement for large
|
||||
* documents to prevent OOM errors. This method adds headers and footers to create a proper HTML
|
||||
@ -136,11 +175,7 @@ public class HtmlConverter {
|
||||
// if the message is big and plain text, just do
|
||||
// a trivial htmlification
|
||||
if (text.length() > MAX_SMART_HTMLIFY_MESSAGE_LENGTH) {
|
||||
return "<html><head/><body>" +
|
||||
htmlifyMessageHeader() +
|
||||
text +
|
||||
htmlifyMessageFooter() +
|
||||
"</body></html>";
|
||||
return simpleTextToHtml(text);
|
||||
}
|
||||
StringReader reader = new StringReader(text);
|
||||
StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH);
|
||||
@ -148,6 +183,11 @@ public class HtmlConverter {
|
||||
try {
|
||||
while ((c = reader.read()) != -1) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
// pine treats <br> as two newlines, but <br/> as one newline. Use <br/> so our messages aren't
|
||||
// doublespaced.
|
||||
buff.append("<br />");
|
||||
break;
|
||||
case '&':
|
||||
buff.append("&");
|
||||
break;
|
||||
@ -168,8 +208,14 @@ public class HtmlConverter {
|
||||
Log.e(K9.LOG_TAG, "Could not read string to convert text to HTML:", e);
|
||||
}
|
||||
text = buff.toString();
|
||||
|
||||
// Replace lines of -,= or _ with horizontal rules
|
||||
text = text.replaceAll("\\s*([-=_]{30,}+)\\s*", "<hr />");
|
||||
|
||||
// TODO: reverse engineer (or troll history) and document
|
||||
text = text.replaceAll("(?m)^([^\r\n]{4,}[\\s\\w,:;+/])(?:\r\n|\n|\r)(?=[a-z]\\S{0,10}[\\s\\n\\r])", "$1 ");
|
||||
|
||||
// Compress four or more newlines down to two newlines
|
||||
text = text.replaceAll("(?m)(\r\n|\n|\r){4,}", "\n\n");
|
||||
|
||||
StringBuffer sb = new StringBuffer(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH);
|
||||
|
@ -99,4 +99,9 @@ public class MessageHelper {
|
||||
return mDateFormat.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
mDateFormat = DateFormatter.getDateFormat(mContext);
|
||||
mTodayDateFormat = android.text.format.DateFormat.getTimeFormat(mContext);
|
||||
}
|
||||
}
|
||||
|
@ -57,24 +57,25 @@ public class Utility {
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the given array of Objects into a single string using the
|
||||
* seperator character and each Object's toString() method. between each
|
||||
* part.
|
||||
* Combines the given array of Objects into a single String using
|
||||
* each Object's toString() method and the separator character
|
||||
* between each part.
|
||||
*
|
||||
* @param parts
|
||||
* @param seperator
|
||||
* @return
|
||||
* @param separator
|
||||
* @return new String
|
||||
*/
|
||||
public static String combine(Object[] parts, char seperator) {
|
||||
public static String combine(Object[] parts, char separator) {
|
||||
if (parts == null) {
|
||||
return null;
|
||||
} else if (parts.length == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
sb.append(parts[i].toString());
|
||||
if (i < parts.length - 1) {
|
||||
sb.append(seperator);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(parts[0]);
|
||||
for (int i = 1; i < parts.length; ++i) {
|
||||
sb.append(separator);
|
||||
sb.append(parts[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -6,80 +6,80 @@ import com.fsck.k9.mail.filter.Base64;
|
||||
import com.fsck.k9.mail.filter.Hex;
|
||||
|
||||
public class Authentication {
|
||||
private static final String US_ASCII = "US-ASCII";
|
||||
private static final String US_ASCII = "US-ASCII";
|
||||
|
||||
/**
|
||||
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
||||
* the server-provided nonce.
|
||||
*
|
||||
* @param username The username.
|
||||
* @param password The password.
|
||||
* @param b64Nonce The nonce as base64-encoded string.
|
||||
* @return The CRAM-MD5 response.
|
||||
*
|
||||
* @throws AuthenticationFailedException If something went wrong.
|
||||
*
|
||||
* @see Authentication#computeCramMd5Bytes(String, String, byte[])
|
||||
*/
|
||||
public static String computeCramMd5(String username, String password, String b64Nonce)
|
||||
throws AuthenticationFailedException {
|
||||
/**
|
||||
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
||||
* the server-provided nonce.
|
||||
*
|
||||
* @param username The username.
|
||||
* @param password The password.
|
||||
* @param b64Nonce The nonce as base64-encoded string.
|
||||
* @return The CRAM-MD5 response.
|
||||
*
|
||||
* @throws AuthenticationFailedException If something went wrong.
|
||||
*
|
||||
* @see Authentication#computeCramMd5Bytes(String, String, byte[])
|
||||
*/
|
||||
public static String computeCramMd5(String username, String password, String b64Nonce)
|
||||
throws AuthenticationFailedException {
|
||||
|
||||
try {
|
||||
byte[] b64NonceBytes = b64Nonce.getBytes(US_ASCII);
|
||||
byte[] b64CRAM = computeCramMd5Bytes(username, password, b64NonceBytes);
|
||||
return new String(b64CRAM, US_ASCII);
|
||||
byte[] b64NonceBytes = b64Nonce.getBytes(US_ASCII);
|
||||
byte[] b64CRAM = computeCramMd5Bytes(username, password, b64NonceBytes);
|
||||
return new String(b64CRAM, US_ASCII);
|
||||
} catch (AuthenticationFailedException e) {
|
||||
throw e;
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new AuthenticationFailedException("This shouldn't happen", e);
|
||||
throw new AuthenticationFailedException("This shouldn't happen", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
||||
* the server-provided nonce.
|
||||
*
|
||||
* @param username The username.
|
||||
* @param password The password.
|
||||
* @param b64Nonce The nonce as base64-encoded byte array.
|
||||
* @return The CRAM-MD5 response as byte array.
|
||||
*
|
||||
* @throws AuthenticationFailedException If something went wrong.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2195">RFC 2195</a>
|
||||
*/
|
||||
public static byte[] computeCramMd5Bytes(String username, String password, byte[] b64Nonce)
|
||||
throws AuthenticationFailedException {
|
||||
/**
|
||||
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
||||
* the server-provided nonce.
|
||||
*
|
||||
* @param username The username.
|
||||
* @param password The password.
|
||||
* @param b64Nonce The nonce as base64-encoded byte array.
|
||||
* @return The CRAM-MD5 response as byte array.
|
||||
*
|
||||
* @throws AuthenticationFailedException If something went wrong.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2195">RFC 2195</a>
|
||||
*/
|
||||
public static byte[] computeCramMd5Bytes(String username, String password, byte[] b64Nonce)
|
||||
throws AuthenticationFailedException {
|
||||
|
||||
try {
|
||||
byte[] nonce = Base64.decodeBase64(b64Nonce);
|
||||
byte[] nonce = Base64.decodeBase64(b64Nonce);
|
||||
|
||||
byte[] secretBytes = password.getBytes(US_ASCII);
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
if (secretBytes.length > 64) {
|
||||
secretBytes = md.digest(secretBytes);
|
||||
}
|
||||
byte[] secretBytes = password.getBytes(US_ASCII);
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
if (secretBytes.length > 64) {
|
||||
secretBytes = md.digest(secretBytes);
|
||||
}
|
||||
|
||||
byte[] ipad = new byte[64];
|
||||
byte[] opad = new byte[64];
|
||||
System.arraycopy(secretBytes, 0, ipad, 0, secretBytes.length);
|
||||
System.arraycopy(secretBytes, 0, opad, 0, secretBytes.length);
|
||||
for (int i = 0; i < ipad.length; i++) ipad[i] ^= 0x36;
|
||||
for (int i = 0; i < opad.length; i++) opad[i] ^= 0x5c;
|
||||
byte[] ipad = new byte[64];
|
||||
byte[] opad = new byte[64];
|
||||
System.arraycopy(secretBytes, 0, ipad, 0, secretBytes.length);
|
||||
System.arraycopy(secretBytes, 0, opad, 0, secretBytes.length);
|
||||
for (int i = 0; i < ipad.length; i++) ipad[i] ^= 0x36;
|
||||
for (int i = 0; i < opad.length; i++) opad[i] ^= 0x5c;
|
||||
|
||||
md.update(ipad);
|
||||
byte[] firstPass = md.digest(nonce);
|
||||
md.update(ipad);
|
||||
byte[] firstPass = md.digest(nonce);
|
||||
|
||||
md.update(opad);
|
||||
byte[] result = md.digest(firstPass);
|
||||
md.update(opad);
|
||||
byte[] result = md.digest(firstPass);
|
||||
|
||||
String plainCRAM = username + " " + new String(Hex.encodeHex(result));
|
||||
byte[] b64CRAM = Base64.encodeBase64(plainCRAM.getBytes(US_ASCII));
|
||||
String plainCRAM = username + " " + new String(Hex.encodeHex(result));
|
||||
byte[] b64CRAM = Base64.encodeBase64(plainCRAM.getBytes(US_ASCII));
|
||||
|
||||
return b64CRAM;
|
||||
return b64CRAM;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AuthenticationFailedException("Something went wrong during CRAM-MD5 computation", e);
|
||||
throw new AuthenticationFailedException("Something went wrong during CRAM-MD5 computation", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,9 +153,13 @@ public abstract class Folder {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isFlagSupported(Flag flag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsFetchingFlags() {
|
||||
return true;
|
||||
}//isFlagSupported
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -20,14 +20,13 @@ package com.fsck.k9.mail.filter;
|
||||
* This code was copied from the Apache Commons project.
|
||||
* The unnecessary parts have been left out.
|
||||
*/
|
||||
public class Hex
|
||||
{
|
||||
public class Hex {
|
||||
/**
|
||||
* Used building output as Hex
|
||||
*/
|
||||
private static final char[] DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
/**
|
||||
@ -43,15 +42,15 @@ public class Hex
|
||||
|
||||
int l = data.length;
|
||||
|
||||
char[] out = new char[l << 1];
|
||||
char[] out = new char[l << 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = DIGITS[(0xF0 & data[i]) >>> 4 ];
|
||||
out[j++] = DIGITS[ 0x0F & data[i] ];
|
||||
}
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = DIGITS[(0xF0 & data[i]) >>> 4 ];
|
||||
out[j++] = DIGITS[ 0x0F & data[i] ];
|
||||
}
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class PeekableInputStream extends InputStream {
|
||||
|
||||
public int peek() throws IOException {
|
||||
if (!mPeeked) {
|
||||
mPeekedByte = read();
|
||||
mPeekedByte = mIn.read();
|
||||
mPeeked = true;
|
||||
}
|
||||
return mPeekedByte;
|
||||
|
@ -14,6 +14,7 @@ import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
|
||||
|
||||
public class MimeUtility {
|
||||
@ -1212,13 +1213,13 @@ public class MimeUtility {
|
||||
* @see #MIME_TYPE_REPLACEMENT_MAP
|
||||
*/
|
||||
public static String canonicalizeMimeType(String mimeType) {
|
||||
for (String[] mimeTypeMapEntry : MIME_TYPE_REPLACEMENT_MAP) {
|
||||
if (mimeTypeMapEntry[0].equals(mimeType)) {
|
||||
return mimeTypeMapEntry[1];
|
||||
}
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
for (String[] mimeTypeMapEntry : MIME_TYPE_REPLACEMENT_MAP) {
|
||||
if (mimeTypeMapEntry[0].equals(mimeType)) {
|
||||
return mimeTypeMapEntry[1];
|
||||
}
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When viewing the attachment we want the MIME type to be as sensible as
|
||||
@ -1381,13 +1382,19 @@ public class MimeUtility {
|
||||
|
||||
/*
|
||||
* See if there is conversion from the MIME charset to the Java one.
|
||||
* this function may also throw an exception if the charset name is not known
|
||||
*/
|
||||
if (!Charset.isSupported(charset)) {
|
||||
boolean supported;
|
||||
try {
|
||||
supported = Charset.isSupported(charset);
|
||||
} catch (IllegalCharsetNameException e) {
|
||||
supported = false;
|
||||
}
|
||||
if (!supported) {
|
||||
Log.e(K9.LOG_TAG, "I don't know how to deal with the charset " + charset +
|
||||
". Falling back to US-ASCII");
|
||||
charset = "US-ASCII";
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert and return as new String
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@ public class ImapResponseParser {
|
||||
private static final SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
|
||||
private static final SimpleDateFormat badDateTimeFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss Z", Locale.US);
|
||||
private static final SimpleDateFormat badDateTimeFormat2 = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.US);
|
||||
private static final SimpleDateFormat badDateTimeFormat3 = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss", Locale.US);
|
||||
|
||||
private PeekableInputStream mIn;
|
||||
private ImapResponse mResponse;
|
||||
@ -194,7 +195,7 @@ public class ImapResponseParser {
|
||||
}
|
||||
|
||||
private String parseAtom() throws IOException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int ch;
|
||||
while (true) {
|
||||
ch = mIn.peek();
|
||||
@ -361,7 +362,7 @@ public class ImapResponseParser {
|
||||
}
|
||||
return parseDate(value);
|
||||
} catch (ParseException pe) {
|
||||
throw new MessagingException("Unable to parse IMAP datetime '"+value+"' ", pe);
|
||||
throw new MessagingException("Unable to parse IMAP datetime '" + value + "' ", pe);
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,8 +427,14 @@ public class ImapResponseParser {
|
||||
return badDateTimeFormat.parse(value);
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
synchronized (badDateTimeFormat2) {
|
||||
return badDateTimeFormat2.parse(value);
|
||||
try {
|
||||
synchronized (badDateTimeFormat2) {
|
||||
return badDateTimeFormat2.parse(value);
|
||||
}
|
||||
} catch (Exception e3) {
|
||||
synchronized (badDateTimeFormat3) {
|
||||
return badDateTimeFormat3.parse(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,10 @@ import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
@ -373,16 +376,31 @@ public class ImapStore extends Store {
|
||||
for (ImapResponse response : responses) {
|
||||
if (ImapResponseParser.equalsIgnoreCase(response.get(0), commandResponse)) {
|
||||
boolean includeFolder = true;
|
||||
String folder = decodeFolderName(response.getString(3));
|
||||
|
||||
String decodedFolderName;
|
||||
try {
|
||||
decodedFolderName = decodeFolderName(response.getString(3));
|
||||
} catch (CharacterCodingException e) {
|
||||
Log.w(K9.LOG_TAG, "Folder name not correctly encoded with the UTF-7 variant " +
|
||||
"as defined by RFC 3501: " + response.getString(3), e);
|
||||
|
||||
//TODO: Use the raw name returned by the server for all commands that require
|
||||
// a folder name. Use the decoded name only for showing it to the user.
|
||||
|
||||
// We currently just skip folders with malformed names.
|
||||
continue;
|
||||
}
|
||||
|
||||
String folder = decodedFolderName;
|
||||
|
||||
if (mPathDelimeter == null) {
|
||||
mPathDelimeter = response.getString(2);
|
||||
mCombinedPrefix = null;
|
||||
}
|
||||
|
||||
if (folder.equalsIgnoreCase(K9.INBOX)) {
|
||||
if (folder.equalsIgnoreCase(mAccount.getInboxFolderName())) {
|
||||
continue;
|
||||
} else if (folder.equalsIgnoreCase(K9.OUTBOX)) {
|
||||
} else if (folder.equals(mAccount.getOutboxFolderName())) {
|
||||
/*
|
||||
* There is a folder on the server with the same name as our local
|
||||
* outbox. Until we have a good plan to deal with this situation
|
||||
@ -390,12 +408,13 @@ public class ImapStore extends Store {
|
||||
*/
|
||||
continue;
|
||||
} else {
|
||||
|
||||
if (getCombinedPrefix().length() > 0) {
|
||||
if (folder.length() >= getCombinedPrefix().length()) {
|
||||
folder = folder.substring(getCombinedPrefix().length());
|
||||
int prefixLength = getCombinedPrefix().length();
|
||||
if (prefixLength > 0) {
|
||||
// Strip prefix from the folder name
|
||||
if (folder.length() >= prefixLength) {
|
||||
folder = folder.substring(prefixLength);
|
||||
}
|
||||
if (!decodeFolderName(response.getString(3)).equalsIgnoreCase(getCombinedPrefix() + folder)) {
|
||||
if (!decodedFolderName.equalsIgnoreCase(getCombinedPrefix() + folder)) {
|
||||
includeFolder = false;
|
||||
}
|
||||
}
|
||||
@ -413,7 +432,7 @@ public class ImapStore extends Store {
|
||||
}
|
||||
}
|
||||
}
|
||||
folders.add(getFolder("INBOX"));
|
||||
folders.add(getFolder(mAccount.getInboxFolderName()));
|
||||
return folders;
|
||||
|
||||
}
|
||||
@ -492,14 +511,15 @@ public class ImapStore extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
private String decodeFolderName(String name) {
|
||||
private String decodeFolderName(String name) throws CharacterCodingException {
|
||||
/*
|
||||
* Convert the encoded name to US-ASCII, then pass it through the modified UTF-7
|
||||
* decoder and return the Unicode String.
|
||||
*/
|
||||
try {
|
||||
byte[] encoded = name.getBytes("US-ASCII");
|
||||
CharBuffer cb = mModifiedUtf7Charset.decode(ByteBuffer.wrap(encoded));
|
||||
// Make sure the decoder throws an exception if it encounters an invalid encoding.
|
||||
CharsetDecoder decoder = mModifiedUtf7Charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT);
|
||||
CharBuffer cb = decoder.decode(ByteBuffer.wrap(name.getBytes("US-ASCII")));
|
||||
return cb.toString();
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
/*
|
||||
@ -548,7 +568,7 @@ public class ImapStore extends Store {
|
||||
|
||||
public String getPrefixedName() throws MessagingException {
|
||||
String prefixedName = "";
|
||||
if (!K9.INBOX.equalsIgnoreCase(mName)) {
|
||||
if (!mAccount.getInboxFolderName().equalsIgnoreCase(mName)) {
|
||||
ImapConnection connection = null;
|
||||
synchronized (this) {
|
||||
if (mConnection == null) {
|
||||
@ -2098,7 +2118,7 @@ public class ImapStore extends Store {
|
||||
System.arraycopy(buf, 1, b64NonceTrim, 0, b64NonceLen - 2);
|
||||
|
||||
byte[] b64CRAM = Authentication.computeCramMd5Bytes(mSettings.getUsername(),
|
||||
mSettings.getPassword(), b64NonceTrim);
|
||||
mSettings.getPassword(), b64NonceTrim);
|
||||
|
||||
mOut.write(b64CRAM);
|
||||
mOut.write(new byte[] { 0x0d, 0x0a });
|
||||
|
@ -10,6 +10,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -366,7 +367,7 @@ public class LocalStore extends Store implements Serializable {
|
||||
Folder.FolderClass pushClass = Folder.FolderClass.SECOND_CLASS;
|
||||
boolean inTopGroup = false;
|
||||
boolean integrate = false;
|
||||
if (K9.INBOX.equals(name)) {
|
||||
if (mAccount.getInboxFolderName().equals(name)) {
|
||||
displayClass = Folder.FolderClass.FIRST_CLASS;
|
||||
syncClass = Folder.FolderClass.FIRST_CLASS;
|
||||
pushClass = Folder.FolderClass.FIRST_CLASS;
|
||||
@ -484,9 +485,6 @@ public class LocalStore extends Store implements Serializable {
|
||||
cursor = db.rawQuery("SELECT COUNT(*) FROM messages", null);
|
||||
cursor.moveToFirst();
|
||||
return cursor.getInt(0); // message count
|
||||
|
||||
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@ -496,8 +494,6 @@ public class LocalStore extends Store implements Serializable {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void getMessageCounts(final AccountStats stats) throws MessagingException {
|
||||
final Account.FolderMode displayMode = mAccount.getFolderDisplayMode();
|
||||
|
||||
@ -506,65 +502,61 @@ public class LocalStore extends Store implements Serializable {
|
||||
public Integer doDbWork(final SQLiteDatabase db) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
String baseQuery = "SELECT SUM(unread_count), SUM(flagged_count) FROM folders WHERE ( name != ? AND name != ? AND name != ? AND name != ? AND name != ? ) ";
|
||||
if (displayMode == Account.FolderMode.NONE) {
|
||||
cursor = db.rawQuery(baseQuery + "AND (name = ? )", new String[] {
|
||||
// Always count messages in the INBOX but exclude special folders and possibly
|
||||
// more (depending on the folder display mode)
|
||||
String baseQuery = "SELECT SUM(unread_count), SUM(flagged_count) " +
|
||||
"FROM folders " +
|
||||
"WHERE (name = ?)" + /* INBOX */
|
||||
" OR (" +
|
||||
"name NOT IN (?, ?, ?, ?, ?)" + /* special folders */
|
||||
"%s)"; /* placeholder for additional constraints */
|
||||
|
||||
mAccount.getTrashFolderName() != null ? mAccount.getTrashFolderName() : "" ,
|
||||
mAccount.getDraftsFolderName() != null ? mAccount.getDraftsFolderName() : "",
|
||||
mAccount.getSpamFolderName() != null ? mAccount.getSpamFolderName() : "",
|
||||
mAccount.getOutboxFolderName() != null ? mAccount.getOutboxFolderName() : "",
|
||||
mAccount.getSentFolderName() != null ? mAccount.getSentFolderName() : "",
|
||||
K9.INBOX
|
||||
}
|
||||
List<String> queryParam = new ArrayList<String>();
|
||||
queryParam.add(mAccount.getInboxFolderName());
|
||||
|
||||
);
|
||||
} else if (displayMode == Account.FolderMode.FIRST_CLASS) {
|
||||
cursor = db.rawQuery(baseQuery + " AND ( name = ? OR display_class = ?)", new String[] {
|
||||
mAccount.getTrashFolderName() != null ? mAccount.getTrashFolderName() : "" ,
|
||||
mAccount.getDraftsFolderName() != null ? mAccount.getDraftsFolderName() : "",
|
||||
mAccount.getSpamFolderName() != null ? mAccount.getSpamFolderName() : "",
|
||||
mAccount.getOutboxFolderName() != null ? mAccount.getOutboxFolderName() : "",
|
||||
mAccount.getSentFolderName() != null ? mAccount.getSentFolderName() : "",
|
||||
K9.INBOX, Folder.FolderClass.FIRST_CLASS.name()
|
||||
});
|
||||
queryParam.add((mAccount.getTrashFolderName() != null) ?
|
||||
mAccount.getTrashFolderName() : "");
|
||||
queryParam.add((mAccount.getDraftsFolderName() != null) ?
|
||||
mAccount.getDraftsFolderName() : "");
|
||||
queryParam.add((mAccount.getSpamFolderName() != null) ?
|
||||
mAccount.getSpamFolderName() : "");
|
||||
queryParam.add((mAccount.getOutboxFolderName() != null) ?
|
||||
mAccount.getOutboxFolderName() : "");
|
||||
queryParam.add((mAccount.getSentFolderName() != null) ?
|
||||
mAccount.getSentFolderName() : "");
|
||||
|
||||
|
||||
} else if (displayMode == Account.FolderMode.FIRST_AND_SECOND_CLASS) {
|
||||
cursor = db.rawQuery(baseQuery + " AND ( name = ? OR display_class = ? OR display_class = ? )", new String[] {
|
||||
mAccount.getTrashFolderName() != null ? mAccount.getTrashFolderName() : "" ,
|
||||
mAccount.getDraftsFolderName() != null ? mAccount.getDraftsFolderName() : "",
|
||||
mAccount.getSpamFolderName() != null ? mAccount.getSpamFolderName() : "",
|
||||
mAccount.getOutboxFolderName() != null ? mAccount.getOutboxFolderName() : "",
|
||||
mAccount.getSentFolderName() != null ? mAccount.getSentFolderName() : "",
|
||||
K9.INBOX, Folder.FolderClass.FIRST_CLASS.name(), Folder.FolderClass.SECOND_CLASS.name()
|
||||
});
|
||||
} else if (displayMode == Account.FolderMode.NOT_SECOND_CLASS) {
|
||||
cursor = db.rawQuery(baseQuery + " AND ( name = ? OR display_class != ?)", new String[] {
|
||||
|
||||
mAccount.getTrashFolderName() != null ? mAccount.getTrashFolderName() : "" ,
|
||||
mAccount.getDraftsFolderName() != null ? mAccount.getDraftsFolderName() : "",
|
||||
mAccount.getSpamFolderName() != null ? mAccount.getSpamFolderName() : "",
|
||||
mAccount.getOutboxFolderName() != null ? mAccount.getOutboxFolderName() : "",
|
||||
mAccount.getSentFolderName() != null ? mAccount.getSentFolderName() : "",
|
||||
K9.INBOX, Folder.FolderClass.SECOND_CLASS.name()
|
||||
});
|
||||
} else if (displayMode == Account.FolderMode.ALL) {
|
||||
cursor = db.rawQuery(baseQuery, new String[] {
|
||||
|
||||
mAccount.getTrashFolderName() != null ? mAccount.getTrashFolderName() : "" ,
|
||||
mAccount.getDraftsFolderName() != null ? mAccount.getDraftsFolderName() : "",
|
||||
mAccount.getSpamFolderName() != null ? mAccount.getSpamFolderName() : "",
|
||||
mAccount.getOutboxFolderName() != null ? mAccount.getOutboxFolderName() : "",
|
||||
mAccount.getSentFolderName() != null ? mAccount.getSentFolderName() : "",
|
||||
});
|
||||
} else {
|
||||
final String extraWhere;
|
||||
switch (displayMode) {
|
||||
case FIRST_CLASS:
|
||||
// Count messages in the INBOX and non-special first class folders
|
||||
extraWhere = " AND (display_class = ?)";
|
||||
queryParam.add(Folder.FolderClass.FIRST_CLASS.name());
|
||||
break;
|
||||
case FIRST_AND_SECOND_CLASS:
|
||||
// Count messages in the INBOX and non-special first and second class folders
|
||||
extraWhere = " AND (display_class IN (?, ?))";
|
||||
queryParam.add(Folder.FolderClass.FIRST_CLASS.name());
|
||||
queryParam.add(Folder.FolderClass.SECOND_CLASS.name());
|
||||
break;
|
||||
case NOT_SECOND_CLASS:
|
||||
// Count messages in the INBOX and non-special non-second-class folders
|
||||
extraWhere = " AND (display_class != ?)";
|
||||
queryParam.add(Folder.FolderClass.SECOND_CLASS.name());
|
||||
break;
|
||||
case ALL:
|
||||
// Count messages in the INBOX and non-special folders
|
||||
extraWhere = "";
|
||||
break;
|
||||
default:
|
||||
Log.e(K9.LOG_TAG, "asked to compute account statistics for an impossible folder mode " + displayMode);
|
||||
stats.unreadMessageCount = 0;
|
||||
stats.flaggedMessageCount = 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
String query = String.format(Locale.US, baseQuery, extraWhere);
|
||||
cursor = db.rawQuery(query, queryParam.toArray(EMPTY_STRING_ARRAY));
|
||||
|
||||
cursor.moveToFirst();
|
||||
stats.unreadMessageCount = cursor.getInt(0);
|
||||
stats.flaggedMessageCount = cursor.getInt(1);
|
||||
@ -1047,14 +1039,14 @@ public class LocalStore extends Store implements Serializable {
|
||||
if (mAccount.isSpecialFolder(name)) {
|
||||
prefHolder.inTopGroup = true;
|
||||
prefHolder.displayClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
if (name.equalsIgnoreCase(K9.INBOX)) {
|
||||
if (name.equalsIgnoreCase(mAccount.getInboxFolderName())) {
|
||||
prefHolder.integrate = true;
|
||||
prefHolder.pushClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
} else {
|
||||
prefHolder.pushClass = LocalFolder.FolderClass.INHERITED;
|
||||
|
||||
}
|
||||
if (name.equalsIgnoreCase(K9.INBOX) ||
|
||||
if (name.equalsIgnoreCase(mAccount.getInboxFolderName()) ||
|
||||
name.equalsIgnoreCase(mAccount.getDraftsFolderName())) {
|
||||
prefHolder.syncClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
} else {
|
||||
@ -1104,7 +1096,8 @@ public class LocalStore extends Store implements Serializable {
|
||||
super(LocalStore.this.mAccount);
|
||||
this.mName = name;
|
||||
|
||||
if (K9.INBOX.equals(getName())) {
|
||||
if (LocalStore.this.mAccount.getInboxFolderName().equals(getName())) {
|
||||
|
||||
mSyncClass = FolderClass.FIRST_CLASS;
|
||||
mPushClass = FolderClass.FIRST_CLASS;
|
||||
mInTopGroup = true;
|
||||
@ -1271,7 +1264,7 @@ public class LocalStore extends Store implements Serializable {
|
||||
}
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.rawQuery("SELECT COUNT(*) FROM messages WHERE folder_id = ?",
|
||||
cursor = db.rawQuery("SELECT COUNT(*) FROM messages WHERE deleted = 0 and folder_id = ?",
|
||||
new String[] {
|
||||
Long.toString(mFolderId)
|
||||
});
|
||||
@ -1484,19 +1477,19 @@ public class LocalStore extends Store implements Serializable {
|
||||
String id = getPrefId();
|
||||
|
||||
// there can be a lot of folders. For the defaults, let's not save prefs, saving space, except for INBOX
|
||||
if (mDisplayClass == FolderClass.NO_CLASS && !K9.INBOX.equals(getName())) {
|
||||
if (mDisplayClass == FolderClass.NO_CLASS && !mAccount.getInboxFolderName().equals(getName())) {
|
||||
editor.remove(id + ".displayMode");
|
||||
} else {
|
||||
editor.putString(id + ".displayMode", mDisplayClass.name());
|
||||
}
|
||||
|
||||
if (mSyncClass == FolderClass.INHERITED && !K9.INBOX.equals(getName())) {
|
||||
if (mSyncClass == FolderClass.INHERITED && !mAccount.getInboxFolderName().equals(getName())) {
|
||||
editor.remove(id + ".syncMode");
|
||||
} else {
|
||||
editor.putString(id + ".syncMode", mSyncClass.name());
|
||||
}
|
||||
|
||||
if (mPushClass == FolderClass.SECOND_CLASS && !K9.INBOX.equals(getName())) {
|
||||
if (mPushClass == FolderClass.SECOND_CLASS && !mAccount.getInboxFolderName().equals(getName())) {
|
||||
editor.remove(id + ".pushMode");
|
||||
} else {
|
||||
editor.putString(id + ".pushMode", mPushClass.name());
|
||||
@ -1674,20 +1667,22 @@ public class LocalStore extends Store implements Serializable {
|
||||
body = new LocalAttachmentBody(Uri.parse(contentUri), mApplication);
|
||||
}
|
||||
|
||||
String encoded_name = EncoderUtil.encodeIfNecessary(name,
|
||||
EncoderUtil.Usage.WORD_ENTITY, 7);
|
||||
|
||||
MimeBodyPart bp = new LocalAttachmentBodyPart(body, id);
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
|
||||
String.format("%s;\n name=\"%s\"",
|
||||
type,
|
||||
encoded_name));
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
|
||||
String.format("%s;\n filename=\"%s\";\n size=%d",
|
||||
contentDisposition,
|
||||
encoded_name, // TODO: Should use encoded word defined in RFC 2231.
|
||||
size));
|
||||
if (name != null) {
|
||||
String encoded_name = EncoderUtil.encodeIfNecessary(name,
|
||||
EncoderUtil.Usage.WORD_ENTITY, 7);
|
||||
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
|
||||
String.format("%s;\n name=\"%s\"",
|
||||
type,
|
||||
encoded_name));
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
|
||||
String.format("%s;\n filename=\"%s\";\n size=%d",
|
||||
contentDisposition,
|
||||
encoded_name, // TODO: Should use encoded word defined in RFC 2231.
|
||||
size));
|
||||
}
|
||||
|
||||
bp.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
|
||||
/*
|
||||
@ -2076,6 +2071,15 @@ public class LocalStore extends Store implements Serializable {
|
||||
for (Part viewable : viewables) {
|
||||
try {
|
||||
String text = MimeUtility.getTextFromPart(viewable);
|
||||
|
||||
/*
|
||||
* Small hack to make sure the string "null" doesn't end up
|
||||
* in one of the StringBuffers.
|
||||
*/
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything with MIME type text/html will be stored as such. Anything
|
||||
* else will be stored as text/plain.
|
||||
@ -2181,6 +2185,15 @@ public class LocalStore extends Store implements Serializable {
|
||||
Part viewable = viewables.get(i);
|
||||
try {
|
||||
String text = MimeUtility.getTextFromPart(viewable);
|
||||
|
||||
/*
|
||||
* Small hack to make sure the string "null" doesn't end up
|
||||
* in one of the StringBuffers.
|
||||
*/
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything with MIME type text/html will be stored as such. Anything
|
||||
* else will be stored as text/plain.
|
||||
@ -2427,16 +2440,18 @@ public class LocalStore extends Store implements Serializable {
|
||||
{ Long.toString(messageId) }, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
String new_html;
|
||||
String htmlContent = cursor.getString(0);
|
||||
|
||||
new_html = cursor.getString(0);
|
||||
new_html = new_html.replaceAll(Pattern.quote("cid:" + contentId),
|
||||
contentUri.toString());
|
||||
if (htmlContent != null) {
|
||||
String newHtmlContent = htmlContent.replaceAll(
|
||||
Pattern.quote("cid:" + contentId),
|
||||
contentUri.toString());
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("html_content", new_html);
|
||||
db.update("messages", cv, "id = ?", new String[]
|
||||
{ Long.toString(messageId) });
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("html_content", newHtmlContent);
|
||||
db.update("messages", cv, "id = ?", new String[]
|
||||
{ Long.toString(messageId) });
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
@ -2552,6 +2567,7 @@ public class LocalStore extends Store implements Serializable {
|
||||
setPushState(null);
|
||||
setLastPush(0);
|
||||
setLastChecked(0);
|
||||
setVisibleLimit(mAccount.getDisplayCount());
|
||||
}
|
||||
|
||||
private void resetUnreadAndFlaggedCounts() {
|
||||
@ -2707,19 +2723,26 @@ public class LocalStore extends Store implements Serializable {
|
||||
text = text.substring(0, 8192);
|
||||
}
|
||||
|
||||
|
||||
// try to remove lines of dashes in the preview
|
||||
text = text.replaceAll("(?m)^----.*?$", "");
|
||||
// remove quoted text from the preview
|
||||
text = text.replaceAll("(?m)^[#>].*$", "");
|
||||
// Remove a common quote header from the preview
|
||||
text = text.replaceAll("(?m)^On .*wrote.?$", "");
|
||||
// Remove a more generic quote header from the preview
|
||||
text = text.replaceAll("(?m)^.*\\w+:$", "");
|
||||
|
||||
// URLs in the preview should just be shown as "..." - They're not
|
||||
// clickable and they usually overwhelm the preview
|
||||
text = text.replaceAll("https?://\\S+", "...");
|
||||
// Don't show newlines in the preview
|
||||
text = text.replaceAll("(\\r|\\n)+", " ");
|
||||
// Collapse whitespace in the preview
|
||||
text = text.replaceAll("\\s+", " ");
|
||||
if (text.length() <= 512) {
|
||||
return text;
|
||||
} else {
|
||||
text = text.substring(0, 512);
|
||||
return text;
|
||||
return text.substring(0, 512);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,13 @@ public class Pop3Store extends Store {
|
||||
private HashMap<String, Folder> mFolders = new HashMap<String, Folder>();
|
||||
private Pop3Capabilities mCapabilities;
|
||||
|
||||
/**
|
||||
* This value is {@code true} if the server supports the CAPA command but doesn't advertise
|
||||
* support for the TOP command OR if the server doesn't support the CAPA command and we
|
||||
* already unsuccessfully tried to use the TOP command.
|
||||
*/
|
||||
private boolean mTopNotSupported;
|
||||
|
||||
/**
|
||||
* pop3://user:password@server:port CONNECTION_SECURITY_NONE
|
||||
* pop3+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL
|
||||
@ -91,11 +98,10 @@ public class Pop3Store extends Store {
|
||||
try {
|
||||
int userIndex = 0, passwordIndex = 1;
|
||||
String[] userInfoParts = uri.getUserInfo().split(":");
|
||||
if (userInfoParts.length > 2)
|
||||
{
|
||||
userIndex++;
|
||||
passwordIndex++;
|
||||
useCramMd5 = true;
|
||||
if (userInfoParts.length > 2) {
|
||||
userIndex++;
|
||||
passwordIndex++;
|
||||
useCramMd5 = true;
|
||||
}
|
||||
mUsername = URLDecoder.decode(userInfoParts[userIndex], "UTF-8");
|
||||
if (userInfoParts.length > passwordIndex) {
|
||||
@ -121,13 +127,13 @@ public class Pop3Store extends Store {
|
||||
@Override
|
||||
public List <? extends Folder > getPersonalNamespaces(boolean forceListAll) throws MessagingException {
|
||||
List<Folder> folders = new LinkedList<Folder>();
|
||||
folders.add(getFolder("INBOX"));
|
||||
folders.add(getFolder(mAccount.getInboxFolderName()));
|
||||
return folders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSettings() throws MessagingException {
|
||||
Pop3Folder folder = new Pop3Folder("INBOX");
|
||||
Pop3Folder folder = new Pop3Folder(mAccount.getInboxFolderName());
|
||||
folder.open(OpenMode.READ_WRITE);
|
||||
if (!mCapabilities.uidl) {
|
||||
/*
|
||||
@ -158,8 +164,9 @@ public class Pop3Store extends Store {
|
||||
public Pop3Folder(String name) {
|
||||
super(Pop3Store.this.mAccount);
|
||||
this.mName = name;
|
||||
if (mName.equalsIgnoreCase("INBOX")) {
|
||||
mName = "INBOX";
|
||||
|
||||
if (mName.equalsIgnoreCase(mAccount.getInboxFolderName())) {
|
||||
mName = mAccount.getInboxFolderName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +176,7 @@ public class Pop3Store extends Store {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mName.equalsIgnoreCase("INBOX")) {
|
||||
if (!mName.equalsIgnoreCase(mAccount.getInboxFolderName())) {
|
||||
throw new MessagingException("Folder does not exist");
|
||||
}
|
||||
|
||||
@ -224,8 +231,7 @@ public class Pop3Store extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
if (useCramMd5)
|
||||
{
|
||||
if (useCramMd5) {
|
||||
try {
|
||||
String b64Nonce = executeSimpleCommand("AUTH CRAM-MD5").replace("+ ", "");
|
||||
|
||||
@ -235,9 +241,7 @@ public class Pop3Store extends Store {
|
||||
} catch (MessagingException me) {
|
||||
throw new AuthenticationFailedException(null, me);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
try {
|
||||
executeSimpleCommand("USER " + mUsername);
|
||||
executeSimpleCommand("PASS " + mPassword, true);
|
||||
@ -279,7 +283,9 @@ public class Pop3Store extends Store {
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
executeSimpleCommand("QUIT");
|
||||
if (isOpen()) {
|
||||
executeSimpleCommand("QUIT");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* QUIT may fail if the connection is already closed. We don't care. It's just
|
||||
@ -329,7 +335,7 @@ public class Pop3Store extends Store {
|
||||
|
||||
@Override
|
||||
public boolean exists() throws MessagingException {
|
||||
return mName.equalsIgnoreCase("INBOX");
|
||||
return mName.equalsIgnoreCase(mAccount.getInboxFolderName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -659,41 +665,67 @@ public class Pop3Store extends Store {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the body of the given message, limiting the stored data
|
||||
* to the specified number of lines. If lines is -1 the entire message
|
||||
* is fetched. This is implemented with RETR for lines = -1 or TOP
|
||||
* for any other value. If the server does not support TOP it is
|
||||
* emulated with RETR and extra lines are thrown away.
|
||||
* @param message
|
||||
* @param lines
|
||||
* Fetches the body of the given message, limiting the downloaded data to the specified
|
||||
* number of lines if possible.
|
||||
*
|
||||
* If lines is -1 the entire message is fetched. This is implemented with RETR for
|
||||
* lines = -1 or TOP for any other value. If the server does not support TOP, RETR is used
|
||||
* instead.
|
||||
*/
|
||||
private void fetchBody(Pop3Message message, int lines)
|
||||
throws IOException, MessagingException {
|
||||
String response = null;
|
||||
if (lines == -1 || !mCapabilities.top) {
|
||||
|
||||
// Try hard to use the TOP command if we're not asked to download the whole message.
|
||||
if (lines != -1 && (!mTopNotSupported || mCapabilities.top)) {
|
||||
try {
|
||||
if (K9.DEBUG && K9.DEBUG_PROTOCOL_POP3 && !mCapabilities.top) {
|
||||
Log.d(K9.LOG_TAG, "This server doesn't support the CAPA command. " +
|
||||
"Checking to see if the TOP command is supported nevertheless.");
|
||||
}
|
||||
|
||||
response = executeSimpleCommand(String.format("TOP %d %d",
|
||||
mUidToMsgNumMap.get(message.getUid()), lines));
|
||||
|
||||
// TOP command is supported. Remember this for the next time.
|
||||
mCapabilities.top = true;
|
||||
} catch (Pop3ErrorResponse e) {
|
||||
if (mCapabilities.top) {
|
||||
// The TOP command should be supported but something went wrong.
|
||||
throw e;
|
||||
} else {
|
||||
if (K9.DEBUG && K9.DEBUG_PROTOCOL_POP3) {
|
||||
Log.d(K9.LOG_TAG, "The server really doesn't support the TOP " +
|
||||
"command. Using RETR instead.");
|
||||
}
|
||||
|
||||
// Don't try to use the TOP command again.
|
||||
mTopNotSupported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
response = executeSimpleCommand(String.format("RETR %d",
|
||||
mUidToMsgNumMap.get(message.getUid())));
|
||||
} else {
|
||||
response = executeSimpleCommand(String.format("TOP %d %d",
|
||||
mUidToMsgNumMap.get(message.getUid()),
|
||||
lines));
|
||||
}
|
||||
if (response != null) {
|
||||
try {
|
||||
message.parse(new Pop3ResponseInputStream(mIn));
|
||||
if (lines == -1 || !mCapabilities.top) {
|
||||
message.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
/*
|
||||
* If we're only downloading headers it's possible
|
||||
* we'll get a broken MIME message which we're not
|
||||
* real worried about. If we've downloaded the body
|
||||
* and can't parse it we need to let the user know.
|
||||
*/
|
||||
if (lines == -1) {
|
||||
throw me;
|
||||
}
|
||||
|
||||
try {
|
||||
message.parse(new Pop3ResponseInputStream(mIn));
|
||||
|
||||
// TODO: if we've received fewer lines than requested we also have the complete message.
|
||||
if (lines == -1 || !mCapabilities.top) {
|
||||
message.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
/*
|
||||
* If we're only downloading headers it's possible
|
||||
* we'll get a broken MIME message which we're not
|
||||
* real worried about. If we've downloaded the body
|
||||
* and can't parse it we need to let the user know.
|
||||
*/
|
||||
if (lines == -1) {
|
||||
throw me;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -722,10 +754,8 @@ public class Pop3Store extends Store {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
Message[] messages = getMessages(null);
|
||||
setFlags(messages, flags, value);
|
||||
public void setFlags(Flag[] flags, boolean value) throws MessagingException {
|
||||
throw new UnsupportedOperationException("POP3: No setFlags(Flag[],boolean)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -809,6 +839,14 @@ public class Pop3Store extends Store {
|
||||
capabilities.top = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!capabilities.top) {
|
||||
/*
|
||||
* If the CAPA command is supported but it doesn't advertise support for the
|
||||
* TOP command, we won't check for it manually.
|
||||
*/
|
||||
mTopNotSupported = true;
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
/*
|
||||
* The server may not support the CAPA command, so we just eat this Exception
|
||||
@ -841,7 +879,7 @@ public class Pop3Store extends Store {
|
||||
|
||||
String response = readLine();
|
||||
if (response.length() > 1 && response.charAt(0) == '-') {
|
||||
throw new MessagingException(response);
|
||||
throw new Pop3ErrorResponse(response);
|
||||
}
|
||||
|
||||
return response;
|
||||
@ -853,6 +891,11 @@ public class Pop3Store extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlagSupported(Flag flag) {
|
||||
return (flag == Flag.DELETED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFetchingFlags() {
|
||||
return false;
|
||||
@ -956,4 +999,13 @@ public class Pop3Store extends Store {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception that is thrown if the server returns an error response.
|
||||
*/
|
||||
static class Pop3ErrorResponse extends MessagingException {
|
||||
public Pop3ErrorResponse(String message) {
|
||||
super(message, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.controller.MessageRetrievalListener;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.*;
|
||||
@ -51,6 +50,7 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Stack;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
@ -79,8 +79,15 @@ public class WebDavStore extends Store {
|
||||
|
||||
private static final Message[] EMPTY_MESSAGE_ARRAY = new Message[0];
|
||||
|
||||
// These are the ids used from Exchange server to identify the special folders
|
||||
// http://social.technet.microsoft.com/Forums/en/exchangesvrdevelopment/thread/1cd2e98c-8a12-44bd-a3e3-9c5ee9e4e14d
|
||||
private static final String DAV_MAIL_INBOX_FOLDER = "inbox";
|
||||
private static final String DAV_MAIL_DRAFTS_FOLDER = "drafts";
|
||||
private static final String DAV_MAIL_SPAM_FOLDER = "junkemail";
|
||||
private static final String DAV_MAIL_SEND_FOLDER = "##DavMailSubmissionURI##";
|
||||
private static final String DAV_MAIL_TMP_FOLDER = "drafts";
|
||||
private static final String DAV_MAIL_TRASH_FOLDER = "deleteditems";
|
||||
private static final String DAV_MAIL_OUTBOX_FOLDER = "outbox";
|
||||
private static final String DAV_MAIL_SENT_FOLDER = "sentitems";
|
||||
|
||||
private short mConnectionSecurity;
|
||||
private String mUsername; /* Stores the username for authentications */
|
||||
@ -101,6 +108,7 @@ public class WebDavStore extends Store {
|
||||
private short mAuthentication = AUTH_TYPE_NONE;
|
||||
private String mCachedLoginUrl;
|
||||
|
||||
private Folder mSendFolder = null;
|
||||
private HashMap<String, WebDavFolder> mFolderList = new HashMap<String, WebDavFolder>();
|
||||
|
||||
/**
|
||||
@ -231,63 +239,136 @@ public class WebDavStore extends Store {
|
||||
@Override
|
||||
public List <? extends Folder > getPersonalNamespaces(boolean forceListAll) throws MessagingException {
|
||||
LinkedList<Folder> folderList = new LinkedList<Folder>();
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
DataSet dataset = new DataSet();
|
||||
String messageBody;
|
||||
String[] folderUrls;
|
||||
int urlLength;
|
||||
|
||||
String translatedInbox = K9.app.getString(R.string.special_mailbox_name_inbox);
|
||||
|
||||
/**
|
||||
* We have to check authentication here so we have the proper URL stored
|
||||
*/
|
||||
getHttpClient();
|
||||
messageBody = getFolderListXml();
|
||||
|
||||
/**
|
||||
* Firstly we get the "special" folders list (inbox, outbox, etc)
|
||||
* and setup the account accordingly
|
||||
*/
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
DataSet dataset = new DataSet();
|
||||
headers.put("Depth", "0");
|
||||
headers.put("Brief", "t");
|
||||
dataset = processRequest(this.mUrl, "SEARCH", messageBody, headers);
|
||||
dataset = processRequest(this.mUrl, "PROPFIND", getSpecialFoldersList(), headers);
|
||||
|
||||
folderUrls = dataset.getHrefs();
|
||||
urlLength = folderUrls.length;
|
||||
HashMap<String, String> specialFoldersMap = dataset.getSpecialFolderToUrl();
|
||||
String folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_INBOX_FOLDER));
|
||||
if (folderName != null) {
|
||||
mAccount.setAutoExpandFolderName(folderName);
|
||||
mAccount.setInboxFolderName(folderName);
|
||||
}
|
||||
|
||||
for (int i = 0; i < urlLength; i++) {
|
||||
String[] urlParts = folderUrls[i].split("/");
|
||||
String folderName = urlParts[urlParts.length - 1];
|
||||
String fullPathName = "";
|
||||
WebDavFolder wdFolder;
|
||||
folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_DRAFTS_FOLDER));
|
||||
if (folderName != null)
|
||||
mAccount.setDraftsFolderName(folderName);
|
||||
|
||||
// Check each Exchange folder name to see if it is the user's inbox.
|
||||
// We will check for the default English inbox ("Inbox"), and the user's
|
||||
// translation for "Inbox", in case the user is using a non-English
|
||||
// version of Exchange.
|
||||
if (folderName.equalsIgnoreCase("Inbox") ||
|
||||
folderName.equalsIgnoreCase(translatedInbox)) {
|
||||
folderName = K9.INBOX;
|
||||
} else {
|
||||
for (int j = 5, count = urlParts.length; j < count; j++) {
|
||||
if (j != 5) {
|
||||
fullPathName = fullPathName + "/" + urlParts[j];
|
||||
} else {
|
||||
fullPathName = urlParts[j];
|
||||
}
|
||||
}
|
||||
try {
|
||||
folderName = java.net.URLDecoder.decode(fullPathName, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
/** If we don't support UTF-8 there's a problem, don't decode it then */
|
||||
folderName = fullPathName;
|
||||
}
|
||||
}
|
||||
folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_TRASH_FOLDER));
|
||||
if (folderName != null)
|
||||
mAccount.setTrashFolderName(folderName);
|
||||
|
||||
wdFolder = new WebDavFolder(this, folderName);
|
||||
wdFolder.setUrl(folderUrls[i]);
|
||||
folderList.add(wdFolder);
|
||||
this.mFolderList.put(folderName, wdFolder);
|
||||
folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_SPAM_FOLDER));
|
||||
if (folderName != null)
|
||||
mAccount.setSpamFolderName(folderName);
|
||||
|
||||
// K-9 Mail's outbox is a special local folder and different from Exchange/WebDAV's outbox.
|
||||
/*
|
||||
folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_OUTBOX_FOLDER));
|
||||
if (folderName != null)
|
||||
mAccount.setOutboxFolderName(folderName);
|
||||
*/
|
||||
|
||||
folderName = getFolderName(specialFoldersMap.get(DAV_MAIL_SENT_FOLDER));
|
||||
if (folderName != null)
|
||||
mAccount.setSentFolderName(folderName);
|
||||
|
||||
/**
|
||||
* Next we get all the folders (including "special" ones)
|
||||
*/
|
||||
headers = new HashMap<String, String>();
|
||||
dataset = new DataSet();
|
||||
headers.put("Brief", "t");
|
||||
dataset = processRequest(this.mUrl, "SEARCH", getFolderListXml(), headers);
|
||||
String[] folderUrls = dataset.getHrefs();
|
||||
|
||||
for (int i = 0; i < folderUrls.length; i++) {
|
||||
String tempUrl = folderUrls[i];
|
||||
WebDavFolder folder = createFolder(tempUrl);
|
||||
if (folder != null)
|
||||
folderList.add(folder);
|
||||
}
|
||||
|
||||
return folderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a folder using the URL passed as parameter (only if it has not been
|
||||
* already created) and adds this to our store folder map.
|
||||
*
|
||||
* @param folderUrl
|
||||
* @return
|
||||
*/
|
||||
private WebDavFolder createFolder(String folderUrl) {
|
||||
if (folderUrl == null)
|
||||
return null;
|
||||
|
||||
WebDavFolder wdFolder = null;
|
||||
String folderName = getFolderName(folderUrl);
|
||||
if (folderName != null) {
|
||||
if (!this.mFolderList.containsKey(folderName)) {
|
||||
wdFolder = new WebDavFolder(this, folderName);
|
||||
wdFolder.setUrl(folderUrl);
|
||||
mFolderList.put(folderName, wdFolder);
|
||||
}
|
||||
}
|
||||
// else: Unknown URL format => NO Folder created
|
||||
|
||||
return wdFolder;
|
||||
}
|
||||
|
||||
private String getFolderName(String folderUrl) {
|
||||
if (folderUrl == null)
|
||||
return null;
|
||||
|
||||
// Here we extract the folder name starting from the complete url.
|
||||
// folderUrl is in the form http://mail.domain.com/exchange/username/foldername
|
||||
// so we need "foldername" which is the string after the fifth slash
|
||||
int folderSlash = -1;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
folderSlash = folderUrl.indexOf('/', folderSlash + 1);
|
||||
if (folderSlash < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (folderSlash > 0) {
|
||||
String folderName;
|
||||
String fullPathName;
|
||||
|
||||
// Removes the final slash if present
|
||||
if (folderUrl.charAt(folderUrl.length() - 1) == '/')
|
||||
fullPathName = folderUrl.substring(folderSlash + 1, folderUrl.length() - 1);
|
||||
else
|
||||
fullPathName = folderUrl.substring(folderSlash + 1);
|
||||
|
||||
// Decodes the url-encoded folder name (i.e. "My%20folder" => "My Folder"
|
||||
try {
|
||||
folderName = java.net.URLDecoder.decode(fullPathName, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
/**
|
||||
* If we don't support UTF-8 there's a problem, don't decode
|
||||
* it then
|
||||
*/
|
||||
folderName = fullPathName;
|
||||
}
|
||||
|
||||
return folderName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Folder getFolder(String name) {
|
||||
WebDavFolder folder;
|
||||
@ -300,7 +381,10 @@ public class WebDavStore extends Store {
|
||||
}
|
||||
|
||||
public Folder getSendSpoolFolder() throws MessagingException {
|
||||
return getFolder(DAV_MAIL_SEND_FOLDER);
|
||||
if (mSendFolder == null)
|
||||
mSendFolder = getFolder(DAV_MAIL_SEND_FOLDER);
|
||||
|
||||
return mSendFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -313,6 +397,26 @@ public class WebDavStore extends Store {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getSpecialFoldersList() {
|
||||
StringBuffer buffer = new StringBuffer(200);
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>");
|
||||
buffer.append("<propfind xmlns=\"DAV:\">");
|
||||
buffer.append("<prop>");
|
||||
buffer.append("<").append(DAV_MAIL_INBOX_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
buffer.append("<").append(DAV_MAIL_DRAFTS_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
buffer.append("<").append(DAV_MAIL_OUTBOX_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
buffer.append("<").append(DAV_MAIL_SENT_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
buffer.append("<").append(DAV_MAIL_TRASH_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
// This should always be ##DavMailSubmissionURI## for which we already have a constant
|
||||
// buffer.append("<sendmsg xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
|
||||
buffer.append("<").append(DAV_MAIL_SPAM_FOLDER).append(" xmlns=\"urn:schemas:httpmail:\"/>");
|
||||
|
||||
buffer.append("</prop>");
|
||||
buffer.append("</propfind>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* WebDAV XML Request body retrieval functions
|
||||
*/
|
||||
@ -980,7 +1084,7 @@ public class WebDavStore extends Store {
|
||||
|
||||
@Override
|
||||
public void sendMessages(Message[] messages) throws MessagingException {
|
||||
WebDavFolder tmpFolder = (WebDavStore.WebDavFolder) getFolder(DAV_MAIL_TMP_FOLDER);
|
||||
WebDavFolder tmpFolder = (WebDavStore.WebDavFolder) getFolder(mAccount.getDraftsFolderName());
|
||||
try {
|
||||
tmpFolder.open(OpenMode.READ_WRITE);
|
||||
Message[] retMessages = tmpFolder.appendWebDavMessages(messages);
|
||||
@ -1017,37 +1121,30 @@ public class WebDavStore extends Store {
|
||||
store = nStore;
|
||||
this.mName = name;
|
||||
|
||||
if (DAV_MAIL_SEND_FOLDER.equals(name)) {
|
||||
this.mFolderUrl = getUrl() + "/" + name + "/";
|
||||
} else {
|
||||
String encodedName = "";
|
||||
try {
|
||||
String[] urlParts = name.split("/");
|
||||
String url = "";
|
||||
for (int i = 0, count = urlParts.length; i < count; i++) {
|
||||
if (i != 0) {
|
||||
url = url + "/" + java.net.URLEncoder.encode(urlParts[i], "UTF-8");
|
||||
} else {
|
||||
url = java.net.URLEncoder.encode(urlParts[i], "UTF-8");
|
||||
}
|
||||
String encodedName = "";
|
||||
try {
|
||||
String[] urlParts = name.split("/");
|
||||
String url = "";
|
||||
for (int i = 0, count = urlParts.length; i < count; i++) {
|
||||
if (i != 0) {
|
||||
url = url + "/" + java.net.URLEncoder.encode(urlParts[i], "UTF-8");
|
||||
} else {
|
||||
url = java.net.URLEncoder.encode(urlParts[i], "UTF-8");
|
||||
}
|
||||
encodedName = url;
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
Log.e(K9.LOG_TAG, "UnsupportedEncodingException URLEncoding folder name, skipping encoded");
|
||||
encodedName = name;
|
||||
}
|
||||
|
||||
encodedName = encodedName.replaceAll("\\+", "%20");
|
||||
|
||||
if (encodedName.equals(K9.INBOX)) {
|
||||
encodedName = "Inbox";
|
||||
}
|
||||
this.mFolderUrl = WebDavStore.this.mUrl;
|
||||
if (!WebDavStore.this.mUrl.endsWith("/")) {
|
||||
this.mFolderUrl += "/";
|
||||
}
|
||||
this.mFolderUrl += encodedName;
|
||||
encodedName = url;
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
Log.e(K9.LOG_TAG, "UnsupportedEncodingException URLEncoding folder name, skipping encoded");
|
||||
encodedName = name;
|
||||
}
|
||||
|
||||
encodedName = encodedName.replaceAll("\\+", "%20");
|
||||
|
||||
this.mFolderUrl = WebDavStore.this.mUrl;
|
||||
if (!WebDavStore.this.mUrl.endsWith("/")) {
|
||||
this.mFolderUrl += "/";
|
||||
}
|
||||
this.mFolderUrl += encodedName;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
@ -1977,6 +2074,17 @@ public class WebDavStore extends Store {
|
||||
mTempData = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashmap of special folder name => special folder url
|
||||
*/
|
||||
public HashMap<String, String> getSpecialFolderToUrl() {
|
||||
// We return the first (and only) map
|
||||
for (HashMap<String, String> folderMap : mData.values()) {
|
||||
return folderMap;
|
||||
}
|
||||
return new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashmap of Message UID => Message Url
|
||||
*/
|
||||
@ -2088,8 +2196,8 @@ public class WebDavStore extends Store {
|
||||
String date = data.get(header);
|
||||
date = date.substring(0, date.length() - 1);
|
||||
|
||||
DateFormat dfInput = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
||||
DateFormat dfOutput = new SimpleDateFormat("EEE, d MMM yy HH:mm:ss Z");
|
||||
DateFormat dfInput = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
|
||||
DateFormat dfOutput = new SimpleDateFormat("EEE, d MMM yy HH:mm:ss Z", Locale.US);
|
||||
String tempDate = "";
|
||||
|
||||
try {
|
||||
|
@ -39,6 +39,14 @@ public class SmtpTransport extends Transport {
|
||||
|
||||
public static final int CONNECTION_SECURITY_SSL_OPTIONAL = 4;
|
||||
|
||||
public static final String AUTH_PLAIN = "PLAIN";
|
||||
|
||||
public static final String AUTH_CRAM_MD5 = "CRAM_MD5";
|
||||
|
||||
public static final String AUTH_LOGIN = "LOGIN";
|
||||
|
||||
public static final String AUTH_AUTOMATIC = "AUTOMATIC";
|
||||
|
||||
String mHost;
|
||||
|
||||
int mPort;
|
||||
@ -163,7 +171,7 @@ public class SmtpTransport extends Transport {
|
||||
executeSimpleCommand(null);
|
||||
|
||||
InetAddress localAddress = mSocket.getLocalAddress();
|
||||
String localHost = localAddress.getHostName();
|
||||
String localHost = localAddress.getCanonicalHostName();
|
||||
String ipAddr = localAddress.getHostAddress();
|
||||
|
||||
if (localHost.equals("") || localHost.equals(ipAddr) || localHost.contains("_")) {
|
||||
@ -221,9 +229,13 @@ public class SmtpTransport extends Transport {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* result contains the results of the EHLO in concatenated form
|
||||
*/
|
||||
boolean useAuthLogin = AUTH_LOGIN.equals(mAuthType);
|
||||
boolean useAuthPlain = AUTH_PLAIN.equals(mAuthType);
|
||||
boolean useAuthCramMD5 = AUTH_CRAM_MD5.equals(mAuthType);
|
||||
|
||||
// Automatically choose best authentication method if none was explicitly selected
|
||||
boolean useAutomaticAuth = !(useAuthLogin || useAuthPlain || useAuthCramMD5);
|
||||
|
||||
boolean authLoginSupported = false;
|
||||
boolean authPlainSupported = false;
|
||||
boolean authCramMD5Supported = false;
|
||||
@ -234,7 +246,7 @@ public class SmtpTransport extends Transport {
|
||||
if (result.matches(".*AUTH.*PLAIN.*$")) {
|
||||
authPlainSupported = true;
|
||||
}
|
||||
if (result.matches(".*AUTH.*CRAM-MD5.*$") && mAuthType != null && mAuthType.equals("CRAM_MD5")) {
|
||||
if (result.matches(".*AUTH.*CRAM-MD5.*$")) {
|
||||
authCramMD5Supported = true;
|
||||
}
|
||||
if (result.matches(".*SIZE \\d*$")) {
|
||||
@ -248,13 +260,40 @@ public class SmtpTransport extends Transport {
|
||||
}
|
||||
}
|
||||
|
||||
if (mUsername != null && mUsername.length() > 0 && mPassword != null
|
||||
&& mPassword.length() > 0) {
|
||||
if (authCramMD5Supported) {
|
||||
if (mUsername != null && mUsername.length() > 0 &&
|
||||
mPassword != null && mPassword.length() > 0) {
|
||||
if (useAuthCramMD5 || (useAutomaticAuth && authCramMD5Supported)) {
|
||||
if (!authCramMD5Supported && K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "Using CRAM_MD5 as authentication method although the " +
|
||||
"server didn't advertise support for it in EHLO response.");
|
||||
}
|
||||
saslAuthCramMD5(mUsername, mPassword);
|
||||
} else if (authPlainSupported) {
|
||||
saslAuthPlain(mUsername, mPassword);
|
||||
} else if (authLoginSupported) {
|
||||
} else if (useAuthPlain || (useAutomaticAuth && authPlainSupported)) {
|
||||
if (!authPlainSupported && K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "Using PLAIN as authentication method although the " +
|
||||
"server didn't advertise support for it in EHLO response.");
|
||||
}
|
||||
try {
|
||||
saslAuthPlain(mUsername, mPassword);
|
||||
} catch (MessagingException ex) {
|
||||
// PLAIN is a special case. Historically, PLAIN has represented both PLAIN and LOGIN; only the
|
||||
// protocol being advertised by the server would be used, with PLAIN taking precedence. Instead
|
||||
// of using only the requested protocol, we'll try PLAIN and then try LOGIN.
|
||||
if (useAuthPlain && authLoginSupported) {
|
||||
if (K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "Using legacy PLAIN authentication behavior and trying LOGIN.");
|
||||
}
|
||||
saslAuthLogin(mUsername, mPassword);
|
||||
} else {
|
||||
// If it was auto detected and failed, continue throwing the exception back up.
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} else if (useAuthLogin || (useAutomaticAuth && authLoginSupported)) {
|
||||
if (!authPlainSupported && K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "Using LOGIN as authentication method although the " +
|
||||
"server didn't advertise support for it in EHLO response.");
|
||||
}
|
||||
saslAuthLogin(mUsername, mPassword);
|
||||
} else {
|
||||
throw new MessagingException("No valid authentication mechanism found.");
|
||||
@ -313,11 +352,20 @@ public class SmtpTransport extends Transport {
|
||||
// If the message has attachments and our server has told us about a limit on
|
||||
// the size of messages, count the message's size before sending it
|
||||
if (mLargestAcceptableMessage > 0 && ((LocalMessage)message).hasAttachments()) {
|
||||
if (message.calculateSize() > mLargestAcceptableMessage) {
|
||||
if (K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "calculating message size");
|
||||
}
|
||||
close(); // (prevent timeouts while calculating the size)
|
||||
final long calculatedSize = message.calculateSize();
|
||||
if (calculatedSize > mLargestAcceptableMessage) {
|
||||
MessagingException me = new MessagingException("Message too large for server");
|
||||
me.setPermanentFailure(possibleSend);
|
||||
throw me;
|
||||
}
|
||||
open(); // (prevent timeouts while calculating the size)
|
||||
if (K9.DEBUG_PROTOCOL_SMTP) {
|
||||
Log.d(K9.LOG_TAG, "calculating message size DONE size=" + calculatedSize + " max allowed=" + mLargestAcceptableMessage);
|
||||
}
|
||||
}
|
||||
|
||||
Address[] from = message.getFrom();
|
||||
@ -344,6 +392,14 @@ public class SmtpTransport extends Transport {
|
||||
executeSimpleCommand("\r\n.");
|
||||
} catch (Exception e) {
|
||||
MessagingException me = new MessagingException("Unable to send message", e);
|
||||
|
||||
// "5xx text" -responses are permanent failures
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && msg.startsWith("5")) {
|
||||
Log.w(K9.LOG_TAG, "handling 5xx SMTP error code as a permanent failure");
|
||||
possibleSend = false;
|
||||
}
|
||||
|
||||
me.setPermanentFailure(possibleSend);
|
||||
throw me;
|
||||
} finally {
|
||||
@ -520,9 +576,9 @@ public class SmtpTransport extends Transport {
|
||||
private void saslAuthCramMD5(String username, String password) throws MessagingException,
|
||||
AuthenticationFailedException, IOException {
|
||||
|
||||
List<String> respList = executeSimpleCommand("AUTH CRAM-MD5");
|
||||
List<String> respList = executeSimpleCommand("AUTH CRAM-MD5");
|
||||
if (respList.size() != 1) {
|
||||
throw new AuthenticationFailedException("Unable to negotiate CRAM-MD5");
|
||||
throw new AuthenticationFailedException("Unable to negotiate CRAM-MD5");
|
||||
}
|
||||
|
||||
String b64Nonce = respList.get(0);
|
||||
|
@ -6,6 +6,7 @@ package com.fsck.k9.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.DialogPreference;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TimePicker;
|
||||
@ -25,12 +26,23 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
* The default value for this preference
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* Store the original value, in case the user
|
||||
* chooses to abort the {@link DialogPreference}
|
||||
* after making a change.
|
||||
*/
|
||||
private int originalHour = 0;
|
||||
/**
|
||||
* Store the original value, in case the user
|
||||
* chooses to abort the {@link DialogPreference}
|
||||
* after making a change.
|
||||
*/
|
||||
private int originalMinute = 0;
|
||||
/**
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public TimePickerPreference(Context context, AttributeSet attrs) {
|
||||
public TimePickerPreference(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
@ -40,8 +52,8 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
* @param attrs
|
||||
* @param defStyle
|
||||
*/
|
||||
public TimePickerPreference(Context context, AttributeSet attrs,
|
||||
int defStyle) {
|
||||
public TimePickerPreference(final Context context, final AttributeSet attrs,
|
||||
final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initialize();
|
||||
}
|
||||
@ -62,39 +74,49 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
protected View onCreateDialogView() {
|
||||
|
||||
TimePicker tp = new TimePicker(getContext());
|
||||
tp.setIs24HourView(DateFormat.is24HourFormat(getContext()));
|
||||
tp.setOnTimeChangedListener(this);
|
||||
|
||||
int h = getHour();
|
||||
int m = getMinute();
|
||||
if (h >= 0 && m >= 0) {
|
||||
tp.setCurrentHour(h);
|
||||
tp.setCurrentMinute(m);
|
||||
originalHour = getHour();
|
||||
originalMinute = getMinute();
|
||||
if (originalHour >= 0 && originalMinute >= 0) {
|
||||
tp.setCurrentHour(originalHour);
|
||||
tp.setCurrentMinute(originalMinute);
|
||||
}
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
/**
|
||||
* @see
|
||||
* android.widget.TimePicker.OnTimeChangedListener#onTimeChanged(android
|
||||
* .widget.TimePicker, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void onTimeChanged(TimePicker view, int hour, int minute) {
|
||||
public void onTimeChanged(final TimePicker view, final int hour, final int minute) {
|
||||
|
||||
persistString(String.format("%02d:%02d", hour, minute));
|
||||
callChangeListener(String.format("%02d:%02d", hour, minute));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
/**
|
||||
* If not a positive result, restore the original value
|
||||
* before going to super.onDialogClosed(positiveResult).
|
||||
*/
|
||||
@Override
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
|
||||
if (!positiveResult) {
|
||||
persistString(String.format("%02d:%02d", originalHour, originalMinute));
|
||||
callChangeListener(String.format("%02d:%02d", originalHour, originalMinute));
|
||||
}
|
||||
super.onDialogClosed(positiveResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.preference.Preference#setDefaultValue(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
public void setDefaultValue(final Object defaultValue) {
|
||||
// BUG this method is never called if you use the 'android:defaultValue' attribute in your XML preference file, not sure why it isn't
|
||||
|
||||
super.setDefaultValue(defaultValue);
|
||||
@ -113,10 +135,10 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
/**
|
||||
* Get the hour value (in 24 hour time)
|
||||
*
|
||||
* @return The hour value, will be 0 to 23 (inclusive)
|
||||
* @return The hour value, will be 0 to 23 (inclusive) or -1 if illegal
|
||||
*/
|
||||
private int getHour() {
|
||||
String time = getPersistedString(this.defaultValue);
|
||||
String time = getTime();
|
||||
if (time == null || !time.matches(VALIDATION_EXPRESSION)) {
|
||||
return -1;
|
||||
}
|
||||
@ -127,10 +149,10 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
/**
|
||||
* Get the minute value
|
||||
*
|
||||
* @return the minute value, will be 0 to 59 (inclusive)
|
||||
* @return the minute value, will be 0 to 59 (inclusive) or -1 if illegal
|
||||
*/
|
||||
private int getMinute() {
|
||||
String time = getPersistedString(this.defaultValue);
|
||||
String time = getTime();
|
||||
if (time == null || !time.matches(VALIDATION_EXPRESSION)) {
|
||||
return -1;
|
||||
}
|
||||
@ -138,6 +160,12 @@ public class TimePickerPreference extends DialogPreference implements
|
||||
return Integer.valueOf(time.split(":")[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time. It is only legal, if it matches
|
||||
* {@link #VALIDATION_EXPRESSION}.
|
||||
*
|
||||
* @return the time as hh:mm
|
||||
*/
|
||||
public String getTime() {
|
||||
return getPersistedString(this.defaultValue);
|
||||
}
|
||||
|
@ -72,7 +72,14 @@ public class AttachmentProvider extends ContentProvider {
|
||||
* We use the cache dir as a temporary directory (since Android doesn't give us one) so
|
||||
* on startup we'll clean up any .tmp files from the last run.
|
||||
*/
|
||||
File[] files = getContext().getCacheDir().listFiles();
|
||||
final File cacheDir = getContext().getCacheDir();
|
||||
if (cacheDir == null) {
|
||||
return true;
|
||||
}
|
||||
File[] files = cacheDir.listFiles();
|
||||
if (files == null) {
|
||||
return true;
|
||||
}
|
||||
for (File file : files) {
|
||||
if (file.getName().endsWith(".tmp")) {
|
||||
file.delete();
|
||||
|
@ -1,7 +1,16 @@
|
||||
package com.fsck.k9.view;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
@ -9,7 +18,12 @@ import android.os.Environment;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
@ -23,9 +37,6 @@ import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart;
|
||||
import com.fsck.k9.provider.AttachmentProvider;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class AttachmentView extends FrameLayout {
|
||||
|
||||
@ -42,6 +53,8 @@ public class AttachmentView extends FrameLayout {
|
||||
public long size;
|
||||
public ImageView iconView;
|
||||
|
||||
private AttachmentFileDownloadCallback callback;
|
||||
|
||||
public AttachmentView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mContext = context;
|
||||
@ -56,7 +69,18 @@ public class AttachmentView extends FrameLayout {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface AttachmentFileDownloadCallback {
|
||||
/**
|
||||
* this method i called by the attachmentview when
|
||||
* he wants to show a filebrowser
|
||||
* the provider should show the filebrowser activity
|
||||
* and save the reference to the attachment view for later.
|
||||
* in his onActivityResult he can get the saved reference and
|
||||
* call the saveFile method of AttachmentView
|
||||
* @param view
|
||||
*/
|
||||
public void showFileBrowser(AttachmentView caller);
|
||||
}
|
||||
public boolean populateFromPart(Part inputPart, Message message, Account account, MessagingController controller, MessagingListener listener) {
|
||||
try {
|
||||
part = (LocalAttachmentBodyPart) inputPart;
|
||||
@ -113,6 +137,14 @@ public class AttachmentView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
});
|
||||
downloadButton.setOnLongClickListener(new OnLongClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
callback.showFileBrowser(AttachmentView.this);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
attachmentName.setText(name);
|
||||
attachmentInfo.setText(SizeFormatter.formatSize(mContext, size));
|
||||
@ -158,9 +190,13 @@ public class AttachmentView extends FrameLayout {
|
||||
saveFile();
|
||||
}
|
||||
|
||||
public void writeFile() {
|
||||
/**
|
||||
* Writes the attachment onto the given path
|
||||
* @param directory: the base dir where the file should be saved.
|
||||
*/
|
||||
public void writeFile(File directory) {
|
||||
try {
|
||||
File file = Utility.createUniqueFile(Environment.getExternalStorageDirectory(), name);
|
||||
File file = Utility.createUniqueFile(directory, name);
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId());
|
||||
InputStream in = mContext.getContentResolver().openInputStream(uri);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
@ -168,14 +204,22 @@ public class AttachmentView extends FrameLayout {
|
||||
out.flush();
|
||||
out.close();
|
||||
in.close();
|
||||
attachmentSaved(file.getName());
|
||||
attachmentSaved(file.toString());
|
||||
new MediaScannerNotifier(mContext, file);
|
||||
} catch (IOException ioe) {
|
||||
attachmentNotSaved();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* saves the file to the defaultpath setting in the config, or if the config
|
||||
* is not set => to the Environment
|
||||
*/
|
||||
public void writeFile() {
|
||||
writeFile(new File(K9.getAttachmentDefaultPath()));
|
||||
}
|
||||
|
||||
public void saveFile() {
|
||||
//TODO: Can the user save attachments on the internal filesystem or sd card only?
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
/*
|
||||
* Abort early if there's no place to save the attachment. We don't want to spend
|
||||
@ -248,4 +292,11 @@ public class AttachmentView extends FrameLayout {
|
||||
mContext.getString(R.string.message_view_status_attachment_not_saved),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
public AttachmentFileDownloadCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
public void setCallback(AttachmentFileDownloadCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class SingleMessageView extends LinearLayout {
|
||||
private Button mDownloadRemainder;
|
||||
private LayoutInflater mInflater;
|
||||
private Contacts mContacts;
|
||||
|
||||
private AttachmentView.AttachmentFileDownloadCallback attachmentCallback;
|
||||
|
||||
public void initialize(Activity activity) {
|
||||
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
|
||||
@ -265,6 +265,7 @@ public class SingleMessageView extends LinearLayout {
|
||||
return;
|
||||
}
|
||||
AttachmentView view = (AttachmentView)mInflater.inflate(R.layout.message_view_attachment, null);
|
||||
view.setCallback(attachmentCallback);
|
||||
if (view.populateFromPart(part, message, account, controller, listener)) {
|
||||
addAttachment(view);
|
||||
}
|
||||
@ -299,4 +300,14 @@ public class SingleMessageView extends LinearLayout {
|
||||
mMessageContentView.clearView();
|
||||
mAttachments.removeAllViews();
|
||||
}
|
||||
|
||||
public AttachmentView.AttachmentFileDownloadCallback getAttachmentCallback() {
|
||||
return attachmentCallback;
|
||||
}
|
||||
|
||||
public void setAttachmentCallback(
|
||||
AttachmentView.AttachmentFileDownloadCallback attachmentCallback) {
|
||||
this.attachmentCallback = attachmentCallback;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fsck.k9;
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import com.fsck.k9.activity.Accounts;
|
||||
|
Loading…
Reference in New Issue
Block a user