From de53537ba3a16b153efae3777935d09879f9c394 Mon Sep 17 00:00:00 2001
From: puhr-mde <45031539+puhr-mde@users.noreply.github.com>
Date: Thu, 26 Sep 2019 10:52:14 +0200
Subject: [PATCH] Cancel ICS file corrupted on Office 365 #1780 (#1842)
* Cancel ICS file corrupted on Office 365 #1780
---
src/PHPMailer.php | 43 +++++++++++++-
test/PHPMailerTest.php | 125 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/src/PHPMailer.php b/src/PHPMailer.php
index df4286cc..978e00ee 100644
--- a/src/PHPMailer.php
+++ b/src/PHPMailer.php
@@ -50,6 +50,15 @@ class PHPMailer
const ENCRYPTION_STARTTLS = 'tls';
const ENCRYPTION_SMTPS = 'ssl';
+ const ICAL_METHOD_REQUEST = 'REQUEST';
+ const ICAL_METHOD_PUBLISH = 'PUBLISH';
+ const ICAL_METHOD_REPLY = 'REPLY';
+ const ICAL_METHOD_ADD = 'ADD';
+ const ICAL_METHOD_CANCEL = 'CANCEL';
+ const ICAL_METHOD_REFRESH = 'REFRESH';
+ const ICAL_METHOD_COUNTER = 'COUNTER';
+ const ICAL_METHOD_DECLINECOUNTER = 'DECLINECOUNTER';
+
/**
* Email priority.
* Options: null (default), 1 = High, 3 = Normal, 5 = low.
@@ -149,6 +158,22 @@ class PHPMailer
*/
public $Ical = '';
+ /**
+ * Value-array of "method" in Contenttype header "text/calendar"
+ *
+ * @var string[]
+ */
+ protected static $IcalMethods = [
+ self::ICAL_METHOD_REQUEST,
+ self::ICAL_METHOD_PUBLISH,
+ self::ICAL_METHOD_REPLY,
+ self::ICAL_METHOD_ADD,
+ self::ICAL_METHOD_CANCEL,
+ self::ICAL_METHOD_REFRESH,
+ self::ICAL_METHOD_COUNTER,
+ self::ICAL_METHOD_DECLINECOUNTER,
+ ];
+
/**
* The complete compiled MIME message body.
*
@@ -2604,7 +2629,14 @@ class PHPMailer
$body .= $this->encodeString($this->Body, $bodyEncoding);
$body .= static::$LE;
if (!empty($this->Ical)) {
- $body .= $this->getBoundary($this->boundary[1], '', static::CONTENT_TYPE_TEXT_CALENDAR . '; method=REQUEST', '');
+ $method = static::ICAL_METHOD_REQUEST;
+ foreach (static::$IcalMethods as $imethod) {
+ if (stripos($this->Ical, 'METHOD:' . $imethod) !== false) {
+ $method = $imethod;
+ break;
+ }
+ }
+ $body .= $this->getBoundary($this->boundary[1], '', static::CONTENT_TYPE_TEXT_CALENDAR . '; method=' . $method, '');
$body .= $this->encodeString($this->Ical, $this->Encoding);
$body .= static::$LE;
}
@@ -2640,7 +2672,14 @@ class PHPMailer
$body .= $this->encodeString($this->Body, $bodyEncoding);
$body .= static::$LE;
if (!empty($this->Ical)) {
- $body .= $this->getBoundary($this->boundary[2], '', static::CONTENT_TYPE_TEXT_CALENDAR . '; method=REQUEST', '');
+ $method = static::ICAL_METHOD_REQUEST;
+ foreach (static::$IcalMethods as $imethod) {
+ if (stripos($this->Ical, 'METHOD:' . $imethod) !== false) {
+ $method = $imethod;
+ break;
+ }
+ }
+ $body .= $this->getBoundary($this->boundary[2], '', static::CONTENT_TYPE_TEXT_CALENDAR . '; method=' . $method, '');
$body .= $this->encodeString($this->Ical, $this->Encoding);
}
$body .= $this->endBoundary($this->boundary[2]);
diff --git a/test/PHPMailerTest.php b/test/PHPMailerTest.php
index d8a9aeb2..408f8e3a 100644
--- a/test/PHPMailerTest.php
+++ b/test/PHPMailerTest.php
@@ -2686,6 +2686,131 @@ EOT;
$this->assertNull($subject);
$this->assertInstanceOf(OAuth::class, $PHPMailer->getOAuth());
}
+
+ /**
+ * Test ICal method
+ */
+ public function testICalMethod()
+ {
+ $this->Mail->Subject .= ': ICal method';
+ $this->Mail->Body = '
ICal method test.
';
+ $this->Mail->AltBody = 'ICal method test.';
+ $this->Mail->Ical = 'BEGIN:VCALENDAR'
+ . "\r\nVERSION:2.0"
+ . "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
+ . "\r\nMETHOD:CANCEL"
+ . "\r\nCALSCALE:GREGORIAN"
+ . "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
+ . "\r\nBEGIN:VEVENT"
+ . "\r\nUID:201909250755-42825@test"
+ . "\r\nDTSTART;20190930T080000Z"
+ . "\r\nSEQUENCE:2"
+ . "\r\nTRANSP:OPAQUE"
+ . "\r\nSTATUS:CONFIRMED"
+ . "\r\nDTEND:20190930T084500Z"
+ . "\r\nLOCATION:[London] London Eye"
+ . "\r\nSUMMARY:Test ICal method"
+ . "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
+ . "\r\n TRUE:MAILTO:attendee-test@example.com"
+ . "\r\nCLASS:PUBLIC"
+ . "\r\nDESCRIPTION:Some plain text"
+ . "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:test@example.com"
+ . "\r\nDTSTAMP:20190925T075546Z"
+ . "\r\nCREATED:20190925T075709Z"
+ . "\r\nLAST-MODIFIED:20190925T075546Z"
+ . "\r\nEND:VEVENT"
+ . "\r\nEND:VCALENDAR";
+ $this->buildBody();
+ $this->Mail->preSend();
+ $this->assertRegExp(
+ '/Content-Type: text\/calendar; method=CANCEL;/',
+ $this->Mail->getSentMIMEMessage(),
+ 'Wrong ICal method in Content-Type header'
+ );
+ }
+
+ /**
+ * Test ICal missing method to use default (REQUEST)
+ */
+ public function testICalInvalidMethod()
+ {
+ $this->Mail->Subject .= ': ICal method';
+ $this->Mail->Body = 'ICal method test.
';
+ $this->Mail->AltBody = 'ICal method test.';
+ $this->Mail->Ical = 'BEGIN:VCALENDAR'
+ . "\r\nVERSION:2.0"
+ . "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
+ . "\r\nMETHOD:INVALID"
+ . "\r\nCALSCALE:GREGORIAN"
+ . "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
+ . "\r\nBEGIN:VEVENT"
+ . "\r\nUID:201909250755-42825@test"
+ . "\r\nDTSTART;20190930T080000Z"
+ . "\r\nSEQUENCE:2"
+ . "\r\nTRANSP:OPAQUE"
+ . "\r\nSTATUS:CONFIRMED"
+ . "\r\nDTEND:20190930T084500Z"
+ . "\r\nLOCATION:[London] London Eye"
+ . "\r\nSUMMARY:Test ICal method"
+ . "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
+ . "\r\n TRUE:MAILTO:attendee-test@example.com"
+ . "\r\nCLASS:PUBLIC"
+ . "\r\nDESCRIPTION:Some plain text"
+ . "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:test@example.com"
+ . "\r\nDTSTAMP:20190925T075546Z"
+ . "\r\nCREATED:20190925T075709Z"
+ . "\r\nLAST-MODIFIED:20190925T075546Z"
+ . "\r\nEND:VEVENT"
+ . "\r\nEND:VCALENDAR";
+ $this->buildBody();
+ $this->Mail->preSend();
+ $this->assertRegExp(
+ '/Content-Type: text\/calendar; method=REQUEST;/',
+ $this->Mail->getSentMIMEMessage(),
+ 'Wrong ICal method in Content-Type header'
+ );
+ }
+
+ /**
+ * Test ICal invalid method to use default (REQUEST)
+ */
+ public function testICalDefaultMethod()
+ {
+ $this->Mail->Subject .= ': ICal method';
+ $this->Mail->Body = 'ICal method test.
';
+ $this->Mail->AltBody = 'ICal method test.';
+ $this->Mail->Ical = 'BEGIN:VCALENDAR'
+ . "\r\nVERSION:2.0"
+ . "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
+ . "\r\nCALSCALE:GREGORIAN"
+ . "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
+ . "\r\nBEGIN:VEVENT"
+ . "\r\nUID:201909250755-42825@test"
+ . "\r\nDTSTART;20190930T080000Z"
+ . "\r\nSEQUENCE:2"
+ . "\r\nTRANSP:OPAQUE"
+ . "\r\nSTATUS:CONFIRMED"
+ . "\r\nDTEND:20190930T084500Z"
+ . "\r\nLOCATION:[London] London Eye"
+ . "\r\nSUMMARY:Test ICal method"
+ . "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
+ . "\r\n TRUE:MAILTO:attendee-test@example.com"
+ . "\r\nCLASS:PUBLIC"
+ . "\r\nDESCRIPTION:Some plain text"
+ . "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:test@example.com"
+ . "\r\nDTSTAMP:20190925T075546Z"
+ . "\r\nCREATED:20190925T075709Z"
+ . "\r\nLAST-MODIFIED:20190925T075546Z"
+ . "\r\nEND:VEVENT"
+ . "\r\nEND:VCALENDAR";
+ $this->buildBody();
+ $this->Mail->preSend();
+ $this->assertRegExp(
+ '/Content-Type: text\/calendar; method=REQUEST;/',
+ $this->Mail->getSentMIMEMessage(),
+ 'Wrong ICal method in Content-Type header'
+ );
+ }
}
/*
* This is a sample form for setting appropriate test values through a browser