Merge remote branch 'gitorious/1.0.x' into 1.0.x

This commit is contained in:
Evan Prodromou 2010-08-03 16:04:54 -07:00
commit 004e42e3e0
326 changed files with 31953 additions and 19653 deletions

62
README
View File

@ -2,8 +2,8 @@
README
------
StatusNet 0.9.1 ("Everybody Hurts")
28 Mar 2010
StatusNet 0.9.2 ("King of Birds")
3 May 2010
This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of
@ -77,7 +77,7 @@ for additional terms.
New this version
================
This is a minor bug and feature release since version 0.9.0 released 4
This is a minor bug and feature release since version 0.9.1 released 28
March 2010.
Because of fixes to OStatus bugs, it is highly recommended that all
@ -85,26 +85,32 @@ public sites upgrade to the new version immediately.
Notable changes this version:
- Twitter bridge truncates and links back to original for long
notices.
- Changed "Home" link in main menu to "Personal".
- A new memcached plugin (using pecl/memcached versus pecl/memcache)
- Opt-in subscription to update@status.net
- Script to run commands on behalf of a user.
- Better Web UI for long notices.
- A plugin to open external links in their own window or tab
- Fixes to Salmon protocol for compatibility with other systems.
- Updates to latest ActivityStreams definition.
- Twitpic-compatible API for image upload.
- Background deletion of user accounts.
- Better support for HTTP basic authentication with CGI/FastCGI
- Better discovery on OStatus
- Support for PuSH-enabled RSS 2.0 feeds
- OpenID-only mode
- OpenID blacklist/whitelist
- OStatus unit tests
- Installer no longer fails with a PHP fatal error when trying to set up the
subscription to update@status.net
- Fixed email notifications for @-replies that come in via OStatus
- OStatus related Fixes to the cloudy theme
- Pass geo locations over Twitter bridge (will only be used if enabled on the
Twitter side)
- scripts/showplugins.php - script to dump the list of activated plugins and
their settings
- scripts/fixup_blocks.php - script to finds any stray subscriptions in
violation of blocks, and removes them
- Allow blocking someone who's not currently subscribed to you (prevents
seeing @-replies from them, or them subbing to you in future)
- Default 2-second timeout on Geonames web service lookups
- Improved localization for plugins
- New anti-spam measures: added nofollow rels to group members list,
subscribers list
- Shared cache key option for Geonames plugin (lets multi-instance sites
share their cached geoname lookups)
- Stability fixes to the TwitterStatusFetcher
- If user allows location sharing but turned off browser location use profile
location
- Improved group listing via the API
- Improved FOAF output
- Several other bugfixes
A full changelog is available at http://status.net/wiki/StatusNet_0.9.1.
A full changelog is available at http://status.net/wiki/StatusNet_0.9.2.
Prerequisites
=============
@ -216,9 +222,9 @@ especially if you've previously installed PHP/MySQL packages.
1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work:
tar zxf statusnet-0.9.1.tar.gz
tar zxf statusnet-0.9.2.tar.gz
...which will make a statusnet-0.9.1 subdirectory in your current
...which will make a statusnet-0.9.2 subdirectory in your current
directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the
files to the server.)
@ -226,7 +232,7 @@ especially if you've previously installed PHP/MySQL packages.
2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work:
mv statusnet-0.9.1 /var/www/statusnet
mv statusnet-0.9.2 /var/www/statusnet
This will make your StatusNet instance available in the statusnet path of
your server, like "http://example.net/statusnet". "microblog" or
@ -641,7 +647,7 @@ with this situation.
If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've
been tracking the "git" version of the software, you will probably
want to upgrade and keep your existing data. There is no automated
upgrade procedure in StatusNet 0.9.1. Try these step-by-step
upgrade procedure in StatusNet 0.9.2. Try these step-by-step
instructions; read to the end first before trying them.
0. Download StatusNet and set up all the prerequisites as if you were
@ -662,7 +668,7 @@ instructions; read to the end first before trying them.
5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database.
6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
7. Unpack your StatusNet 0.9.1 tarball and move it to "statusnet" or
7. Unpack your StatusNet 0.9.2 tarball and move it to "statusnet" or
wherever your code used to be.
8. Copy the config.php file and avatar directory from your old
directory to your new directory.
@ -1539,7 +1545,7 @@ repository (see below), and you get a compilation error ("unexpected
T_STRING") in the browser, check to see that you don't have any
conflicts in your code.
If you upgraded to StatusNet 0.9.1 without reading the "Notice
If you upgraded to StatusNet 0.9.2 without reading the "Notice
inboxes" section above, and all your users' 'Personal' tabs are empty,
read the "Notice inboxes" section above.

View File

@ -18,15 +18,19 @@
*
* @category Actions
* @package Actions
* @author Evan Prodromou <evan@status.net>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Adrian Lang <mail@adrianlang.de>
* @author Meitar Moscovitz <meitarm@gmail.com>
* @author Sarven Capadisli <csarven@status.net>
* @author Brenda Wallace <shiny@cpan.org>
* @author Brion Vibber <brion@pobox.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@controlyourself.ca>
* @author Meitar Moscovitz <meitarm@gmail.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
* @author Zach Copley <zach@status.net>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @link http://status.net
*/

View File

@ -21,8 +21,10 @@
*
* @category API
* @package StatusNet
* @author Brion Vibber <brion@pobox.com>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0

View File

@ -21,6 +21,7 @@
*
* @category API
* @package StatusNet
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0

View File

@ -75,7 +75,7 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');

View File

@ -232,7 +232,8 @@ class ApiDirectMessageAction extends ApiAuthAction
function showXmlDirectMessages()
{
$this->initDocument('xml');
$this->elementStart('direct-messages', array('type' => 'array'));
$this->elementStart('direct-messages', array('type' => 'array',
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
foreach ($this->messages as $m) {
$dm_array = $this->directMessageArray($m);

View File

@ -52,7 +52,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
class ApiDirectMessageNewAction extends ApiAuthAction
{
var $source = null;
var $other = null;
var $content = null;
@ -76,13 +75,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction
return;
}
$this->source = $this->trimmed('source'); // Not supported by Twitter.
$reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
if (empty($this->source) || in_array($this->source, $reserved_sources)) {
$source = 'api';
}
$this->content = $this->trimmed('text');
$this->user = $this->auth_user;

View File

@ -25,6 +25,7 @@
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -25,6 +25,7 @@
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -0,0 +1,367 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update a group's profile
*
* 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 API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* API analog to the group edit page
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@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 ApiGroupProfileUpdateAction extends ApiAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->nickname = common_canonical_nickname($this->trimmed('nickname'));
$this->fullname = $this->trimmed('fullname');
$this->homepage = $this->trimmed('homepage');
$this->description = $this->trimmed('description');
$this->location = $this->trimmed('location');
$this->aliasstring = $this->trimmed('aliases');
$this->user = $this->auth_user;
$this->group = $this->getTargetGroup($this->arg('id'));
return true;
}
/**
* Handle the request
*
* See which request params have been set, and update the profile
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if (empty($this->group)) {
$this->clientError(_('Group not found.'), 404, $this->format);
return false;
}
if (!$this->user->isAdmin($this->group)) {
$this->clientError(_('You must be an admin to edit the group.'), 403);
return false;
}
$this->group->query('BEGIN');
$orig = clone($this->group);
try {
if (!empty($this->nickname)) {
if ($this->validateNickname()) {
$this->group->nickname = $this->nickname;
$this->group->mainpage = common_local_url(
'showgroup',
array('nickname' => $this->nickname)
);
}
}
if (!empty($this->fullname)) {
$this->validateFullname();
$this->group->fullname = $this->fullname;
}
if (!empty($this->homepage)) {
$this->validateHomepage();
$this->group->homepage = $this->hompage;
}
if (!empty($this->description)) {
$this->validateDescription();
$this->group->description = $this->decription;
}
if (!empty($this->location)) {
$this->validateLocation();
$this->group->location = $this->location;
}
} catch (ApiValidationException $ave) {
$this->clientError(
$ave->getMessage(),
403,
$this->format
);
return;
}
$result = $this->group->update($orig);
if (!$result) {
common_log_db_error($this->group, 'UPDATE', __FILE__);
$this->serverError(_('Could not update group.'));
}
$aliases = array();
try {
if (!empty($this->aliasstring)) {
$aliases = $this->validateAliases();
}
} catch (ApiValidationException $ave) {
$this->clientError(
$ave->getMessage(),
403,
$this->format
);
return;
}
$result = $this->group->setAliases($aliases);
if (!$result) {
$this->serverError(_('Could not create aliases.'));
}
if (!empty($this->nickname) && ($this->nickname != $orig->nickname)) {
common_log(LOG_INFO, "Saving local group info.");
$local = Local_group::staticGet('group_id', $this->group->id);
$local->setNickname($this->nickname);
}
$this->group->query('COMMIT');
switch($this->format) {
case 'xml':
$this->showSingleXmlGroup($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
break;
default:
$this->clientError(_('API method not found.'), 404, $this->format);
break;
}
}
function nicknameExists($nickname)
{
$group = Local_group::staticGet('nickname', $nickname);
if (!empty($group) &&
$group->group_id != $this->group->id) {
return true;
}
$alias = Group_alias::staticGet('alias', $nickname);
if (!empty($alias) &&
$alias->group_id != $this->group->id) {
return true;
}
return false;
}
function validateNickname()
{
if (!Validate::string(
$this->nickname, array(
'min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT
)
)
) {
throw new ApiValidationException(
_(
'Nickname must have only lowercase letters ' .
'and numbers and no spaces.'
)
);
} else if ($this->nicknameExists($this->nickname)) {
throw new ApiValidationException(
_('Nickname already in use. Try another one.')
);
} else if (!User_group::allowedNickname($this->nickname)) {
throw new ApiValidationException(
_('Not a valid nickname.')
);
}
return true;
}
function validateHomepage()
{
if (!is_null($this->homepage)
&& (strlen($this->homepage) > 0)
&& !Validate::uri(
$this->homepage,
array('allowed_schemes' => array('http', 'https')
)
)
) {
throw new ApiValidationException(
_('Homepage is not a valid URL.')
);
}
}
function validateFullname()
{
if (!is_null($this->fullname) && mb_strlen($this->fullname) > 255) {
throw new ApiValidationException(
_('Full name is too long (max 255 chars).')
);
}
}
function validateDescription()
{
if (User_group::descriptionTooLong($this->description)) {
throw new ApiValidationException(
sprintf(
_('description is too long (max %d chars).'),
User_group::maxDescription()
)
);
}
}
function validateLocation()
{
if (!is_null($this->location) && mb_strlen($this->location) > 255) {
throw new ApiValidationException(
_('Location is too long (max 255 chars).')
);
}
}
function validateAliases()
{
$aliases = array_map(
'common_canonical_nickname',
array_unique(
preg_split('/[\s,]+/',
$this->aliasstring
)
)
);
if (count($aliases) > common_config('group', 'maxaliases')) {
throw new ApiValidationException(
sprintf(
_('Too many aliases! Maximum %d.'),
common_config('group', 'maxaliases')
)
);
}
foreach ($aliases as $alias) {
if (!Validate::string(
$alias, array(
'min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT)
)
) {
throw new ApiValidationException(
sprintf(
_('Invalid alias: "%s"'),
$alias
)
);
}
if ($this->nicknameExists($alias)) {
throw new ApiValidationException(
sprintf(
_('Alias "%s" already in use. Try another one.'),
$alias)
);
}
// XXX assumes alphanum nicknames
if (strcmp($alias, $this->nickname) == 0) {
throw new ApiValidationException(
_('Alias can\'t be the same as nickname.')
);
}
}
return $aliases;
}
}

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -31,6 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Action for outputting search results in Twitter compatible Atom
* format.
@ -44,10 +46,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
* @see ApiAction
* @see ApiPrivateAuthAction
*/
class TwitapisearchatomAction extends ApiAction
class ApiSearchAtomAction extends ApiPrivateAuthAction
{
var $cnt;
@ -96,8 +98,11 @@ class TwitapisearchatomAction extends ApiAction
function prepare($args)
{
common_debug("in apisearchatom prepare()");
parent::prepare($args);
$this->query = $this->trimmed('q');
$this->lang = $this->trimmed('lang');
$this->rpp = $this->trimmed('rpp');
@ -138,6 +143,7 @@ class TwitapisearchatomAction extends ApiAction
function handle($args)
{
parent::handle($args);
common_debug("In apisearchatom handle()");
$this->showAtom();
}
@ -342,10 +348,24 @@ class TwitapisearchatomAction extends ApiAction
'rel' => 'related',
'href' => $profile->avatarUrl()));
// TODO: Here is where we'd put in a link to an atom feed for threads
// @todo: Here is where we'd put in a link to an atom feed for threads
$this->element("twitter:source", null,
htmlentities($this->sourceLink($notice->source)));
$source = null;
$ns = $notice->getSource();
if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
} else {
$source = $ns->code;
}
}
$this->element("twitter:source", null, $source);
$this->elementStart('author');

View File

@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -31,6 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
/**
@ -44,7 +45,7 @@ require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
* @see ApiAction
*/
class TwitapisearchjsonAction extends ApiAction
class ApiSearchJSONAction extends ApiPrivateAuthAction
{
var $query;
var $lang;
@ -64,6 +65,8 @@ class TwitapisearchjsonAction extends ApiAction
function prepare($args)
{
common_debug("apisearchjson prepare()");
parent::prepare($args);
$this->query = $this->trimmed('q');

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -57,7 +58,7 @@ require_once INSTALLDIR . '/lib/apiauth.php';
class ApiStatusesDestroyAction extends ApiAuthAction
{
var $status = null;
var $status = null;
/**
* Take arguments for running
@ -99,39 +100,43 @@ class ApiStatusesDestroyAction extends ApiAuthAction
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found.'), $code = 404);
return;
$this->clientError(
_('API method not found.'),
404
);
return;
}
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
$this->clientError(_('This method requires a POST or DELETE.'),
400, $this->format);
return;
}
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
$this->clientError(
_('This method requires a POST or DELETE.'),
400,
$this->format
);
return;
}
if (empty($this->notice)) {
$this->clientError(_('No status found with that ID.'),
404, $this->format);
return;
}
if (empty($this->notice)) {
$this->clientError(
_('No status found with that ID.'),
404, $this->format
);
return;
}
if ($this->user->id == $this->notice->profile_id) {
$replies = new Reply;
$replies->get('notice_id', $this->notice_id);
$replies->delete();
$this->notice->delete();
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
} else {
$this->clientError(_('You may not delete another user\'s status.'),
403, $this->format);
}
$this->showNotice();
if ($this->user->id == $this->notice->profile_id) {
$replies = new Reply;
$replies->get('notice_id', $this->notice_id);
$replies->delete();
$this->notice->delete();
$this->showNotice();
} else {
$this->clientError(
_('You may not delete another user\'s status.'),
403,
$this->format
);
}
}
/**

View File

@ -79,7 +79,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
$this->user = $this->auth_user;
if ($this->user->id == $notice->profile_id) {
if ($this->user->id == $this->original->profile_id) {
$this->clientError(_('Cannot repeat your own notice.'),
400, $this->format);
return false;

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -29,10 +29,102 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how this method works. */
/*! @page statusesupdate statuses/update
@section Description
Updates the authenticating user's status. Requires the status parameter specified below.
Request must be a POST.
@par URL pattern
/api/statuses/update.:format
@par Formats (:format)
xml, json
@par HTTP Method(s)
POST
@par Requires Authentication
Yes
@param status (Required) The URL-encoded text of the status update.
@param source (Optional) The source of the status.
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
@param lat (Optional) The latitude the status refers to.
@param long (Optional) The longitude the status refers to.
@param media (Optional) a media upload, such as an image or movie file.
@sa @ref authentication
@sa @ref apiroot
@subsection usagenotes Usage notes
@li The URL pattern is relative to the @ref apiroot.
@li If the @e source parameter is not supplied the source of the status will default to 'api'.
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
to encode the latitude and longitude (see example response below <georss:point>).
@li Data uploaded via the @e media parameter should be multipart/form-data encoded.
@subsection exampleusage Example usage
@verbatim
curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
@endverbatim
@subsection exampleresponse Example response
@verbatim
<?xml version="1.0" encoding="UTF-8"?>
<status>
<text>Howdy!</text>
<truncated>false</truncated>
<created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
<in_reply_to_status_id/>
<source>api</source>
<id>26668724</id>
<in_reply_to_user_id/>
<in_reply_to_screen_name/>
<geo xmlns:georss="http://www.georss.org/georss">
<georss:point>30.468 -94.743</georss:point>
</geo>
<favorited>false</favorited>
<user>
<id>25803</id>
<name>Jed Sanders</name>
<screen_name>jedsanders</screen_name>
<location>Hoop and Holler, Texas</location>
<description>I like to think of myself as America's Favorite.</description>
<profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
<url>http://jedsanders.net</url>
<protected>false</protected>
<followers_count>5</followers_count>
<profile_background_color/>
<profile_text_color/>
<profile_link_color/>
<profile_sidebar_fill_color/>
<profile_sidebar_border_color/>
<friends_count>2</friends_count>
<created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
<favourites_count>0</favourites_count>
<utc_offset>0</utc_offset>
<time_zone>UTC</time_zone>
<profile_background_image_url/>
<profile_background_tile>false</profile_background_tile>
<statuses_count>70</statuses_count>
<following>true</following>
<notifications>true</notifications>
</user>
</status>
@endverbatim
*/
if (!defined('STATUSNET')) {
exit(1);
}
@ -64,8 +156,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
var $lat = null;
var $lon = null;
static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
/**
* Take arguments for running
*
@ -80,19 +170,9 @@ class ApiStatusesUpdateAction extends ApiAuthAction
parent::prepare($args);
$this->status = $this->trimmed('status');
$this->source = $this->trimmed('source');
$this->lat = $this->trimmed('lat');
$this->lon = $this->trimmed('long');
// try to set the source attr from OAuth app
if (empty($this->source)) {
$this->source = $this->oauth_source;
}
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
$this->source = 'api';
}
$this->in_reply_to_status_id
= intval($this->trimmed('in_reply_to_status_id'));

View File

@ -206,7 +206,8 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
{
switch ($this->format) {
case 'xml':
$this->elementStart('users', array('type' => 'array'));
$this->elementStart('users', array('type' => 'array',
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
foreach ($this->profiles as $profile) {
$this->showProfile(
$profile,

View File

@ -25,6 +25,7 @@
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -150,7 +151,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);
@ -185,17 +186,23 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
{
$notices = array();
common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
$notice = $this->user->favoriteNotices(
true,
($this->page-1) * $this->count,
$this->count,
true
$this->since_id,
$this->max_id
);
} else {
$notice = $this->user->favoriteNotices(
false,
($this->page-1) * $this->count,
$this->count,
false
$this->since_id,
$this->max_id
);
}

View File

@ -28,11 +28,107 @@
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how this method works. */
/*! @page friendstimeline statuses/friends_timeline
@section Description
Returns the 20 most recent statuses posted by the authenticating
user and that user's friends. This is the equivalent of "You and
friends" page in the web interface.
@par URL patterns
@li /api/statuses/friends_timeline.:format
@li /api/statuses/friends_timeline/:id.:format
@par Formats (:format)
xml, json, rss, atom
@par ID (:id)
username, user id
@par HTTP Method(s)
GET
@par Requires Authentication
Sometimes (see: @ref authentication)
@param user_id (Optional) Specifies a user by ID
@param screen_name (Optional) Specifies a user by screename (nickname)
@param since_id (Optional) Returns only statuses with an ID greater
than (that is, more recent than) the specified ID.
@param max_id (Optional) Returns only statuses with an ID less than
(that is, older than) or equal to the specified ID.
@param count (Optional) Specifies the number of statuses to retrieve.
@param page (Optional) Specifies the page of results to retrieve.
@sa @ref authentication
@sa @ref apiroot
@subsection usagenotes Usage notes
@li The URL pattern is relative to the @ref apiroot.
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
to encode the latitude and longitude (see example response below <georss:point>).
@subsection exampleusage Example usage
@verbatim
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
@endverbatim
@subsection exampleresponse Example response
@verbatim
<?xml version="1.0"?>
<statuses type="array">
<status>
<text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
<truncated>false</truncated>
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
<in_reply_to_status_id/>
<source>&lt;a href="http://code.google.com/p/microblog-purple/"&gt;mbpidgin&lt;/a&gt;</source>
<id>26674201</id>
<in_reply_to_user_id/>
<in_reply_to_screen_name/>
<geo/>
<favorited>false</favorited>
<user>
<id>246</id>
<name>Mark</name>
<screen_name>lambic</screen_name>
<location>Montreal, Canada</location>
<description>Geek</description>
<profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
<url>http://lambic.co.uk</url>
<protected>false</protected>
<followers_count>73</followers_count>
<profile_background_color>#F0F2F5</profile_background_color>
<profile_text_color/>
<profile_link_color>#002E6E</profile_link_color>
<profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
<profile_sidebar_border_color/>
<friends_count>58</friends_count>
<created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
<favourites_count>2</favourites_count>
<utc_offset>-14400</utc_offset>
<time_zone>US/Eastern</time_zone>
<profile_background_image_url/>
<profile_background_tile>false</profile_background_tile>
<statuses_count>933</statuses_count>
<following>false</following>
<notifications>false</notifications>
</user>
</status>
</statuses>
@endverbatim
*/
if (!defined('STATUSNET')) {
exit(1);
}
@ -153,7 +249,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -105,7 +106,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
function showTimeline()
{
// We'll pull common formatting out of this for other formats
$atom = new AtomGroupNoticeFeed($this->group);
$atom = new AtomGroupNoticeFeed($this->group, $this->auth_user);
$self = $this->getSelfUri();

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -152,7 +153,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -151,7 +152,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -55,6 +56,95 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how this method works. */
/*! @page publictimeline statuses/public_timeline
@section Description
Returns the 20 most recent notices from users throughout the system who have
uploaded their own avatars. Depending on configuration, it may or may not
not include notices from automatic posting services.
@par URL patterns
@li /api/statuses/public_timeline.:format
@par Formats (:format)
xml, json, rss, atom
@par HTTP Method(s)
GET
@par Requires Authentication
No
@param since_id (Optional) Returns only statuses with an ID greater
than (that is, more recent than) the specified ID.
@param max_id (Optional) Returns only statuses with an ID less than
(that is, older than) or equal to the specified ID.
@param count (Optional) Specifies the number of statuses to retrieve.
@param page (Optional) Specifies the page of results to retrieve.
@sa @ref apiroot
@subsection usagenotes Usage notes
@li The URL pattern is relative to the @ref apiroot.
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
to encode the latitude and longitude (see example response below <georss:point>).
@subsection exampleusage Example usage
@verbatim
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
@endverbatim
@subsection exampleresponse Example response
@verbatim
<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
<text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
<truncated>false</truncated>
<created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
<in_reply_to_status_id>28838393</in_reply_to_status_id>
<source>xmpp</source>
<id>28838456</id>
<in_reply_to_user_id>39303</in_reply_to_user_id>
<in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
<geo></geo>
<favorited>false</favorited>
<user>
<id>44517</id>
<name>joshua may</name>
<screen_name>notjosh</screen_name>
<location></location>
<description></description>
<profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
<url></url>
<protected>false</protected>
<followers_count>17</followers_count>
<profile_background_color></profile_background_color>
<profile_text_color></profile_text_color>
<profile_link_color></profile_link_color>
<profile_sidebar_fill_color></profile_sidebar_fill_color>
<profile_sidebar_border_color></profile_sidebar_border_color>
<friends_count>20</friends_count>
<created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
<favourites_count>0</favourites_count>
<utc_offset>0</utc_offset>
<time_zone>UTC</time_zone>
<profile_background_image_url></profile_background_image_url>
<profile_background_tile>false</profile_background_tile>
<statuses_count>100</statuses_count>
<following>false</following>
<notifications>false</notifications>
</user>
</status>
[....]
</statuses>
@endverbatim
*/
class ApiTimelinePublicAction extends ApiPrivateAuthAction
{
@ -130,7 +220,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -117,7 +117,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -26,6 +26,7 @@
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -138,7 +139,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);

View File

@ -29,6 +29,7 @@
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -115,7 +116,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
// We'll use the shared params from the Atom stub
// for other feed types.
$atom = new AtomUserNoticeFeed($this->user);
$atom = new AtomUserNoticeFeed($this->user, $this->auth_user);
$link = common_local_url(
'showstream',

View File

@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -31,6 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Returns the top ten queries that are currently trending
*
@ -43,7 +45,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @see ApiAction
*/
class TwitapitrendsAction extends ApiAction
class ApiTrendsAction extends ApiPrivateAuthAction
{
var $callback;
@ -82,7 +84,7 @@ class TwitapitrendsAction extends ApiAction
*/
function showTrends()
{
$this->serverError(_('API method under construction.'), $code = 501);
$this->serverError(_('API method under construction.'), 501);
}
}

View File

@ -113,7 +113,7 @@ class ApiUserShowAction extends ApiPrivateAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');

View File

@ -87,13 +87,15 @@ class BlockAction extends ProfileFormAction
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$this->returnToArgs();
$this->returnToPrevious();
} elseif ($this->arg('yes')) {
$this->handlePost();
$this->returnToArgs();
$this->returnToPrevious();
} else {
$this->showPage();
}
} else {
$this->showPage();
}
}
@ -118,6 +120,12 @@ class BlockAction extends ProfileFormAction
*/
function areYouSureForm()
{
// @fixme if we ajaxify the confirmation form, skip the preview on ajax hits
$profile = new ArrayWrapper(array($this->profile));
$preview = new ProfileList($profile, $this);
$preview->show();
$id = $this->profile->id;
$this->elementStart('form', array('id' => 'block-' . $id,
'method' => 'post',
@ -187,4 +195,38 @@ class BlockAction extends ProfileFormAction
$this->autofocus('form_action-yes');
}
/**
* Override for form session token checks; on our first hit we're just
* requesting confirmation, which doesn't need a token. We need to be
* able to take regular GET requests from email!
*
* @throws ClientException if token is bad on POST request or if we have
* confirmation parameters which could trigger something.
*/
function checkSessionToken()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST' ||
$this->arg('yes') ||
$this->arg('no')) {
return parent::checkSessionToken();
}
}
/**
* If we reached this form without returnto arguments, return to the
* current user's subscription list.
*
* @return string URL
*/
function defaultReturnTo()
{
$user = common_current_user();
if ($user) {
return common_local_url('subscribers',
array('nickname' => $user->nickname));
} else {
return common_local_url('public');
}
}
}

View File

@ -92,10 +92,10 @@ class DeleteuserAction extends ProfileFormAction
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$this->returnToArgs();
$this->returnToPrevious();
} elseif ($this->arg('yes')) {
$this->handlePost();
$this->returnToArgs();
$this->returnToPrevious();
} else {
$this->showPage();
}

View File

@ -126,9 +126,19 @@ class DesignadminpanelAction extends AdminPanelAction
return;
}
// check for an image upload
// check for file uploads
$bgimage = $this->saveBackgroundImage();
$customTheme = $this->saveCustomTheme();
$oldtheme = common_config('site', 'theme');
if ($customTheme) {
// This feels pretty hacky :D
$this->args['theme'] = $customTheme;
$themeChanged = true;
} else {
$themeChanged = ($this->trimmed('theme') != $oldtheme);
}
static $settings = array('theme', 'logo');
@ -140,15 +150,13 @@ class DesignadminpanelAction extends AdminPanelAction
$this->validate($values);
$oldtheme = common_config('site', 'theme');
$config = new Config();
$config->query('BEGIN');
// Only update colors if the theme has not changed.
if ($oldtheme == $values['theme']) {
if (!$themeChanged) {
$bgcolor = new WebColor($this->trimmed('design_background'));
$ccolor = new WebColor($this->trimmed('design_content'));
@ -190,6 +198,13 @@ class DesignadminpanelAction extends AdminPanelAction
Config::save('design', 'backgroundimage', $bgimage);
}
if (common_config('custom_css', 'enabled')) {
$css = $this->arg('css');
if ($css != common_config('custom_css', 'css')) {
Config::save('custom_css', 'css', $css);
}
}
$config->query('COMMIT');
}
@ -263,6 +278,33 @@ class DesignadminpanelAction extends AdminPanelAction
}
}
/**
* Save the custom theme if the user uploaded one.
*
* @return mixed custom theme name, if succesful, or null if no theme upload.
* @throws ClientException for invalid theme archives
* @throws ServerException if trouble saving the theme files
*/
function saveCustomTheme()
{
if (common_config('theme_upload', 'enabled') &&
$_FILES['design_upload_theme']['error'] == UPLOAD_ERR_OK) {
$upload = ThemeUploader::fromUpload('design_upload_theme');
$basedir = common_config('local', 'dir');
if (empty($basedir)) {
$basedir = INSTALLDIR . '/local';
}
$name = 'custom'; // @todo allow multiples, custom naming?
$outdir = $basedir . '/theme/' . $name;
$upload->extract($outdir);
return $name;
} else {
return null;
}
}
/**
* Attempt to validate setting values
*
@ -371,7 +413,15 @@ class DesignAdminPanelForm extends AdminForm
function formData()
{
$this->showLogo();
$this->showTheme();
$this->showBackground();
$this->showColors();
$this->showAdvanced();
}
function showLogo()
{
$this->out->elementStart('fieldset', array('id' => 'settings_design_logo'));
$this->out->element('legend', null, _('Change logo'));
@ -384,6 +434,11 @@ class DesignAdminPanelForm extends AdminForm
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
function showTheme()
{
$this->out->elementStart('fieldset', array('id' => 'settings_design_theme'));
$this->out->element('legend', null, _('Change theme'));
@ -407,10 +462,23 @@ class DesignAdminPanelForm extends AdminForm
false, $this->value('theme'));
$this->unli();
if (common_config('theme_upload', 'enabled')) {
$this->li();
$this->out->element('label', array('for' => 'design_upload_theme'), _('Custom theme'));
$this->out->element('input', array('id' => 'design_upload_theme',
'name' => 'design_upload_theme',
'type' => 'file'));
$this->out->element('p', 'form_guide', _('You can upload a custom StatusNet theme as a .ZIP archive.'));
$this->unli();
}
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
function showBackground()
{
$design = $this->out->design;
$this->out->elementStart('fieldset', array('id' =>
@ -486,6 +554,11 @@ class DesignAdminPanelForm extends AdminForm
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
function showColors()
{
$design = $this->out->design;
$this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
$this->out->element('legend', null, _('Change colours'));
@ -493,6 +566,7 @@ class DesignAdminPanelForm extends AdminForm
$this->out->elementStart('ul', 'form_data');
try {
// @fixme avoid loop unrolling in non-performance-critical contexts like this
$bgcolor = new WebColor($design->backgroundcolor);
@ -560,6 +634,7 @@ class DesignAdminPanelForm extends AdminForm
$this->unli();
} catch (WebColorException $e) {
// @fixme normalize them individually!
common_log(LOG_ERR, 'Bad color values in site design: ' .
$e->getMessage());
}
@ -569,6 +644,27 @@ class DesignAdminPanelForm extends AdminForm
$this->out->elementEnd('ul');
}
function showAdvanced()
{
if (common_config('custom_css', 'enabled')) {
$this->out->elementStart('fieldset', array('id' => 'settings_design_advanced'));
$this->out->element('legend', null, _('Advanced'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->out->element('label', array('for' => 'css'), _('Custom CSS'));
$this->out->element('textarea', array('name' => 'css',
'id' => 'css',
'cols' => '50',
'rows' => '10'),
strval(common_config('custom_css', 'css')));
$this->unli();
$this->out->elementEnd('fieldset');
$this->out->elementEnd('ul');
}
}
/**
* Action elements
*

View File

@ -89,7 +89,7 @@ class FavoritesrssAction extends Rss10Action
function getNotices($limit=0)
{
$user = $this->user;
$notice = $user->favoriteNotices(0, $limit);
$notice = $user->favoriteNotices(false, 0, $limit);
$notices = array();
while ($notice->fetch()) {
$notices[] = clone($notice);

View File

@ -95,7 +95,9 @@ class FoafAction extends Action
// Would be nice to tell if they were a Person or not (e.g. a #person usertag?)
$this->elementStart('Agent', array('rdf:about' =>
$this->user->uri));
$this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
if ($this->user->email) {
$this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
}
if ($this->profile->fullname) {
$this->element('name', null, $this->profile->fullname);
}
@ -152,7 +154,9 @@ class FoafAction extends Action
}
$person = $this->showMicrobloggingAccount($this->profile,
common_root_url(), $this->user->uri, false);
common_root_url(), $this->user->uri,
/*$fetchSubscriptions*/true,
/*$isSubscriber*/false);
// Get people who subscribe to user
@ -207,7 +211,8 @@ class FoafAction extends Action
$this->showMicrobloggingAccount($profile,
($local == 'local') ? common_root_url() : null,
$uri,
true);
/*$fetchSubscriptions*/false,
/*$isSubscriber*/($type == LISTENER || $type == BOTH));
if ($foaf_url) {
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
}
@ -232,7 +237,21 @@ class FoafAction extends Action
$this->elementEnd('PersonalProfileDocument');
}
function showMicrobloggingAccount($profile, $service=null, $useruri=null, $isSubscriber=false)
/**
* Output FOAF <account> bit for the given profile.
*
* @param Profile $profile
* @param mixed $service Root URL of this StatusNet instance for a local
* user, otherwise null.
* @param mixed $useruri URI string for the referenced profile..
* @param boolean $fetchSubscriptions Should we load and list all their subscriptions?
* @param boolean $isSubscriber if not fetching subs, we can still mark the user as following the current page.
*
* @return array if $fetchSubscribers is set, return a list of info on those
* subscriptions.
*/
function showMicrobloggingAccount($profile, $service=null, $useruri=null, $fetchSubscriptions=false, $isSubscriber=false)
{
$attr = array();
if ($useruri) {
@ -254,9 +273,7 @@ class FoafAction extends Action
$person = array();
if ($isSubscriber) {
$this->element('sioc:follows', array('rdf:resource'=>$this->user->uri . '#acct'));
} else {
if ($fetchSubscriptions) {
// Get people user is subscribed to
$sub = new Subscription();
$sub->subscriber = $profile->id;
@ -281,6 +298,9 @@ class FoafAction extends Action
}
unset($sub);
} else if ($isSubscriber) {
// Just declare that they follow the user whose FOAF we're showing.
$this->element('sioc:follows', array('rdf:resource' => $this->user->uri . '#acct'));
}
$this->elementEnd('OnlineAccount');

View File

@ -37,6 +37,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @category Action
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/

View File

@ -117,7 +117,7 @@ class GroupblockAction extends RedirectingAction
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$this->returnToArgs();
$this->returnToPrevious();
} elseif ($this->arg('yes')) {
$this->blockProfile();
} elseif ($this->arg('blockto')) {
@ -207,7 +207,7 @@ class GroupblockAction extends RedirectingAction
return false;
}
$this->returnToArgs();
$this->returnToPrevious();
}
/**

View File

@ -133,8 +133,7 @@ class ImsettingsAction extends ConnectSettingsAction
'message with further instructions. '.
'(Did you add %s to your buddy list?)'),
$transport_info['display'],
$transport_info['daemon_screenname'],
jabber_daemon_address()));
$transport_info['daemon_screenname']));
$this->hidden('screenname', $confirm->address);
// TRANS: Button label to cancel an IM address confirmation procedure.
$this->submit('cancel', _m('BUTTON','Cancel'));
@ -163,12 +162,11 @@ class ImsettingsAction extends ConnectSettingsAction
'action' =>
common_local_url('imsettings')));
$this->elementStart('fieldset', array('id' => 'settings_im_preferences'));
$this->element('legend', null, _('Preferences'));
// TRANS: Header for IM preferences form.
$this->element('legend', null, _('IM Preferences'));
$this->hidden('token', common_session_token());
$this->elementStart('table');
$this->elementStart('tr');
// TRANS: Header for IM preferences form.
$this->element('th', null, _('IM Preferences'));
foreach($user_im_prefs_by_transport as $transport=>$user_im_prefs)
{
$this->element('th', null, $transports[$transport]['display']);
@ -278,19 +276,20 @@ class ImsettingsAction extends ConnectSettingsAction
$user = common_current_user();
$user_im_prefs = new User_im_prefs();
$user_im_prefs->query('BEGIN');
$user_im_prefs->user_id = $user->id;
if($user_im_prefs->find() && $user_im_prefs->fetch())
{
$preferences = array('notify', 'updatefrompresence', 'replies', 'microid');
$user_im_prefs->query('BEGIN');
do
{
$original = clone($user_im_prefs);
$new = clone($user_im_prefs);
foreach($preferences as $preference)
{
$user_im_prefs->$preference = $this->boolean($user_im_prefs->transport . '_' . $preference);
$new->$preference = $this->boolean($new->transport . '_' . $preference);
}
$result = $user_im_prefs->update($original);
$result = $new->update($original);
if ($result === false) {
common_log_db_error($user, 'UPDATE', __FILE__);
@ -299,8 +298,8 @@ class ImsettingsAction extends ConnectSettingsAction
return;
}
}while($user_im_prefs->fetch());
$user_im_prefs->query('COMMIT');
}
$user_im_prefs->query('COMMIT');
// TRANS: Confirmation message for successful IM preferences save.
$this->showForm(_('Preferences saved.'), true);
}

View File

@ -62,6 +62,28 @@ class LoginAction extends Action
return false;
}
/**
* Prepare page to run
*
*
* @param $args
* @return string title
*/
function prepare($args)
{
parent::prepare($args);
// @todo this check should really be in index.php for all sensitive actions
$ssl = common_config('site', 'ssl');
if (empty($_SERVER['HTTPS']) && ($ssl == 'always' || $ssl == 'sometimes')) {
common_redirect(common_local_url('login'));
// exit
}
return true;
}
/**
* Handle input, produce output
*
@ -267,9 +289,13 @@ class LoginAction extends Action
'user name and password ' .
'before changing your settings.');
} else {
return _('Login with your username and password. ' .
'Don\'t have a username yet? ' .
'[Register](%%action.register%%) a new account.');
$prompt = _('Login with your username and password.');
if (!common_config('site', 'closed') && !common_config('site', 'inviteonly')) {
$prompt .= ' ';
$prompt .= _('Don\'t have a username yet? ' .
'[Register](%%action.register%%) a new account.');
}
return $prompt;
}
}

View File

@ -23,6 +23,7 @@
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2008 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -8,7 +8,9 @@
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Craig Andrews <candrews@integralblue.com>
* @author Robin Millette <millette@status.net>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
@ -44,6 +46,7 @@ require_once INSTALLDIR.'/lib/xrdsoutputter.php';
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*

View File

@ -74,6 +74,13 @@ class RegisterAction extends Action
parent::prepare($args);
$this->code = $this->trimmed('code');
// @todo this check should really be in index.php for all sensitive actions
$ssl = common_config('site', 'ssl');
if (empty($_SERVER['HTTPS']) && ($ssl == 'always' || $ssl == 'sometimes')) {
common_redirect(common_local_url('register'));
// exit
}
if (empty($this->code)) {
common_ensure_session();
if (array_key_exists('invitecode', $_SESSION)) {
@ -491,6 +498,45 @@ class RegisterAction extends Action
$this->elementStart('li');
$this->element('input', $attrs);
$this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
$this->raw($this->licenseCheckbox());
$this->elementEnd('label');
$this->elementEnd('li');
}
$this->elementEnd('ul');
$this->submit('submit', _('Register'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
function licenseCheckbox()
{
$out = '';
switch (common_config('license', 'type')) {
case 'private':
// TRANS: Copyright checkbox label in registration dialog, for private sites.
$out .= htmlspecialchars(sprintf(
_('I understand that content and data of %1$s are private and confidential.'),
common_config('site', 'name')));
// fall through
case 'allrightsreserved':
if ($out != '') {
$out .= ' ';
}
if (common_config('license', 'owner')) {
// TRANS: Copyright checkbox label in registration dialog, for all rights reserved with a specified copyright owner.
$out .= htmlspecialchars(sprintf(
_('My text and files are copyright by %1$s.'),
common_config('license', 'owner')));
} else {
// TRANS: Copyright checkbox label in registration dialog, for all rights reserved with ownership left to contributors.
$out .= htmlspecialchars(_('My text and files remain under my own copyright.'));
}
// TRANS: Copyright checkbox label in registration dialog, for all rights reserved.
$out .= ' ' . _('All rights reserved.');
break;
case 'cc': // fall through
default:
// TRANS: Copyright checkbox label in registration dialog, for Creative Commons-style licenses.
$message = _('My text and files are available under %s ' .
'except this private data: password, ' .
'email address, IM address, and phone number.');
@ -499,14 +545,9 @@ class RegisterAction extends Action
'">' .
htmlspecialchars(common_config('license', 'title')) .
'</a>';
$this->raw(sprintf(htmlspecialchars($message), $link));
$this->elementEnd('label');
$this->elementEnd('li');
$out .= sprintf(htmlspecialchars($message), $link);
}
$this->elementEnd('ul');
$this->submit('submit', _('Register'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
return $out;
}
/**

View File

@ -121,11 +121,11 @@ class ShowfavoritesAction extends OwnerDesignAction
// Show imported/gateway notices as well as local if
// the user is looking at his own favorites
$this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1, true);
$this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1);
} else {
$this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1, false);
$this->notice = $this->user->favoriteNotices(false, ($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1);
}
if (empty($this->notice)) {

View File

@ -430,14 +430,6 @@ class ShowgroupAction extends GroupDesignAction
function showStatistics()
{
// XXX: WORM cache this
$members = $this->group->getMembers();
$members_count = 0;
/** $member->count() doesn't work. */
while ($members->fetch()) {
$members_count++;
}
$this->elementStart('div', array('id' => 'entity_statistics',
'class' => 'section'));
@ -451,7 +443,7 @@ class ShowgroupAction extends GroupDesignAction
$this->elementStart('dl', 'entity_members');
$this->element('dt', null, _('Members'));
$this->element('dd', null, (is_int($members_count)) ? $members_count : '0');
$this->element('dd', null, $this->group->getMemberCount());
$this->elementEnd('dl');
$this->elementEnd('div');

View File

@ -185,7 +185,9 @@ class SubscriptionsListItem extends SubscriptionListItem
return;
}
if (!common_config('xmpp', 'enabled') && !common_config('sms', 'enabled')) {
$transports = array();
Event::handle('GetImTransports', array(&$transports));
if (!$transports && !common_config('sms', 'enabled')) {
return;
}
@ -195,7 +197,7 @@ class SubscriptionsListItem extends SubscriptionListItem
'action' => common_local_url('subedit')));
$this->out->hidden('token', common_session_token());
$this->out->hidden('profile', $this->profile->id);
if (common_config('xmpp', 'enabled')) {
if ($transports) {
$attrs = array('name' => 'jabber',
'type' => 'checkbox',
'class' => 'checkbox',
@ -205,7 +207,7 @@ class SubscriptionsListItem extends SubscriptionListItem
}
$this->out->element('input', $attrs);
$this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('Jabber'));
$this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('IM'));
} else {
$this->out->hidden('jabber', $sub->jabber);
}

View File

@ -41,6 +41,8 @@ if (!defined('STATUSNET')) {
* @category Info
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
* @link http://status.net/
*/

0
avatar/.gitignore vendored Normal file → Executable file
View File

View File

@ -75,13 +75,13 @@ class Fave extends Memcached_DataObject
return Memcached_DataObject::pkeyGet('Fave', $kv);
}
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false)
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
{
$ids = Notice::stream(array('Fave', '_streamDirect'),
array($user_id, $own),
($own) ? 'fave:ids_by_user_own:'.$user_id :
'fave:ids_by_user:'.$user_id,
$offset, $limit);
$offset, $limit, $since_id, $max_id);
return $ids;
}

View File

@ -116,7 +116,11 @@ class File extends Memcached_DataObject
return false;
}
function processNew($given_url, $notice_id=null) {
/**
* @fixme refactor this mess, it's gotten pretty scary.
* @param bool $followRedirects
*/
function processNew($given_url, $notice_id=null, $followRedirects=true) {
if (empty($given_url)) return -1; // error, no url to process
$given_url = File_redirection::_canonUrl($given_url);
if (empty($given_url)) return -1; // error, no url to process
@ -124,6 +128,10 @@ class File extends Memcached_DataObject
if (empty($file)) {
$file_redir = File_redirection::staticGet('url', $given_url);
if (empty($file_redir)) {
// @fixme for new URLs this also looks up non-redirect data
// such as target content type, size, etc, which we need
// for File::saveNew(); so we call it even if not following
// new redirects.
$redir_data = File_redirection::where($given_url);
if (is_array($redir_data)) {
$redir_url = $redir_data['url'];
@ -134,11 +142,19 @@ class File extends Memcached_DataObject
throw new ServerException("Can't process url '$given_url'");
}
// TODO: max field length
if ($redir_url === $given_url || strlen($redir_url) > 255) {
if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) {
$x = File::saveNew($redir_data, $given_url);
$file_id = $x->id;
} else {
$x = File::processNew($redir_url, $notice_id);
// This seems kind of messed up... for now skipping this part
// if we're already under a redirect, so we don't go into
// horrible infinite loops if we've been given an unstable
// redirect (where the final destination of the first request
// doesn't match what we get when we ask for it again).
//
// Seen in the wild with clojure.org, which redirects through
// wikispaces for auth and appends session data in the URL params.
$x = File::processNew($redir_url, $notice_id, /*followRedirects*/false);
$file_id = $x->id;
File_redirection::saveNew($redir_data, $file_id, $given_url);
}

View File

@ -115,9 +115,12 @@ class Inbox extends Memcached_DataObject
*/
static function insertNotice($user_id, $notice_id)
{
$inbox = DB_DataObject::staticGet('inbox', 'user_id', $user_id);
if (empty($inbox)) {
// Going straight to the DB rather than trusting our caching
// during an update. Note: not using DB_DataObject::staticGet,
// which is unsafe to use directly (in-process caching causes
// memory leaks, which accumulate in queue processes).
$inbox = new Inbox();
if (!$inbox->get('user_id', $user_id)) {
$inbox = Inbox::initialize($user_id);
}

View File

@ -128,12 +128,13 @@ class Memcached_DataObject extends Safe_DataObject
}
static function cacheKey($cls, $k, $v) {
if (is_object($cls) || is_object($k) || is_object($v)) {
if (is_object($cls) || is_object($k) || (is_object($v) && !($v instanceof DB_DataObject_Cast))) {
$e = new Exception();
common_log(LOG_ERR, __METHOD__ . ' object in param: ' .
str_replace("\n", " ", $e->getTraceAsString()));
}
return common_cache_key(strtolower($cls).':'.$k.':'.$v);
$vstr = self::valueString($v);
return common_cache_key(strtolower($cls).':'.$k.':'.$vstr);
}
static function getcached($cls, $k, $v) {
@ -229,10 +230,10 @@ class Memcached_DataObject extends Safe_DataObject
if (empty($this->$key)) {
continue;
}
$ckeys[] = $this->cacheKey($this->tableName(), $key, $this->$key);
$ckeys[] = $this->cacheKey($this->tableName(), $key, self::valueString($this->$key));
} else if ($type == 'K' || $type == 'N') {
$pkey[] = $key;
$pval[] = $this->$key;
$pval[] = self::valueString($this->$key);
} else {
throw new Exception("Unknown key type $key => $type for " . $this->tableName());
}
@ -351,7 +352,7 @@ class Memcached_DataObject extends Safe_DataObject
* low-level database function and add a comment to the
* query string. This should then be visible in process lists
* and slow query logs, to help identify problem areas.
*
*
* Also marks whether this was a web GET/POST or which daemon
* was running it.
*
@ -604,5 +605,30 @@ class Memcached_DataObject extends Safe_DataObject
return $c->set($cacheKey, $value);
}
static function valueString($v)
{
$vstr = null;
if (is_object($v) && $v instanceof DB_DataObject_Cast) {
switch ($v->type) {
case 'date':
$vstr = $v->year . '-' . $v->month . '-' . $v->day;
break;
case 'blob':
case 'string':
case 'sql':
case 'datetime':
case 'time':
throw new ServerException("Unhandled DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
break;
default:
throw new ServerException("Unknown DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
break;
}
} else {
$vstr = strval($v);
}
return $vstr;
}
}

View File

@ -29,6 +29,7 @@
* @author Robin Millette <millette@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license GNU Affero General Public License http://www.gnu.org/licenses/
*/
@ -97,15 +98,20 @@ class Notice extends Memcached_DataObject
// For auditing purposes, save a record that the notice
// was deleted.
$deleted = new Deleted_notice();
// @fixme we have some cases where things get re-run and so the
// insert fails.
$deleted = Deleted_notice::staticGet('id', $this->id);
if (!$deleted) {
$deleted = new Deleted_notice();
$deleted->id = $this->id;
$deleted->profile_id = $this->profile_id;
$deleted->uri = $this->uri;
$deleted->created = $this->created;
$deleted->deleted = common_sql_now();
$deleted->id = $this->id;
$deleted->profile_id = $this->profile_id;
$deleted->uri = $this->uri;
$deleted->created = $this->created;
$deleted->deleted = common_sql_now();
$deleted->insert();
$deleted->insert();
}
// Clear related records
@ -704,7 +710,7 @@ class Notice extends Memcached_DataObject
/**
* Is this notice part of an active conversation?
*
*
* @return boolean true if other messages exist in the same
* conversation, false if this is the only one
*/
@ -981,8 +987,7 @@ class Notice extends Memcached_DataObject
* messages, we won't deliver to any remote targets as that's the
* source service's responsibility.
*
* @fixme Unlike saveReplies() there's no mail notification here.
* Move that to distrib queue handler?
* Mail notifications etc will be handled later.
*
* @param array of unique identifier URIs for recipients
*/
@ -1008,8 +1013,6 @@ class Notice extends Memcached_DataObject
$reply->profile_id = $user->id;
$id = $reply->insert();
self::blow('reply:stream:%d', $user->id);
}
}
@ -1021,8 +1024,7 @@ class Notice extends Memcached_DataObject
* and save reply records indicating that this message needs to be
* delivered to those users.
*
* Side effect: local recipients get e-mail notifications here.
* @fixme move mail notifications to distrib?
* Mail notifications to local profiles will be sent later.
*
* @return array of integer profile IDs
*/
@ -1076,23 +1078,21 @@ class Notice extends Memcached_DataObject
throw new ServerException("Couldn't save reply for {$this->id}, {$mentioned->id}");
} else {
$replied[$mentioned->id] = 1;
self::blow('reply:stream:%d', $mentioned->id);
}
}
}
$recipientIds = array_keys($replied);
foreach ($recipientIds as $recipientId) {
$user = User::staticGet('id', $recipientId);
if (!empty($user)) {
self::blow('reply:stream:%d', $reply->profile_id);
mail_notify_attn($user, $this);
}
}
return $recipientIds;
}
/**
* Pull the complete list of @-reply targets for this notice.
*
* @return array of integer profile ids
*/
function getReplies()
{
// XXX: cache me
@ -1115,6 +1115,30 @@ class Notice extends Memcached_DataObject
return $ids;
}
/**
* Send e-mail notifications to local @-reply targets.
*
* Replies must already have been saved; this is expected to be run
* from the distrib queue handler.
*/
function sendReplyNotifications()
{
// Don't send reply notifications for repeats
if (!empty($this->repeat_of)) {
return array();
}
$recipientIds = $this->getReplies();
foreach ($recipientIds as $recipientId) {
$user = User::staticGet('id', $recipientId);
if (!empty($user)) {
mail_notify_attn($user, $this);
}
}
}
/**
* Pull list of groups this notice needs to be delivered to,
* as previously recorded by saveGroups() or saveKnownGroups().
@ -1154,7 +1178,7 @@ class Notice extends Memcached_DataObject
return $groups;
}
function asAtomEntry($namespace=false, $source=false, $author=true)
function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null)
{
$profile = $this->getProfile();
@ -1167,7 +1191,8 @@ class Notice extends Memcached_DataObject
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/',
'xmlns:media' => 'http://purl.org/syndication/atommedia',
'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0');
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
'xmlns:statusnet' => 'http://status.net/schema/api/1/');
} else {
$attrs = array();
}
@ -1202,7 +1227,7 @@ class Notice extends Memcached_DataObject
$xs->element('title', null, common_xml_safe_str($this->content));
if ($author) {
$xs->raw($profile->asAtomAuthor());
$xs->raw($profile->asAtomAuthor($cur));
$xs->raw($profile->asActivityActor());
}
@ -1215,6 +1240,46 @@ class Notice extends Memcached_DataObject
$xs->element('published', null, common_date_w3dtf($this->created));
$xs->element('updated', null, common_date_w3dtf($this->created));
$source = null;
$ns = $this->getSource();
if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
} else {
$source = $ns->code;
}
}
$noticeInfoAttr = array(
'local_id' => $this->id, // local notice ID (useful to clients for ordering)
'source' => $source, // the client name (source attribution)
);
$ns = $this->getSource();
if ($ns) {
if (!empty($ns->url)) {
$noticeInfoAttr['source_link'] = $ns->url;
}
}
if (!empty($cur)) {
$noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false";
$profile = $cur->getProfile();
$noticeInfoAttr['repeated'] = ($profile->hasRepeated($this->id)) ? "true" : "false";
}
if (!empty($this->repeat_of)) {
$noticeInfoAttr['repeat_of'] = $this->repeat_of;
}
$xs->element('statusnet:notice_info', $noticeInfoAttr, null);
if ($this->reply_to) {
$reply_notice = Notice::staticGet('id', $this->reply_to);
if (!empty($reply_notice)) {
@ -1781,4 +1846,53 @@ class Notice extends Memcached_DataObject
return $result;
}
/**
* Get the source of the notice
*
* @return Notice_source $ns A notice source object. 'code' is the only attribute
* guaranteed to be populated.
*/
function getSource()
{
$ns = new Notice_source();
if (!empty($this->source)) {
switch ($this->source) {
case 'web':
case 'xmpp':
case 'mail':
case 'omb':
case 'system':
case 'api':
$ns->code = $this->source;
break;
default:
$ns = Notice_source::staticGet($this->source);
if (!$ns) {
$ns = new Notice_source();
$ns->code = $this->source;
$app = Oauth_application::staticGet('name', $this->source);
if ($app) {
$ns->name = $app->name;
$ns->url = $app->source_url;
}
}
break;
}
}
return $ns;
}
/**
* Determine whether the notice was locally created
*
* @return boolean locality
*/
public function isLocal()
{
return ($this->is_local == Notice::LOCAL_PUBLIC ||
$this->is_local == Notice::LOCAL_NONPUBLIC);
}
}

View File

@ -849,15 +849,23 @@ class Profile extends Memcached_DataObject
*
* Assumes that Atom has been previously set up as the base namespace.
*
* @param Profile $cur the current authenticated user
*
* @return string
*/
function asAtomAuthor()
function asAtomAuthor($cur = null)
{
$xs = new XMLStringer(true);
$xs->elementStart('author');
$xs->element('name', null, $this->nickname);
$xs->element('uri', null, $this->getUri());
if ($cur != null) {
$attrs = Array();
$attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false';
$attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false';
$xs->element('statusnet:profile_info', $attrs, null);
}
$xs->elementEnd('author');
return $xs->getString();

View File

@ -64,4 +64,17 @@ class Queue_item extends Memcached_DataObject
$qi = null;
return null;
}
/**
* Release a claimed item.
*/
function releaseCLaim()
{
// DB_DataObject doesn't let us save nulls right now
$sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->id);
$this->query($sql);
$this->claimed = null;
$this->encache();
}
}

View File

@ -22,6 +22,20 @@ class Reply extends Memcached_DataObject
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
/**
* Wrapper for record insertion to update related caches
*/
function insert()
{
$result = parent::insert();
if ($result) {
self::blow('reply:stream:%d', $this->profile_id);
}
return $result;
}
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
{
$ids = Notice::stream(array('Reply', '_streamDirect'),

View File

@ -144,26 +144,49 @@ class Status_network extends Safe_DataObject
return parent::update($orig);
}
/**
* DB_DataObject doesn't allow updating keys (even non-primary)
*/
function updateKeys(&$orig)
{
$this->_connect();
foreach (array('hostname', 'pathname') as $k) {
if (strcmp($this->$k, $orig->$k) != 0) {
$parts[] = $k . ' = ' . $this->_quote($this->$k);
}
}
if (count($parts) == 0) {
// No changes
return true;
}
$toupdate = implode(', ', $parts);
$table = common_database_tablename($this->tableName());
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
' WHERE nickname = ' . $this->_quote($this->nickname);
$orig->decache();
$result = $this->query($qry);
if ($result) {
$this->encache();
}
return $result;
}
function delete()
{
$this->decache(); # while we still have the values!
return parent::delete();
}
/**
* @param string $servername hostname
* @param string $pathname URL base path
* @param string $wildcard hostname suffix to match wildcard config
* @return mixed Status_network or null
*/
static function setupSite($servername, $pathname, $wildcard)
static function getFromHostname($servername, $wildcard)
{
global $config;
$sn = null;
// XXX I18N, probably not crucial for hostnames
// XXX This probably needs a tune up
if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) {
// special case for exact match
if (0 == strcasecmp($servername, $wildcard)) {
@ -182,6 +205,23 @@ class Status_network extends Safe_DataObject
}
}
}
return $sn;
}
/**
* @param string $servername hostname
* @param string $pathname URL base path
* @param string $wildcard hostname suffix to match wildcard config
*/
static function setupSite($servername, $pathname, $wildcard)
{
global $config;
$sn = null;
// XXX I18N, probably not crucial for hostnames
// XXX This probably needs a tune up
$sn = self::getFromHostname($servername, $wildcard);
if (!empty($sn)) {

View File

@ -459,9 +459,9 @@ class User extends Memcached_DataObject
return $profile->getNotices($offset, $limit, $since_id, $before_id);
}
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE, $own=false)
function favoriteNotices($own=false, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
{
$ids = Fave::stream($this->id, $offset, $limit, $own);
$ids = Fave::stream($this->id, $offset, $limit, $own, $since_id, $max_id);
return Notice::getStreamByIds($ids);
}

View File

@ -154,6 +154,21 @@ class User_group extends Memcached_DataObject
return $members;
}
function getMemberCount()
{
// XXX: WORM cache this
$members = $this->getMembers();
$member_count = 0;
/** $member->count() doesn't work. */
while ($members->fetch()) {
$member_count++;
}
return $member_count;
}
function getAdmins($offset=0, $limit=null)
{
$qry =

View File

@ -68,4 +68,27 @@ class User_im_prefs extends Memcached_DataObject
{
return array(false,false);
}
/**
* We have two compound keys with unique constraints:
* (transport, user_id) which is our primary key, and
* (transport, screenname) which is an additional constraint.
*
* Currently there's not a way to represent that second key
* in the general keys list, so we're adding it here to the
* list of keys to use for caching, ensuring that it gets
* cleared as well when we change.
*
* @return array of cache keys
*/
function _allCacheKeys()
{
$ukeys = 'transport,screenname';
$uvals = $this->transport . ',' . $this->screenname;
$ckeys = parent::_allCacheKeys();
$ckeys[] = $this->cacheKey($this->tableName(), $ukeys, $uvals);
return $ckeys;
}
}

View File

@ -647,8 +647,10 @@ modified = 384
[user_im_prefs__keys]
user_id = K
transport = K
transport = U
screenname = U
; There's another unique index on (transport, screenname)
; but we have no way to represent a compound index other than
; the primary key in here. To ensure proper cache purging,
; we need to tweak the class.
[user_urlshortener_prefs]
user_id = 129

View File

@ -45,7 +45,7 @@ $config['site']['path'] = 'statusnet';
// lighttpd, nginx), you can enable X-Sendfile support for better
// performance. Presently, only attachment serving when the site is
// in private mode will use X-Sendfile.
// $config['site']['X-Sendfile'] = false;
// $config['site']['use_x_sendfile'] = false;
// You may also need to enable X-Sendfile support for your web server and
// allow it to access files outside of the web root. For Apache with
// mod_xsendfile, you can add these to your .htaccess or server config:

View File

@ -81,3 +81,42 @@ ALTER TABLE profile ADD COLUMN lon decimal(10,7) /*comment 'longitude'*/;
ALTER TABLE profile ADD COLUMN location_id integer /* comment 'location id if possible'*/;
ALTER TABLE profile ADD COLUMN location_ns integer /* comment 'namespace for location'*/;
ALTER TABLE consumer add COLUMN consumer_secret varchar(255) not null ; /*comment 'secret value'*/
ALTER TABLE token ADD COLUMN verifier varchar(255); /* comment 'verifier string for OAuth 1.0a',*/
ALTER TABLE token ADD COLUMN verified_callback varchar(255); /* comment 'verified callback URL for OAuth 1.0a',*/
create table queue_item_new (
id serial /* comment 'unique identifier'*/,
frame bytea not null /* comment 'data: object reference or opaque string'*/,
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 (id)
);
insert into queue_item_new (frame,transport,created,claimed)
select ('0x' || notice_id::text)::bytea,transport,created,claimed from queue_item;
alter table queue_item rename to queue_item_old;
alter table queue_item_new rename to queue_item;
ALTER TABLE confirm_address ALTER column sent set default CURRENT_TIMESTAMP;
create table user_location_prefs (
user_id integer not null /*comment 'user who has the preference'*/ references "user" (id),
share_location int default 1 /* comment 'Whether to share location data'*/,
created timestamp not null /*comment 'date this record was created'*/,
modified timestamp /* comment 'date this record was modified'*/,
primary key (user_id)
);
create table inbox (
user_id integer not null /* comment 'user receiving the notice' */ references "user" (id),
notice_ids bytea /* comment 'packed list of notice ids' */,
primary key (user_id)
);

View File

@ -9,13 +9,16 @@ VALUES
('bti','bti','http://gregkh.github.com/bti/', now()),
('choqok', 'Choqok', 'http://choqok.gnufolks.org/', now()),
('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
('DarterosStatus', 'Darteros Status', 'http://www.darteros.com/doc/Darteros_Status', now()),
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
('drupal','Drupal','http://drupal.org/', now()),
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/', now()),
('identica-mode','Emacs Identica-mode','http://nongnu.org/identica-mode/', now()),
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
('get2gnow', 'get2gnow', 'http://uberchicgeekchick.com/?projects=get2gnow', now()),
('gNewBook', 'gNewBook', 'http://www.gnewbook.org/', now()),
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
@ -53,6 +56,7 @@ VALUES
('tr.im','tr.im','http://tr.im/', now()),
('triklepost', 'Tricklepost', 'http://github.com/zcopley/tricklepost/tree/master', now()),
('tweenky','Tweenky','http://beta.tweenky.com/', now()),
('TweetDeck', 'TweetDeck', 'http://www.tweetdeck.com/', now()),
('twhirl','Twhirl','http://www.twhirl.org/', now()),
('twibble','twibble','http://www.twibble.de/', now()),
('Twidge','Twidge','http://software.complete.org/twidge', now()),

View File

@ -8,6 +8,10 @@ create table profile (
homepage varchar(255) /* comment 'identifying URL' */,
bio varchar(140) /* comment 'descriptive biography' */,
location varchar(255) /* comment 'physical location' */,
lat decimal(10,7) /* comment 'latitude'*/ ,
lon decimal(10,7) /* comment 'longitude'*/ ,
location_id integer /* comment 'location id if possible'*/ ,
location_ns integer /* comment 'namespace for location'*/ ,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
@ -132,6 +136,7 @@ create table notice (
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),
location varchar(255) /* comment 'physical location' */,
lat decimal(10,7) /* comment 'latitude'*/ ,
lon decimal(10,7) /* comment 'longitude'*/ ,
location_id integer /* comment 'location id if possible'*/ ,
@ -182,6 +187,7 @@ create index fave_modified_idx on fave using btree(modified);
create table consumer (
consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
consumer_secret varchar(255) not null /* comment 'secret value', */,
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' */,
@ -195,6 +201,9 @@ create table token (
type integer not null default 0 /* comment 'request or access' */,
state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
verifier varchar(255) /*comment 'verifier string for OAuth 1.0a'*/,
verified_callback varchar(255) /*comment 'verified callback URL for OAuth 1.0a'*/,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
@ -213,17 +222,33 @@ create table nonce (
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) ,
create sequence oauth_application_seq;
create table oauth_application (
id bigint default nextval('oauth_application_seq') primary key /* comment 'unique identifier' */,
owner integer not null /* comment 'owner of the application' */ references profile (id),
consumer_key varchar(255) not null /* comment 'application consumer key' */ references consumer (consumer_key),
name varchar(255) unique not null /* comment 'name of the application' */,
description varchar(255) /* comment 'description of the application' */,
icon varchar(255) not null /* comment 'application icon' */,
source_url varchar(255) /* comment 'application homepage - used for source link' */,
organization varchar(255) /* comment 'name of the organization running the application' */,
homepage varchar(255) /* comment 'homepage for the organization' */,
callback_url varchar(255) /* comment 'url to redirect to after authentication' */,
"type" integer default 0 /* comment 'type of app, 1 = browser, 2 = desktop' */,
access_type integer default 0 /* comment 'default access type, bit 1 = read, bit 2 = write' */,
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);
create table oauth_application_user (
profile_id integer not null /* 'user of the application' */ references profile (id),
application_id integer not null /* 'id of the application' */ references oauth_application (id),
access_type integer default 0 /* 'access type, bit 1 = read, bit 2 = write' */,
token varchar(255) /* 'request or access token' */,
created timestamp not null default CURRENT_TIMESTAMP /* 'date this record was created' */,
modified timestamp /* 'date this record was modified' */,
primary key (profile_id, application_id)
);
/* These are used by JanRain OpenID library */
@ -251,7 +276,7 @@ create table confirm_address (
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' */,
sent timestamp default CURRENT_TIMESTAMP /* comment 'date this was sent for queueing' */,
modified timestamp /* comment 'date this record was modified' */
);
@ -262,14 +287,12 @@ create table remember_me (
);
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)
id serial /* comment 'unique identifier'*/,
frame bytea not null /* comment 'data: object reference or opaque string'*/,
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 (id)
);
create index queue_item_created_idx on queue_item using btree(created);
@ -589,3 +612,39 @@ create table login_token (
primary key (user_id)
);
create table user_location_prefs (
user_id integer not null /* comment 'user who has the preference' */ references "user" (id),
share_location integer default 1 /* comment 'Whether to share location data' */,
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)
);
create table inbox (
user_id integer not null /* comment 'user receiving the notice' */ references "user" (id),
notice_ids bytea /* comment 'packed list of notice ids' */,
primary key (user_id)
);
create sequence conversation_seq;
create table conversation (
id bigint default nextval('conversation_seq') primary key /* comment 'unique identifier' */,
uri varchar(225) unique /* comment 'URI of the conversation' */,
created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
create table local_group (
group_id integer primary key /* comment 'group represented' */ references user_group (id),
nickname varchar(64) unique /* comment 'group represented' */,
created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);

View File

@ -1,4 +1,4 @@
You can post messages to %%site.name%% using a many kinds of cell
You can post messages to %%site.name%% using many kinds of cell
phones that support SMS messaging. This site does not support SMS
directly; rather, it uses your carrier's email gateway to send and
receive messages.

82
extlib/Mail.php Normal file → Executable file
View File

@ -1,22 +1,47 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: Mail.php,v 1.17 2006/09/15 03:41:18 jon Exp $
/**
* PEAR's Mail:: interface.
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2002-2007, Richard Heyes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail
* @author Chuck Hagenbuch <chuck@horde.org>
* @copyright 1997-2010 Chuck Hagenbuch
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Mail.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
require_once 'PEAR.php';
@ -26,7 +51,7 @@ require_once 'PEAR.php';
* useful in multiple mailer backends.
*
* @access public
* @version $Revision: 1.17 $
* @version $Revision: 294747 $
* @package Mail
*/
class Mail
@ -82,12 +107,20 @@ class Mail
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
*
* @access public
* @deprecated use Mail_mail::send instead
*/
function send($recipients, $headers, $body)
{
$this->_sanitizeHeaders($headers);
if (!is_array($headers)) {
return PEAR::raiseError('$headers must be an array');
}
$result = $this->_sanitizeHeaders($headers);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
// if we're passed an array of recipients, implode it.
if (is_array($recipients)) {
@ -103,10 +136,9 @@ class Mail
}
// flatten the headers out.
list(,$text_headers) = Mail::prepareHeaders($headers);
list(, $text_headers) = Mail::prepareHeaders($headers);
return mail($recipients, $subject, $body, $text_headers);
}
/**
@ -151,9 +183,9 @@ class Mail
foreach ($headers as $key => $value) {
if (strcasecmp($key, 'From') === 0) {
include_once 'Mail/RFC822.php';
$parser = &new Mail_RFC822();
$parser = new Mail_RFC822();
$addresses = $parser->parseAddressList($value, 'localhost', false);
if (PEAR::isError($addresses)) {
if (is_a($addresses, 'PEAR_Error')) {
return $addresses;
}
@ -221,7 +253,7 @@ class Mail
$addresses = Mail_RFC822::parseAddressList($recipients, 'localhost', false);
// If parseAddressList() returned a PEAR_Error object, just return it.
if (PEAR::isError($addresses)) {
if (is_a($addresses, 'PEAR_Error')) {
return $addresses;
}

83
extlib/Mail/RFC822.php Normal file → Executable file
View File

@ -1,37 +1,48 @@
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2001-2002, Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Authors: Richard Heyes <richard@phpguru.org> |
// | Chuck Hagenbuch <chuck@horde.org> |
// +-----------------------------------------------------------------------+
/**
* RFC 822 Email address list validation Utility
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2001-2010, Richard Heyes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail
* @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org
* @copyright 2001-2010 Richard Heyes
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: RFC822.php 294749 2010-02-08 08:22:25Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
/**
* RFC 822 Email address list validation Utility
@ -52,7 +63,7 @@
*
* @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org>
* @version $Revision: 1.24 $
* @version $Revision: 294749 $
* @license BSD
* @package Mail
*/
@ -635,8 +646,8 @@ class Mail_RFC822 {
$comment = $this->_splitCheck($parts, ')');
$comments[] = $comment;
// +1 is for the trailing )
$_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1);
// +2 is for the brackets
$_mailbox = substr($_mailbox, strpos($_mailbox, '('.$comment)+strlen($comment)+2);
} else {
break;
}

63
extlib/Mail/mail.php Normal file → Executable file
View File

@ -1,27 +1,52 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: mail.php,v 1.20 2007/10/06 17:00:00 chagenbu Exp $
/**
* internal PHP-mail() implementation of the PEAR Mail:: interface.
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2010 Chuck Hagenbuch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail
* @author Chuck Hagenbuch <chuck@horde.org>
* @copyright 2010 Chuck Hagenbuch
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: mail.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
/**
* internal PHP-mail() implementation of the PEAR Mail:: interface.
* @package Mail
* @version $Revision: 1.20 $
* @version $Revision: 294747 $
*/
class Mail_mail extends Mail {

64
extlib/Mail/mock.php Normal file → Executable file
View File

@ -1,29 +1,53 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: mock.php,v 1.1 2007/12/08 17:57:54 chagenbu Exp $
//
/**
* Mock implementation
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2010 Chuck Hagenbuch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail
* @author Chuck Hagenbuch <chuck@horde.org>
* @copyright 2010 Chuck Hagenbuch
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: mock.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
/**
* Mock implementation of the PEAR Mail:: interface for testing.
* @access public
* @package Mail
* @version $Revision: 1.1 $
* @version $Revision: 294747 $
*/
class Mail_mock extends Mail {

64
extlib/Mail/null.php Normal file → Executable file
View File

@ -1,29 +1,53 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Phil Kernick <philk@rotfl.com.au> |
// +----------------------------------------------------------------------+
//
// $Id: null.php,v 1.2 2004/04/06 05:19:03 jon Exp $
//
/**
* Null implementation of the PEAR Mail interface
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2010 Phil Kernick
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail
* @author Phil Kernick <philk@rotfl.com.au>
* @copyright 2010 Phil Kernick
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: null.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
/**
* Null implementation of the PEAR Mail:: interface.
* @access public
* @package Mail
* @version $Revision: 1.2 $
* @version $Revision: 294747 $
*/
class Mail_null extends Mail {

7
extlib/Mail/sendmail.php Normal file → Executable file
View File

@ -20,7 +20,7 @@
* Sendmail implementation of the PEAR Mail:: interface.
* @access public
* @package Mail
* @version $Revision: 1.19 $
* @version $Revision: 294744 $
*/
class Mail_sendmail extends Mail {
@ -117,7 +117,7 @@ class Mail_sendmail extends Mail {
if (is_a($recipients, 'PEAR_Error')) {
return $recipients;
}
$recipients = escapeShellCmd(implode(' ', $recipients));
$recipients = implode(' ', array_map('escapeshellarg', $recipients));
$headerElements = $this->prepareHeaders($headers);
if (is_a($headerElements, 'PEAR_Error')) {
@ -141,7 +141,8 @@ class Mail_sendmail extends Mail {
return PEAR::raiseError('From address specified with dangerous characters.');
}
$from = escapeShellCmd($from);
$from = escapeshellarg($from); // Security bug #16200
$mail = @popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w');
if (!$mail) {
return PEAR::raiseError('Failed to open sendmail [' . $this->sendmail_path . '] for execution.');

73
extlib/Mail/smtp.php Normal file → Executable file
View File

@ -1,21 +1,48 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Chuck Hagenbuch <chuck@horde.org> |
// | Jon Parise <jon@php.net> |
// +----------------------------------------------------------------------+
/**
* SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class.
*
* PHP versions 4 and 5
*
* LICENSE:
*
* Copyright (c) 2010, Chuck Hagenbuch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category HTTP
* @package HTTP_Request
* @author Jon Parise <jon@php.net>
* @author Chuck Hagenbuch <chuck@horde.org>
* @copyright 2010 Chuck Hagenbuch
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: smtp.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
/** Error: Failed to create a Net_SMTP object */
define('PEAR_MAIL_SMTP_ERROR_CREATE', 10000);
@ -42,7 +69,7 @@ define('PEAR_MAIL_SMTP_ERROR_DATA', 10006);
* SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class.
* @access public
* @package Mail
* @version $Revision: 1.33 $
* @version $Revision: 294747 $
*/
class Mail_smtp extends Mail {
@ -278,6 +305,16 @@ class Mail_smtp extends Mail {
/* Send the message's headers and the body as SMTP data. */
$res = $this->_smtp->data($textHeaders . "\r\n\r\n" . $body);
list(,$args) = $this->_smtp->getResponse();
if (preg_match("/Ok: queued as (.*)/", $args, $queued)) {
$this->queued_as = $queued[1];
}
/* we need the greeting; from it we can extract the authorative name of the mail server we've really connected to.
* ideal if we're connecting to a round-robin of relay servers and need to track which exact one took the email */
$this->greeting = $this->_smtp->getGreeting();
if (is_a($res, 'PEAR_Error')) {
$error = $this->_error('Failed to send data', $res);
$this->_smtp->rset();

44
extlib/Mail/smtpmx.php Normal file → Executable file
View File

@ -8,19 +8,43 @@
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
* LICENSE:
*
* Copyright (c) 2010, gERD Schaufelberger
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Mail
* @package Mail_smtpmx
* @author gERD Schaufelberger <gerd@php-tools.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: smtpmx.php,v 1.2 2007/10/06 17:00:00 chagenbu Exp $
* @see Mail
* @copyright 2010 gERD Schaufelberger
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: smtpmx.php 294747 2010-02-08 08:18:33Z clockwerx $
* @link http://pear.php.net/package/Mail/
*/
require_once 'Net/SMTP.php';
@ -32,7 +56,7 @@ require_once 'Net/SMTP.php';
* @access public
* @author gERD Schaufelberger <gerd@php-tools.net>
* @package Mail
* @version $Revision: 1.2 $
* @version $Revision: 294747 $
*/
class Mail_smtpmx extends Mail {

View File

@ -18,7 +18,7 @@
// | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> |
// +----------------------------------------------------------------------+
//
// $Id: SMTP.php,v 1.63 2008/06/10 05:39:12 jon Exp $
// $Id: SMTP.php 293948 2010-01-24 21:46:00Z jon $
require_once 'PEAR.php';
require_once 'Net/Socket.php';
@ -91,6 +91,13 @@ class Net_SMTP
*/
var $_debug = false;
/**
* Debug output handler.
* @var callback
* @access private
*/
var $_debug_handler = null;
/**
* The socket resource being used to connect to the SMTP server.
* @var resource
@ -112,6 +119,13 @@ class Net_SMTP
*/
var $_arguments = array();
/**
* Stores the SMTP server's greeting string.
* @var string
* @access private
*/
var $_greeting = null;
/**
* Stores detected features of the SMTP server.
* @var array
@ -172,9 +186,30 @@ class Net_SMTP
* @access public
* @since 1.1.0
*/
function setDebug($debug)
function setDebug($debug, $handler = null)
{
$this->_debug = $debug;
$this->_debug_handler = $handler;
}
/**
* Write the given debug text to the current debug output handler.
*
* @param string $message Debug mesage text.
*
* @access private
* @since 1.3.3
*/
function _debug($message)
{
if ($this->_debug) {
if ($this->_debug_handler) {
call_user_func_array($this->_debug_handler,
array(&$this, $message));
} else {
echo "DEBUG: $message\n";
}
}
}
/**
@ -189,13 +224,12 @@ class Net_SMTP
*/
function _send($data)
{
if ($this->_debug) {
echo "DEBUG: Send: $data\n";
}
$this->_debug("Send: $data");
if (PEAR::isError($error = $this->_socket->write($data))) {
return PEAR::raiseError('Failed to write to socket: ' .
$error->getMessage());
$error = $this->_socket->write($data);
if ($error === false || PEAR::isError($error)) {
$msg = ($error) ? $error->getMessage() : "unknown error";
return PEAR::raiseError("Failed to write to socket: $msg");
}
return true;
@ -262,9 +296,7 @@ class Net_SMTP
for ($i = 0; $i <= $this->_pipelined_commands; $i++) {
while ($line = $this->_socket->readLine()) {
if ($this->_debug) {
echo "DEBUG: Recv: $line\n";
}
$this->_debug("Recv: $line");
/* If we receive an empty line, the connection has been closed. */
if (empty($line)) {
@ -319,6 +351,20 @@ class Net_SMTP
return array($this->_code, join("\n", $this->_arguments));
}
/**
* Return the SMTP server's greeting string.
*
* @return string A string containing the greeting string, or null if a
* greeting has not been received.
*
* @access public
* @since 1.3.3
*/
function getGreeting()
{
return $this->_greeting;
}
/**
* Attempt to connect to the SMTP server.
*
@ -334,6 +380,7 @@ class Net_SMTP
*/
function connect($timeout = null, $persistent = false)
{
$this->_greeting = null;
$result = $this->_socket->connect($this->host, $this->port,
$persistent, $timeout);
if (PEAR::isError($result)) {
@ -344,6 +391,10 @@ class Net_SMTP
if (PEAR::isError($error = $this->_parseResponse(220))) {
return $error;
}
/* Extract and store a copy of the server's greeting string. */
list(, $this->_greeting) = $this->getResponse();
if (PEAR::isError($error = $this->_negotiate())) {
return $error;
}
@ -452,40 +503,43 @@ class Net_SMTP
* @param string The password to authenticate with.
* @param string The requested authentication method. If none is
* specified, the best supported method will be used.
* @param bool Flag indicating whether or not TLS should be attempted.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function auth($uid, $pwd , $method = '')
function auth($uid, $pwd , $method = '', $tls = true)
{
if (empty($this->_esmtp['AUTH'])) {
if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
if (!isset($this->_esmtp['STARTTLS'])) {
return PEAR::raiseError('SMTP server does not support authentication');
}
if (PEAR::isError($result = $this->_put('STARTTLS'))) {
return $result;
}
if (PEAR::isError($result = $this->_parseResponse(220))) {
return $result;
}
if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
return $result;
} elseif ($result !== true) {
return PEAR::raiseError('STARTTLS failed');
}
/* Send EHLO again to recieve the AUTH string from the
* SMTP server. */
$this->_negotiate();
if (empty($this->_esmtp['AUTH'])) {
return PEAR::raiseError('SMTP server does not support authentication');
}
} else {
return PEAR::raiseError('SMTP server does not support authentication');
/* We can only attempt a TLS connection if one has been requested,
* we're running PHP 5.1.0 or later, have access to the OpenSSL
* extension, are connected to an SMTP server which supports the
* STARTTLS extension, and aren't already connected over a secure
* (SSL) socket connection. */
if ($tls && version_compare(PHP_VERSION, '5.1.0', '>=') &&
extension_loaded('openssl') && isset($this->_esmtp['STARTTLS']) &&
strncasecmp($this->host, 'ssl://', 6) !== 0) {
/* Start the TLS connection attempt. */
if (PEAR::isError($result = $this->_put('STARTTLS'))) {
return $result;
}
if (PEAR::isError($result = $this->_parseResponse(220))) {
return $result;
}
if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
return $result;
} elseif ($result !== true) {
return PEAR::raiseError('STARTTLS failed');
}
/* Send EHLO again to recieve the AUTH string from the
* SMTP server. */
$this->_negotiate();
}
if (empty($this->_esmtp['AUTH'])) {
return PEAR::raiseError('SMTP server does not support authentication');
}
/* If no method has been specified, get the name of the best
@ -844,30 +898,51 @@ class Net_SMTP
/**
* Send the DATA command.
*
* @param string $data The message body to send.
* @param mixed $data The message data, either as a string or an open
* file resource.
* @param string $headers The message headers. If $headers is provided,
* $data is assumed to contain only body data.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function data($data)
function data($data, $headers = null)
{
/* Verify that $data is a supported type. */
if (!is_string($data) && !is_resource($data)) {
return PEAR::raiseError('Expected a string or file resource');
}
/* RFC 1870, section 3, subsection 3 states "a value of zero
* indicates that no fixed maximum message size is in force".
* Furthermore, it says that if "the parameter is omitted no
* information is conveyed about the server's fixed maximum
* message size". */
if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) {
if (strlen($data) >= $this->_esmtp['SIZE']) {
/* Start by considering the size of the optional headers string.
* We also account for the addition 4 character "\r\n\r\n"
* separator sequence. */
$size = (is_null($headers)) ? 0 : strlen($headers) + 4;
if (is_resource($data)) {
$stat = fstat($data);
if ($stat === false) {
return PEAR::raiseError('Failed to get file size');
}
$size += $stat['size'];
} else {
$size += strlen($data);
}
if ($size >= $this->_esmtp['SIZE']) {
$this->disconnect();
return PEAR::raiseError('Message size excedes the server limit');
return PEAR::raiseError('Message size exceeds server limit');
}
}
/* Quote the data based on the SMTP standards. */
$this->quotedata($data);
/* Initiate the DATA command. */
if (PEAR::isError($error = $this->_put('DATA'))) {
return $error;
}
@ -875,9 +950,40 @@ class Net_SMTP
return $error;
}
if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) {
return $result;
/* If we have a separate headers string, send it first. */
if (!is_null($headers)) {
$this->quotedata($headers);
if (PEAR::isError($result = $this->_send($headers . "\r\n\r\n"))) {
return $result;
}
}
/* Now we can send the message body data. */
if (is_resource($data)) {
/* Stream the contents of the file resource out over our socket
* connection, line by line. Each line must be run through the
* quoting routine. */
while ($line = fgets($data, 1024)) {
$this->quotedata($line);
if (PEAR::isError($result = $this->_send($line))) {
return $result;
}
}
/* Finally, send the DATA terminator sequence. */
if (PEAR::isError($result = $this->_send("\r\n.\r\n"))) {
return $result;
}
} else {
/* Just send the entire quoted string followed by the DATA
* terminator. */
$this->quotedata($data);
if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) {
return $result;
}
}
/* Verify that the data was successfully received by the server. */
if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
return $error;
}

View File

@ -19,16 +19,20 @@
* @category StatusNet
* @package StatusNet
* @author Brenda Wallace <shiny@cpan.org>
* @author Brion Vibber <brion@pobox.com>
* @author Christopher Vollick <psycotica0@gmail.com>
* @author CiaranG <ciaran@ciarang.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@controlezvous.ca>
* @author Gina Haeussge <osd@foosel.net>
* @author James Walker <walkah@walkah.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
*
* @license GNU Affero General Public License http://www.gnu.org/licenses/
*/
@ -200,7 +204,7 @@ function checkMirror($action_obj, $args)
function isLoginAction($action)
{
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds', 'otp', 'opensearch');
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds', 'otp', 'opensearch', 'rsd');
$login = null;

View File

@ -31,6 +31,7 @@
* @author Sarven Capadisli <csarven@status.net>
* @author Tom Adams <tom@holizz.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @version 0.9.x
* @link http://status.net

View File

@ -84,7 +84,7 @@ var SN = { // StatusNet
form.find('#'+SN.C.S.NoticeTextCount).text(jQuery.data(form[0], 'ElementData').MaxLength);
}
if ($('body')[0].id != 'conversation' && window.location.hash.length === 0) {
if ($('body')[0].id != 'conversation' && window.location.hash.length === 0 && $(window).scrollTop() == 0) {
form.find('textarea').focus();
}
},

View File

@ -235,6 +235,16 @@ class Action extends HTMLOutputter // lawsuit
Event::handle('EndShowDesign', array($this));
}
Event::handle('EndShowStyles', array($this));
if (common_config('custom_css', 'enabled')) {
$css = common_config('custom_css', 'css');
if (Event::handle('StartShowCustomCss', array($this, &$css))) {
if (trim($css) != '') {
$this->style($css);
}
Event::handle('EndShowCustomCss', array($this));
}
}
}
}
@ -467,7 +477,7 @@ class Action extends HTMLOutputter // lawsuit
_m('MENU', 'Logout'), $tooltip, false, 'nav_logout');
}
else {
if (!common_config('site', 'closed')) {
if (!common_config('site', 'closed') && !common_config('site', 'inviteonly')) {
// TRANS: Tooltip for main menu option "Register"
$tooltip = _m('TOOLTIP', 'Create an account');
$this->menuItem(common_local_url('register'),

View File

@ -83,6 +83,7 @@ class Activity
const CREATOR = 'creator';
const CONTENTNS = 'http://purl.org/rss/1.0/modules/content/';
const ENCODED = 'encoded';
public $actor; // an ActivityObject
public $verb; // a string (the URL)
@ -269,14 +270,21 @@ class Activity
$this->title = ActivityUtils::childContent($item, ActivityObject::TITLE, self::RSS);
$contentEl = ActivityUtils::child($item, ActivityUtils::CONTENT, self::CONTENTNS);
$contentEl = ActivityUtils::child($item, self::ENCODED, self::CONTENTNS);
if (!empty($contentEl)) {
$this->content = htmlspecialchars_decode($contentEl->textContent, ENT_QUOTES);
// <content:encoded> XML node's text content is HTML; no further processing needed.
$this->content = $contentEl->textContent;
} else {
$descriptionEl = ActivityUtils::child($item, self::DESCRIPTION, self::RSS);
if (!empty($descriptionEl)) {
$this->content = htmlspecialchars_decode($descriptionEl->textContent, ENT_QUOTES);
// Per spec, <description> must be plaintext.
// In practice, often there's HTML... but these days good
// feeds are using <content:encoded> which is explicitly
// real HTML.
// We'll treat this following spec, and do HTML escaping
// to convert from plaintext to HTML.
$this->content = htmlspecialchars($descriptionEl->textContent);
}
}

View File

@ -213,11 +213,19 @@ class ActivityUtils
// slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3
if (empty($type) || $type == 'text') {
return $el->textContent;
// We have plaintext saved as the XML text content.
// Since we want HTML, we need to escape any special chars.
return htmlspecialchars($el->textContent);
} else if ($type == 'html') {
// We have HTML saved as the XML text content.
// No additional processing required once we've got it.
$text = $el->textContent;
return htmlspecialchars_decode($text, ENT_QUOTES);
return $text;
} else if ($type == 'xhtml') {
// Per spec, the <content type="xhtml"> contains a single
// HTML <div> with XHTML namespace on it as a child node.
// We need to pull all of that <div>'s child nodes and
// serialize them back to an (X)HTML source fragment.
$divEl = ActivityUtils::child($el, 'div', 'http://www.w3.org/1999/xhtml');
if (empty($divEl)) {
return null;

View File

@ -284,9 +284,10 @@ class AdminPanelAction extends Action
$this->clientError(_("Unable to delete design setting."));
return null;
}
return $result;
}
return $result;
return null;
}
function canAdmin($name)

View File

@ -28,14 +28,78 @@
* @author Toby Inkster <mail@tobyinkster.co.uk>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how the API works. */
/*! @mainpage StatusNet REST API
@section Introduction
Some explanatory text about the API would be nice.
@section API Methods
@subsection timelinesmethods_sec Timeline Methods
@li @ref publictimeline
@li @ref friendstimeline
@subsection statusmethods_sec Status Methods
@li @ref statusesupdate
@subsection usermethods_sec User Methods
@subsection directmessagemethods_sec Direct Message Methods
@subsection friendshipmethods_sec Friendship Methods
@subsection socialgraphmethods_sec Social Graph Methods
@subsection accountmethods_sec Account Methods
@subsection favoritesmethods_sec Favorites Methods
@subsection blockmethods_sec Block Methods
@subsection oauthmethods_sec OAuth Methods
@subsection helpmethods_sec Help Methods
@subsection groupmethods_sec Group Methods
@page apiroot API Root
The URLs for methods referred to in this API documentation are
relative to the StatusNet API root. The API root is determined by the
site's @b server and @b path variables, which are generally specified
in config.php. For example:
@code
$config['site']['server'] = 'example.org';
$config['site']['path'] = 'statusnet'
@endcode
The pattern for a site's API root is: @c protocol://server/path/api E.g:
@c http://example.org/statusnet/api
The @b path can be empty. In that case the API root would simply be:
@c http://example.org/api
*/
if (!defined('STATUSNET')) {
exit(1);
}
class ApiValidationException extends Exception { }
/**
* Contains most of the Twitter-compatible API output functions.
*
@ -63,9 +127,12 @@ class ApiAction extends Action
var $count = null;
var $max_id = null;
var $since_id = null;
var $source = null;
var $access = self::READ_ONLY; // read (default) or read-write
static $reserved_sources = array('web', 'omb', 'ostatus', 'mail', 'xmpp', 'api');
/**
* Initialization.
*
@ -89,6 +156,12 @@ class ApiAction extends Action
header('X-StatusNet-Warning: since parameter is disabled; use since_id');
}
$this->source = $this->trimmed('source');
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
$this->source = 'api';
}
return true;
}
@ -200,11 +273,13 @@ class ApiAction extends Action
// Is the requesting user following this user?
$twitter_user['following'] = false;
$twitter_user['statusnet:blocking'] = false;
$twitter_user['notifications'] = false;
if (isset($this->auth_user)) {
$twitter_user['following'] = $this->auth_user->isSubscribed($profile);
$twitter_user['statusnet:blocking'] = $this->auth_user->hasBlocked($profile);
// Notifications on?
$sub = Subscription::pkeyGet(array('subscriber' =>
@ -224,6 +299,10 @@ class ApiAction extends Action
}
}
// StatusNet-specific
$twitter_user['statusnet:profile_url'] = $profile->profileurl;
return $twitter_user;
}
@ -252,7 +331,23 @@ class ApiAction extends Action
$twitter_status['created_at'] = $this->dateTwitter($notice->created);
$twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ?
intval($notice->reply_to) : null;
$twitter_status['source'] = $this->sourceLink($notice->source);
$source = null;
$ns = $notice->getSource();
if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
} else {
$source = $ns->code;
}
}
$twitter_status['source'] = $source;
$twitter_status['id'] = intval($notice->id);
$replier_profile = null;
@ -309,25 +404,41 @@ class ApiAction extends Action
$twitter_status['user'] = $twitter_user;
}
// StatusNet-specific
$twitter_status['statusnet:html'] = $notice->rendered;
return $twitter_status;
}
function twitterGroupArray($group)
{
$twitter_group=array();
$twitter_group['id']=$group->id;
$twitter_group['url']=$group->permalink();
$twitter_group['nickname']=$group->nickname;
$twitter_group['fullname']=$group->fullname;
$twitter_group['original_logo']=$group->original_logo;
$twitter_group['homepage_logo']=$group->homepage_logo;
$twitter_group['stream_logo']=$group->stream_logo;
$twitter_group['mini_logo']=$group->mini_logo;
$twitter_group['homepage']=$group->homepage;
$twitter_group['description']=$group->description;
$twitter_group['location']=$group->location;
$twitter_group['created']=$this->dateTwitter($group->created);
$twitter_group['modified']=$this->dateTwitter($group->modified);
$twitter_group = array();
$twitter_group['id'] = $group->id;
$twitter_group['url'] = $group->permalink();
$twitter_group['nickname'] = $group->nickname;
$twitter_group['fullname'] = $group->fullname;
if (isset($this->auth_user)) {
$twitter_group['member'] = $this->auth_user->isMember($group);
$twitter_group['blocked'] = Group_block::isBlocked(
$group,
$this->auth_user->getProfile()
);
}
$twitter_group['member_count'] = $group->getMemberCount();
$twitter_group['original_logo'] = $group->original_logo;
$twitter_group['homepage_logo'] = $group->homepage_logo;
$twitter_group['stream_logo'] = $group->stream_logo;
$twitter_group['mini_logo'] = $group->mini_logo;
$twitter_group['homepage'] = $group->homepage;
$twitter_group['description'] = $group->description;
$twitter_group['location'] = $group->location;
$twitter_group['created'] = $this->dateTwitter($group->created);
$twitter_group['modified'] = $this->dateTwitter($group->modified);
return $twitter_group;
}
@ -476,9 +587,13 @@ class ApiAction extends Action
}
}
function showTwitterXmlStatus($twitter_status, $tag='status')
function showTwitterXmlStatus($twitter_status, $tag='status', $namespaces=false)
{
$this->elementStart($tag);
$attrs = array();
if ($namespaces) {
$attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/';
}
$this->elementStart($tag, $attrs);
foreach($twitter_status as $element => $value) {
switch ($element) {
case 'user':
@ -512,9 +627,13 @@ class ApiAction extends Action
$this->elementEnd('group');
}
function showTwitterXmlUser($twitter_user, $role='user')
function showTwitterXmlUser($twitter_user, $role='user', $namespaces=false)
{
$this->elementStart($role);
$attrs = array();
if ($namespaces) {
$attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/';
}
$this->elementStart($role, $attrs);
foreach($twitter_user as $element => $value) {
if ($element == 'status') {
$this->showTwitterXmlStatus($twitter_user['status']);
@ -596,7 +715,7 @@ class ApiAction extends Action
{
$this->initDocument('xml');
$twitter_status = $this->twitterStatusArray($notice);
$this->showTwitterXmlStatus($twitter_status);
$this->showTwitterXmlStatus($twitter_status, 'status', true);
$this->endDocument('xml');
}
@ -612,7 +731,8 @@ class ApiAction extends Action
{
$this->initDocument('xml');
$this->elementStart('statuses', array('type' => 'array'));
$this->elementStart('statuses', array('type' => 'array',
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
if (is_array($notice)) {
foreach ($notice as $n) {
@ -779,9 +899,13 @@ class ApiAction extends Action
$this->elementEnd('entry');
}
function showXmlDirectMessage($dm)
function showXmlDirectMessage($dm, $namespaces=false)
{
$this->elementStart('direct_message');
$attrs = array();
if ($namespaces) {
$attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/';
}
$this->elementStart('direct_message', $attrs);
foreach($dm as $element => $value) {
switch ($element) {
case 'sender':
@ -858,7 +982,7 @@ class ApiAction extends Action
{
$this->initDocument('xml');
$dmsg = $this->directMessageArray($message);
$this->showXmlDirectMessage($dmsg);
$this->showXmlDirectMessage($dmsg, true);
$this->endDocument('xml');
}
@ -975,7 +1099,8 @@ class ApiAction extends Action
{
$this->initDocument('xml');
$this->elementStart('users', array('type' => 'array'));
$this->elementStart('users', array('type' => 'array',
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
if (is_array($user)) {
foreach ($user as $u) {
@ -1293,43 +1418,6 @@ class ApiAction extends Action
}
}
function sourceLink($source)
{
$source_name = _($source);
switch ($source) {
case 'web':
case 'xmpp':
case 'mail':
case 'omb':
case 'api':
break;
default:
$name = null;
$url = null;
$ns = Notice_source::staticGet($source);
if ($ns) {
$name = $ns->name;
$url = $ns->url;
} else {
$app = Oauth_application::staticGet('name', $source);
if ($app) {
$name = $app->name;
$url = $app->source_url;
}
}
if (!empty($name) && !empty($url)) {
$source_name = '<a href="' . $url . '">' . $name . '</a>';
}
break;
}
return $source_name;
}
/**
* Returns query argument or default value if not found. Certain
* parameters used throughout the API are lightly scrubbed and

View File

@ -30,10 +30,29 @@
* @author Sarven Capadisli <csarven@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how this method works. */
/*! @page authentication Authentication
StatusNet supports HTTP Basic Authentication and OAuth for API calls.
@warning Currently, users who have created accounts without setting a
password via OpenID, Facebook Connect, etc., cannot use the API until
they set a password with their account settings panel.
@section HTTP Basic Auth
@section OAuth
*/
if (!defined('STATUSNET')) {
exit(1);
}
@ -54,7 +73,6 @@ class ApiAuthAction extends ApiAction
{
var $auth_user_nickname = null;
var $auth_user_password = null;
var $oauth_source = null;
/**
* Take arguments for running, looks for an OAuth request,
@ -163,7 +181,7 @@ class ApiAuthAction extends ApiAction
// set the source attr
$this->oauth_source = $app->name;
$this->source = $app->name;
$appUser = Oauth_application_user::staticGet('token', $access_token);

View File

@ -32,6 +32,7 @@
* @author Sarven Capadisli <csarven@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
@ -106,4 +107,4 @@ class ApiBareAuthAction extends ApiAuthAction
return false;
}
}
}

View File

@ -31,6 +31,7 @@
* @author Sarven Capadisli <csarven@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -50,12 +50,13 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
* Constructor
*
* @param Group $group the group for the feed
* @param User $cur the current authenticated user, if any
* @param boolean $indent flag to turn indenting on or off
*
* @return void
*/
function __construct($group, $indent = true) {
parent::__construct($indent);
function __construct($group, $cur = null, $indent = true) {
parent::__construct($cur, $indent);
$this->group = $group;
// TRANS: Title in atom group notice feed. %s is a group name.
@ -95,4 +96,23 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
return $this->group;
}
function initFeed()
{
parent::initFeed();
$attrs = array();
if (!empty($this->cur)) {
$attrs['member'] = $this->cur->isMember($this->group)
? 'true' : 'false';
$attrs['blocked'] = Group_block::isBlocked(
$this->group,
$this->cur->getProfile()
) ? 'true' : 'false';
}
$attrs['member_count'] = $this->group->getMemberCount();
$this->element('statusnet:group_info', $attrs, null);
}
}

View File

@ -44,9 +44,22 @@ if (!defined('STATUSNET'))
*/
class AtomNoticeFeed extends Atom10Feed
{
function __construct($indent = true) {
var $cur;
/**
* Constructor - adds a bunch of XML namespaces we need in our
* notice-specific Atom feeds, and allows setting the current
* authenticated user (useful for API methods).
*
* @param User $cur the current authenticated user (optional)
* @param boolean $indent Whether to indent XML output
*
*/
function __construct($cur = null, $indent = true) {
parent::__construct($indent);
$this->cur = $cur;
// Feeds containing notice info use these namespaces
$this->addNamespace(
@ -79,6 +92,11 @@ class AtomNoticeFeed extends Atom10Feed
'ostatus',
'http://ostatus.org/schema/1.0'
);
$this->addNamespace(
'statusnet',
'http://status.net/schema/api/1/'
);
}
/**
@ -110,7 +128,9 @@ class AtomNoticeFeed extends Atom10Feed
$source = $this->showSource();
$author = $this->showAuthor();
$this->addEntryRaw($notice->asAtomEntry(false, $source, $author));
$cur = empty($this->cur) ? common_current_user() : $this->cur;
$this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur));
}
function showSource()

View File

@ -50,13 +50,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed
* Constructor
*
* @param User $user the user for the feed
* @param User $cur the current authenticated user, if any
* @param boolean $indent flag to turn indenting on or off
*
* @return void
*/
function __construct($user, $indent = true) {
parent::__construct($indent);
function __construct($user, $cur = null, $indent = true) {
parent::__construct($cur, $indent);
$this->user = $user;
if (!empty($user)) {
$profile = $user->getProfile();

View File

@ -22,6 +22,7 @@
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -22,6 +22,7 @@
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/

View File

@ -76,8 +76,8 @@ class AvatarLink
$alink = new AvatarLink();
$alink->url = $filename;
$alink->height = $size;
$alink->width = $size;
if (!empty($filename)) {
$alink->width = $size;
$alink->type = self::mediatype($filename);
} else {
$alink->url = User_group::defaultLogo($size);

View File

@ -22,10 +22,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
//exit with 200 response, if this is checking fancy from the installer
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
define('STATUSNET_VERSION', '0.9.1');
define('STATUSNET_VERSION', '0.9.2');
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
define('STATUSNET_CODENAME', 'Everybody Hurts');
define('STATUSNET_CODENAME', 'King of Birds');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
@ -132,6 +132,12 @@ require_once INSTALLDIR.'/lib/serverexception.php';
//set PEAR error handling to use regular PHP exceptions
function PEAR_ErrorToPEAR_Exception($err)
{
//DB_DataObject throws error when an empty set would be returned
//That behavior is weird, and not how the rest of StatusNet works.
//So just ignore those errors.
if ($err->getCode() == DB_DATAOBJECT_ERROR_NODATA) {
return;
}
if ($err->getCode()) {
throw new PEAR_Exception($err->getMessage(), $err->getCode());
}

View File

@ -105,7 +105,9 @@ class ConnectSettingsNav extends Widget
# action => array('prompt', 'title')
$menu = array();
if (common_config('xmpp', 'enabled')) {
$transports = array();
Event::handle('GetImTransports', array(&$transports));
if ($transports) {
$menu['imsettings'] =
array(_('IM'),
_('Updates by instant messenger (IM)'));

View File

@ -135,9 +135,7 @@ class DBQueueManager extends QueueManager
if (empty($qi->claimed)) {
$this->_log(LOG_WARNING, "[$queue:item $qi->id] Ignoring failure for unclaimed queue item");
} else {
$orig = clone($qi);
$qi->claimed = null;
$qi->update($orig);
$qi->releaseClaim();
}
$this->stats('error', $queue);

Some files were not shown because too many files have changed in this diff Show More