]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge remote-tracking branch 'upstream/master' into social-master
authorRoland Haeder <roland@mxchange.org>
Tue, 10 Nov 2015 18:05:53 +0000 (19:05 +0100)
committerRoland Haeder <roland@mxchange.org>
Tue, 10 Nov 2015 18:05:53 +0000 (19:05 +0100)
Signed-off-by: Roland Haeder <roland@mxchange.org>
1  2 
.gitignore
actions/doc.php
classes/Notice.php
lib/activity.php
lib/activityutils.php
lib/noticelistitem.php
plugins/Favorite/classes/Fave.php
plugins/OStatus/OStatusPlugin.php
plugins/OStatus/classes/FeedSub.php
plugins/OStatus/classes/Ostatus_profile.php
plugins/WebFinger/WebFingerPlugin.php

diff --combined .gitignore
index b9289b7c2af432167ff68d572b7aad8610965f3e,41084c45cd1cf2e0a198bef83e7fffcc2cf1d5ae..51ac39e6f29f103367ad7ef80db8d1f8a7b28ed8
@@@ -1,36 -1,32 +1,11 @@@
--avatar/*
--background/*
--files/*
--file/*
--local/*
--_darcs/*
--logs/*
--log/*
--run/*
--config.php
--.htaccess
--httpd.conf
--*.tmproj
--dataobject.ini
--*~
--*.bak
--*.orig
--*.rej
--.#*
--*.swp
--.buildpath
--.project
--.settings
--TODO.rym
--config-*.php
--good-config.php
--lac08.log
--php.log
--.DS_Store
--nbproject
--*.mo
- *log*
- htaccess-sample
- installer.txt
- extlib/DB.php
- .gitmodules
 -
++/nbproject/private/
++/nbproject/*~
++/manifest.mf
++/build/
++/dist/
++/data/*
++/*.properties
++/*-ejb/nbproject/private/
++/*-ejb/nbproject/*~
++/*-ejb/build/
++/*-ejb/dist/
diff --combined actions/doc.php
index d59c63631a4c02049f8b29ae4042c4ee37110b65,694544dd038c0a02ce6ec47e15bcdb835546535d..d897b4e58c5131d452066c57c52a58a456847bd9
@@@ -28,9 -28,7 +28,7 @@@
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('STATUSNET') && !defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('GNUSOCIAL')) { exit(1); }
  
  /**
   * Documentation class.
   * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
   * @link     http://status.net/
   */
- class DocAction extends Action
+ class DocAction extends ManagedAction
  {
      var $output   = null;
      var $filename = null;
      var $title    = null;
  
-     function prepare(array $args=array())
+     protected function doPreparation()
      {
-         parent::prepare($args);
          $this->title  = $this->trimmed('title');
          if (!preg_match('/^[a-zA-Z0-9_-]*$/', $this->title)) {
              $this->title = 'help';
          $this->output = null;
  
          $this->loadDoc();
-         return true;
-     }
-     /**
-      * Handle a request
-      *
-      * @param array $args array of arguments
-      *
-      * @return nothing
-      */
-     function handle(array $args=array())
-     {
-         parent::handle($args);
-         $this->showPage();
      }
  
-     /**
-      * Page title
-      *
-      * Gives the page title of the document. Override default for hAtom entry.
-      *
-      * @return void
-      */
-     function showPageTitle()
+     public function title()
      {
-         $this->element('h1', array('class' => 'entry-title'), $this->title());
-     }
-     /**
-      * Block for content.
-      *
-      * Overrides default from Action to wrap everything in an hAtom entry.
-      *
-      * @return void.
-      */
-     function showContentBlock()
-     {
-         $this->elementStart('div', array('id' => 'content', 'class' => 'h-entry'));
-         $this->showPageTitle();
-         $this->showPageNoticeBlock();
-         $this->elementStart('div', array('id' => 'content_inner',
-                                          'class' => 'e-content'));
-         // show the actual content (forms, lists, whatever)
-         $this->showContent();
-         $this->elementEnd('div');
-         $this->elementEnd('div');
+         return ucfirst($this->title);
      }
  
      /**
          $this->raw($this->output);
      }
  
-     /**
-      * Page title.
-      *
-      * Uses the title of the document.
-      *
-      * @return page title
-      */
-     function title()
+     function showNoticeForm()
      {
-         return ucfirst($this->title);
+         // no notice form
      }
  
      /**
       *
       * @return boolean read-only flag (false)
       */
 -    function isReadOnly($args)
 +    function isReadOnly(array $args=array())
      {
          return true;
      }
diff --combined classes/Notice.php
index 0fe1296bc3f8624573941e4219b29b8d26a440f2,41c4544cf2fc69efc5ce84c43fbbea11729b2f5a..37310af8ef638190df12783aa65bccf52c93b5a9
@@@ -158,6 -158,14 +158,14 @@@ class Notice extends Managed_DataObjec
          $this->_profile[$this->profile_id] = $profile;
      }
  
+     public function deleteAs(Profile $actor)
+     {
+         if ($this->getProfile()->sameAs($actor) || $actor->hasRight(Right::DELETEOTHERSNOTICE)) {
+             return $this->delete();
+         }
+         throw new AuthorizationException('You are not allowed to delete other user\'s notices');
+     }
      function delete($useWhere=false)
      {
          // For auditing purposes, save a record that the notice
       * Record the given set of hash tags in the db for this notice.
       * Given tag strings will be normalized and checked for dupes.
       */
 -    function saveKnownTags($hashtags)
 +    function saveKnownTags(array $hashtags)
      {
          //turn each into their canonical tag
          //this is needed to remove dupes before saving e.g. #hash.tag = #hashtag
       * @return Notice
       * @throws ClientException
       */
 -    static function saveNew($profile_id, $content, $source, array $options=null) {
 +    static function saveNew($profile_id, $content, $source, array $options=array()) {
          $defaults = array('uri' => null,
                            'url' => null,
                            'conversation' => null,   // URI of conversation
                            'object_type' => null,
                            'verb' => null);
  
 -        if (!empty($options) && is_array($options)) {
 +        /*
 +         * Above type-hint is already array, so simply count it, this saves
 +         * "some" CPU cycles.
 +         */
 +        if (count($options) > 0) {
              $options = array_merge($defaults, $options);
 -            extract($options);
 -        } else {
 -            extract($defaults);
          }
  
 +        extract($options);
 +
          if (!isset($is_local)) {
              $is_local = Notice::LOCAL_PUBLIC;
          }
                  throw new ClientException(_('You cannot repeat your own notice.'));
              }
  
 -            if ($repeat->scope != Notice::SITE_SCOPE &&
 -                $repeat->scope != Notice::PUBLIC_SCOPE) {
 +            if ($repeat->isPrivateScope()) {
                  // TRANS: Client error displayed when trying to repeat a non-public notice.
                  throw new ClientException(_('Cannot repeat a private notice.'), 403);
              }
       *
       * @return void
       */
 -    function saveKnownUrls($urls)
 +    function saveKnownUrls(array $urls)
      {
          if (common_config('attachments', 'process_links')) {
              // @fixme validation?
          return $this->_replies[$this->getID()];
      }
  
 -    function _setReplies($replies)
 +    function _setReplies(array $replies)
      {
          $this->_replies[$this->getID()] = $replies;
      }
                }
  
                $groups = User_group::multiGet('id', $ids);
 -              $this->_groups[$this->id] = $groups->fetchAll();
 +              $this->_setGroups($groups->fetchAll());
                return $this->_groups[$this->id];
      }
  
 -    function _setGroups($groups)
 +    function _setGroups(array $groups)
      {
          $this->_groups[$this->id] = $groups;
      }
       */
      public function getTags()
      {
 +        // Check default scope (non-private notices)
 +        $inScope = (!$this->isPrivateScope());
 +
 +        // Get current profile
 +        $profile = Profile::current();
 +
 +        // Is the general scope check okay and the user in logged in?
 +        //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . ']: inScope=' . intval($inScope) . ',profile[]=' . gettype($profile));
 +        if (($inScope === TRUE) && ($profile instanceof Profile)) {
 +            /*
 +             * Check scope, else a privacy leaks happens this way:
 +             *
 +             * 1) Bob and Alice follow each other and write private notices
 +             *    (this->scope=2) to each other.
 +             * 2) Bob uses tags in his private notice to alice (which she can
 +             *    read from him).
 +             * 3) Alice adds that notice (with tags) to her favorites
 +             *    ("faving") it.
 +             * 4) The tags from Bob's private notice becomes visible in Alice's
 +             *    profile.
 +             *
 +             * This has the simple background that the scope is not being
 +             * re-checked. This has to be done here at this point because given
 +             * above scenario is a privacy leak as the tags may be *really*
 +             * private (nobody else shall see them) such as initmate words or
 +             * very political words.
 +             */
 +            $inScope = $this->inScope($profile);
 +            //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . ']: inScope=' . intval($inScope) . ' - After inScope() has been called.');
 +        }
 +
          $tags = array();
  
          $keypart = sprintf('notice:tags:%d', $this->id);
          } else {
              $tag = new Notice_tag();
              $tag->notice_id = $this->id;
 -            if ($tag->find()) {
 +
 +            // Check scope for privacy-leak protection (see some lines above why)
 +            if (($inScope === TRUE) && ($tag->find())) {
                  while ($tag->fetch()) {
                      $tags[] = $tag->tag;
                  }
                  ($this->is_local != Notice::GATEWAY));
      }
  
 +    public function isPrivateScope () {
 +        return ($this->scope != Notice::SITE_SCOPE &&
 +                $this->scope != Notice::PUBLIC_SCOPE);
 +    }
 +
      /**
       * Check that the given profile is allowed to read, respond to, or otherwise
       * act on this notice.
       *
       * @return boolean whether the profile is in the notice's scope
       */
 -    function inScope($profile)
 +    function inScope(Profile $profile=null)
      {
          if (is_null($profile)) {
              $keypart = sprintf('notice:in-scope-for:%d:null', $this->id);
          return ($result == 1) ? true : false;
      }
  
 -    protected function _inScope($profile)
 +    protected function _inScope(Profile $profile=null)
      {
          if (!is_null($this->scope)) {
              $scope = $this->scope;
          return !$this->isHiddenSpam($profile);
      }
  
 -    function isHiddenSpam($profile) {
 +    function isHiddenSpam(Profile $profile=null) {
  
          // Hide posts by silenced users from everyone but moderators.
  
        return $scope;
      }
  
 -      static function fillProfiles($notices)
 +      static function fillProfiles(array $notices)
        {
                $map = self::getProfiles($notices);
                foreach ($notices as $entry=>$notice) {
                return array_values($map);
        }
  
 -      static function getProfiles(&$notices)
 +      static function getProfiles(array &$notices)
        {
                $ids = array();
                foreach ($notices as $notice) {
                return Profile::pivotGet('id', $ids);
        }
  
 -      static function fillGroups(&$notices)
 +      static function fillGroups(array &$notices)
        {
          $ids = self::_idsOf($notices);
          $gis = Group_inbox::listGet('notice_id', $ids);
                return array_keys($ids);
      }
  
 -    static function fillAttachments(&$notices)
 +    static function fillAttachments(array &$notices)
      {
          $ids = self::_idsOf($notices);
          $f2pMap = File_to_post::listGet('post_id', $ids);
                }
      }
  
 -    static function fillReplies(&$notices)
 +    static function fillReplies(array &$notices)
      {
          $ids = self::_idsOf($notices);
          $replyMap = Reply::listGet('notice_id', $ids);
          }
      }
  
 +    /**
 +     * Checks whether the current profile is allowed (in scope) to see this notice.
 +     *
 +     * @return $inScope Whether the current profile is allowed to see this notice
 +     */
 +    function isCurrentProfileInScope () {
 +        // Check scope, default is allowed
 +        $inScope = TRUE;
 +
 +        //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . '] this->tag=' . $this->tag . ',this->id=' . $this->id . ',this->scope=' . $this->scope);
 +
 +        // Is it private scope?
 +        if ($this->isPrivateScope()) {
 +            // 2) Get current profile
 +            $profile = Profile::current();
 +
 +            // Is the profile not set?
 +            if (!$profile instanceof Profile) {
 +                // Public viewer shall not see a tag from a private dent (privacy leak)
 +                //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . '] Not logged in (public view).');
 +                $inScope = FALSE;
 +            } elseif (!$this->inScope($profile)) {
 +                // Current profile is not in scope (not allowed to see) of notice
 +                //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . '] profile->id=' . $profile->id . ' is not allowed to see this notice.');
 +                $inScope = FALSE;
 +            }
 +        }
 +
 +        // Return result
 +        //* NOISY-DEBUG: */ common_debug('[' . __METHOD__ . ':' . __LINE__ . '] this->tag=' . $this->tag . ',this->weight=' . $this->weight . ',inScope=' . intval($inScope) . ' - EXIT!');
 +        return $inScope;
 +    }
 +
      static public function beforeSchemaUpdate()
      {
          $table = strtolower(get_called_class());
diff --combined lib/activity.php
index 6b3ccf3519dd496b98b95dafe6107eeea1772bb5,4db3b9ff4e801c2bab10772ebb800ddadf578a0c..49e7fdbcd4020c57ad2cd3c362156cc7e368a126
@@@ -107,7 -107,6 +107,7 @@@ class Activit
      public $selfLink; // <link rel='self' type='application/atom+xml'>
      public $editLink; // <link rel='edit' type='application/atom+xml'>
      public $generator; // ActivityObject representing the generating application
 +
      /**
       * Turns a regular old Atom <entry> into a magical activity
       *
  
          if (!empty($targetEl)) {
              $this->target = new ActivityObject($targetEl);
-         } elseif (ActivityUtils::compareTypes($this->verb, array(ActivityVerb::FAVORITE))) {
+         } elseif (ActivityUtils::compareVerbs($this->verb, array(ActivityVerb::FAVORITE))) {
              // StatusNet didn't send a 'target' for their Favorite atom entries
              $this->target = clone($this->objects[0]);
          }
diff --combined lib/activityutils.php
index ac7eb9421334cee2b508aca2bb827fb2cc1faf17,ef2e23224374b6a9ddd9629ef366e7f19ed0bdb7..bb430c6f7849b8f0818b18933d190f1d7005aab9
@@@ -301,7 -301,7 +301,7 @@@ class ActivityUtil
          return false;
      }
  
 -    static function getFeedAuthor($feedEl)
 +    static function getFeedAuthor(DOMElement $feedEl)
      {
          // Try old and deprecated activity:subject
  
          return null;
      }
  
-     static function compareTypes($type, array $objects)    // this does verbs too!
 -    static function compareTypes($type, $objects)
++    static function compareTypes($type, array $objects)
      {
          $type = self::resolveUri($type);
 -        foreach ((array)$objects as $object) {
 +        foreach ($objects as $object) {
              if ($type === self::resolveUri($object)) {
                  return true;
              }
          return false;
      }
  
+     static function compareVerbs($type, $objects)
+     {
+         return self::compareTypes($type, $objects);
+     }
      static function resolveUri($uri, $make_relative=false)
      {
          if (empty($uri)) {
diff --combined lib/noticelistitem.php
index 36668a8f77bf7685b45cd12b23cc36ee7e562f0b,2fa41038925d595e4ec9c384d3f2a63efdb9ea24..88bb8bf92710429aad5f6f94d932bf9b404db8d3
@@@ -64,6 -64,7 +64,7 @@@ class NoticeListItem extends Widge
      protected $options = true;
      protected $maxchars = 0;   // if <= 0 it means use full posts
      protected $item_tag = 'li';
+     protected $pa = null;
  
      /**
       * constructor
          $this->elementStart('section', array('class'=>'notice-headers'));
          $this->showNoticeTitle();
          $this->showAuthor();
-         if ($this->addressees) { $this->showAddressees(); }
+         if (!empty($this->notice->reply_to) || count($this->getProfileAddressees()) > 0) {
+             $this->elementStart('div', array('class' => 'parents'));
+             if (!empty($this->notice->reply_to)) { $this->showParent(); }
+             if ($this->addressees) { $this->showAddressees(); }
+             $this->elementEnd('div');
+         }
          $this->elementEnd('section');
      }
  
      {
          if (Event::handle('StartShowNoticeOptions', array($this))) {
              $user = common_current_user();
 -            if ($user) {
 +
 +            if ($user instanceof User) {
                  $this->out->elementStart('div', 'notice-options');
                  if (Event::handle('StartShowNoticeOptionItems', array($this))) {
                      $this->showReplyLink();
                  }
                  $this->out->elementEnd('div');
              }
 +
              Event::handle('EndShowNoticeOptions', array($this));
          }
      }
      function showAuthor()
      {
          $attrs = array('href' => $this->profile->profileurl,
-                        'class' => 'h-card p-author',
+                        'class' => 'h-card',
                         'title' => $this->profile->getNickname());
+         if(empty($this->repeat)) { $attrs['class'] .= ' p-author'; }
  
          if (Event::handle('StartShowNoticeItemAuthor', array($this->profile, $this->out, &$attrs))) {
              $this->out->elementStart('a', $attrs);
          }
      }
  
+     function showParent()
+     {
+         $this->out->element(
+             'a',
+             array(
+                 'href' => $this->notice->getParent()->getUrl(),
+                 'class' => 'u-in-reply-to',
+                 'rel' => 'in-reply-to'
+             ),
+             'in reply to'
+         );
+     }
      function showAddressees()
      {
          $pa = $this->getProfileAddressees();
  
      function getProfileAddressees()
      {
-         $pa = array();
+         if($this->pa) { return $this->pa; }
+         $this->pa = array();
  
          $attentions = $this->getReplyProfiles();
  
          foreach ($attentions as $attn) {
              $class = $attn->isGroup() ? 'group' : 'account';
-             $pa[] = array('href' => $attn->profileurl,
-                           'title' => $attn->getNickname(),
-                           'class' => "addressee {$class}",
-                           'text' => $attn->getStreamName());
+             $this->pa[] = array('href' => $attn->profileurl,
+                                 'title' => $attn->getNickname(),
+                                 'class' => "addressee {$class}",
+                                 'text' => $attn->getStreamName());
          }
  
-         return $pa;
+         return $this->pa;
      }
  
      function getReplyProfiles()
index 310679ef637941fe34cd174e663bd6661bf759a6,f40efcf8abb82a089e1581807dcd324e4019aa2e..51e11153dbc8d57588b7f13f04dce358b827a3da
@@@ -250,7 -250,7 +250,7 @@@ class Fave extends Managed_DataObjec
       *
       * @return array Array of Fave objects
       */
 -    static public function byNotice($notice)
 +    static public function byNotice(Notice $notice)
      {
          if (!isset(self::$_faves[$notice->id])) {
              self::fillFaves(array($notice->id));
          $target = self::getTargetFromStored($stored);
  
          // The following logic was copied from StatusNet's Activity plugin
-         if (ActivityUtils::compareTypes($target->verb, array(ActivityVerb::POST))) {
+         if (ActivityUtils::compareVerbs($target->verb, array(ActivityVerb::POST))) {
              // "I like the thing you posted"
              $act->objects = $target->asActivity()->objects;
          } else {
index 41f9abfcdff2383e3bbcab0cae3d58e08f0440f6,bc08a62eff7b6f628417096e0ddb7f8af8f330cc..8f729bef6f57aae03900dd90aadc88c88d4a8ec6
@@@ -104,13 -104,16 +104,16 @@@ class OStatusPlugin extends Plugi
  
          // Incoming from a foreign PuSH hub
          $qm->connect('pushin', 'PushInQueueHandler');
+         // Re-subscribe feeds that need renewal
+         $qm->connect('pushrenew', 'PushRenewQueueHandler');
          return true;
      }
  
      /**
       * Put saved notices into the queue for pubsub distribution.
       */
 -    function onStartEnqueueNotice($notice, &$transports)
 +    function onStartEnqueueNotice(Notice $notice, array &$transports)
      {
          if ($notice->inScope(null)) {
              // put our transport first, in case there's any conflict (like OMB)
      /*
       * If the field being looked for is URI look for the profile
       */
 -    function onStartProfileCompletionSearch($action, $profile, $search_engine) {
 +    public function onStartProfileCompletionSearch(Action $action, Profile $profile, $search_engine) {
          if ($action->field == 'uri') {
              $profile->joinAdd(array('id', 'user:id'));
              $profile->whereAdd('uri LIKE "%' . $profile->escape($q) . '%"');
       * @param array &$mention in/out param: set of found mentions
       * @return boolean hook return value
       */
 -    function onEndFindMentions(Profile $sender, $text, &$mentions)
 +    function onEndFindMentions(Profile $sender, $text, array &$mentions)
      {
          $matches = array();
  
       * @param Profile &$profile
       * @return hook return code
       */
 -    function onStartCommandGetProfile($command, $arg, &$profile)
 +    public function onStartCommandGetProfile(Command $command, $arg, Profile &$profile = null)
      {
          $oprofile = $this->pullRemoteProfile($arg);
          if ($oprofile instanceof Ostatus_profile && !$oprofile->isGroup()) {
       * @param User_group &$group
       * @return hook return code
       */
 -    function onStartCommandGetGroup($command, $arg, &$group)
 +    function onStartCommandGetGroup(Command $command, $arg, User_group &$group = null)
      {
          $oprofile = $this->pullRemoteProfile($arg);
          if ($oprofile instanceof Ostatus_profile && $oprofile->isGroup()) {
          return true;
      }
  
 -    function onEndShowStatusNetScripts($action) {
 +    public function onEndShowStatusNetScripts(Action $action) {
          $action->script($this->path('js/ostatus.js'));
          return true;
      }
          if ($oprofile instanceof Ostatus_profile) {
              $oprofile->processFeed($feed, 'push');
          } else {
 -            common_log(LOG_DEBUG, "No ostatus profile for incoming feed $feedsub->uri");
 +            common_debug("No ostatus profile for incoming feed $feedsub->uri");
          }
      }
  
          $oprofile->query(sprintf($sql, $profile->id, $profile->id));
  
          if ($oprofile->N == 0) {
 -            common_log(LOG_DEBUG, "No OStatus remote subscribees for $profile->nickname");
 +            common_debug("No OStatus remote subscribees for $profile->nickname");
              return true;
          }
  
          return true;
      }
  
 -    public function onProfileDeleteRelated($profile, &$related)
 +    public function onProfileDeleteRelated(Profile $profile, array &$related)
      {
          // Ostatus_profile has a 'profile_id' property, which will be used to find the object
          $related[] = 'Ostatus_profile';
          }
          return true;
      }
+     public function onCronDaily()
+     {
+         try {
+             $sub = FeedSub::renewalCheck();
+         } catch (NoResultException $e) {
+             common_log(LOG_INFO, "There were no expiring feeds.");
+             return;
+         }
+         $qm = QueueManager::get();
+         while ($sub->fetch()) {
+             $item = array('feedsub_id' => $sub->id);
+             $qm->enqueue($item, 'pushrenew');
+         }
+     }
  }
index 149d57f63cc76b996e9bd4701c3c8f51bb366e9c,0c7129e885a5983671dc7527110fe12f7c98d082..b0875c298865b86f70fa1d8c57c272368d73d25a
@@@ -295,7 -295,7 +295,7 @@@ class FeedSub extends Managed_DataObjec
      {
          $fs = new FeedSub();
          // the "" empty string check is because we historically haven't saved unsubscribed feeds as NULL
-         $fs->whereAdd('sub_end IS NOT NULL AND sub_end!="" AND sub_end < NOW() - INTERVAL 1 day');
+         $fs->whereAdd('sub_end IS NOT NULL AND sub_end!="" AND sub_end < NOW() + INTERVAL 1 day');
          if (!$fs->find()) { // find can be both false and 0, depending on why nothing was found
              throw new NoResultException($fs);
          }
              $response = $client->post($hub, $headers, $post);
              $status = $response->getStatus();
              // PuSH specificed response status code
-             if ($status == 202) {
+             if ($status == 202  || $status == 204) {
                  common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback');
                  return;
              } else if ($status >= 200 && $status < 300) {
                      return true;
                  }
                  if (common_config('feedsub', 'debug')) {
 -                    $tempfile = tempnam(sys_get_temp_dir(), 'feedsub-receive');
 +                    $tempfile = tempnam(common_get_temp_dir(), 'feedsub-receive');
                      if ($tempfile) {
                          file_put_contents($tempfile, $post);
                      }
index be8a6f66a710a37c42c39f716eb427d146d9b090,da7a4b424475087ac251c553fa9f8c443c33d20e..ddd1a2a38dfe145ba881e3f6d94e9ea254edcb8e
@@@ -371,10 -371,9 +371,10 @@@ class Ostatus_profile extends Managed_D
       * send immediately but won't get the return value.
       *
       * @param mixed $entry XML string, Notice, or Activity
 +     * @param Profile $actor Acting profile
       * @return boolean success
       */
 -    public function notifyDeferred($entry, $actor)
 +    public function notifyDeferred($entry, Profile $actor)
      {
          if ($this->salmonuri) {
              $data = array('salmonuri' => $this->salmonuri,
       *
       * @return Notice Notice representing the new (or existing) activity
       */
 -    public function processEntry($entry, $feed, $source)
 +    public function processEntry(DOMElement $entry, DOMElement $feed, $source)
      {
          $activity = new Activity($entry, $feed);
          return $this->processActivity($activity, $source);
      }
  
      // TODO: Make this throw an exception
 -    public function processActivity($activity, $source)
 +    public function processActivity(Activity $activity, $source)
      {
          $notice = null;
  
       * @return mixed saved Notice or false
       * @todo FIXME: Break up this function, it's getting nasty long
       */
 -    public function processPost($activity, $method)
 +    public function processPost(Activity $activity, $method)
      {
          $notice = null;
  
       */
      static public function filterAttention(Profile $sender, array $attention)
      {
 -        common_log(LOG_DEBUG, "Original reply recipients: " . implode(', ', array_keys($attention)));
 +        common_debug("Original reply recipients: " . implode(', ', array_keys($attention)));
          $groups = array();
          $replies = array();
          foreach ($attention as $recipient=>$type) {
                      if ($sender->isMember($group)) {
                          $groups[] = $group->id;
                      } else {
 -                        common_log(LOG_DEBUG, sprintf('Skipping reply to local group %s as sender %d is not a member', $group->getNickname(), $sender->id));
 +                        common_debug(sprintf('Skipping reply to local group %s as sender %d is not a member', $group->getNickname(), $sender->id));
                      }
                      continue;
                  } else {
 -                    common_log(LOG_DEBUG, "Skipping reply to bogus group $recipient");
 +                    common_debug("Skipping reply to bogus group $recipient");
                  }
              }
  
                  continue;
              } catch (Exception $e) {
                  // Neither a recognizable local nor remote user!
 -                common_log(LOG_DEBUG, "Skipping reply to unrecognized profile $recipient: " . $e->getMessage());
 +                common_debug("Skipping reply to unrecognized profile $recipient: " . $e->getMessage());
              }
  
          }
 -        common_log(LOG_DEBUG, "Local reply recipients: " . implode(', ', $replies));
 -        common_log(LOG_DEBUG, "Local group recipients: " . implode(', ', $groups));
 +        common_debug("Local reply recipients: " . implode(', ', $replies));
 +        common_debug("Local group recipients: " . implode(', ', $groups));
          return array($groups, $replies);
      }
  
              }
          }
  
+         $obj = ActivityUtils::getFeedAuthor($feedEl);
          // @todo FIXME: We should check whether this feed has elements
          // with different <author> or <dc:creator> elements, and... I dunno.
          // Do something about that.
  
-         $obj = ActivityObject::fromRssChannel($feedEl);
+         if(empty($obj)) { $obj = ActivityObject::fromRssChannel($feedEl); }
  
          return self::ensureActivityObjectProfile($obj, $hints);
      }
  
          // @todo FIXME: This should be better encapsulated
          // ripped from oauthstore.php (for old OMB client)
 -        $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
 +        $temp_filename = tempnam(common_get_temp_dir(), 'listener_avatar');
          try {
              $imgData = HTTPClient::quickGet($url);
              // Make sure it's at least an image file. ImageFile can do the rest.
          $discover = false;
  
          if (!$homeuri) {
 -            common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true));
 +            common_debug(__METHOD__ . " empty actor profile URI: " . var_export($activity, true));
              // TRANS: Exception.
              throw new Exception(_m('No profile URI.'));
          }
          // @todo tags from categories
  
          if ($profile->id) {
 -            common_log(LOG_DEBUG, "Updating OStatus profile $profile->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
 +            common_debug("Updating OStatus profile $profile->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
              $profile->update($orig);
          }
      }
          $group->homepage = self::getActivityObjectHomepage($object, $hints);
  
          if ($group->id) {   // If no id, we haven't called insert() yet, so don't run update()
 -            common_log(LOG_DEBUG, "Updating OStatus group $group->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
 +            common_debug("Updating OStatus group $group->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
              $group->update($orig);
          }
      }
  
 -    protected static function updatePeopletag($tag, ActivityObject $object, array $hints=array()) {
 +    protected static function updatePeopletag(Peopletag $tag, ActivityObject $object, array $hints=array()) {
          $orig = clone($tag);
  
          $tag->tag = $object->title;
          $tag->tagger = $tagger->profile_id;
  
          if ($tag->id) {
 -            common_log(LOG_DEBUG, "Updating OStatus peopletag $tag->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
 +            common_debug("Updating OStatus peopletag $tag->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
              $tag->update($orig);
          }
      }
          } else {
              $actor = $activity->actor;
  
 -            if (empty($actor)) {
 +            if (!$actor instanceof Profile) {
                  // OK here! assume the default
              } else if ($actor->id == $this->getUri() || $actor->link == $this->getUri()) {
                  $this->updateFromActivityObject($actor);
index 28dc1bf0798bbbf52fc9348c6c6338f955040af6,ce8c847aa799c2c744490f3b0e40779810a54f62..1edc3d8971351790ac70f9fc22418800814a6237
@@@ -42,7 -42,7 +42,7 @@@ class WebFingerPlugin extends Plugi
          common_config_set('webfinger', 'http_alias', $this->http_alias);
      }
  
 -    public function onRouterInitialized($m)
 +    public function onRouterInitialized(URLMapper $m)
      {
          $m->connect('.well-known/host-meta', array('action' => 'hostmeta'));
          $m->connect('.well-known/host-meta.:format',
      /**
       * Add a link header for LRDD Discovery
       */
 -    public function onStartShowHTML($action)
 +    public function onStartShowHTML(Action $action)
      {
          if ($action instanceof ShowstreamAction) {
              $acct = 'acct:'. $action->getTarget()->getNickname() .'@'. 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.'"');
+                 header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="'.$type.'"', false);
              }
          }
      }