Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 110 additions & 2 deletions lib/Ajax/Imple/ItipRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @package IMP
*/

use Horde\Util\HordeString;
use Horde\Util\Variables;

/**
Expand Down Expand Up @@ -126,18 +127,29 @@ protected function _handle(Variables|Horde_Variables $vars)
break;

case 'update':
// vEvent reply.
// vEvent reply or counter-proposal.
// vTodo reply.
switch ($components[$key]->getType()) {
case 'vEvent':
if ($registry->hasMethod('calendar/updateAttendee')) {
try {
if ($tmp = $contents->getHeader()->getHeader('from')) {
$storeProposal = false;
try {
$storeProposal = strtoupper($vCal->getAttribute('METHOD')) === 'COUNTER';
} catch (Horde_Icalendar_Exception $e) {
}
$registry->call('calendar/updateAttendee', [
$components[$key],
$tmp->getAddressList(true)->first()->bare_address,
$storeProposal,
]);
$notification->push(_('Respondent Status Updated.'), 'horde.success');
$notification->push(
$storeProposal
? _('Counter proposal recorded.')
: _('Respondent Status Updated.'),
'horde.success'
);
$result = true;
}
} catch (Horde_Exception $e) {
Expand Down Expand Up @@ -168,6 +180,49 @@ protected function _handle(Variables|Horde_Variables $vars)
}
break;

case 'counter-accept':
if (isset($components[$key]) && $components[$key]->getType() == 'vEvent') {
$result = $this->_handlevEvent($key, $components, $mime_part);
if ($result && $registry->hasMethod('calendar/updateAttendee')) {
try {
if ($tmp = $contents->getHeader()->getHeader('from')) {
$registry->call('calendar/updateAttendee', [
$components[$key],
$tmp->getAddressList(true)->first()->bare_address,
true,
]);
}
} catch (Horde_Exception $e) {
$notification->push(sprintf(_('There was an error updating the event attendee state: %s'), $e->getMessage()), 'horde.warning');
}
}
} else {
$notification->push(_('This action is not supported.'), 'horde.warning');
}
break;

case 'counter-decline':
if (isset($components[$key]) && $components[$key]->getType() == 'vEvent') {
try {
$to = null;
if ($tmp = $contents->getHeader()->getHeader('from')) {
$to = $tmp->getAddressList(true)->first()->bare_address;
}
if (empty($to)) {
throw new Horde_Exception(_("Unable to determine attendee address."));
}
$this->_sendDeclineCounter($components[$key], $to, $vars->identity);
$notification->push(_('Decline counter sent.'), 'horde.success');
$result = true;
} catch (Horde_Exception $e) {
Horde::log($e, Horde_Log::ERR);
$notification->push(sprintf(_('Error sending decline counter: %s.'), $e->getMessage()), 'horde.error');
}
} else {
$notification->push(_('This action is not supported.'), 'horde.warning');
}
break;

case 'import':
case 'accept-import':
// vFreebusy reply.
Expand Down Expand Up @@ -463,6 +518,59 @@ protected function _handle(Variables|Horde_Variables $vars)
return $result;
}

/**
* Send a METHOD=DECLINECOUNTER response to an attendee.
*/
protected function _sendDeclineCounter(
Horde_Icalendar_Vevent $vevent,
$toAddress,
$identityId = null
) {
global $injector;

$identity = $injector->getInstance('IMP_Identity');
$identity->setDefault($identityId);
$from = $identity->getFromAddress();

$vCal = new Horde_Icalendar();
$vCal->setAttribute('PRODID', '-//The Horde Project//' . strval(Horde_Mime_Headers_UserAgent::create()) . '//EN');
$vCal->setAttribute('METHOD', 'DECLINECOUNTER');
$counterEvent = clone $vevent;
$counterEvent->setAttribute('DTSTAMP', new Horde_Date('now', 'UTC'));
$vCal->addComponent($counterEvent);

$body = new Horde_Mime_Part();
$body->setType('text/plain');
$body->setCharset('UTF-8');
$body->setContents(HordeString::wrap(_('Your proposed new time was declined by the organizer.'), 76));

$ics = new Horde_Mime_Part();
$ics->setType('text/calendar');
$ics->setCharset('UTF-8');
$ics->setContents($vCal->exportvCalendar());
$ics->setName('icalendar.ics');
$ics->setContentTypeParameter('METHOD', 'DECLINECOUNTER');

$mime = new Horde_Mime_Part();
$mime[] = $body;
$mime[] = $ics;

$headers = new Horde_Mime_Headers();
$headers->addHeaderOb(Horde_Core_Mime_Headers_Received::createHordeHop());
$headers->addHeaderOb(Horde_Mime_Headers_MessageId::create());
$headers->addHeaderOb(Horde_Mime_Headers_Date::create());
$headers->addHeader('From', $from);
$headers->addHeader('To', $toAddress);

$replyto = $identity->getValue('replyto_addr');
if (!empty($replyto) && !$from->match($replyto)) {
$headers->addHeader('Reply-To', $replyto);
}
$headers->addHeader('Subject', _('Decline Counter Proposal'));

$mime->send($toAddress, $headers, $injector->getInstance('IMP_Mail'));
}

protected function _handlevEvent($key, array $components, $mime_part)
{
global $notification, $registry;
Expand Down
26 changes: 26 additions & 0 deletions lib/Mime/Viewer/Itip.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,32 @@ protected function _vEvent($vevent, $id, $method = 'PUBLISH', $components = [])
}
break;

case 'COUNTER':
$desc = _('%s has proposed a new time for "%s".');
$sender = $this->_senderFromHeader();
if ($registry->hasMethod('calendar/updateAttendee')
&& $this->_autoUpdateReply(self::AUTO_UPDATE_EVENT_REPLY, $sender)) {
try {
$registry->call('calendar/updateAttendee', [
$vevent,
$sender,
true,
]);
$notification->push(_('Counter proposal recorded.'), 'horde.success');
} catch (Horde_Exception $e) {
$notification->push(sprintf(_('There was an error updating the event: %s'), $e->getMessage()), 'horde.error');
}
} elseif ($registry->hasMethod('calendar/updateAttendee')) {
$options['update'] = _('Record proposed new time');
}
if ($registry->hasMethod('calendar/replace')) {
$options['counter-accept'] = _('Accept proposed time');
}
if ($registry->hasMethod('calendar/updateAttendee')) {
$options['counter-decline'] = _('Decline proposed time');
}
break;

case 'CANCEL':
try {
$vevent->getAttributeSingle('RECURRENCE-ID');
Expand Down
4 changes: 3 additions & 1 deletion test/Imp/Stub/ItipRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* @subpackage UnitTests
*/

use Horde\Util\Variables;

/**
* Stub for testing the IMP Itip Imple handler.
*
Expand All @@ -26,7 +28,7 @@
*/
class Imp_Stub_Ajax_Imple_ItipRequest extends IMP_Ajax_Imple_ItipRequest
{
public function handle(Horde_Variables $vars)
public function handle(Horde_Variables|Variables $vars)
{
$this->_handle($vars);
}
Expand Down
Loading
Loading