Esempio n. 1
0
 /**
  * For initializing members of the class.
  *
  * @param array $argarray misc. arguments
  *
  * @return boolean true
  */
 function prepare($argarray)
 {
     parent::prepare($argarray);
     // User must be logged in.
     $user = common_current_user();
     if (empty($user)) {
         throw new ClientException(_("You must be logged in to train spam."), 403);
     }
     // User must have the right to review spam
     if (!$user->hasRight(ActivitySpamPlugin::TRAINSPAM)) {
         throw new ClientException(_('You cannot review spam on this site.'), 403);
     }
     $id = $this->trimmed('notice');
     $this->notice = Notice::getKV('id', $id);
     if (empty($this->notice)) {
         throw new ClientException(_("No such notice."));
     }
     $this->checkSessionToken();
     $filter = null;
     Event::handle('GetSpamFilter', array(&$filter));
     if (empty($filter)) {
         throw new ServerException(_("No spam filter configured."));
     }
     $this->filter = $filter;
     $this->category = $this->trimmed('category');
     if ($this->category !== SpamFilter::SPAM && $this->category !== SpamFilter::HAM) {
         throw new ClientException(_("No such category."));
     }
     return true;
 }
Esempio n. 2
0
 /**
  * Class handler.
  *
  * @param array $args query arguments
  *
  * @return void
  */
 function handle($args)
 {
     parent::handle($args);
     $profile = AnonymousFavePlugin::getAnonProfile();
     if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
         // TRANS: Client error.
         $this->clientError(_m('Could not favor notice! Please make sure your browser has cookies enabled.'));
     }
     $id = $this->trimmed('notice');
     $notice = Notice::getKV($id);
     $token = $this->checkSessionToken();
     // Throws exception
     $stored = Fave::addNew($profile, $notice);
     if ($this->boolean('ajax')) {
         $this->startHTML('text/xml;charset=utf-8');
         $this->elementStart('head');
         // TRANS: Title.
         $this->element('title', null, _m('Disfavor favorite'));
         $this->elementEnd('head');
         $this->elementStart('body');
         $disfavor = new AnonDisFavorForm($this, $notice);
         $disfavor->show();
         $this->elementEnd('body');
         $this->endHTML();
     } else {
         $this->returnToPrevious();
     }
 }
Esempio n. 3
0
 /**
  * constructor
  *
  * Also initializes the profile attribute.
  *
  * @param Notice $notice The notice we'll display
  */
 function __construct(Notice $notice, Action $out = null, array $prefs = array())
 {
     parent::__construct($out);
     if (!empty($notice->repeat_of)) {
         $original = Notice::getKV('id', $notice->repeat_of);
         if (!$original instanceof Notice) {
             // could have been deleted
             $this->notice = $notice;
         } else {
             $this->notice = $original;
             $this->repeat = $notice;
         }
     } else {
         $this->notice = $notice;
     }
     $this->profile = $this->notice->getProfile();
     // integer preferences
     foreach (array('maxchars') as $key) {
         if (array_key_exists($key, $prefs)) {
             $this->{$key} = (int) $prefs[$key];
         }
     }
     // boolean preferences
     foreach (array('addressees', 'attachments', 'options') as $key) {
         if (array_key_exists($key, $prefs)) {
             $this->{$key} = (bool) $prefs[$key];
         }
     }
     // string preferences
     foreach (array('id_prefix', 'item_tag') as $key) {
         if (array_key_exists($key, $prefs)) {
             $this->{$key} = $prefs[$key];
         }
     }
 }
Esempio n. 4
0
 /**
  * Look up a notice from an argument, by poster's name to get last post
  * or notice_id prefixed with #.
  *
  * @return Notice
  * @throws CommandException
  */
 function getNotice($arg)
 {
     $notice = null;
     if (Event::handle('StartCommandGetNotice', array($this, $arg, &$notice))) {
         if (substr($this->other, 0, 1) == '#') {
             // A specific notice_id #123
             $notice = Notice::getKV(substr($arg, 1));
             if (!$notice) {
                 // TRANS: Command exception text shown when a notice ID is requested that does not exist.
                 throw new CommandException(_('Notice with that id does not exist.'));
             }
         }
         if (Validate::uri($this->other)) {
             // A specific notice by URI lookup
             $notice = Notice::getKV('uri', $arg);
         }
         if (!$notice) {
             // Local or remote profile name to get their last notice.
             // May throw an exception and report 'no such user'
             $recipient = $this->getProfile($arg);
             $notice = $recipient->getCurrentNotice();
             if (!$notice) {
                 // TRANS: Command exception text shown when a last user notice is requested and it does not exist.
                 throw new CommandException(_('User has no last notice.'));
             }
         }
     }
     Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
     if (!$notice) {
         // TRANS: Command exception text shown when a notice ID is requested that does not exist.
         throw new CommandException(_('Notice with that id does not exist.'));
     }
     return $notice;
 }
 function handle($notice)
 {
     assert($notice instanceof Notice);
     $this->notice = $notice;
     $this->user = User::getKV('id', $notice->profile_id);
     try {
         $profile = $this->notice->getProfile();
     } catch (Exception $e) {
         common_log(LOG_ERR, "Can't get profile for notice; skipping: " . $e->getMessage());
         return true;
     }
     if ($notice->isLocal()) {
         // Notices generated on remote sites will have already
         // been pushed to user's subscribers by their origin sites.
         $this->pushUser();
     }
     foreach ($notice->getGroups() as $group) {
         $oprofile = Ostatus_profile::getKV('group_id', $group->id);
         if ($oprofile) {
             // remote group
             if ($notice->isLocal()) {
                 $this->pingReply($oprofile);
             }
         } else {
             // local group
             $this->pushGroup($group->id);
         }
     }
     if ($notice->isLocal()) {
         // Notices generated on other sites will have already
         // pinged their reply-targets.
         foreach ($notice->getReplies() as $profile_id) {
             $oprofile = Ostatus_profile::getKV('profile_id', $profile_id);
             if ($oprofile) {
                 $this->pingReply($oprofile);
             }
         }
         if (!empty($this->notice->reply_to)) {
             $replyTo = Notice::getKV('id', $this->notice->reply_to);
             if (!empty($replyTo)) {
                 foreach ($replyTo->getReplies() as $profile_id) {
                     $oprofile = Ostatus_profile::getKV('profile_id', $profile_id);
                     if ($oprofile) {
                         $this->pingReply($oprofile);
                     }
                 }
             }
         }
         foreach ($notice->getProfileTags() as $ptag) {
             $oprofile = Ostatus_profile::getKV('peopletag_id', $ptag->id);
             if (!$oprofile) {
                 $this->pushPeopletag($ptag);
             }
         }
     }
     return true;
 }
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  */
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     $id = $this->trimmed('id');
     $this->original = Notice::getKV('id', $id);
     if (!$this->original instanceof Notice) {
         // TRANS: Client error displayed trying to repeat a non-existing notice through the API.
         $this->clientError(_('No such notice.'), 400, $this->format);
     }
     return true;
 }
Esempio n. 7
0
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     $args = $this->returnToArgs();
     $this->photoid = $args[1]['photoid'];
     $this->photo = GNUsocialPhoto::getKV('id', $this->photoid);
     $this->notice = Notice::getKV('id', $this->photo->notice_id);
     $this->user = Profile::getKV('id', $this->notice->profile_id);
     $this->conv = $this->notice->getConversation();
     return true;
 }
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  */
 function prepare($args)
 {
     parent::prepare($args);
     $this->user = $this->auth_user;
     $this->notice_id = (int) $this->trimmed('id');
     if (empty($notice_id)) {
         $this->notice_id = (int) $this->arg('id');
     }
     $this->notice = Notice::getKV((int) $this->notice_id);
     return true;
 }
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     $this->notice = Notice::getKV($this->arg('id'));
     if (!empty($this->notice->repeat_of)) {
         common_log(LOG_DEBUG, 'Trying to Fave ' . $this->notice->id . ', repeat of ' . $this->notice->repeat_of);
         common_log(LOG_DEBUG, 'Will Fave ' . $this->notice->repeat_of . ' instead');
         $real_notice_id = $this->notice->repeat_of;
         $this->notice = Notice::getKV($real_notice_id);
     }
     return true;
 }
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  */
 function prepare($args)
 {
     parent::prepare($args);
     $this->user = $this->auth_user;
     $this->notice = Notice::getKV($this->arg('id'));
     if ($this->notice->repeat_of != '') {
         common_log(LOG_DEBUG, 'Trying to unFave ' . $this->notice->id);
         common_log(LOG_DEBUG, 'Will unFave ' . $this->notice->repeat_of . ' instead');
         $real_notice_id = $this->notice->repeat_of;
         $this->notice = Notice::getKV($real_notice_id);
     }
     return true;
 }
Esempio n. 11
0
 function getNotice()
 {
     $this->id = $this->trimmed('id');
     $this->bookmark = Bookmark::getKV('id', $this->id);
     if (empty($this->bookmark)) {
         // TRANS: Client exception thrown when referring to a non-existing bookmark.
         throw new ClientException(_m('No such bookmark.'), 404);
     }
     $notice = Notice::getKV('uri', $this->bookmark->uri);
     if (empty($notice)) {
         // Did we used to have it, and it got deleted?
         // TRANS: Client exception thrown when referring to a non-existing bookmark.
         throw new ClientException(_m('No such bookmark.'), 404);
     }
     return $notice;
 }
Esempio n. 12
0
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  *
  */
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     $this->notice_id = $this->trimmed('notice_id');
     $this->original = Notice::getKV('id', $this->notice_id);
     if (empty($this->original)) {
         // TRANS: Client error displayed trying to display redents of a non-exiting notice.
         $this->clientError(_('No such notice.'), 400, $this->format);
         return false;
     }
     $cnt = $this->trimmed('count');
     if (empty($cnt) || !is_integer($cnt)) {
         $this->cnt = 100;
     } else {
         $this->cnt = min((int) $cnt, self::MAXCOUNT);
     }
     return true;
 }
 /**
  * show the list of notices
  *
  * "Uses up" the stream by looping through it. So, probably can't
  * be called twice on the same list.
  *
  * @return int count of notices listed.
  */
 function show()
 {
     $this->out->elementStart('div', array('id' => 'notices_primary'));
     // TRANS: Header for Notices section.
     $this->out->element('h2', null, _m('HEADER', 'Notices'));
     $this->out->elementStart('ol', array('class' => 'notices threaded-notices xoxo'));
     $notices = $this->notice->fetchAll();
     $total = count($notices);
     $notices = array_slice($notices, 0, NOTICES_PER_PAGE);
     $allnotices = self::_allNotices($notices);
     self::prefill($allnotices);
     $conversations = array();
     foreach ($notices as $notice) {
         // Collapse repeats into their originals...
         if ($notice->repeat_of) {
             $orig = Notice::getKV('id', $notice->repeat_of);
             if ($orig instanceof Notice) {
                 $notice = $orig;
             }
         }
         $convo = $notice->conversation;
         if (!empty($conversations[$convo])) {
             // Seen this convo already -- skip!
             continue;
         }
         $conversations[$convo] = true;
         // Get the convo's root notice
         $root = $notice->conversationRoot($this->userProfile);
         if ($root instanceof Notice) {
             $notice = $root;
         }
         try {
             $item = $this->newListItem($notice);
             $item->show();
         } catch (Exception $e) {
             // we log exceptions and continue
             common_log(LOG_ERR, $e->getMessage());
             continue;
         }
     }
     $this->out->elementEnd('ol');
     $this->out->elementEnd('div');
     return $total;
 }
Esempio n. 14
0
 protected function doPreparation()
 {
     $id = $this->trimmed('notice');
     if (empty($id)) {
         // TRANS: Client error displayed when trying to repeat a notice while not providing a notice ID.
         $this->clientError(_('No notice specified.'));
     }
     $this->notice = Notice::getKV('id', $id);
     if (!$this->notice instanceof Notice) {
         // TRANS: Client error displayed when trying to repeat a non-existing notice.
         $this->clientError(_('Notice not found.'));
     }
     $this->repeat = $this->notice->repeat($this->scoped, 'web');
     if (!$this->repeat instanceof Notice) {
         // TRANS: Error when unable to repeat a notice for unknown reason.
         $this->clientError(_('Could not repeat notice for unknown reason. Please contact the webmaster!'));
     }
     return true;
 }
Esempio n. 15
0
 function prepare($args)
 {
     parent::prepare($args);
     $this->user = common_current_user();
     if (!$this->user) {
         // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
         common_user_error(_('Not logged in.'));
         exit;
     }
     $notice_id = $this->trimmed('notice');
     $this->notice = Notice::getKV($notice_id);
     if (!$this->notice) {
         // TRANS: Error message displayed trying to delete a non-existing notice.
         common_user_error(_('No such notice.'));
         exit;
     }
     $this->profile = $this->notice->getProfile();
     $this->user_profile = $this->user->getProfile();
     return true;
 }
Esempio n. 16
0
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  */
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     if ($this->format !== 'json') {
         $this->clientError('This method currently only serves JSON.', 415);
     }
     $id = $this->trimmed('id');
     $this->original = Notice::getKV('id', $id);
     if (!$this->original instanceof Notice) {
         // TRANS: Client error displayed trying to display redents of a non-exiting notice.
         $this->clientError(_('No such notice.'), 400);
     }
     $cnt = $this->trimmed('count');
     if (empty($cnt) || !is_integer($cnt)) {
         $cnt = 100;
     } else {
         $this->cnt = min((int) $cnt, self::MAXCOUNT);
     }
     return true;
 }
 /**
  * For initializing members of the class.
  *
  * @param array $args misc. arguments
  *
  * @return boolean true
  */
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     $profileId = $this->trimmed('profile');
     $noticeId = $this->trimmed('notice');
     $this->_profile = Profile::getKV('id', $profileId);
     if (empty($this->_profile)) {
         // TRANS: Client exception.
         throw new ClientException(_('No such profile.'), 404);
     }
     $this->_notice = Notice::getKV('id', $noticeId);
     if (empty($this->_notice)) {
         // TRANS: Client exception thrown when referencing a non-existing notice.
         throw new ClientException(_('No such notice.'), 404);
     }
     $this->_fave = Fave::pkeyGet(array('user_id' => $profileId, 'notice_id' => $noticeId));
     if (empty($this->_fave)) {
         // TRANS: Client exception thrown when referencing a non-existing favorite.
         throw new ClientException(_('No such favorite.'), 404);
     }
     return true;
 }
Esempio n. 18
0
 /**
  * Class handler.
  *
  * @param array $args query arguments
  *
  * @return void
  */
 function handle($args)
 {
     parent::handle($args);
     $profile = AnonymousFavePlugin::getAnonProfile();
     if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
         $this->clientError(_m('Could not disfavor notice! Please make sure your browser has cookies enabled.'));
     }
     $id = $this->trimmed('notice');
     $notice = Notice::getKV($id);
     $token = $this->checkSessionToken();
     $fave = new Fave();
     $fave->user_id = $profile->id;
     $fave->notice_id = $notice->id;
     if (!$fave->find(true)) {
         throw new NoResultException($fave);
     }
     $result = $fave->delete();
     if (!$result) {
         common_log_db_error($fave, 'DELETE', __FILE__);
         // TRANS: Server error.
         $this->serverError(_m('Could not delete favorite.'));
     }
     Fave::blowCacheForProfileId($profile->id);
     if ($this->boolean('ajax')) {
         $this->startHTML('text/xml;charset=utf-8');
         $this->elementStart('head');
         // TRANS: Title.
         $this->element('title', null, _m('Add to favorites'));
         $this->elementEnd('head');
         $this->elementStart('body');
         $favor = new AnonFavorForm($this, $notice);
         $favor->show();
         $this->elementEnd('body');
         $this->endHTML();
     } else {
         $this->returnToPrevious();
     }
 }
Esempio n. 19
0
 /**
  * Take arguments for running
  *
  * @param array $args $_REQUEST args
  *
  * @return boolean success flag
  */
 protected function prepare(array $args = array())
 {
     parent::prepare($args);
     // 'id' is an undocumented parameter in Twitter's API. Several
     // clients make use of it, so we support it too.
     // show.json?id=12345 takes precedence over /show/12345.json
     $this->notice_id = (int) $this->trimmed('id');
     $this->notice = Notice::getKV('id', $this->notice_id);
     if (!$this->notice instanceof Notice) {
         $deleted = Deleted_notice::getKV('id', $this->notice_id);
         if ($deleted instanceof Deleted_notice) {
             // TRANS: Client error displayed trying to show a deleted notice.
             $this->clientError(_('Notice deleted.'), 410);
         }
         // TRANS: Client error displayed trying to show a non-existing notice.
         $this->clientError(_('No such notice.'), 404);
     }
     if (!$this->notice->inScope($this->scoped)) {
         // TRANS: Client exception thrown when trying a view a notice the user has no access to.
         throw new ClientException(_('Access restricted.'), 403);
     }
     return true;
 }
Esempio n. 20
0
 /**
  * For initializing members of the class.
  *
  * @param array $argarray misc. arguments
  *
  * @return boolean true
  */
 function prepare($argarray)
 {
     Action::prepare($argarray);
     $this->id = $this->trimmed('id');
     $this->answer = QnA_Answer::getKV('id', $this->id);
     if (empty($this->answer)) {
         // TRANS: Client exception thrown when requesting a non-existing answer.
         throw new ClientException(_m('No such answer.'), 404);
     }
     $this->question = $this->answer->getQuestion();
     if (empty($this->question)) {
         // TRANS: Client exception thrown when requesting an answer that has no connected question.
         throw new ClientException(_m('No question for this answer.'), 404);
     }
     $this->notice = Notice::getKV('uri', $this->answer->uri);
     if (empty($this->notice)) {
         // TRANS: Did we used to have it, and it got deleted?
         throw new ClientException(_m('No such answer.'), 404);
     }
     $this->user = User::getKV('id', $this->answer->profile_id);
     if (empty($this->user)) {
         // TRANS: Client exception thrown when requesting answer data for a non-existing user.
         throw new ClientException(_m('No such user.'), 404);
     }
     $this->profile = $this->user->getProfile();
     if (empty($this->profile)) {
         // TRANS: Client exception thrown when requesting answer data for a user without a profile.
         throw new ServerException(_m('User without a profile.'));
     }
     try {
         $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
     } catch (Exception $e) {
         $this->avatar = null;
     }
     return true;
 }
 /**
  * Handle the request
  *
  * Make a new notice for the update, save it, and show it
  *
  * @return void
  */
 protected function handle()
 {
     parent::handle();
     // Workaround for PHP returning empty $_POST and $_FILES when POST
     // length > post_max_size in php.ini
     if (empty($_FILES) && empty($_POST) && $_SERVER['CONTENT_LENGTH'] > 0) {
         // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
         // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
         $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.', 'The server was unable to handle that much POST data (%s bytes) due to its current configuration.', intval($_SERVER['CONTENT_LENGTH']));
         $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
     }
     if (empty($this->status)) {
         // TRANS: Client error displayed when the parameter "status" is missing.
         $this->clientError(_('Client must provide a \'status\' parameter with a value.'));
     }
     if (is_null($this->scoped)) {
         // TRANS: Client error displayed when updating a status for a non-existing user.
         $this->clientError(_('No such user.'), 404);
     }
     /* Do not call shortenLinks until the whole notice has been build */
     // Check for commands
     $inter = new CommandInterpreter();
     $cmd = $inter->handle_command($this->auth_user, $this->status);
     if ($cmd) {
         if ($this->supported($cmd)) {
             $cmd->execute(new Channel());
         }
         // Cmd not supported?  Twitter just returns your latest status.
         // And, it returns your last status whether the cmd was successful
         // or not!
         $this->notice = $this->auth_user->getCurrentNotice();
     } else {
         $reply_to = null;
         if (!empty($this->in_reply_to_status_id)) {
             // Check whether notice actually exists
             $reply = Notice::getKV($this->in_reply_to_status_id);
             if ($reply) {
                 $reply_to = $this->in_reply_to_status_id;
             } else {
                 // TRANS: Client error displayed when replying to a non-existing notice.
                 $this->clientError(_('Parent notice not found.'), 404);
             }
         }
         $upload = null;
         try {
             $upload = MediaFile::fromUpload('media', $this->scoped);
             $this->status .= ' ' . $upload->shortUrl();
             /* Do not call shortenLinks until the whole notice has been build */
         } catch (NoUploadedMediaException $e) {
             // There was no uploaded media for us today.
         }
         /* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
         $status_shortened = $this->auth_user->shortenLinks($this->status);
         if (Notice::contentTooLong($status_shortened)) {
             if ($upload instanceof MediaFile) {
                 $upload->delete();
             }
             // TRANS: Client error displayed exceeding the maximum notice length.
             // TRANS: %d is the maximum lenth for a notice.
             $msg = _m('Maximum notice size is %d character, including attachment URL.', 'Maximum notice size is %d characters, including attachment URL.', Notice::maxContent());
             /* Use HTTP 413 error code (Request Entity Too Large)
              * instead of basic 400 for better understanding
              */
             $this->clientError(sprintf($msg, Notice::maxContent()), 413);
         }
         $content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
         $options = array('reply_to' => $reply_to);
         if ($this->scoped->shareLocation()) {
             $locOptions = Notice::locationOptions($this->lat, $this->lon, null, null, $this->scoped);
             $options = array_merge($options, $locOptions);
         }
         try {
             $this->notice = Notice::saveNew($this->scoped->id, $content, $this->source, $options);
         } catch (Exception $e) {
             $this->clientError($e->getMessage(), $e->getCode());
         }
         if (isset($upload)) {
             $upload->attachToNotice($this->notice);
         }
     }
     $this->showNotice();
 }
Esempio n. 22
0
    function showQvitter()
    {
        $logged_in_user_nickname = '';
        $logged_in_user_obj = false;
        $logged_in_user = common_current_user();
        if ($logged_in_user) {
            $logged_in_user_nickname = $logged_in_user->nickname;
            $logged_in_user_obj = ApiAction::twitterUserArray($logged_in_user->getProfile());
        }
        $registrationsclosed = false;
        if (common_config('site', 'closed') == 1 || common_config('site', 'inviteonly') == 1) {
            $registrationsclosed = true;
        }
        // check if the client's ip address is blocked for registration
        if (is_array(QvitterPlugin::settings("blocked_ips"))) {
            $client_ip_is_blocked = in_array($_SERVER['REMOTE_ADDR'], QvitterPlugin::settings("blocked_ips"));
        }
        $sitetitle = common_config('site', 'name');
        $siterootdomain = common_config('site', 'server');
        $qvitterpath = Plugin::staticPath('Qvitter', '');
        $apiroot = common_path('api/', StatusNet::isHTTPS());
        $attachmentroot = common_path('attachment/', StatusNet::isHTTPS());
        $instanceurl = common_path('', StatusNet::isHTTPS());
        // user's browser's language setting
        $user_browser_language = 'en';
        // use english if we can't find the browser language
        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $user_browser_language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
        }
        common_set_returnto('');
        // forget this
        // if this is a profile we add a link header for LRDD Discovery (see WebfingerPlugin.php)
        if (substr_count($_SERVER['REQUEST_URI'], '/') == 1) {
            $nickname = substr($_SERVER['REQUEST_URI'], 1);
            if (preg_match("/^[a-zA-Z0-9]+\$/", $nickname) == 1) {
                $acct = 'acct:' . $nickname . '@' . common_config('site', 'server');
                $url = common_local_url('webfinger') . '?resource=' . $acct;
                foreach (array(Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE) as $type) {
                    header('Link: <' . $url . '>; rel="' . Discovery::LRDD_REL . '"; type="' . $type . '"');
                }
            }
        }
        ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
		"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
		<html xmlns="http://www.w3.org/1999/xhtml">
			<head>
				<title><?php 
        print $sitetitle;
        ?>
</title>
				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
				<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
				<link rel="stylesheet" type="text/css" href="<?php 
        print $qvitterpath;
        ?>
css/qvitter.css?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/css/qvitter.css'));
        ?>
" />
				<link rel="stylesheet" type="text/css" href="<?php 
        print $qvitterpath;
        ?>
css/jquery.minicolors.css" />
				<link rel="shortcut icon" type="image/x-icon" href="<?php 
        print $qvitterpath;
        print QvitterPlugin::settings("favicon");
        ?>
">
				<?php 
        // if qvitter is a webapp and this is a users url we add feeds
        if (substr_count($_SERVER['REQUEST_URI'], '/') == 1) {
            $nickname = substr($_SERVER['REQUEST_URI'], 1);
            if (preg_match("/^[a-zA-Z0-9]+\$/", $nickname) == 1) {
                $user = User::getKV('nickname', $nickname);
                if (!isset($user->id)) {
                    //error_log("QVITTER: Could not get user id for user with nickname: $nickname – REQUEST_URI: ".$_SERVER['REQUEST_URI']);
                } else {
                    print '<link title="Notice feed for ' . $nickname . ' (Activity Streams JSON)" type="application/stream+json" href="' . $instanceurl . 'api/statuses/user_timeline/' . $user->id . '.as" rel="alternate">' . "\n";
                    print '				<link title="Notice feed for ' . $nickname . ' (RSS 1.0)" type="application/rdf+xml" href="' . $instanceurl . $nickname . '/rss" rel="alternate">' . "\n";
                    print '				<link title="Notice feed for ' . $nickname . ' (RSS 2.0)" type="application/rss+xml" href="' . $instanceurl . 'api/statuses/user_timeline/' . $user->id . '.rss" rel="alternate">' . "\n";
                    print '				<link title="Notice feed for ' . $nickname . ' (Atom)" type="application/atom+xml" href="' . $instanceurl . 'api/statuses/user_timeline/' . $user->id . '.atom" rel="alternate">' . "\n";
                    print '				<link title="FOAF for ' . $nickname . '" type="application/rdf+xml" href="' . $instanceurl . $nickname . '/foaf" rel="meta">' . "\n";
                    print '				<link href="' . $instanceurl . $nickname . '/microsummary" rel="microsummary">' . "\n";
                    // maybe openid
                    if (array_key_exists('OpenID', StatusNet::getActivePlugins())) {
                        print '				<link rel="openid2.provider" href="' . common_local_url('openidserver') . '"/>' . "\n";
                        print '				<link rel="openid2.local_id" href="' . $user->getProfile()->profileurl . '"/>' . "\n";
                        print '				<link rel="openid2.server" href="' . common_local_url('openidserver') . '"/>' . "\n";
                        print '				<link rel="openid2.delegate" href="' . $user->getProfile()->profileurl . '"/>' . "\n";
                    }
                }
            }
        } elseif (substr($_SERVER['REQUEST_URI'], 0, 7) == '/group/') {
            $group_id_or_name = substr($_SERVER['REQUEST_URI'], 7);
            if (stristr($group_id_or_name, '/id')) {
                $group_id_or_name = substr($group_id_or_name, 0, strpos($group_id_or_name, '/id'));
                $group = User_group::getKV('id', $group_id_or_name);
                if ($group instanceof User_group) {
                    $group_name = $group->nickname;
                    $group_id = $group_id_or_name;
                }
            } else {
                $group = Local_group::getKV('nickname', $group_id_or_name);
                if ($group instanceof Local_group) {
                    $group_id = $group->group_id;
                    $group_name = $group_id_or_name;
                }
            }
            if (preg_match("/^[a-zA-Z0-9]+\$/", $group_id_or_name) == 1 && isset($group_name) && isset($group_id)) {
                ?>

				<link rel="alternate" href="<?php 
                echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id' => $group_id, 'format' => 'as')));
                ?>
" type="application/stream+json" title="Notice feed for '<?php 
                echo htmlspecialchars($group_name);
                ?>
' group (Activity Streams JSON)" />
				<link rel="alternate" href="<?php 
                echo htmlspecialchars(common_local_url('grouprss', array('nickname' => $group_name)));
                ?>
" type="application/rdf+xml" title="Notice feed for '<?php 
                echo htmlspecialchars($group_name);
                ?>
' group (RSS 1.0)" />
				<link rel="alternate" href="<?php 
                echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id' => $group_id, 'format' => 'rss')));
                ?>
" type="application/rss+xml" title="Notice feed for '<?php 
                echo htmlspecialchars($group_name);
                ?>
' group (RSS 2.0)" />
				<link rel="alternate" href="<?php 
                echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id' => $group_id, 'format' => 'atom')));
                ?>
" type="application/atom+xml" title="Notice feed for '<?php 
                echo htmlspecialchars($group_name);
                ?>
' group (Atom)" />
				<link rel="meta" href="<?php 
                echo htmlspecialchars(common_local_url('foafgroup', array('nickname' => $group_name)));
                ?>
" type="application/rdf+xml" title="FOAF for '<?php 
                echo htmlspecialchars($group_name);
                ?>
' group" />
                <?php 
            }
        }
        // oembed discovery for local notices
        if (substr($_SERVER['REQUEST_URI'], 0, 8) == '/notice/' && $this->arg('notice') && array_key_exists('Oembed', StatusNet::getActivePlugins())) {
            $notice = Notice::getKV('id', $this->arg('notice'));
            if ($notice instanceof Notice) {
                if ($notice->isLocal()) {
                    try {
                        $notice_url = $notice->getUrl();
                        print '<link title="oEmbed" href="' . common_local_url('apiqvitteroembednotice', array('id' => $notice->id, 'format' => 'json')) . '?url=' . urlencode($notice_url) . '" type="application/json+oembed" rel="alternate">';
                        print '<link title="oEmbed" href="' . common_local_url('apiqvitteroembednotice', array('id' => $notice->id, 'format' => 'xml')) . '?url=' . urlencode($notice_url) . '" type="application/xml+oembed" rel="alternate">';
                    } catch (Exception $e) {
                        //
                    }
                }
            }
        }
        ?>
				<script>

					/*
					@licstart  The following is the entire license notice for the
					JavaScript code in this page.

					Copyright (C) 2015  Hannes Mannerheim and other contributors

					This program is free software: you can redistribute it and/or modify
					it under the terms of the GNU Affero General Public License as
					published by the Free Software Foundation, either version 3 of the
					License, or (at your option) any later version.

					This program is distributed in the hope that it will be useful,
					but WITHOUT ANY WARRANTY; without even the implied warranty of
					MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
					GNU Affero General Public License for more details.

					You should have received a copy of the GNU Affero General Public License
					along with this program.  If not, see <http://www.gnu.org/licenses/>.

					@licend  The above is the entire license notice
					for the JavaScript code in this page.
					*/

                    window.usersLanguageCode = <?php 
        print json_encode($user_browser_language);
        ?>
;
                    window.usersLanguageNameInEnglish = <?php 
        print json_encode(Locale::getDisplayLanguage($user_browser_language, 'en'));
        ?>
;
                    window.englishLanguageData = <?php 
        print file_get_contents(QVITTERDIR . '/locale/en.json');
        ?>
;
                    window.defaultAvatarStreamSize = <?php 
        print json_encode(Avatar::defaultImage(AVATAR_STREAM_SIZE));
        ?>
;
                    window.defaultAvatarProfileSize = <?php 
        print json_encode(Avatar::defaultImage(AVATAR_PROFILE_SIZE));
        ?>
;
					window.textLimit = <?php 
        print json_encode((int) common_config('site', 'textlimit'));
        ?>
;
					window.registrationsClosed = <?php 
        print json_encode($registrationsclosed);
        ?>
;
					window.thisSiteThinksItIsHttpButIsActuallyHttps = <?php 
        // this is due to a crazy setup at quitter.se, sorry about that
        $siteSSL = common_config('site', 'ssl');
        if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' && $siteSSL == 'never') {
            $this_site_thinks_it_is_http_but_is_actually_https = true;
            print 'true';
        } else {
            $this_site_thinks_it_is_http_but_is_actually_https = false;
            print 'false';
        }
        ?>
;
					window.siteTitle = <?php 
        print json_encode($sitetitle);
        ?>
;
					window.loggedIn = <?php 
        $logged_in_user_json = json_encode($logged_in_user_obj);
        $logged_in_user_json = str_replace('http:\\/\\/quitter.se\\/', 'https:\\/\\/quitter.se\\/', $logged_in_user_json);
        print $logged_in_user_json;
        ?>
;
					window.timeBetweenPolling = <?php 
        print QvitterPlugin::settings("timebetweenpolling");
        ?>
;
					window.apiRoot = <?php 
        $api_root = common_path("api/", StatusNet::isHTTPS());
        if ($this_site_thinks_it_is_http_but_is_actually_https) {
            $api_root = str_replace('http://', 'https://', $api_root);
        }
        print '\'' . $api_root . '\'';
        ?>
;
					window.fullUrlToThisQvitterApp = '<?php 
        print $qvitterpath;
        ?>
';
					window.siteRootDomain = '<?php 
        print $siterootdomain;
        ?>
';
					window.siteInstanceURL = '<?php 
        print $instanceurl;
        ?>
';
					window.defaultLinkColor = '<?php 
        print QvitterPlugin::settings("defaultlinkcolor");
        ?>
';
					window.defaultBackgroundColor = '<?php 
        print QvitterPlugin::settings("defaultbackgroundcolor");
        ?>
';
					window.siteBackground = '<?php 
        print QvitterPlugin::settings("sitebackground");
        ?>
';
					window.enableWelcomeText = <?php 
        print json_encode(QvitterPlugin::settings("enablewelcometext"));
        ?>
;
					window.customWelcomeText = <?php 
        print json_encode(QvitterPlugin::settings("customwelcometext"));
        ?>
;
					window.urlShortenerAPIURL = '<?php 
        print QvitterPlugin::settings("urlshortenerapiurl");
        ?>
';
					window.urlShortenerSignature = '<?php 
        print QvitterPlugin::settings("urlshortenersignature");
        ?>
';
					window.commonSessionToken = '<?php 
        print common_session_token();
        ?>
';
					window.siteMaxThumbnailSize = <?php 
        print common_config('thumbnail', 'maxsize');
        ?>
;
					window.siteAttachmentURLBase = '<?php 
        print $attachmentroot;
        ?>
';
					window.siteEmail = '<?php 
        print common_config('site', 'email');
        ?>
';
					window.siteLicenseTitle = '<?php 
        print common_config('license', 'title');
        ?>
';
					window.siteLicenseURL = '<?php 
        print common_config('license', 'url');
        ?>
';
					window.customTermsOfUse = <?php 
        print json_encode(QvitterPlugin::settings("customtermsofuse"));
        ?>
;
                    window.siteLocalOnlyDefaultPath = <?php 
        print common_config('public', 'localonly') ? 'true' : 'false';
        ?>
;
                    <?php 
        // Get all topics in Qvitter's namespace in Profile_prefs
        if ($logged_in_user) {
            try {
                $qvitter_profile_prefs = Profile_prefs::getNamespace(Profile::current(), 'qvitter');
            } catch (Exception $e) {
                $qvitter_profile_prefs = array();
            }
            if (count($qvitter_profile_prefs) > 0) {
                $topic_data = new stdClass();
                foreach ($qvitter_profile_prefs as $pref) {
                    $topic_data->{$pref->topic} = $pref->data;
                }
                print 'window.qvitterProfilePrefs = ' . json_encode($topic_data) . ';';
            } else {
                print 'window.qvitterProfilePrefs = false;';
            }
        }
        ?>

					// available language files and their last update time
					window.availableLanguages = {<?php 
        // scan all files in the locale directory and create a json object with their change date added
        $available_languages = array_diff(scandir(QVITTERDIR . '/locale'), array('..', '.'));
        foreach ($available_languages as $lankey => $lan) {
            $lancode = substr($lan, 0, strpos($lan, '.'));
            // for the paranthesis containing language region to work with rtl in ltr enviroment and vice versa, we add a
            // special rtl or ltr html char after the paranthesis
            // this list is incomplete, but if any rtl language gets a regional translation, it will probably be arabic
            $rtl_or_ltr_special_char = '&lrm;';
            $base_lancode = substr($lancode, 0, strpos($lancode, '_'));
            if ($base_lancode == 'ar' || $base_lancode == 'fa' || $base_lancode == 'he') {
                $rtl_or_ltr_special_char = '&rlm;';
            }
            // also make an array with all language names, to use for generating menu
            $languagecodesandnames[$lancode]['english_name'] = Locale::getDisplayLanguage($lancode, 'en');
            $languagecodesandnames[$lancode]['name'] = Locale::getDisplayLanguage($lancode, $lancode);
            if (Locale::getDisplayRegion($lancode, $lancode)) {
                $languagecodesandnames[$lancode]['name'] .= ' (' . Locale::getDisplayRegion($lancode, $lancode) . ')' . $rtl_or_ltr_special_char;
            }
            // ahorita meme only on quitter.es
            if ($lancode == 'es_ahorita') {
                if ($siterootdomain == 'quitter.es') {
                    $languagecodesandnames[$lancode]['name'] = 'español (ahorita)';
                } else {
                    unset($available_languages[$lankey]);
                    unset($languagecodesandnames[$lancode]);
                    continue;
                }
            }
            print "\n" . '						"' . $lancode . '": "' . $lan . '?changed=' . date('YmdHis', filemtime(QVITTERDIR . '/locale/' . $lan)) . '",';
        }
        ?>

						};

				</script>
				<?php 
        // event for other plugins to use to add head elements to qvitter
        Event::handle('QvitterEndShowHeadElements', array($this));
        ?>
			</head>
			<body style="background-color:<?php 
        print QvitterPlugin::settings("defaultbackgroundcolor");
        ?>
">
                <?php 
        // add an accessibility toggle link to switch to standard UI, if we're logged in
        if ($logged_in_user) {
            print '<a id="accessibility-toggle-link" href="#"></a>';
        }
        ?>
				<input id="upload-image-input" class="upload-image-input" type="file" name="upload-image-input">
				<div class="topbar">
					<a href="<?php 
        // if we're logged in, the logo links to the home stream
        // if logged out it links to the site's public stream
        if ($logged_in_user) {
            print $instanceurl . $logged_in_user_nickname . '/all';
        } else {
            print $instanceurl . 'main/public';
        }
        ?>
"><div id="logo"></div></a><?php 
        // menu for logged in users
        if ($logged_in_user) {
            ?>
    					<a id="settingslink">
    						<div class="dropdown-toggle">
    							<div class="nav-session" style="background-image:url('<?php 
            print htmlspecialchars($logged_in_user_obj['profile_image_url_profile_size']);
            ?>
')"></div>
    						</div>
    					</a><?php 
        }
        ?>
<div id="top-compose" class="hidden"></div>
					<ul class="quitter-settings dropdown-menu">
						<li class="dropdown-caret right">
							<span class="caret-outer"></span>
							<span class="caret-inner"></span>
						</li>
						<li class="fullwidth"><a id="logout"></a></li>
						<li class="fullwidth dropdown-divider"></li>
						<li class="fullwidth"><a id="edit-profile-header-link"></a></li>
						<li class="fullwidth"><a id="settings" href="<?php 
        print $instanceurl;
        ?>
settings/profile" donthijack></a></li>
						<li class="fullwidth"><a id="faq-link"></a></li>
                        <li class="fullwidth"><a id="shortcuts-link"></a></li>
						<?php 
        if (common_config('invite', 'enabled') && !common_config('site', 'closed')) {
            ?>
							<li class="fullwidth"><a id="invite-link" href="<?php 
            print $instanceurl;
            ?>
main/invite"></a></li>
						<?php 
        }
        ?>
						<li class="fullwidth"><a id="classic-link"></a></li>
						<li class="fullwidth language dropdown-divider"></li>
						<?php 
        // languages
        foreach ($languagecodesandnames as $lancode => $lan) {
            print '<li class="language"><a class="language-link" title="' . $lan['english_name'] . '" data-lang-code="' . $lancode . '">' . $lan['name'] . '</a></li>';
        }
        ?>
                        <li class="fullwidth language dropdown-divider"></li>
                        <li class="fullwidth"><a href="https://git.gnu.io/h2p/Qvitter/tree/master/locale" target="_blank" id="add-edit-language-link"></a></li>
					</ul>
					<div class="global-nav">
						<div class="global-nav-inner">
							<div class="container">
								<div id="search">
									<input type="text" spellcheck="false" autocomplete="off" name="q" placeholder="Sök" id="search-query" class="search-input">
									<span class="search-icon">
										<button class="icon nav-search" type="submit" tabindex="-1">
											<span> Sök </span>
										</button>
									</span>
								</div>
								<ul class="language-dropdown">
									<li class="dropdown">
										<a class="dropdown-toggle">
											<small></small>
											<span class="current-language"></span>
											<b class="caret"></b>
										</a>
										<ul class="dropdown-menu">
											<li class="dropdown-caret right">
												<span class="caret-outer"></span>
												<span class="caret-inner"></span>
											</li>
											<?php 
        // languages
        foreach ($languagecodesandnames as $lancode => $lan) {
            print '<li><a class="language-link" title="' . $lan['english_name'] . '" data-lang-code="' . $lancode . '">' . $lan['name'] . '</a></li>';
        }
        ?>
										</ul>
									</li>
								</ul>
							</div>
						</div>
					</div>
				</div>
                <div id="no-js-error">Please enable javascript to use this site.<script>var element = document.getElementById('no-js-error'); element.parentNode.removeChild(element);</script></div>
				<div id="page-container">
					<?php 
        $site_notice = common_config('site', 'notice');
        if (!empty($site_notice)) {
            print '<div id="site-notice">' . common_config('site', 'notice') . '</div>';
        }
        // welcome text, login and register container if logged out
        if ($logged_in_user === null) {
            ?>
                        <div class="front-welcome-text <?php 
            if ($registrationsclosed) {
                print 'registrations-closed';
            }
            ?>
"></div>
                        <div id="login-register-container">
    						<div id="login-content">
    							<form id="form_login" class="form_settings" action="<?php 
            print common_local_url('qvitterlogin');
            ?>
" method="post">
    								<div id="username-container">
    									<input id="nickname" name="nickname" type="text" value="<?php 
            print $logged_in_user_nickname;
            ?>
" tabindex="1" />
    								</div>
    								<table class="password-signin"><tbody><tr>
    									<td class="flex-table-primary">
    										<div class="placeholding-input">
    											<input id="password" name="password" type="password" tabindex="2" value="" />
    										</div>
    									</td>
    									<td class="flex-table-secondary">
    										<button class="submit" type="submit" id="submit-login" tabindex="4"></button>
    									</td>
    								</tr></tbody></table>
    								<div id="remember-forgot">
    									<input type="checkbox" id="rememberme" name="rememberme" value="yes" tabindex="3" checked="checked"> <span id="rememberme_label"></span> · <a id="forgot-password" href="<?php 
            print $instanceurl;
            ?>
main/recoverpassword" ></a>
    									<input type="hidden" id="token" name="token" value="<?php 
            print common_session_token();
            ?>
">
    									<?php 
            if (array_key_exists('OpenID', StatusNet::getActivePlugins())) {
                print '<a href="' . $instanceurl . 'main/openid" id="openid-login" title="OpenID" donthijack>OpenID</a>';
            }
            ?>
    								</div>
    							</form>
    						</div>
    						<?php 
            if ($registrationsclosed === false && $client_ip_is_blocked === false) {
                ?>
<div class="front-signup">
    							<h2></h2>
    							<div class="signup-input-container"><input placeholder="" type="text" name="user[name]" autocomplete="off" class="text-input" id="signup-user-name"></div>
    							<div class="signup-input-container"><input placeholder="" type="text" name="user[email]" autocomplete="off" id="signup-user-email"></div>
    							<div class="signup-input-container"><input placeholder="" type="password" name="user[user_password]" class="text-input" id="signup-user-password"></div>
    							<button id="signup-btn-step1" class="signup-btn" type="submit"></button>
    						</div>
                            <div id="other-servers-link"></div><?php 
            }
            ?>
<div id="qvitter-notice-logged-out"><?php 
            print common_config('site', 'qvitternoticeloggedout');
            ?>
</div>
                        </div><?php 
        }
        // box containing the logged in users queet count and compose form
        if ($logged_in_user) {
            ?>
                        <div id="user-container" style="display:none;">
    						<div id="user-header" style="background-image:url('<?php 
            print htmlspecialchars($logged_in_user_obj['cover_photo']);
            ?>
')">
    							<div id="mini-edit-profile-button"></div>
    							<div class="profile-header-inner-overlay"></div>
    							<div id="user-avatar-container"><img id="user-avatar" src="<?php 
            print htmlspecialchars($logged_in_user_obj['profile_image_url_profile_size']);
            ?>
" /></div>
    							<div id="user-name"><?php 
            print htmlspecialchars($logged_in_user_obj['name']);
            ?>
</div>
    							<div id="user-screen-name"><?php 
            print htmlspecialchars($logged_in_user_obj['screen_name']);
            ?>
</div>
    						</div>
    						<ul id="user-body">
    							<li><a href="<?php 
            print $instanceurl . $logged_in_user->nickname;
            ?>
" id="user-queets"><span class="label"></span><strong><?php 
            print $logged_in_user_obj['statuses_count'];
            ?>
</strong></a></li>
    							<li><a href="<?php 
            print $instanceurl . $logged_in_user->nickname;
            ?>
/subscriptions" id="user-following"><span class="label"></span><strong><?php 
            print $logged_in_user_obj['friends_count'];
            ?>
</strong></a></li>
    							<li><a href="<?php 
            print $instanceurl . $logged_in_user->nickname;
            ?>
/groups" id="user-groups"><span class="label"></span><strong><?php 
            print $logged_in_user_obj['groups_count'];
            ?>
</strong></a></li>
    						</ul>
    						<div id="user-footer">
    							<div id="user-footer-inner">
    								<div id="queet-box" class="queet-box queet-box-syntax" data-start-text=""></div>
    								<div class="syntax-middle"></div>
    								<div class="syntax-two" contenteditable="true"></div>
    								<div class="mentions-suggestions"></div>
    								<div class="queet-toolbar">
    									<div class="queet-box-extras">
    										<button class="upload-image"></button>
    										<button class="shorten disabled">URL</button>
    									</div>
    									<div class="queet-button">
    										<span class="queet-counter"></span>
    										<button></button>
    									</div>
    								</div>
    							</div>
    						</div>
                            <div id="main-menu" class="menu-container"><?php 
            if ($logged_in_user) {
                ?>
<a href="<?php 
                print $instanceurl . $logged_in_user->nickname;
                ?>
/all" class="stream-selection friends-timeline"><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl . $logged_in_user->nickname;
                ?>
/notifications" class="stream-selection notifications"><span id="unseen-notifications"></span><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl . $logged_in_user->nickname;
                ?>
/replies" class="stream-selection mentions"><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl . $logged_in_user->nickname;
                ?>
" class="stream-selection my-timeline"><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl . $logged_in_user->nickname;
                ?>
/favorites" class="stream-selection favorites"><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl;
                ?>
main/public" class="stream-selection public-timeline"><i class="chev-right"></i></a>
            							<a href="<?php 
                print $instanceurl;
                ?>
main/all" class="stream-selection public-and-external-timeline"><i class="chev-right"></i></a>
                                        <?php 
            }
            ?>
        						</div>
        						<div class="menu-container" id="bookmark-container"></div>
                                <div class="menu-container" id="history-container"></div>
                                <div id="clear-history"></div>
        						<div id="qvitter-notice"><?php 
            print common_config('site', 'qvitternotice');
            ?>
</div>
        					</div><?php 
        }
        ?>

                    <div id="feed">
						<div id="feed-header">
							<div id="feed-header-inner">
								<h2></h2>
								<div class="reload-stream"></div>
							</div>
						</div>
						<div id="new-queets-bar-container" class="hidden"><div id="new-queets-bar"></div></div>
						<div id="feed-body"></div>
					</div>
                    <div id="hidden-html"><?php 
        // adds temporary support for microformats and linkbacks on the notice page
        if (substr($_SERVER['REQUEST_URI'], 0, 8) == '/notice/' && $this->arg('notice')) {
            echo '<ol class="notices xoxo">';
            if ($notice instanceof Notice) {
                $widget = new NoticeListItem($notice, $this);
                $widget->show();
                $this->flush();
            }
            echo '</ol>';
        }
        Event::handle('QvitterHiddenHtml', array($this));
        ?>
</div>
					<div id="footer"><div id="footer-spinner-container"></div></div>
				</div>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/jquery-2.1.4.min.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/jquery-2.1.4.min.js'));
        ?>
"></script>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/jquery-ui.min.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/jquery-ui.min.js'));
        ?>
"></script>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/jquery.minicolors.min.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/jquery.minicolors.min.js'));
        ?>
"></script>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/jquery.jWindowCrop.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/jquery.jWindowCrop.js'));
        ?>
"></script>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/load-image.min.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/load-image.min.js'));
        ?>
"></script>
				<script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/xregexp-all-3.0.0-pre.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/xregexp-all-3.0.0-pre.js'));
        ?>
"></script>
                <script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/lz-string.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/lz-string.js'));
        ?>
"></script>
                <script type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/lib/bowser.min.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/lib/bowser.min.js'));
        ?>
"></script>
				<script charset="utf-8" type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/dom-functions.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/dom-functions.js'));
        ?>
"></script>
				<script charset="utf-8" type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/misc-functions.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/misc-functions.js'));
        ?>
"></script>
				<script charset="utf-8" type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/ajax-functions.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/ajax-functions.js'));
        ?>
"></script>
                <script charset="utf-8" type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/stream-router.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/stream-router.js'));
        ?>
"></script>
				<script charset="utf-8" type="text/javascript" src="<?php 
        print $qvitterpath;
        ?>
js/qvitter.js?changed=<?php 
        print date('YmdHis', filemtime(QVITTERDIR . '/js/qvitter.js'));
        ?>
"></script>
				<?php 
        // event for other plugins to add scripts to qvitter
        Event::handle('QvitterEndShowScripts', array($this));
        // we might have custom javascript in the config file that we want to add
        if (QvitterPlugin::settings('js')) {
            print '<script type="text/javascript">' . QvitterPlugin::settings('js') . '</script>';
        }
        ?>
			<div id="dynamic-styles">
				<style>
					a, a:visited, a:active,
					ul.stats li:hover a,
					ul.stats li:hover a strong,
					#user-body a:hover div strong,
					#user-body a:hover div div,
					.permalink-link:hover,
					.stream-item.expanded > .queet .stream-item-expand,
					.stream-item-footer .with-icn .requeet-text a b:hover,
					.queet-text span.attachment.more,
					.stream-item-header .created-at a:hover,
					.stream-item-header a.account-group:hover .name,
					.queet:hover .stream-item-expand,
					.show-full-conversation:hover,
					#new-queets-bar,
					.menu-container div,
					.cm-mention, .cm-tag, .cm-group, .cm-url, .cm-email,
					div.syntax-middle span,
					#user-body strong,
					ul.stats,
					.stream-item:not(.temp-post) ul.queet-actions li .icon:not(.is-mine):hover:before,
					.show-full-conversation,
					#user-body #user-queets:hover .label,
					#user-body #user-groups:hover .label,
					#user-body #user-following:hover .label,
					ul.stats a strong,
					.queet-box-extras button,
					#openid-login:hover:after,
                    .post-to-group {
						color:/*COLORSTART*/<?php 
        print QvitterPlugin::settings("defaultlinkcolor");
        ?>
/*COLOREND*/;
						}
					#unseen-notifications,
					.stream-item.notification.not-seen > .queet::before,
					#top-compose,
					#logo,
					.queet-toolbar button,
					#user-header,
					.profile-header-inner,
					.topbar,
					.menu-container,
					.member-button.member,
					.external-follow-button.following,
					.qvitter-follow-button.following,
					.save-profile-button,
					.crop-and-save-button,
					.topbar .global-nav.show-logo:before,
					.topbar .global-nav.pulse-logo:before,
                    .dropdown-menu li:not(.dropdown-caret) a:hover {
						background-color:/*BACKGROUNDCOLORSTART*/<?php 
        print QvitterPlugin::settings("defaultlinkcolor");
        ?>
/*BACKGROUNDCOLOREND*/;
						}
					.queet-box-syntax[contenteditable="true"]:focus,
                    .stream-item.selected-by-keyboard::before {
						border-color:/*BORDERCOLORSTART*/#999999/*BORDERCOLOREND*/;
						}
					#user-footer-inner,
					.inline-reply-queetbox,
					#popup-faq #faq-container p.indent {
						background-color:/*LIGHTERBACKGROUNDCOLORSTART*/rgb(205,230,239)/*LIGHTERBACKGROUNDCOLOREND*/;
						}
					#user-footer-inner,
					.queet-box,
					.queet-box-syntax[contenteditable="true"],
					.inline-reply-queetbox,
					span.inline-reply-caret,
				    .stream-item.expanded .stream-item.first-visible-after-parent,
					#popup-faq #faq-container p.indent,
                    .post-to-group,
                    .quoted-notice:hover,
                    .oembed-item:hover,
                    .stream-item:hover:not(.expanded) .quoted-notice:hover,
                    .stream-item:hover:not(.expanded) .oembed-item:hover {
						border-color:/*LIGHTERBORDERCOLORSTART*/rgb(155,206,224)/*LIGHTERBORDERCOLOREND*/;
						}
					span.inline-reply-caret .caret-inner {
						border-bottom-color:/*LIGHTERBORDERBOTTOMCOLORSTART*/rgb(205,230,239)/*LIGHTERBORDERBOTTOMCOLOREND*/;
						}

					.modal-close .icon,
					.chev-right,
					.close-right,
					button.icon.nav-search,
					.member-button .join-text i,
					.external-member-button .join-text i,
					.external-follow-button .follow-text i,
					.qvitter-follow-button .follow-text i,
					#logo,
					.upload-cover-photo,
					.upload-avatar,
					.upload-background-image,
					button.shorten i,
					.reload-stream,
					.topbar .global-nav:before,
					.stream-item.notification.repeat .dogear,
					.stream-item.notification.like .dogear,
					.ostatus-link,
					.close-edit-profile-window {
						background-image: url("<?php 
        print QvitterPlugin::settings("sprite");
        ?>
");
						background-size: 500px 1329px;
						}
					@media (max-width: 910px) {
						#search-query,
						.menu-container a,
						.menu-container a.current,
						.stream-selection.friends-timeline:after,
						.stream-selection.notifications:after,
						.stream-selection.my-timeline:after,
						.stream-selection.public-timeline:after {
							background-image: url("<?php 
        print QvitterPlugin::settings("sprite");
        ?>
");
							background-size: 500px 1329px;
							}
						}

				</style>
			</div>
			</body>
		</html>


			<?php 
    }
Esempio n. 23
0
Test generation and sending of magic envelopes for Salmon slaps.

     --notice=N   generate entry for this notice number
     --verify     send signed magic envelope to Tuomas Koski's test service
     --slap=<url> send signed Salmon slap to the destination endpoint


END_OF_HELP;
require_once INSTALLDIR . '/scripts/commandline.inc';
if (!have_option('--notice')) {
    print "{$helptext}";
    exit(1);
}
$notice_id = get_option_value('--notice');
$notice = Notice::getKV('id', $notice_id);
$profile = $notice->getProfile();
$entry = $notice->asAtomEntry(true);
echo "== Original entry ==\n\n";
print $entry;
print "\n\n";
$magic_env = MagicEnvelope::signAsUser($entry, $profile->getUser());
$envxml = $magic_env->toXML();
echo "== Signed envelope ==\n\n";
print $envxml;
print "\n\n";
echo "== Testing local verification ==\n\n";
$magic_env = new MagicEnvelope($envxml);
$activity = new Activity($magic_env->getPayload()->documentElement);
$actprofile = Profile::fromUri($activity->actor->id);
$ok = $magic_env->verify($actprofile);
Esempio n. 24
0
 function postNote($user, $author, $activity)
 {
     $note = $activity->objects[0];
     $sourceUri = $note->id;
     $notice = Notice::getKV('uri', $sourceUri);
     if ($notice instanceof Notice) {
         common_log(LOG_INFO, "Notice {$sourceUri} already exists.");
         if ($this->trusted) {
             $profile = $notice->getProfile();
             $uri = $profile->getUri();
             if ($uri === $author->id) {
                 common_log(LOG_INFO, sprintf('Updating notice author from %s to %s', $author->id, $user->getUri()));
                 $orig = clone $notice;
                 $notice->profile_id = $user->id;
                 $notice->update($orig);
                 return;
             } else {
                 // TRANS: Client exception thrown when trying to import a notice by another user.
                 // TRANS: %1$s is the source URI of the notice, %2$s is the URI of the author.
                 throw new ClientException(sprintf(_('Already know about notice %1$s and ' . ' it has a different author %2$s.'), $sourceUri, $uri));
             }
         } else {
             // TRANS: Client exception thrown when trying to overwrite the author information for a non-trusted user during import.
             throw new ClientException(_('Not overwriting author info for non-trusted user.'));
         }
     }
     // Use summary as fallback for content
     if (!empty($note->content)) {
         $sourceContent = $note->content;
     } else {
         if (!empty($note->summary)) {
             $sourceContent = $note->summary;
         } else {
             if (!empty($note->title)) {
                 $sourceContent = $note->title;
             } else {
                 // @fixme fetch from $sourceUrl?
                 // TRANS: Client exception thrown when trying to import a notice without content.
                 // TRANS: %s is the notice URI.
                 throw new ClientException(sprintf(_('No content for notice %s.'), $sourceUri));
             }
         }
     }
     // Get (safe!) HTML and text versions of the content
     $rendered = common_purify($sourceContent);
     $content = common_strip_html($rendered);
     $shortened = $user->shortenLinks($content);
     $options = array('is_local' => Notice::LOCAL_PUBLIC, 'uri' => $sourceUri, 'rendered' => $rendered, 'replies' => array(), 'groups' => array(), 'tags' => array(), 'urls' => array(), 'distribute' => false);
     // Check for optional attributes...
     if (!empty($activity->time)) {
         $options['created'] = common_sql_date($activity->time);
     }
     if ($activity->context) {
         // Any individual or group attn: targets?
         list($options['groups'], $options['replies']) = $this->filterAttention($activity->context->attention);
         // Maintain direct reply associations
         // @fixme what about conversation ID?
         if (!empty($activity->context->replyToID)) {
             $orig = Notice::getKV('uri', $activity->context->replyToID);
             if ($orig instanceof Notice) {
                 $options['reply_to'] = $orig->id;
             }
         }
         $location = $activity->context->location;
         if ($location) {
             $options['lat'] = $location->lat;
             $options['lon'] = $location->lon;
             if ($location->location_id) {
                 $options['location_ns'] = $location->location_ns;
                 $options['location_id'] = $location->location_id;
             }
         }
     }
     // Atom categories <-> hashtags
     foreach ($activity->categories as $cat) {
         if ($cat->term) {
             $term = common_canonical_tag($cat->term);
             if ($term) {
                 $options['tags'][] = $term;
             }
         }
     }
     // Atom enclosures -> attachment URLs
     foreach ($activity->enclosures as $href) {
         // @fixme save these locally or....?
         $options['urls'][] = $href;
     }
     common_log(LOG_INFO, "Saving notice {$options['uri']}");
     $saved = Notice::saveNew($user->id, $content, 'restore', $options);
     return $saved;
 }
Esempio n. 25
0
 function getNotice()
 {
     $notice = Notice::getKV('uri', $this->uri);
     if (empty($notice)) {
         // TRANS: Server exception thrown when requesting a non-exsting notice for an RSVP ("please respond").
         // TRANS: %s is the RSVP with the missing notice.
         throw new ServerException(sprintf(_m('RSVP %s does not correspond to a notice in the database.'), $this->id));
     }
     return $notice;
 }
 /**
  * Handle the request
  *
  * Make a new notice for the update, save it, and show it
  *
  * @return void
  */
 protected function handle()
 {
     parent::handle();
     // Workaround for PHP returning empty $_POST and $_FILES when POST
     // length > post_max_size in php.ini
     if (empty($_FILES) && empty($_POST) && $_SERVER['CONTENT_LENGTH'] > 0) {
         // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
         // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
         $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.', 'The server was unable to handle that much POST data (%s bytes) due to its current configuration.', intval($_SERVER['CONTENT_LENGTH']));
         $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
     }
     if (empty($this->status)) {
         // TRANS: Client error displayed when the parameter "status" is missing.
         $this->clientError(_('Client must provide a \'status\' parameter with a value.'));
     }
     if (is_null($this->scoped)) {
         // TRANS: Client error displayed when updating a status for a non-existing user.
         $this->clientError(_('No such user.'), 404);
     }
     /* Do not call shortenlinks until the whole notice has been build */
     // Check for commands
     $inter = new CommandInterpreter();
     $cmd = $inter->handle_command($this->auth_user, $this->status);
     if ($cmd) {
         if ($this->supported($cmd)) {
             $cmd->execute(new Channel());
         }
         // Cmd not supported?  Twitter just returns your latest status.
         // And, it returns your last status whether the cmd was successful
         // or not!
         $this->notice = $this->auth_user->getCurrentNotice();
     } else {
         $reply_to = null;
         if (!empty($this->in_reply_to_status_id)) {
             // Check whether notice actually exists
             $reply = Notice::getKV($this->in_reply_to_status_id);
             if ($reply) {
                 $reply_to = $this->in_reply_to_status_id;
             } else {
                 // TRANS: Client error displayed when replying to a non-existing notice.
                 $this->clientError(_('Parent notice not found.'), 404);
             }
         }
         $upload = null;
         try {
             $upload = MediaFile::fromUpload('media', $this->scoped);
         } catch (NoUploadedMediaException $e) {
             // There was no uploaded media for us today.
         }
         if (isset($upload)) {
             $this->status .= ' ' . $upload->shortUrl();
             /* Do not call shortenlinks until the whole notice has been build */
         }
         // in Qvitter we shorten _before_ posting, so disble shortening here
         $status_shortened = $this->status;
         if (Notice::contentTooLong($status_shortened)) {
             if ($upload instanceof MediaFile) {
                 $upload->delete();
             }
             // TRANS: Client error displayed exceeding the maximum notice length.
             // TRANS: %d is the maximum lenth for a notice.
             $msg = _m('Maximum notice size is %d character, including attachment URL.', 'Maximum notice size is %d characters, including attachment URL.', Notice::maxContent());
             /* Use HTTP 413 error code (Request Entity Too Large)
              * instead of basic 400 for better understanding
              */
             $this->clientError(sprintf($msg, Notice::maxContent()), 413);
         }
         $content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
         $options = array('reply_to' => $reply_to);
         // -------------------------------------------------------------
         // -------- Qvitter's post-to-the-right-group stuff! -----------
         // -------------------------------------------------------------
         // guess the groups by the content first, if we don't have group id:s as meta data
         $profile = Profile::getKV('id', $this->scoped->id);
         $guessed_groups = User_group::groupsFromText($content, $profile);
         // if the user has specified any group id:s, correct the guesswork
         if (strlen($this->post_to_groups) > 0) {
             // get the groups that the user wants to post to
             $group_ids = explode(':', $this->post_to_groups);
             $correct_groups = array();
             foreach ($group_ids as $group_id) {
                 $correct_groups[] = User_group::getKV('id', $group_id);
             }
             // correct the guesses
             $corrected_group_ids = array();
             foreach ($guessed_groups as $guessed_group) {
                 $id_to_keep = $guessed_group->id;
                 foreach ($correct_groups as $k => $correct_group) {
                     if ($correct_group->nickname == $guessed_group->nickname) {
                         $id_to_keep = $correct_group->id;
                         unset($correct_groups[$k]);
                         break;
                     }
                 }
                 $corrected_group_ids[$id_to_keep] = true;
             }
             // but we still want to post to all of the groups that the user specified by id
             // even if we couldn't use it to correct a bad guess
             foreach ($correct_groups as $correct_group) {
                 $corrected_group_ids[$correct_group->id] = true;
             }
             $options['groups'] = array_keys($corrected_group_ids);
         } else {
             $guessed_ids = array();
             foreach ($guessed_groups as $guessed_group) {
                 $guessed_ids[$guessed_group->id] = true;
             }
             $options['groups'] = array_keys($guessed_ids);
         }
         // -------------------------------------------------------------
         // ------ End of Qvitter's post-to-the-right-group stuff! ------
         // -------------------------------------------------------------
         if ($this->scoped->shareLocation()) {
             $locOptions = Notice::locationOptions($this->lat, $this->lon, null, null, $this->scoped);
             $options = array_merge($options, $locOptions);
         }
         try {
             $this->notice = Notice::saveNew($this->scoped->id, $content, $this->source, $options);
         } catch (Exception $e) {
             $this->clientError($e->getMessage(), $e->getCode());
         }
         if (isset($upload)) {
             $upload->attachToNotice($this->notice);
         }
     }
     $this->showNotice();
 }
Esempio n. 27
0
 /**
  * Checks for deleted remote notices and deleted the locally
  * A local qvitter-delete-notice is outputted in the onNoticeDeleteRelated event above
  *
  * @return boolean hook flag
  */
 public function onEndHandleFeedEntry($activity)
 {
     if ($activity->verb == 'qvitter-delete-notice' && class_exists('StatusNet') && !array_key_exists('ActivityModeration', StatusNet::getActivePlugins())) {
         $deleter_profile_uri = $activity->actor->id;
         $deleted_notice_uri = $activity->objects[0]->objects[0]->content;
         $deleted_notice_uri = substr($deleted_notice_uri, strpos($deleted_notice_uri, '{{') + 2);
         $deleted_notice_uri = substr($deleted_notice_uri, 0, strpos($deleted_notice_uri, '}}'));
         $deleter_ostatus_profile = Ostatus_profile::getKV('uri', $deleter_profile_uri);
         if (!$deleter_ostatus_profile instanceof Ostatus_profile) {
             return true;
         }
         $deleter_profile = Profile::getKV('id', $deleter_ostatus_profile->profile_id);
         $deleted_notice = Notice::getKV('uri', $deleted_notice_uri);
         if (!$deleter_profile instanceof Profile || !$deleted_notice instanceof Notice) {
             return true;
         }
         if ($deleter_profile->id != $deleted_notice->profile_id) {
             return true;
         }
         $deleted_notice->delete();
     }
     return true;
 }
Esempio n. 28
0
 public function onEndGetWebFingerResource($resource, WebFingerResource &$target = null, array $args = array())
 {
     $profile = null;
     if (Discovery::isAcct($resource)) {
         $parts = explode('@', substr(urldecode($resource), 5));
         // 5 is strlen of 'acct:'
         if (count($parts) == 2) {
             list($nick, $domain) = $parts;
             if ($domain === common_config('site', 'server')) {
                 $nick = common_canonical_nickname($nick);
                 $user = User::getKV('nickname', $nick);
                 if (!$user instanceof User) {
                     throw new NoSuchUserException(array('nickname' => $nick));
                 }
                 $profile = $user->getProfile();
             } else {
                 throw new Exception(_('Remote profiles not supported via WebFinger yet.'));
             }
         }
     } else {
         $user = User::getKV('uri', $resource);
         if ($user instanceof User) {
             $profile = $user->getProfile();
         } else {
             // try and get it by profile url
             $profile = Profile::getKV('profileurl', $resource);
         }
     }
     if ($profile instanceof Profile) {
         $target = new WebFingerResource_Profile($profile);
         return false;
         // We got our target, stop handler execution
     }
     $notice = Notice::getKV('uri', $resource);
     if ($notice instanceof Notice) {
         $target = new WebFingerResource_Notice($notice);
         return false;
     }
     return true;
 }
Esempio n. 29
0
 function getNotice()
 {
     return Notice::getKV('uri', $this->uri);
 }
Esempio n. 30
0
 function postNote($activity)
 {
     $note = $activity->objects[0];
     // Use summary as fallback for content
     if (!empty($note->content)) {
         $sourceContent = $note->content;
     } else {
         if (!empty($note->summary)) {
             $sourceContent = $note->summary;
         } else {
             if (!empty($note->title)) {
                 $sourceContent = $note->title;
             } else {
                 // @fixme fetch from $sourceUrl?
                 // TRANS: Client error displayed when posting a notice without content through the API.
                 // TRANS: %d is the notice ID (number).
                 $this->clientError(sprintf(_('No content for notice %d.'), $note->id));
             }
         }
     }
     // Get (safe!) HTML and text versions of the content
     $rendered = common_purify($sourceContent);
     $content = common_strip_html($rendered);
     $shortened = $this->auth_user->shortenLinks($content);
     $options = array('is_local' => Notice::LOCAL_PUBLIC, 'rendered' => $rendered, 'replies' => array(), 'groups' => array(), 'tags' => array(), 'urls' => array());
     // accept remote URI (not necessarily a good idea)
     common_debug("Note ID is {$note->id}");
     if (!empty($note->id)) {
         $notice = Notice::getKV('uri', trim($note->id));
         if (!empty($notice)) {
             // TRANS: Client error displayed when using another format than AtomPub.
             // TRANS: %s is the notice URI.
             $this->clientError(sprintf(_('Notice with URI "%s" already exists.'), $note->id));
         }
         common_log(LOG_NOTICE, "Saving client-supplied notice URI '{$note->id}'");
         $options['uri'] = $note->id;
     }
     // accept remote create time (also maybe not such a good idea)
     if (!empty($activity->time)) {
         common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
         $options['created'] = common_sql_date($activity->time);
     }
     // Check for optional attributes...
     if ($activity->context instanceof ActivityContext) {
         foreach ($activity->context->attention as $uri => $type) {
             try {
                 $profile = Profile::fromUri($uri);
                 if ($profile->isGroup()) {
                     $options['groups'][] = $profile->id;
                 } else {
                     $options['replies'][] = $uri;
                 }
             } catch (UnknownUriException $e) {
                 common_log(LOG_WARNING, sprintf('AtomPub post with unknown attention URI %s', $uri));
             }
         }
         // Maintain direct reply associations
         // @fixme what about conversation ID?
         if (!empty($activity->context->replyToID)) {
             $orig = Notice::getKV('uri', $activity->context->replyToID);
             if (!empty($orig)) {
                 $options['reply_to'] = $orig->id;
             }
         }
         $location = $activity->context->location;
         if ($location) {
             $options['lat'] = $location->lat;
             $options['lon'] = $location->lon;
             if ($location->location_id) {
                 $options['location_ns'] = $location->location_ns;
                 $options['location_id'] = $location->location_id;
             }
         }
     }
     // Atom categories <-> hashtags
     foreach ($activity->categories as $cat) {
         if ($cat->term) {
             $term = common_canonical_tag($cat->term);
             if ($term) {
                 $options['tags'][] = $term;
             }
         }
     }
     // Atom enclosures -> attachment URLs
     foreach ($activity->enclosures as $href) {
         // @fixme save these locally or....?
         $options['urls'][] = $href;
     }
     $saved = Notice::saveNew($this->target->id, $content, 'atompub', $options);
     return $saved;
 }