]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.8.x' into 0.9.x
authorEvan Prodromou <evan@status.net>
Thu, 27 Aug 2009 18:16:45 +0000 (11:16 -0700)
committerEvan Prodromou <evan@status.net>
Thu, 27 Aug 2009 18:16:45 +0000 (11:16 -0700)
Conflicts:
EVENTS.txt
actions/finishremotesubscribe.php
actions/postnotice.php
actions/public.php
actions/remotesubscribe.php
actions/showstream.php
actions/updateprofile.php
actions/userauthorization.php
classes/laconica.ini
lib/common.php
lib/oauthstore.php
lib/omb.php

70 files changed:
1  2 
EVENTS.txt
README
actions/accesstoken.php
actions/all.php
actions/confirmaddress.php
actions/doc.php
actions/editgroup.php
actions/favorited.php
actions/finishremotesubscribe.php
actions/groupsearch.php
actions/invite.php
actions/login.php
actions/logout.php
actions/newgroup.php
actions/newmessage.php
actions/newnotice.php
actions/noticesearch.php
actions/postnotice.php
actions/profilesettings.php
actions/public.php
actions/publictagcloud.php
actions/register.php
actions/remotesubscribe.php
actions/replies.php
actions/requesttoken.php
actions/showfavorites.php
actions/showgroup.php
actions/shownotice.php
actions/showstream.php
actions/subscribers.php
actions/twitapidirect_messages.php
actions/twitapistatuses.php
actions/updateprofile.php
actions/userauthorization.php
actions/xrds.php
classes/Notice.php
classes/Profile.php
classes/User.php
classes/statusnet.ini
config.php.sample
db/statusnet.sql
db/statusnet_pg.sql
doc-src/help
index.php
install.php
js/util.js
lib/accountsettingsaction.php
lib/action.php
lib/command.php
lib/common.php
lib/facebookaction.php
lib/groupeditform.php
lib/logingroupnav.php
lib/messageform.php
lib/noticeform.php
lib/oauthstore.php
lib/omb.php
lib/router.php
lib/settingsaction.php
lib/unqueuemanager.php
lib/util.php
plugins/OpenID/finishaddopenid.php
plugins/OpenID/finishopenidlogin.php
plugins/OpenID/openid.php
plugins/OpenID/openidlogin.php
plugins/OpenID/openidsettings.php
plugins/OpenID/publicxrds.php
scripts/maildaemon.php
scripts/ombqueuehandler.php
scripts/xmppdaemon.php

diff --cc EVENTS.txt
index a79687bae180b71511f21a90a425faf3da79823c,68cb28603b644ea092a58a18fe91877c4c4d26af..05d172585549f413a4be6e3ed457ad38044f7d80
@@@ -20,16 -20,22 +20,22 @@@ StartShowStyles: Showing Style links; g
  EndShowStyles: End showing Style links; good place to add custom styles
  - $action: the current action
  
- StartShowLaconicaStyles: Showing Laconica Style links
+ StartShowStatusNetStyles: Showing StatusNet Style links
  - $action: the current action
  
- EndShowLaconicaStyles: End showing Laconica tyle links;  good place to add handheld or JavaScript dependent styles
+ EndShowStatusNetStyles: End showing StatusNet Style links;  good place to add handheld or JavaScript dependant styles
+ - $action: the current action
+ StartShowLaconicaStyles: backwards compatibility; deprecated
+ - $action: the current action
+ EndShowLaconicaStyles: backwards compatibility; deprecated
  - $action: the current action
  
 -StartShowUAStyles: Showing custom UA Style links
 +StartShowUAStyles: Showing custom User-Agent style links
  - $action: the current action
  
 -EndShowUAStyles: End showing custom UA Style links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
 +EndShowUAStyles: End showing custom User-Agent links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
  - $action: the current action
  
  StartShowScripts: Showing JavaScript links
diff --cc README
Simple merge
index dcd04a1b404f79ad0c8635e080ddd30deea374f3,c99aaeded32ab74b544d1a532ec9630c0a784b3d..76bd40473a954729f43fd2f53bbc852292b35446
@@@ -36,14 -35,14 +36,14 @@@ require_once INSTALLDIR.'/extlib/libomb
  require_once INSTALLDIR.'/lib/omb.php';
  
  /**
 - * Access token class.
 + * Access token class
   *
   * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
+  * @package  StatusNet
+  * @author   Evan Prodromou <evan@status.net>
+  * @author   Robin Millette <millette@status.net>
   * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
+  * @link     http://status.net/
   */
  class AccesstokenAction extends Action
  {
diff --cc actions/all.php
Simple merge
Simple merge
diff --cc actions/doc.php
Simple merge
Simple merge
Simple merge
index da563cb29014d020e546441177b61fae10890986,871bc3d2d131c3d8fbd7b1c33deb598ca461ebfc..44abbfceb793c31d9a74119cce11987643246948
@@@ -1,18 -1,7 +1,18 @@@
  <?php
 -/*
 +/**
 + * Handler for remote subscription finish callback
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + *
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
+  * StatusNet - the distributed open-source microblogging tool
+  * Copyright (C) 2008, 2009, StatusNet, Inc.
   *
   * 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
   *
   * 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/>.
 - */
 + **/
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
 +require_once INSTALLDIR.'/lib/omb.php';
  
 +/**
 + * Handler for remote subscription finish callback
 + *
 + * When a remote user subscribes a local user, a redirect to this action is
 + * issued after the remote user authorized his service to subscribe.
 + *
 + * @category Action
 + * @package  Laconica
 + * @author   Evan Prodromou <evan@controlyourself.ca>
 + * @author   Robin Millette <millette@controlyourself.ca>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 + * @link     http://laconi.ca/
 + */
  class FinishremotesubscribeAction extends Action
  {
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 14152a83d64d36387445e2fdf3cf348ca33a179a,e775ca17e83e6359ebefefe3711d86a13c485a8f..c2e1c44cae0b4a84099663aee85d954befa4edaf
@@@ -1,18 -1,7 +1,18 @@@
  <?php
 -/*
 +/**
 + * Handle postnotice action
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + *
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
+  * StatusNet - the distributed open-source microblogging tool
+  * Copyright (C) 2008, 2009, StatusNet, Inc.
   *
   * 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
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once INSTALLDIR.'/lib/omb.php';
 +require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
  
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
 +/**
 + * Handler for postnotice action
 + *
 + * @category Action
-  * @link     http://laconi.ca/
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
++ * @link     http://status.net/
 + */
  class PostnoticeAction extends Action
  {
 +    /**
 +     * For initializing members of the class.
 +     *
 +     * @param array $argarray misc. arguments
 +     *
 +     * @return boolean true
 +     */
 +    function prepare($argarray)
 +    {
 +        parent::prepare($argarray);
 +        try {
 +            $this->checkNotice();
 +        } catch (Exception $e) {
 +            $this->clientError($e->getMessage());
 +            return false;
 +        }
 +        return true;
 +    }
 +
      function handle($args)
      {
          parent::handle($args);
              $this->clientError(_('Invalid notice content'), 400);
              return false;
          }
 -        $notice_uri = $req->get_parameter('omb_notice');
 -        if (!Validate::uri($notice_uri) &&
 -            !common_valid_tag($notice_uri)) {
 -            $this->clientError(_('Invalid notice uri'), 400);
 -            return false;
 -        }
 -        $notice_url = $req->get_parameter('omb_notice_url');
 -        if ($notice_url && !common_valid_http_url($notice_url)) {
 -            $this->clientError(_('Invalid notice url'), 400);
 -            return false;
 +        $license      = $_POST['omb_notice_license'];
 +        $site_license = common_config('license', 'url');
 +        if ($license && !common_compatible_license($license, $site_license)) {
 +            throw new Exception(sprintf(_('Notice license â€˜%s’ is not ' .
 +                                          'compatible with site license â€˜%s’.'),
 +                                        $license, $site_license));
          }
 -        $notice = Notice::staticGet('uri', $notice_uri);
 -        if (!$notice) {
 -            $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
 -            if (is_string($notice)) {
 -                common_server_serror($notice, 500);
 -                return false;
 -            }
 -            common_broadcast_notice($notice, true);
 -        }
 -        return true;
      }
  }
- ?>
++?>
Simple merge
index 15bedb7119b6f24cde6b29f8a9e2bb3d85bd69d3,d426648f3d3623ad214adc00a3d748ef930749e9..86b0d6f56b2350200cc0402c7e320e90c4103913
@@@ -225,12 -244,14 +225,13 @@@ class PublicAction extends Actio
      function showAnonymousMessage()
      {
          if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
-           $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                   'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
-                   '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))');
 -            $m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
 -                           'based on the Free Software [StatusNet](http://status.net/) tool. ' .
 -                           '[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' .
 -                           '([Read more](%%%%doc.help%%%%))'),
 -                         (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
++            $m = _('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
++                   'based on the Free Software [StatusNet](http://status.net/) tool. ' .
++                   '[Join now](%%%%action.register%%%%) to share notices about yourself with friends, family, and colleagues! ' .
++                   '([Read more](%%%%doc.help%%%%))');
          } else {
              $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                    'based on the Free Software [Laconica](http://laconi.ca/) tool.');
+                    'based on the Free Software [StatusNet](http://status.net/) tool.');
          }
          $this->elementStart('div', array('id' => 'anon_notice'));
          $this->raw(common_markup_to_html($m));
Simple merge
Simple merge
index 353717bebfd76faf6761c7b98b7d2d2ab5f5f248,374392d4a31df096599dc11cc2e59f002566aeaa..aee2a5d8e79f1d7a54a7c1f945eecf4752299344
@@@ -1,18 -1,7 +1,18 @@@
  <?php
 -/*
 +/**
 + * Handler for remote subscription
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + *
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
+  * StatusNet - the distributed open-source microblogging tool
+  * Copyright (C) 2008, 2009, StatusNet, Inc.
   *
   * 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
   *
   * 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/>.
 - */
 + **/
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once INSTALLDIR.'/lib/omb.php';
 +require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
 +require_once INSTALLDIR.'/extlib/libomb/profile.php';
 +
 +/**
 + * Handler for remote subscription
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + */
  
  class RemotesubscribeAction extends Action
  {
Simple merge
Simple merge
Simple merge
index c3471c195a2e19010aac020897f3550f942a9691,8157ee3c852f0884288e058c8e83bae90bc88806..ff994976215263447b6151d5f65b131873c1039f
@@@ -448,13 -448,14 +448,13 @@@ class ShowgroupAction extends GroupDesi
      {
          if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
              $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+                 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
                  'short messages about their life and interests. '.
 -                '[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
 -                     $this->group->nickname,
 -                     (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
 +                '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
 +                     $this->group->nickname);
          } else {
              $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+                 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
                  'short messages about their life and interests. '),
                       $this->group->nickname);
          }
Simple merge
index cd5d4bb7013bfb84f87d8eca580ddc0ba8c74bb6,4d3067eed37275e35144fc2ecd292e956a0c4954..2e9679faed5444a6f4af302b0c0af0dcc2d7979d
@@@ -386,12 -388,14 +386,12 @@@ class ShowstreamAction extends ProfileA
      {
          if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
              $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                  'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
+                  'based on the Free Software [StatusNet](http://status.net/) tool. ' .
 -                 '[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
 -                 $this->user->nickname,
 -                 (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
 -                 $this->user->nickname);
 +                 '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
 +                 $this->user->nickname, $this->user->nickname);
          } else {
              $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
-                  'based on the Free Software [Laconica](http://laconi.ca/) tool. '),
+                  'based on the Free Software [StatusNet](http://status.net/) tool. '),
                   $this->user->nickname, $this->user->nickname);
        }
          $this->elementStart('div', array('id' => 'anon_notice'));
Simple merge
Simple merge
Simple merge
index b020413b3563fd3e2ebc6b50872ba6a4aec74f50,9a4cf8e4659b6f51c09fb23a48993457efd52014..7f7dd75fef14481c8992d6e3ae7db711533eab9c
@@@ -1,18 -1,7 +1,18 @@@
  <?php
 -/*
 +/**
 + * Handle an updateprofile action
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + *
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
+  * StatusNet - the distributed open-source microblogging tool
+  * Copyright (C) 2008, 2009, StatusNet, Inc.
   *
   * 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
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once INSTALLDIR.'/lib/omb.php';
 +require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
  
 +/**
 + * Handle an updateprofile action
 + *
 + * @category Action
 + * @package  Laconica
 + * @author   Evan Prodromou <evan@controlyourself.ca>
 + * @author   Robin Millette <millette@controlyourself.ca>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 + * @link     http://laconi.ca/
 + */
  class UpdateprofileAction extends Action
  {
 -    
 -    function handle($args)
 -    {
 -        parent::handle($args);
 -        try {
 -            common_remove_magic_from_request();
 -            $req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
 -            # Note: server-to-server function!
 -            $server = omb_oauth_server();
 -            list($consumer, $token) = $server->verify_request($req);
 -            if ($this->update_profile($req, $consumer, $token)) {
 -                header('HTTP/1.1 200 OK');
 -                header('Content-type: text/plain');
 -                print "omb_version=".OMB_VERSION_01;
 -            }
 -        } catch (OAuthException $e) {
 -            $this->serverError($e->getMessage());
 -            return;
 -        }
 -    }
  
 -    function update_profile($req, $consumer, $token)
 +    /**
 +     * For initializing members of the class.
 +     *
 +     * @param array $argarray misc. arguments
 +     *
 +     * @return boolean true
 +     */
 +    function prepare($argarray)
      {
          $version = $req->get_parameter('omb_version');
          if ($version != OMB_VERSION_01) {
index cc8bfdaea499963f2747ad15483aa350d9c7fa5f,a9ac1f256f79eb3bef2e445fe2fbab668c33089e..dc59e6c94112ccec04d926c11647ce3c9b7a3e5b
@@@ -1,18 -1,7 +1,18 @@@
  <?php
 -/*
 +/**
 + * Let the user authorize a remote subscription request
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
++ * @link     http://status.net/
 + *
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
+  * StatusNet - the distributed open-source microblogging tool
+  * Copyright (C) 2008, 2009, StatusNet, Inc.
   *
   * 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
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once INSTALLDIR.'/lib/omb.php';
 +require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
 +require_once INSTALLDIR.'/extlib/libomb/profile.php';
  define('TIMESTAMP_THRESHOLD', 300);
  
  class UserauthorizationAction extends Action
              }
              if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
                                            IMAGETYPE_PNG))) {
 -                throw new OAuthException("Wrong image type for '$avatar'");
 +                throw new Exception(sprintf(_('Wrong image type for avatar URL '.
 +                                              '‘%s’.'), $avatar));
              }
          }
 -        $callback = $_GET['oauth_callback'];
 -        if ($callback && !common_valid_http_url($callback)) {
 -            throw new OAuthException("Invalid callback URL '$callback'");
 -        }
 -        if ($callback && $callback == common_local_url('finishremotesubscribe')) {
 -            throw new OAuthException("Callback URL '$callback' is for local site.");
 -        }
      }
--}
++}
index b3aa8df8e57499bda8e5f18978fcff8ea4ed0e58,def10e4cf7bd90d8af6b6263eec7af093dfb1fbe..8ba89fec0ff7c56a262ebaa29374ba9a8c0b8359
@@@ -34,18 -34,16 +34,18 @@@ if (!defined('STATUSNET') && !defined('
  }
  
  require_once INSTALLDIR.'/lib/omb.php';
 +require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
 +require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
  
  /**
 - * XRDS for OpenID
 + * XRDS for OpenMicroBlogging
   *
   * @category Action
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
+  * @package  StatusNet
+  * @author   Evan Prodromou <evan@status.net>
+  * @author   Robin Millette <millette@status.net>
   * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * @link     http://laconi.ca/
+  * @link     http://status.net/
   */
  class XrdsAction extends Action
  {
Simple merge
Simple merge
Simple merge
index 8123265e46c879fd6ff043a3c498d40aca82aef9,766bed75deff2a8af0134b0c6773dac420895844..7edeeebe4fa3ec7b0e49ef05615f61b63feee1e7
mode 100644,100644..100755
- [status_network]
+ [avatar]
+ profile_id = 129
+ original = 17
+ width = 129
+ height = 129
+ mediatype = 130
+ filename = 2
+ url = 2
+ created = 142
+ modified = 384
+ [avatar__keys]
+ profile_id = K
+ width = K
+ height = K
+ url = U
++[config]
++section = 130
++setting = 130
++value = 2
++
++[config__keys]
++section = K
++setting = K
++
+ [confirm_address]
+ code = 130
+ user_id = 129
+ address = 130
+ address_extra = 130
+ address_type = 130
+ claimed = 14
+ sent = 14
+ modified = 384
+ [confirm_address__keys]
+ code = K
+ [consumer]
+ consumer_key = 130
+ seed = 130
+ created = 142
+ modified = 384
+ [consumer__keys]
+ consumer_key = K
++[deleted_notice]
++id = 129
++profile_id = 129
++uri = 2
++created = 142
++deleted = 142
++
++[deleted_notice__keys]
++id = K
++uri = U
++
+ [design]
+ id = 129
+ backgroundcolor = 1
+ contentcolor = 1
+ sidebarcolor = 1
+ textcolor = 1
+ linkcolor = 1
+ backgroundimage = 2
+ disposition = 17
+ [design__keys]
+ id = N
+ [fave]
+ notice_id = 129
+ user_id = 129
+ modified = 384
+ [fave__keys]
+ notice_id = K
+ user_id = K
+ [file]
+ id = 129
+ url = 2
+ mimetype = 2
+ size = 1
+ title = 2
+ date = 1
+ protected = 1
+ filename = 2
+ modified = 384
+ [file__keys]
+ id = N
+ [file_oembed]
+ file_id = 129
+ version = 2
+ type = 2
+ provider = 2
+ provider_url = 2
+ width = 1
+ height = 1
+ html = 34
+ title = 2
+ author_name = 2
+ author_url = 2
+ url = 2
+ modified = 384
+ [file_oembed__keys]
+ file_id = K
+ [file_redirection]
+ url = 130
+ file_id = 1
+ redirections = 1
+ httpcode = 1
+ modified = 384
+ [file_redirection__keys]
+ url = K
+ [file_thumbnail]
+ file_id = 129
+ url = 2
+ width = 1
+ height = 1
+ modified = 384
+ [file_thumbnail__keys]
+ file_id = K
+ url = U
+ [file_to_post]
+ file_id = 129
+ post_id = 129
+ modified = 384
+ [file_to_post__keys]
+ file_id = K
+ post_id = K
+ [foreign_link]
+ user_id = 129
+ foreign_id = 129
+ service = 129
+ credentials = 2
+ noticesync = 145
+ friendsync = 145
+ profilesync = 145
+ last_noticesync = 14
+ last_friendsync = 14
+ created = 142
+ modified = 384
+ [foreign_link__keys]
+ user_id = K
+ foreign_id = K
+ service = K
+ [foreign_service]
+ id = 129
+ name = 130
+ description = 2
+ created = 142
+ modified = 384
+ [foreign_service__keys]
+ id = K
+ name = U
+ [foreign_subscription]
+ service = 129
+ subscriber = 129
+ subscribed = 129
+ created = 142
+ [foreign_subscription__keys]
+ service = K
+ subscriber = K
+ subscribed = K
+ [foreign_user]
+ id = 129
+ service = 129
+ uri = 130
+ nickname = 2
+ created = 142
+ modified = 384
+ [foreign_user__keys]
+ id = K
+ service = K
+ uri = U
+ [group_alias]
+ alias = 130
+ group_id = 129
+ modified = 384
+ [group_alias__keys]
+ alias = K
+ [group_block]
+ group_id = 129
+ blocked = 129
+ blocker = 129
+ modified = 384
+ [group_block__keys]
+ group_id = K
+ blocked = K
+ [group_inbox]
+ group_id = 129
+ notice_id = 129
+ created = 142
+ [group_inbox__keys]
+ group_id = K
+ notice_id = K
+ [group_member]
+ group_id = 129
+ profile_id = 129
+ is_admin = 17
+ created = 142
+ modified = 384
+ [group_member__keys]
+ group_id = K
+ profile_id = K
+ [invitation]
+ code = 130
+ user_id = 129
+ address = 130
+ address_type = 130
+ created = 142
+ [invitation__keys]
+ code = K
+ [message]
+ id = 129
+ uri = 2
+ from_profile = 129
+ to_profile = 129
 -content = 2
++content = 34
+ rendered = 34
+ url = 2
+ created = 142
+ modified = 384
+ source = 2
+ [message__keys]
+ id = N
+ [nonce]
+ consumer_key = 130
+ tok = 2
+ nonce = 130
+ ts = 142
+ created = 142
+ modified = 384
+ [nonce__keys]
+ consumer_key = K
+ nonce = K
+ ts = K
+ [notice]
+ id = 129
+ profile_id = 129
+ uri = 2
 -content = 2
++content = 34
+ rendered = 34
+ url = 2
+ created = 142
+ modified = 384
+ reply_to = 1
+ is_local = 17
+ source = 2
+ conversation = 1
+ [notice__keys]
+ id = N
+ [notice_inbox]
+ user_id = 129
+ notice_id = 129
+ created = 142
+ source = 17
+ [notice_inbox__keys]
+ user_id = K
+ notice_id = K
+ [notice_source]
+ code = 130
+ name = 130
+ url = 130
+ created = 142
+ modified = 384
+ [notice_source__keys]
+ code = K
+ [notice_tag]
+ tag = 130
+ notice_id = 129
+ created = 142
+ [notice_tag__keys]
+ tag = K
+ notice_id = K
+ [profile]
+ id = 129
  nickname = 130
- hostname = 2
- pathname = 2
- dbhost = 2
- dbuser = 2
- dbpass = 2
- dbname = 2
- sitename = 2
- theme = 2
- logo = 2
- created = 142
- modified = 384
- [status_network__keys]
- nickname = K
- hostname = U
- pathname = U
+ fullname = 2
+ profileurl = 2
+ homepage = 2
 -bio = 2
++bio = 34
+ location = 2
+ created = 142
+ modified = 384
+ [profile__keys]
+ id = N
+ [profile_block]
+ blocker = 129
+ blocked = 129
+ modified = 384
+ [profile_block__keys]
+ blocker = K
+ blocked = K
+ [profile_tag]
+ tagger = 129
+ tagged = 129
+ tag = 130
+ modified = 384
+ [profile_tag__keys]
+ tagger = K
+ tagged = K
+ tag = K
+ [queue_item]
+ notice_id = 129
+ transport = 130
+ created = 142
+ claimed = 14
+ [queue_item__keys]
+ notice_id = K
+ transport = K
+ [related_group]
+ group_id = 129
+ related_group_id = 129
+ created = 142
+ [related_group__keys]
+ group_id = K
+ related_group_id = K
+ [remember_me]
+ code = 130
+ user_id = 129
+ modified = 384
+ [remember_me__keys]
+ code = K
+ [remote_profile]
+ id = 129
+ uri = 2
+ postnoticeurl = 2
+ updateprofileurl = 2
+ created = 142
+ modified = 384
+ [remote_profile__keys]
+ id = K
+ uri = U
+ [reply]
+ notice_id = 129
+ profile_id = 129
+ modified = 384
+ replied_id = 1
+ [reply__keys]
+ notice_id = K
+ profile_id = K
+ [session]
+ id = 130
+ session_data = 34
+ created = 142
+ modified = 384
+ [session__keys]
+ id = K
+ [sms_carrier]
+ id = 129
+ name = 2
+ email_pattern = 130
+ created = 142
+ modified = 384
+ [sms_carrier__keys]
+ id = K
+ name = U
+ [subscription]
+ subscriber = 129
+ subscribed = 129
+ jabber = 17
+ sms = 17
+ token = 2
+ secret = 2
+ created = 142
+ modified = 384
+ [subscription__keys]
+ subscriber = K
+ subscribed = K
+ [token]
+ consumer_key = 130
+ tok = 130
+ secret = 130
+ type = 145
+ state = 17
+ created = 142
+ modified = 384
+ [token__keys]
+ consumer_key = K
+ tok = K
+ [user]
+ id = 129
+ nickname = 2
+ password = 2
+ email = 2
+ incomingemail = 2
+ emailnotifysub = 17
+ emailnotifyfav = 17
+ emailnotifynudge = 17
+ emailnotifymsg = 17
+ emailnotifyattn = 17
+ emailmicroid = 17
+ language = 2
+ timezone = 2
+ emailpost = 17
+ jabber = 2
+ jabbernotify = 17
+ jabberreplies = 17
+ jabbermicroid = 17
+ updatefrompresence = 17
+ sms = 2
+ carrier = 1
+ smsnotify = 17
+ smsreplies = 17
+ smsemail = 2
+ uri = 2
+ autosubscribe = 17
+ urlshorteningservice = 2
+ inboxed = 17
+ design_id = 1
+ viewdesigns = 17
+ created = 142
+ modified = 384
+ [user__keys]
+ id = K
+ nickname = U
+ email = U
+ incomingemail = U
+ jabber = U
+ sms = U
+ uri = U
+ [user_group]
+ id = 129
+ nickname = 2
+ fullname = 2
+ homepage = 2
 -description = 2
++description = 34
+ location = 2
+ original_logo = 2
+ homepage_logo = 2
+ stream_logo = 2
+ mini_logo = 2
+ design_id = 1
+ created = 142
+ modified = 384
+ [user_group__keys]
+ id = N
+ [user_openid]
+ canonical = 130
+ display = 130
+ user_id = 129
+ created = 142
+ modified = 384
+ [user_openid__keys]
+ canonical = K
+ display = U
Simple merge
index 0000000000000000000000000000000000000000,2c04f680a85d587a032cd06fada5c63c8488eaa5..1662ef7a8be6bc074c1c76b4a25937cd3955ad3d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,537 +1,559 @@@
 -    bio varchar(140) comment 'descriptive biography',
+ /* local and remote users have profiles */
+ create table profile (
+     id integer auto_increment primary key comment 'unique identifier',
+     nickname varchar(64) not null comment 'nickname or username',
+     fullname varchar(255) comment 'display name',
+     profileurl varchar(255) comment 'URL, cached so we dont regenerate',
+     homepage varchar(255) comment 'identifying URL',
 -    content varchar(140) comment 'update content',
++    bio text comment 'descriptive biography',
+     location varchar(255) comment 'physical location',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     index profile_nickname_idx (nickname),
+     FULLTEXT(nickname, fullname, location, bio, homepage)
+ ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table avatar (
+     profile_id integer not null comment 'foreign key to profile table' references profile (id),
+     original boolean default false comment 'uploaded by user or generated?',
+     width integer not null comment 'image width',
+     height integer not null comment 'image height',
+     mediatype varchar(32) not null comment 'file type',
+     filename varchar(255) null comment 'local filename, if local',
+     url varchar(255) unique key comment 'avatar location',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (profile_id, width, height),
+     index avatar_profile_id_idx (profile_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table sms_carrier (
+     id integer primary key comment 'primary key for SMS carrier',
+     name varchar(64) unique key comment 'name of the carrier',
+     email_pattern varchar(255) not null comment 'sprintf pattern for making an email address from a phone number',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* local users */
+ create table user (
+     id integer primary key comment 'foreign key to profile table' references profile (id),
+     nickname varchar(64) unique key comment 'nickname or username, duped in profile',
+     password varchar(255) comment 'salted password, can be null for OpenID users',
+     email varchar(255) unique key comment 'email address for password recovery etc.',
+     incomingemail varchar(255) unique key comment 'email address for post-by-email',
+     emailnotifysub tinyint default 1 comment 'Notify by email of subscriptions',
+     emailnotifyfav tinyint default 1 comment 'Notify by email of favorites',
+     emailnotifynudge tinyint default 1 comment 'Notify by email of nudges',
+     emailnotifymsg tinyint default 1 comment 'Notify by email of direct messages',
+     emailnotifyattn tinyint default 1 comment 'Notify by email of @-replies',
+     emailmicroid tinyint default 1 comment 'whether to publish email microid',
+     language varchar(50) comment 'preferred language',
+     timezone varchar(50) comment 'timezone',
+     emailpost tinyint default 1 comment 'Post by email',
+     jabber varchar(255) unique key comment 'jabber ID for notices',
+     jabbernotify tinyint default 0 comment 'whether to send notices to jabber',
+     jabberreplies tinyint default 0 comment 'whether to send notices to jabber on replies',
+     jabbermicroid tinyint default 1 comment 'whether to publish xmpp microid',
+     updatefrompresence tinyint default 0 comment 'whether to record updates from Jabber presence notices',
+     sms varchar(64) unique key comment 'sms phone number',
+     carrier integer comment 'foreign key to sms_carrier' references sms_carrier (id),
+     smsnotify tinyint default 0 comment 'whether to send notices to SMS',
+     smsreplies tinyint default 0 comment 'whether to send notices to SMS on replies',
+     smsemail varchar(255) comment 'built from sms and carrier',
+     uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
+     autosubscribe tinyint default 0 comment 'automatically subscribe to users who subscribe to us',
+     urlshorteningservice varchar(50) default 'ur1.ca' comment 'service to use for auto-shortening URLs',
+     inboxed tinyint default 0 comment 'has an inbox been created for this user?',
+     design_id integer comment 'id of a design' references design(id),
+     viewdesigns tinyint default 1 comment 'whether to view user-provided designs',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     index user_smsemail_idx (smsemail)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+ /* remote people */
+ create table remote_profile (
+     id integer primary key comment 'foreign key to profile table' references profile (id),
+     uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
+     postnoticeurl varchar(255) comment 'URL we use for posting notices',
+     updateprofileurl varchar(255) comment 'URL we use for updates to this profile',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table subscription (
+     subscriber integer not null comment 'profile listening',
+     subscribed integer not null comment 'profile being listened to',
+     jabber tinyint default 1 comment 'deliver jabber messages',
+     sms tinyint default 1 comment 'deliver sms messages',
+     token varchar(255) comment 'authorization token',
+     secret varchar(255) comment 'token secret',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (subscriber, subscribed),
+     index subscription_subscriber_idx (subscriber),
+     index subscription_subscribed_idx (subscribed),
+     index subscription_token_idx (token)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table notice (
+     id integer auto_increment primary key comment 'unique identifier',
+     profile_id integer not null comment 'who made the update' references profile (id),
+     uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
 -    content varchar(140) comment 'message content',
++    content text comment 'update content',
+     rendered text comment 'HTML version of the content',
+     url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     reply_to integer comment 'notice replied to (usually a guess)' references notice (id),
+     is_local tinyint default 0 comment 'notice was generated by a user',
+     source varchar(32) comment 'source of comment, like "web", "im", or "clientname"',
+     conversation integer comment 'id of root notice in this conversation' references notice (id),
+     index notice_profile_id_idx (profile_id),
+     index notice_conversation_idx (conversation),
+     index notice_created_idx (created),
+     index notice_replyto_idx (reply_to),
+     FULLTEXT(content)
+ ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table notice_source (
+      code varchar(32) primary key not null comment 'source code',
+      name varchar(255) not null comment 'name of the source',
+      url varchar(255) not null comment 'url to link to',
+      created datetime not null comment 'date this record was created',
+      modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table reply (
+     notice_id integer not null comment 'notice that is the reply' references notice (id),
+     profile_id integer not null comment 'profile replied to' references profile (id),
+     modified timestamp not null comment 'date this record was modified',
+     replied_id integer comment 'notice replied to (not used, see notice.reply_to)',
+     constraint primary key (notice_id, profile_id),
+     index reply_notice_id_idx (notice_id),
+     index reply_profile_id_idx (profile_id),
+     index reply_replied_id_idx (replied_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table fave (
+     notice_id integer not null comment 'notice that is the favorite' references notice (id),
+     user_id integer not null comment 'user who likes this notice' references user (id),
+     modified timestamp not null comment 'date this record was modified',
+     constraint primary key (notice_id, user_id),
+     index fave_notice_id_idx (notice_id),
+     index fave_user_id_idx (user_id),
+     index fave_modified_idx (modified)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* tables for OAuth */
+ create table consumer (
+     consumer_key varchar(255) primary key comment 'unique identifier, root URL',
+     seed char(32) not null comment 'seed for new tokens by this consumer',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table token (
+     consumer_key varchar(255) not null comment 'unique identifier, root URL' references consumer (consumer_key),
+     tok char(32) not null comment 'identifying value',
+     secret char(32) not null comment 'secret value',
+     type tinyint not null default 0 comment 'request or access',
+     state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (consumer_key, tok)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table nonce (
+     consumer_key varchar(255) not null comment 'unique identifier, root URL',
+     tok char(32) null comment 'buggy old value, ignored',
+     nonce char(32) not null comment 'nonce',
+     ts datetime not null comment 'timestamp sent',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (consumer_key, ts, nonce)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* One-to-many relationship of user to openid_url */
+ create table user_openid (
+     canonical varchar(255) primary key comment 'Canonical true URL',
+     display varchar(255) not null unique key comment 'URL for viewing, may be different from canonical',
+     user_id integer not null comment 'user owning this URL' references user (id),
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     index user_openid_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* These are used by JanRain OpenID library */
+ create table oid_associations (
+     server_url BLOB,
+     handle VARCHAR(255) character set latin1,
+     secret BLOB,
+     issued INTEGER,
+     lifetime INTEGER,
+     assoc_type VARCHAR(64),
+     PRIMARY KEY (server_url(255), handle)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table oid_nonces (
+     server_url VARCHAR(2047),
+     timestamp INTEGER,
+     salt CHAR(40),
+     UNIQUE (server_url(255), timestamp, salt)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table confirm_address (
+     code varchar(32) not null primary key comment 'good random code',
+     user_id integer not null comment 'user who requested confirmation' references user (id),
+     address varchar(255) not null comment 'address (email, Jabber, SMS, etc.)',
+     address_extra varchar(255) not null comment 'carrier ID, for SMS',
+     address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
+     claimed datetime comment 'date this was claimed for queueing',
+     sent datetime comment 'date this was sent for queueing',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table remember_me (
+     code varchar(32) not null primary key comment 'good random code',
+     user_id integer not null comment 'user who is logged in' references user (id),
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table queue_item (
+     notice_id integer not null comment 'notice queued' references notice (id),
+     transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
+     created datetime not null comment 'date this record was created',
+     claimed datetime comment 'date this item was claimed',
+     constraint primary key (notice_id, transport),
+     index queue_item_created_idx (created)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* Hash tags */
+ create table notice_tag (
+     tag varchar( 64 ) not null comment 'hash tag associated with this notice',
+     notice_id integer not null comment 'notice tagged' references notice (id),
+     created datetime not null comment 'date this record was created',
+     constraint primary key (tag, notice_id),
+     index notice_tag_created_idx (created),
+     index notice_tag_notice_id_idx (notice_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ /* Synching with foreign services */
+ create table foreign_service (
+      id int not null primary key comment 'numeric key for service',
+      name varchar(32) not null unique key comment 'name of the service',
+      description varchar(255) comment 'description',
+      created datetime not null comment 'date this record was created',
+      modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table foreign_user (
+      id bigint not null comment 'unique numeric key on foreign service',
+      service int not null comment 'foreign key to service' references foreign_service(id),
+      uri varchar(255) not null unique key comment 'identifying URI',
+      nickname varchar(255) comment 'nickname on foreign service',
+      created datetime not null comment 'date this record was created',
+      modified timestamp comment 'date this record was modified',
+      constraint primary key (id, service)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table foreign_link (
+      user_id int comment 'link to user on this system, if exists' references user (id),
+      foreign_id bigint unsigned comment 'link to user on foreign service, if exists' references foreign_user(id),
+      service int not null comment 'foreign key to service' references foreign_service(id),
+      credentials varchar(255) comment 'authc credentials, typically a password',
+      noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
+      friendsync tinyint not null default 2 comment 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
+      profilesync tinyint not null default 1 comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
+      last_noticesync datetime default null comment 'last time notices were imported',
+      last_friendsync datetime default null comment 'last time friends were imported',
+      created datetime not null comment 'date this record was created',
+      modified timestamp comment 'date this record was modified',
+      constraint primary key (user_id, foreign_id, service),
+      index foreign_user_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table foreign_subscription (
+      service int not null comment 'service where relationship happens' references foreign_service(id),
+      subscriber int not null comment 'subscriber on foreign service' references foreign_user (id),
+      subscribed int not null comment 'subscribed user' references foreign_user (id),
+      created datetime not null comment 'date this record was created',
+      constraint primary key (service, subscriber, subscribed),
+      index foreign_subscription_subscriber_idx (subscriber),
+      index foreign_subscription_subscribed_idx (subscribed)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table invitation (
+      code varchar(32) not null primary key comment 'random code for an invitation',
+      user_id int not null comment 'who sent the invitation' references user (id),
+      address varchar(255) not null comment 'invitation sent to',
+      address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
+      created datetime not null comment 'date this record was created',
+      index invitation_address_idx (address, address_type),
+      index invitation_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table message (
+     id integer auto_increment primary key comment 'unique identifier',
+     uri varchar(255) unique key comment 'universally unique identifier',
+     from_profile integer not null comment 'who the message is from' references profile (id),
+     to_profile integer not null comment 'who the message is to' references profile (id),
 -    description varchar(140) comment 'descriptive biography',
++    content text comment 'message content',
+     rendered text comment 'HTML version of the content',
+     url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     source varchar(32) comment 'source of comment, like "web", "im", or "clientname"',
+     index message_from_idx (from_profile),
+     index message_to_idx (to_profile),
+     index message_created_idx (created)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table notice_inbox (
+     user_id integer not null comment 'user receiving the message' references user (id),
+     notice_id integer not null comment 'notice received' references notice (id),
+     created datetime not null comment 'date the notice was created',
+     source tinyint default 1 comment 'reason it is in the inbox, 1=subscription',
+     constraint primary key (user_id, notice_id),
+     index notice_inbox_notice_id_idx (notice_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table profile_tag (
+    tagger integer not null comment 'user making the tag' references user (id),
+    tagged integer not null comment 'profile tagged' references profile (id),
+    tag varchar(64) not null comment 'hash tag associated with this notice',
+    modified timestamp comment 'date the tag was added',
+    constraint primary key (tagger, tagged, tag),
+    index profile_tag_modified_idx (modified),
+    index profile_tag_tagger_tag_idx (tagger, tag),
+    index profile_tag_tagged_idx (tagged)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table profile_block (
+    blocker integer not null comment 'user making the block' references user (id),
+    blocked integer not null comment 'profile that is blocked' references profile (id),
+    modified timestamp comment 'date of blocking',
+    constraint primary key (blocker, blocked)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table user_group (
+     id integer auto_increment primary key comment 'unique identifier',
+     nickname varchar(64) unique key comment 'nickname for addressing',
+     fullname varchar(255) comment 'display name',
+     homepage varchar(255) comment 'URL, cached so we dont regenerate',
 -) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++    description text comment 'group description',
+     location varchar(255) comment 'related physical location, if any',
+     original_logo varchar(255) comment 'original size logo',
+     homepage_logo varchar(255) comment 'homepage (profile) size logo',
+     stream_logo varchar(255) comment 'stream-sized logo',
+     mini_logo varchar(255) comment 'mini logo',
+     design_id integer comment 'id of a design' references design(id),
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     index user_group_nickname_idx (nickname)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table group_member (
+     group_id integer not null comment 'foreign key to user_group' references user_group (id),
+     profile_id integer not null comment 'foreign key to profile table' references profile (id),
+     is_admin boolean default false comment 'is this user an admin?',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (group_id, profile_id),
+     index group_member_profile_id_idx (profile_id),
+     index group_member_created_idx (created)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table related_group (
+     group_id integer not null comment 'foreign key to user_group' references user_group (id),
+     related_group_id integer not null comment 'foreign key to user_group' references user_group (id),
+     created datetime not null comment 'date this record was created',
+     constraint primary key (group_id, related_group_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table group_inbox (
+     group_id integer not null comment 'group receiving the message' references user_group (id),
+     notice_id integer not null comment 'notice received' references notice (id),
+     created datetime not null comment 'date the notice was created',
+     constraint primary key (group_id, notice_id),
+     index group_inbox_created_idx (created)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table file (
+     id integer primary key auto_increment,
+     url varchar(255) comment 'destination URL after following redirections',
+     mimetype varchar(50) comment 'mime type of resource',
+     size integer comment 'size of resource when available',
+     title varchar(255) comment 'title of resource when available',
+     date integer(11) comment 'date of resource according to http query',
+     protected integer(1) comment 'true when URL is private (needs login)',
+     filename varchar(255) comment 'if a local file, name of the file',
+     modified timestamp comment 'date this record was modified',
+     unique(url)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table file_oembed (
+     file_id integer primary key comment 'oEmbed for that URL/file' references file (id),
+     version varchar(20) comment 'oEmbed spec. version',
+     type varchar(20) comment 'oEmbed type: photo, video, link, rich',
+     provider varchar(50) comment 'name of this oEmbed provider',
+     provider_url varchar(255) comment 'URL of this oEmbed provider',
+     width integer comment 'width of oEmbed resource when available',
+     height integer comment 'height of oEmbed resource when available',
+     html text comment 'html representation of this oEmbed resource when applicable',
+     title varchar(255) comment 'title of oEmbed resource when available',
+     author_name varchar(50) comment 'author name for this oEmbed resource',
+     author_url varchar(255) comment 'author URL for this oEmbed resource',
+     url varchar(255) comment 'URL for this oEmbed resource when applicable (photo, link)',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+ create table file_redirection (
+     url varchar(255) primary key comment 'short URL (or any other kind of redirect) for file (id)',
+     file_id integer comment 'short URL for what URL/file' references file (id),
+     redirections integer comment 'redirect count',
+     httpcode integer comment 'HTTP status code (20x, 30x, etc.)',
+     modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table file_thumbnail (
+     file_id integer primary key comment 'thumbnail for what URL/file' references file (id),
+     url varchar(255) comment 'URL of thumbnail',
+     width integer comment 'width of thumbnail',
+     height integer comment 'height of thumbnail',
+     modified timestamp comment 'date this record was modified',
+     unique(url)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table file_to_post (
+     file_id integer comment 'id of URL/file' references file (id),
+     post_id integer comment 'id of the notice it belongs to' references notice (id),
+     modified timestamp comment 'date this record was modified',
+     constraint primary key (file_id, post_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table design (
+     id integer primary key auto_increment comment 'design ID',
+     backgroundcolor integer comment 'main background color',
+     contentcolor integer comment 'content area background color',
+     sidebarcolor integer comment 'sidebar background color',
+     textcolor integer comment 'text color',
+     linkcolor integer comment 'link color',
+     backgroundimage varchar(255) comment 'background image, if any',
+     disposition tinyint default 1 comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table group_block (
+    group_id integer not null comment 'group profile is blocked from' references user_group (id),
+    blocked integer not null comment 'profile that is blocked' references profile (id),
+    blocker integer not null comment 'user making the block' references user (id),
+    modified timestamp comment 'date of blocking',
+    constraint primary key (group_id, blocked)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table group_alias (
+    alias varchar(64) primary key comment 'additional nickname for the group',
+    group_id integer not null comment 'group profile is blocked from' references user_group (id),
+    modified timestamp comment 'date alias was created',
+    index group_alias_group_id_idx (group_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+ create table session (
+     id varchar(32) primary key comment 'session ID',
+     session_data text comment 'session data',
+     created datetime not null comment 'date this record was created',
+     modified timestamp comment 'date this record was modified',
+     index session_modified_idx (modified)
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++
++create table deleted_notice (
++
++    id integer primary key comment 'identity of notice',
++    profile_id integer not null comment 'author of the notice',
++    uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
++    created datetime not null comment 'date the notice record was created',
++    deleted datetime not null comment 'date the notice record was created',
++
++    index deleted_notice_profile_id_idx (profile_id)
++
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++
++create table config (
++
++    section varchar(32) comment 'configuration section',
++    setting varchar(32) comment 'configuration setting',
++    value varchar(255) comment 'configuration value',
++
++    constraint primary key (section, setting)
++
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
index 0000000000000000000000000000000000000000,ad34720a23357e405c99a7ff433303385d4df041..b5626d3f4a063ae5eb73c0219bca8444f0e594d0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,539 +1,550 @@@
+ /* local and remote users have profiles */
+ create sequence profile_seq;
+ create table profile (
+     id bigint default nextval('profile_seq') primary key /* comment 'unique identifier' */,
+     nickname varchar(64) not null /* comment 'nickname or username' */,
+     fullname varchar(255) /* comment 'display name' */,
+     profileurl varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+     homepage varchar(255) /* comment 'identifying URL' */,
+     bio varchar(140) /* comment 'descriptive biography' */,
+     location varchar(255) /* comment 'physical location' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     textsearch tsvector
+ );
+ create index profile_nickname_idx on profile using btree(nickname);
+ create table avatar (
+     profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id) ,
+     original integer default 0 /* comment 'uploaded by user or generated?' */,
+     width integer not null /* comment 'image width' */,
+     height integer not null /* comment 'image height' */,
+     mediatype varchar(32) not null /* comment 'file type' */,
+     filename varchar(255) null /* comment 'local filename, if local' */,
+     url varchar(255) unique /* comment 'avatar location' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     primary key(profile_id, width, height)
+ );
+ create index avatar_profile_id_idx on avatar using btree(profile_id);
+ create sequence sms_carrier_seq;
+ create table sms_carrier (
+     id bigint default nextval('sms_carrier_seq') primary key /* comment 'primary key for SMS carrier' */,
+     name varchar(64) unique /* comment 'name of the carrier' */,
+     email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified ' */
+ );
+ create sequence design_seq;
+ create table design (
+     id bigint default nextval('design_seq') /* comment 'design ID'*/,
+     backgroundcolor integer /* comment 'main background color'*/ ,
+     contentcolor integer /*comment 'content area background color'*/ ,
+     sidebarcolor integer /*comment 'sidebar background color'*/ ,
+     textcolor integer /*comment 'text color'*/ ,
+     linkcolor integer /*comment 'link color'*/,
+     backgroundimage varchar(255) /*comment 'background image, if any'*/,
+     disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+     primary key (id)
+ );
+ /* local users */
+ create table "user" (
+     id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+     nickname varchar(64) unique /* comment 'nickname or username, duped in profile' */,
+     password varchar(255) /* comment 'salted password, can be null for OpenID users' */,
+     email varchar(255) unique /* comment 'email address for password recovery etc.' */,
+     incomingemail varchar(255) unique /* comment 'email address for post-by-email' */,
+     emailnotifysub integer default 1 /* comment 'Notify by email of subscriptions' */,
+     emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
+     emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
+     emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
+     emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */, 
+     emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
+     language varchar(50) /* comment 'preferred language' */,
+     timezone varchar(50) /* comment 'timezone' */,
+     emailpost integer default 1 /* comment 'Post by email' */,
+     jabber varchar(255) unique /* comment 'jabber ID for notices' */,
+     jabbernotify integer default 0 /* comment 'whether to send notices to jabber' */,
+     jabberreplies integer default 0 /* comment 'whether to send notices to jabber on replies' */,
+     jabbermicroid integer default 1 /* comment 'whether to publish xmpp microid' */,
+     updatefrompresence integer default 0 /* comment 'whether to record updates from Jabber presence notices' */,
+     sms varchar(64) unique /* comment 'sms phone number' */,
+     carrier integer /* comment 'foreign key to sms_carrier' */ references sms_carrier (id) ,
+     smsnotify integer default 0 /* comment 'whether to send notices to SMS' */,
+     smsreplies integer default 0 /* comment 'whether to send notices to SMS on replies' */,
+     smsemail varchar(255) /* comment 'built from sms and carrier' */,
+     uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+     autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
+     urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
+     inboxed integer default 0 /* comment 'has an inbox been created for this user?' */, 
+     design_id integer /* comment 'id of a design' */references design(id),
+     viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create index user_smsemail_idx on "user" using btree(smsemail);
+ /* remote people */
+ create table remote_profile (
+     id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+     uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+     postnoticeurl varchar(255) /* comment 'URL we use for posting notices' */,
+     updateprofileurl varchar(255) /* comment 'URL we use for updates to this profile' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create table subscription (
+     subscriber integer not null /* comment 'profile listening' */,
+     subscribed integer not null /* comment 'profile being listened to' */,
+     jabber integer default 1 /* comment 'deliver jabber messages' */,
+     sms integer default 1 /* comment 'deliver sms messages' */,
+     token varchar(255) /* comment 'authorization token' */,
+     secret varchar(255) /* comment 'token secret' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     primary key (subscriber, subscribed)
+ );
+ create index subscription_subscriber_idx on subscription using btree(subscriber);
+ create index subscription_subscribed_idx on subscription using btree(subscribed);
+ create sequence notice_seq;
+ create table notice (
+     id bigint default nextval('notice_seq') primary key /* comment 'unique identifier' */,
+     profile_id integer not null /* comment 'who made the update' */ references profile (id) ,
+     uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+     content varchar(140) /* comment 'update content' */,
+     rendered text /* comment 'HTML version of the content' */,
+     url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
+     is_local integer default 0 /* comment 'notice was generated by a user' */,
+     source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
+     conversation integer /*id of root notice in this conversation' */ references notice (id)
+ /*    FULLTEXT(content) */
+ );
+ create index notice_profile_id_idx on notice using btree(profile_id);
+ create index notice_created_idx on notice using btree(created);
+ create table notice_source (
+      code varchar(32) primary key not null /* comment 'source code' */,
+      name varchar(255) not null /* comment 'name of the source' */,
+      url varchar(255) not null /* comment 'url to link to' */,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+      modified timestamp /* comment 'date this record was modified' */
+ );
+ create table reply (
+     notice_id integer not null /* comment 'notice that is the reply' */ references notice (id) ,
+     profile_id integer not null /* comment 'profile replied to' */ references profile (id) ,
+     modified timestamp /* comment 'date this record was modified' */,
+     replied_id integer /* comment 'notice replied to (not used, see notice.reply_to)' */,
+     primary key (notice_id, profile_id)
+ );
+ create index reply_notice_id_idx on reply using btree(notice_id);
+ create index reply_profile_id_idx on reply using btree(profile_id);
+ create index reply_replied_id_idx on reply using btree(replied_id);
+ create table fave (
+     notice_id integer not null /* comment 'notice that is the favorite' */ references notice (id),
+     user_id integer not null /* comment 'user who likes this notice' */ references "user" (id) ,
+     modified timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was modified' */,
+     primary key (notice_id, user_id)
+ );
+ create index fave_notice_id_idx on fave using btree(notice_id);
+ create index fave_user_id_idx on fave using btree(user_id);
+ create index fave_modified_idx on fave using btree(modified);
+ /* tables for OAuth */
+ create table consumer (
+     consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
+     seed char(32) not null /* comment 'seed for new tokens by this consumer' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create table token (
+     consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */ references consumer (consumer_key),
+     tok char(32) not null /* comment 'identifying value' */,
+     secret char(32) not null /* comment 'secret value' */,
+     type integer not null default 0 /* comment 'request or access' */,
+     state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     primary key (consumer_key, tok)
+ );
+ create table nonce (
+     consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */,
+     tok char(32) /* comment 'buggy old value, ignored' */,
+     nonce char(32) null /* comment 'buggy old value, ignored */,
+     ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     primary key (consumer_key, ts, nonce)
+ );
+ /* One-to-many relationship of user to openid_url */
+ create table user_openid (
+     canonical varchar(255) primary key /* comment 'Canonical true URL' */,
+     display varchar(255) not null unique /* comment 'URL for viewing, may be different from canonical' */,
+     user_id integer not null /* comment 'user owning this URL' */ references "user" (id) ,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create index user_openid_user_id_idx on user_openid using btree(user_id);
+ /* These are used by JanRain OpenID library */
+ create table oid_associations (
+     server_url varchar(2047),
+     handle varchar(255),
+     secret bytea,
+     issued integer,
+     lifetime integer,
+     assoc_type varchar(64),
+     primary key (server_url, handle)
+ );
+ create table oid_nonces (
+     server_url varchar(2047),
+     "timestamp" integer,
+     salt character(40),
+     unique (server_url, "timestamp", salt)
+ );
+ create table confirm_address (
+     code varchar(32) not null primary key /* comment 'good random code' */,
+     user_id integer not null /* comment 'user who requested confirmation' */ references "user" (id),
+     address varchar(255) not null /* comment 'address (email, Jabber, SMS, etc.)' */,
+     address_extra varchar(255) not null default '' /* comment 'carrier ID, for SMS' */,
+     address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms")' */,
+     claimed timestamp /* comment 'date this was claimed for queueing' */,
+     sent timestamp /* comment 'date this was sent for queueing' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create table remember_me (
+     code varchar(32) not null primary key /* comment 'good random code' */,
+     user_id integer not null /* comment 'user who is logged in' */ references "user" (id),
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create table queue_item (
+     notice_id integer not null /* comment 'notice queued' */ references notice (id) ,
+     transport varchar(8) not null /* comment 'queue for what? "email", "jabber", "sms", "irc", ...' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     claimed timestamp /* comment 'date this item was claimed' */,
+     primary key (notice_id, transport)
+ );
+ create index queue_item_created_idx on queue_item using btree(created);
+ /* Hash tags */
+ create table notice_tag (
+     tag varchar( 64 ) not null /* comment 'hash tag associated with this notice' */,
+     notice_id integer not null /* comment 'notice tagged' */ references notice (id) ,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     primary key (tag, notice_id)
+ );
+ create index notice_tag_created_idx on notice_tag using btree(created);
+ /* Synching with foreign services */
+ create table foreign_service (
+      id int not null primary key /* comment 'numeric key for service' */,
+      name varchar(32) not null unique /* comment 'name of the service' */,
+      description varchar(255) /* comment 'description' */,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+      modified timestamp /* comment 'date this record was modified' */
+ );
+ create table foreign_user (
+      id int not null unique /* comment 'unique numeric key on foreign service' */,
+      service int not null /* comment 'foreign key to service' */ references foreign_service(id) ,
+      uri varchar(255) not null unique /* comment 'identifying URI' */,
+      nickname varchar(255) /* comment 'nickname on foreign service' */,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+      modified timestamp /* comment 'date this record was modified' */,
+      
+      primary key (id, service)
+ );
+ create table foreign_link (
+      user_id int /* comment 'link to user on this system, if exists' */ references "user" (id),
+      foreign_id int /* comment 'link' */ references foreign_user (id),
+      service int not null /* comment 'foreign key to service' */ references foreign_service (id),
+      credentials varchar(255) /* comment 'authc credentials, typically a password' */,
+      noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
+      friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */, 
+      profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
+      last_noticesync timestamp default null /* comment 'last time notices were imported' */,
+      last_friendsync timestamp default null /* comment 'last time friends were imported' */,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+      modified timestamp /* comment 'date this record was modified' */,
+      primary key (user_id,foreign_id,service)
+ );
+ create index foreign_user_user_id_idx on foreign_link using btree(user_id);
+ create table foreign_subscription (
+      service int not null /* comment 'service where relationship happens' */ references foreign_service(id) ,
+      subscriber int not null /* comment 'subscriber on foreign service' */ ,
+      subscribed int not null /* comment 'subscribed user' */ ,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+      
+      primary key (service, subscriber, subscribed)
+ );
+ create index foreign_subscription_subscriber_idx on foreign_subscription using btree(subscriber);
+ create index foreign_subscription_subscribed_idx on foreign_subscription using btree(subscribed);
+ create table invitation (
+      code varchar(32) not null primary key /* comment 'random code for an invitation' */,
+      user_id int not null /* comment 'who sent the invitation' */ references "user" (id),
+      address varchar(255) not null /* comment 'invitation sent to' */,
+      address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms") '*/,
+      created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */
+ );
+ create index invitation_address_idx on invitation using btree(address,address_type);
+ create index invitation_user_id_idx on invitation using btree(user_id);
+ create sequence message_seq;
+ create table message (
+     id bigint default nextval('message_seq') primary key /* comment 'unique identifier' */,
+     uri varchar(255) unique /* comment 'universally unique identifier' */,
+     from_profile integer not null /* comment 'who the message is from' */ references profile (id),
+     to_profile integer not null /* comment 'who the message is to' */ references profile (id),
+     content varchar(140) /* comment 'message content' */,
+     rendered text /* comment 'HTML version of the content' */,
+     url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
+     
+ );
+ create index message_from_idx on message using btree(from_profile);
+ create index message_to_idx on message using btree(to_profile);
+ create index message_created_idx on message using btree(created);
+ create table notice_inbox (
+     user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
+     notice_id integer not null /* comment 'notice received' */ references notice (id),
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+     source integer default 1 /* comment 'reason it is in the inbox: 1=subscription' */,
+     primary key (user_id, notice_id)
+ );
+ create index notice_inbox_notice_id_idx on notice_inbox using btree(notice_id);
+ create table profile_tag (
+    tagger integer not null /* comment 'user making the tag' */ references "user" (id),
+    tagged integer not null /* comment 'profile tagged' */ references profile (id),
+    tag varchar(64) not null /* comment 'hash tag associated with this notice' */,
+    modified timestamp /* comment 'date the tag was added' */,
+    primary key (tagger, tagged, tag)
+ );
+ create index profile_tag_modified_idx on profile_tag using btree(modified);
+ create index profile_tag_tagger_tag_idx on profile_tag using btree(tagger,tag);
+ create table profile_block (
+    blocker integer not null /* comment 'user making the block' */ references "user" (id),
+    blocked integer not null /* comment 'profile that is blocked' */ references profile (id),
+    modified timestamp /* comment 'date of blocking' */,
+    primary key (blocker, blocked)
+ );
+ create sequence user_group_seq;
+ create table user_group (
+     id bigint default nextval('user_group_seq') primary key /* comment 'unique identifier' */,
+     nickname varchar(64) unique /* comment 'nickname for addressing' */,
+     fullname varchar(255) /* comment 'display name' */,
+     homepage varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+     description varchar(140) /* comment 'descriptive biography' */,
+     location varchar(255) /* comment 'related physical location, if any' */,
+     original_logo varchar(255) /* comment 'original size logo' */,
+     homepage_logo varchar(255) /* comment 'homepage (profile) size logo' */,
+     stream_logo varchar(255) /* comment 'stream-sized logo' */,
+     mini_logo varchar(255) /* comment 'mini logo' */,
+     design_id integer /*comment 'id of a design' */ references design(id),
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */
+ );
+ create index user_group_nickname_idx on user_group using btree(nickname);
+ create table group_member (
+     group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+     profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id),
+     is_admin integer default 0 /* comment 'is this user an admin?' */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     modified timestamp /* comment 'date this record was modified' */,
+     primary key (group_id, profile_id)
+ );
+ create table related_group (
+     group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id) ,
+     related_group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+     primary key (group_id, related_group_id)
+ );
+ create table group_inbox (
+     group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
+     notice_id integer not null /* comment 'notice received' references notice (id) */,
+     created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+     primary key (group_id, notice_id)
+ );
+ create index group_inbox_created_idx on group_inbox using btree(created);
+ /*attachments and URLs stuff */
+ create sequence file_seq;
+ create table file (
+     id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
+     url varchar(255) unique, 
+     mimetype varchar(50), 
+     size integer, 
+     title varchar(255), 
+     date integer, 
+     protected integer,
+     filename text /* comment 'if a local file, name of the file' */,
+     modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
+ );
+ create sequence file_oembed_seq;
+ create table file_oembed (
+     file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
+     version varchar(20),
+     type varchar(20),
+     provider varchar(50),
+     provider_url varchar(255),
+     width integer,
+     height integer,
+     html text,
+     title varchar(255),
+     author_name varchar(50), 
+     author_url varchar(255), 
+     url varchar(255) 
+ );
+ create sequence file_redirection_seq;
+ create table file_redirection (
+     url varchar(255) primary key, 
+     file_id bigint, 
+     redirections integer, 
+     httpcode integer
+ );
+ create sequence file_thumbnail_seq;
+ create table file_thumbnail (
+     file_id bigint primary key, 
+     url varchar(255) unique, 
+     width integer, 
+     height integer 
+ );
+ create sequence file_to_post_seq;
+ create table file_to_post (
+     file_id bigint, 
+     post_id bigint, 
+     primary key (file_id, post_id)
+ );
+ create table group_block (
+    group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
+    blocked integer not null /* comment 'profile that is blocked' */references profile (id),
+    blocker integer not null /* comment 'user making the block'*/ references "user" (id),
+    modified timestamp /* comment 'date of blocking'*/ ,
+    primary key (group_id, blocked)
+ );
+ create table group_alias (
+    alias varchar(64) /* comment 'additional nickname for the group'*/ ,
+    group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
+    modified timestamp /* comment 'date alias was created'*/,
+    primary key (alias)
+ );
+ create index group_alias_group_id_idx on group_alias (group_id);
+ create table session (
+     id varchar(32) primary key /* comment 'session ID'*/,
+     session_data text /* comment 'session data'*/,
+     created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created'*/,
+     modified integer DEFAULT extract(epoch from CURRENT_TIMESTAMP) /* comment 'date this record was modified'*/ 
+ );
+ create index session_modified_idx on session (modified);
++create table deleted_notice (
++
++    id integer primary key /* comment 'identity of notice'*/ ,
++    profile_id integer /* not null comment 'author of the notice'*/,
++    uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI'*/,
++    created timestamp not null  /* comment 'date the notice record was created'*/ ,
++    deleted timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date the notice record was created'*/
++);
++
++CREATE index deleted_notice_profile_id_idx on deleted_notice (profile_id);
++
+ /* Textsearch stuff */
+ create index textsearch_idx on profile using gist(textsearch);
+ create index noticecontent_idx on notice using gist(to_tsvector('english',content));
+ create trigger textsearchupdate before insert or update on profile for each row
+ execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
diff --cc doc-src/help
index 49b521983fd4faa06d73bb82ad63f824ba09099b,8d7acf63b4738e65bfe53fc98b43515bf322b4a5..93300ab242e3c517cc4f25b54d5c3ad898ef7e9c
@@@ -26,8 -26,9 +26,8 @@@ Here are some documents that you might 
  * [SMS](%%doc.sms%%) - tying your cellphone to %%site.name%%
  * [tags](%%doc.tags%%) - different ways to use tagging
  * [Groups](%%doc.groups%%) - joining together in groups
 -* [OpenID](%%doc.openid%%) - what OpenID is and how to use it with this service
  * [OpenMicroBlogging](%%doc.openmublog%%) - subscribing to remote users
  * [Privacy](%%doc.privacy%%) - %%site.name%%'s privacy policy
- * [Source](%%doc.source%%) - How to get the Laconica source code
- * [Badge](%%doc.badge%%) - How to put a Laconica badge on your blog or homepage
+ * [Source](%%doc.source%%) - How to get the StatusNet source code
+ * [Badge](%%doc.badge%%) - How to put a StatusNet badge on your blog or homepage
  * [Bookmarklet](%%doc.bookmarklet%%) - Bookmarklet for posting Web pages
diff --cc index.php
Simple merge
diff --cc install.php
index a03dfa775071a6352b2cb85c65d6614cd36f0cde,42d848911b820c9a599cda32a8849116834e94a2..dc42a5b3dba2d5d477c0e897929526f17a69ecf6
@@@ -371,15 -373,15 +373,15 @@@ function writeConf($sitename, $server, 
              // site location
              "\$config['site']['server'] = '$server';\n".
              "\$config['site']['path'] = '$path'; \n\n".
-             
              // checks if fancy URLs are enabled
              ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
-             
              // database
              "\$config['db']['database'] = '{$db['database']}';\n\n".
 -            ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
 +            ($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
              "\$config['db']['type'] = '{$db['type']}';\n\n".
-             
              "?>";
      // write configuration file out to install directory
      $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
@@@ -416,12 -425,10 +425,12 @@@ function runDbScript($filename, $conn, 
  
  ?>
  <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
 -<!DOCTYPE html>
 +<!DOCTYPE html
 +PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 +       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
      <head>
-         <title>Install Laconica</title>
+         <title>Install StatusNet</title>
        <link rel="shortcut icon" href="favicon.ico"/>
          <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
          <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
diff --cc js/util.js
Simple merge
Simple merge
diff --cc lib/action.php
Simple merge
diff --cc lib/command.php
Simple merge
diff --cc lib/common.php
index 31b81da597218c80ea85ebe1eb1e46c998785f72,39d4ffc9b9c3999dd715eea61b8121f8391fcec3..3b21b548cf9ef81ca0cb689b6bfd879e08117a90
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) { exit(1); }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
- define('LACONICA_VERSION', '0.9.0dev');
 -define('STATUSNET_VERSION', '0.8.1');
++define('STATUSNET_VERSION', '0.9.0dev');
+ define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
  
- // XXX: move these to class variables
 -define('STATUSNET_CODENAME', 'Second Guessing');
++define('STATUSNET_CODENAME', 'Stand');
  
  define('AVATAR_PROFILE_SIZE', 96);
  define('AVATAR_STREAM_SIZE', 48);
@@@ -118,11 -120,9 +119,11 @@@ $config 
                'ssl' => 'never',
                'sslserver' => null,
                'shorturllength' => 30,
 -              'dupelimit' => 60), # default for same person saying the same thing
 +              'dupelimit' => 60, # default for same person saying the same thing
 +              'textlimit' => 140,
 +              ),
          'syslog' =>
-         array('appname' => 'laconica', # for syslog
+         array('appname' => 'statusnet', # for syslog
                'priority' => 'debug', # XXX: currently ignored
                'facility' => LOG_USER),
          'queue' =>
@@@ -379,24 -379,14 +384,24 @@@ function _have_config(
  
  $_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1);
  
- if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
-     $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini';
+ if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
+     $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini';
  }
  
 -// Ignore openidonly if OpenID is disabled
 -
 -if (!$config['openid']['enabled']) {
 -    $config['site']['openidonly'] = false;
 +function __autoload($cls)
 +{
 +    if (file_exists(INSTALLDIR.'/classes/' . $cls . '.php')) {
 +        require_once(INSTALLDIR.'/classes/' . $cls . '.php');
 +    } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($cls) . '.php')) {
 +        require_once(INSTALLDIR.'/lib/' . strtolower($cls) . '.php');
 +    } else if (mb_substr($cls, -6) == 'Action' &&
 +               file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php')) {
 +        require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
 +    } else if ($cls == 'OAuthRequest') {
 +        require_once('OAuth.php');
 +    } else {
 +        Event::handle('Autoload', array(&$cls));
 +    }
  }
  
  // XXX: how many of these could be auto-loaded on use?
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 87d8cf2137b197718d93b4d5803502e5c50f867f,6db07b20f781c9e2cf901a6e631760b681e80f41..e69a00f55f2ab61e588a763e882e926d2c962c06
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once(INSTALLDIR.'/lib/omb.php');
 +require_once 'libomb/datastore.php';
  
- class LaconicaDataStore extends OMB_Datastore
+ class StatusNetOAuthDataStore extends OAuthDataStore
  {
  
      // We keep a record of who's contacted us
diff --cc lib/omb.php
index b9d0eef64e6291e69e38d505590acd00a623f45c,0d62445991a4b5a08399217248c3556a1267c4d5..0566701ff16990fbc45b6e3003b6e4f67455c5f7
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
- if (!defined('LACONICA')) {
-     exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
  
 -require_once('OAuth.php');
 -require_once(INSTALLDIR.'/lib/oauthstore.php');
 -
 -require_once(INSTALLDIR.'/classes/Consumer.php');
 -require_once(INSTALLDIR.'/classes/Nonce.php');
 -require_once(INSTALLDIR.'/classes/Token.php');
 -
 -require_once('Auth/Yadis/Yadis.php');
 -
 -define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
 -define('OMB_NAMESPACE', 'http://openmicroblogging.org/protocol/0.1');
 -define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
 -define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
 -
 -define('OMB_ENDPOINT_UPDATEPROFILE', OMB_NAMESPACE.'/updateProfile');
 -define('OMB_ENDPOINT_POSTNOTICE', OMB_NAMESPACE.'/postNotice');
 -define('OAUTH_ENDPOINT_REQUEST', OAUTH_NAMESPACE.'endpoint/request');
 -define('OAUTH_ENDPOINT_AUTHORIZE', OAUTH_NAMESPACE.'endpoint/authorize');
 -define('OAUTH_ENDPOINT_ACCESS', OAUTH_NAMESPACE.'endpoint/access');
 -define('OAUTH_ENDPOINT_RESOURCE', OAUTH_NAMESPACE.'endpoint/resource');
 -define('OAUTH_AUTH_HEADER', OAUTH_NAMESPACE.'parameters/auth-header');
 -define('OAUTH_POST_BODY', OAUTH_NAMESPACE.'parameters/post-body');
 -define('OAUTH_HMAC_SHA1', OAUTH_NAMESPACE.'signature/HMAC-SHA1');
 +require_once INSTALLDIR.'/lib/oauthstore.php';
 +require_once 'OAuth.php';
 +require_once 'libomb/constants.php';
 +require_once 'libomb/service_consumer.php';
 +require_once 'libomb/notice.php';
 +require_once 'libomb/profile.php';
 +require_once 'Auth/Yadis/Yadis.php';
  
  function omb_oauth_consumer()
  {
@@@ -51,8 -65,8 +49,8 @@@ function omb_oauth_server(
  function omb_oauth_datastore()
  {
      static $store = null;
 -    if (!$store) {
 +    if (is_null($store)) {
-         $store = new LaconicaDataStore();
+         $store = new StatusNetOAuthDataStore();
      }
      return $store;
  }
@@@ -115,115 -165,140 +113,115 @@@ function omb_broadcast_profile($profile
          return false;
      }
  
 -    $con = omb_oauth_consumer();
 +    $profile = $user->getProfile();
  
 -    $token = new OAuthToken($tk, $secret);
 -
 -    $url = $postnoticeurl;
 -    $parsed = parse_url($url);
 -    $params = array();
 -    parse_str($parsed['query'], $params);
 -
 -    $req = OAuthRequest::from_consumer_and_token($con, $token,
 -                                                 'POST', $url, $params);
 -
 -    $req->set_parameter('omb_version', OMB_VERSION_01);
 -    $req->set_parameter('omb_listenee', $user->uri);
 -    $req->set_parameter('omb_notice', $notice->uri);
 -    $req->set_parameter('omb_notice_content', $notice->content);
 -    $req->set_parameter('omb_notice_url', common_local_url('shownotice',
 -                                                           array('notice' =>
 -                                                                 $notice->id)));
 -    $req->set_parameter('omb_notice_license', common_config('license', 'url'));
 +    $omb_profile = profile_to_omb_profile($user->uri, $profile, true);
  
 -    $user->free();
 -    unset($user);
 +    /* Get remote users subscribed to this profile. */
 +    $rp = new Remote_profile();
  
 -    $req->sign_request(omb_hmac_sha1(), $con, $token);
 +    $rp->query('SELECT updateprofileurl, token, secret ' .
 +               'FROM subscription JOIN remote_profile ' .
 +               'ON subscription.subscriber = remote_profile.id ' .
 +               'WHERE subscription.subscribed = ' . $profile->id . ' ');
  
 -    # We re-use this tool's fetcher, since it's pretty good
 +    $posted = array();
  
 -    $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
 +    while ($rp->fetch()) {
 +        if (isset($posted[$rp->updateprofileurl])) {
 +            /* We already posted to this url. */
 +            continue;
 +        }
 +        common_debug('Posting to ' . $rp->updateprofileurl, __FILE__);
 +
 +        /* Update profile. */
-         $service = new Laconica_OMB_Service_Consumer(
++        $service = new StatusNet_OMB_Service_Consumer(
 +                     array(OMB_ENDPOINT_UPDATEPROFILE => $rp->updateprofileurl));
 +        try {
 +            $service->setToken($rp->token, $rp->secret);
 +            $service->updateProfile($omb_profile);
 +        } catch (Exception $e) {
 +            common_log(LOG_ERR, 'Failed posting to ' . $rp->updateprofileurl);
 +            common_log(LOG_ERR, 'Error status '.$e);
 +            continue;
 +        }
 +        $posted[$rp->updateprofileurl] = true;
  
 -    if (!$fetcher) {
 -        common_log(LOG_WARNING, 'Failed to initialize Yadis fetcher.', __FILE__);
 -        return false;
 +        common_debug('Finished to ' . $rp->updateprofileurl, __FILE__);
      }
  
 -    $result = $fetcher->post($req->get_normalized_http_url(),
 -                             $req->to_postdata(),
 -                             array('User-Agent: StatusNet/' . STATUSNET_VERSION));
 -
 -    if ($result->status == 403) { # not authorized, don't send again
 -        common_debug('403 result, deleting subscription', __FILE__);
 -        # FIXME: figure out how to delete this
 -        # $subscription->delete();
 -        return false;
 -    } else if ($result->status != 200) {
 -        common_debug('Error status '.$result->status, __FILE__);
 -        return false;
 -    } else { # success!
 -        parse_str($result->body, $return);
 -        if ($return['omb_version'] == OMB_VERSION_01) {
 -            return true;
 -        } else {
 -            return false;
 -        }
 -    }
 +    return;
  }
  
- class Laconica_OMB_Service_Consumer extends OMB_Service_Consumer {
 -function omb_broadcast_profile($profile)
 -{
 -    # First, get remote users subscribed to this profile
 -    # XXX: use a join here rather than looping through results
 -    $sub = new Subscription();
 -    $sub->subscribed = $profile->id;
 -    if ($sub->find()) {
 -        $updated = array();
 -        while ($sub->fetch()) {
 -            $rp = Remote_profile::staticGet('id', $sub->subscriber);
 -            if ($rp) {
 -                if (!array_key_exists($rp->updateprofileurl, $updated)) {
 -                    if (omb_update_profile($profile, $rp, $sub)) {
 -                        $updated[$rp->updateprofileurl] = true;
 -                    }
 -                }
 -            }
 -        }
++class StatusNet_OMB_Service_Consumer extends OMB_Service_Consumer {
 +    public function __construct($urls)
 +    {
 +        $this->services       = $urls;
 +        $this->datastore      = omb_oauth_datastore();
 +        $this->oauth_consumer = omb_oauth_consumer();
 +        $this->fetcher        = Auth_Yadis_Yadis::getHTTPFetcher();
      }
 +
  }
  
 -function omb_update_profile($profile, $remote_profile, $subscription)
 +function profile_to_omb_profile($uri, $profile, $force = false)
  {
 -    $user = User::staticGet($profile->id);
 -    $con = omb_oauth_consumer();
 -    $token = new OAuthToken($subscription->token, $subscription->secret);
 -    $url = $remote_profile->updateprofileurl;
 -    $parsed = parse_url($url);
 -    $params = array();
 -    parse_str($parsed['query'], $params);
 -    $req = OAuthRequest::from_consumer_and_token($con, $token,
 -                                                 "POST", $url, $params);
 -    $req->set_parameter('omb_version', OMB_VERSION_01);
 -    $req->set_parameter('omb_listenee', $user->uri);
 -    $req->set_parameter('omb_listenee_profile', common_profile_url($profile->nickname));
 -    $req->set_parameter('omb_listenee_nickname', $profile->nickname);
 -
 -    # We use blanks to force emptying any existing values in these optional fields
 -
 -    $req->set_parameter('omb_listenee_fullname',
 -                        ($profile->fullname) ? $profile->fullname : '');
 -    $req->set_parameter('omb_listenee_homepage',
 -                        ($profile->homepage) ? $profile->homepage : '');
 -    $req->set_parameter('omb_listenee_bio',
 -                        ($profile->bio) ? $profile->bio : '');
 -    $req->set_parameter('omb_listenee_location',
 -                        ($profile->location) ? $profile->location : '');
 +    $omb_profile = new OMB_Profile($uri);
 +    $omb_profile->setNickname($profile->nickname);
 +    $omb_profile->setLicenseURL(common_config('license', 'url'));
 +    if (!is_null($profile->fullname)) {
 +        $omb_profile->setFullname($profile->fullname);
 +    } elseif ($force) {
 +        $omb_profile->setFullname('');
 +    }
 +    if (!is_null($profile->homepage)) {
 +        $omb_profile->setHomepage($profile->homepage);
 +    } elseif ($force) {
 +        $omb_profile->setHomepage('');
 +    }
 +    if (!is_null($profile->bio)) {
 +        $omb_profile->setBio($profile->bio);
 +    } elseif ($force) {
 +        $omb_profile->setBio('');
 +    }
 +    if (!is_null($profile->location)) {
 +        $omb_profile->setLocation($profile->location);
 +    } elseif ($force) {
 +        $omb_profile->setLocation('');
 +    }
 +    if (!is_null($profile->profileurl)) {
 +        $omb_profile->setProfileURL($profile->profileurl);
 +    } elseif ($force) {
 +        $omb_profile->setProfileURL('');
 +    }
  
      $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
 -    $req->set_parameter('omb_listenee_avatar',
 -                        ($avatar) ? $avatar->url : '');
 +    if ($avatar) {
 +        $omb_profile->setAvatarURL($avatar->url);
 +    } elseif ($force) {
 +        $omb_profile->setAvatarURL('');
 +    }
 +    return $omb_profile;
 +}
  
 -    $req->sign_request(omb_hmac_sha1(), $con, $token);
 +function notice_to_omb_notice($notice)
 +{
 +    /* Create an OMB_Notice for $notice. */
 +    $user = User::staticGet('id', $notice->profile_id);
  
 -    # We re-use this tool's fetcher, since it's pretty good
 +    if (!$user) {
 +        return null;
 +    }
  
 -    $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
 +    $profile = $user->getProfile();
  
 -    $result = $fetcher->post($req->get_normalized_http_url(),
 -                             $req->to_postdata(),
 -                             array('User-Agent: StatusNet/' . STATUSNET_VERSION));
 +    $omb_notice = new OMB_Notice(profile_to_omb_profile($user->uri, $profile),
 +                                 $notice->uri,
 +                                 $notice->content);
 +    $omb_notice->setURL(common_local_url('shownotice', array('notice' =>
 +                                                                 $notice->id)));
 +    $omb_notice->setLicenseURL(common_config('license', 'url'));
  
 -    if (empty($result) || !$result) {
 -        common_debug("Unable to contact " . $req->get_normalized_http_url());
 -    } else if ($result->status == 403) { # not authorized, don't send again
 -        common_debug('403 result, deleting subscription', __FILE__);
 -        $subscription->delete();
 -        return false;
 -    } else if ($result->status != 200) {
 -        common_debug('Error status '.$result->status, __FILE__);
 -        return false;
 -    } else { # success!
 -        parse_str($result->body, $return);
 -        if (isset($return['omb_version']) && $return['omb_version'] === OMB_VERSION_01) {
 -            return true;
 -        } else {
 -            return false;
 -        }
 -    }
 +    return $omb_notice;
  }
 +?>
diff --cc lib/router.php
Simple merge
Simple merge
Simple merge
diff --cc lib/util.php
Simple merge
index 7753158d5d458dde42988307a10bd1164e9e17e3,0000000000000000000000000000000000000000..6e889205d7cc6130adc3aa072a93dcffb696a0d9
mode 100644,000000..100644
--- /dev/null
@@@ -1,185 -1,0 +1,185 @@@
-  * Laconica, the distributed open-source microblogging tool
 +<?php
 +/**
-  * @package   Laconica
-  * @author    Evan Prodromou <evan@controlyourself.ca>
-  * @copyright 2008-2009 Control Yourself, Inc.
++ * StatusNet, the distributed open-source microblogging tool
 + *
 + * Complete adding an OpenID
 + *
 + * PHP version 5
 + *
 + * LICENCE: 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/>.
 + *
 + * @category  Settings
-  * @link      http://laconi.ca/
++ * @package   StatusNet
++ * @author    Evan Prodromou <evan@status.net>
++ * @copyright 2008-2009 StatusNet, Inc.
 + * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- if (!defined('LACONICA')) {
++ * @link      http://status.net/
 + */
 +
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
 +    exit(1);
 +}
 +
 +require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 +
 +/**
 + * Complete adding an OpenID
 + *
 + * Handle the return from an OpenID verification
 + *
 + * @category Settings
-  * @link     http://laconi.ca/
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link     http://status.net/
 + */
 +
 +class FinishaddopenidAction extends Action
 +{
 +    var $msg = null;
 +
 +    /**
 +     * Handle the redirect back from OpenID confirmation
 +     *
 +     * Check to see if the user's logged in, and then try
 +     * to use the OpenID login system.
 +     *
 +     * @param array $args $_REQUEST arguments
 +     *
 +     * @return void
 +     */
 +
 +    function handle($args)
 +    {
 +        parent::handle($args);
 +        if (!common_logged_in()) {
 +            $this->clientError(_('Not logged in.'));
 +        } else {
 +            $this->tryLogin();
 +        }
 +    }
 +
 +    /**
 +     * Try to log in using OpenID
 +     *
 +     * Check the OpenID for validity; potentially store it.
 +     *
 +     * @return void
 +     */
 +
 +    function tryLogin()
 +    {
 +        $consumer =& oid_consumer();
 +
 +        $response = $consumer->complete(common_local_url('finishaddopenid'));
 +
 +        if ($response->status == Auth_OpenID_CANCEL) {
 +            $this->message(_('OpenID authentication cancelled.'));
 +            return;
 +        } else if ($response->status == Auth_OpenID_FAILURE) {
 +            // Authentication failed; display the error message.
 +            $this->message(sprintf(_('OpenID authentication failed: %s'),
 +                                   $response->message));
 +        } else if ($response->status == Auth_OpenID_SUCCESS) {
 +
 +            $display   = $response->getDisplayIdentifier();
 +            $canonical = ($response->endpoint && $response->endpoint->canonicalID) ?
 +              $response->endpoint->canonicalID : $display;
 +
 +            $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
 +
 +            if ($sreg_resp) {
 +                $sreg = $sreg_resp->contents();
 +            }
 +
 +            $cur =& common_current_user();
 +
 +            $other = oid_get_user($canonical);
 +
 +            if ($other) {
 +                if ($other->id == $cur->id) {
 +                    $this->message(_('You already have this OpenID!'));
 +                } else {
 +                    $this->message(_('Someone else already has this OpenID.'));
 +                }
 +                return;
 +            }
 +
 +            // start a transaction
 +
 +            $cur->query('BEGIN');
 +
 +            $result = oid_link_user($cur->id, $canonical, $display);
 +
 +            if (!$result) {
 +                $this->message(_('Error connecting user.'));
 +                return;
 +            }
 +            if ($sreg) {
 +                if (!oid_update_user($cur, $sreg)) {
 +                    $this->message(_('Error updating profile'));
 +                    return;
 +                }
 +            }
 +
 +            // success!
 +
 +            $cur->query('COMMIT');
 +
 +            oid_set_last($display);
 +
 +            common_redirect(common_local_url('openidsettings'), 303);
 +        }
 +    }
 +
 +    /**
 +     * Show a failure message
 +     *
 +     * Something went wrong. Save the message, and show the page.
 +     *
 +     * @param string $msg Error message to show
 +     *
 +     * @return void
 +     */
 +
 +    function message($msg)
 +    {
 +        $this->message = $msg;
 +        $this->showPage();
 +    }
 +
 +    /**
 +     * Title of the page
 +     *
 +     * @return string title
 +     */
 +
 +    function title()
 +    {
 +        return _('OpenID Login');
 +    }
 +
 +    /**
 +     * Show error message
 +     *
 +     * @return void
 +     */
 +
 +    function showPageNotice()
 +    {
 +        if ($this->message) {
 +            $this->element('p', 'error', $this->message);
 +        }
 +    }
 +}
index bc0d2d66c398e68f6f8949f75765653c165b8ec6,0000000000000000000000000000000000000000..50a9c15c87a8730e2b9fb7ce11f415e97cb93d32
mode 100644,000000..100644
--- /dev/null
@@@ -1,495 -1,0 +1,495 @@@
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
 +<?php
 +/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
 + *
 + * 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/>.
 + */
 +
-     # We try to use an OpenID URL as a legal Laconica user name in this order
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 +
 +require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 +
 +class FinishopenidloginAction extends Action
 +{
 +    var $error = null;
 +    var $username = null;
 +    var $message = null;
 +
 +    function handle($args)
 +    {
 +        parent::handle($args);
 +        if (common_is_real_login()) {
 +            $this->clientError(_('Already logged in.'));
 +        } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
 +            $token = $this->trimmed('token');
 +            if (!$token || $token != common_session_token()) {
 +                $this->showForm(_('There was a problem with your session token. Try again, please.'));
 +                return;
 +            }
 +            if ($this->arg('create')) {
 +                if (!$this->boolean('license')) {
 +                    $this->showForm(_('You can\'t register if you don\'t agree to the license.'),
 +                                    $this->trimmed('newname'));
 +                    return;
 +                }
 +                $this->createNewUser();
 +            } else if ($this->arg('connect')) {
 +                $this->connectUser();
 +            } else {
 +                common_debug(print_r($this->args, true), __FILE__);
 +                $this->showForm(_('Something weird happened.'),
 +                                $this->trimmed('newname'));
 +            }
 +        } else {
 +            $this->tryLogin();
 +        }
 +    }
 +
 +    function showPageNotice()
 +    {
 +        if ($this->error) {
 +            $this->element('div', array('class' => 'error'), $this->error);
 +        } else {
 +            $this->element('div', 'instructions',
 +                           sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
 +        }
 +    }
 +
 +    function title()
 +    {
 +        return _('OpenID Account Setup');
 +    }
 +
 +    function showForm($error=null, $username=null)
 +    {
 +        $this->error = $error;
 +        $this->username = $username;
 +
 +        $this->showPage();
 +    }
 +
 +    function showContent()
 +    {
 +        if (!empty($this->message_text)) {
 +            $this->element('div', array('class' => 'error'), $this->message_text);
 +            return;
 +        }
 +
 +        $this->elementStart('form', array('method' => 'post',
 +                                          'id' => 'account_connect',
 +                                          'action' => common_local_url('finishopenidlogin')));
 +        $this->hidden('token', common_session_token());
 +        $this->element('h2', null,
 +                       _('Create new account'));
 +        $this->element('p', null,
 +                       _('Create a new user with this nickname.'));
 +        $this->input('newname', _('New nickname'),
 +                     ($this->username) ? $this->username : '',
 +                     _('1-64 lowercase letters or numbers, no punctuation or spaces'));
 +        $this->elementStart('p');
 +        $this->element('input', array('type' => 'checkbox',
 +                                      'id' => 'license',
 +                                      'name' => 'license',
 +                                      'value' => 'true'));
 +        $this->text(_('My text and files are available under '));
 +        $this->element('a', array('href' => common_config('license', 'url')),
 +                       common_config('license', 'title'));
 +        $this->text(_(' except this private data: password, email address, IM address, phone number.'));
 +        $this->elementEnd('p');
 +        $this->submit('create', _('Create'));
 +        $this->element('h2', null,
 +                       _('Connect existing account'));
 +        $this->element('p', null,
 +                       _('If you already have an account, login with your username and password to connect it to your OpenID.'));
 +        $this->input('nickname', _('Existing nickname'));
 +        $this->password('password', _('Password'));
 +        $this->submit('connect', _('Connect'));
 +        $this->elementEnd('form');
 +    }
 +
 +    function tryLogin()
 +    {
 +        $consumer = oid_consumer();
 +
 +        $response = $consumer->complete(common_local_url('finishopenidlogin'));
 +
 +        if ($response->status == Auth_OpenID_CANCEL) {
 +            $this->message(_('OpenID authentication cancelled.'));
 +            return;
 +        } else if ($response->status == Auth_OpenID_FAILURE) {
 +            // Authentication failed; display the error message.
 +            $this->message(sprintf(_('OpenID authentication failed: %s'), $response->message));
 +        } else if ($response->status == Auth_OpenID_SUCCESS) {
 +            // This means the authentication succeeded; extract the
 +            // identity URL and Simple Registration data (if it was
 +            // returned).
 +            $display = $response->getDisplayIdentifier();
 +            $canonical = ($response->endpoint->canonicalID) ?
 +              $response->endpoint->canonicalID : $response->getDisplayIdentifier();
 +
 +            $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
 +
 +            if ($sreg_resp) {
 +                $sreg = $sreg_resp->contents();
 +            }
 +
 +            $user = oid_get_user($canonical);
 +
 +            if ($user) {
 +                oid_set_last($display);
 +                # XXX: commented out at @edd's request until better
 +                # control over how data flows from OpenID provider.
 +                # oid_update_user($user, $sreg);
 +                common_set_user($user);
 +                common_real_login(true);
 +                if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
 +                    common_rememberme($user);
 +                }
 +                unset($_SESSION['openid_rememberme']);
 +                $this->goHome($user->nickname);
 +            } else {
 +                $this->saveValues($display, $canonical, $sreg);
 +                $this->showForm(null, $this->bestNewNickname($display, $sreg));
 +            }
 +        }
 +    }
 +
 +    function message($msg)
 +    {
 +        $this->message_text = $msg;
 +        $this->showPage();
 +    }
 +
 +    function saveValues($display, $canonical, $sreg)
 +    {
 +        common_ensure_session();
 +        $_SESSION['openid_display'] = $display;
 +        $_SESSION['openid_canonical'] = $canonical;
 +        $_SESSION['openid_sreg'] = $sreg;
 +    }
 +
 +    function getSavedValues()
 +    {
 +        return array($_SESSION['openid_display'],
 +                     $_SESSION['openid_canonical'],
 +                     $_SESSION['openid_sreg']);
 +    }
 +
 +    function createNewUser()
 +    {
 +        # FIXME: save invite code before redirect, and check here
 +
 +        if (common_config('site', 'closed')) {
 +            $this->clientError(_('Registration not allowed.'));
 +            return;
 +        }
 +
 +        $invite = null;
 +
 +        if (common_config('site', 'inviteonly')) {
 +            $code = $_SESSION['invitecode'];
 +            if (empty($code)) {
 +                $this->clientError(_('Registration not allowed.'));
 +                return;
 +            }
 +
 +            $invite = Invitation::staticGet($code);
 +
 +            if (empty($invite)) {
 +                $this->clientError(_('Not a valid invitation code.'));
 +                return;
 +            }
 +        }
 +
 +        $nickname = $this->trimmed('newname');
 +
 +        if (!Validate::string($nickname, array('min_length' => 1,
 +                                               'max_length' => 64,
 +                                               'format' => NICKNAME_FMT))) {
 +            $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
 +            return;
 +        }
 +
 +        if (!User::allowed_nickname($nickname)) {
 +            $this->showForm(_('Nickname not allowed.'));
 +            return;
 +        }
 +
 +        if (User::staticGet('nickname', $nickname)) {
 +            $this->showForm(_('Nickname already in use. Try another one.'));
 +            return;
 +        }
 +
 +        list($display, $canonical, $sreg) = $this->getSavedValues();
 +
 +        if (!$display || !$canonical) {
 +            $this->serverError(_('Stored OpenID not found.'));
 +            return;
 +        }
 +
 +        # Possible race condition... let's be paranoid
 +
 +        $other = oid_get_user($canonical);
 +
 +        if ($other) {
 +            $this->serverError(_('Creating new account for OpenID that already has a user.'));
 +            return;
 +        }
 +
 +        $location = '';
 +        if (!empty($sreg['country'])) {
 +            if ($sreg['postcode']) {
 +                # XXX: use postcode to get city and region
 +                # XXX: also, store postcode somewhere -- it's valuable!
 +                $location = $sreg['postcode'] . ', ' . $sreg['country'];
 +            } else {
 +                $location = $sreg['country'];
 +            }
 +        }
 +
 +        if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
 +            $fullname = $sreg['fullname'];
 +        } else {
 +            $fullname = '';
 +        }
 +
 +        if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
 +            $email = $sreg['email'];
 +        } else {
 +            $email = '';
 +        }
 +
 +        # XXX: add language
 +        # XXX: add timezone
 +
 +        $args = array('nickname' => $nickname,
 +                      'email' => $email,
 +                      'fullname' => $fullname,
 +                      'location' => $location);
 +
 +        if (!empty($invite)) {
 +            $args['code'] = $invite->code;
 +        }
 +
 +        $user = User::register($args);
 +
 +        $result = oid_link_user($user->id, $canonical, $display);
 +
 +        oid_set_last($display);
 +        common_set_user($user);
 +        common_real_login(true);
 +        if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
 +            common_rememberme($user);
 +        }
 +        unset($_SESSION['openid_rememberme']);
 +        common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
 +                        303);
 +    }
 +
 +    function connectUser()
 +    {
 +        $nickname = $this->trimmed('nickname');
 +        $password = $this->trimmed('password');
 +
 +        if (!common_check_user($nickname, $password)) {
 +            $this->showForm(_('Invalid username or password.'));
 +            return;
 +        }
 +
 +        # They're legit!
 +
 +        $user = User::staticGet('nickname', $nickname);
 +
 +        list($display, $canonical, $sreg) = $this->getSavedValues();
 +
 +        if (!$display || !$canonical) {
 +            $this->serverError(_('Stored OpenID not found.'));
 +            return;
 +        }
 +
 +        $result = oid_link_user($user->id, $canonical, $display);
 +
 +        if (!$result) {
 +            $this->serverError(_('Error connecting user to OpenID.'));
 +            return;
 +        }
 +
 +        oid_update_user($user, $sreg);
 +        oid_set_last($display);
 +        common_set_user($user);
 +        common_real_login(true);
 +        if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
 +            common_rememberme($user);
 +        }
 +        unset($_SESSION['openid_rememberme']);
 +        $this->goHome($user->nickname);
 +    }
 +
 +    function goHome($nickname)
 +    {
 +        $url = common_get_returnto();
 +        if ($url) {
 +            # We don't have to return to it again
 +            common_set_returnto(null);
 +        } else {
 +            $url = common_local_url('all',
 +                                    array('nickname' =>
 +                                          $nickname));
 +        }
 +        common_redirect($url, 303);
 +    }
 +
 +    function bestNewNickname($display, $sreg)
 +    {
 +
 +        # Try the passed-in nickname
 +
 +        if (!empty($sreg['nickname'])) {
 +            $nickname = $this->nicknamize($sreg['nickname']);
 +            if ($this->isNewNickname($nickname)) {
 +                return $nickname;
 +            }
 +        }
 +
 +        # Try the full name
 +
 +        if (!empty($sreg['fullname'])) {
 +            $fullname = $this->nicknamize($sreg['fullname']);
 +            if ($this->isNewNickname($fullname)) {
 +                return $fullname;
 +            }
 +        }
 +
 +        # Try the URL
 +
 +        $from_url = $this->openidToNickname($display);
 +
 +        if ($from_url && $this->isNewNickname($from_url)) {
 +            return $from_url;
 +        }
 +
 +        # XXX: others?
 +
 +        return null;
 +    }
 +
 +    function isNewNickname($str)
 +    {
 +        if (!Validate::string($str, array('min_length' => 1,
 +                                          'max_length' => 64,
 +                                          'format' => NICKNAME_FMT))) {
 +            return false;
 +        }
 +        if (!User::allowed_nickname($str)) {
 +            return false;
 +        }
 +        if (User::staticGet('nickname', $str)) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    function openidToNickname($openid)
 +    {
 +        if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
 +            return $this->xriToNickname($openid);
 +        } else {
 +            return $this->urlToNickname($openid);
 +        }
 +    }
 +
++    # We try to use an OpenID URL as a legal StatusNet user name in this order
 +    # 1. Plain hostname, like http://evanp.myopenid.com/
 +    # 2. One element in path, like http://profile.typekey.com/EvanProdromou/
 +    #    or http://getopenid.com/evanprodromou
 +
 +    function urlToNickname($openid)
 +    {
 +        static $bad = array('query', 'user', 'password', 'port', 'fragment');
 +
 +        $parts = parse_url($openid);
 +
 +        # If any of these parts exist, this won't work
 +
 +        foreach ($bad as $badpart) {
 +            if (array_key_exists($badpart, $parts)) {
 +                return null;
 +            }
 +        }
 +
 +        # We just have host and/or path
 +
 +        # If it's just a host...
 +        if (array_key_exists('host', $parts) &&
 +            (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0))
 +        {
 +            $hostparts = explode('.', $parts['host']);
 +
 +            # Try to catch common idiom of nickname.service.tld
 +
 +            if ((count($hostparts) > 2) &&
 +                (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au
 +                (strcmp($hostparts[0], 'www') != 0))
 +            {
 +                return $this->nicknamize($hostparts[0]);
 +            } else {
 +                # Do the whole hostname
 +                return $this->nicknamize($parts['host']);
 +            }
 +        } else {
 +            if (array_key_exists('path', $parts)) {
 +                # Strip starting, ending slashes
 +                $path = preg_replace('@/$@', '', $parts['path']);
 +                $path = preg_replace('@^/@', '', $path);
 +                if (strpos($path, '/') === false) {
 +                    return $this->nicknamize($path);
 +                }
 +            }
 +        }
 +
 +        return null;
 +    }
 +
 +    function xriToNickname($xri)
 +    {
 +        $base = $this->xriBase($xri);
 +
 +        if (!$base) {
 +            return null;
 +        } else {
 +            # =evan.prodromou
 +            # or @gratis*evan.prodromou
 +            $parts = explode('*', substr($base, 1));
 +            return $this->nicknamize(array_pop($parts));
 +        }
 +    }
 +
 +    function xriBase($xri)
 +    {
 +        if (substr($xri, 0, 6) == 'xri://') {
 +            return substr($xri, 6);
 +        } else {
 +            return $xri;
 +        }
 +    }
 +
 +    # Given a string, try to make it work as a nickname
 +
 +    function nicknamize($str)
 +    {
 +        $str = preg_replace('/\W/', '', $str);
 +        return strtolower($str);
 +    }
 +}
index 4787cd605dd65add814e770fdc6a064431819631,0000000000000000000000000000000000000000..0944117c00fc5e0b2a62401184ac7ea2ac3db822
mode 100644,000000..100644
--- /dev/null
@@@ -1,280 -1,0 +1,280 @@@
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
 +<?php
 +/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
 + *
 + * 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/>.
 + */
 +
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 +
 +require_once(INSTALLDIR.'/plugins/OpenID/User_openid.php');
 +
 +require_once('Auth/OpenID.php');
 +require_once('Auth/OpenID/Consumer.php');
 +require_once('Auth/OpenID/SReg.php');
 +require_once('Auth/OpenID/MySQLStore.php');
 +
 +# About one year cookie expiry
 +
 +define('OPENID_COOKIE_EXPIRY', round(365.25 * 24 * 60 * 60));
 +define('OPENID_COOKIE_KEY', 'lastusedopenid');
 +
 +function oid_store()
 +{
 +    static $store = null;
 +    if (!$store) {
 +        # Can't be called statically
 +        $user = new User();
 +        $conn = $user->getDatabaseConnection();
 +        $store = new Auth_OpenID_MySQLStore($conn);
 +    }
 +    return $store;
 +}
 +
 +function oid_consumer()
 +{
 +    $store = oid_store();
 +    $consumer = new Auth_OpenID_Consumer($store);
 +    return $consumer;
 +}
 +
 +function oid_clear_last()
 +{
 +    oid_set_last('');
 +}
 +
 +function oid_set_last($openid_url)
 +{
 +    common_set_cookie(OPENID_COOKIE_KEY,
 +                     $openid_url,
 +                     time() + OPENID_COOKIE_EXPIRY);
 +}
 +
 +function oid_get_last()
 +{
 +    if (empty($_COOKIE[OPENID_COOKIE_KEY])) {
 +        return null;
 +    }
 +    $openid_url = $_COOKIE[OPENID_COOKIE_KEY];
 +    if ($openid_url && strlen($openid_url) > 0) {
 +        return $openid_url;
 +    } else {
 +        return null;
 +    }
 +}
 +
 +function oid_link_user($id, $canonical, $display)
 +{
 +
 +    $oid = new User_openid();
 +    $oid->user_id = $id;
 +    $oid->canonical = $canonical;
 +    $oid->display = $display;
 +    $oid->created = DB_DataObject_Cast::dateTime();
 +
 +    if (!$oid->insert()) {
 +        $err = PEAR::getStaticProperty('DB_DataObject','lastError');
 +        common_debug('DB error ' . $err->code . ': ' . $err->message, __FILE__);
 +        return false;
 +    }
 +
 +    return true;
 +}
 +
 +function oid_get_user($openid_url)
 +{
 +    $user = null;
 +    $oid = User_openid::staticGet('canonical', $openid_url);
 +    if ($oid) {
 +        $user = User::staticGet('id', $oid->user_id);
 +    }
 +    return $user;
 +}
 +
 +function oid_check_immediate($openid_url, $backto=null)
 +{
 +    if (!$backto) {
 +        $action = $_REQUEST['action'];
 +        $args = common_copy_args($_GET);
 +        unset($args['action']);
 +        $backto = common_local_url($action, $args);
 +    }
 +    common_debug('going back to "' . $backto . '"', __FILE__);
 +
 +    common_ensure_session();
 +
 +    $_SESSION['openid_immediate_backto'] = $backto;
 +    common_debug('passed-in variable is "' . $backto . '"', __FILE__);
 +    common_debug('session variable is "' . $_SESSION['openid_immediate_backto'] . '"', __FILE__);
 +
 +    oid_authenticate($openid_url,
 +                     'finishimmediate',
 +                     true);
 +}
 +
 +function oid_authenticate($openid_url, $returnto, $immediate=false)
 +{
 +
 +    $consumer = oid_consumer();
 +
 +    if (!$consumer) {
 +        common_server_error(_('Cannot instantiate OpenID consumer object.'));
 +        return false;
 +    }
 +
 +    common_ensure_session();
 +
 +    $auth_request = $consumer->begin($openid_url);
 +
 +    // Handle failure status return values.
 +    if (!$auth_request) {
 +        return _('Not a valid OpenID.');
 +    } else if (Auth_OpenID::isFailure($auth_request)) {
 +        return sprintf(_('OpenID failure: %s'), $auth_request->message);
 +    }
 +
 +    $sreg_request = Auth_OpenID_SRegRequest::build(// Required
 +                                                   array(),
 +                                                   // Optional
 +                                                   array('nickname',
 +                                                         'email',
 +                                                         'fullname',
 +                                                         'language',
 +                                                         'timezone',
 +                                                         'postcode',
 +                                                         'country'));
 +
 +    if ($sreg_request) {
 +        $auth_request->addExtension($sreg_request);
 +    }
 +
 +    $trust_root = common_root_url(true);
 +    $process_url = common_local_url($returnto);
 +
 +    if ($auth_request->shouldSendRedirect()) {
 +        $redirect_url = $auth_request->redirectURL($trust_root,
 +                                                   $process_url,
 +                                                   $immediate);
 +        if (!$redirect_url) {
 +        } else if (Auth_OpenID::isFailure($redirect_url)) {
 +            return sprintf(_('Could not redirect to server: %s'), $redirect_url->message);
 +        } else {
 +            common_redirect($redirect_url, 303);
 +        }
 +    } else {
 +        // Generate form markup and render it.
 +        $form_id = 'openid_message';
 +        $form_html = $auth_request->formMarkup($trust_root, $process_url,
 +                                               $immediate, array('id' => $form_id));
 +
 +        # XXX: This is cheap, but things choke if we don't escape ampersands
 +        # in the HTML attributes
 +
 +        $form_html = preg_replace('/&/', '&amp;', $form_html);
 +
 +        // Display an error if the form markup couldn't be generated;
 +        // otherwise, render the HTML.
 +        if (Auth_OpenID::isFailure($form_html)) {
 +            common_server_error(sprintf(_('Could not create OpenID form: %s'), $form_html->message));
 +        } else {
 +            $action = new AutosubmitAction(); // see below
 +            $action->form_html = $form_html;
 +            $action->form_id = $form_id;
 +            $action->prepare(array('action' => 'autosubmit'));
 +            $action->handle(array('action' => 'autosubmit'));
 +        }
 +    }
 +}
 +
 +# Half-assed attempt at a module-private function
 +
 +function _oid_print_instructions()
 +{
 +    common_element('div', 'instructions',
 +                   _('This form should automatically submit itself. '.
 +                      'If not, click the submit button to go to your '.
 +                      'OpenID provider.'));
 +}
 +
 +# update a user from sreg parameters
 +
 +function oid_update_user(&$user, &$sreg)
 +{
 +
 +    $profile = $user->getProfile();
 +
 +    $orig_profile = clone($profile);
 +
 +    if ($sreg['fullname'] && strlen($sreg['fullname']) <= 255) {
 +        $profile->fullname = $sreg['fullname'];
 +    }
 +
 +    if ($sreg['country']) {
 +        if ($sreg['postcode']) {
 +            # XXX: use postcode to get city and region
 +            # XXX: also, store postcode somewhere -- it's valuable!
 +            $profile->location = $sreg['postcode'] . ', ' . $sreg['country'];
 +        } else {
 +            $profile->location = $sreg['country'];
 +        }
 +    }
 +
 +    # XXX save language if it's passed
 +    # XXX save timezone if it's passed
 +
 +    if (!$profile->update($orig_profile)) {
 +        common_server_error(_('Error saving the profile.'));
 +        return false;
 +    }
 +
 +    $orig_user = clone($user);
 +
 +    if ($sreg['email'] && Validate::email($sreg['email'], true)) {
 +        $user->email = $sreg['email'];
 +    }
 +
 +    if (!$user->update($orig_user)) {
 +        common_server_error(_('Error saving the user.'));
 +        return false;
 +    }
 +
 +    return true;
 +}
 +
 +class AutosubmitAction extends Action
 +{
 +    var $form_html = null;
 +    var $form_id = null;
 +
 +    function handle($args)
 +    {
 +        parent::handle($args);
 +        $this->showPage();
 +    }
 +
 +    function title()
 +    {
 +        return _('OpenID Auto-Submit');
 +    }
 +
 +    function showContent()
 +    {
 +        $this->raw($this->form_html);
 +        $this->element('script', null,
 +                       '$(document).ready(function() { ' .
 +                       '    $(\'#'. $this->form_id .'\').submit(); '.
 +                       '});');
 +    }
 +}
index 3d968c56e21404e622fa923fb781334f20097803,0000000000000000000000000000000000000000..07c82db3e1497f602d277160cc2e5549bcc40f78
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,131 @@@
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
 +<?php
 +/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
 + *
 + * 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/>.
 + */
 +
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 +
 +require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 +
 +class OpenidloginAction extends Action
 +{
 +    function handle($args)
 +    {
 +        parent::handle($args);
 +        if (common_is_real_login()) {
 +            $this->clientError(_('Already logged in.'));
 +        } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
 +            $openid_url = $this->trimmed('openid_url');
 +
 +            # CSRF protection
 +            $token = $this->trimmed('token');
 +            if (!$token || $token != common_session_token()) {
 +                $this->showForm(_('There was a problem with your session token. Try again, please.'), $openid_url);
 +                return;
 +            }
 +
 +            $rememberme = $this->boolean('rememberme');
 +
 +            common_ensure_session();
 +
 +            $_SESSION['openid_rememberme'] = $rememberme;
 +
 +            $result = oid_authenticate($openid_url,
 +                                       'finishopenidlogin');
 +
 +            if (is_string($result)) { # error message
 +                unset($_SESSION['openid_rememberme']);
 +                $this->showForm($result, $openid_url);
 +            }
 +        } else {
 +            $openid_url = oid_get_last();
 +            $this->showForm(null, $openid_url);
 +        }
 +    }
 +
 +    function getInstructions()
 +    {
 +        if (common_logged_in() && !common_is_real_login() &&
 +            common_get_returnto()) {
 +            // rememberme logins have to reauthenticate before
 +            // changing any profile settings (cookie-stealing protection)
 +            return _('For security reasons, please re-login with your ' .
 +                     '[OpenID](%%doc.openid%%) ' .
 +                     'before changing your settings.');
 +        } else {
 +            return _('Login with an [OpenID](%%doc.openid%%) account.');
 +        }
 +    }
 +
 +    function showPageNotice()
 +    {
 +        if ($this->error) {
 +            $this->element('div', array('class' => 'error'), $this->error);
 +        } else {
 +            $instr = $this->getInstructions();
 +            $output = common_markup_to_html($instr);
 +            $this->elementStart('div', 'instructions');
 +            $this->raw($output);
 +            $this->elementEnd('div');
 +        }
 +    }
 +
 +    function title()
 +    {
 +        return _('OpenID Login');
 +    }
 +
 +    function showForm($error=null, $openid_url)
 +    {
 +        $this->error = $error;
 +        $this->openid_url = $openid_url;
 +        $this->showPage();
 +    }
 +
 +    function showContent() {
 +        $formaction = common_local_url('openidlogin');
 +        $this->elementStart('form', array('method' => 'post',
 +                                           'id' => 'form_openid_login',
 +                                           'class' => 'form_settings',
 +                                           'action' => $formaction));
 +        $this->elementStart('fieldset');
 +        $this->element('legend', null, _('OpenID login'));
 +        $this->hidden('token', common_session_token());
 +
 +        $this->elementStart('ul', 'form_data');
 +        $this->elementStart('li');
 +        $this->input('openid_url', _('OpenID URL'),
 +                     $this->openid_url,
 +                     _('Your OpenID URL'));
 +        $this->elementEnd('li');
 +        $this->elementStart('li', array('id' => 'settings_rememberme'));
 +        $this->checkbox('rememberme', _('Remember me'), false,
 +                        _('Automatically login in the future; ' .
 +                           'not for shared computers!'));
 +        $this->elementEnd('li');
 +        $this->elementEnd('ul');
 +        $this->submit('submit', _('Login'));
 +        $this->elementEnd('fieldset');
 +        $this->elementEnd('form');
 +    }
 +
 +    function showLocalNav()
 +    {
 +        $nav = new LoginGroupNav($this);
 +        $nav->show();
 +    }
 +}
index 26bf6483660823175c87367fe44ad9d08aa0f16f,0000000000000000000000000000000000000000..104ea8d889d95d5ea5d13037762a6f46f25bb6ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
-  * Laconica, the distributed open-source microblogging tool
 +<?php
 +/**
-  * @package   Laconica
-  * @author    Evan Prodromou <evan@controlyourself.ca>
-  * @copyright 2008-2009 Control Yourself, Inc.
++ * StatusNet, the distributed open-source microblogging tool
 + *
 + * Settings for OpenID
 + *
 + * PHP version 5
 + *
 + * LICENCE: 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/>.
 + *
 + * @category  Settings
-  * @link      http://laconi.ca/
++ * @package   StatusNet
++ * @author    Evan Prodromou <evan@status.net>
++ * @copyright 2008-2009 StatusNet, Inc.
 + * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- if (!defined('LACONICA')) {
++ * @link      http://status.net/
 + */
 +
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
 +    exit(1);
 +}
 +
 +require_once INSTALLDIR.'/lib/accountsettingsaction.php';
 +require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 +
 +/**
 + * Settings for OpenID
 + *
 + * Lets users add, edit and delete OpenIDs from their account
 + *
 + * @category Settings
-  * @link     http://laconi.ca/
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link     http://status.net/
 + */
 +
 +class OpenidsettingsAction extends AccountSettingsAction
 +{
 +    /**
 +     * Title of the page
 +     *
 +     * @return string Page title
 +     */
 +
 +    function title()
 +    {
 +        return _('OpenID settings');
 +    }
 +
 +    /**
 +     * Instructions for use
 +     *
 +     * @return string Instructions for use
 +     */
 +
 +    function getInstructions()
 +    {
 +        return _('[OpenID](%%doc.openid%%) lets you log into many sites' .
 +                 ' with the same user account.'.
 +                 ' Manage your associated OpenIDs from here.');
 +    }
 +
 +    /**
 +     * Show the form for OpenID management
 +     *
 +     * We have one form with a few different submit buttons to do different things.
 +     *
 +     * @return void
 +     */
 +
 +    function showContent()
 +    {
 +        $user = common_current_user();
 +
 +        $this->elementStart('form', array('method' => 'post',
 +                                          'id' => 'form_settings_openid_add',
 +                                          'class' => 'form_settings',
 +                                          'action' =>
 +                                          common_local_url('openidsettings')));
 +        $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
 +        $this->element('legend', null, _('Add OpenID'));
 +        $this->hidden('token', common_session_token());
 +        $this->element('p', 'form_guide',
 +                       _('If you want to add an OpenID to your account, ' .
 +                         'enter it in the box below and click "Add".'));
 +        $this->elementStart('ul', 'form_data');
 +        $this->elementStart('li');
 +        $this->element('label', array('for' => 'openid_url'),
 +                       _('OpenID URL'));
 +        $this->element('input', array('name' => 'openid_url',
 +                                      'type' => 'text',
 +                                      'id' => 'openid_url'));
 +        $this->elementEnd('li');
 +        $this->elementEnd('ul');
 +        $this->element('input', array('type' => 'submit',
 +                                      'id' => 'settings_openid_add_action-submit',
 +                                      'name' => 'add',
 +                                      'class' => 'submit',
 +                                      'value' => _('Add')));
 +        $this->elementEnd('fieldset');
 +        $this->elementEnd('form');
 +
 +        $oid = new User_openid();
 +
 +        $oid->user_id = $user->id;
 +
 +        $cnt = $oid->find();
 +
 +        if ($cnt > 0) {
 +
 +            $this->element('h2', null, _('Remove OpenID'));
 +
 +            if ($cnt == 1 && !$user->password) {
 +
 +                $this->element('p', 'form_guide',
 +                               _('Removing your only OpenID '.
 +                                 'would make it impossible to log in! ' .
 +                                 'If you need to remove it, '.
 +                                 'add another OpenID first.'));
 +
 +                if ($oid->fetch()) {
 +                    $this->elementStart('p');
 +                    $this->element('a', array('href' => $oid->canonical),
 +                                   $oid->display);
 +                    $this->elementEnd('p');
 +                }
 +
 +            } else {
 +
 +                $this->element('p', 'form_guide',
 +                               _('You can remove an OpenID from your account '.
 +                                 'by clicking the button marked "Remove".'));
 +                $idx = 0;
 +
 +                while ($oid->fetch()) {
 +                    $this->elementStart('form',
 +                                        array('method' => 'POST',
 +                                              'id' => 'form_settings_openid_delete' . $idx,
 +                                              'class' => 'form_settings',
 +                                              'action' =>
 +                                              common_local_url('openidsettings')));
 +                    $this->elementStart('fieldset');
 +                    $this->hidden('token', common_session_token());
 +                    $this->element('a', array('href' => $oid->canonical),
 +                                   $oid->display);
 +                    $this->element('input', array('type' => 'hidden',
 +                                                  'id' => 'openid_url'.$idx,
 +                                                  'name' => 'openid_url',
 +                                                  'value' => $oid->canonical));
 +                    $this->element('input', array('type' => 'submit',
 +                                                  'id' => 'remove'.$idx,
 +                                                  'name' => 'remove',
 +                                                  'class' => 'submit remove',
 +                                                  'value' => _('Remove')));
 +                    $this->elementEnd('fieldset');
 +                    $this->elementEnd('form');
 +                    $idx++;
 +                }
 +            }
 +        }
 +    }
 +
 +    /**
 +     * Handle a POST request
 +     *
 +     * Muxes to different sub-functions based on which button was pushed
 +     *
 +     * @return void
 +     */
 +
 +    function handlePost()
 +    {
 +        // CSRF protection
 +        $token = $this->trimmed('token');
 +        if (!$token || $token != common_session_token()) {
 +            $this->showForm(_('There was a problem with your session token. '.
 +                              'Try again, please.'));
 +            return;
 +        }
 +
 +        if ($this->arg('add')) {
 +            $result = oid_authenticate($this->trimmed('openid_url'),
 +                                       'finishaddopenid');
 +            if (is_string($result)) { // error message
 +                $this->showForm($result);
 +            }
 +        } else if ($this->arg('remove')) {
 +            $this->removeOpenid();
 +        } else {
 +            $this->showForm(_('Something weird happened.'));
 +        }
 +    }
 +
 +    /**
 +     * Handles a request to remove an OpenID from the user's account
 +     *
 +     * Validates input and, if everything is OK, deletes the OpenID.
 +     * Reloads the form with a success or error notification.
 +     *
 +     * @return void
 +     */
 +
 +    function removeOpenid()
 +    {
 +        $openid_url = $this->trimmed('openid_url');
 +
 +        $oid = User_openid::staticGet('canonical', $openid_url);
 +
 +        if (!$oid) {
 +            $this->showForm(_('No such OpenID.'));
 +            return;
 +        }
 +        $cur = common_current_user();
 +        if (!$cur || $oid->user_id != $cur->id) {
 +            $this->showForm(_('That OpenID does not belong to you.'));
 +            return;
 +        }
 +        $oid->delete();
 +        $this->showForm(_('OpenID removed.'), true);
 +        return;
 +    }
 +}
index f088c25d127b3f087b37f29beb279ae5373f0a73,0000000000000000000000000000000000000000..1b2b359caa43cf0a15d9adc689dd9ab381928bbd
mode 100644,000000..100644
--- /dev/null
@@@ -1,122 -1,0 +1,122 @@@
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
 +<?php
 +
 +/**
 + * Public XRDS for OpenID
 + *
 + * PHP version 5
 + *
 + * @category Action
-  * @link     http://laconi.ca/
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
-  * Laconica - a distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, Control Yourself, Inc.
++ * @link     http://status.net/
 + *
- if (!defined('LACONICA')) {
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
 + *
 + * 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/>.
 + */
 +
-  * @package  Laconica
-  * @author   Evan Prodromou <evan@controlyourself.ca>
-  * @author   Robin Millette <millette@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
 +    exit(1);
 +}
 +
 +require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 +
 +/**
 + * Public XRDS for OpenID
 + *
 + * @category Action
-  * @link     http://laconi.ca/
++ * @package  StatusNet
++ * @author   Evan Prodromou <evan@status.net>
++ * @author   Robin Millette <millette@status.net>
 + * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
++ * @link     http://status.net/
 + *
 + * @todo factor out similarities with XrdsAction
 + */
 +class PublicxrdsAction extends Action
 +{
 +    /**
 +     * Is read only?
 +     *
 +     * @return boolean true
 +     */
 +    function isReadOnly($args)
 +    {
 +        return true;
 +    }
 +
 +    /**
 +     * Class handler.
 +     *
 +     * @param array $args array of arguments
 +     *
 +     * @return nothing
 +     */
 +    function handle($args)
 +    {
 +        parent::handle($args);
 +        header('Content-Type: application/xrds+xml');
 +        $this->startXML();
 +        $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
 +        $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
 +                                          'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
 +                                          'version' => '2.0'));
 +        $this->element('Type', null, 'xri://$xrds*simple');
 +        foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
 +            $this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
 +                                common_local_url($finish));
 +        }
 +        $this->elementEnd('XRD');
 +        $this->elementEnd('XRDS');
 +        $this->endXML();
 +    }
 +
 +    /**
 +     * Show service.
 +     *
 +     * @param string $type    XRDS type
 +     * @param string $uri     URI
 +     * @param array  $params  type parameters, null by default
 +     * @param array  $sigs    type signatures, null by default
 +     * @param string $localId local ID, null by default
 +     *
 +     * @return void
 +     */
 +    function showService($type, $uri, $params=null, $sigs=null, $localId=null)
 +    {
 +        $this->elementStart('Service');
 +        if ($uri) {
 +            $this->element('URI', null, $uri);
 +        }
 +        $this->element('Type', null, $type);
 +        if ($params) {
 +            foreach ($params as $param) {
 +                $this->element('Type', null, $param);
 +            }
 +        }
 +        if ($sigs) {
 +            foreach ($sigs as $sig) {
 +                $this->element('Type', null, $sig);
 +            }
 +        }
 +        if ($localId) {
 +            $this->element('LocalID', null, $localId);
 +        }
 +        $this->elementEnd('Service');
 +    }
 +}
 +
Simple merge
Simple merge
Simple merge