Skip to content

Commit

Permalink
[mms] Strip PGP armor text when replying to a message.
Browse files Browse the repository at this point in the history
  • Loading branch information
slusarz committed Nov 7, 2013
1 parent aeb151b commit eebf1b6
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 87 deletions.
1 change: 1 addition & 0 deletions imp/docs/CHANGES
Expand Up @@ -2,6 +2,7 @@
v6.2.0-git
----------

[mms] Strip PGP armor text when replying to a message.
[mms] Move determination whether to scan plaintext messages for PGP data from
preferences to MIME viewer configuration.
[mms] Add copy email option to the address context menu in dynamic view.
Expand Down
12 changes: 12 additions & 0 deletions imp/lib/Compose.php
Expand Up @@ -2837,6 +2837,18 @@ protected function _getMessageText($contents, array $options = array())
$msg = rtrim(substr($msg, 0, $pos));
}

/* Remove PGP armored text. */
$pgp = $injector->getInstance('IMP_Crypt_Pgp')->armoredTextToPart($msg);
if (!is_null($pgp)) {
$msg = '';
$pgp->buildMimeIds();
foreach ($pgp->contentTypeMap() as $key => $val) {
if (strpos($val, 'text/') === 0) {
$msg .= $pgp[$key]->getContents();
}
}
}

if ($part->getContentTypeParameter('format') == 'flowed') {
$flowed = new Horde_Text_Flowed($msg, 'UTF-8');
if (Horde_String::lower($part->getContentTypeParameter('delsp')) == 'yes') {
Expand Down
92 changes: 92 additions & 0 deletions imp/lib/Crypt/Pgp.php
Expand Up @@ -699,4 +699,96 @@ public function getKeys($data)
return $out;
}

/**
* TODO
*/
public function armoredTextToPart($data, $charset = 'UTF-8')
{
$parts = $this->parsePGPData($data);

if (empty($parts) ||
((count($parts) == 1) && ($parts[0]['type'] == self::ARMOR_TEXT))) {
return null;
}

$new_part = new Horde_Mime_Part();
$new_part->setType('multipart/mixed');

foreach ($parts as $val) {
switch ($val['type']) {
case self::ARMOR_TEXT:
$part = new Horde_Mime_Part();
$part->setType('text/plain');
$part->setCharset($charset);
$part->setContents(implode("\n", $val['data']));
$new_part->addPart($part);
break;

case self::ARMOR_PUBLIC_KEY:
$part = new Horde_Mime_Part();
$part->setType('application/pgp-keys');
$part->setContents(implode("\n", $val['data']));
$new_part->addPart($part);
break;

case self::ARMOR_MESSAGE:
$part = new Horde_Mime_Part();
$part->setType('multipart/encrypted');
$part->setMetadata(IMP_Mime_Viewer_Pgp::PGP_ARMOR, true);
$part->setContentTypeParameter('protocol', 'application/pgp-encrypted');

$part1 = new Horde_Mime_Part();
$part1->setType('application/pgp-encrypted');
$part1->setContents("Version: 1\n");

$part2 = new Horde_Mime_Part();
$part2->setType('application/octet-stream');
$part2->setContents(implode("\n", $val['data']));
$part2->setDisposition('inline');

$part->addPart($part1);
$part->addPart($part2);

$new_part->addPart($part);
break;

case self::ARMOR_SIGNED_MESSAGE:
if (($sig = current($parts)) &&
($sig['type'] == self::ARMOR_SIGNATURE)) {
$part = new Horde_Mime_Part();
$part->setType('multipart/signed');
// TODO: add micalg parameter
$part->setContentTypeParameter('protocol', 'application/pgp-signature');

$part1 = new Horde_Mime_Part();
$part1->setType('text/plain');
$part1->setCharset($charset);

$part1_data = implode("\n", $val['data']);
$part1->setContents(substr($part1_data, strpos($part1_data, "\n\n") + 2));

$part2 = new Horde_Mime_Part();

$part2->setType('application/pgp-signature');
$part2->setContents(implode("\n", $val['data']) . "\n" . implode("\n", $sig['data']));
// A true pgp-signature part would only contain the
// detached signature. However, we need to carry around
// the entire armored text to verify correctly. Use a
// IMP-specific content-type parameter to clue the PGP
// driver into this fact.
$part2->setMetadata(IMP_Mime_Viewer_Pgp::PGP_SIG, true);
$part2->setMetadata(IMP_Mime_Viewer_Pgp::PGP_CHARSET, $charset);

$part->addPart($part1);
$part->addPart($part2);
$new_part->addPart($part);

next($parts);
}
}
}

return $new_part;
}

}
93 changes: 6 additions & 87 deletions imp/lib/Mime/Viewer/Plain.php
Expand Up @@ -244,99 +244,18 @@ protected function _getEmbeddedMimeParts()
*/
protected function _parsePGP()
{
$parts = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->parsePGPData(
$part = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->armoredTextToPart(
new Horde_Stream_Existing(array(
'stream' => $this->_mimepart->getContents(array('stream' => true))
))
)),
$this->_mimepart->getCharset()
);

if (empty($parts) ||
((count($parts) == 1) &&
($parts[0]['type'] == Horde_Crypt_Pgp::ARMOR_TEXT))) {
return null;
}

$new_part = new Horde_Mime_Part();
$new_part->setType('multipart/mixed');
$charset = $this->_mimepart->getCharset();
$mime_id = $this->_mimepart->getMimeId();

while (list(,$val) = each($parts)) {
switch ($val['type']) {
case Horde_Crypt_Pgp::ARMOR_TEXT:
$part = new Horde_Mime_Part();
$part->setType('text/plain');
$part->setCharset($charset);
$part->setContents(implode("\n", $val['data']));
$new_part->addPart($part);
break;

case Horde_Crypt_Pgp::ARMOR_PUBLIC_KEY:
$part = new Horde_Mime_Part();
$part->setType('application/pgp-keys');
$part->setContents(implode("\n", $val['data']));
$new_part->addPart($part);
break;

case Horde_Crypt_Pgp::ARMOR_MESSAGE:
$part = new Horde_Mime_Part();
$part->setType('multipart/encrypted');
$part->setMetadata(IMP_Mime_Viewer_Pgp::PGP_ARMOR, true);
$part->setContentTypeParameter('protocol', 'application/pgp-encrypted');

$part1 = new Horde_Mime_Part();
$part1->setType('application/pgp-encrypted');
$part1->setContents("Version: 1\n");

$part2 = new Horde_Mime_Part();
$part2->setType('application/octet-stream');
$part2->setContents(implode("\n", $val['data']));
$part2->setDisposition('inline');

$part->addPart($part1);
$part->addPart($part2);

$new_part->addPart($part);
break;

case Horde_Crypt_Pgp::ARMOR_SIGNED_MESSAGE:
if (($sig = current($parts)) &&
($sig['type'] == Horde_Crypt_Pgp::ARMOR_SIGNATURE)) {
$part = new Horde_Mime_Part();
$part->setType('multipart/signed');
// TODO: add micalg parameter
$part->setContentTypeParameter('protocol', 'application/pgp-signature');

$part1 = new Horde_Mime_Part();
$part1->setType('text/plain');
$part1->setCharset($charset);

$part1_data = implode("\n", $val['data']);
$part1->setContents(substr($part1_data, strpos($part1_data, "\n\n") + 2));

$part2 = new Horde_Mime_Part();
$part2->setType('application/pgp-signature');
$part2->setContents(implode("\n", $val['data']) . "\n" . implode("\n", $sig['data']));
// A true pgp-signature part would only contain the
// detached signature. However, we need to carry around
// the entire armored text to verify correctly. Use a
// IMP-specific content-type parameter to clue the PGP
// driver into this fact.
$part2->setMetadata(IMP_Mime_Viewer_Pgp::PGP_SIG, true);
$part2->setMetadata(IMP_Mime_Viewer_Pgp::PGP_CHARSET, $charset);

$part->addPart($part1);
$part->addPart($part2);
$new_part->addPart($part);

next($parts);
}
}
if (!is_null($part)) {
self::$_cache[$this->_mimepart->getMimeId()] = true;
}

self::$_cache[$mime_id] = true;

return $new_part;
return $part;
}

/**
Expand Down
1 change: 1 addition & 0 deletions imp/package.xml
Expand Up @@ -33,6 +33,7 @@
</stability>
<license uri="http://www.horde.org/licenses/gpl">GPL-2.0</license>
<notes>
* [mms] Strip PGP armor text when replying to a message.
* [mms] Move determination whether to scan plaintext messages for PGP data from preferences to MIME viewer configuration.
* [mms] Add copy email option to the address context menu in dynamic view.
* [mms] Support uploading multiple attachments at once in dynamic view.
Expand Down

0 comments on commit eebf1b6

Please sign in to comment.