Merge branch 'pgp_mime_preparations'

This commit is contained in:
cketti 2015-03-16 16:14:45 +01:00
commit ab964cf8af
213 changed files with 7384 additions and 4384 deletions

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>lock-closed</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="lock-closed" sketch:type="MSArtboardGroup" fill="#000000">
<path d="M81.502,45.132 L79.577,45.132 L79.577,29.479 C79.479,10.285 66.387,-0.164 50.476,-0.164 C34.57,-0.164 20.304,10.782 20.801,29.479 L20.785,45.112 C20.785,45.112 21.025,45.133 19.825,45.133 C18.555,45.133 10.185,46.606 10.185,54.069 L10.185,89.893 C10.185,97.852 19.605,99.836 19.825,99.836 L81.027,99.836 C81.247,99.836 90.181,98.843 90.181,89.893 L90.181,54.564 C90.182,46.109 81.727,45.132 81.502,45.132 L81.502,45.132 Z M59.334,86.055 L41.061,86.055 L46.024,71.489 C43.904,70.077 42.496,67.623 42.496,64.824 C42.496,60.44 45.938,56.886 50.183,56.886 C54.428,56.886 57.87,60.443 57.87,64.824 C57.87,67.619 56.466,70.077 54.348,71.485 L59.334,86.055 L59.334,86.055 Z M34.261,45.132 L34.277,29.686 C34.277,19.737 40.348,11.783 50.183,11.783 C59.924,11.783 66.088,18.741 66.088,29.686 L66.098,45.132 L34.261,45.132 L34.261,45.132 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>lock-error</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="lock-error" sketch:type="MSArtboardGroup" fill="#000000">
<path d="M80.459,45.474 L78.533,45.474 L78.533,29.826 C78.435,10.633 65.344,0.183 49.433,0.183 C33.527,0.183 19.265,11.128 19.761,29.826 L19.745,45.454 C19.745,45.454 19.985,45.475 18.784,45.475 C17.514,45.475 9.145,46.946 9.145,54.407 L9.145,90.228 C9.145,98.187 18.565,100.171 18.784,100.171 L79.984,100.171 C80.203,100.171 89.138,99.178 89.138,90.228 L89.138,54.901 C89.139,46.452 80.684,45.474 80.459,45.474 L80.459,45.474 Z M33.234,30.033 C33.234,20.084 39.304,12.131 49.14,12.131 C58.881,12.131 65.045,19.088 65.045,30.033 L65.055,45.474 L33.218,45.474 L33.234,30.033 L33.234,30.033 Z M59.4033767,90.873 L48.4582822,79.9279055 L38.2296593,90.3644491 L31.6365,83.7568884 L42.5824946,72.8153942 L32.3439707,62.5939721 L38.7544118,56.1079235 L49.7013065,67.0503177 L60.1234487,56.7100837 L66.6365,63.2240351 L55.6896053,74.1673294 L66.0091373,84.4778605 L59.4033767,90.873 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>lock-open</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="lock-open" sketch:type="MSArtboardGroup" fill="#000000">
<path d="M79.577,26.479 C79.577,10.833 66.387,-0.164 50.476,-0.164 C34.57,-0.164 20.304,10.782 20.801,29.479 L20.785,45.112 C20.785,45.112 21.025,45.133 19.825,45.133 C18.555,45.133 10.185,46.606 10.185,54.069 L10.185,89.893 C10.185,97.852 19.605,99.836 19.825,99.836 L81.027,99.836 C81.247,99.836 90.181,98.843 90.181,89.893 L90.181,54.564 C90.181,46.107 81.726,45.13 81.5,45.13 L34.259,45.13 L34.275,29.684 C34.275,19.735 40.346,11.781 50.181,11.781 C59.922,11.781 66.664,18.164 66.664,29.164 L79.577,26.479 Z M59.334,86.055 L41.061,86.055 L46.024,71.49 C43.904,70.078 42.496,67.624 42.496,64.825 C42.496,60.44 45.938,56.887 50.183,56.887 C54.428,56.887 57.87,60.445 57.87,64.825 C57.87,67.62 56.466,70.078 54.348,71.485 L59.334,86.055 L59.334,86.055 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-expired-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-expired-cutout" sketch:type="MSArtboardGroup" transform="translate(0.110156, 0.000000)" fill="#000000">
<path d="M5.21763502,25.9334098 C4.62201801,24.5421709 5.31408066,20.2649627 6.50270803,18.5737297 C7.69394204,16.8824967 14.8139764,11.1118682 18.0827017,9.51888655 C21.3514269,7.92852492 25.1232335,10.7136228 25.1232335,10.7136228 L31.1693326,18.5737297 C21.6564037,21.754453 12.2477403,33.889148 12.2477403,33.889148 C12.2477403,33.889148 5.81325202,27.3259588 5.21763502,25.9334098 Z M50.7969868,98.0040129 C30.5564763,98.0040129 14.1592664,81.3860653 14.1592664,60.910451 C14.1592664,41.4138456 29.0387981,25.4459175 47.9423376,23.9707712 L47.9423376,18.3341735 L41.6333009,18.3341735 L41.6333009,9.02828206 L59.2561767,9.02828206 L59.2561767,18.3341735 L53.6477076,18.3341735 L53.6477076,23.9707712 C72.5460092,25.4445909 87.4333977,41.412519 87.4333977,60.910451 C87.4333977,81.3847387 71.0296405,98.0040129 50.7969868,98.0040129 Z M51.541054,71.6933659 C57.6539179,71.6933659 62.6093732,66.7455263 62.6093732,60.6420567 C62.6093732,54.5385872 57.6539179,49.5907476 51.541054,49.5907476 C45.4281901,49.5907476 40.4727348,54.5385872 40.4727348,60.6420567 C40.4727348,66.7455263 45.4281901,71.6933659 51.541054,71.6933659 Z M96.3766201,25.9341425 C95.7811759,27.3252533 89.3433427,33.889148 89.3433427,33.889148 C89.3433427,33.889148 79.9321974,21.7542607 70.4233315,18.5751403 L76.4676764,10.7157573 C76.4676764,10.7157573 80.2396916,7.92829614 83.5087714,9.5185113 C86.7765483,11.1152759 93.8997286,16.884063 95.0880111,18.5751403 C96.2775965,20.2635977 96.9694584,24.540412 96.3766201,25.9341425 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-invalid-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-invalid-cutout" sketch:type="MSArtboardGroup" transform="translate(0.110156, 0.000000)" fill="#000000">
<path d="M77.3119658,92 L50,64.6787909 L22.6865385,92 L8.00299145,77.3054987 L35.3149573,49.9977557 L8,22.6870202 L22.6850427,8.00149623 L50,35.3137279 L77.3149573,8 L92,22.6825315 L64.6850427,49.9977557 L91.9970085,77.3054987 L77.3119658,92 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 995 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="101px" height="100px" viewBox="0 0 101 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-revoked-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-revoked-cutout" sketch:type="MSArtboardGroup" transform="translate(0.915625, 0.000000)" fill="#000000">
<path d="M50.1457786,95.2902674 C25.2543974,95.2902674 5,75.0407401 5,50.1451337 C5,25.252107 25.2556872,5 50.1457786,5 C75.03587,5 95.2902674,25.252107 95.2902674,50.1451337 C95.2902674,75.0394503 75.0371599,95.2902674 50.1457786,95.2902674 Z M35.5297191,75.6701923 C39.8404345,78.1467253 44.8296167,79.569442 50.1464236,79.569442 C66.3793238,79.569442 79.5862102,66.3638454 79.5862102,50.1296554 C79.5862102,44.8115586 78.1622037,39.8223764 75.6843808,35.5116611 L35.5297191,75.6701923 Z M50.1464236,20.6911586 C33.9135233,20.6911586 20.7066369,33.8967551 20.7066369,50.1309452 C20.7066369,55.3523024 22.0803389,60.2563538 24.473031,64.512895 L64.5296632,24.4575526 C60.2718321,22.0635707 55.3690706,20.6911586 50.1464236,20.6911586 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="101px" height="100px" viewBox="0 0 101 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-unknown-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-unknown-cutout" sketch:type="MSArtboardGroup" transform="translate(0.915625, 0.000000)" fill="#000000">
<path d="M11.4743662,97.2253545 C1.98936285,97.2253571 -1.69987039,86.6466353 1.98936288,81.2764443 C2.36018089,80.2888073 37.5445854,9.4248374 37.6406733,9.21698534 C41.524789,0.483122973 56.8650161,0.0416071437 60.7924391,9.21698534 C60.7572519,9.19524917 98.2991929,81.8687547 97.9337883,81.2642177 C101.323931,86.2404407 96.9260512,97.2253571 88.8978453,97.2253545 C88.8978453,97.2253545 11.4756386,97.2879401 11.4743662,97.2253545 Z M50.5378687,73.3388569 C47.2443918,73.3388569 44.2703808,76.046195 44.2703808,79.5061732 C44.2703808,82.9729198 47.1388056,85.6802579 50.5378687,85.6802579 C53.9369317,85.6802579 56.8040029,82.9729198 56.8040029,79.5061732 C56.8053565,76.046195 53.8313455,73.3388569 50.5378687,73.3388569 Z M50.3063913,28.5 C46.5729719,28.5 42.719076,30.2990258 43.0805057,32.9143334 L45.8826007,65.934287 L54.7315355,65.934287 L57.5322768,32.9143334 C57.8937065,30.2990258 54.0398106,28.5 50.3063913,28.5 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="101px" height="100px" viewBox="0 0 101 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-unverified-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-unverified-cutout" sketch:type="MSArtboardGroup" transform="translate(0.915625, 0.000000)" fill="#000000">
<path d="M49.8900274,96.5521596 C75.8474106,96.5521596 96.8900274,75.5095428 96.8900274,49.5521596 C96.8900274,23.5947764 75.8474106,2.5521596 49.8900274,2.5521596 C23.9326441,2.5521596 2.89002736,23.5947764 2.89002736,49.5521596 C2.89002736,75.5095428 23.9326441,96.5521596 49.8900274,96.5521596 Z M42.9188472,79.4349375 L42.9188472,67.0146143 L55.3391704,67.0146143 L55.3391704,79.4349375 L42.9188472,79.4349375 Z M68.652586,41.8646591 C67.9712562,43.583078 67.1302842,45.0524085 66.1249189,46.2716815 C65.1167028,47.4919237 64.0039592,48.5318919 62.7800362,49.3906167 C61.5570634,50.25128 60.4006082,51.1080664 59.3135213,51.9677605 C58.2254842,52.829393 57.2609796,53.8121774 56.4181072,54.9209598 C55.5733342,56.0307115 55.0449948,57.4147511 54.8273874,59.0779247 L54.8273874,62.237567 L43.8168316,62.237567 L43.8168316,58.4954263 C43.9802747,56.114064 44.4278428,54.1165111 45.1623867,52.5095519 C45.89503,50.9025928 46.7531065,49.5292145 47.7309145,48.3923248 C48.7106231,47.2564044 49.7425954,46.2716815 50.8296823,45.4400947 C51.9177195,44.6104463 52.9230848,43.7769211 53.8476788,42.9463035 C54.7722728,42.1147166 55.5201202,41.2007465 56.0912209,40.2024546 C56.6623216,39.2041628 56.9188893,37.9577517 56.8647251,36.4612832 C56.8647251,33.9112774 56.2537138,32.0261534 55.030741,30.804942 C53.8058678,29.5876075 52.1058691,28.9760325 49.9326456,28.9760325 C48.4645081,28.9760325 47.2006746,29.2677664 46.1392445,29.8492956 C45.0797149,30.4317941 44.2092851,31.2071664 43.5298558,32.177351 C42.848526,33.1475357 42.3477439,34.2844253 42.0208576,35.5860816 C41.6939713,36.8906456 41.5305282,38.2901926 41.5305282,39.7866612 L29.5431146,39.7866612 C29.5953784,36.7917856 30.0999615,34.0479368 31.0521128,31.5541455 C32.0023636,29.0593851 33.3346152,26.8970655 35.0479174,25.0691252 C36.7612195,23.2382773 38.8270647,21.8115922 41.2464032,20.7832547 C43.6666919,19.7568556 46.3730062,19.2441406 49.3624951,19.2441406 C53.2224138,19.2441406 56.4447142,19.785932 59.0274958,20.8666072 C61.6093272,21.9482516 63.6894262,23.2935226 65.2668425,24.9024202 C66.8442588,26.5103485 67.9712562,28.2423365 68.6516357,30.0993532 C69.3310651,31.9573391 69.6703046,33.6883579 69.6703046,35.2962862 C69.6722051,37.9567825 69.3320153,40.1481786 68.652586,41.8646591 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8053) - http://www.bohemiancoding.com/sketch -->
<title>signature-verified-cutout</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="signature-verified-cutout" sketch:type="MSArtboardGroup" transform="translate(0.110156, 0.000000)" fill="#000000">
<path d="M50,97 C75.9573832,97 97,75.9573832 97,50 C97,24.0426168 75.9573832,3 50,3 C24.0426168,3 3,24.0426168 3,50 C3,75.9573832 24.0426168,97 50,97 Z M46.2732912,77.5085 L20,57.830916 L27.9184401,47.6349702 L43.3096859,59.5152262 L70.31112,23 L80.867825,30.7782191 L46.2732912,77.5085 Z" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

19
images/update-drawables-pgp.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
APP_DIR=../k9mail/src/main
MDPI_DIR=$APP_DIR/res/drawable-mdpi
HDPI_DIR=$APP_DIR/res/drawable-hdpi
XDPI_DIR=$APP_DIR/res/drawable-xhdpi
XXDPI_DIR=$APP_DIR/res/drawable-xxhdpi
XXXDPI_DIR=$APP_DIR/res/drawable-xxxhdpi
SRC_DIR=./drawables-pgp/
for NAME in "status_lock_closed" "status_lock_error" "status_lock_open" "status_signature_expired_cutout" "status_signature_invalid_cutout" "status_signature_revoked_cutout" "status_signature_unknown_cutout" "status_signature_unverified_cutout" "status_signature_verified_cutout"
do
echo $NAME
inkscape -w 24 -h 24 -e "$MDPI_DIR/$NAME.png" "$SRC_DIR/$NAME.svg"
inkscape -w 32 -h 32 -e "$HDPI_DIR/$NAME.png" "$SRC_DIR/$NAME.svg"
inkscape -w 48 -h 48 -e "$XDPI_DIR/$NAME.png" "$SRC_DIR/$NAME.svg"
inkscape -w 64 -h 64 -e "$XXDPI_DIR/$NAME.png" "$SRC_DIR/$NAME.svg"
done

View File

@ -2,14 +2,25 @@ package com.fsck.k9.mail;
public abstract class BodyPart implements Part {
private Multipart mParent;
private String serverExtra;
private Multipart parent;
@Override
public String getServerExtra() {
return serverExtra;
}
@Override
public void setServerExtra(String serverExtra) {
this.serverExtra = serverExtra;
}
public Multipart getParent() {
return mParent;
return parent;
}
public void setParent(Multipart parent) {
mParent = parent;
this.parent = parent;
}
public abstract void setEncoding(String encoding) throws MessagingException;

View File

@ -120,9 +120,6 @@ public abstract class Message implements Part, CompositeBody {
@Override
public abstract Body getBody();
@Override
public abstract String getContentType() throws MessagingException;
@Override
public abstract void addHeader(String name, String value) throws MessagingException;
@ -141,7 +138,7 @@ public abstract class Message implements Part, CompositeBody {
public abstract void removeHeader(String name) throws MessagingException;
@Override
public abstract void setBody(Body body) throws MessagingException;
public abstract void setBody(Body body);
public abstract long getId();
@ -150,55 +147,6 @@ public abstract class Message implements Part, CompositeBody {
public abstract int getSize();
/*
* calculateContentPreview
* Takes a plain text message body as a string.
* Returns a message summary as a string suitable for showing in a message list
*
* A message summary should be about the first 160 characters
* of unique text written by the message sender
* Quoted text, "On $date" and so on will be stripped out.
* All newlines and whitespace will be compressed.
*
*/
public static String calculateContentPreview(String text) {
if (text == null) {
return null;
}
// Only look at the first 8k of a message when calculating
// the preview. This should avoid unnecessary
// memory usage on large messages
if (text.length() > 8192) {
text = text.substring(0, 8192);
}
// Remove (correctly delimited by '-- \n') signatures
text = text.replaceAll("(?ms)^-- [\\r\\n]+.*", "");
// 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+:$", "");
// Remove horizontal rules.
text = text.replaceAll("\\s*([-=_]{30,}+)\\s*", " ");
// 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+", " ");
// Remove any whitespace at the beginning and end of the string.
text = text.trim();
return (text.length() <= 512) ? text : text.substring(0, 512);
}
public void delete(String trashFolderName) throws MessagingException {}
/*

View File

@ -28,7 +28,9 @@ public abstract class Multipart implements CompositeBody {
return Collections.unmodifiableList(mParts);
}
public abstract String getContentType();
public abstract String getMimeType();
public abstract String getBoundary();
public int getCount() {
return mParts.size();
@ -64,4 +66,7 @@ public abstract class Multipart implements CompositeBody {
((TextBody)body).setCharset(charset);
}
}
public abstract byte[] getPreamble();
public abstract byte[] getEpilogue();
}

View File

@ -2,6 +2,7 @@
package com.fsck.k9.mail;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public interface Part {
@ -15,22 +16,24 @@ public interface Part {
Body getBody();
String getContentType() throws MessagingException;
String getContentType();
String getDisposition() throws MessagingException;
String getContentId() throws MessagingException;
String getContentId();
String[] getHeader(String name) throws MessagingException;
boolean isMimeType(String mimeType) throws MessagingException;
String getMimeType() throws MessagingException;
String getMimeType();
void setBody(Body body) throws MessagingException;
void setBody(Body body);
void writeTo(OutputStream out) throws IOException, MessagingException;
void writeHeaderTo(OutputStream out) throws IOException, MessagingException;
/**
* Called just prior to transmission, once the type of transport is known to
* be 7bit.
@ -44,4 +47,8 @@ public interface Part {
*/
//TODO perhaps it would be clearer to use a flag "force7bit" in writeTo
void setUsing7bitTransport() throws MessagingException;
String getServerExtra();
void setServerExtra(String serverExtra);
}

View File

@ -1,6 +1,5 @@
package com.fsck.k9.mail.internet;
import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.Base64OutputStream;
import org.apache.commons.io.IOUtils;
@ -15,7 +14,7 @@ import java.io.*;
* and writeTo one time. After writeTo is called, or the InputStream returned from
* getInputStream is closed the file is deleted and the Body should be considered disposed of.
*/
public class BinaryTempFileBody implements RawDataBody {
public class BinaryTempFileBody implements RawDataBody, SizeAware {
private static File mTempDirectory;
private File mFile;
@ -26,6 +25,10 @@ public class BinaryTempFileBody implements RawDataBody {
mTempDirectory = tempDirectory;
}
public static File getTempDirectory() {
return mTempDirectory;
}
@Override
public String getEncoding() {
return mEncoding;
@ -101,6 +104,15 @@ public class BinaryTempFileBody implements RawDataBody {
}
}
@Override
public long getSize() {
return mFile.length();
}
public File getFile() {
return mFile;
}
class BinaryTempFileBodyInputStream extends FilterInputStream {
public BinaryTempFileBodyInputStream(InputStream in) {
super(in);

View File

@ -11,10 +11,7 @@ import com.fsck.k9.mail.CompositeBody;
import com.fsck.k9.mail.MessagingException;
/**
* A {@link BinaryTempFileBody} extension containing a body of type
* message/rfc822. This relates to a BinaryTempFileBody the same way that a
* {@link LocalAttachmentMessageBody} relates to a {@link LocalAttachmentBody}.
*
* A {@link BinaryTempFileBody} extension containing a body of type message/rfc822.
*/
public class BinaryTempFileMessageBody extends BinaryTempFileBody implements CompositeBody {
@ -63,4 +60,4 @@ public class BinaryTempFileMessageBody extends BinaryTempFileBody implements Com
*/
}
}
}

View File

@ -48,7 +48,7 @@ public class MessageExtractor {
* determine the charset from HTML message.
*/
if (mimeType.equalsIgnoreCase("text/html") && charset == null) {
InputStream in = part.getBody().getInputStream();
InputStream in = MimeUtility.decodeBody(body);
try {
byte[] buf = new byte[256];
in.read(buf, 0, buf.length);
@ -64,18 +64,8 @@ public class MessageExtractor {
}
} finally {
try {
if (in instanceof BinaryTempFileBody.BinaryTempFileBodyInputStream) {
/*
* If this is a BinaryTempFileBodyInputStream, calling close()
* will delete the file. But we can't let that happen because
* the file needs to be opened again by the code a few lines
* down.
*/
((BinaryTempFileBody.BinaryTempFileBodyInputStream) in).closeWithoutDeleting();
} else {
in.close();
}
} catch (Exception e) { /* ignore */ }
MimeUtility.closeInputStreamWithoutDeletingTemporaryFiles(in);
} catch (IOException e) { /* ignore */ }
}
}
charset = fixupCharset(charset, getMessageFromPart(part));
@ -84,22 +74,12 @@ public class MessageExtractor {
* Now we read the part into a buffer for further processing. Because
* the stream is now wrapped we'll remove any transfer encoding at this point.
*/
InputStream in = part.getBody().getInputStream();
InputStream in = MimeUtility.decodeBody(body);
try {
String text = CharsetSupport.readToString(in, charset);
// Replace the body with a TextBody that already contains the decoded text
part.setBody(new TextBody(text));
return text;
return CharsetSupport.readToString(in, charset);
} finally {
try {
/*
* This time we don't care if it's a BinaryTempFileBodyInputStream. We
* replaced the body with a TextBody instance and hence don't need the
* file anymore.
*/
in.close();
MimeUtility.closeInputStreamWithoutDeletingTemporaryFiles(in);
} catch (IOException e) { /* Ignore */ }
}
}
@ -186,6 +166,8 @@ public class MessageExtractor {
Html html = new Html(part);
viewables.add(html);
}
} else if (part.getMimeType().equalsIgnoreCase("application/pgp-signature")) {
// ignore this type explicitly
} else {
// Everything else is treated as attachment.
attachments.add(part);

View File

@ -5,7 +5,6 @@ import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyPart;
import com.fsck.k9.mail.CompositeBody;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Multipart;
import java.io.BufferedWriter;
import java.io.IOException;
@ -73,7 +72,7 @@ public class MimeBodyPart extends BodyPart {
}
@Override
public void setBody(Body body) throws MessagingException {
public void setBody(Body body) {
this.mBody = body;
}
@ -86,7 +85,7 @@ public class MimeBodyPart extends BodyPart {
}
@Override
public String getContentType() throws MessagingException {
public String getContentType() {
String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
return (contentType == null) ? "text/plain" : contentType;
}
@ -97,7 +96,7 @@ public class MimeBodyPart extends BodyPart {
}
@Override
public String getContentId() throws MessagingException {
public String getContentId() {
String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
if (contentId == null) {
return null;
@ -112,7 +111,7 @@ public class MimeBodyPart extends BodyPart {
}
@Override
public String getMimeType() throws MessagingException {
public String getMimeType() {
return MimeUtility.getHeaderParameter(getContentType(), null);
}
@ -135,6 +134,11 @@ public class MimeBodyPart extends BodyPart {
}
}
@Override
public void writeHeaderTo(OutputStream out) throws IOException, MessagingException {
mHeader.writeTo(out);
}
@Override
public void setUsing7bitTransport() throws MessagingException {
String type = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);

View File

@ -11,28 +11,11 @@ import java.util.*;
public class MimeHeader {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* Application specific header that contains Store specific information about an attachment.
* In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later
* retrieve the attachment at will from the server.
* The info is recorded from this header on LocalStore.appendMessages and is put back
* into the MIME data by LocalStore.fetch.
*/
public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData";
public static final String HEADER_CONTENT_TYPE = "Content-Type";
public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
public static final String HEADER_CONTENT_ID = "Content-ID";
/**
* Fields that should be omitted when writing the header using writeTo()
*/
private static final String[] writeOmitFields = {
// HEADER_ANDROID_ATTACHMENT_DOWNLOADED,
// HEADER_ANDROID_ATTACHMENT_ID,
HEADER_ANDROID_ATTACHMENT_STORE_DATA
};
private List<Field> mFields = new ArrayList<Field>();
private String mCharset = null;
@ -101,14 +84,12 @@ public class MimeHeader {
public void writeTo(OutputStream out) throws IOException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
for (Field field : mFields) {
if (!Arrays.asList(writeOmitFields).contains(field.name)) {
if (field.hasRawData()) {
writer.write(field.getRaw());
} else {
writeNameValueField(writer, field);
}
writer.write("\r\n");
if (field.hasRawData()) {
writer.write(field.getRaw());
} else {
writeNameValueField(writer, field);
}
writer.write("\r\n");
}
writer.flush();
}

View File

@ -57,6 +57,7 @@ public class MimeMessage extends Message {
private Body mBody;
protected int mSize;
private String serverExtra;
public MimeMessage() {
}
@ -162,7 +163,7 @@ public class MimeMessage extends Message {
}
@Override
public String getContentType() throws MessagingException {
public String getContentType() {
String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
return (contentType == null) ? "text/plain" : contentType;
}
@ -171,12 +172,14 @@ public class MimeMessage extends Message {
public String getDisposition() throws MessagingException {
return getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
}
@Override
public String getContentId() throws MessagingException {
public String getContentId() {
return null;
}
@Override
public String getMimeType() throws MessagingException {
public String getMimeType() {
return MimeUtility.getHeaderParameter(getContentType(), null);
}
@ -308,13 +311,10 @@ public class MimeMessage extends Message {
if (mMessageId == null) {
mMessageId = getFirstHeader("Message-ID");
}
if (mMessageId == null) { // even after checking the header
setMessageId(generateMessageId());
}
return mMessageId;
}
private String generateMessageId() {
public void generateMessageId() throws MessagingException {
String hostname = null;
if (mFrom != null && mFrom.length >= 1) {
@ -330,7 +330,9 @@ public class MimeMessage extends Message {
}
/* We use upper case here to match Apple Mail Message-ID format (for privacy) */
return "<" + UUID.randomUUID().toString().toUpperCase(Locale.US) + "@" + hostname + ">";
String messageId = "<" + UUID.randomUUID().toString().toUpperCase(Locale.US) + "@" + hostname + ">";
setMessageId(messageId);
}
public void setMessageId(String messageId) throws MessagingException {
@ -394,7 +396,7 @@ public class MimeMessage extends Message {
}
@Override
public void setBody(Body body) throws MessagingException {
public void setBody(Body body) {
this.mBody = body;
}
@ -444,6 +446,11 @@ public class MimeMessage extends Message {
}
}
@Override
public void writeHeaderTo(OutputStream out) throws IOException, MessagingException {
mHeader.writeTo(out);
}
@Override
public InputStream getInputStream() throws MessagingException {
return null;
@ -487,13 +494,11 @@ public class MimeMessage extends Message {
stack.addFirst(MimeMessage.this);
} else {
expect(Part.class);
try {
MimeMessage m = new MimeMessage();
((Part)stack.peek()).setBody(m);
stack.addFirst(m);
} catch (MessagingException me) {
throw new Error(me);
}
Part part = (Part) stack.peek();
MimeMessage m = new MimeMessage();
part.setBody(m);
stack.addFirst(m);
}
}
@ -519,7 +524,10 @@ public class MimeMessage extends Message {
Part e = (Part)stack.peek();
try {
MimeMultipart multiPart = new MimeMultipart(e.getContentType());
String contentType = e.getContentType();
String mimeType = MimeUtility.getHeaderParameter(contentType, null);
String boundary = MimeUtility.getHeaderParameter(contentType, "boundary");
MimeMultipart multiPart = new MimeMultipart(mimeType, boundary);
e.setBody(multiPart);
stack.addFirst(multiPart);
} catch (MessagingException me) {
@ -540,7 +548,21 @@ public class MimeMessage extends Message {
@Override
public void endMultipart() {
stack.removeFirst();
expect(Multipart.class);
Multipart multipart = (Multipart) stack.removeFirst();
boolean hasNoBodyParts = multipart.getCount() == 0;
boolean hasNoEpilogue = multipart.getEpilogue() == null;
if (hasNoBodyParts && hasNoEpilogue) {
/*
* The parser is calling startMultipart(), preamble(), and endMultipart() when all we have is
* headers of a "multipart/*" part. But there's really no point in keeping a Multipart body if all
* of the content is missing.
*/
expect(Part.class);
Part part = (Part) stack.peek();
part.setBody(null);
}
}
@Override
@ -686,4 +708,16 @@ public class MimeMessage extends Message {
setEncoding(MimeUtil.ENC_QUOTED_PRINTABLE);
}
}
@Override
public String getServerExtra() {
return serverExtra;
}
@Override
public void setServerExtra(String serverExtra) {
this.serverExtra = serverExtra;
}
}

View File

@ -23,9 +23,10 @@ public class MimeMessageHelper {
if (body instanceof Multipart) {
Multipart multipart = ((Multipart) body);
multipart.setParent(part);
String type = multipart.getContentType();
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, type);
if ("multipart/signed".equalsIgnoreCase(type)) {
String mimeType = multipart.getMimeType();
String contentType = String.format("%s; boundary=\"%s\"", mimeType, multipart.getBoundary());
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
if ("multipart/signed".equalsIgnoreCase(mimeType)) {
setEncoding(part, MimeUtil.ENC_7BIT);
} else {
setEncoding(part, MimeUtil.ENC_8BIT);

View File

@ -10,30 +10,26 @@ import java.util.Locale;
import java.util.Random;
public class MimeMultipart extends Multipart {
private byte[] mPreamble;
private byte[] mEpilogue;
private String mContentType;
private final String mBoundary;
private String mimeType;
private byte[] preamble;
private byte[] epilogue;
private final String boundary;
public MimeMultipart() throws MessagingException {
mBoundary = generateBoundary();
boundary = generateBoundary();
setSubType("mixed");
}
public MimeMultipart(String contentType) throws MessagingException {
this.mContentType = contentType;
try {
mBoundary = MimeUtility.getHeaderParameter(contentType, "boundary");
if (mBoundary == null) {
throw new MessagingException("MultiPart does not contain boundary: " + contentType);
}
} catch (Exception e) {
throw new MessagingException(
"Invalid MultiPart Content-Type; must contain subtype and boundary. ("
+ contentType + ")", e);
public MimeMultipart(String mimeType, String boundary) throws MessagingException {
if (mimeType == null) {
throw new IllegalArgumentException("mimeType can't be null");
}
if (boundary == null) {
throw new IllegalArgumentException("boundary can't be null");
}
this.mimeType = mimeType;
this.boundary = boundary;
}
public String generateBoundary() {
@ -46,40 +42,53 @@ public class MimeMultipart extends Multipart {
return sb.toString().toUpperCase(Locale.US);
}
@Override
public String getBoundary() {
return boundary;
}
public byte[] getPreamble() {
return preamble;
}
public void setPreamble(byte[] preamble) {
this.mPreamble = preamble;
this.preamble = preamble;
}
public byte[] getEpilogue() {
return epilogue;
}
public void setEpilogue(byte[] epilogue) {
mEpilogue = epilogue;
this.epilogue = epilogue;
}
@Override
public String getContentType() {
return mContentType;
public String getMimeType() {
return mimeType;
}
public void setSubType(String subType) {
mContentType = String.format("multipart/%s; boundary=\"%s\"", subType, mBoundary);
mimeType = "multipart/" + subType;
}
@Override
public void writeTo(OutputStream out) throws IOException, MessagingException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
if (mPreamble != null) {
out.write(mPreamble);
if (preamble != null) {
out.write(preamble);
writer.write("\r\n");
}
if (getBodyParts().isEmpty()) {
writer.write("--");
writer.write(mBoundary);
writer.write(boundary);
writer.write("\r\n");
} else {
for (BodyPart bodyPart : getBodyParts()) {
writer.write("--");
writer.write(mBoundary);
writer.write(boundary);
writer.write("\r\n");
writer.flush();
bodyPart.writeTo(out);
@ -88,11 +97,11 @@ public class MimeMultipart extends Multipart {
}
writer.write("--");
writer.write(mBoundary);
writer.write(boundary);
writer.write("--\r\n");
writer.flush();
if (mEpilogue != null) {
out.write(mEpilogue);
if (epilogue != null) {
out.write(epilogue);
}
}

View File

@ -16,10 +16,7 @@ import org.apache.james.mime4j.util.MimeUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
@ -1029,7 +1026,7 @@ public class MimeUtility {
@Override
public void close() throws IOException {
super.close();
rawInputStream.close();
closeInputStreamWithoutDeletingTemporaryFiles(rawInputStream);
}
};
} else if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) {
@ -1037,7 +1034,7 @@ public class MimeUtility {
@Override
public void close() throws IOException {
super.close();
rawInputStream.close();
closeInputStreamWithoutDeletingTemporaryFiles(rawInputStream);
}
};
} else {
@ -1050,6 +1047,14 @@ public class MimeUtility {
return inputStream;
}
public static void closeInputStreamWithoutDeletingTemporaryFiles(InputStream rawInputStream) throws IOException {
if (rawInputStream instanceof BinaryTempFileBody.BinaryTempFileBodyInputStream) {
((BinaryTempFileBody.BinaryTempFileBodyInputStream) rawInputStream).closeWithoutDeleting();
} else {
rawInputStream.close();
}
}
public static String getMimeTypeByExtension(String filename) {
String returnedType = null;
String extension = null;

View File

@ -0,0 +1,6 @@
package com.fsck.k9.mail.internet;
public interface SizeAware {
long getSize();
}

View File

@ -10,10 +10,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import com.fsck.k9.mail.filter.CountingOutputStream;
import org.apache.james.mime4j.codec.QuotedPrintableOutputStream;
import org.apache.james.mime4j.util.MimeUtil;
public class TextBody implements Body {
public class TextBody implements Body, SizeAware {
/**
* Immutable empty byte array
@ -98,4 +99,33 @@ public class TextBody implements Body {
public void setComposedMessageOffset(Integer composedMessageOffset) {
this.mComposedMessageOffset = composedMessageOffset;
}
@Override
public long getSize() {
try {
byte[] bytes = mBody.getBytes(mCharset);
if (MimeUtil.ENC_8BIT.equalsIgnoreCase(mEncoding)) {
return bytes.length;
} else {
return getLengthWhenQuotedPrintableEncoded(bytes);
}
} catch (IOException e) {
throw new RuntimeException("Couldn't get body size", e);
}
}
private long getLengthWhenQuotedPrintableEncoded(byte[] bytes) throws IOException {
CountingOutputStream countingOutputStream = new CountingOutputStream();
OutputStream quotedPrintableOutputStream = new QuotedPrintableOutputStream(countingOutputStream, false);
try {
quotedPrintableOutputStream.write(bytes);
} finally {
try {
quotedPrintableOutputStream.close();
} catch (IOException e) { /* ignore */ }
}
return countingOutputStream.getCount();
}
}

View File

@ -0,0 +1,118 @@
package com.fsck.k9.mail.message;
import java.io.IOException;
import java.io.InputStream;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.parser.ContentHandler;
import org.apache.james.mime4j.parser.MimeStreamParser;
import org.apache.james.mime4j.stream.BodyDescriptor;
import org.apache.james.mime4j.stream.Field;
import org.apache.james.mime4j.stream.MimeConfig;
public class MessageHeaderParser {
public static void parse(final Part part, InputStream headerInputStream) throws MessagingException {
MimeStreamParser parser = getMimeStreamParser();
parser.setContentHandler(new MessageHeaderParserContentHandler(part));
try {
parser.parse(headerInputStream);
} catch (MimeException me) {
throw new MessagingException("Error parsing headers", me);
} catch (IOException e) {
throw new MessagingException("I/O error parsing headers", e);
}
}
private static MimeStreamParser getMimeStreamParser() {
MimeConfig parserConfig = new MimeConfig();
parserConfig.setMaxHeaderLen(-1);
parserConfig.setMaxLineLen(-1);
parserConfig.setMaxHeaderCount(-1);
return new MimeStreamParser(parserConfig);
}
private static class MessageHeaderParserContentHandler implements ContentHandler {
private final Part part;
public MessageHeaderParserContentHandler(Part part) {
this.part = part;
}
@Override
public void field(Field rawField) throws MimeException {
String name = rawField.getName();
String raw = rawField.getRaw().toString();
try {
part.addRawHeader(name, raw);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
@Override
public void startMessage() throws MimeException {
/* do nothing */
}
@Override
public void endMessage() throws MimeException {
/* do nothing */
}
@Override
public void startBodyPart() throws MimeException {
/* do nothing */
}
@Override
public void endBodyPart() throws MimeException {
/* do nothing */
}
@Override
public void startHeader() throws MimeException {
/* do nothing */
}
@Override
public void endHeader() throws MimeException {
/* do nothing */
}
@Override
public void preamble(InputStream is) throws MimeException, IOException {
/* do nothing */
}
@Override
public void epilogue(InputStream is) throws MimeException, IOException {
/* do nothing */
}
@Override
public void startMultipart(BodyDescriptor bd) throws MimeException {
/* do nothing */
}
@Override
public void endMultipart() throws MimeException {
/* do nothing */
}
@Override
public void body(BodyDescriptor bd, InputStream is) throws MimeException, IOException {
/* do nothing */
}
@Override
public void raw(InputStream is) throws MimeException, IOException {
/* do nothing */
}
}
}

View File

@ -1456,13 +1456,9 @@ public class ImapStore extends RemoteStore {
throws MessagingException {
checkOpen(); //only need READ access
String[] parts = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
if (parts == null) {
return;
}
String partId = part.getServerExtra();
String fetch;
String partId = parts[0];
if ("TEXT".equalsIgnoreCase(partId)) {
fetch = String.format(Locale.US, "BODY.PEEK[TEXT]<0.%d>",
mStoreConfig.getMaximumAutoDownloadMessageSize());
@ -1715,7 +1711,7 @@ public class ImapStore extends RemoteStore {
break;
}
}
part.setBody(mp);
MimeMessageHelper.setBody(part, mp);
} else {
/*
* This is a body. We need to add as much information as we can find out about
@ -1835,7 +1831,7 @@ public class ImapStore extends RemoteStore {
if (part instanceof ImapMessage) {
((ImapMessage) part).setSize(size);
}
part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id);
part.setServerExtra(id);
}
}

View File

@ -20,6 +20,7 @@ dependencies {
compile 'com.android.support:support-v13:21.0.2'
compile 'net.sourceforge.htmlcleaner:htmlcleaner:2.10'
compile 'de.cketti.library.changelog:ckchangelog:1.2.1'
compile 'com.github.bumptech.glide:glide:3.4.0'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'