Exemplo n.º 1
0
 function asString()
 {
     if (!empty($this->formatted)) {
         $xs = new XMLStringer(true);
         $xs->elementStart('poco:address');
         $xs->element('poco:formatted', null, common_xml_safe_str($this->formatted));
         $xs->elementEnd('poco:address');
         return $xs->getString();
     }
     return null;
 }
Exemplo n.º 2
0
 function asString()
 {
     $xs = new XMLStringer(true);
     $xs->elementStart('poco:urls');
     $xs->element('poco:type', null, $this->type);
     $xs->element('poco:value', null, $this->value);
     if (!empty($this->primary)) {
         $xs->element('poco:primary', null, 'true');
     }
     $xs->elementEnd('poco:urls');
     return $xs->getString();
 }
Exemplo n.º 3
0
 function addAuthor($name, $uri = null, $email = null)
 {
     $xs = new XMLStringer(true);
     $xs->elementStart('author');
     if (!empty($name)) {
         $xs->element('name', null, $name);
     } else {
         throw new Atom10FeedException(_('Author element must contain a name element.'));
     }
     if (isset($uri)) {
         $xs->element('uri', null, $uri);
     }
     if (isset($email)) {
         $xs->element('email', null, $email);
     }
     $xs->elementEnd('author');
     array_push($this->authors, $xs->getString());
 }
Exemplo n.º 4
0
 /**
  * extra information for XMPP messages, as defined by Twitter
  *
  * @param Profile $profile Profile of the sending user
  * @param Notice  $notice  Notice being sent
  *
  * @return string Extra information (Atom, HTML, addresses) in string format
  */
 protected function format_entry(Notice $notice)
 {
     $profile = $notice->getProfile();
     $entry = $notice->asAtomEntry(true, true);
     $xs = new XMLStringer();
     $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
     $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
     $xs->element('a', array('href' => $profile->profileurl), $profile->nickname);
     try {
         $parent = $notice->getParent();
         $orig_profile = $parent->getProfile();
         $orig_profurl = $orig_profile->getUrl();
         $xs->text(" => ");
         $xs->element('a', array('href' => $orig_profurl), $orig_profile->nickname);
         $xs->text(": ");
     } catch (InvalidUrlException $e) {
         $xs->text(sprintf(' => %s', $orig_profile->nickname));
     } catch (NoParentNoticeException $e) {
         $xs->text(": ");
     } catch (NoResultException $e) {
         // Parent notice was probably deleted.
         $xs->text(": ");
     }
     // FIXME: Why do we replace \t with ''? is it just to make it pretty? shouldn't whitespace be handled well...?
     $xs->raw(str_replace("\t", "", $notice->getRendered()));
     $xs->text(" ");
     $xs->element('a', array('href' => common_local_url('conversation', array('id' => $notice->conversation)) . '#notice-' . $notice->id), sprintf(_m('[%u]'), $notice->id));
     $xs->elementEnd('body');
     $xs->elementEnd('html');
     $html = $xs->getString();
     return $html . ' ' . $entry;
 }
Exemplo n.º 5
0
 public function toXML()
 {
     $xs = new XMLStringer();
     $xs->startXML();
     $xs->elementStart('XRD', array('xmlns' => XRD::XRD_NS));
     if ($this->host) {
         $xs->element('hm:Host', array('xmlns:hm' => XRD::HOST_META_NS), $this->host);
     }
     if ($this->expires) {
         $xs->element('Expires', null, $this->expires);
     }
     if ($this->subject) {
         $xs->element('Subject', null, $this->subject);
     }
     foreach ($this->alias as $alias) {
         $xs->element('Alias', null, $alias);
     }
     foreach ($this->links as $link) {
         $titles = array();
         if (isset($link['title'])) {
             $titles = $link['title'];
             unset($link['title']);
         }
         $xs->elementStart('Link', $link);
         foreach ($titles as $title) {
             $xs->element('Title', null, $title);
         }
         $xs->elementEnd('Link');
     }
     $xs->elementEnd('XRD');
     return $xs->getString();
 }
Exemplo n.º 6
0
 /**
  * Send an Activity Streams notification to the remote Salmon endpoint,
  * if so configured.
  *
  * @param Profile $actor  Actor who did the activity
  * @param string  $verb   Activity::SUBSCRIBE or Activity::JOIN
  * @param Object  $object object of the action; must define asActivityNoun($tag)
  */
 public function notify(Profile $actor, $verb, $object = null, $target = null)
 {
     if ($object == null) {
         $object = $this;
     }
     if (empty($this->salmonuri)) {
         return false;
     }
     $text = 'update';
     $id = TagURI::mint('%s:%s:%s', $verb, $actor->getURI(), common_date_iso8601(time()));
     // @todo FIXME: Consolidate all these NS settings somewhere.
     $attributes = array('xmlns' => Activity::ATOM, 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:media' => 'http://purl.org/syndication/atommedia');
     $entry = new XMLStringer();
     $entry->elementStart('entry', $attributes);
     $entry->element('id', null, $id);
     $entry->element('title', null, $text);
     $entry->element('summary', null, $text);
     $entry->element('published', null, common_date_w3dtf(common_sql_now()));
     $entry->element('activity:verb', null, $verb);
     $entry->raw($actor->asAtomAuthor());
     $entry->raw($actor->asActivityActor());
     $entry->raw($object->asActivityNoun('object'));
     if ($target != null) {
         $entry->raw($target->asActivityNoun('target'));
     }
     $entry->elementEnd('entry');
     $xml = $entry->getString();
     common_log(LOG_INFO, "Posting to Salmon endpoint {$this->salmonuri}: {$xml}");
     Salmon::post($this->salmonuri, $xml, $actor);
 }
Exemplo n.º 7
0
 /**
  * Create an <me:env> XML representation of the envelope.
  *
  * @return string representation of XML document
  */
 public function toXML()
 {
     $xs = new XMLStringer();
     $xs->startXML();
     $xs->elementStart('me:env', array('xmlns:me' => self::NS));
     $xs->element('me:data', array('type' => $this->data_type), $this->data);
     $xs->element('me:encoding', null, $this->encoding);
     $xs->element('me:alg', null, $this->alg);
     $xs->element('me:sig', null, $this->getSignature());
     $xs->elementEnd('me:env');
     $string = $xs->getString();
     return $string;
 }
Exemplo n.º 8
0
 /**
  * Send an Activity Streams notification to the remote Salmon endpoint,
  * if so configured.
  *
  * @param Profile $actor  Actor who did the activity
  * @param string  $verb   Activity::SUBSCRIBE or Activity::JOIN
  * @param Object  $object object of the action; must define asActivityNoun($tag)
  */
 public function notify($actor, $verb, $object = null, $target = null)
 {
     if (!$actor instanceof Profile) {
         $type = gettype($actor);
         if ($type == 'object') {
             $type = get_class($actor);
         }
         // TRANS: Server exception.
         // TRANS: %1$s is the method name the exception occured in, %2$s is the actor type.
         throw new ServerException(sprintf(_m('Invalid actor passed to %1$s: %2$s.'), __METHOD__, $type));
     }
     if ($object == null) {
         $object = $this;
     }
     if ($this->salmonuri) {
         $text = 'update';
         $id = TagURI::mint('%s:%s:%s', $verb, $actor->getURI(), common_date_iso8601(time()));
         // @todo FIXME: Consolidate all these NS settings somewhere.
         $attributes = array('xmlns' => Activity::ATOM, 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:media' => 'http://purl.org/syndication/atommedia');
         $entry = new XMLStringer();
         $entry->elementStart('entry', $attributes);
         $entry->element('id', null, $id);
         $entry->element('title', null, $text);
         $entry->element('summary', null, $text);
         $entry->element('published', null, common_date_w3dtf(common_sql_now()));
         $entry->element('activity:verb', null, $verb);
         $entry->raw($actor->asAtomAuthor());
         $entry->raw($actor->asActivityActor());
         $entry->raw($object->asActivityNoun('object'));
         if ($target != null) {
             $entry->raw($target->asActivityNoun('target'));
         }
         $entry->elementEnd('entry');
         $xml = $entry->getString();
         common_log(LOG_INFO, "Posting to Salmon endpoint {$this->salmonuri}: {$xml}");
         $salmon = new Salmon();
         // ?
         return $salmon->post($this->salmonuri, $xml, $actor);
     }
     return false;
 }
Exemplo n.º 9
0
 function asAtomEntry($namespace = false, $source = false, $author = true)
 {
     $profile = $this->getProfile();
     $xs = new XMLStringer(true);
     if ($namespace) {
         $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0');
     } else {
         $attrs = array();
     }
     $xs->elementStart('entry', $attrs);
     if ($source) {
         $xs->elementStart('source');
         $xs->element('id', null, $profile->profileurl);
         $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
         $xs->element('link', array('href' => $profile->profileurl));
         $user = User::staticGet('id', $profile->id);
         if (!empty($user)) {
             $atom_feed = common_local_url('ApiTimelineUser', array('format' => 'atom', 'id' => $profile->nickname));
             $xs->element('link', array('rel' => 'self', 'type' => 'application/atom+xml', 'href' => $profile->profileurl));
             $xs->element('link', array('rel' => 'license', 'href' => common_config('license', 'url')));
         }
         $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
         $xs->element('updated', null, common_date_w3dtf($this->created));
     }
     if ($source) {
         $xs->elementEnd('source');
     }
     $xs->element('title', null, common_xml_safe_str($this->content));
     if ($author) {
         $xs->raw($profile->asAtomAuthor());
         $xs->raw($profile->asActivityActor());
     }
     $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $this->bestUrl()));
     $xs->element('id', null, $this->uri);
     $xs->element('published', null, common_date_w3dtf($this->created));
     $xs->element('updated', null, common_date_w3dtf($this->created));
     if ($this->reply_to) {
         $reply_notice = Notice::staticGet('id', $this->reply_to);
         if (!empty($reply_notice)) {
             $xs->element('link', array('rel' => 'related', 'href' => $reply_notice->bestUrl()));
             $xs->element('thr:in-reply-to', array('ref' => $reply_notice->uri, 'href' => $reply_notice->bestUrl()));
         }
     }
     if (!empty($this->conversation)) {
         $conv = Conversation::staticGet('id', $this->conversation);
         if (!empty($conv)) {
             $xs->element('link', array('rel' => 'ostatus:conversation', 'href' => $conv->uri));
         }
     }
     $reply_ids = $this->getReplies();
     foreach ($reply_ids as $id) {
         $profile = Profile::staticGet('id', $id);
         if (!empty($profile)) {
             $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $profile->getUri()));
         }
     }
     $groups = $this->getGroups();
     foreach ($groups as $group) {
         $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $group->permalink()));
     }
     if (!empty($this->repeat_of)) {
         $repeat = Notice::staticGet('id', $this->repeat_of);
         if (!empty($repeat)) {
             $xs->element('ostatus:forward', array('ref' => $repeat->uri, 'href' => $repeat->bestUrl()));
         }
     }
     $xs->element('content', array('type' => 'html'), common_xml_safe_str($this->rendered));
     $tag = new Notice_tag();
     $tag->notice_id = $this->id;
     if ($tag->find()) {
         while ($tag->fetch()) {
             $xs->element('category', array('term' => $tag->tag));
         }
     }
     $tag->free();
     # Enclosures
     $attachments = $this->attachments();
     if ($attachments) {
         foreach ($attachments as $attachment) {
             $enclosure = $attachment->getEnclosure();
             if ($enclosure) {
                 $attributes = array('rel' => 'enclosure', 'href' => $enclosure->url, 'type' => $enclosure->mimetype, 'length' => $enclosure->size);
                 if ($enclosure->title) {
                     $attributes['title'] = $enclosure->title;
                 }
                 $xs->element('link', $attributes, null);
             }
         }
     }
     if (!empty($this->lat) && !empty($this->lon)) {
         $xs->element('georss:point', null, $this->lat . ' ' . $this->lon);
     }
     $xs->elementEnd('entry');
     return $xs->getString();
 }
Exemplo n.º 10
0
 /**
  * Send a summary email to the user
  *
  * @param mixed $object
  * @return boolean true on success, false on failure
  */
 function handle($user_id)
 {
     // Skip if they've asked not to get summaries
     $ess = Email_summary_status::staticGet('user_id', $user_id);
     if (!empty($ess) && !$ess->send_summary) {
         common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
         return true;
     }
     $since_id = null;
     if (!empty($ess)) {
         $since_id = $ess->last_summary_id;
     }
     $user = User::staticGet('id', $user_id);
     if (empty($user)) {
         common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
         return true;
     }
     if (empty($user->email)) {
         common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
         return true;
     }
     $profile = $user->getProfile();
     if (empty($profile)) {
         common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
         return true;
     }
     $stream = new InboxNoticeStream($user, $user->getProfile());
     $notice = $stream->getNotices(0, self::MAX_NOTICES, $since_id);
     if (empty($notice) || $notice->N == 0) {
         common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
         return true;
     }
     // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
     // figuring out a better way. -ESP
     $new_top = null;
     if ($notice instanceof ArrayWrapper) {
         $new_top = $notice->_items[0]->id;
     }
     // TRANS: Subject for e-mail.
     $subject = sprintf(_m('Your latest updates from %s'), common_config('site', 'name'));
     $out = new XMLStringer(true);
     $out->elementStart('html');
     $out->elementStart('head');
     $out->element('title', null, $subject);
     $out->elementEnd('head');
     $out->elementStart('body');
     $out->elementStart('div', array('width' => '100%', 'style' => 'background-color: #ffffff; border: 4px solid #4c609a; padding: 10px;'));
     $out->elementStart('div', array('style' => 'color: #ffffff; background-color: #4c609a; font-weight: bold; margin-bottom: 10px; padding: 4px;'));
     // TRANS: Text in e-mail summary.
     // TRANS: %1$s is the StatusNet sitename, %2$s is the recipient's profile name.
     $out->raw(sprintf(_m('Recent updates from %1$s for %2$s:'), common_config('site', 'name'), $profile->getBestName()));
     $out->elementEnd('div');
     $out->elementStart('table', array('width' => '550px', 'style' => 'border: none; border-collapse: collapse;', 'cellpadding' => '6'));
     while ($notice->fetch()) {
         $profile = Profile::staticGet('id', $notice->profile_id);
         if (empty($profile)) {
             continue;
         }
         $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
         $out->elementStart('tr');
         $out->elementStart('td', array('width' => AVATAR_STREAM_SIZE, 'height' => AVATAR_STREAM_SIZE, 'align' => 'left', 'valign' => 'top', 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
         $out->element('img', array('src' => $avatar ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE), 'width' => AVATAR_STREAM_SIZE, 'height' => AVATAR_STREAM_SIZE, 'alt' => $profile->getBestName()));
         $out->elementEnd('td');
         $out->elementStart('td', array('align' => 'left', 'valign' => 'top', 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
         $out->element('a', array('href' => $profile->profileurl), $profile->nickname);
         $out->text(' ');
         $out->raw($notice->rendered);
         $out->elementStart('div', array('style' => 'font-size: 0.8em; padding-top: 4px;'));
         $noticeurl = $notice->bestUrl();
         // above should always return an URL
         assert(!empty($noticeurl));
         $out->elementStart('a', array('rel' => 'bookmark', 'href' => $noticeurl));
         $dt = common_date_iso8601($notice->created);
         $out->element('abbr', array('style' => 'border-bottom: none;', 'title' => $dt), common_date_string($notice->created));
         $out->elementEnd('a');
         if ($notice->hasConversation()) {
             $conv = Conversation::staticGet('id', $notice->conversation);
             $convurl = $conv->uri;
             if (!empty($convurl)) {
                 $out->text(' ');
                 $out->element('a', array('href' => $convurl . '#notice-' . $notice->id), _m('in context'));
             }
         }
         $out->elementEnd('div');
         $out->elementEnd('td');
         $out->elementEnd('tr');
     }
     $out->elementEnd('table');
     // TRANS: Link text for link to e-mail settings.
     // TRANS: %1$s is a link to the e-mail settings, %2$s is the StatusNet sitename.
     $out->raw("<p>" . sprintf(_m('<a href="%1$s">change your email settings for %2$s</a>'), common_local_url('emailsettings'), common_config('site', 'name')) . "</p>");
     $out->elementEnd('div');
     $out->elementEnd('body');
     $out->elementEnd('html');
     $body = $out->getString();
     // FIXME: do something for people who don't like HTML email
     mail_to_user($user, $subject, $body, array('Content-Type' => 'text/html; charset=utf-8', 'Mime-Version' => '1.0'));
     if (empty($ess)) {
         $ess = new Email_summary_status();
         $ess->user_id = $user_id;
         $ess->created = common_sql_now();
         $ess->last_summary_id = $new_top;
         $ess->modified = common_sql_now();
         $ess->insert();
     } else {
         $orig = clone $ess;
         $ess->last_summary_id = $new_top;
         $ess->modified = common_sql_now();
         $ess->update($orig);
     }
     return true;
 }
Exemplo n.º 11
0
function common_at_hash_link($sender_id, $tag)
{
    $user = User::staticGet($sender_id);
    if (!$user) {
        return $tag;
    }
    $tagged = Profile_tag::getTagged($user->id, common_canonical_tag($tag));
    if ($tagged) {
        $url = common_local_url('subscriptions', array('nickname' => $user->nickname, 'tag' => $tag));
        $xs = new XMLStringer();
        $xs->elementStart('span', 'tag');
        $xs->element('a', array('href' => $url, 'rel' => $tag), $tag);
        $xs->elementEnd('span');
        return $xs->getString();
    } else {
        return $tag;
    }
}
Exemplo n.º 12
0
 /**
  * Create an <me:env> XML representation of the envelope.
  *
  * @return string representation of XML document
  */
 public function toXML(Profile $target = null, $flavour = null)
 {
     $xs = new XMLStringer();
     $xs->startXML();
     // header, to point out it's not HTML or anything...
     if (Event::handle('StartMagicEnvelopeToXML', array($this, $xs, $flavour, $target))) {
         // fall back to our default, normal Magic Envelope XML.
         // the $xs element _may_ have had elements added, or could get in the end event
         $xs->elementStart('me:env', array('xmlns:me' => self::NS));
         $xs->element('me:data', array('type' => $this->data_type), $this->data);
         $xs->element('me:encoding', null, $this->encoding);
         $xs->element('me:alg', null, $this->alg);
         $xs->element('me:sig', null, $this->getSignature());
         $xs->elementEnd('me:env');
         Event::handle('EndMagicEnvelopeToXML', array($this, $xs, $flavour, $target));
     }
     return $xs->getString();
 }
Exemplo n.º 13
0
 static function toHTML($profile, $question)
 {
     $notice = $question->getNotice();
     $out = new XMLStringer();
     $cls = array('qna_question');
     if (!empty($question->closed)) {
         $cls[] = 'closed';
     }
     $out->elementStart('p', array('class' => implode(' ', $cls)));
     if (!empty($question->description)) {
         $out->elementStart('span', 'question-description');
         $out->raw(common_render_text($question->description));
         $out->elementEnd('span');
     }
     $cnt = $question->countAnswers();
     if (!empty($cnt)) {
         $out->elementStart('span', 'answer-count');
         // TRANS: Number of given answers to a question.
         // TRANS: %s is the number of given answers.
         $out->text(sprintf(_m('%s answer', '%s answers', $cnt), $cnt));
         $out->elementEnd('span');
     }
     if (!empty($question->closed)) {
         $out->elementStart('span', 'question-closed');
         // TRANS: Notification that a question cannot be answered anymore because it is closed.
         $out->text(_m('This question is closed.'));
         $out->elementEnd('span');
     }
     $out->elementEnd('p');
     return $out->getString();
 }
Exemplo n.º 14
0
 function asString($tag = 'activity:object')
 {
     $xs = new XMLStringer(true);
     $xs->elementStart($tag);
     $xs->element('activity:object-type', null, $this->type);
     $xs->element(self::ID, null, $this->id);
     if (!empty($this->title)) {
         $xs->element(self::TITLE, null, common_xml_safe_str($this->title));
     }
     if (!empty($this->summary)) {
         $xs->element(self::SUMMARY, null, common_xml_safe_str($this->summary));
     }
     if (!empty($this->content)) {
         // XXX: assuming HTML content here
         $xs->element(ActivityUtils::CONTENT, array('type' => 'html'), common_xml_safe_str($this->content));
     }
     if (!empty($this->link)) {
         $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $this->link), null);
     }
     if ($this->type == ActivityObject::PERSON || $this->type == ActivityObject::GROUP) {
         foreach ($this->avatarLinks as $avatar) {
             $xs->element('link', array('rel' => 'avatar', 'type' => $avatar->type, 'media:width' => $avatar->width, 'media:height' => $avatar->height, 'href' => $avatar->url), null);
         }
     }
     if (!empty($this->geopoint)) {
         $xs->element('georss:point', null, $this->geopoint);
     }
     if (!empty($this->poco)) {
         $xs->raw($this->poco->asString());
     }
     $xs->elementEnd($tag);
     return $xs->getString();
 }
Exemplo n.º 15
0
 /**
  * extra information for XMPP messages, as defined by Twitter
  *
  * @param Profile $profile Profile of the sending user
  * @param Notice  $notice  Notice being sent
  *
  * @return string Extra information (Atom, HTML, addresses) in string format
  */
 protected function format_entry(Notice $notice)
 {
     $profile = $notice->getProfile();
     $entry = $notice->asAtomEntry(true, true);
     $xs = new XMLStringer();
     $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
     $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
     $xs->element('a', array('href' => $profile->profileurl), $profile->nickname);
     try {
         $parent = $notice->getParent();
         $orig_profile = $parent->getProfile();
         $orig_profurl = $orig_profile->getUrl();
         $xs->text(" => ");
         $xs->element('a', array('href' => $orig_profurl), $orig_profile->nickname);
         $xs->text(": ");
     } catch (InvalidUrlException $e) {
         $xs->text(sprintf(' => %s', $orig_profile->nickname));
     } catch (NoParentNoticeException $e) {
         $xs->text(": ");
     }
     if (!empty($notice->rendered)) {
         $notice->rendered = str_replace("\t", "", $notice->rendered);
         $xs->raw($notice->rendered);
     } else {
         $xs->raw(common_render_content($notice->content, $notice));
     }
     $xs->text(" ");
     $xs->element('a', array('href' => common_local_url('conversation', array('id' => $notice->conversation)) . '#notice-' . $notice->id), sprintf(_m('[%u]'), $notice->id));
     $xs->elementEnd('body');
     $xs->elementEnd('html');
     $html = $xs->getString();
     return $html . ' ' . $entry;
 }
Exemplo n.º 16
0
/**
 * extra information for XMPP messages, as defined by Twitter
 *
 * @param Profile $profile Profile of the sending user
 * @param Notice  $notice  Notice being sent
 *
 * @return string Extra information (Atom, HTML, addresses) in string format
 */
function jabber_format_entry($profile, $notice)
{
    $entry = $notice->asAtomEntry(true, true);
    $xs = new XMLStringer();
    $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
    $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
    $xs->element('a', array('href' => $profile->profileurl), $profile->nickname);
    $xs->text(": ");
    if (!empty($notice->rendered)) {
        $xs->raw($notice->rendered);
    } else {
        $xs->raw(common_render_content($notice->content, $notice));
    }
    $xs->text(" ");
    $xs->element('a', array('href' => common_local_url('conversation', array('id' => $notice->conversation)) . '#notice-' . $notice->id), sprintf(_('[%s]'), $notice->id));
    $xs->elementEnd('body');
    $xs->elementEnd('html');
    $html = $xs->getString();
    return $html . ' ' . $entry;
}
Exemplo n.º 17
0
 public function toXML($env)
 {
     $xs = new XMLStringer();
     $xs->startXML();
     $xs->elementStart('me:env', array('xmlns:me' => MagicEnvelope::NS));
     $xs->element('me:data', array('type' => $env['data_type']), $env['data']);
     $xs->element('me:encoding', null, $env['encoding']);
     $xs->element('me:alg', null, $env['alg']);
     $xs->element('me:sig', null, $env['sig']);
     $xs->elementEnd('me:env');
     $string = $xs->getString();
     common_debug($string);
     return $string;
 }
Exemplo n.º 18
0
 function asAtomEntry($namespace = false, $source = false, $author = true, $cur = null)
 {
     $profile = $this->getProfile();
     $xs = new XMLStringer(true);
     if ($namespace) {
         $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', 'xmlns:statusnet' => 'http://status.net/schema/api/1/');
     } else {
         $attrs = array();
     }
     if (Event::handle('StartActivityStart', array(&$this, &$xs, &$attrs))) {
         $xs->elementStart('entry', $attrs);
         Event::handle('EndActivityStart', array(&$this, &$xs, &$attrs));
     }
     if (Event::handle('StartActivitySource', array(&$this, &$xs))) {
         if ($source) {
             $atom_feed = $profile->getAtomFeed();
             if (!empty($atom_feed)) {
                 $xs->elementStart('source');
                 // XXX: we should store the actual feed ID
                 $xs->element('id', null, $atom_feed);
                 // XXX: we should store the actual feed title
                 $xs->element('title', null, $profile->getBestName());
                 $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $profile->profileurl));
                 $xs->element('link', array('rel' => 'self', 'type' => 'application/atom+xml', 'href' => $atom_feed));
                 $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
                 $notice = $profile->getCurrentNotice();
                 if (!empty($notice)) {
                     $xs->element('updated', null, self::utcDate($notice->created));
                 }
                 $user = User::staticGet('id', $profile->id);
                 if (!empty($user)) {
                     $xs->element('link', array('rel' => 'license', 'href' => common_config('license', 'url')));
                 }
                 $xs->elementEnd('source');
             }
         }
         Event::handle('EndActivitySource', array(&$this, &$xs));
     }
     $title = common_xml_safe_str($this->content);
     if (Event::handle('StartActivityTitle', array(&$this, &$xs, &$title))) {
         $xs->element('title', null, $title);
         Event::handle('EndActivityTitle', array($this, &$xs, $title));
     }
     $atomAuthor = '';
     if ($author) {
         $atomAuthor = $profile->asAtomAuthor($cur);
     }
     if (Event::handle('StartActivityAuthor', array(&$this, &$xs, &$atomAuthor))) {
         if (!empty($atomAuthor)) {
             $xs->raw($atomAuthor);
             Event::handle('EndActivityAuthor', array(&$this, &$xs, &$atomAuthor));
         }
     }
     $actor = '';
     if ($author) {
         $actor = $profile->asActivityActor();
     }
     if (Event::handle('StartActivityActor', array(&$this, &$xs, &$actor))) {
         if (!empty($actor)) {
             $xs->raw($actor);
             Event::handle('EndActivityActor', array(&$this, &$xs, &$actor));
         }
     }
     $url = $this->bestUrl();
     if (Event::handle('StartActivityLink', array(&$this, &$xs, &$url))) {
         $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $url));
         Event::handle('EndActivityLink', array(&$this, &$xs, $url));
     }
     $id = $this->uri;
     if (Event::handle('StartActivityId', array(&$this, &$xs, &$id))) {
         $xs->element('id', null, $id);
         Event::handle('EndActivityId', array(&$this, &$xs, $id));
     }
     $published = self::utcDate($this->created);
     if (Event::handle('StartActivityPublished', array(&$this, &$xs, &$published))) {
         $xs->element('published', null, $published);
         Event::handle('EndActivityPublished', array(&$this, &$xs, $published));
     }
     $updated = $published;
     // XXX: notices are usually immutable
     if (Event::handle('StartActivityUpdated', array(&$this, &$xs, &$updated))) {
         $xs->element('updated', null, $updated);
         Event::handle('EndActivityUpdated', array(&$this, &$xs, $updated));
     }
     $content = common_xml_safe_str($this->rendered);
     if (Event::handle('StartActivityContent', array(&$this, &$xs, &$content))) {
         $xs->element('content', array('type' => 'html'), $content);
         Event::handle('EndActivityContent', array(&$this, &$xs, $content));
     }
     // Most of our notices represent POSTing a NOTE. This is the default verb
     // for activity streams, so we normally just leave it out.
     $verb = ActivityVerb::POST;
     if (Event::handle('StartActivityVerb', array(&$this, &$xs, &$verb))) {
         $xs->element('activity:verb', null, $verb);
         Event::handle('EndActivityVerb', array(&$this, &$xs, $verb));
     }
     // We use the default behavior for activity streams: if there's no activity:object,
     // then treat the entry itself as the object. Here, you can set the type of that object,
     // which is normally a NOTE.
     $type = ActivityObject::NOTE;
     if (Event::handle('StartActivityDefaultObjectType', array(&$this, &$xs, &$type))) {
         $xs->element('activity:object-type', null, $type);
         Event::handle('EndActivityDefaultObjectType', array(&$this, &$xs, $type));
     }
     // Since we usually use the entry itself as an object, we don't have an explicit
     // object. Some extensions may want to add them (for photo, event, music, etc.).
     $objects = array();
     if (Event::handle('StartActivityObjects', array(&$this, &$xs, &$objects))) {
         foreach ($objects as $object) {
             $xs->raw($object->asString());
         }
         Event::handle('EndActivityObjects', array(&$this, &$xs, $objects));
     }
     $noticeInfoAttr = array('local_id' => $this->id);
     // local notice ID (useful to clients for ordering)
     $ns = $this->getSource();
     if (!empty($ns)) {
         $noticeInfoAttr['source'] = $ns->code;
         if (!empty($ns->url)) {
             $noticeInfoAttr['source_link'] = $ns->url;
             if (!empty($ns->name)) {
                 $noticeInfoAttr['source'] = '<a href="' . htmlspecialchars($ns->url) . '" rel="nofollow">' . htmlspecialchars($ns->name) . '</a>';
             }
         }
     }
     if (!empty($cur)) {
         $noticeInfoAttr['favorite'] = $cur->hasFave($this) ? "true" : "false";
         $profile = $cur->getProfile();
         $noticeInfoAttr['repeated'] = $profile->hasRepeated($this->id) ? "true" : "false";
     }
     if (!empty($this->repeat_of)) {
         $noticeInfoAttr['repeat_of'] = $this->repeat_of;
     }
     if (Event::handle('StartActivityNoticeInfo', array(&$this, &$xs, &$noticeInfoAttr))) {
         $xs->element('statusnet:notice_info', $noticeInfoAttr, null);
         Event::handle('EndActivityNoticeInfo', array(&$this, &$xs, $noticeInfoAttr));
     }
     $replyNotice = null;
     if ($this->reply_to) {
         $replyNotice = Notice::staticGet('id', $this->reply_to);
     }
     if (Event::handle('StartActivityInReplyTo', array(&$this, &$xs, &$replyNotice))) {
         if (!empty($replyNotice)) {
             $xs->element('link', array('rel' => 'related', 'href' => $replyNotice->bestUrl()));
             $xs->element('thr:in-reply-to', array('ref' => $replyNotice->uri, 'href' => $replyNotice->bestUrl()));
             Event::handle('EndActivityInReplyTo', array(&$this, &$xs, $replyNotice));
         }
     }
     $conv = null;
     if (!empty($this->conversation)) {
         $conv = Conversation::staticGet('id', $this->conversation);
     }
     if (Event::handle('StartActivityConversation', array(&$this, &$xs, &$conv))) {
         if (!empty($conv)) {
             $xs->element('link', array('rel' => 'ostatus:conversation', 'href' => $conv->uri));
         }
         Event::handle('EndActivityConversation', array(&$this, &$xs, $conv));
     }
     $replyProfiles = array();
     $reply_ids = $this->getReplies();
     foreach ($reply_ids as $id) {
         $profile = Profile::staticGet('id', $id);
         if (!empty($profile)) {
             $replyProfiles[] = $profile;
         }
     }
     if (Event::handle('StartActivityAttentionProfiles', array(&$this, &$xs, &$replyProfiles))) {
         foreach ($replyProfiles as $profile) {
             $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $profile->getUri()));
             $xs->element('link', array('rel' => 'mentioned', 'href' => $profile->getUri()));
         }
         Event::handle('EndActivityAttentionProfiles', array(&$this, &$xs, $replyProfiles));
     }
     $groups = $this->getGroups();
     if (Event::handle('StartActivityAttentionGroups', array(&$this, &$xs, &$groups))) {
         foreach ($groups as $group) {
             $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $group->permalink()));
             $xs->element('link', array('rel' => 'mentioned', 'href' => $group->permalink()));
         }
         Event::handle('EndActivityAttentionGroups', array(&$this, &$xs, $groups));
     }
     $repeat = null;
     if (!empty($this->repeat_of)) {
         $repeat = Notice::staticGet('id', $this->repeat_of);
     }
     if (Event::handle('StartActivityForward', array(&$this, &$xs, &$repeat))) {
         if (!empty($repeat)) {
             $xs->element('ostatus:forward', array('ref' => $repeat->uri, 'href' => $repeat->bestUrl()));
         }
         Event::handle('EndActivityForward', array(&$this, &$xs, $repeat));
     }
     $tags = $this->getTags();
     if (Event::handle('StartActivityCategories', array(&$this, &$xs, &$tags))) {
         foreach ($tags as $tag) {
             $xs->element('category', array('term' => $tag));
         }
         Event::handle('EndActivityCategories', array(&$this, &$xs, $tags));
     }
     // Enclosures
     $enclosures = array();
     $attachments = $this->attachments();
     foreach ($attachments as $attachment) {
         $enclosure = $attachment->getEnclosure();
         if ($enclosure) {
             $enclosures[] = $enclosure;
         }
     }
     if (Event::handle('StartActivityEnclosures', array(&$this, &$xs, &$enclosures))) {
         foreach ($enclosures as $enclosure) {
             $attributes = array('rel' => 'enclosure', 'href' => $enclosure->url, 'type' => $enclosure->mimetype, 'length' => $enclosure->size);
             if ($enclosure->title) {
                 $attributes['title'] = $enclosure->title;
             }
             $xs->element('link', $attributes, null);
         }
         Event::handle('EndActivityEnclosures', array(&$this, &$xs, $enclosures));
     }
     $lat = $this->lat;
     $lon = $this->lon;
     if (Event::handle('StartActivityGeo', array(&$this, &$xs, &$lat, &$lon))) {
         if (!empty($lat) && !empty($lon)) {
             $xs->element('georss:point', null, $lat . ' ' . $lon);
         }
         Event::handle('EndActivityGeo', array(&$this, &$xs, $lat, $lon));
     }
     if (Event::handle('StartActivityEnd', array(&$this, &$xs))) {
         $xs->elementEnd('entry');
         Event::handle('EndActivityEnd', array(&$this, &$xs));
     }
     return $xs->getString();
 }
Exemplo n.º 19
0
 /**
  * show the notice location
  *
  * shows the notice location in the correct language.
  *
  * If an URL is available, makes a link. Otherwise, just a span.
  *
  * @return void
  */
 function showNoticeLocation()
 {
     $id = $this->notice->id;
     $location = $this->notice->getLocation();
     if (empty($location)) {
         return;
     }
     $name = $location->getName();
     $lat = $this->notice->lat;
     $lon = $this->notice->lon;
     $latlon = !empty($lat) && !empty($lon) ? $lat . ';' . $lon : '';
     if (empty($name)) {
         $latdms = $this->decimalDegreesToDMS(abs($lat));
         $londms = $this->decimalDegreesToDMS(abs($lon));
         // TRANS: Used in coordinates as abbreviation of north
         $north = _('N');
         // TRANS: Used in coordinates as abbreviation of south
         $south = _('S');
         // TRANS: Used in coordinates as abbreviation of east
         $east = _('E');
         // TRANS: Used in coordinates as abbreviation of west
         $west = _('W');
         $name = sprintf(_('%1$u°%2$u\'%3$u"%4$s %5$u°%6$u\'%7$u"%8$s'), $latdms['deg'], $latdms['min'], $latdms['sec'], $lat > 0 ? $north : $south, $londms['deg'], $londms['min'], $londms['sec'], $lon > 0 ? $east : $west);
     }
     $url = $location->getUrl();
     $this->out->text(' ');
     $this->out->elementStart('span', array('class' => 'location'));
     $this->out->text(_('at'));
     $this->out->text(' ');
     if (empty($url)) {
         $this->out->element('abbr', array('class' => 'geo', 'title' => $latlon), $name);
     } else {
         $xstr = new XMLStringer(false);
         $xstr->elementStart('a', array('href' => $url, 'rel' => 'external'));
         $xstr->element('abbr', array('class' => 'geo', 'title' => $latlon), $name);
         $xstr->elementEnd('a');
         $this->out->raw($xstr->getString());
     }
     $this->out->elementEnd('span');
 }
Exemplo n.º 20
0
 /**
  * Returns an XML string fragment with limited profile information
  * as an Atom <author> element.
  *
  * Assumes that Atom has been previously set up as the base namespace.
  *
  * @param Profile $cur the current authenticated user
  *
  * @return string
  */
 function asAtomAuthor($cur = null)
 {
     $xs = new XMLStringer(true);
     $xs->elementStart('author');
     $xs->element('name', null, $this->nickname);
     $xs->element('uri', null, $this->getUri());
     if ($cur != null) {
         $attrs = array();
         $attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false';
         $attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false';
         $xs->element('statusnet:profile_info', $attrs, null);
     }
     $xs->elementEnd('author');
     return $xs->getString();
 }
Exemplo n.º 21
0
function common_tag_link($tag)
{
    $canonical = common_canonical_tag($tag);
    if (common_config('singleuser', 'enabled')) {
        // regular TagAction isn't set up in 1user mode
        $nickname = User::singleUserNickname();
        $url = common_local_url('showstream', array('nickname' => $nickname, 'tag' => $canonical));
    } else {
        $url = common_local_url('tag', array('tag' => $canonical));
    }
    $xs = new XMLStringer();
    $xs->elementStart('span', 'tag');
    $xs->element('a', array('href' => $url, 'rel' => 'tag'), $tag);
    $xs->elementEnd('span');
    return $xs->getString();
}
Exemplo n.º 22
0
 function asString($namespace = false)
 {
     $xs = new XMLStringer(true);
     if ($namespace) {
         $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:media' => 'http://purl.org/syndication/atommedia');
     } else {
         $attrs = array();
     }
     $xs->elementStart('entry', $attrs);
     $xs->element('id', null, $this->id);
     $xs->element('title', null, $this->title);
     $xs->element('published', null, common_date_iso8601($this->time));
     $xs->element('content', array('type' => 'html'), $this->content);
     if (!empty($this->summary)) {
         $xs->element('summary', null, $this->summary);
     }
     if (!empty($this->link)) {
         $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html'), $this->link);
     }
     // XXX: add context
     $xs->elementStart('author');
     $xs->element('uri', array(), $this->actor->id);
     if ($this->actor->title) {
         $xs->element('name', array(), $this->actor->title);
     }
     $xs->elementEnd('author');
     $xs->raw($this->actor->asString('activity:actor'));
     $xs->element('activity:verb', null, $this->verb);
     if (!empty($this->objects)) {
         foreach ($this->objects as $object) {
             $xs->raw($object->asString());
         }
     }
     if ($this->target) {
         $xs->raw($this->target->asString('activity:target'));
     }
     foreach ($this->categories as $cat) {
         $xs->raw($cat->asString());
     }
     $xs->elementEnd('entry');
     return $xs->getString();
 }
Exemplo n.º 23
0
function common_group_link($sender_id, $nickname)
{
    $sender = Profile::staticGet($sender_id);
    $group = User_group::getForNickname($nickname, $sender);
    if ($sender && $group && $sender->isMember($group)) {
        $attrs = array('href' => $group->permalink(), 'class' => 'url');
        if (!empty($group->fullname)) {
            $attrs['title'] = $group->fullname . ' (' . $group->nickname . ')';
        }
        $xs = new XMLStringer();
        $xs->elementStart('span', 'vcard');
        $xs->elementStart('a', $attrs);
        $xs->element('span', 'fn nickname', $nickname);
        $xs->elementEnd('a');
        $xs->elementEnd('span');
        return $xs->getString();
    } else {
        return $nickname;
    }
}
Exemplo n.º 24
0
 static function toHTML($profile, $question, $answer)
 {
     $notice = $question->getNotice();
     $out = new XMLStringer();
     $cls = array('qna_answer');
     if (!empty($answer->best)) {
         $cls[] = 'best';
     }
     $out->elementStart('p', array('class' => implode(' ', $cls)));
     $out->elementStart('span', 'answer-content');
     $out->raw(common_render_text($answer->content));
     $out->elementEnd('span');
     if (!empty($answer->revisions)) {
         $out->elementstart('span', 'answer-revisions');
         $out->text(htmlspecialchars(sprintf(_m('%s revision', '%s revisions', $answer->revisions), $answer->revisions)));
         $out->elementEnd('span');
     }
     $out->elementEnd('p');
     return $out->getString();
 }
Exemplo n.º 25
0
 function asAtomAuthor()
 {
     $xs = new XMLStringer(true);
     $xs->elementStart('author');
     $xs->element('name', null, $this->nickname);
     $xs->element('uri', null, $this->permalink());
     $xs->elementEnd('author');
     return $xs->getString();
 }
Exemplo n.º 26
0
 public function onStartMagicEnvelopeToXML(MagicEnvelope $magic_env, XMLStringer $xs, $flavour = null, Profile $target = null)
 {
     // Since Diaspora doesn't use a separate namespace for their "extended"
     // salmon slap, we'll have to resort to this workaround hack.
     if ($flavour !== 'diaspora') {
         return true;
     }
     // WARNING: This changes the $magic_env contents! Be aware of it.
     /**
      * https://wiki.diasporafoundation.org/Federation_protocol_overview
      * http://www.rubydoc.info/github/Raven24/diaspora-federation/master/DiasporaFederation/Salmon/EncryptedSlap
      *
      * Constructing the encryption header
      */
     // For some reason diaspora wants the salmon slap in a <diaspora> header.
     $xs->elementStart('diaspora', array('xmlns' => 'https://joindiaspora.com/protocol'));
     /**
      * Choose an AES key and initialization vector, suitable for the
      * aes-256-cbc cipher. I shall refer to this as the “inner key”
      * and the “inner initialization vector (iv)”.
      */
     $inner_key = new Crypt_AES(CRYPT_AES_MODE_CBC);
     $inner_key->setKeyLength(256);
     // set length to 256 bits (could be calculated, but let's be sure)
     $inner_key->setKey(common_random_rawstr(32));
     // 32 bytes from a (pseudo) random source
     $inner_key->setIV(common_random_rawstr(16));
     // 16 bytes is the block length
     /**
      * Construct the following XML snippet:
      *  <decrypted_header>
      *      <iv>((base64-encoded inner iv))</iv>
      *      <aes_key>((base64-encoded inner key))</aes_key>
      *      <author>
      *          <name>Alice Exampleman</name>
      *          <uri>acct:user@sender.example</uri>
      *      </author>
      *  </decrypted_header>
      */
     $decrypted_header = sprintf('<decrypted_header><iv>%1$s</iv><aes_key>%2$s</aes_key><author_id>%3$s</author_id></decrypted_header>', base64_encode($inner_key->iv), base64_encode($inner_key->key), $magic_env->getActor()->getAcctUri());
     /**
      * Construct another AES key and initialization vector suitable
      * for the aes-256-cbc cipher. I shall refer to this as the
      * “outer key” and the “outer initialization vector (iv)”.
      */
     $outer_key = new Crypt_AES(CRYPT_AES_MODE_CBC);
     $outer_key->setKeyLength(256);
     // set length to 256 bits (could be calculated, but let's be sure)
     $outer_key->setKey(common_random_rawstr(32));
     // 32 bytes from a (pseudo) random source
     $outer_key->setIV(common_random_rawstr(16));
     // 16 bytes is the block length
     /**
      * Encrypt your <decrypted_header> XML snippet using the “outer key”
      * and “outer iv” (using the aes-256-cbc cipher). This encrypted
      * blob shall be referred to as “the ciphertext”. 
      */
     $ciphertext = $outer_key->encrypt($decrypted_header);
     /**
      * Construct the following JSON object, which shall be referred to
      * as “the outer aes key bundle”:
      *  {
      *      "iv": ((base64-encoded AES outer iv)),
      *      "key": ((base64-encoded AES outer key))
      *  }
      */
     $outer_bundle = json_encode(array('iv' => base64_encode($outer_key->iv), 'key' => base64_encode($outer_key->key)));
     /**
      * Encrypt the “outer aes key bundle” with Bob’s RSA public key.
      * I shall refer to this as the “encrypted outer aes key bundle”.
      */
     common_debug('Diaspora creating "outer aes key bundle", will require magic-public-key');
     $key_fetcher = new MagicEnvelope();
     $remote_keys = $key_fetcher->getKeyPair($target, true);
     // actually just gets the public key
     $enc_outer = $remote_keys->publicKey->encrypt($outer_bundle);
     /**
      * Construct the following JSON object, which I shall refer to as
      * the “encrypted header json object”:
      *  {
      *      "aes_key": ((base64-encoded encrypted outer aes key bundle)),
      *      "ciphertext": ((base64-encoded ciphertextm from above))
      *  }
      */
     $enc_header = json_encode(array('aes_key' => base64_encode($enc_outer), 'ciphertext' => base64_encode($ciphertext)));
     /**
      * Construct the xml snippet:
      *  <encrypted_header>((base64-encoded encrypted header json object))</encrypted_header>
      */
     $xs->element('encrypted_header', null, base64_encode($enc_header));
     /**
      * In order to prepare the payload message for inclusion in your
      * salmon slap, you will:
      *
      * 1. Encrypt the payload message using the aes-256-cbc cipher and
      *      the “inner encryption key” and “inner encryption iv” you
      *      chose earlier.
      * 2. Base64-encode the encrypted payload message.
      */
     $payload = $inner_key->encrypt($magic_env->getData());
     //FIXME: This means we don't actually put an <atom:entry> in the payload,
     // since Diaspora has its own update method! Silly me. Read up on:
     // https://wiki.diasporafoundation.org/Federation_Message_Semantics
     $magic_env->signMessage(base64_encode($payload), 'application/xml');
     // Since we have to change the content of me:data we'll just write the
     // whole thing from scratch. We _could_ otherwise have just manipulated
     // that element and added the encrypted_header in the EndMagicEnvelopeToXML event.
     $xs->elementStart('me:env', array('xmlns:me' => MagicEnvelope::NS));
     $xs->element('me:data', array('type' => $magic_env->getDataType()), $magic_env->getData());
     $xs->element('me:encoding', null, $magic_env->getEncoding());
     $xs->element('me:alg', null, $magic_env->getSignatureAlgorithm());
     $xs->element('me:sig', null, $magic_env->getSignature());
     $xs->elementEnd('me:env');
     $xs->elementEnd('entry');
     return false;
 }