The preceding commit resulted in attachments of type message/rfc822 being
sent with 8bit encoding even when the SMTP server did not support
8BITMIME. This commit assures that messages will be converted to 7bit
when necessary.
A new interface CompositeBody was created that extends Body, and classes
Message and Multipart were changed from implementing Body to
CompositeBody. Additional classes BinaryTempFileMessageBody and
LocalAttachmentMessageBody were created (by extending BinaryTempFileBody
and LocalAttachmentBody, respectively), and they too implement
CompositeBody.
A CompositeBody is a Body containing a composite-type that can contain
subparts that may require recursive processing when converting from 8bit
to 7bit. The Part to which a CompositeBody belongs is only permitted to
use 8bit or 7bit encoding for the CompositeBody.
Previously, a Message was created so that it was 7bit clean by default
(even though that meant base64 encoding all attachments, including
messages). Then, if the SMTP server supported 8BITMIME,
Message.setEncoding("8bit") was called so that bodies of type TextBody
would been transmitted using 8bit encoding rather than quoted-printable.
Now, messages are created with 8bit encoding by default. Then, if the
SMTP server does not support 8BITMIME, Message.setUsing7bitTransport is
called to recursively convert the message and its subparts to 7bit. The
method setUsing7bitTransport was added to the interfaces Part and
CompositeBody.
setEncoding no longer iterates over parts in Multipart. That task belongs
to setUsing7bitTransport, which may in turn call setEncoding on the parts.
MimeUtility.getEncodingforType was created as a helper function for
choosing a default encoding that should be used for a given MIME type when
an attachment is added to a message (either while composing or when
retrieving from LocalStore).
setEncoding was implemented in MimeBodyPart to assure that the encoding
set in the Part's headers was the same as set for the Part's Body. (The
method already existed in MimeMessage, which has similarities with
MimeBodyPart.)
MimeMessage.parse(InputStream in, boolean recurse) was implemented so that
the parser could be told to recursively process nested messages read from
the InputStream, thus giving access to all subparts at any level that may
need to be converted from 8bit to 7bit.
The problem: Receive a message with an attachment of type message/rfc822
and forward it. When the message is sent, K-9 Mail uses base64 encoding
for the attachment. (Alternatively, you could compose a new message and
add such an attachment from a file using a filing-picking app, but that is
not 100% effective because the app may not choose the correct
message/rfc822 MIME type for the attachment.)
Such encoding is prohibited per RFC 2046 (5.2.1) and RFC 2045 (6.4). Only
8bit or 7bit encoding is permitted for attachments of type message/rfc822.
Thunderbird refuses to decode such attachments. All that is shown is the
base64 encoded body.
This commit implements LocalAttachmentBody.setEncoding. If an attachment
to a newly composed message is itself a message, then setEncoding("8bit")
is called, otherwise setEncoding("base64") is called for the attachment.
Similar behavior occurs when an attachment is retrieved from LocalStore.
The setEncoding method was added to the Body interface, since all
implementations of Body now declare the method.
The problem here differs from that in the preceding commit: Here, the
encoding problem occurs on sending, not on receipt. Here, the entire
message (headers and body) is base64 encoded, not just the body. Here,
the headers correctly identify the encoding used; it's just that the RFC
does not permit such encoding of attached messages. The problem here
could in fact occur in combination with the preceding problem.
Issue 5734 exemplifies the problem: receive a message with an attachment
of type message/rfc822 that doesn't use base64 encoding for the body of
the attached message. K-9 Mail incorrectly stores the attached message
locally with its original headers but using base64 encoding for the body.
A discrepancy thus exists between what the headers say about the encoding
of the body versus the actual encoding used. This is obvious when
attempting to view the attachment (either by using a compatible message
viewer available on the device or by saving the attachment to a file and
viewing the file contents).
The process: When a message with an attached sub-message is received,
Message.parse puts the attachment in a new MimeMessage with the
attachment's body in a BinaryTempFileBody. LocalFolder.saveAttachment
then calls Message.writeTo (which later calls BinaryTempFileBody.writeTo)
to place the entire attachment (headers and body) in a new file that will
become a LocalAttachmentBody. Until now, BinaryTempFileBody.writeTo
could only save the message body using base64 encoding.
This commit implements BinaryTempFileBody.setEncoding and assures that the
body is written out with the same encoding that was found in its headers.
Currently, K-9 Mail detects if an SMTP server supports 8BITMIME (RFC
6152), and if so, TextBody parts are sent with content-transfer-ecoding =
8bit. Otherwise, they are sent using quoted-printable.
This adds the required "BODY=8BITMIME" parameter to the MAIL command when
sending messages to servers that support 8BITMIME.
The new method is a little bit janky, but a little bit of jank is better than 2n
heavy SQL count queries per folder before we even show the folder list.
On my 200 folder account, display of the folder list activity drops from 10+s to
< 1s
If you attempted to use SSL to connect to a server that speaks
STARTTLS, you should get an SSL protocol error. Instead, you
were likely to get an "Unrecognized Certificate" error that shows
you an unrelated certificate chain and asks you to accept it or
reject it. Neither action would work because the actual problem
had nothing to do with certificates. The unrelated certificate
chain that popped up had been statically stored when validating
a prior connection to a different server.
With this patch, certificate chains are no longer stored statically
when validating server connections.
Issue 5886 is an example of a user experiencing this problem.
Deleting a message creates an entry in EmailProviderCache so
EmailProviderCacheCursor can skip the Cursor row during the time
it takes to update the database.
Previously EmailProviderCacheCursor.isLast() returned the wrong
result when the last row in the wrapped Cursor was hidden. This
lead to the crash in MergeCursor.
Fixes issue 5820
Effective with earlier commit e2c5229e85,
messages are wrapped with <html> tags at display time, rather than
when messages are saved.
For consistency, this commit removes tags from a status message, because
they, too, will be added back at display time.
Closes pull request 286.
Gmail style user pics, 2nd try
* sfuhrm/gmail-style-user-pics:
Changed the fallback char from 'K' to '?'. The riddler was here ;).
Using Android proposed colors as contact color palette now: http://developer.android.com/design/style/color.html
Fixed NPE found by blackbox87 ... thanks pal!
Added more finer characters as proposed by cketti
Caching also the calculated anonymous bitmap as proposed by maniac103. This removes a lot of code for special handling unknown contacts.
Bugfix for negative modulo result indexing the palette array
Changed hash based color calc to a hash indexed palette as discussed in the pull request.
GMail-app-style generated colorful one-letter contact pictures for pictureless contacts
Conflicts:
src/com/fsck/k9/activity/misc/ContactPictureLoader.java
src/com/fsck/k9/fragment/MessageListFragment.java
java.lang.NullPointerException
at com.fsck.k9.controller.MessagingController.actOnMessages(MessagingController.java:5602)
at com.fsck.k9.controller.MessagingController.deleteThreads(MessagingController.java:3986)
at com.fsck.k9.fragment.MessageListFragment.onDelete(MessageListFragment.java:1311)
at com.fsck.k9.fragment.MessageListFragment.onDelete(MessageListFragment.java:1306)
at com.fsck.k9.fragment.MessageListFragment.onContextItemSelected(MessageListFragment.java:1506)
at android.support.v4.app.Fragment.performContextItemSelected(Fragment.java:1583)
at android.support.v4.app.FragmentManagerImpl.dispatchContextItemSelected(FragmentManager.java:1992)
at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:370)
at com.actionbarsherlock.app.SherlockFragmentActivity.onMenuItemSelected(SherlockFragmentActivity.java:211)
at com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback.onMenuItemSelected(PhoneWindow.java:4038)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
at com.android.internal.view.menu.MenuDialogHelper.onClick(MenuDialogHelper.java:193)
at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:934)
at android.widget.AdapterView.performItemClick(AdapterView.java:301)
at android.widget.AbsListView.performItemClick(AbsListView.java:1287)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3078)
at android.widget.AbsListView$1.run(AbsListView.java:4161)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)
This patch makes sure actions started via the context menu operate on
the correct message even when the message list changes and the 'adapter
position' accessible via the menu object points to another message.
When the message the menu was opened for is deleted the context menu
will be closed.
Previously the app crashed when upgrading the database failed. Now we
reset the database version and run the upgrade code again (recreating
all tables).
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.fsck.k9/com.fsck.k9.activity.UpgradeDatabases}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2117)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2155)
at android.app.ActivityThread.access$700(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5062)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1409)
at android.app.Activity.startActivityForResult(Activity.java:3389)
at android.app.Activity.startActivityForResult(Activity.java:3350)
at android.app.Activity.startActivity(Activity.java:3562)
at android.app.Activity.startActivity(Activity.java:3528)
at com.fsck.k9.activity.UpgradeDatabases.launchOriginalActivity(UpgradeDatabases.java:183)
at com.fsck.k9.activity.UpgradeDatabases.onCreate(UpgradeDatabases.java:109)
at android.app.Activity.performCreate(Activity.java:5058)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2081)
... 11 more
Market reported NPE:
java.lang.NullPointerException
at com.fsck.k9.view.MessageHeader.showAdditionalHeaders(MessageHeader.java:186)
at com.fsck.k9.view.MessageHeader.onShowAdditionalHeaders(MessageHeader.java:318)
at com.fsck.k9.fragment.MessageViewFragment.onToggleAllHeadersView(MessageViewFragment.java:300)
at com.fsck.k9.activity.MessageList.onOptionsItemSelected(MessageList.java:867)
at android.support.v4.app.Watson.onMenuItemSelected(Watson.java:119)
at com.actionbarsherlock.ActionBarSherlock.callbackOptionsItemSelected(ActionBarSherlock.java:603)
at com.actionbarsherlock.internal.ActionBarSherlockNative.dispatchOptionsItemSelected(ActionBarSherlockNative.java:78)
at com.actionbarsherlock.app.SherlockFragmentActivity.onMenuItemSelected(SherlockFragmentActivity.java:205)
at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1047)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
at com.android.internal.view.menu.ListMenuPresenter.onItemClick(ListMenuPresenter.java:180)
at android.widget.AdapterView.performItemClick(AdapterView.java:301)
at android.widget.AbsListView.performItemClick(AbsListView.java:1276)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3067)
at android.widget.AbsListView$1.run(AbsListView.java:3963)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4898)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.fsck.k9/com.fsck.k9.activity.MessageList}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1970)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
at android.app.ActivityThread.access$600(ActivityThread.java:128)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4517)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.fsck.k9.activity.MessageList.decodeExtras(MessageList.java:368)
at com.fsck.k9.activity.MessageList.onCreate(MessageList.java:216)
at android.app.Activity.performCreate(Activity.java:4470)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
k
This reverts commit bbdec62e37.
Aside from being the incorrect solution for fixing the problem
described in pull request 211, the patch generates 'Dead code'
warnings inside the if(){} statements on lines 46 and 47.
The correct fix for the problem was already implemented in commit
5678786c97.
Although the logcat in the pull request was generated after the fix,
line numbers in the log indicate that it was based on an outdated
version of MimeUtility.java from before the fix.
* 'Issue_4503_auto-fit_messages_option' of https://github.com/zjw/k-9:
Revert "Don't show a disabled preference if there is nothing a user can do to enable it."
Fix indentation
Correct preference version number.
Issue 4503: Auto-fit messages option
Don't show a disabled preference if there is nothing a user can do to enable it.
Reported for Kaiten:
java.lang.IllegalStateException: Can not perform this action after
onSaveInstanceState
...
at android.support.v4.app.DialogFragment.dismiss
Previously the activity theme was used to display the auto-complete
suggestions. This lead to unreadable text when the activity theme was
different from the "composer theme".
This was disabled in faa666394c
because it isn't possible to extract the name of the android
contact in the 'ORDER BY...' clause when querying the database.
Instead it simply sorts by the email address.
This may cause the same contact to appear multiple times in
the list, if they have multiple email addresses assigned.
But in most cases this is good enough and surely better than
not having the option to sort by sender at all.
Desktop mail clients such as Thunderbird also simply use the
sender email information when sorting the column.
This also adds a SenderComparator for usage in the MergeCursor.
Seemingly the intents in the task back stack got confused when the
pending intent was updated in those versions (the Accounts intent was
delivered to MessageList). Avoid that by not updating the current
intent, but dropping the old one.
Fixes issue #4955.