diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php
index 638317165..b0b5d817f 100644
--- a/src/applications/calendar/application/PhabricatorCalendarApplication.php
+++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php
@@ -1,75 +1,75 @@
 <?php
 
 final class PhabricatorCalendarApplication extends PhabricatorApplication {
 
   public function getName() {
     return pht('Calendar');
   }
 
   public function getShortDescription() {
     return pht('Upcoming Events');
   }
 
   public function getFlavorText() {
     return pht('Never miss an episode ever again.');
   }
 
   public function getBaseURI() {
     return '/calendar/';
   }
 
   public function getFontIcon() {
     return 'fa-calendar';
   }
 
   public function getTitleGlyph() {
     // Unicode has a calendar character but it's in some distant code plane,
     // use "keyboard" since it looks vaguely similar.
     return "\xE2\x8C\xA8";
   }
 
   public function isPrototype() {
     return true;
   }
 
   public function getRemarkupRules() {
     return array(
       new PhabricatorCalendarRemarkupRule(),
     );
   }
 
   public function getRoutes() {
     return array(
       '/E(?P<id>[1-9]\d*)' => 'PhabricatorCalendarEventViewController',
       '/calendar/' => array(
         '' => 'PhabricatorCalendarViewController',
         'all/' => 'PhabricatorCalendarBrowseController',
         'event/' => array(
           '(?:query/(?P<queryKey>[^/]+)/)?'
             => 'PhabricatorCalendarEventListController',
           'create/'
             => 'PhabricatorCalendarEventEditController',
           'edit/(?P<id>[1-9]\d*)/'
             => 'PhabricatorCalendarEventEditController',
           'cancel/(?P<id>[1-9]\d*)/'
             => 'PhabricatorCalendarEventCancelController',
-          'join/(?P<id>[1-9]\d*)/'
+          '(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
             => 'PhabricatorCalendarEventJoinController',
         ),
       ),
     );
   }
 
   public function getQuickCreateItems(PhabricatorUser $viewer) {
     $items = array();
 
     $item = id(new PHUIListItemView())
       ->setName(pht('Calendar Event'))
       ->setIcon('fa-calendar')
       ->setHref($this->getBaseURI().'event/create/');
     $items[] = $item;
 
     return $items;
   }
 
 }
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
index 01875351b..cd72d03fd 100644
--- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
@@ -1,279 +1,277 @@
 <?php
 
 final class PhabricatorCalendarEventEditController
   extends PhabricatorCalendarController {
 
   private $id;
 
   public function willProcessRequest(array $data) {
     $this->id = idx($data, 'id');
   }
 
   public function isCreate() {
     return !$this->id;
   }
 
   public function processRequest() {
     $request = $this->getRequest();
     $user = $request->getUser();
     $user_phid = $user->getPHID();
     $error_name = true;
     $validation_exception = null;
 
     $start_time = id(new AphrontFormDateControl())
       ->setUser($user)
       ->setName('start')
       ->setLabel(pht('Start'))
       ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY);
 
     $end_time = id(new AphrontFormDateControl())
       ->setUser($user)
       ->setName('end')
       ->setLabel(pht('End'))
       ->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY);
 
     if ($this->isCreate()) {
       $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user);
       $end_value = $end_time->readValueFromRequest($request);
       $start_value = $start_time->readValueFromRequest($request);
       $submit_label = pht('Create');
       $filter = 'event/create/';
       $page_title = pht('Create Event');
       $redirect = 'created';
       $subscribers = array();
       $invitees = array($user_phid);
     } else {
       $event = id(new PhabricatorCalendarEventQuery())
         ->setViewer($user)
         ->withIDs(array($this->id))
         ->requireCapabilities(
           array(
             PhabricatorPolicyCapability::CAN_VIEW,
             PhabricatorPolicyCapability::CAN_EDIT,
           ))
         ->executeOne();
       if (!$event) {
         return new Aphront404Response();
       }
 
       $end_time->setValue($event->getDateTo());
       $start_time->setValue($event->getDateFrom());
       $submit_label = pht('Update');
       $filter       = 'event/edit/'.$event->getID().'/';
       $page_title   = pht('Update Event');
       $redirect     = 'updated';
 
       $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
         $event->getPHID());
+
       $invitees = array();
       foreach ($event->getInvitees() as $invitee) {
         if ($invitee->isUninvited()) {
           continue;
         } else {
           $invitees[] = $invitee->getInviteePHID();
         }
       }
     }
 
     $errors = array();
     if ($request->isFormPost()) {
       $xactions = array();
       $name = $request->getStr('name');
       $type = $request->getInt('status');
       $start_value = $start_time->readValueFromRequest($request);
       $end_value = $end_time->readValueFromRequest($request);
       $description = $request->getStr('description');
       $subscribers = $request->getArr('subscribers');
+
       $invitees = $request->getArr('invitees');
       $new_invitees = $this->getNewInviteeList($invitees, $event);
-
+      $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
       if ($this->isCreate()) {
         $status = idx($new_invitees, $user->getPHID());
-        $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
         if ($status) {
           $new_invitees[$user->getPHID()] = $status_attending;
         }
       }
 
       if ($start_time->getError()) {
         $errors[] = pht('Invalid start time; reset to default.');
       }
       if ($end_time->getError()) {
         $errors[] = pht('Invalid end time; reset to default.');
       }
       if (!$errors) {
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_NAME)
           ->setNewValue($name);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_START_DATE)
           ->setNewValue($start_value);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_END_DATE)
           ->setNewValue($end_value);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_STATUS)
           ->setNewValue($type);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorTransactions::TYPE_SUBSCRIBERS)
           ->setNewValue(array('=' => array_fuse($subscribers)));
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_INVITE)
           ->setNewValue($new_invitees);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION)
           ->setNewValue($description);
 
         $editor = id(new PhabricatorCalendarEventEditor())
           ->setActor($user)
           ->setContentSourceFromRequest($request)
           ->setContinueOnNoEffect(true);
 
         try {
           $xactions = $editor->applyTransactions($event, $xactions);
           $response = id(new AphrontRedirectResponse());
           return $response->setURI('/E'.$event->getID());
         } catch (PhabricatorApplicationTransactionValidationException $ex) {
           $validation_exception = $ex;
           $error_name = $ex
             ->getShortMessage(PhabricatorCalendarEventTransaction::TYPE_NAME);
         }
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = id(new PHUIInfoView())
         ->setTitle(pht('Status can not be set!'))
         ->setErrors($errors);
     }
 
     $name = id(new AphrontFormTextControl())
       ->setLabel(pht('Name'))
       ->setName('name')
       ->setValue($event->getName())
       ->setError($error_name);
 
     $status_select = id(new AphrontFormSelectControl())
       ->setLabel(pht('Status'))
       ->setName('status')
       ->setValue($event->getStatus())
       ->setOptions($event->getStatusOptions());
 
     $description = id(new AphrontFormTextAreaControl())
       ->setLabel(pht('Description'))
       ->setName('description')
       ->setValue($event->getDescription());
 
     $subscribers = id(new AphrontFormTokenizerControl())
       ->setLabel(pht('Subscribers'))
       ->setName('subscribers')
       ->setValue($subscribers)
       ->setUser($user)
       ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
 
     $invitees = id(new AphrontFormTokenizerControl())
       ->setLabel(pht('Invitees'))
       ->setName('invitees')
       ->setValue($invitees)
       ->setUser($user)
       ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
 
     $form = id(new AphrontFormView())
       ->setUser($user)
       ->appendChild($name)
       ->appendChild($status_select)
       ->appendChild($start_time)
       ->appendChild($end_time)
       ->appendControl($subscribers)
       ->appendControl($invitees)
       ->appendChild($description);
 
     $submit = id(new AphrontFormSubmitControl())
       ->setValue($submit_label);
     if ($this->isCreate()) {
       $submit->addCancelButton($this->getApplicationURI());
     } else {
       $submit->addCancelButton('/E'.$event->getID());
     }
 
     $form->appendChild($submit);
 
     $form_box = id(new PHUIObjectBoxView())
       ->setHeaderText($page_title)
       ->setFormErrors($errors)
       ->setForm($form);
 
     $nav = $this->buildSideNavView($event);
     $nav->selectFilter($filter);
 
     $crumbs = $this->buildApplicationCrumbs();
 
     if (!$this->isCreate()) {
       $crumbs->addTextCrumb('E'.$event->getId(), '/E'.$event->getId());
     }
 
     $crumbs->addTextCrumb($page_title);
 
     $object_box = id(new PHUIObjectBoxView())
       ->setHeaderText($page_title)
       ->setValidationException($validation_exception)
       ->appendChild($form);
 
     $nav->appendChild(
       array(
         $crumbs,
         $object_box,
       ));
 
     return $this->buildApplicationPage(
       $nav,
       array(
         'title' => $page_title,
       ));
   }
 
 
   public function getNewInviteeList(array $phids, $event) {
     $invitees = $event->getInvitees();
     $invitees = mpull($invitees, null, 'getInviteePHID');
     $invited_status = PhabricatorCalendarEventInvitee::STATUS_INVITED;
     $uninvited_status = PhabricatorCalendarEventInvitee::STATUS_UNINVITED;
     $phids = array_fuse($phids);
 
     $new = array();
     foreach ($phids as $phid) {
-      $old_invitee = idx($invitees, $phid);
-      if ($old_invitee) {
-        $old_status = $old_invitee->getStatus();
-        if ($old_status != $uninvited_status) {
-          continue;
-        }
+      $old_status = $event->getUserInviteStatus($phid);
+      if ($old_status != $uninvited_status) {
+        continue;
       }
       $new[$phid] = $invited_status;
     }
 
     foreach ($invitees as $invitee) {
       $deleted_invitee = !idx($phids, $invitee->getInviteePHID());
       if ($deleted_invitee) {
         $new[$invitee->getInviteePHID()] = $uninvited_status;
       }
     }
 
     return $new;
   }
 
 }
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php
index 59c955767..00a1a80bd 100644
--- a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php
@@ -1,74 +1,81 @@
 <?php
 
 final class PhabricatorCalendarEventJoinController
   extends PhabricatorCalendarController {
 
   private $id;
 
+  const ACTION_ACCEPT = 'accept';
+  const ACTION_DECLINE = 'decline';
+  const ACTION_JOIN = 'join';
+
   public function handleRequest(AphrontRequest $request) {
     $this->id = $request->getURIData('id');
+    $action = $request->getURIData('action');
+
     $request = $this->getRequest();
     $viewer = $request->getViewer();
     $declined_status = PhabricatorCalendarEventInvitee::STATUS_DECLINED;
     $attending_status = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
 
     $event = id(new PhabricatorCalendarEventQuery())
       ->setViewer($viewer)
       ->withIDs(array($this->id))
       ->executeOne();
 
     if (!$event) {
       return new Aphront404Response();
     }
 
     $cancel_uri = '/E'.$event->getID();
     $validation_exception = null;
 
     $is_attending = $event->getIsUserAttending($viewer->getPHID());
 
     if ($request->isFormPost()) {
       $new_status = null;
 
       if ($is_attending) {
         $new_status = array($viewer->getPHID() => $declined_status);
       } else {
         $new_status = array($viewer->getPHID() => $attending_status);
       }
 
       $xaction = id(new PhabricatorCalendarEventTransaction())
         ->setTransactionType(
           PhabricatorCalendarEventTransaction::TYPE_INVITE)
         ->setNewValue($new_status);
 
       $editor = id(new PhabricatorCalendarEventEditor())
         ->setActor($viewer)
         ->setContentSourceFromRequest($request)
         ->setContinueOnNoEffect(true)
         ->setContinueOnMissingFields(true);
 
       try {
         $editor->applyTransactions($event, array($xaction));
         return id(new AphrontRedirectResponse())->setURI($cancel_uri);
       } catch (PhabricatorApplicationTransactionValidationException $ex) {
         $validation_exception = $ex;
       }
     }
 
-    if (!$is_attending) {
+    if (($action == self::ACTION_JOIN && !$is_attending)
+      || $action == self::ACTION_ACCEPT) {
       $title = pht('Join Event');
       $paragraph = pht('Would you like to join this event?');
       $submit = pht('Join');
     } else {
       $title = pht('Decline Event');
       $paragraph = pht('Would you like to decline this event?');
       $submit = pht('Decline');
     }
 
     return $this->newDialog()
       ->setTitle($title)
       ->setValidationException($validation_exception)
       ->appendParagraph($paragraph)
       ->addCancelButton($cancel_uri)
       ->addSubmitButton($submit);
   }
 }
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
index d8de1fffb..0019ad071 100644
--- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
@@ -1,175 +1,203 @@
 <?php
 
 final class PhabricatorCalendarEventViewController
   extends PhabricatorCalendarController {
 
   private $id;
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function willProcessRequest(array $data) {
     $this->id = $data['id'];
   }
 
   public function processRequest() {
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $event = id(new PhabricatorCalendarEventQuery())
       ->setViewer($viewer)
       ->withIDs(array($this->id))
       ->executeOne();
     if (!$event) {
       return new Aphront404Response();
     }
 
     $title = 'E'.$event->getID();
     $page_title = $title.' '.$event->getName();
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($title, '/E'.$event->getID());
 
     $timeline = $this->buildTransactionTimeline(
       $event,
       new PhabricatorCalendarEventTransactionQuery());
 
     $header = $this->buildHeaderView($event);
     $actions = $this->buildActionView($event);
     $properties = $this->buildPropertyView($event);
 
     $properties->setActionList($actions);
     $box = id(new PHUIObjectBoxView())
       ->setHeader($header)
       ->addPropertyList($properties);
 
     return $this->buildApplicationPage(
       array(
         $crumbs,
         $box,
         $timeline,
       ),
       array(
         'title' => $page_title,
       ));
   }
 
   private function buildHeaderView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
+    $id = $event->getID();
+
     $is_cancelled = $event->getIsCancelled();
     $icon = $is_cancelled ? ('fa-times') : ('fa-calendar');
     $color = $is_cancelled ? ('grey') : ('green');
     $status = $is_cancelled ? ('Cancelled') : ('Active');
 
-    return id(new PHUIHeaderView())
+    $invite_status = $event->getUserInviteStatus($viewer->getPHID());
+    $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED;
+    $is_invite_pending = ($invite_status == $status_invited);
+
+    $header = id(new PHUIHeaderView())
       ->setUser($viewer)
       ->setHeader($event->getName())
       ->setStatus($icon, $color, $status)
       ->setPolicyObject($event);
+
+    if ($is_invite_pending) {
+      $decline_button = id(new PHUIButtonView())
+        ->setTag('a')
+        ->setIcon(id(new PHUIIconView())
+          ->setIconFont('fa-times grey'))
+        ->setHref($this->getApplicationURI("/event/decline/{$id}/"))
+        ->setWorkflow(true)
+        ->setText(pht('Decline'));
+
+      $accept_button = id(new PHUIButtonView())
+        ->setTag('a')
+        ->setIcon(id(new PHUIIconView())
+          ->setIconFont('fa-check green'))
+        ->setHref($this->getApplicationURI("/event/accept/{$id}/"))
+        ->setWorkflow(true)
+        ->setText(pht('Accept'));
+
+      $header->addActionLink($decline_button)
+        ->addActionLink($accept_button);
+    }
+    return $header;
   }
 
   private function buildActionView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
     $id = $event->getID();
     $is_cancelled = $event->getIsCancelled();
     $is_attending = $event->getIsUserAttending($viewer->getPHID());
 
     $actions = id(new PhabricatorActionListView())
       ->setObjectURI($this->getApplicationURI('event/'.$id.'/'))
       ->setUser($viewer)
       ->setObject($event);
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $event,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $actions->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Event'))
         ->setIcon('fa-pencil')
         ->setHref($this->getApplicationURI("event/edit/{$id}/"))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
     if ($is_attending) {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Decline Event'))
           ->setIcon('fa-user-times')
           ->setHref($this->getApplicationURI("event/join/{$id}/"))
           ->setWorkflow(true));
     } else {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Join Event'))
           ->setIcon('fa-user-plus')
           ->setHref($this->getApplicationURI("event/join/{$id}/"))
           ->setWorkflow(true));
     }
 
     if ($is_cancelled) {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Reinstate Event'))
           ->setIcon('fa-plus')
           ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     } else {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Cancel Event'))
           ->setIcon('fa-times')
           ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     }
 
     return $actions;
   }
 
   private function buildPropertyView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
 
     $properties = id(new PHUIPropertyListView())
       ->setUser($viewer)
       ->setObject($event);
 
     $properties->addProperty(
       pht('Starts'),
       phabricator_datetime($event->getDateFrom(), $viewer));
 
     $properties->addProperty(
       pht('Ends'),
       phabricator_datetime($event->getDateTo(), $viewer));
 
     $invitees = $event->getInvitees();
     $invitee_list = new PHUIStatusListView();
     foreach ($invitees as $invitee) {
       if ($invitee->isUninvited()) {
         continue;
       }
       $item = new PHUIStatusItemView();
       $invitee_phid = $invitee->getInviteePHID();
       $target = $viewer->renderHandle($invitee_phid);
-      $item->setNote($invitee->getStatus());
-      $item->setTarget($target);
+      $item->setNote($invitee->getStatus())
+        ->setTarget($target);
       $invitee_list->addItem($item);
     }
 
     $properties->addProperty(
       pht('Invitees'),
       $invitee_list);
 
     $properties->invokeWillRenderEvent();
 
     $properties->addSectionHeader(
       pht('Description'),
       PHUIPropertyListView::ICON_SUMMARY);
     $properties->addTextContent($event->getDescription());
 
     return $properties;
   }
 
 }