]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/OStatus/OStatusPlugin.php
Merge branch 'swat0' into 0.9.x
[quix0rs-gnu-social.git] / plugins / OStatus / OStatusPlugin.php
index 9d5613b200c8847694b1b81eee18411987017b2c..f9a8782faa119284f8414d508e8a637185b92c31 100644 (file)
@@ -28,6 +28,15 @@ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/ext
 
 class FeedSubException extends Exception
 {
+    function __construct($msg=null)
+    {
+        $type = get_class($this);
+        if ($msg) {
+            parent::__construct("$type: $msg");
+        } else {
+            parent::__construct($type);
+        }
+    }
 }
 
 class OStatusPlugin extends Plugin
@@ -44,15 +53,19 @@ class OStatusPlugin extends Plugin
         $m->connect('.well-known/host-meta',
                     array('action' => 'hostmeta'));
         $m->connect('main/xrd',
-                    array('action' => 'xrd'));
+                    array('action' => 'userxrd'));
+        $m->connect('main/ownerxrd',
+                    array('action' => 'ownerxrd'));
         $m->connect('main/ostatus',
                     array('action' => 'ostatusinit'));
         $m->connect('main/ostatus?nickname=:nickname',
                   array('action' => 'ostatusinit'), array('nickname' => '[A-Za-z0-9_-]+'));
+        $m->connect('main/ostatus?group=:group',
+                  array('action' => 'ostatusinit'), array('group' => '[A-Za-z0-9_-]+'));
         $m->connect('main/ostatussub',
                     array('action' => 'ostatussub'));
-        $m->connect('main/ostatussub',
-                    array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+'));
+        $m->connect('main/ostatusgroup',
+                    array('action' => 'ostatusgroup'));
 
         // PuSH actions
         $m->connect('main/push/hub', array('action' => 'pushhub'));
@@ -83,6 +96,8 @@ class OStatusPlugin extends Plugin
 
         // Outgoing from our internal PuSH hub
         $qm->connect('hubconf', 'HubConfQueueHandler');
+        $qm->connect('hubprep', 'HubPrepQueueHandler');
+
         $qm->connect('hubout', 'HubOutQueueHandler');
 
         // Outgoing Salmon replies (when we don't need a return value)
@@ -98,7 +113,10 @@ class OStatusPlugin extends Plugin
      */
     function onStartEnqueueNotice($notice, &$transports)
     {
-        $transports[] = 'ostatus';
+        if ($notice->isLocal()) {
+            // put our transport first, in case there's any conflict (like OMB)
+            array_unshift($transports, 'ostatus');
+        }
         return true;
     }
 
@@ -109,13 +127,13 @@ class OStatusPlugin extends Plugin
     {
         if ($action instanceof ShowstreamAction) {
             $acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server');
-            $url = common_local_url('xrd');
+            $url = common_local_url('userxrd');
             $url.= '?uri='. $acct;
-            
+
             header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"');
         }
     }
-    
+
     /**
      * Set up a PuSH hub link to our internal link for canonical timeline
      * Atom feeds for users and groups.
@@ -149,6 +167,9 @@ class OStatusPlugin extends Plugin
 
             // Also, we'll add in the salmon link
             $salmon = common_local_url($salmonAction, array('id' => $id));
+            $feed->addLink($salmon, array('rel' => Salmon::REL_SALMON));
+
+            // XXX: these are deprecated
             $feed->addLink($salmon, array('rel' => Salmon::NS_REPLIES));
             $feed->addLink($salmon, array('rel' => Salmon::NS_MENTIONS));
         }
@@ -216,29 +237,14 @@ class OStatusPlugin extends Plugin
 
         if (empty($cur)) {
             // Add an OStatus subscribe
-            $output->elementStart('li', 'entity_subscribe');
             $url = common_local_url('ostatusinit',
-                                    array('nickname' => $group->nickname));
+                                    array('group' => $group->nickname));
             $output->element('a', array('href' => $url,
                                         'class' => 'entity_remote_subscribe'),
                                 _m('Join'));
-
-            $output->elementEnd('li');
         }
 
-        return false;
-    }
-
-
-    /**
-     * Check if we've got remote replies to send via Salmon.
-     *
-     * @fixme push webfinger lookup & sending to a background queue
-     * @fixme also detect short-form name for remote subscribees where not ambiguous
-     */
-
-    function onEndNoticeSave($notice)
-    {
+        return true;
     }
 
     /**
@@ -256,7 +262,7 @@ class OStatusPlugin extends Plugin
         $matches = array();
 
         // Webfinger matches: @user@example.com
-        if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)!',
+        if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\-?\w+\.)*\w+(?:\w+\-\w+)*\.\w+)!',
                        $text,
                        $wmatches,
                        PREG_OFFSET_CAPTURE)) {
@@ -290,7 +296,7 @@ class OStatusPlugin extends Plugin
                     $url = "$scheme://$target";
                     $this->log(LOG_INFO, "Checking profile address '$url'");
                     try {
-                        $oprofile = Ostatus_profile::ensureProfile($url);
+                        $oprofile = Ostatus_profile::ensureProfileURL($url);
                         if ($oprofile && !$oprofile->isGroup()) {
                             $profile = $oprofile->localProfile();
                             $matches[$pos] = array('mentioned' => array($profile),
@@ -321,6 +327,86 @@ class OStatusPlugin extends Plugin
         return true;
     }
 
+    /**
+     * Allow remote profile references to be used in commands:
+     *   sub update@status.net
+     *   whois evan@identi.ca
+     *   reply http://identi.ca/evan hey what's up
+     *
+     * @param Command $command
+     * @param string $arg
+     * @param Profile &$profile
+     * @return hook return code
+     */
+    function onStartCommandGetProfile($command, $arg, &$profile)
+    {
+        $oprofile = $this->pullRemoteProfile($arg);
+        if ($oprofile && !$oprofile->isGroup()) {
+            $profile = $oprofile->localProfile();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Allow remote group references to be used in commands:
+     *   join group+statusnet@identi.ca
+     *   join http://identi.ca/group/statusnet
+     *   drop identi.ca/group/statusnet
+     *
+     * @param Command $command
+     * @param string $arg
+     * @param User_group &$group
+     * @return hook return code
+     */
+    function onStartCommandGetGroup($command, $arg, &$group)
+    {
+        $oprofile = $this->pullRemoteProfile($arg);
+        if ($oprofile && $oprofile->isGroup()) {
+            $group = $oprofile->localGroup();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    protected function pullRemoteProfile($arg)
+    {
+        $oprofile = null;
+        if (preg_match('!^((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)$!', $arg)) {
+            // webfinger lookup
+            try {
+                return Ostatus_profile::ensureWebfinger($arg);
+            } catch (Exception $e) {
+                common_log(LOG_ERR, 'Webfinger lookup failed for ' .
+                                    $arg . ': ' . $e->getMessage());
+            }
+        }
+
+        // Look for profile URLs, with or without scheme:
+        $urls = array();
+        if (preg_match('!^https?://((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) {
+            $urls[] = $arg;
+        }
+        if (preg_match('!^((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) {
+            $schemes = array('http', 'https');
+            foreach ($schemes as $scheme) {
+                $urls[] = "$scheme://$arg";
+            }
+        }
+
+        foreach ($urls as $url) {
+            try {
+                return Ostatus_profile::ensureProfileURL($url);
+            } catch (Exception $e) {
+                common_log(LOG_ERR, 'Profile lookup failed for ' .
+                                    $arg . ': ' . $e->getMessage());
+            }
+        }
+        return null;
+    }
+
     /**
      * Make sure necessary tables are filled out.
      */
@@ -335,12 +421,12 @@ class OStatusPlugin extends Plugin
     }
 
     function onEndShowStatusNetStyles($action) {
-        $action->cssLink(common_path('plugins/OStatus/theme/base/css/ostatus.css'));
+        $action->cssLink('plugins/OStatus/theme/base/css/ostatus.css');
         return true;
     }
 
     function onEndShowStatusNetScripts($action) {
-        $action->script(common_path('plugins/OStatus/js/ostatus.js'));
+        $action->script('plugins/OStatus/js/ostatus.js');
         return true;
     }
 
@@ -371,6 +457,7 @@ class OStatusPlugin extends Plugin
                 return false;
             }
         }
+       return true;
     }
 
     /**
@@ -390,6 +477,24 @@ class OStatusPlugin extends Plugin
         }
     }
 
+    /**
+     * Tell the FeedSub infrastructure whether we have any active OStatus
+     * usage for the feed; if not it'll be able to garbage-collect the
+     * feed subscription.
+     *
+     * @param FeedSub $feedsub
+     * @param integer $count in/out
+     * @return mixed hook return code
+     */
+    function onFeedSubSubscriberCount($feedsub, &$count)
+    {
+        $oprofile = Ostatus_profile::staticGet('feeduri', $feedsub->uri);
+        if ($oprofile) {
+            $count += $oprofile->subscriberCount();
+        }
+        return true;
+    }
+
     /**
      * When about to subscribe to a remote user, start a server-to-server
      * PuSH subscription if needed. If we can't establish that, abort.
@@ -587,7 +692,6 @@ class OStatusPlugin extends Plugin
             // Drop the PuSH subscription if there are no other subscribers.
             $oprofile->garbageCollect();
 
-
             $member = Profile::staticGet($user->id);
 
             $act = new Activity();
@@ -731,6 +835,13 @@ class OStatusPlugin extends Plugin
         return true;
     }
 
+    function onStartShowUserGroupsContent($action)
+    {
+        $this->showEntityRemoteSubscribe($action, 'ostatusgroup');
+
+        return true;
+    }
+
     function onEndShowSubscriptionsMiniList($action)
     {
         $this->showEntityRemoteSubscribe($action);
@@ -740,21 +851,21 @@ class OStatusPlugin extends Plugin
 
     function onEndShowGroupsMiniList($action)
     {
-        $this->showEntityRemoteSubscribe($action);
+        $this->showEntityRemoteSubscribe($action, 'ostatusgroup');
 
         return true;
     }
 
-    function showEntityRemoteSubscribe($action)
+    function showEntityRemoteSubscribe($action, $target='ostatussub')
     {
         $user = common_current_user();
         if ($user && ($user->id == $action->profile->id)) {
             $action->elementStart('div', 'entity_actions');
             $action->elementStart('p', array('id' => 'entity_remote_subscribe',
                                              'class' => 'entity_subscribe'));
-            $action->element('a', array('href' => common_local_url('ostatussub'),
+            $action->element('a', array('href' => common_local_url($target),
                                         'class' => 'entity_remote_subscribe')
-                                , _m('New'));
+                                , _m('Remote'));
             $action->elementEnd('p');
             $action->elementEnd('div');
         }
@@ -806,4 +917,85 @@ class OStatusPlugin extends Plugin
 
         return true;
     }
+
+    function onStartProfileListItemActionElements($item)
+    {
+        if (!common_logged_in()) {
+
+            $profileUser = User::staticGet('id', $item->profile->id);
+
+            if (!empty($profileUser)) {
+
+                $output = $item->out;
+
+                // Add an OStatus subscribe
+                $output->elementStart('li', 'entity_subscribe');
+                $url = common_local_url('ostatusinit',
+                                        array('nickname' => $profileUser->nickname));
+                $output->element('a', array('href' => $url,
+                                            'class' => 'entity_remote_subscribe'),
+                                 _m('Subscribe'));
+                $output->elementEnd('li');
+            }
+        }
+
+        return true;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'OStatus',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou, James Walker, Brion Vibber, Zach Copley',
+                            'homepage' => 'http://status.net/wiki/Plugin:OStatus',
+                            'rawdescription' =>
+                            _m('Follow people across social networks that implement '.
+                               '<a href="http://ostatus.org/">OStatus</a>.'));
+
+        return true;
+    }
+
+    /**
+     * Utility function to check if the given URL is a canonical group profile
+     * page, and if so return the ID number.
+     *
+     * @param string $url
+     * @return mixed int or false
+     */
+    public static function localGroupFromUrl($url)
+    {
+        $template = common_local_url('groupbyid', array('id' => '31337'));
+        $template = preg_quote($template, '/');
+        $template = str_replace('31337', '(\d+)', $template);
+        if (preg_match("/$template/", $url, $matches)) {
+            return intval($matches[1]);
+        }
+        return false;
+    }
+
+    public function onStartProfileGetAtomFeed($profile, &$feed)
+    {
+        $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id);
+
+        if (empty($oprofile)) {
+            return true;
+        }
+
+        $feed = $oprofile->feeduri;
+        return false;
+    }
+
+    function onStartGetProfileFromURI($uri, &$profile) {
+
+        // XXX: do discovery here instead (OStatus_profile::ensureProfileURI($uri))
+
+        $oprofile = Ostatus_profile::staticGet('uri', $uri);
+
+        if (!empty($oprofile) && !$oprofile->isGroup()) {
+            $profile = $oprofile->localProfile();
+            return false;
+        }
+
+        return true;
+    }
 }