]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - extlib/libomb/service_provider.php
Merge remote branch 'statusnet/1.0.x' into irc-plugin
[quix0rs-gnu-social.git] / extlib / libomb / service_provider.php
index 753152713bd13c0e86ca89aaa7f265dbc0f8fd82..9a1a488a6b4db57a2073ee0ff4690599e194c70c 100755 (executable)
@@ -1,13 +1,6 @@
 <?php
-
-require_once 'constants.php';
-require_once 'remoteserviceexception.php';
-require_once 'helper.php';
-
 /**
- * OMB service realization
- *
- * This class realizes a complete, simple OMB service.
+ * This file is part of libomb
  *
  * PHP version 5
  *
@@ -24,402 +17,445 @@ require_once 'helper.php';
  * 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/>.
  *
- * @package   OMB
- * @author    Adrian Lang <mail@adrianlang.de>
- * @copyright 2009 Adrian Lang
- * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
- **/
-
-class OMB_Service_Provider {
-  protected $user; /* An OMB_Profile representing the user */
-  protected $datastore; /* AN OMB_Datastore */
-
-  protected $remote_user; /* An OMB_Profile representing the remote user during
-                            the authorization process */
-
-  protected $oauth_server; /* An OAuthServer; should only be accessed via
-                              getOAuthServer. */
-
-  /**
-   * Initialize an OMB_Service_Provider object
-   *
-   * Constructs an OMB_Service_Provider instance that provides OMB services
-   * referring to a particular user.
-   *
-   * @param OMB_Profile   $user         An OMB_Profile; mandatory for XRDS
-   *                                    output, user auth handling and OMB
-   *                                    action performing
-   * @param OMB_Datastore $datastore    An OMB_Datastore; mandatory for
-   *                                    everything but XRDS output
-   * @param OAuthServer   $oauth_server An OAuthServer; used for token writing
-   *                                    and OMB action handling; will use
-   *                                    default value if not set
-   *
-   * @access public
-   **/
-  public function __construct ($user = null, $datastore = null, $oauth_server = null) {
-    $this->user = $user;
-    $this->datastore = $datastore;
-    $this->oauth_server = $oauth_server;
-  }
-
-  public function getRemoteUser() {
-    return $this->remote_user;
-  }
-
-  /**
-   * Write a XRDS document
-   *
-   * Writes a XRDS document specifying the OMB service. Optionally uses a
-   * given object of a class implementing OMB_XRDS_Writer for output. Else
-   * OMB_Plain_XRDS_Writer is used.
-   *
-   * @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs
-   * @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to
-   *                                     write the XRDS document
-   *
-   * @access public
-   *
-   * @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer
-   *               returns nothing.
-   **/
-  public function writeXRDS($xrds_mapper, $xrds_writer = null) {
-    if ($xrds_writer == null) {
-        require_once 'plain_xrds_writer.php';
-        $xrds_writer = new OMB_Plain_XRDS_Writer();
-    }
-    return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
-  }
-
-  /**
-   * Echo a request token
-   *
-   * Outputs an unauthorized request token for the query found in $_GET or
-   * $_POST.
-   *
-   * @access public
-   **/
-  public function writeRequestToken() {
-    OMB_Helper::removeMagicQuotesFromRequest();
-    echo $this->getOAuthServer()->fetch_request_token(OAuthRequest::from_request());
-  }
-
-  /**
-   * Handle an user authorization request.
-   *
-   * Parses an authorization request. This includes OAuth and OMB verification.
-   * Throws exceptions on failures. Returns an OMB_Profile object representing
-   * the remote user.
-   *
-   * The OMB_Profile passed to the constructor of OMB_Service_Provider should
-   * not represent the user specified in the authorization request, but the one
-   * currently logged in to the service. This condition being satisfied,
-   * handleUserAuth will check whether the listener specified in the request is
-   * identical to the logged in user.
-   *
-   * @access public
-   *
-   * @return OMB_Profile The profile of the soon-to-be subscribed, i. e. remote
-   *                     user
-   **/
-  public function handleUserAuth() {
-    OMB_Helper::removeMagicQuotesFromRequest();
-
-    /* Verify the request token. */
-
-    $this->token = $this->datastore->lookup_token(null, "request", $_GET['oauth_token']);
-    if (is_null($this->token)) {
-      throw new OAuthException('The given request token has not been issued ' .
-                               'by this service.');
+ * @package OMB
+ * @author  Adrian Lang <mail@adrianlang.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
+ * @version 0.1a-20090828
+ * @link    http://adrianlang.de/libomb
+ */
+
+require_once 'constants.php';
+require_once 'helper.php';
+require_once 'notice.php';
+require_once 'remoteserviceexception.php';
+
+/**
+ * OMB service realization
+ *
+ * This class realizes a complete, simple OMB service.
+ */
+class OMB_Service_Provider
+{
+    protected $user; /* An OMB_Profile representing the user */
+    protected $datastore; /* AN OMB_Datastore */
+
+    protected $remote_user; /* An OMB_Profile representing the remote user
+                               during the authorization process */
+
+    protected $oauth_server; /* An OAuthServer; should only be accessed via
+                                getOAuthServer. */
+
+    /**
+     * Initialize an OMB_Service_Provider object
+     *
+     * Constructs an OMB_Service_Provider instance that provides OMB services
+     * referring to a particular user.
+     *
+     * @param OMB_Profile   $user         An OMB_Profile; mandatory for XRDS
+     *                                    output, user auth handling and OMB
+     *                                    action performing
+     * @param OMB_Datastore $datastore    An OMB_Datastore; mandatory for
+     *                                    everything but XRDS output
+     * @param OAuthServer   $oauth_server An OAuthServer; used for token writing
+     *                                    and OMB action handling; will use
+     *                                    default value if not set
+     *
+     * @access public
+     */
+    public function __construct ($user = null, $datastore = null,
+                                 $oauth_server = null)
+    {
+        $this->user         = $user;
+        $this->datastore    = $datastore;
+        $this->oauth_server = $oauth_server;
     }
 
-    /* Verify the OMB part. */
+    /**
+     * Return the remote user during user authorization
+     *
+     * Returns an OMB_Profile representing the remote user during the user
+     * authorization request.
+     *
+     * @return OMB_Profile The remote user
+     */
+    public function getRemoteUser()
+    {
+        return $this->remote_user;
+    }
 
-    if ($_GET['omb_version'] !== OMB_VERSION) {
-      throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
-                                   'Wrong OMB version ' . $_GET['omb_version']);
+    /**
+     * Write a XRDS document
+     *
+     * Writes a XRDS document specifying the OMB service. Optionally uses a
+     * given object of a class implementing OMB_XRDS_Writer for output. Else
+     * OMB_Plain_XRDS_Writer is used.
+     *
+     * @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs
+     * @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to
+     *                                     write the XRDS document
+     *
+     * @access public
+     *
+     * @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer
+     *               returns nothing.
+     */
+    public function writeXRDS($xrds_mapper, $xrds_writer = null)
+    {
+        if ($xrds_writer == null) {
+                require_once 'plain_xrds_writer.php';
+                $xrds_writer = new OMB_Plain_XRDS_Writer();
+        }
+        return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
     }
 
-    if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) {
-      throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
-                                 'Wrong OMB listener ' . $_GET['omb_listener']);
+    /**
+     * Echo a request token
+     *
+     * Outputs an unauthorized request token for the query found in $_GET or
+     * $_POST.
+     *
+     * @access public
+     */
+    public function writeRequestToken()
+    {
+        OMB_Helper::removeMagicQuotesFromRequest();
+        echo $this->getOAuthServer()->fetch_request_token(
+                                                  OAuthRequest::from_request());
     }
 
-    foreach (array('omb_listenee', 'omb_listenee_profile',
-                   'omb_listenee_nickname', 'omb_listenee_license') as $param) {
-      if (!isset($_GET[$param]) || is_null($_GET[$param])) {
-        throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
+    /**
+     * Handle an user authorization request.
+     *
+     * Parses an authorization request. This includes OAuth and OMB
+     * verification.
+     * Throws exceptions on failures. Returns an OMB_Profile object representing
+     * the remote user.
+     *
+     * The OMB_Profile passed to the constructor of OMB_Service_Provider should
+     * not represent the user specified in the authorization request, but the
+     * one currently logged in to the service. This condition being satisfied,
+     * handleUserAuth will check whether the listener specified in the request
+     * is identical to the logged in user.
+     *
+     * @access public
+     *
+     * @return OMB_Profile The profile of the soon-to-be subscribed, i. e.
+     *                     remote user
+     */
+    public function handleUserAuth()
+    {
+        OMB_Helper::removeMagicQuotesFromRequest();
+
+        /* Verify the request token. */
+
+        $this->token = $this->datastore->lookup_token(null, "request",
+                                                      $_GET['oauth_token']);
+        if (is_null($this->token)) {
+            throw new OAuthException('The given request token has not been ' .
+                                     'issued by this service.');
+        }
+
+        /* Verify the OMB part. */
+
+        if ($_GET['omb_version'] !== OMB_VERSION) {
+            throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
+                                                         'Wrong OMB version ' .
+                                                         $_GET['omb_version']);
+        }
+
+        if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) {
+            throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
+                                                         'Wrong OMB listener ' .
+                                                         $_GET['omb_listener']);
+        }
+
+        foreach (array('omb_listenee', 'omb_listenee_profile',
+                       'omb_listenee_nickname', 'omb_listenee_license') as $param) {
+            if (!isset($_GET[$param]) || is_null($_GET[$param])) {
+                throw OMB_RemoteServiceException::forRequest(
+                                       OAUTH_ENDPOINT_AUTHORIZE,
                                        "Required parameter '$param' not found");
-      }
-    }
+            }
+        }
 
-    /* Store given callback for later use. */
-    if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') {
-      $this->callback = $_GET['oauth_callback'];
-      if (!OMB_Helper::validateURL($this->callback)) {
-        throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
-                                              'Invalid callback URL specified');
-      }
+        /* Store given callback for later use. */
+        if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') {
+            $this->callback = $_GET['oauth_callback'];
+            if (!OMB_Helper::validateURL($this->callback)) {
+                throw OMB_RemoteServiceException::forRequest(
+                                        OAUTH_ENDPOINT_AUTHORIZE,
+                                        'Invalid callback URL specified');
+            }
+        }
+        $this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
+
+        return $this->remote_user;
     }
-    $this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
-
-    return $this->remote_user;
-  }
-
-  /**
-   * Continue the OAuth dance after user authorization
-   *
-   * Performs the appropriate actions after user answered the authorization
-   * request.
-   *
-   * @param bool $accepted Whether the user granted authorization
-   *
-   * @access public
-   *
-   * @return array A two-component array with the values:
-   *                - callback The callback URL or null if none given
-   *                - token    The authorized request token or null if not
-   *                           authorized.
-   **/
-  public function continueUserAuth($accepted) {
-    $callback = $this->callback;
-    if (!$accepted) {
-      $this->datastore->revoke_token($this->token->key);
-      $this->token = null;
-      /* TODO: The handling is probably wrong in terms of OAuth 1.0 but the way
-               laconica works. Moreover I don’t know the right way either. */
-
-    } else {
-      $this->datastore->authorize_token($this->token->key);
-      $this->datastore->saveProfile($this->remote_user);
-      $this->datastore->saveSubscription($this->user->getIdentifierURI(),
-                          $this->remote_user->getIdentifierURI(), $this->token);
-
-      if (!is_null($this->callback)) {
-        /* Callback wants to get some informations as well. */
-        $params = $this->user->asParameters('omb_listener', false);
-
-        $params['oauth_token'] = $this->token->key;
-        $params['omb_version'] = OMB_VERSION;
-
-        $callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
-        foreach ($params as $k => $v) {
-          $callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
-                       OAuthUtil::urlencode_rfc3986($v) . '&';
+
+    /**
+     * Continue the OAuth dance after user authorization
+     *
+     * Performs the appropriate actions after user answered the authorization
+     * request.
+     *
+     * @param bool $accepted Whether the user granted authorization
+     *
+     * @access public
+     *
+     * @return array A two-component array with the values:
+     *                 - callback The callback URL or null if none given
+     *                 - token    The authorized request token or null if not
+     *                            authorized.
+     */
+    public function continueUserAuth($accepted)
+    {
+        $callback = $this->callback;
+        if (!$accepted) {
+            $this->datastore->revoke_token($this->token->key);
+            $this->token = null;
+
+        } else {
+            $this->datastore->authorize_token($this->token->key);
+            $this->datastore->saveProfile($this->remote_user);
+            $this->datastore->saveSubscription($this->user->getIdentifierURI(),
+                                         $this->remote_user->getIdentifierURI(),
+                                         $this->token);
+
+            if (!is_null($this->callback)) {
+                /* Callback wants to get some informations as well. */
+                $params = $this->user->asParameters('omb_listener', false);
+
+                $params['oauth_token'] = $this->token->key;
+                $params['omb_version'] = OMB_VERSION;
+
+                $callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
+                foreach ($params as $k => $v) {
+                    $callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
+                                 OAuthUtil::urlencode_rfc3986($v) . '&';
+                }
+            }
         }
-      }
+        return array($callback, $this->token);
     }
-    return array($callback, $this->token);
-  }
-
-  /**
-   * Echo an access token
-   *
-   * Outputs an access token for the query found in $_POST. OMB 0.1 specifies
-   * that the access token request has to be a POST even if OAuth allows GET as
-   * well.
-   *
-   * @access public
-   **/
-  public function writeAccessToken() {
-    OMB_Helper::removeMagicQuotesFromRequest();
-    echo $this->getOAuthServer()->fetch_access_token(
+
+    /**
+     * Echo an access token
+     *
+     * Outputs an access token for the query found in $_POST. OMB 0.1 specifies
+     * that the access token request has to be a POST even if OAuth allows GET
+     * as well.
+     *
+     * @access public
+     */
+    public function writeAccessToken()
+    {
+        OMB_Helper::removeMagicQuotesFromRequest();
+        echo $this->getOAuthServer()->fetch_access_token(
                                             OAuthRequest::from_request('POST'));
-  }
-
-  /**
-   * Handle an updateprofile request
-   *
-   * Handles an updateprofile request posted to this service. Updates the
-   * profile through the OMB_Datastore.
-   *
-   * @access public
-   *
-   * @return OMB_Profile The updated profile
-   **/
-  public function handleUpdateProfile() {
-    list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
-    $profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
-    $this->datastore->saveProfile($profile);
-    $this->finishOMBRequest();
-    return $profile;
-  }
-
-  /**
-   * Handle a postnotice request
-   *
-   * Handles a postnotice request posted to this service. Saves the notice
-   * through the OMB_Datastore.
-   *
-   * @access public
-   *
-   * @return OMB_Notice The received notice
-   **/
-  public function handlePostNotice() {
-    list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
-    require_once 'notice.php';
-    $notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
-    $this->datastore->saveNotice($notice);
-    $this->finishOMBRequest();
-    return $notice;
-  }
-
-  /**
-   * Handle an OMB request
-   *
-   * Performs common OMB request handling.
-   *
-   * @param string $uri The URI defining the OMB endpoint being served
-   *
-   * @access protected
-   *
-   * @return array(OAuthRequest, OMB_Profile)
-   **/
-  protected function handleOMBRequest($uri) {
-
-    OMB_Helper::removeMagicQuotesFromRequest();
-    $req = OAuthRequest::from_request('POST');
-    $listenee =  $req->get_parameter('omb_listenee');
-
-    try {
-        list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
-    } catch (OAuthException $e) {
-      header('HTTP/1.1 403 Forbidden');
-      throw OMB_RemoteServiceException::forRequest($uri,
-                                   'Revoked accesstoken for ' . $listenee);
     }
 
-    $version = $req->get_parameter('omb_version');
-    if ($version !== OMB_VERSION) {
-      header('HTTP/1.1 400 Bad Request');
-      throw OMB_RemoteServiceException::forRequest($uri,
-                                   'Wrong OMB version ' . $version);
+    /**
+     * Handle an updateprofile request
+     *
+     * Handles an updateprofile request posted to this service. Updates the
+     * profile through the OMB_Datastore.
+     *
+     * @access public
+     *
+     * @return OMB_Profile The updated profile
+     */
+    public function handleUpdateProfile()
+    {
+        list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
+        $profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
+        $this->datastore->saveProfile($profile);
+        $this->finishOMBRequest();
+        return $profile;
     }
 
-    $profile = $this->datastore->getProfile($listenee);
-    if (is_null($profile)) {
-      header('HTTP/1.1 400 Bad Request');
-      throw OMB_RemoteServiceException::forRequest($uri,
-                                   'Unknown remote profile ' . $listenee);
+    /**
+     * Handle a postnotice request
+     *
+     * Handles a postnotice request posted to this service. Saves the notice
+     * through the OMB_Datastore.
+     *
+     * @access public
+     *
+     * @return OMB_Notice The received notice
+     */
+    public function handlePostNotice()
+    {
+        list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
+
+        $notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
+        $this->datastore->saveNotice($notice);
+        $this->finishOMBRequest();
+
+        return $notice;
     }
 
-    $subscribers = $this->datastore->getSubscriptions($listenee);
-    if (count($subscribers) === 0) {
-      header('HTTP/1.1 403 Forbidden');
-      throw OMB_RemoteServiceException::forRequest($uri,
-                                   'No subscriber for ' . $listenee);
-    }
+    /**
+     * Handle an OMB request
+     *
+     * Performs common OMB request handling.
+     *
+     * @param string $uri The URI defining the OMB endpoint being served
+     *
+     * @access protected
+     *
+     * @return array(OAuthRequest, OMB_Profile)
+     */
+    protected function handleOMBRequest($uri)
+    {
+        OMB_Helper::removeMagicQuotesFromRequest();
+        $req      = OAuthRequest::from_request('POST');
+        $listenee = $req->get_parameter('omb_listenee');
+
+        try {
+            list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
+        } catch (OAuthException $e) {
+            header('HTTP/1.1 403 Forbidden');
+            throw OMB_RemoteServiceException::forRequest($uri,
+                                       'Revoked accesstoken for ' . $listenee);
+        }
 
-    return array($req, $profile);
-  }
-
-  /**
-   * Finishes an OMB request handling
-   *
-   * Performs common OMB request handling finishing.
-   *
-   * @access protected
-   **/
-  protected function finishOMBRequest() {
-    header('HTTP/1.1 200 OK');
-    header('Content-type: text/plain');
-    /* There should be no clutter but the version. */
-    echo "omb_version=" . OMB_VERSION;
-  }
-
-  /**
-   * Return an OAuthServer
-   *
-   * Checks whether the OAuthServer is null. If so, initializes it with a
-   * default value. Returns the OAuth server.
-   *
-   * @access protected
-   **/
-  protected function getOAuthServer() {
-    if (is_null($this->oauth_server)) {
-      $this->oauth_server = new OAuthServer($this->datastore);
-      $this->oauth_server->add_signature_method(
-                                          new OAuthSignatureMethod_HMAC_SHA1());
+        $version = $req->get_parameter('omb_version');
+        if ($version !== OMB_VERSION) {
+            header('HTTP/1.1 400 Bad Request');
+            throw OMB_RemoteServiceException::forRequest($uri,
+                                               'Wrong OMB version ' . $version);
+        }
+
+        $profile = $this->datastore->getProfile($listenee);
+        if (is_null($profile)) {
+            header('HTTP/1.1 400 Bad Request');
+            throw OMB_RemoteServiceException::forRequest($uri,
+                                         'Unknown remote profile ' . $listenee);
+        }
+
+        $subscribers = $this->datastore->getSubscriptions($listenee);
+        if (count($subscribers) === 0) {
+            header('HTTP/1.1 403 Forbidden');
+            throw OMB_RemoteServiceException::forRequest($uri,
+                                              'No subscriber for ' . $listenee);
+        }
+
+        return array($req, $profile);
     }
-    return $this->oauth_server;
-  }
-
-  /**
-   * Publish a notice
-   *
-   * Posts an OMB notice. This includes storing the notice and posting it to
-   * subscribed users.
-   *
-   * @param OMB_Notice $notice The new notice
-   *
-   * @access public
-   *
-   * @return array An array mapping subscriber URIs to the exception posting to
-   *               them has raised; Empty array if no exception occured
-   **/
-  public function postNotice($notice) {
-    $uri = $this->user->getIdentifierURI();
-
-    /* $notice is passed by reference and may change. */
-    $this->datastore->saveNotice($notice);
-    $subscribers = $this->datastore->getSubscriptions($uri);
-
-    /* No one to post to. */
-    if (is_null($subscribers)) {
-        return array();
+
+    /**
+     * Finishes an OMB request handling
+     *
+     * Performs common OMB request handling finishing.
+     *
+     * @access protected
+     */
+    protected function finishOMBRequest()
+    {
+        header('HTTP/1.1 200 OK');
+        header('Content-type: text/plain');
+        /* There should be no clutter but the version. */
+        echo "omb_version=" . OMB_VERSION;
     }
 
-    require_once 'service_consumer.php';
-
-    $err = array();
-    foreach($subscribers as $subscriber) {
-      try {
-        $service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
-        $service->setToken($subscriber['token'], $subscriber['secret']);
-        $service->postNotice($notice);
-      } catch (Exception $e) {
-        $err[$subscriber['uri']] = $e;
-        continue;
-      }
+    /**
+     * Return an OAuthServer
+     *
+     * Checks whether the OAuthServer is null. If so, initializes it with a
+     * default value. Returns the OAuth server.
+     *
+     * @access protected
+     */
+    protected function getOAuthServer()
+    {
+        if (is_null($this->oauth_server)) {
+            $this->oauth_server = new OAuthServer($this->datastore);
+            $this->oauth_server->add_signature_method(
+                                          new OAuthSignatureMethod_HMAC_SHA1());
+        }
+        return $this->oauth_server;
     }
-    return $err;
-  }
-
-  /**
-   * Publish a profile update
-   *
-   * Posts the current profile as an OMB profile update. This includes updating
-   * the stored profile and posting it to subscribed users.
-   *
-   * @access public
-   *
-   * @return array An array mapping subscriber URIs to the exception posting to
-   *               them has raised; Empty array if no exception occured
-   **/
-  public function updateProfile() {
-    $uri = $this->user->getIdentifierURI();
-
-    $this->datastore->saveProfile($this->user);
-    $subscribers = $this->datastore->getSubscriptions($uri);
-
-    /* No one to post to. */
-    if (is_null($subscribers)) {
-        return array();
+
+    /**
+     * Publish a notice
+     *
+     * Posts an OMB notice. This includes storing the notice and posting it to
+     * subscribed users.
+     *
+     * @param OMB_Notice $notice The new notice
+     *
+     * @access public
+     *
+     * @return array An array mapping subscriber URIs to the exception posting
+     *               to them has raised; Empty array if no exception occured
+     */
+    public function postNotice($notice)
+    {
+        $uri = $this->user->getIdentifierURI();
+
+        /* $notice is passed by reference and may change. */
+        $this->datastore->saveNotice($notice);
+        $subscribers = $this->datastore->getSubscriptions($uri);
+
+        /* No one to post to. */
+        if (is_null($subscribers)) {
+            return array();
+        }
+
+        require_once 'service_consumer.php';
+
+        $err = array();
+        foreach ($subscribers as $subscriber) {
+            try {
+                $service = new OMB_Service_Consumer($subscriber['uri'], $uri,
+                                                    $this->datastore);
+                $service->setToken($subscriber['token'], $subscriber['secret']);
+                $service->postNotice($notice);
+            } catch (Exception $e) {
+                $err[$subscriber['uri']] = $e;
+                continue;
+            }
+        }
+        return $err;
     }
 
-    require_once 'service_consumer.php';
-
-    $err = array();
-    foreach($subscribers as $subscriber) {
-      try {
-        $service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
-        $service->setToken($subscriber['token'], $subscriber['secret']);
-        $service->updateProfile($this->user);
-      } catch (Exception $e) {
-        $err[$subscriber['uri']] = $e;
-        continue;
-      }
+    /**
+     * Publish a profile update
+     *
+     * Posts the current profile as an OMB profile update. This includes
+     * updating the stored profile and posting it to subscribed users.
+     *
+     * @access public
+     *
+     * @return array An array mapping subscriber URIs to the exception posting
+     *               to them has raised; Empty array if no exception occured
+     */
+    public function updateProfile()
+    {
+        $uri = $this->user->getIdentifierURI();
+
+        $this->datastore->saveProfile($this->user);
+        $subscribers = $this->datastore->getSubscriptions($uri);
+
+        /* No one to post to. */
+        if (is_null($subscribers)) {
+                return array();
+        }
+
+        require_once 'service_consumer.php';
+
+        $err = array();
+        foreach ($subscribers as $subscriber) {
+            try {
+                $service = new OMB_Service_Consumer($subscriber['uri'], $uri,
+                                                    $this->datastore);
+                $service->setToken($subscriber['token'], $subscriber['secret']);
+                $service->updateProfile($this->user);
+            } catch (Exception $e) {
+                $err[$subscriber['uri']] = $e;
+                continue;
+            }
+        }
+        return $err;
     }
-    return $err;
-  }
 }