forked from GNUsocial/gnu-social
Merge branch '0.7.x' into 0.8.x
This commit is contained in:
commit
34a61b40f4
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,11 +1,15 @@
|
||||
avatar/*
|
||||
files/*
|
||||
_darcs/*
|
||||
logs/*
|
||||
config.php
|
||||
.htaccess
|
||||
httpd.conf
|
||||
*.tmproj
|
||||
dataobject.ini
|
||||
*~
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
.#*
|
||||
*.swp
|
||||
|
54
EVENTS.txt
54
EVENTS.txt
@ -15,6 +15,24 @@ StartSecondaryNav: Showing the secondary nav menu
|
||||
EndSecondaryNav: At the end of the secondary nav menu
|
||||
- $action: the current action
|
||||
|
||||
StartShowStyles: Showing Style links; good place to add UA style resets
|
||||
- $action: the current action
|
||||
|
||||
EndShowStyles: End showing Style links; good place to add custom styles
|
||||
- $action: the current action
|
||||
|
||||
StartShowLaconicaStyles: Showing Laconica Style links
|
||||
- $action: the current action
|
||||
|
||||
EndShowLaconicaStyles: End showing Laconica Style links; good place to add handheld or JavaScript dependant styles
|
||||
- $action: the current action
|
||||
|
||||
StartShowUAStyles: Showing custom UA Style links
|
||||
- $action: the current action
|
||||
|
||||
EndShowUAStyles: End showing custom UA Style links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
|
||||
- $action: the current action
|
||||
|
||||
StartShowScripts: Showing JavaScript links
|
||||
- $action: the current action
|
||||
|
||||
@ -34,3 +52,39 @@ StartShowLaconicaScripts: Showing Laconica script links (use this to link to a C
|
||||
EndShowLaconicaScripts: End showing Laconica script links
|
||||
- $action: the current action
|
||||
|
||||
StartShowSections: Start the list of sections in the sidebar
|
||||
- $action: the current action
|
||||
|
||||
EndShowSections: End the list of sections in the sidebar
|
||||
- $action: the current action
|
||||
|
||||
StartShowHeader: Showing before the header container
|
||||
- $action: the current action
|
||||
|
||||
EndShowHeader: Showing after the header container
|
||||
- $action: the current action
|
||||
|
||||
StartShowFooter: Showing before the footer container
|
||||
- $action: the current action
|
||||
|
||||
EndShowFooter: Showing after the footer container
|
||||
- $action: the current action
|
||||
|
||||
StartShowContentBlock: Showing before the content container
|
||||
- $action: the current action
|
||||
|
||||
EndShowContentBlock: Showing after the content container
|
||||
- $action: the current action
|
||||
|
||||
StartNoticeSave: before inserting a notice (good place for content filters)
|
||||
- $notice: notice being saved (no ID or URI)
|
||||
|
||||
EndNoticeSave: after inserting a notice and related code
|
||||
- $notice: notice that was saved (with ID and URI)
|
||||
|
||||
StartShowLocalNavBlock: Showing the local nav menu
|
||||
- $action: the current action
|
||||
|
||||
EndShowLocalNavBlock: At the end of the local nav menu
|
||||
- $action: the current action
|
||||
|
||||
|
53
README
53
README
@ -511,7 +511,7 @@ server is probably a good idea for high-volume sites.
|
||||
needs as a parameter the install path; if you run it from the
|
||||
Laconica dir, "." should suffice.
|
||||
|
||||
This will run six (for now) queue handlers:
|
||||
This will run eight (for now) queue handlers:
|
||||
|
||||
* xmppdaemon.php - listens for new XMPP messages from users and stores
|
||||
them as notices in the database.
|
||||
@ -525,6 +525,10 @@ This will run six (for now) queue handlers:
|
||||
of registered users.
|
||||
* xmppconfirmhandler.php - sends confirmation messages to registered
|
||||
users.
|
||||
* twitterqueuehandler.php - sends queued notices to Twitter for user
|
||||
who have opted to set up Twitter bridging.
|
||||
* facebookqueuehandler.php - sends queued notices to Facebook for users
|
||||
of the built-in Facebook application.
|
||||
|
||||
Note that these queue daemons are pretty raw, and need your care. In
|
||||
particular, they leak memory, and you may want to restart them on a
|
||||
@ -557,6 +561,53 @@ Sample cron job:
|
||||
# Update Twitter friends subscriptions every half hour
|
||||
0,30 * * * * /path/to/php /path/to/laconica/scripts/synctwitterfriends.php>&/dev/null
|
||||
|
||||
Built-in Facebook Application
|
||||
-----------------------------
|
||||
|
||||
Laconica's Facebook application allows your users to automatically
|
||||
update their Facebook statuses with their latest notices, invite
|
||||
their friends to use the app (and thus your site), view their notice
|
||||
timelines, and post notices -- all from within Facebook. The application
|
||||
is built into Laconica and runs on your host. For automatic Facebook
|
||||
status updating to work you will need to enable queuing and run the
|
||||
facebookqueuehandler.php daemon (see the "Queues and daemons" section
|
||||
above).
|
||||
|
||||
Quick setup instructions*:
|
||||
|
||||
Install the Facebook Developer application on Facebook:
|
||||
|
||||
http://www.facebook.com/developers/
|
||||
|
||||
Use it to create a new application and generate an API key and secret.
|
||||
Uncomment the Facebook app section of your config.php and copy in the
|
||||
key and secret, e.g.:
|
||||
|
||||
# Config section for the built-in Facebook application
|
||||
$config['facebook']['apikey'] = 'APIKEY';
|
||||
$config['facebook']['secret'] = 'SECRET';
|
||||
|
||||
In Facebook's application editor, specify the following URLs for your app:
|
||||
|
||||
- Callback URL: http://example.net/mublog/facebook/
|
||||
- Post-Remove URL: http://example.net/mublog/facebook/remove
|
||||
- Post-Add Redirect URL: http://apps.facebook.com/yourapp/
|
||||
- Canvas URL: http://apps.facebook.com/yourapp/
|
||||
|
||||
(Replace 'example.net' with your host's URL, 'mublog' with the path
|
||||
to your Laconica installation, and 'yourapp' with the name of the
|
||||
Facebook application you created.)
|
||||
|
||||
Additionally, Choose "Web" for Application type in the Advanced tab.
|
||||
In the "Canvas setting" section, choose the "FBML" for Render Method,
|
||||
"Smart Size" for IFrame size, and "Full width (760px)" for Canvas Width.
|
||||
Everything else can be left with default values.
|
||||
|
||||
*For more detailed instructions please see the installation guide on the
|
||||
Laconica wiki:
|
||||
|
||||
http://laconi.ca/trac/wiki/FacebookApplication
|
||||
|
||||
Sitemaps
|
||||
--------
|
||||
|
||||
|
@ -69,13 +69,22 @@ class AllAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => common_local_url('allrss', array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => sprintf(_('Feed for friends of %s'), $this->user->nickname)));
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('allrss', array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api', array('apiaction' => 'statuses',
|
||||
'method' => 'friends',
|
||||
'argument' => $this->user->nickname.'.rss')),
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api', array('apiaction' => 'statuses',
|
||||
'method' => 'friends',
|
||||
'argument' => $this->user->nickname.'.atom')),
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)));
|
||||
}
|
||||
|
||||
function showLocalNav()
|
||||
@ -84,15 +93,6 @@ class AllAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
$fl->show(array(0=>array('href'=>common_local_url('allrss', array('nickname' => $this->user->nickname)),
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'allrss')));
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
|
@ -54,6 +54,8 @@ class AllrssAction extends Rss10Action
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
function prepare($args)
|
||||
@ -104,7 +106,8 @@ class AllrssAction extends Rss10Action
|
||||
'link' => common_local_url('all',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'description' => sprintf(_('Feed for friends of %s'), $user->nickname));
|
||||
'description' => sprintf(_('Feed for friends of %s'),
|
||||
$user->nickname));
|
||||
return $c;
|
||||
}
|
||||
|
||||
@ -123,10 +126,5 @@ class AllrssAction extends Rss10Action
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
return $avatar ? $avatar->url : null;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,14 +131,14 @@ class ApiAction extends Action
|
||||
'statuses/followers',
|
||||
'favorites/favorites');
|
||||
|
||||
# If the site is "private", all API methods need authentication
|
||||
|
||||
if (common_config('site', 'private')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fullname = "$this->api_action/$this->api_method";
|
||||
|
||||
// If the site is "private", all API methods except laconica/config
|
||||
// need authentication
|
||||
if (common_config('site', 'private')) {
|
||||
return $fullname != 'laconica/config' || false;
|
||||
}
|
||||
|
||||
if (in_array($fullname, $bareauth)) {
|
||||
# bareauth: only needs auth if without an argument
|
||||
if ($this->api_arg) {
|
||||
|
@ -145,6 +145,7 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$this->submit('delete', _('Delete'));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
@ -256,6 +257,8 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
$this->uploadAvatar();
|
||||
} else if ($this->arg('crop')) {
|
||||
$this->cropAvatar();
|
||||
} else if ($this->arg('delete')) {
|
||||
$this->deleteAvatar();
|
||||
} else {
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
}
|
||||
@ -345,6 +348,29 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rid of the current avatar.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function deleteAvatar()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$avatar = $profile->getOriginalAvatar();
|
||||
$avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
$avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||
$avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
|
||||
$avatar->delete();
|
||||
|
||||
$this->showForm(_('Avatar deleted.'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the jCrop stylesheet
|
||||
*
|
||||
|
@ -59,7 +59,7 @@ class DocAction extends Action
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->title = $this->trimmed('title');
|
||||
$this->filename = INSTALLDIR.'/doc/'.$this->title;
|
||||
$this->filename = INSTALLDIR.'/doc-src/'.$this->title;
|
||||
if (!file_exists($this->filename)) {
|
||||
$this->clientError(_('No such document.'));
|
||||
return;
|
||||
|
@ -164,6 +164,11 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||
$user->emailnotifymsg);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('emailnotifyattn',
|
||||
_('Send me email when someone sends me an "@-reply".'),
|
||||
$user->emailnotifyattn);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('emailnotifynudge',
|
||||
_('Allow friends to nudge me and send me an email.'),
|
||||
$user->emailnotifynudge);
|
||||
@ -255,6 +260,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||
$emailnotifyfav = $this->boolean('emailnotifyfav');
|
||||
$emailnotifymsg = $this->boolean('emailnotifymsg');
|
||||
$emailnotifynudge = $this->boolean('emailnotifynudge');
|
||||
$emailnotifyattn = $this->boolean('emailnotifyattn');
|
||||
$emailmicroid = $this->boolean('emailmicroid');
|
||||
$emailpost = $this->boolean('emailpost');
|
||||
|
||||
@ -270,6 +276,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||
$user->emailnotifyfav = $emailnotifyfav;
|
||||
$user->emailnotifymsg = $emailnotifymsg;
|
||||
$user->emailnotifynudge = $emailnotifynudge;
|
||||
$user->emailnotifyattn = $emailnotifyattn;
|
||||
$user->emailmicroid = $emailmicroid;
|
||||
$user->emailpost = $emailpost;
|
||||
|
||||
|
@ -83,7 +83,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if ($this->message_text) {
|
||||
if (!empty($this->message_text)) {
|
||||
$this->element('p', null, $this->message);
|
||||
return;
|
||||
}
|
||||
@ -232,7 +232,8 @@ class FinishopenidloginAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
if ($sreg['country']) {
|
||||
$location = '';
|
||||
if (!empty($sreg['country'])) {
|
||||
if ($sreg['postcode']) {
|
||||
# XXX: use postcode to get city and region
|
||||
# XXX: also, store postcode somewhere -- it's valuable!
|
||||
@ -242,12 +243,16 @@ class FinishopenidloginAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
if ($sreg['fullname'] && mb_strlen($sreg['fullname']) <= 255) {
|
||||
if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
|
||||
$fullname = $sreg['fullname'];
|
||||
} else {
|
||||
$fullname = '';
|
||||
}
|
||||
|
||||
if ($sreg['email'] && Validate::email($sreg['email'], true)) {
|
||||
if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
|
||||
$email = $sreg['email'];
|
||||
} else {
|
||||
$email = '';
|
||||
}
|
||||
|
||||
# XXX: add language
|
||||
@ -328,7 +333,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
# Try the passed-in nickname
|
||||
|
||||
if ($sreg['nickname']) {
|
||||
if (!empty($sreg['nickname'])) {
|
||||
$nickname = $this->nicknamize($sreg['nickname']);
|
||||
if ($this->isNewNickname($nickname)) {
|
||||
return $nickname;
|
||||
@ -337,7 +342,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
# Try the full name
|
||||
|
||||
if ($sreg['fullname']) {
|
||||
if (!empty($sreg['fullname'])) {
|
||||
$fullname = $this->nicknamize($sreg['fullname']);
|
||||
if ($this->isNewNickname($fullname)) {
|
||||
return $fullname;
|
||||
|
@ -237,7 +237,13 @@ class FinishremotesubscribeAction extends Action
|
||||
{
|
||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
|
||||
copy($url, $temp_filename);
|
||||
return $profile->setOriginal($temp_filename);
|
||||
$imagefile = new ImageFile($profile->id, $temp_filename);
|
||||
$filename = Avatar::filename($profile->id,
|
||||
image_type_to_extension($imagefile->type),
|
||||
null,
|
||||
common_timestamp());
|
||||
rename($temp_filename, Avatar::path($filename));
|
||||
return $profile->setOriginal($filename);
|
||||
}
|
||||
|
||||
function access_token($omb)
|
||||
|
@ -141,13 +141,4 @@ class groupRssAction extends Rss10Action
|
||||
{
|
||||
return $this->group->homepage_logo;
|
||||
}
|
||||
|
||||
# override parent to add X-SUP-ID URL
|
||||
|
||||
function initRss($limit=0)
|
||||
{
|
||||
$url = common_local_url('sup', null, $this->group->id);
|
||||
header('X-SUP-ID: '.$url);
|
||||
parent::initRss($limit);
|
||||
}
|
||||
}
|
||||
|
@ -108,13 +108,15 @@ class LoginAction extends Action
|
||||
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
||||
$password = $this->arg('password');
|
||||
|
||||
if (!common_check_user($nickname, $password)) {
|
||||
$user = common_check_user($nickname, $password);
|
||||
|
||||
if (!$user) {
|
||||
$this->showForm(_('Incorrect username or password.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// success!
|
||||
if (!common_set_user($nickname)) {
|
||||
if (!common_set_user($user)) {
|
||||
$this->serverError(_('Error setting user.'));
|
||||
return;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ class NewmessageAction extends Action
|
||||
|
||||
function showNoticeForm()
|
||||
{
|
||||
$message_form = new MessageForm($this, $this->to, $this->content);
|
||||
$message_form = new MessageForm($this, $this->other, $this->content);
|
||||
$message_form->show();
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,12 @@ class NewnoticeAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$this->saveNewNotice();
|
||||
try {
|
||||
$this->saveNewNotice();
|
||||
} catch (Exception $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
@ -123,15 +128,13 @@ class NewnoticeAction extends Action
|
||||
$content = $this->trimmed('status_textarea');
|
||||
|
||||
if (!$content) {
|
||||
$this->showForm(_('No content!'));
|
||||
return;
|
||||
$this->clientError(_('No content!'));
|
||||
} else {
|
||||
$content_shortened = common_shorten_links($content);
|
||||
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->showForm(_('That\'s too long. '.
|
||||
'Max notice size is 140 chars.'));
|
||||
return;
|
||||
$this->clientError(_('That\'s too long. '.
|
||||
'Max notice size is 140 chars.'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +157,7 @@ class NewnoticeAction extends Action
|
||||
($replyto == 'false') ? null : $replyto);
|
||||
|
||||
if (is_string($notice)) {
|
||||
$this->showForm($notice);
|
||||
$this->clientError($notice);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,20 @@ class NoticesearchAction extends SearchAction
|
||||
return _('Text search');
|
||||
}
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
$q = $this->trimmed('q');
|
||||
|
||||
if (!$q) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array(new Feed(Feed::RSS1, common_local_url('noticesearchrss',
|
||||
array('q' => $q)),
|
||||
sprintf(_('Search results for "%s" on %s'),
|
||||
$q, common_config('site', 'name'))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show results
|
||||
*
|
||||
@ -119,26 +133,6 @@ class NoticesearchAction extends SearchAction
|
||||
$page, 'noticesearch', array('q' => $q));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show header
|
||||
*
|
||||
* @param array $arr array containing the query
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
$q = $this->trimmed('q');
|
||||
if ($q) {
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => common_local_url('noticesearchrss',
|
||||
array('q' => $q)),
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => _('Search Stream Feed')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice
|
||||
*
|
||||
|
@ -92,27 +92,3 @@ class PeoplesearchAction extends SearchAction
|
||||
}
|
||||
}
|
||||
|
||||
class PeopleSearchResults extends ProfileList
|
||||
{
|
||||
var $terms = null;
|
||||
var $pattern = null;
|
||||
|
||||
function __construct($profile, $terms, $action)
|
||||
{
|
||||
parent::__construct($profile, $terms, $action);
|
||||
$this->terms = array_map('preg_quote',
|
||||
array_map('htmlspecialchars', $terms));
|
||||
$this->pattern = '/('.implode('|',$terms).')/i';
|
||||
}
|
||||
|
||||
function highlight($text)
|
||||
{
|
||||
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,12 +119,20 @@ class PublicAction extends Action
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => common_local_url('publicrss'),
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => _('Public Stream Feed')));
|
||||
return array(new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||
_('Public Stream Feed (RSS 1.0)')),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'public_timeline.rss')),
|
||||
_('Public Stream Feed (RSS 2.0)')),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'public_timeline.atom')),
|
||||
_('Public Stream Feed (Atom)')));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,27 +193,6 @@ class PublicAction extends Action
|
||||
$this->page, 'public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a list of exported feeds for this page
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @todo I18N
|
||||
*/
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
$fl->show(array(0 => array('href' => common_local_url('publicrss'),
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'publicrss'),
|
||||
1 => array('href' => common_local_url('publicatom'),
|
||||
'type' => 'atom',
|
||||
'version' => 'Atom 1.0',
|
||||
'item' => 'publicatom')));
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
// $top = new TopPostersSection($this);
|
||||
|
@ -129,16 +129,13 @@ class RepliesAction extends Action
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$rssurl = common_local_url('repliesrss',
|
||||
array('nickname' => $this->user->nickname));
|
||||
$rsstitle = sprintf(_('Feed for replies to %s'), $this->user->nickname);
|
||||
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => $rssurl,
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => $rsstitle));
|
||||
return array(new Feed(Feed::RSS1, $rssurl, $rsstitle));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,25 +150,6 @@ class RepliesAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the replies feed links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
|
||||
$rssurl = common_local_url('repliesrss',
|
||||
array('nickname' => $this->user->nickname));
|
||||
|
||||
$fl->show(array(0=>array('href'=> $rssurl,
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'repliesrss')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the content
|
||||
*
|
||||
|
@ -136,10 +136,10 @@ class ShowfavoritesAction extends Action
|
||||
/**
|
||||
* Feeds for the <head> section
|
||||
*
|
||||
* @return void
|
||||
* @return array Feed objects to show
|
||||
*/
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$feedurl = common_local_url('favoritesrss',
|
||||
array('nickname' =>
|
||||
@ -147,10 +147,7 @@ class ShowfavoritesAction extends Action
|
||||
$feedtitle = sprintf(_('Feed for favorites of %s'),
|
||||
$this->user->nickname);
|
||||
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => $feedurl,
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => $feedtitle));
|
||||
return array(new Feed(Feed::RSS1, $feedurl, $feedtitle));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,28 +162,6 @@ class ShowfavoritesAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the replies feed links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$feedurl = common_local_url('favoritesrss',
|
||||
array('nickname' =>
|
||||
$this->user->nickname));
|
||||
|
||||
$fl = new FeedList($this);
|
||||
|
||||
// XXX: I18N
|
||||
|
||||
$fl->show(array(0=>array('href'=> $feedurl,
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'Favorites')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the content
|
||||
*
|
||||
|
@ -244,7 +244,7 @@ class ShowgroupAction extends Action
|
||||
if ($this->group->location) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->element('dd', 'location', $this->group->location);
|
||||
$this->element('dd', 'label', $this->group->location);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
@ -292,37 +292,18 @@ class ShowgroupAction extends Action
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of links to feeds this page produces
|
||||
* Get a list of the feeds for this page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
$fl->show(array(0=>array('href'=>common_local_url('grouprss',
|
||||
array('nickname' => $this->group->nickname)),
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'notices')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of links to feeds this page produces
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$url =
|
||||
common_local_url('grouprss',
|
||||
array('nickname' => $this->group->nickname));
|
||||
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => $url,
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => sprintf(_('Notice feed for %s group'),
|
||||
return array(new Feed(Feed::RSS1, $url, sprintf(_('Notice feed for %s group'),
|
||||
$this->group->nickname)));
|
||||
}
|
||||
|
||||
|
@ -155,58 +155,39 @@ class ShowstreamAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
function showExportData()
|
||||
function getFeeds()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
$fl->show(array(0=>array('href'=>common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'notices'),
|
||||
1=>array('href'=>common_local_url('usertimeline',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
'type' => 'atom',
|
||||
'version' => 'Atom 1.0',
|
||||
'item' => 'usertimeline'),
|
||||
2=>array('href'=>common_local_url('foaf',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
'type' => 'rdf',
|
||||
'version' => 'FOAF',
|
||||
'item' => 'foaf')));
|
||||
}
|
||||
|
||||
function showFeeds()
|
||||
{
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'type' => 'application/rss+xml',
|
||||
'href' => common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
'title' => sprintf(_('Notice feed for %s (RSS)'),
|
||||
$this->user->nickname)));
|
||||
|
||||
$this->element('link',
|
||||
array('rel' => 'alternate',
|
||||
'href' => common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline.atom',
|
||||
'argument' => $this->user->nickname)),
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => sprintf(_('Notice feed for %s (Atom)'),
|
||||
$this->user->nickname)));
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
sprintf(_('Notice feed for %s (RSS 1.0)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline',
|
||||
'argument' => $this->user->nickname.'.rss')),
|
||||
sprintf(_('Notice feed for %s (RSS 2.0)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline',
|
||||
'argument' => $this->user->nickname.'.atom')),
|
||||
sprintf(_('Notice feed for %s (Atom)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::FOAF,
|
||||
common_local_url('foaf', array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
sprintf(_('FOAF for %s'), $this->user->nickname)));
|
||||
}
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
// FOAF
|
||||
$this->element('link', array('rel' => 'meta',
|
||||
'href' => common_local_url('foaf', array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
'type' => 'application/rdf+xml',
|
||||
'title' => 'FOAF'));
|
||||
// for remote subscriptions etc.
|
||||
$this->element('meta', array('http-equiv' => 'X-XRDS-Location',
|
||||
'content' => common_local_url('xrds', array('nickname' =>
|
||||
$this->user->nickname))));
|
||||
$this->user->nickname))));
|
||||
|
||||
if ($this->profile->bio) {
|
||||
$this->element('meta', array('name' => 'description',
|
||||
@ -248,6 +229,15 @@ class ShowstreamAction extends Action
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $this->profile->nickname));
|
||||
$this->elementEnd('dd');
|
||||
|
||||
$user = User::staticGet('id', $this->profile->id);
|
||||
$cur = common_current_user();
|
||||
if ($cur && $cur->id == $user->id) {
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
|
||||
$this->elementEnd('dd');
|
||||
}
|
||||
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_nickname');
|
||||
@ -256,7 +246,7 @@ class ShowstreamAction extends Action
|
||||
$hasFN = ($this->profile->fullname) ? 'nickname url uid' : 'fn nickname url uid';
|
||||
$this->element('a', array('href' => $this->profile->profileurl,
|
||||
'rel' => 'me', 'class' => $hasFN),
|
||||
$this->profile->nickname);
|
||||
$this->profile->nickname);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
@ -272,7 +262,7 @@ class ShowstreamAction extends Action
|
||||
if ($this->profile->location) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->element('dd', 'location', $this->profile->location);
|
||||
$this->element('dd', 'label', $this->profile->location);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
@ -302,11 +292,11 @@ class ShowstreamAction extends Action
|
||||
$this->elementStart('ul', 'tags xoxo');
|
||||
foreach ($tags as $tag) {
|
||||
$this->elementStart('li');
|
||||
$this->element('span', 'mark_hash', '#');
|
||||
$this->element('a', array('rel' => 'tag',
|
||||
'href' => common_local_url('peopletag',
|
||||
array('tag' => $tag))),
|
||||
$tag);
|
||||
// Avoid space by using raw output.
|
||||
$pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
|
||||
common_local_url('peopletag', array('tag' => $tag)) .
|
||||
'">' . $tag . '</a>';
|
||||
$this->raw($pt);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
@ -324,7 +314,7 @@ class ShowstreamAction extends Action
|
||||
$this->elementStart('li', 'entity_edit');
|
||||
$this->element('a', array('href' => common_local_url('profilesettings'),
|
||||
'title' => _('Edit profile settings')),
|
||||
_('Edit'));
|
||||
_('Edit'));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
@ -346,9 +336,8 @@ class ShowstreamAction extends Action
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
$user = User::staticGet('id', $this->profile->id);
|
||||
if ($cur && $cur->id != $user->id && $cur->mutuallySubscribed($user)) {
|
||||
$this->elementStart('li', 'entity_send-a-message');
|
||||
$this->elementStart('li', 'entity_send-a-message');
|
||||
$this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)),
|
||||
'title' => _('Send a direct message to this user')),
|
||||
_('Message'));
|
||||
@ -490,7 +479,7 @@ class ShowstreamAction extends Action
|
||||
$this->elementStart('dl', 'entity_member-since');
|
||||
$this->element('dt', null, _('Member since'));
|
||||
$this->element('dd', null, date('j M Y',
|
||||
strtotime($this->profile->created)));
|
||||
strtotime($this->profile->created)));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_subscriptions');
|
||||
|
@ -61,12 +61,11 @@ class TagAction extends Action
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showFeeds()
|
||||
function getFeeds()
|
||||
{
|
||||
$this->element('link', array('rel' => 'alternate',
|
||||
'href' => common_local_url('tagrss', array('tag' => $this->tag)),
|
||||
'type' => 'application/rss+xml',
|
||||
'title' => sprintf(_('Feed for tag %s'), $this->tag)));
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('tagrss', array('tag' => $this->tag)),
|
||||
sprintf(_('Feed for tag %s'), $this->tag)));
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
@ -74,15 +73,6 @@ class TagAction extends Action
|
||||
return sprintf(_('Messages tagged "%s", most recent first'), $this->tag);
|
||||
}
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
$fl = new FeedList($this);
|
||||
$fl->show(array(0=>array('href'=>common_local_url('tagrss', array('tag' => $this->tag)),
|
||||
'type' => 'rss',
|
||||
'version' => 'RSS 1.0',
|
||||
'item' => 'tagrss')));
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
|
@ -110,7 +110,7 @@ class TagotherAction extends Action
|
||||
if ($this->profile->location) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->element('dd', 'location', $this->profile->location);
|
||||
$this->element('dd', 'label', $this->profile->location);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
if ($this->profile->homepage) {
|
||||
@ -135,7 +135,8 @@ class TagotherAction extends Action
|
||||
'id' => 'form_tag_user',
|
||||
'class' => 'form_settings',
|
||||
'name' => 'tagother',
|
||||
'action' => $this->selfUrl()));
|
||||
'action' => common_local_url('tagother', array('id' => $this->profile->id))));
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Tag user'));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
@ -24,20 +24,19 @@ require_once(INSTALLDIR.'/lib/twitterapi.php');
|
||||
class TwitapiaccountAction extends TwitterapiAction
|
||||
{
|
||||
|
||||
function verify_credentials($args, $apidata)
|
||||
function verify_credentials($args, $apidata)
|
||||
{
|
||||
|
||||
if ($apidata['content-type'] == 'xml') {
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
print '<authorized>true</authorized>';
|
||||
} elseif ($apidata['content-type'] == 'json') {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
print '{"authorized":true}';
|
||||
} else {
|
||||
common_user_error(_('API method not found!'), $code=404);
|
||||
}
|
||||
|
||||
}
|
||||
if ($apidata['content-type'] == 'xml') {
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
print '<authorized>true</authorized>';
|
||||
} elseif ($apidata['content-type'] == 'json') {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
print '{"authorized":true}';
|
||||
} else {
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print 'Authorized';
|
||||
}
|
||||
}
|
||||
|
||||
function end_session($args, $apidata)
|
||||
{
|
||||
|
@ -204,7 +204,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
# FriendFeed's SUP protocol
|
||||
# Also added RSS and Atom feeds
|
||||
|
||||
$suplink = common_local_url('sup', null, $user->id);
|
||||
$suplink = common_local_url('sup', null, null, $user->id);
|
||||
header('X-SUP-ID: '.$suplink);
|
||||
|
||||
# XXX: since
|
||||
@ -470,19 +470,28 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber');
|
||||
}
|
||||
|
||||
function friendsIDs($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber', true);
|
||||
}
|
||||
|
||||
function followers($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed');
|
||||
}
|
||||
|
||||
function subscriptions($apidata, $other_attr, $user_attr)
|
||||
function followersIDs($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed', true);
|
||||
}
|
||||
|
||||
function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false)
|
||||
{
|
||||
|
||||
# XXX: lite
|
||||
|
||||
$this->auth_user = $apidate['user'];
|
||||
$this->auth_user = $apidata['user'];
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
|
||||
if (!$user) {
|
||||
@ -514,7 +523,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
}
|
||||
|
||||
$sub->orderBy('created DESC');
|
||||
$sub->limit(($page-1)*100, 100);
|
||||
|
||||
if (!$onlyIDs) {
|
||||
$sub->limit(($page-1)*100, 100);
|
||||
}
|
||||
|
||||
$others = array();
|
||||
|
||||
@ -529,7 +541,13 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$type = $apidata['content-type'];
|
||||
|
||||
$this->init_document($type);
|
||||
$this->show_profiles($others, $type);
|
||||
|
||||
if ($onlyIDs) {
|
||||
$this->showIDs($others, $type);
|
||||
} else {
|
||||
$this->show_profiles($others, $type);
|
||||
}
|
||||
|
||||
$this->end_document($type);
|
||||
}
|
||||
|
||||
@ -555,6 +573,28 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
}
|
||||
}
|
||||
|
||||
function showIDs($profiles, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'xml':
|
||||
$this->elementStart('ids');
|
||||
foreach ($profiles as $profile) {
|
||||
$this->element('id', null, $profile->id);
|
||||
}
|
||||
$this->elementEnd('ids');
|
||||
break;
|
||||
case 'json':
|
||||
$ids = array();
|
||||
foreach ($profiles as $profile) {
|
||||
$ids[] = (int)$profile->id;
|
||||
}
|
||||
print json_encode($ids);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('unsupported file type'));
|
||||
}
|
||||
}
|
||||
|
||||
function featured($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
@ -32,6 +32,7 @@ if (!defined('LACONICA')) {
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/connectsettingsaction.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
define('SUBSCRIPTIONS', 80);
|
||||
|
||||
@ -90,7 +91,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$fuser = null;
|
||||
|
||||
$flink = Foreign_link::getByUserID($user->id, 1); // 1 == Twitter
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
if ($flink) {
|
||||
$fuser = $flink->getForeignUser();
|
||||
@ -358,7 +359,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$flink->user_id = $user->id;
|
||||
$flink->foreign_id = $twit_user->id;
|
||||
$flink->service = 1; // Twitter
|
||||
$flink->service = TWITTER_SERVICE;
|
||||
$flink->credentials = $password;
|
||||
$flink->created = common_sql_now();
|
||||
|
||||
|
@ -330,7 +330,13 @@ class UserauthorizationAction extends Action
|
||||
{
|
||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
|
||||
copy($url, $temp_filename);
|
||||
return $profile->setOriginal($temp_filename);
|
||||
$imagefile = new ImageFile($profile->id, $temp_filename);
|
||||
$filename = Avatar::filename($profile->id,
|
||||
image_type_to_extension($imagefile->type),
|
||||
null,
|
||||
common_timestamp());
|
||||
rename($temp_filename, Avatar::path($filename));
|
||||
return $profile->setOriginal($filename);
|
||||
}
|
||||
|
||||
function showAcceptMessage($tok)
|
||||
|
@ -90,7 +90,7 @@ class UserrssAction extends Rss10Action
|
||||
|
||||
function initRss($limit=0)
|
||||
{
|
||||
$url = common_local_url('sup', null, $this->user->id);
|
||||
$url = common_local_url('sup', null, null, $this->user->id);
|
||||
header('X-SUP-ID: '.$url);
|
||||
parent::initRss($limit);
|
||||
}
|
||||
@ -100,4 +100,3 @@ class UserrssAction extends Rss10Action
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
BIN
bin/flowplayer-3.0.5.swf
Normal file
BIN
bin/flowplayer-3.0.5.swf
Normal file
Binary file not shown.
BIN
bin/flowplayer.audio-3.0.3.swf
Normal file
BIN
bin/flowplayer.audio-3.0.3.swf
Normal file
Binary file not shown.
BIN
bin/flowplayer.controls-3.0.3.swf
Normal file
BIN
bin/flowplayer.controls-3.0.3.swf
Normal file
Binary file not shown.
@ -34,22 +34,23 @@ class Notice extends Memcached_DataObject
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'notice'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $__table = 'notice'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $content; // varchar(140)
|
||||
public $rendered; // text()
|
||||
public $rendered; // text()
|
||||
public $url; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $reply_to; // int(4)
|
||||
public $is_local; // tinyint(1)
|
||||
public $source; // varchar(32)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $reply_to; // int(4)
|
||||
public $is_local; // tinyint(1)
|
||||
public $source; // varchar(32)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Notice',$k,$v); }
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Notice',$k,$v);
|
||||
}
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
@ -94,23 +95,28 @@ class Notice extends Memcached_DataObject
|
||||
/* Add them to the database */
|
||||
foreach(array_unique($match[1]) as $hashtag) {
|
||||
/* elide characters we don't want in the tag */
|
||||
$hashtag = common_canonical_tag($hashtag);
|
||||
|
||||
$tag = DB_DataObject::factory('Notice_tag');
|
||||
$tag->notice_id = $this->id;
|
||||
$tag->tag = $hashtag;
|
||||
$tag->created = $this->created;
|
||||
$id = $tag->insert();
|
||||
if (!$id) {
|
||||
$last_error = PEAR::getStaticProperty('DB_DataObject','lastError');
|
||||
common_log(LOG_ERR, 'DB error inserting hashtag: ' . $last_error->message);
|
||||
common_server_error(sprintf(_('DB error inserting hashtag: %s'), $last_error->message));
|
||||
return;
|
||||
}
|
||||
$this->saveTag($hashtag);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function saveTag($hashtag)
|
||||
{
|
||||
$hashtag = common_canonical_tag($hashtag);
|
||||
|
||||
$tag = new Notice_tag();
|
||||
$tag->notice_id = $this->id;
|
||||
$tag->tag = $hashtag;
|
||||
$tag->created = $this->created;
|
||||
$id = $tag->insert();
|
||||
|
||||
if (!$id) {
|
||||
throw new ServerException(sprintf(_('DB error inserting hashtag: %s'),
|
||||
$last_error->message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static function saveNew($profile_id, $content, $source=null, $is_local=1, $reply_to=null, $uri=null) {
|
||||
|
||||
$profile = Profile::staticGet($profile_id);
|
||||
@ -136,10 +142,12 @@ class Notice extends Memcached_DataObject
|
||||
$notice->profile_id = $profile_id;
|
||||
|
||||
$blacklist = common_config('public', 'blacklist');
|
||||
$autosource = common_config('public', 'autosource');
|
||||
|
||||
# Blacklisted are non-false, but not 1, either
|
||||
|
||||
if ($blacklist && in_array($profile_id, $blacklist)) {
|
||||
if (($blacklist && in_array($profile_id, $blacklist)) ||
|
||||
($source && $autosource && in_array($source, $autosource))) {
|
||||
$notice->is_local = -1;
|
||||
} else {
|
||||
$notice->is_local = $is_local;
|
||||
@ -154,33 +162,38 @@ class Notice extends Memcached_DataObject
|
||||
$notice->source = $source;
|
||||
$notice->uri = $uri;
|
||||
|
||||
$id = $notice->insert();
|
||||
if (Event::handle('StartNoticeSave', array(&$notice))) {
|
||||
|
||||
if (!$id) {
|
||||
common_log_db_error($notice, 'INSERT', __FILE__);
|
||||
return _('Problem saving notice.');
|
||||
}
|
||||
$id = $notice->insert();
|
||||
|
||||
# Update the URI after the notice is in the database
|
||||
if (!$uri) {
|
||||
$orig = clone($notice);
|
||||
$notice->uri = common_notice_uri($notice);
|
||||
|
||||
if (!$notice->update($orig)) {
|
||||
common_log_db_error($notice, 'UPDATE', __FILE__);
|
||||
if (!$id) {
|
||||
common_log_db_error($notice, 'INSERT', __FILE__);
|
||||
return _('Problem saving notice.');
|
||||
}
|
||||
|
||||
# Update the URI after the notice is in the database
|
||||
if (!$uri) {
|
||||
$orig = clone($notice);
|
||||
$notice->uri = common_notice_uri($notice);
|
||||
|
||||
if (!$notice->update($orig)) {
|
||||
common_log_db_error($notice, 'UPDATE', __FILE__);
|
||||
return _('Problem saving notice.');
|
||||
}
|
||||
}
|
||||
|
||||
# XXX: do we need to change this for remote users?
|
||||
|
||||
$notice->saveReplies();
|
||||
$notice->saveTags();
|
||||
$notice->saveGroups();
|
||||
|
||||
$notice->addToInboxes();
|
||||
$notice->query('COMMIT');
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
}
|
||||
|
||||
# XXX: do we need to change this for remote users?
|
||||
|
||||
$notice->saveReplies();
|
||||
$notice->saveTags();
|
||||
$notice->saveGroups();
|
||||
|
||||
$notice->addToInboxes();
|
||||
$notice->query('COMMIT');
|
||||
|
||||
# Clear the cache for subscribed users, so they'll update at next request
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
|
||||
@ -614,6 +627,15 @@ class Notice extends Memcached_DataObject
|
||||
continue;
|
||||
}
|
||||
|
||||
// we automatically add a tag for every group name, too
|
||||
|
||||
$tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname),
|
||||
'notice_id' => $this->id));
|
||||
|
||||
if (is_null($tag)) {
|
||||
$this->saveTag($nickname);
|
||||
}
|
||||
|
||||
if ($profile->isMember($group)) {
|
||||
|
||||
$gi = new Group_inbox();
|
||||
@ -725,10 +747,19 @@ class Notice extends Memcached_DataObject
|
||||
if (!$id) {
|
||||
common_log_db_error($reply, 'INSERT', __FILE__);
|
||||
return;
|
||||
} else {
|
||||
$replied[$recipient->id] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($replied) as $recipient) {
|
||||
$user = User::staticGet('id', $recipient);
|
||||
if ($user) {
|
||||
mail_notify_attn($user, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,4 +54,9 @@ class Notice_tag extends Memcached_DataObject
|
||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $this->tag));
|
||||
}
|
||||
}
|
||||
|
||||
function &pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Notice_tag', $kv);
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ class User extends Memcached_DataObject
|
||||
public $emailnotifyfav; // tinyint(1) default_1
|
||||
public $emailnotifynudge; // tinyint(1) default_1
|
||||
public $emailnotifymsg; // tinyint(1) default_1
|
||||
public $emailnotifyattn; // tinyint(1) default_1
|
||||
public $emailmicroid; // tinyint(1) default_1
|
||||
public $language; // varchar(50)
|
||||
public $timezone; // varchar(50)
|
||||
@ -62,8 +63,10 @@ class User extends Memcached_DataObject
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('User',$k,$v); }
|
||||
function staticGet($k,$v=NULL)
|
||||
{
|
||||
return Memcached_DataObject::staticGet('User',$k,$v);
|
||||
}
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
@ -180,16 +183,16 @@ class User extends Memcached_DataObject
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = common_profile_url($nickname);
|
||||
|
||||
if ($fullname) {
|
||||
if (!empty($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if ($homepage) {
|
||||
if (!empty($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if ($bio) {
|
||||
if (!empty($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if ($location) {
|
||||
if (!empty($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
@ -197,7 +200,7 @@ class User extends Memcached_DataObject
|
||||
|
||||
$id = $profile->insert();
|
||||
|
||||
if (!$id) {
|
||||
if (empty($id)) {
|
||||
common_log_db_error($profile, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
@ -207,13 +210,13 @@ class User extends Memcached_DataObject
|
||||
$user->id = $id;
|
||||
$user->nickname = $nickname;
|
||||
|
||||
if ($password) { # may not have a password for OpenID users
|
||||
if (!empty($password)) { # may not have a password for OpenID users
|
||||
$user->password = common_munge_password($password, $id);
|
||||
}
|
||||
|
||||
# Users who respond to invite email have proven their ownership of that address
|
||||
|
||||
if ($code) {
|
||||
if (!empty($code)) {
|
||||
$invite = Invitation::staticGet($code);
|
||||
if ($invite && $invite->address && $invite->address_type == 'email' && $invite->address == $email) {
|
||||
$user->email = $invite->address;
|
||||
@ -250,7 +253,7 @@ class User extends Memcached_DataObject
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($email && !$user->email) {
|
||||
if (!empty($email) && !$user->email) {
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
$confirm->code = common_confirmation_code(128);
|
||||
@ -265,7 +268,7 @@ class User extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
if ($code && $user->email) {
|
||||
if (!empty($code) && $user->email) {
|
||||
$user->emailChanged();
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,8 @@ created = 142
|
||||
modified = 384
|
||||
|
||||
[sms_carrier__keys]
|
||||
id = N
|
||||
id = K
|
||||
name = U
|
||||
|
||||
[subscription]
|
||||
subscriber = 129
|
||||
@ -331,6 +332,7 @@ emailnotifysub = 17
|
||||
emailnotifyfav = 17
|
||||
emailnotifynudge = 17
|
||||
emailnotifymsg = 17
|
||||
emailnotifyattn = 17
|
||||
emailmicroid = 17
|
||||
language = 2
|
||||
timezone = 2
|
||||
|
@ -18,6 +18,8 @@ $config['site']['server'] = 'localhost';
|
||||
$config['site']['path'] = 'laconica';
|
||||
#$config['site']['fancy'] = false;
|
||||
#$config['site']['theme'] = 'default';
|
||||
#To enable the built-in mobile style sheet, defaults to false.
|
||||
#$config['site']['mobile'] = true;
|
||||
#For contact email, defaults to $_SERVER["SERVER_ADMIN"]
|
||||
#$config['site']['email'] = 'admin@example.net';
|
||||
#Brought by...
|
||||
@ -107,6 +109,14 @@ $config['sphinx']['port'] = 3312;
|
||||
#$config['public']['blacklist'][] = 123;
|
||||
#$config['public']['blacklist'][] = 2307;
|
||||
|
||||
#Mark certain notice sources as automatic and thus not
|
||||
#appropriate for public feed
|
||||
#$config['public]['autosource'][] = 'twitterfeed';
|
||||
#$config['public]['autosource'][] = 'rssdent';
|
||||
#$config['public]['autosource'][] = 'Ping.Fm';
|
||||
#$config['public]['autosource'][] = 'HelloTxt';
|
||||
#$config['public]['autosource'][] = 'Updating.Me';
|
||||
|
||||
#Do notice broadcasts offline
|
||||
#If you use this, you must run the six offline daemons in the
|
||||
#background. See the README for details.
|
||||
@ -139,7 +149,7 @@ $config['sphinx']['port'] = 3312;
|
||||
#$config['profile']['banned'][] = 'hacker';
|
||||
#$config['profile']['banned'][] = 12345;
|
||||
|
||||
# config section for the built-in Facebook application
|
||||
# Config section for the built-in Facebook application
|
||||
#$config['facebook']['apikey'] = 'APIKEY';
|
||||
#$config['facebook']['secret'] = 'SECRET';
|
||||
|
||||
|
@ -1,61 +0,0 @@
|
||||
insert into sms_carrier
|
||||
(name, email_pattern, created)
|
||||
values
|
||||
('3 River Wireless', '%s@sms.3rivers.net', now()),
|
||||
('7-11 Speakout', '%s@cingularme.com', now()),
|
||||
('Airtel (Karnataka, India)', '%s@airtelkk.com', now()),
|
||||
('Alaska Communications Systems', '%s@msg.acsalaska.com', now()),
|
||||
('Alltel Wireless', '%s@message.alltel.com', now()),
|
||||
('AT&T Wireless', '%s@txt.att.net', now()),
|
||||
('Bell Mobility (Canada)', '%s@txt.bell.ca', now()),
|
||||
('Boost Mobile', '%s@myboostmobile.com', now()),
|
||||
('Cellular One (Dobson)', '%s@mobile.celloneusa.com', now()),
|
||||
('Cincinnati Bell Wireless', '%s@gocbw.com', now()),
|
||||
('Cingular (Postpaid)', '%s@cingularme.com', now()),
|
||||
('Centennial Wireless', '%s@cwemail.com', now()),
|
||||
('Cingular (GoPhone prepaid)', '%s@cingularme.com', now()),
|
||||
('Claro (Nicaragua)', '%s@ideasclaro-ca.com', now()),
|
||||
('Comcel', '%s@comcel.com.co', now()),
|
||||
('Cricket', '%s@sms.mycricket.com', now()),
|
||||
('CTI', '%s@sms.ctimovil.com.ar', now()),
|
||||
('Emtel (Mauritius)', '%s@emtelworld.net', now()),
|
||||
('Fido (Canada)', '%s@fido.ca', now()),
|
||||
('General Communications Inc.', '%s@msg.gci.net', now()),
|
||||
('Globalstar', '%s@msg.globalstarusa.com', now()),
|
||||
('Helio', '%s@myhelio.com', now()),
|
||||
('Illinois Valley Cellular', '%s@ivctext.com', now()),
|
||||
('i wireless', '%s.iws@iwspcs.net', now()),
|
||||
('Meteor (Ireland)', '%s@sms.mymeteor.ie', now()),
|
||||
('Mero Mobile (Nepal)', '%s@sms.spicenepal.com', now()),
|
||||
('MetroPCS', '%s@mymetropcs.com', now()),
|
||||
('Movicom', '%s@movimensaje.com.ar', now()),
|
||||
('Mobitel (Sri Lanka)', '%s@sms.mobitel.lk', now()),
|
||||
('Movistar (Colombia)', '%s@movistar.com.co', now()),
|
||||
('MTN (South Africa)', '%s@sms.co.za', now()),
|
||||
('MTS (Canada)', '%s@text.mtsmobility.com', now()),
|
||||
('Nextel (Argentina)', '%s@nextel.net.ar', now()),
|
||||
('Orange (Poland)', '%s@orange.pl', now()),
|
||||
('Orange (UK)', '%s@orange.net', now()),
|
||||
('Personal (Argentina)', '%s@personal-net.com.ar', now()),
|
||||
('Plus GSM (Poland)', '%s@text.plusgsm.pl', now()),
|
||||
('President''s Choice (Canada)', '%s@txt.bell.ca', now()),
|
||||
('Qwest', '%s@qwestmp.com', now()),
|
||||
('Rogers (Canada)', '%s@pcs.rogers.com', now()),
|
||||
('Sasktel (Canada)', '%s@sms.sasktel.com', now()),
|
||||
('Setar Mobile email (Aruba)', '%s@mas.aw', now()),
|
||||
('Solo Mobile', '%s@txt.bell.ca', now()),
|
||||
('Sprint (PCS)', '%s@messaging.sprintpcs.com', now()),
|
||||
('Sprint (Nextel)', '%s@page.nextel.com', now()),
|
||||
('Suncom', '%s@tms.suncom.com', now()),
|
||||
('T-Mobile', '%s@tmomail.net', now()),
|
||||
('T-Mobile (Austria)', '%s@sms.t-mobile.at', now()),
|
||||
('Telus Mobility (Canada)', '%s@msg.telus.com', now()),
|
||||
('Thumb Cellular', '%s@sms.thumbcellular.com', now()),
|
||||
('Tigo (Formerly Ola)', '%s@sms.tigo.com.co', now()),
|
||||
('Unicel', '%s@utext.com', now()),
|
||||
('US Cellular', '%s@email.uscc.net', now()),
|
||||
('Verizon', '%s@vtext.com', now()),
|
||||
('Virgin Mobile (Canada)', '%s@vmobile.ca', now()),
|
||||
('Virgin Mobile (USA)', '%s@vmobl.com', now()),
|
||||
('Vodafone NZ (txt ''R'' to 901 to enable first)', '%s@sms.vodafone.net.nz', now()),
|
||||
('YCC', '%s@sms.ycc.ru', now());
|
@ -31,7 +31,7 @@ create table avatar (
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table sms_carrier (
|
||||
id integer auto_increment primary key comment 'primary key for SMS carrier',
|
||||
id integer primary key comment 'primary key for SMS carrier',
|
||||
name varchar(64) unique key comment 'name of the carrier',
|
||||
email_pattern varchar(255) not null comment 'sprintf pattern for making an email address from a phone number',
|
||||
created datetime not null comment 'date this record was created',
|
||||
@ -50,6 +50,7 @@ create table user (
|
||||
emailnotifyfav tinyint default 1 comment 'Notify by email of favorites',
|
||||
emailnotifynudge tinyint default 1 comment 'Notify by email of nudges',
|
||||
emailnotifymsg tinyint default 1 comment 'Notify by email of direct messages',
|
||||
emailnotifyattn tinyint default 1 comment 'Notify by email of @-replies',
|
||||
emailmicroid tinyint default 1 comment 'whether to publish email microid',
|
||||
language varchar(50) comment 'preferred language',
|
||||
timezone varchar(50) comment 'timezone',
|
||||
@ -260,7 +261,8 @@ create table notice_tag (
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
||||
constraint primary key (tag, notice_id),
|
||||
index notice_tag_created_idx (created)
|
||||
index notice_tag_created_idx (created),
|
||||
index notice_tag_notice_id_idx (notice_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
/* Synching with foreign services */
|
||||
@ -358,7 +360,8 @@ create table profile_tag (
|
||||
|
||||
constraint primary key (tagger, tagged, tag),
|
||||
index profile_tag_modified_idx (modified),
|
||||
index profile_tag_tagger_tag_idx (tagger, tag)
|
||||
index profile_tag_tagger_tag_idx (tagger, tag),
|
||||
index profile_tag_tagged_idx (tagged)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table profile_block (
|
||||
@ -402,7 +405,9 @@ create table group_member (
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
constraint primary key (group_id, profile_id)
|
||||
constraint primary key (group_id, profile_id),
|
||||
index group_member_profile_id_idx (profile_id),
|
||||
index group_member_created_idx (created)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
|
63
db/sms_carrier.sql
Normal file
63
db/sms_carrier.sql
Normal file
@ -0,0 +1,63 @@
|
||||
INSERT INTO sms_carrier
|
||||
(id, name, email_pattern, created)
|
||||
VALUES
|
||||
(100056, '3 River Wireless', '%s@sms.3rivers.net', now()),
|
||||
(100057, '7-11 Speakout', '%s@cingularme.com', now()),
|
||||
(100058, 'Airtel (Karnataka, India)', '%s@airtelkk.com', now()),
|
||||
(100059, 'Alaska Communications Systems', '%s@msg.acsalaska.com', now()),
|
||||
(100060, 'Alltel Wireless', '%s@message.alltel.com', now()),
|
||||
(100061, 'AT&T Wireless', '%s@txt.att.net', now()),
|
||||
(100062, 'Bell Mobility (Canada)', '%s@txt.bell.ca', now()),
|
||||
(100063, 'Boost Mobile', '%s@myboostmobile.com', now()),
|
||||
(100064, 'Cellular One (Dobson)', '%s@mobile.celloneusa.com', now()),
|
||||
(100065, 'Cingular (Postpaid)', '%s@cingularme.com', now()),
|
||||
(100066, 'Centennial Wireless', '%s@cwemail.com', now()),
|
||||
(100067, 'Cingular (GoPhone prepaid)', '%s@cingularme.com', now()),
|
||||
(100068, 'Claro (Nicaragua)', '%s@ideasclaro-ca.com', now()),
|
||||
(100069, 'Comcel', '%s@comcel.com.co', now()),
|
||||
(100070, 'Cricket', '%s@sms.mycricket.com', now()),
|
||||
(100071, 'CTI', '%s@sms.ctimovil.com.ar', now()),
|
||||
(100072, 'Emtel (Mauritius)', '%s@emtelworld.net', now()),
|
||||
(100073, 'Fido (Canada)', '%s@fido.ca', now()),
|
||||
(100074, 'General Communications Inc.', '%s@msg.gci.net', now()),
|
||||
(100075, 'Globalstar', '%s@msg.globalstarusa.com', now()),
|
||||
(100076, 'Helio', '%s@myhelio.com', now()),
|
||||
(100077, 'Illinois Valley Cellular', '%s@ivctext.com', now()),
|
||||
(100078, 'i wireless', '%s.iws@iwspcs.net', now()),
|
||||
(100079, 'Meteor (Ireland)', '%s@sms.mymeteor.ie', now()),
|
||||
(100080, 'Mero Mobile (Nepal)', '%s@sms.spicenepal.com', now()),
|
||||
(100081, 'MetroPCS', '%s@mymetropcs.com', now()),
|
||||
(100082, 'Movicom', '%s@movimensaje.com.ar', now()),
|
||||
(100083, 'Mobitel (Sri Lanka)', '%s@sms.mobitel.lk', now()),
|
||||
(100084, 'Movistar (Colombia)', '%s@movistar.com.co', now()),
|
||||
(100085, 'MTN (South Africa)', '%s@sms.co.za', now()),
|
||||
(100086, 'MTS (Canada)', '%s@text.mtsmobility.com', now()),
|
||||
(100087, 'Nextel (Argentina)', '%s@nextel.net.ar', now()),
|
||||
(100088, 'Orange (Poland)', '%s@orange.pl', now()),
|
||||
(100089, 'Personal (Argentina)', '%s@personal-net.com.ar', now()),
|
||||
(100090, 'Plus GSM (Poland)', '%s@text.plusgsm.pl', now()),
|
||||
(100091, 'President\'s Choice (Canada)', '%s@txt.bell.ca', now()),
|
||||
(100092, 'Qwest', '%s@qwestmp.com', now()),
|
||||
(100093, 'Rogers (Canada)', '%s@pcs.rogers.com', now()),
|
||||
(100094, 'Sasktel (Canada)', '%s@sms.sasktel.com', now()),
|
||||
(100095, 'Setar Mobile email (Aruba)', '%s@mas.aw', now()),
|
||||
(100096, 'Solo Mobile', '%s@txt.bell.ca', now()),
|
||||
(100097, 'Sprint (PCS)', '%s@messaging.sprintpcs.com', now()),
|
||||
(100098, 'Sprint (Nextel)', '%s@page.nextel.com', now()),
|
||||
(100099, 'Suncom', '%s@tms.suncom.com', now()),
|
||||
(100100, 'T-Mobile', '%s@tmomail.net', now()),
|
||||
(100101, 'T-Mobile (Austria)', '%s@sms.t-mobile.at', now()),
|
||||
(100102, 'Telus Mobility (Canada)', '%s@msg.telus.com', now()),
|
||||
(100103, 'Thumb Cellular', '%s@sms.thumbcellular.com', now()),
|
||||
(100104, 'Tigo (Formerly Ola)', '%s@sms.tigo.com.co', now()),
|
||||
(100105, 'Unicel', '%s@utext.com', now()),
|
||||
(100106, 'US Cellular', '%s@email.uscc.net', now()),
|
||||
(100107, 'Verizon', '%s@vtext.com', now()),
|
||||
(100108, 'Virgin Mobile (Canada)', '%s@vmobile.ca', now()),
|
||||
(100109, 'Virgin Mobile (USA)', '%s@vmobl.com', now()),
|
||||
(100110, 'YCC', '%s@sms.ycc.ru', now()),
|
||||
(100111, 'Orange (UK)', '%s@orange.net', now()),
|
||||
(100112, 'Cincinnati Bell Wireless', '%s@gocbw.com', now()),
|
||||
(100113, 'T-Mobile Germany', '%s@t-mobile-sms.de', now()),
|
||||
(100114, 'Vodafone Germany', '%s@vodafone-sms.de', now()),
|
||||
(100115, 'E-Plus', '%s@smsmail.eplus.de', now());
|
65
doc-src/badge
Normal file
65
doc-src/badge
Normal file
@ -0,0 +1,65 @@
|
||||
Install the %%site.name%% badge on you blog or web site to show the latest updates
|
||||
from you and your friends!
|
||||
|
||||
<MTMarkdownOptions output='raw'>
|
||||
<script type="text/javascript" src="http://identi.ca/js/identica-badge.js">
|
||||
{
|
||||
"user":"kentbrew",
|
||||
"server":"identi.ca",
|
||||
"headerText":" and friends"
|
||||
}
|
||||
</script>
|
||||
</MTMarkdownOptions>
|
||||
|
||||
Things to try
|
||||
--------------
|
||||
|
||||
* Click an avatar and the badge will refresh with that user's timeline
|
||||
* Click a nickname to open a user's profile in your browser
|
||||
* Click a notice's timestamp to view the notice in your browser
|
||||
* @-replies and #tags are live links
|
||||
|
||||
## Installation instructions
|
||||
|
||||
Copy and paste the following JavaScript into an HTML page where
|
||||
you want the badge to show up. Substitute your own ID in the user
|
||||
parameter.
|
||||
|
||||
<pre>
|
||||
<script type="text/javascript" src="http://identi.ca/js/identica-badge.js">
|
||||
{
|
||||
"user":"kentbrew",
|
||||
"server":"identi.ca",
|
||||
"headerText":" and friends"
|
||||
}
|
||||
</script>
|
||||
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
Valid parameters for the badge:
|
||||
-------------------------------
|
||||
|
||||
* user : defaults to 7000 (@kentbrew)
|
||||
* headerText : defaults to empty
|
||||
* height : defaults to 350px
|
||||
* width : defaults to 300px
|
||||
* background : defaults to #193441. If you set evenBackground, oddBackground,
|
||||
and headerBackground, you won't see it at all.
|
||||
* border : defaults to 1px solid black
|
||||
* userColor : defaults to whatever link color is set to on your page
|
||||
* headerBackground : defaults to transparent
|
||||
* headerColor : defaults to white
|
||||
* evenBackground : defaults to #fff
|
||||
* oddBackground : defaults to #eee
|
||||
* thumbnailBorder : 1px solid black
|
||||
* thumbnailSize : defaults to 24px
|
||||
* padding : defaults to 3px
|
||||
* server : defaults to identi.ca
|
||||
|
||||
Licence
|
||||
-------
|
||||
|
||||
Identi.ca badge by [Kent Brewster](http://kentbrewster.com/identica-badge/).
|
||||
Licenced under [CC-BY-SA-3](http://kentbrewster.com/rights-and-permissions/).
|
485
extlib/Net/URL.php
Normal file
485
extlib/Net/URL.php
Normal file
@ -0,0 +1,485 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2004, 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. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard at php net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: URL.php,v 1.49 2007/06/28 14:43:07 davidc Exp $
|
||||
//
|
||||
// Net_URL Class
|
||||
|
||||
|
||||
class Net_URL
|
||||
{
|
||||
var $options = array('encode_query_keys' => false);
|
||||
/**
|
||||
* Full url
|
||||
* @var string
|
||||
*/
|
||||
var $url;
|
||||
|
||||
/**
|
||||
* Protocol
|
||||
* @var string
|
||||
*/
|
||||
var $protocol;
|
||||
|
||||
/**
|
||||
* Username
|
||||
* @var string
|
||||
*/
|
||||
var $username;
|
||||
|
||||
/**
|
||||
* Password
|
||||
* @var string
|
||||
*/
|
||||
var $password;
|
||||
|
||||
/**
|
||||
* Host
|
||||
* @var string
|
||||
*/
|
||||
var $host;
|
||||
|
||||
/**
|
||||
* Port
|
||||
* @var integer
|
||||
*/
|
||||
var $port;
|
||||
|
||||
/**
|
||||
* Path
|
||||
* @var string
|
||||
*/
|
||||
var $path;
|
||||
|
||||
/**
|
||||
* Query string
|
||||
* @var array
|
||||
*/
|
||||
var $querystring;
|
||||
|
||||
/**
|
||||
* Anchor
|
||||
* @var string
|
||||
*/
|
||||
var $anchor;
|
||||
|
||||
/**
|
||||
* Whether to use []
|
||||
* @var bool
|
||||
*/
|
||||
var $useBrackets;
|
||||
|
||||
/**
|
||||
* PHP4 Constructor
|
||||
*
|
||||
* @see __construct()
|
||||
*/
|
||||
function Net_URL($url = null, $useBrackets = true)
|
||||
{
|
||||
$this->__construct($url, $useBrackets);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP5 Constructor
|
||||
*
|
||||
* Parses the given url and stores the various parts
|
||||
* Defaults are used in certain cases
|
||||
*
|
||||
* @param string $url Optional URL
|
||||
* @param bool $useBrackets Whether to use square brackets when
|
||||
* multiple querystrings with the same name
|
||||
* exist
|
||||
*/
|
||||
function __construct($url = null, $useBrackets = true)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->useBrackets = $useBrackets;
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
function initialize()
|
||||
{
|
||||
$HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
|
||||
|
||||
$this->user = '';
|
||||
$this->pass = '';
|
||||
$this->host = '';
|
||||
$this->port = 80;
|
||||
$this->path = '';
|
||||
$this->querystring = array();
|
||||
$this->anchor = '';
|
||||
|
||||
// Only use defaults if not an absolute URL given
|
||||
if (!preg_match('/^[a-z0-9]+:\/\//i', $this->url)) {
|
||||
$this->protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
|
||||
|
||||
/**
|
||||
* Figure out host/port
|
||||
*/
|
||||
if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) &&
|
||||
preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches))
|
||||
{
|
||||
$host = $matches[1];
|
||||
if (!empty($matches[3])) {
|
||||
$port = $matches[3];
|
||||
} else {
|
||||
$port = $this->getStandardPort($this->protocol);
|
||||
}
|
||||
}
|
||||
|
||||
$this->user = '';
|
||||
$this->pass = '';
|
||||
$this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
|
||||
$this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
|
||||
$this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
|
||||
$this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
|
||||
$this->anchor = '';
|
||||
}
|
||||
|
||||
// Parse the url and store the various parts
|
||||
if (!empty($this->url)) {
|
||||
$urlinfo = parse_url($this->url);
|
||||
|
||||
// Default querystring
|
||||
$this->querystring = array();
|
||||
|
||||
foreach ($urlinfo as $key => $value) {
|
||||
switch ($key) {
|
||||
case 'scheme':
|
||||
$this->protocol = $value;
|
||||
$this->port = $this->getStandardPort($value);
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
case 'pass':
|
||||
case 'host':
|
||||
case 'port':
|
||||
$this->$key = $value;
|
||||
break;
|
||||
|
||||
case 'path':
|
||||
if ($value{0} == '/') {
|
||||
$this->path = $value;
|
||||
} else {
|
||||
$path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
|
||||
$this->path = sprintf('%s/%s', $path, $value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'query':
|
||||
$this->querystring = $this->_parseRawQueryString($value);
|
||||
break;
|
||||
|
||||
case 'fragment':
|
||||
$this->anchor = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns full url
|
||||
*
|
||||
* @return string Full url
|
||||
* @access public
|
||||
*/
|
||||
function getURL()
|
||||
{
|
||||
$querystring = $this->getQueryString();
|
||||
|
||||
$this->url = $this->protocol . '://'
|
||||
. $this->user . (!empty($this->pass) ? ':' : '')
|
||||
. $this->pass . (!empty($this->user) ? '@' : '')
|
||||
. $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
|
||||
. $this->path
|
||||
. (!empty($querystring) ? '?' . $querystring : '')
|
||||
. (!empty($this->anchor) ? '#' . $this->anchor : '');
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a querystring item (URL parameter).
|
||||
* Automatically encodes parameters with rawurlencode() if $preencoded
|
||||
* is false.
|
||||
* You can pass an array to $value, it gets mapped via [] in the URL if
|
||||
* $this->useBrackets is activated.
|
||||
*
|
||||
* @param string $name Name of item
|
||||
* @param string $value Value of item
|
||||
* @param bool $preencoded Whether value is urlencoded or not, default = not
|
||||
* @access public
|
||||
*/
|
||||
function addQueryString($name, $value, $preencoded = false)
|
||||
{
|
||||
if ($this->getOption('encode_query_keys')) {
|
||||
$name = rawurlencode($name);
|
||||
}
|
||||
|
||||
if ($preencoded) {
|
||||
$this->querystring[$name] = $value;
|
||||
} else {
|
||||
$this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a querystring item
|
||||
*
|
||||
* @param string $name Name of item
|
||||
* @access public
|
||||
*/
|
||||
function removeQueryString($name)
|
||||
{
|
||||
if ($this->getOption('encode_query_keys')) {
|
||||
$name = rawurlencode($name);
|
||||
}
|
||||
|
||||
if (isset($this->querystring[$name])) {
|
||||
unset($this->querystring[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the querystring to literally what you supply
|
||||
*
|
||||
* @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc
|
||||
* @access public
|
||||
*/
|
||||
function addRawQueryString($querystring)
|
||||
{
|
||||
$this->querystring = $this->_parseRawQueryString($querystring);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns flat querystring
|
||||
*
|
||||
* @return string Querystring
|
||||
* @access public
|
||||
*/
|
||||
function getQueryString()
|
||||
{
|
||||
if (!empty($this->querystring)) {
|
||||
foreach ($this->querystring as $name => $value) {
|
||||
// Encode var name
|
||||
$name = rawurlencode($name);
|
||||
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $k => $v) {
|
||||
$querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
|
||||
}
|
||||
} elseif (!is_null($value)) {
|
||||
$querystring[] = $name . '=' . $value;
|
||||
} else {
|
||||
$querystring[] = $name;
|
||||
}
|
||||
}
|
||||
$querystring = implode(ini_get('arg_separator.output'), $querystring);
|
||||
} else {
|
||||
$querystring = '';
|
||||
}
|
||||
|
||||
return $querystring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses raw querystring and returns an array of it
|
||||
*
|
||||
* @param string $querystring The querystring to parse
|
||||
* @return array An array of the querystring data
|
||||
* @access private
|
||||
*/
|
||||
function _parseRawQuerystring($querystring)
|
||||
{
|
||||
$parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$return = array();
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (strpos($part, '=') !== false) {
|
||||
$value = substr($part, strpos($part, '=') + 1);
|
||||
$key = substr($part, 0, strpos($part, '='));
|
||||
} else {
|
||||
$value = null;
|
||||
$key = $part;
|
||||
}
|
||||
|
||||
if (!$this->getOption('encode_query_keys')) {
|
||||
$key = rawurldecode($key);
|
||||
}
|
||||
|
||||
if (preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
|
||||
$key = $matches[1];
|
||||
$idx = $matches[2];
|
||||
|
||||
// Ensure is an array
|
||||
if (empty($return[$key]) || !is_array($return[$key])) {
|
||||
$return[$key] = array();
|
||||
}
|
||||
|
||||
// Add data
|
||||
if ($idx === '') {
|
||||
$return[$key][] = $value;
|
||||
} else {
|
||||
$return[$key][$idx] = $value;
|
||||
}
|
||||
} elseif (!$this->useBrackets AND !empty($return[$key])) {
|
||||
$return[$key] = (array)$return[$key];
|
||||
$return[$key][] = $value;
|
||||
} else {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves //, ../ and ./ from a path and returns
|
||||
* the result. Eg:
|
||||
*
|
||||
* /foo/bar/../boo.php => /foo/boo.php
|
||||
* /foo/bar/../../boo.php => /boo.php
|
||||
* /foo/bar/.././/boo.php => /foo/boo.php
|
||||
*
|
||||
* This method can also be called statically.
|
||||
*
|
||||
* @param string $path URL path to resolve
|
||||
* @return string The result
|
||||
*/
|
||||
function resolvePath($path)
|
||||
{
|
||||
$path = explode('/', str_replace('//', '/', $path));
|
||||
|
||||
for ($i=0; $i<count($path); $i++) {
|
||||
if ($path[$i] == '.') {
|
||||
unset($path[$i]);
|
||||
$path = array_values($path);
|
||||
$i--;
|
||||
|
||||
} elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
|
||||
unset($path[$i]);
|
||||
unset($path[$i-1]);
|
||||
$path = array_values($path);
|
||||
$i -= 2;
|
||||
|
||||
} elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
|
||||
unset($path[$i]);
|
||||
$path = array_values($path);
|
||||
$i--;
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return implode('/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard port number for a protocol
|
||||
*
|
||||
* @param string $scheme The protocol to lookup
|
||||
* @return integer Port number or NULL if no scheme matches
|
||||
*
|
||||
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
|
||||
*/
|
||||
function getStandardPort($scheme)
|
||||
{
|
||||
switch (strtolower($scheme)) {
|
||||
case 'http': return 80;
|
||||
case 'https': return 443;
|
||||
case 'ftp': return 21;
|
||||
case 'imap': return 143;
|
||||
case 'imaps': return 993;
|
||||
case 'pop3': return 110;
|
||||
case 'pop3s': return 995;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the URL to a particular protocol
|
||||
*
|
||||
* @param string $protocol Protocol to force the URL to
|
||||
* @param integer $port Optional port (standard port is used by default)
|
||||
*/
|
||||
function setProtocol($protocol, $port = null)
|
||||
{
|
||||
$this->protocol = $protocol;
|
||||
$this->port = is_null($port) ? $this->getStandardPort($protocol) : $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an option
|
||||
*
|
||||
* This function set an option
|
||||
* to be used thorough the script.
|
||||
*
|
||||
* @access public
|
||||
* @param string $optionName The optionname to set
|
||||
* @param string $value The value of this option.
|
||||
*/
|
||||
function setOption($optionName, $value)
|
||||
{
|
||||
if (!array_key_exists($optionName, $this->options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->options[$optionName] = $value;
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an option
|
||||
*
|
||||
* This function gets an option
|
||||
* from the $this->options array
|
||||
* and return it's value.
|
||||
*
|
||||
* @access public
|
||||
* @param string $opionName The name of the option to retrieve
|
||||
* @see $this->options
|
||||
*/
|
||||
function getOption($optionName)
|
||||
{
|
||||
if (!isset($this->options[$optionName])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->options[$optionName];
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
324
extlib/Net/URL/Mapper.php
Normal file
324
extlib/Net/URL/Mapper.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Mapper.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
require_once 'Net/URL/Mapper/Path.php';
|
||||
require_once 'Net/URL/Mapper/Exception.php';
|
||||
|
||||
/**
|
||||
* URL parser and mapper class
|
||||
*
|
||||
* This class takes an URL and a configuration and returns formatted data
|
||||
* about the request according to a configuration parameter
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
class Net_URL_Mapper
|
||||
{
|
||||
/**
|
||||
* Array of Net_URL_Mapper instances
|
||||
* @var array
|
||||
*/
|
||||
private static $instances = array();
|
||||
|
||||
/**
|
||||
* Mapped paths collection
|
||||
* @var array
|
||||
*/
|
||||
protected $paths = array();
|
||||
|
||||
/**
|
||||
* Prefix used for url mapping
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* Optional scriptname if mod_rewrite is not available
|
||||
* @var string
|
||||
*/
|
||||
protected $scriptname = '';
|
||||
|
||||
/**
|
||||
* Mapper instance id
|
||||
* @var string
|
||||
*/
|
||||
protected $id = '__default__';
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
* Constructor is private, you should use getInstance() instead.
|
||||
*/
|
||||
private function __construct() { }
|
||||
|
||||
/**
|
||||
* Returns a singleton object corresponding to the requested instance id
|
||||
* @param string Requested instance name
|
||||
* @return Object Net_URL_Mapper Singleton
|
||||
*/
|
||||
public static function getInstance($id = '__default__')
|
||||
{
|
||||
if (!isset(self::$instances[$id])) {
|
||||
$m = new Net_URL_Mapper();
|
||||
$m->id = $id;
|
||||
self::$instances[$id] = $m;
|
||||
}
|
||||
return self::$instances[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance id
|
||||
* @return string Mapper instance id
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a path and creates a connection
|
||||
* @param string The path to connect
|
||||
* @param array Default values for path parts
|
||||
* @param array Regular expressions for path parts
|
||||
* @return object Net_URL_Mapper_Path
|
||||
*/
|
||||
public function connect($path, $defaults = array(), $rules = array())
|
||||
{
|
||||
$pathObj = new Net_URL_Mapper_Path($path, $defaults, $rules);
|
||||
$this->addPath($pathObj);
|
||||
return $pathObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the url prefix if needed
|
||||
*
|
||||
* Example: using the prefix to differenciate mapper instances
|
||||
* <code>
|
||||
* $fr = Net_URL_Mapper::getInstance('fr');
|
||||
* $fr->setPrefix('/fr');
|
||||
* $en = Net_URL_Mapper::getInstance('en');
|
||||
* $en->setPrefix('/en');
|
||||
* </code>
|
||||
*
|
||||
* @param string URL prefix
|
||||
*/
|
||||
public function setPrefix($prefix)
|
||||
{
|
||||
$this->prefix = '/'.trim($prefix, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scriptname if mod_rewrite not available
|
||||
*
|
||||
* Example: will match and generate url like
|
||||
* - index.php/view/product/1
|
||||
* <code>
|
||||
* $m = Net_URL_Mapper::getInstance();
|
||||
* $m->setScriptname('index.php');
|
||||
* </code>
|
||||
* @param string URL prefix
|
||||
*/
|
||||
public function setScriptname($scriptname)
|
||||
{
|
||||
$this->scriptname = $scriptname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will attempt to match an url with a defined path
|
||||
*
|
||||
* If an url corresponds to a path, the resulting values are returned
|
||||
* in an array. If none is found, null is returned. In case an url is
|
||||
* matched but its content doesn't validate the path rules, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param string URL
|
||||
* @return array|null array if match found, null otherwise
|
||||
* @throws Net_URL_Mapper_InvalidException
|
||||
*/
|
||||
public function match($url)
|
||||
{
|
||||
$nurl = '/'.trim($url, '/');
|
||||
|
||||
// Remove scriptname if needed
|
||||
|
||||
if (!empty($this->scriptname) &&
|
||||
strpos($nurl, $this->scriptname) === 0) {
|
||||
$nurl = substr($nurl, strlen($this->scriptname));
|
||||
if (empty($nurl)) {
|
||||
$nurl = '/';
|
||||
}
|
||||
}
|
||||
|
||||
// Remove prefix
|
||||
|
||||
if (!empty($this->prefix)) {
|
||||
if (strpos($nurl, $this->prefix) !== 0) {
|
||||
return null;
|
||||
}
|
||||
$nurl = substr($nurl, strlen($this->prefix));
|
||||
if (empty($nurl)) {
|
||||
$nurl = '/';
|
||||
}
|
||||
}
|
||||
|
||||
// Remove query string
|
||||
|
||||
if (($pos = strpos($nurl, '?')) !== false) {
|
||||
$nurl = substr($nurl, 0, $pos);
|
||||
}
|
||||
|
||||
$paths = array();
|
||||
$values = null;
|
||||
|
||||
// Make a list of paths that conform to route format
|
||||
|
||||
foreach ($this->paths as $path) {
|
||||
$regex = $path->getFormat();
|
||||
if (preg_match($regex, $nurl)) {
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure one of the paths found is valid
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$regex = $path->getRule();
|
||||
if (preg_match($regex, $nurl, $matches)) {
|
||||
$values = $path->getDefaults();
|
||||
array_shift($matches);
|
||||
$clean = array();
|
||||
foreach ($matches as $k => $v) {
|
||||
$v = trim($v, '/');
|
||||
if (!is_int($k) && $v !== '') {
|
||||
$values[$k] = $v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A path conforms but does not validate
|
||||
|
||||
if (is_null($values) && !empty($paths)) {
|
||||
$e = new Net_URL_Mapper_InvalidException('A path was found but is invalid.');
|
||||
$e->setPath($paths[0]);
|
||||
$e->setUrl($url);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an url based on given parameters
|
||||
*
|
||||
* Will attempt to find a path definition that matches the given parameters and
|
||||
* will generate an url based on this path.
|
||||
*
|
||||
* @param array Values to be used for the url generation
|
||||
* @param array Key/value pairs for query string if needed
|
||||
* @param string Anchor (fragment) if needed
|
||||
* @return string|false String if a rule was found, false otherwise
|
||||
*/
|
||||
public function generate($values = array(), $qstring = array(), $anchor = '')
|
||||
{
|
||||
// Use root path if any
|
||||
|
||||
if (empty($values) && isset($this->paths['/'])) {
|
||||
return $this->scriptname.$this->prefix.$this->paths['/']->generate($values, $qstring, $anchor);
|
||||
}
|
||||
|
||||
foreach ($this->paths as $path) {
|
||||
$set = array();
|
||||
foreach ($values as $k => $v) {
|
||||
if ($path->hasKey($k, $v)) {
|
||||
$set[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($set) == count($values) &&
|
||||
count($set) <= $path->getMaxKeys()) {
|
||||
|
||||
$req = $path->getRequired();
|
||||
if (count(array_intersect(array_keys($set), $req)) != count($req)) {
|
||||
continue;
|
||||
}
|
||||
$gen = $path->generate($set, $qstring, $anchor);
|
||||
return $this->scriptname.$this->prefix.$gen;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns defined paths
|
||||
* @return array Array of paths
|
||||
*/
|
||||
public function getPaths()
|
||||
{
|
||||
return $this->paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all paths
|
||||
* This is probably only useful for testing
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->paths = array();
|
||||
$this->prefix = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new path to the mapper
|
||||
* @param object Net_URL_Mapper_Path object
|
||||
*/
|
||||
public function addPath(Net_URL_Mapper_Path $path)
|
||||
{
|
||||
$this->paths[$path->getPath()] = $path;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
104
extlib/Net/URL/Mapper/Exception.php
Normal file
104
extlib/Net/URL/Mapper/Exception.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* Exception classes for Net_URL_Mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Exception.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for exceptions in PEAR
|
||||
*/
|
||||
require_once 'PEAR/Exception.php';
|
||||
|
||||
/**
|
||||
* Base class for exceptions in Net_URL_Mapper package
|
||||
*
|
||||
* Such a base class is required by the Exception RFC:
|
||||
* http://pear.php.net/pepr/pepr-proposal-show.php?id=132
|
||||
* It will rarely be thrown directly, its specialized subclasses will be
|
||||
* thrown most of the time.
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_URL_Mapper
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
class Net_URL_Mapper_Exception extends PEAR_Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a path is invalid
|
||||
*
|
||||
* A path can conform to a given structure, but contain invalid parameters.
|
||||
* <code>
|
||||
* $m = Net_URL_Mapper::getInstance();
|
||||
* $m->connect('hi/:name', null, array('name'=>'[a-z]+'));
|
||||
* $m->match('/hi/FOXY'); // Will throw the exception
|
||||
* </code>
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_URL_Mapper
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
class Net_URL_Mapper_InvalidException extends Net_URL_Mapper_Exception
|
||||
{
|
||||
protected $path;
|
||||
protected $url;
|
||||
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function setUrl($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
}
|
||||
?>
|
142
extlib/Net/URL/Mapper/Part.php
Normal file
142
extlib/Net/URL/Mapper/Part.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Part.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
abstract class Net_URL_Mapper_Part
|
||||
{
|
||||
protected $defaults;
|
||||
protected $rule;
|
||||
protected $public;
|
||||
protected $type;
|
||||
protected $required = false;
|
||||
|
||||
/**
|
||||
* Part name if dynamic or content, generated from path
|
||||
* @var string
|
||||
*/
|
||||
public $content;
|
||||
|
||||
const DYNAMIC = 1;
|
||||
const WILDCARD = 2;
|
||||
const FIXED = 3;
|
||||
|
||||
public function __construct($content, $path)
|
||||
{
|
||||
$this->content = $content;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function setRule($rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
abstract public function getFormat();
|
||||
|
||||
abstract public function getRule();
|
||||
|
||||
public function addSlash($str)
|
||||
{
|
||||
$str = trim($str, '/');
|
||||
if (($pos = strpos($this->path, '/')) !== false) {
|
||||
if ($pos == 0) {
|
||||
$str = '/'.$str;
|
||||
} else {
|
||||
$str .= '/';
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function addSlashRegex($str)
|
||||
{
|
||||
$str = trim($str, '/');
|
||||
if (($pos = strpos($this->path, '/')) !== false) {
|
||||
if ($pos == 0) {
|
||||
$str = '\/'.$str;
|
||||
} else {
|
||||
$str .= '\/';
|
||||
}
|
||||
}
|
||||
if (!$this->isRequired()) {
|
||||
$str = '('.$str.'|)';
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function setDefaults($defaults)
|
||||
{
|
||||
$this->defaults = (string)$defaults;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function accept($visitor, $method = null)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$visitor->$method($this, $args);
|
||||
}
|
||||
|
||||
public function setRequired($required)
|
||||
{
|
||||
$this->required = $required;
|
||||
}
|
||||
|
||||
public function isRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
abstract public function generate($value = null);
|
||||
|
||||
public function match($value)
|
||||
{
|
||||
$rule = $this->getRule();
|
||||
return preg_match('/^'.$rule.'$/', $this->addSlash($value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
81
extlib/Net/URL/Mapper/Part/Dynamic.php
Normal file
81
extlib/Net/URL/Mapper/Part/Dynamic.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Dynamic.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
require_once 'Net/URL/Mapper/Part.php';
|
||||
|
||||
class Net_URL_Mapper_Part_Dynamic extends Net_URL_Mapper_Part
|
||||
{
|
||||
|
||||
public function __construct($content, $path)
|
||||
{
|
||||
$this->type = Net_URL_Mapper_Part::DYNAMIC;
|
||||
$this->setRequired(true);
|
||||
parent::__construct($content, $path);
|
||||
}
|
||||
|
||||
public function getFormat()
|
||||
{
|
||||
return $this->addSlashRegex('[^\/]+');
|
||||
}
|
||||
|
||||
public function getRule()
|
||||
{
|
||||
if (!empty($this->rule)) {
|
||||
return '(?P<'.$this->content.'>'.$this->addSlashRegex($this->rule).')';
|
||||
}
|
||||
return '(?P<'.$this->content.'>'.$this->addSlashRegex('[^\/]+').')';
|
||||
}
|
||||
|
||||
public function generate($value = null)
|
||||
{
|
||||
if (is_array($value) && isset($value[$this->content])) {
|
||||
$val = $value[$this->content];
|
||||
} elseif (!is_array($value) && !is_null($value)) {
|
||||
$val = $value;
|
||||
} else {
|
||||
$val = $this->defaults;
|
||||
}
|
||||
return $this->addSlash(urlencode($val));
|
||||
}
|
||||
}
|
||||
?>
|
70
extlib/Net/URL/Mapper/Part/Fixed.php
Normal file
70
extlib/Net/URL/Mapper/Part/Fixed.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Fixed.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
require_once 'Net/URL/Mapper/Part.php';
|
||||
|
||||
class Net_URL_Mapper_Part_Fixed extends Net_URL_Mapper_Part
|
||||
{
|
||||
|
||||
public function __construct($content, $path)
|
||||
{
|
||||
$this->type = Net_URL_Mapper_Part::FIXED;
|
||||
parent::__construct($content, $path);
|
||||
}
|
||||
|
||||
public function getFormat()
|
||||
{
|
||||
return $this->getRule();
|
||||
}
|
||||
|
||||
public function getRule()
|
||||
{
|
||||
return preg_quote($this->path, '/');
|
||||
}
|
||||
|
||||
public function generate($value = null)
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
?>
|
80
extlib/Net/URL/Mapper/Part/Wildcard.php
Normal file
80
extlib/Net/URL/Mapper/Part/Wildcard.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Wildcard.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
require_once 'Net/URL/Mapper/Part.php';
|
||||
|
||||
class Net_URL_Mapper_Part_Wildcard extends Net_URL_Mapper_Part
|
||||
{
|
||||
|
||||
public function __construct($content, $path)
|
||||
{
|
||||
$this->type = Net_URL_Mapper_Part::WILDCARD;
|
||||
$this->setRequired(true);
|
||||
parent::__construct($content, $path);
|
||||
}
|
||||
|
||||
public function getFormat()
|
||||
{
|
||||
return $this->addSlashRegex('.*');;
|
||||
}
|
||||
|
||||
public function getRule()
|
||||
{
|
||||
return '(?P<'.$this->content.'>'.$this->addSlashRegex('.*').')';
|
||||
}
|
||||
|
||||
public function generate($value = null)
|
||||
{
|
||||
if (is_array($value) && isset($value[$this->content])) {
|
||||
$val = $value[$this->content];
|
||||
} elseif (!is_array($value) && !is_null($value)) {
|
||||
$val = $value;
|
||||
} else {
|
||||
$val = $this->defaults;
|
||||
}
|
||||
return $this->addSlash(str_replace(
|
||||
array('%2F', '%23'),
|
||||
array('/', '#'), urlencode($val)));
|
||||
}
|
||||
}
|
||||
?>
|
430
extlib/Net/URL/Mapper/Path.php
Normal file
430
extlib/Net/URL/Mapper/Path.php
Normal file
@ -0,0 +1,430 @@
|
||||
<?php
|
||||
/**
|
||||
* URL parser and mapper
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * 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 Net
|
||||
* @package Net_URL_Mapper
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Path.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||
*/
|
||||
|
||||
require_once 'Net/URL.php';
|
||||
require_once 'Net/URL/Mapper/Part/Dynamic.php';
|
||||
require_once 'Net/URL/Mapper/Part/Wildcard.php';
|
||||
require_once 'Net/URL/Mapper/Part/Fixed.php';
|
||||
|
||||
class Net_URL_Mapper_Path
|
||||
{
|
||||
private $path = '';
|
||||
private $N = 0;
|
||||
public $token;
|
||||
public $value;
|
||||
private $line = 1;
|
||||
private $state = 1;
|
||||
|
||||
|
||||
protected $alias;
|
||||
protected $rules = array();
|
||||
protected $defaults = array();
|
||||
protected $parts = array();
|
||||
protected $rule;
|
||||
protected $format;
|
||||
protected $minKeys;
|
||||
protected $maxKeys;
|
||||
protected $fixed = true;
|
||||
protected $required;
|
||||
|
||||
public function __construct($path = '', $defaults = array(), $rules = array())
|
||||
{
|
||||
$this->path = '/'.trim(Net_URL::resolvePath($path), '/');
|
||||
$this->setDefaults($defaults);
|
||||
$this->setRules($rules);
|
||||
|
||||
try {
|
||||
$this->parsePath();
|
||||
} catch (Exception $e) {
|
||||
// The path could not be parsed correctly, treat it as fixed
|
||||
$this->fixed = true;
|
||||
$part = self::createPart(Net_URL_Mapper_Part::FIXED, $this->path, $this->path);
|
||||
$this->parts = array($part);
|
||||
}
|
||||
$this->getRequired();
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
protected function parsePath()
|
||||
{
|
||||
while ($this->yylex()) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path alias
|
||||
* Path aliases can be used instead of full path
|
||||
* @return null|string
|
||||
*/
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path name
|
||||
* @param string Set the path name
|
||||
* @see getAlias()
|
||||
*/
|
||||
public function setAlias($alias)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path parts default values
|
||||
* @return null|array
|
||||
*/
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path parts default values
|
||||
* @param array Associative array with format partname => value
|
||||
*/
|
||||
public function setDefaults($defaults)
|
||||
{
|
||||
if (is_array($defaults)) {
|
||||
$this->defaults = $defaults;
|
||||
} else {
|
||||
$this->defaults = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path parts default values
|
||||
* @param array Associative array with format partname => value
|
||||
*/
|
||||
public function setRules($rules)
|
||||
{
|
||||
if (is_array($rules)) {
|
||||
$this->rules = $rules;
|
||||
} else {
|
||||
$this->rules = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the regular expression used to match this path
|
||||
* @return string PERL Regular expression
|
||||
*/
|
||||
public function getRule()
|
||||
{
|
||||
if (is_null($this->rule)) {
|
||||
$this->rule = '/^';
|
||||
foreach ($this->parts as $path => $part) {
|
||||
$this->rule .= $part->getRule();
|
||||
}
|
||||
$this->rule .= '$/';
|
||||
}
|
||||
return $this->rule;
|
||||
}
|
||||
|
||||
public function getFormat()
|
||||
{
|
||||
if (is_null($this->format)) {
|
||||
$this->format = '/^';
|
||||
foreach ($this->parts as $path => $part) {
|
||||
$this->format .= $part->getFormat();
|
||||
}
|
||||
$this->format .= '$/';
|
||||
}
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
protected function addPart($part)
|
||||
{
|
||||
if (array_key_exists($part->content, $this->defaults)) {
|
||||
$part->setRequired(false);
|
||||
$part->setDefaults($this->defaults[$part->content]);
|
||||
}
|
||||
if (isset($this->rules[$part->content])) {
|
||||
$part->setRule($this->rules[$part->content]);
|
||||
}
|
||||
$this->rule = null;
|
||||
if ($part->getType() != Net_URL_Mapper_Part::FIXED) {
|
||||
$this->fixed = false;
|
||||
$this->parts[$part->content] = $part;
|
||||
} else {
|
||||
$this->parts[] = $part;
|
||||
}
|
||||
return $part;
|
||||
}
|
||||
|
||||
public static function createPart($type, $content, $path)
|
||||
{
|
||||
switch ($type) {
|
||||
case Net_URL_Mapper_Part::DYNAMIC:
|
||||
return new Net_URL_Mapper_Part_Dynamic($content, $path);
|
||||
break;
|
||||
case Net_URL_Mapper_Part::WILDCARD:
|
||||
return new Net_URL_Mapper_Part_Wildcard($content, $path);
|
||||
break;
|
||||
default:
|
||||
return new Net_URL_Mapper_Part_Fixed($content, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the path contains the given part by name
|
||||
* If value parameter is given, the part also checks if the
|
||||
* given value conforms to the part rule.
|
||||
* @param string Part name
|
||||
* @param mixed The value to check against
|
||||
*/
|
||||
public function hasKey($partName, $value = null)
|
||||
{
|
||||
if (array_key_exists($partName, $this->parts)) {
|
||||
if (!is_null($value) && $value !== false) {
|
||||
return $this->parts[$partName]->match($value);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} elseif (array_key_exists($partName, $this->defaults) &&
|
||||
$value == $this->defaults[$partName]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function generate($values = array(), $qstring = array(), $anchor = '')
|
||||
{
|
||||
$path = '';
|
||||
foreach ($this->parts as $part) {
|
||||
$path .= $part->generate($values);
|
||||
}
|
||||
$path = '/'.trim(Net_URL::resolvePath($path), '/');
|
||||
if (!empty($qstring)) {
|
||||
$path .= '?'.http_build_query($qstring);
|
||||
}
|
||||
if (!empty($anchor)) {
|
||||
$path .= '#'.ltrim($anchor, '#');
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function getRequired()
|
||||
{
|
||||
if (!isset($this->required)) {
|
||||
$req = array();
|
||||
foreach ($this->parts as $part) {
|
||||
if ($part->isRequired()) {
|
||||
$req[] = $part->content;
|
||||
}
|
||||
}
|
||||
$this->required = $req;
|
||||
}
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
public function getMaxKeys()
|
||||
{
|
||||
if (is_null($this->maxKeys)) {
|
||||
$this->maxKeys = count($this->required);
|
||||
$this->maxKeys += count($this->defaults);
|
||||
}
|
||||
return $this->maxKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private $_yy_state = 1;
|
||||
private $_yy_stack = array();
|
||||
|
||||
function yylex()
|
||||
{
|
||||
return $this->{'yylex' . $this->_yy_state}();
|
||||
}
|
||||
|
||||
function yypushstate($state)
|
||||
{
|
||||
array_push($this->_yy_stack, $this->_yy_state);
|
||||
$this->_yy_state = $state;
|
||||
}
|
||||
|
||||
function yypopstate()
|
||||
{
|
||||
$this->_yy_state = array_pop($this->_yy_stack);
|
||||
}
|
||||
|
||||
function yybegin($state)
|
||||
{
|
||||
$this->_yy_state = $state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function yylex1()
|
||||
{
|
||||
$tokenMap = array (
|
||||
1 => 1,
|
||||
3 => 1,
|
||||
5 => 1,
|
||||
7 => 1,
|
||||
9 => 1,
|
||||
);
|
||||
if ($this->N >= strlen($this->path)) {
|
||||
return false; // end of input
|
||||
}
|
||||
$yy_global_pattern = "/^(\/?:\/?\\(([a-zA-Z0-9_]+)\\))|^(\/?\\*\/?\\(([a-zA-Z0-9_]+)\\))|^(\/?:([a-zA-Z0-9_]+))|^(\/?\\*([a-zA-Z0-9_]+))|^(\/?([^\/:*]+))/";
|
||||
|
||||
do {
|
||||
if (preg_match($yy_global_pattern, substr($this->path, $this->N), $yymatches)) {
|
||||
$yysubmatches = $yymatches;
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
if (!count($yymatches)) {
|
||||
throw new Exception('Error: lexing failed because a rule matched' .
|
||||
'an empty string. Input "' . substr($this->path,
|
||||
$this->N, 5) . '... state START');
|
||||
}
|
||||
next($yymatches); // skip global match
|
||||
$this->token = key($yymatches); // token number
|
||||
if ($tokenMap[$this->token]) {
|
||||
// extract sub-patterns for passing to lex function
|
||||
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
|
||||
$tokenMap[$this->token]);
|
||||
} else {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$this->value = current($yymatches); // token value
|
||||
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
|
||||
if ($r === null) {
|
||||
$this->N += strlen($this->value);
|
||||
$this->line += substr_count("\n", $this->value);
|
||||
// accept this token
|
||||
return true;
|
||||
} elseif ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} elseif ($r === false) {
|
||||
$this->N += strlen($this->value);
|
||||
$this->line += substr_count("\n", $this->value);
|
||||
if ($this->N >= strlen($this->path)) {
|
||||
return false; // end of input
|
||||
}
|
||||
// skip this token
|
||||
continue;
|
||||
} else { $yy_yymore_patterns = array(
|
||||
1 => "^(\/?\\*\/?\\(([a-zA-Z0-9_]+)\\))|^(\/?:([a-zA-Z0-9_]+))|^(\/?\\*([a-zA-Z0-9_]+))|^(\/?([^\/:*]+))",
|
||||
3 => "^(\/?:([a-zA-Z0-9_]+))|^(\/?\\*([a-zA-Z0-9_]+))|^(\/?([^\/:*]+))",
|
||||
5 => "^(\/?\\*([a-zA-Z0-9_]+))|^(\/?([^\/:*]+))",
|
||||
7 => "^(\/?([^\/:*]+))",
|
||||
9 => "",
|
||||
);
|
||||
|
||||
// yymore is needed
|
||||
do {
|
||||
if (!strlen($yy_yymore_patterns[$this->token])) {
|
||||
throw new Exception('cannot do yymore for the last token');
|
||||
}
|
||||
if (preg_match($yy_yymore_patterns[$this->token],
|
||||
substr($this->path, $this->N), $yymatches)) {
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
next($yymatches); // skip global match
|
||||
$this->token = key($yymatches); // token number
|
||||
$this->value = current($yymatches); // token value
|
||||
$this->line = substr_count("\n", $this->value);
|
||||
}
|
||||
} while ($this->{'yy_r1_' . $this->token}() !== null);
|
||||
// accept
|
||||
$this->N += strlen($this->value);
|
||||
$this->line += substr_count("\n", $this->value);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
throw new Exception('Unexpected input at line' . $this->line .
|
||||
': ' . $this->path[$this->N]);
|
||||
}
|
||||
break;
|
||||
} while (true);
|
||||
} // end function
|
||||
|
||||
|
||||
const START = 1;
|
||||
function yy_r1_1($yy_subpatterns)
|
||||
{
|
||||
|
||||
$c = $yy_subpatterns[0];
|
||||
$part = self::createPart(Net_URL_Mapper_Part::DYNAMIC, $c, $this->value);
|
||||
$this->addPart($part);
|
||||
}
|
||||
function yy_r1_3($yy_subpatterns)
|
||||
{
|
||||
|
||||
$c = $yy_subpatterns[0];
|
||||
$part = self::createPart(Net_URL_Mapper_Part::WILDCARD, $c, $this->value);
|
||||
$this->addPart($part);
|
||||
}
|
||||
function yy_r1_5($yy_subpatterns)
|
||||
{
|
||||
|
||||
$c = $yy_subpatterns[0];
|
||||
$part = self::createPart(Net_URL_Mapper_Part::DYNAMIC, $c, $this->value);
|
||||
$this->addPart($part);
|
||||
}
|
||||
function yy_r1_7($yy_subpatterns)
|
||||
{
|
||||
|
||||
$c = $yy_subpatterns[0];
|
||||
$part = self::createPart(Net_URL_Mapper_Part::WILDCARD, $c, $this->value);
|
||||
$this->addPart($part);
|
||||
}
|
||||
function yy_r1_9($yy_subpatterns)
|
||||
{
|
||||
|
||||
$c = $yy_subpatterns[0];
|
||||
$part = self::createPart(Net_URL_Mapper_Part::FIXED, $c, $this->value);
|
||||
$this->addPart($part);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
162
htaccess.sample
162
htaccess.sample
@ -4,165 +4,9 @@ RewriteEngine On
|
||||
|
||||
RewriteBase /mublog/
|
||||
|
||||
RewriteRule ^$ index.php?action=public [L,QSA]
|
||||
RewriteRule ^rss$ index.php?action=publicrss [L,QSA]
|
||||
RewriteRule ^xrds$ index.php?action=publicxrds [L,QSA]
|
||||
RewriteRule ^featuredrss$ index.php?action=featuredrss [L,QSA]
|
||||
RewriteRule ^favoritedrss$ index.php?action=favoritedrss [L,QSA]
|
||||
RewriteRule ^opensearch/people$ index.php?action=opensearch&type=people [L,QSA]
|
||||
RewriteRule ^opensearch/notice$ index.php?action=opensearch&type=notice [L,QSA]
|
||||
|
||||
RewriteRule ^doc/about$ index.php?action=doc&title=about [L,QSA]
|
||||
RewriteRule ^doc/contact$ index.php?action=doc&title=contact [L,QSA]
|
||||
RewriteRule ^doc/faq$ index.php?action=doc&title=faq [L,QSA]
|
||||
RewriteRule ^doc/help$ index.php?action=doc&title=help [L,QSA]
|
||||
RewriteRule ^doc/im$ index.php?action=doc&title=im [L,QSA]
|
||||
RewriteRule ^doc/openid$ index.php?action=doc&title=openid [L,QSA]
|
||||
RewriteRule ^doc/openmublog$ index.php?action=doc&title=openmublog [L,QSA]
|
||||
RewriteRule ^doc/privacy$ index.php?action=doc&title=privacy [L,QSA]
|
||||
RewriteRule ^doc/source$ index.php?action=doc&title=source [L,QSA]
|
||||
RewriteRule ^doc/tags$ index.php?action=doc&title=tags [L,QSA]
|
||||
RewriteRule ^doc/groups$ index.php?action=doc&title=groups [L,QSA]
|
||||
RewriteRule ^doc/sms$ index.php?action=doc&title=sms [L,QSA]
|
||||
|
||||
RewriteRule ^facebook/$ index.php?action=facebookhome [L,QSA]
|
||||
RewriteRule ^facebook/index.php$ index.php?action=facebookhome [L,QSA]
|
||||
RewriteRule ^facebook/settings.php$ index.php?action=facebooksettings [L,QSA]
|
||||
RewriteRule ^facebook/invite.php$ index.php?action=facebookinvite [L,QSA]
|
||||
RewriteRule ^facebook/remove$ index.php?action=facebookremove [L,QSA]
|
||||
|
||||
RewriteRule ^main/login$ index.php?action=login [L,QSA]
|
||||
RewriteRule ^main/logout$ index.php?action=logout [L,QSA]
|
||||
RewriteRule ^main/register/(.*)$ index.php?action=register&code=$1 [L,QSA]
|
||||
RewriteRule ^main/register$ index.php?action=register [L,QSA]
|
||||
RewriteRule ^main/openid$ index.php?action=openidlogin [L,QSA]
|
||||
RewriteRule ^main/remote$ index.php?action=remotesubscribe [L,QSA]
|
||||
|
||||
RewriteRule ^main/subscribe$ index.php?action=subscribe [L,QSA]
|
||||
RewriteRule ^main/unsubscribe$ index.php?action=unsubscribe [L,QSA]
|
||||
RewriteRule ^main/confirmaddress$ index.php?action=confirmaddress [L,QSA]
|
||||
RewriteRule ^main/confirmaddress/(.*)$ index.php?action=confirmaddress&code=$1 [L,QSA]
|
||||
RewriteRule ^main/recoverpassword$ index.php?action=recoverpassword [L,QSA]
|
||||
RewriteRule ^main/recoverpassword/(.*)$ index.php?action=recoverpassword&code=$1 [L,QSA]
|
||||
RewriteRule ^main/invite$ index.php?action=invite [L,QSA]
|
||||
|
||||
RewriteRule ^main/favor$ index.php?action=favor [L,QSA]
|
||||
RewriteRule ^main/disfavor$ index.php?action=disfavor [L,QSA]
|
||||
|
||||
RewriteRule ^main/sup$ index.php?action=sup [L,QSA]
|
||||
|
||||
RewriteRule ^main/tagother$ index.php?action=tagother [L,QSA]
|
||||
|
||||
RewriteRule ^main/block$ index.php?action=block [L,QSA]
|
||||
|
||||
RewriteRule ^settings/profile$ index.php?action=profilesettings [L,QSA]
|
||||
RewriteRule ^settings/avatar$ index.php?action=avatarsettings [L,QSA]
|
||||
RewriteRule ^settings/password$ index.php?action=passwordsettings [L,QSA]
|
||||
RewriteRule ^settings/openid$ index.php?action=openidsettings [L,QSA]
|
||||
RewriteRule ^settings/im$ index.php?action=imsettings [L,QSA]
|
||||
RewriteRule ^settings/email$ index.php?action=emailsettings [L,QSA]
|
||||
RewriteRule ^settings/sms$ index.php?action=smssettings [L,QSA]
|
||||
RewriteRule ^settings/twitter$ index.php?action=twittersettings [L,QSA]
|
||||
RewriteRule ^settings/other$ index.php?action=othersettings [L,QSA]
|
||||
|
||||
RewriteRule ^search/group$ index.php?action=groupsearch [L,QSA]
|
||||
RewriteRule ^search/people$ index.php?action=peoplesearch [L,QSA]
|
||||
RewriteRule ^search/notice$ index.php?action=noticesearch [L,QSA]
|
||||
RewriteRule ^search/notice/rss$ index.php?action=noticesearchrss [L,QSA]
|
||||
|
||||
RewriteRule ^notice/new$ index.php?action=newnotice [L,QSA]
|
||||
RewriteRule ^notice/(\d+)$ index.php?action=shownotice¬ice=$1 [L,QSA]
|
||||
RewriteRule ^notice/delete/((\d+))?$ index.php?action=deletenotice¬ice=$2 [L,QSA]
|
||||
RewriteRule ^notice/delete$ index.php?action=deletenotice [L,QSA]
|
||||
|
||||
RewriteRule ^message/new$ index.php?action=newmessage [L,QSA]
|
||||
RewriteRule ^message/(\d+)$ index.php?action=showmessage&message=$1 [L,QSA]
|
||||
|
||||
RewriteRule ^user/(\d+)$ index.php?action=userbyid&id=$1 [L,QSA]
|
||||
|
||||
RewriteRule ^tags/?$ index.php?action=publictagcloud [L,QSA]
|
||||
RewriteRule ^tag/([a-zA-Z0-9]+)/rss$ index.php?action=tagrss&tag=$1 [L,QSA]
|
||||
RewriteRule ^tag(/(.*))?$ index.php?action=tag&tag=$2 [L,QSA]
|
||||
|
||||
RewriteRule ^peopletag/([a-zA-Z0-9]+)$ index.php?action=peopletag&tag=$1 [L,QSA]
|
||||
|
||||
RewriteRule ^featured/?$ index.php?action=featured [L,QSA]
|
||||
RewriteRule ^favorited/?$ index.php?action=favorited [L,QSA]
|
||||
|
||||
RewriteRule ^group/new$ index.php?action=newgroup [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/edit$ index.php?action=editgroup&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/join$ index.php?action=joingroup&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/leave$ index.php?action=leavegroup&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/members$ index.php?action=groupmembers&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/logo$ index.php?action=grouplogo&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([0-9]+)/id$ index.php?action=groupbyid&id=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)/rss$ index.php?action=grouprss&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group/([a-zA-Z0-9]+)$ index.php?action=showgroup&nickname=$1 [L,QSA]
|
||||
RewriteRule ^group$ index.php?action=groups [L,QSA]
|
||||
|
||||
# Twitter-compatible API rewrites
|
||||
# XXX: Surely these can be refactored a little -- Zach
|
||||
RewriteRule ^api/statuses/public_timeline(.*)$ index.php?action=api&apiaction=statuses&method=public_timeline$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/friends_timeline(.*)$ index.php?action=api&apiaction=statuses&method=friends_timeline$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/user_timeline/(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/user_timeline(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/show/(.*)$ index.php?action=api&apiaction=statuses&method=show&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/update(.*)$ index.php?action=api&apiaction=statuses&method=update$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/replies(.*)$ index.php?action=api&apiaction=statuses&method=replies&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/destroy/(.*)$ index.php?action=api&apiaction=statuses&method=destroy&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/friends/(.*)$ index.php?action=api&apiaction=statuses&method=friends&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/friends(.*)$ index.php?action=api&apiaction=statuses&method=friends$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/followers/(.*)$ index.php?action=api&apiaction=statuses&method=followers&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/followers(.*)$ index.php?action=api&apiaction=statuses&method=followers$1 [L,QSA]
|
||||
RewriteRule ^api/statuses/featured(.*)$ index.php?action=api&apiaction=statuses&method=featured$1 [L,QSA]
|
||||
RewriteRule ^api/users/show/(.*)$ index.php?action=api&apiaction=users&method=show&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/users/show(.*)$ index.php?action=api&apiaction=users&method=show$1 [L,QSA]
|
||||
RewriteRule ^api/direct_messages/sent(.*)$ index.php?action=api&apiaction=direct_messages&method=sent$1 [L,QSA]
|
||||
RewriteRule ^api/direct_messages/destroy/(.*)$ index.php?action=api&apiaction=direct_messages&method=destroy&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/direct_messages/new(.*)$ index.php?action=api&apiaction=direct_messages&method=create$1 [L,QSA]
|
||||
RewriteRule ^api/direct_messages(.*)$ index.php?action=api&apiaction=direct_messages&method=direct_messages$1 [L,QSA]
|
||||
RewriteRule ^api/friendships/create/(.*)$ index.php?action=api&apiaction=friendships&method=create&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/friendships/destroy/(.*)$ index.php?action=api&apiaction=friendships&method=destroy&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/friendships/exists(.*)$ index.php?action=api&apiaction=friendships&method=exists$1 [L,QSA]
|
||||
RewriteRule ^api/account/verify_credentials(.*)$ index.php?action=api&apiaction=account&method=verify_credentials$1 [L,QSA]
|
||||
RewriteRule ^api/account/end_session$ index.php?action=api&apiaction=account&method=end_session$1 [L,QSA]
|
||||
RewriteRule ^api/account/update_location(.*)$ index.php?action=api&apiaction=account&method=update_location$1 [L,QSA]
|
||||
RewriteRule ^api/account/update_delivery_device(.*)$ index.php?action=api&apiaction=account&method=update_delivery_device$1 [L,QSA]
|
||||
RewriteRule ^api/account/rate_limit_status(.*)$ index.php?action=api&apiaction=account&method=rate_limit_status$1 [L,QSA]
|
||||
RewriteRule ^api/favorites/create/(.*)$ index.php?action=api&apiaction=favorites&method=create&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/favorites/destroy/(.*)$ index.php?action=api&apiaction=favorites&method=destroy&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/favorites/(.*)$ index.php?action=api&apiaction=favorites&method=favorites&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/favorites(.*)$ index.php?action=api&apiaction=favorites&method=favorites$1 [L,QSA]
|
||||
RewriteRule ^api/notifications/follow/(.*)$ index.php?action=api&apiaction=notifications&method=follow&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/notifications/leave/(.*)$ index.php?action=api&apiaction=notifications&method=leave&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/blocks/create/(.*)$ index.php?action=api&apiaction=blocks&method=create&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/blocks/destroy/(.*)$ index.php?action=api&apiaction=blocks&method=destroy&argument=$1 [L,QSA]
|
||||
RewriteRule ^api/help/(.*)$ index.php?action=api&apiaction=help&method=$1 [L,QSA]
|
||||
RewriteRule ^api/laconica/version(.*)$ index.php?action=api&apiaction=laconica&method=version$1 [L,QSA]
|
||||
RewriteRule ^api/laconica/config(.*)$ index.php?action=api&apiaction=laconica&method=config$1 [L,QSA]
|
||||
RewriteRule ^api/laconica/wadl\.xml$ index.php?action=api&apiaction=laconica&method=wadl.xml [L,QSA]
|
||||
|
||||
RewriteRule ^(\w+)/subscriptions$ index.php?action=subscriptions&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/subscriptions/([a-zA-Z0-9]+)$ index.php?action=subscriptions&nickname=$1&tag=$2 [L,QSA]
|
||||
RewriteRule ^(\w+)/subscribers/([a-zA-Z0-9]+)$ index.php?action=subscribers&nickname=$1&tag=$2 [L,QSA]
|
||||
RewriteRule ^(\w+)/subscribers$ index.php?action=subscribers&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/nudge$ index.php?action=nudge&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/xrds$ index.php?action=xrds&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/rss$ index.php?action=userrss&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/all$ index.php?action=all&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/all/rss$ index.php?action=allrss&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/foaf$ index.php?action=foaf&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/replies$ index.php?action=replies&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/replies/rss$ index.php?action=repliesrss&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/avatar/(original|96|48|24)$ index.php?action=avatarbynickname&nickname=$1&size=$2 [L,QSA]
|
||||
RewriteRule ^(\w+)/favorites$ index.php?action=showfavorites&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/favorites/rss$ index.php?action=favoritesrss&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/inbox$ index.php?action=inbox&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/outbox$ index.php?action=outbox&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/microsummary$ index.php?action=microsummary&nickname=$1 [L,QSA]
|
||||
RewriteRule ^(\w+)/groups$ index.php?action=usergroups&nickname=$1 [L,QSA]
|
||||
|
||||
RewriteRule ^(\w+)$ index.php?action=showstream&nickname=$1 [L,QSA]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule (.*) index.php?p=$1 [L,QSA]
|
||||
|
||||
<FilesMatch "\.(ini)">
|
||||
Order allow,deny
|
||||
|
159
index.php
159
index.php
@ -22,70 +22,131 @@ define('LACONICA', true);
|
||||
|
||||
require_once INSTALLDIR . '/lib/common.php';
|
||||
|
||||
// get and cache current user
|
||||
$user = null;
|
||||
$action = null;
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
// initialize language env
|
||||
|
||||
common_init_language();
|
||||
|
||||
$action = $_REQUEST['action'];
|
||||
|
||||
if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) {
|
||||
common_redirect(common_local_url('public'));
|
||||
function getPath($req)
|
||||
{
|
||||
if ((common_config('site', 'fancy') || !array_key_exists('PATH_INFO', $_SERVER))
|
||||
&& array_key_exists('p', $req)) {
|
||||
return $req['p'];
|
||||
} else if (array_key_exists('PATH_INFO', $_SERVER)) {
|
||||
return $_SERVER['PATH_INFO'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// If the site is private, and they're not on one of the "public"
|
||||
// parts of the site, redirect to login
|
||||
function handleError($error)
|
||||
{
|
||||
if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$user && common_config('site', 'private') &&
|
||||
!in_array($action, array('login', 'openidlogin', 'finishopenidlogin',
|
||||
'recoverpassword', 'api', 'doc', 'register'))) {
|
||||
common_redirect(common_local_url('login'));
|
||||
common_log(LOG_ERR, "PEAR error: " . $error->getMessage());
|
||||
$msg = sprintf(_('The database for %s isn\'t responding correctly, '.
|
||||
'so the site won\'t work properly. '.
|
||||
'The site admins probably know about the problem, '.
|
||||
'but you can contact them at %s to make sure. '.
|
||||
'Otherwise, wait a few minutes and try again.'),
|
||||
common_config('site', 'name'),
|
||||
common_config('site', 'email'));
|
||||
|
||||
$dac = new DBErrorAction($msg, 500);
|
||||
$dac->showPage();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
$actionfile = INSTALLDIR."/actions/$action.php";
|
||||
function main()
|
||||
{
|
||||
global $user, $action;
|
||||
|
||||
if (!file_exists($actionfile)) {
|
||||
$cac = new ClientErrorAction(_('Unknown action'), 404);
|
||||
$cac->showPage();
|
||||
} else {
|
||||
// For database errors
|
||||
|
||||
include_once $actionfile;
|
||||
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
|
||||
|
||||
// XXX: we need a little more structure in this script
|
||||
|
||||
// get and cache current user
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
// initialize language env
|
||||
|
||||
common_init_language();
|
||||
|
||||
$path = getPath($_REQUEST);
|
||||
|
||||
$r = Router::get();
|
||||
|
||||
$args = $r->map($path);
|
||||
|
||||
if (!$args) {
|
||||
$cac = new ClientErrorAction(_('Unknown page'), 404);
|
||||
$cac->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$args = array_merge($args, $_REQUEST);
|
||||
|
||||
$action = $args['action'];
|
||||
|
||||
if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) {
|
||||
common_redirect(common_local_url('public'));
|
||||
return;
|
||||
}
|
||||
|
||||
// If the site is private, and they're not on one of the "public"
|
||||
// parts of the site, redirect to login
|
||||
|
||||
if (!$user && common_config('site', 'private') &&
|
||||
!in_array($action, array('login', 'openidlogin', 'finishopenidlogin',
|
||||
'recoverpassword', 'api', 'doc', 'register'))) {
|
||||
common_redirect(common_local_url('login'));
|
||||
return;
|
||||
}
|
||||
|
||||
$action_class = ucfirst($action).'Action';
|
||||
|
||||
$action_obj = new $action_class();
|
||||
|
||||
if ($config['db']['mirror'] && $action_obj->isReadOnly()) {
|
||||
if (is_array($config['db']['mirror'])) {
|
||||
// "load balancing", ha ha
|
||||
$k = array_rand($config['db']['mirror']);
|
||||
|
||||
$mirror = $config['db']['mirror'][$k];
|
||||
} else {
|
||||
$mirror = $config['db']['mirror'];
|
||||
}
|
||||
$config['db']['database'] = $mirror;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($action_obj->prepare($_REQUEST)) {
|
||||
$action_obj->handle($_REQUEST);
|
||||
}
|
||||
} catch (ClientException $cex) {
|
||||
$cac = new ClientErrorAction($cex->getMessage(), $cex->getCode());
|
||||
if (!class_exists($action_class)) {
|
||||
$cac = new ClientErrorAction(_('Unknown action'), 404);
|
||||
$cac->showPage();
|
||||
} catch (ServerException $sex) { // snort snort guffaw
|
||||
$sac = new ServerErrorAction($sex->getMessage(), $sex->getCode());
|
||||
$sac->showPage();
|
||||
} catch (Exception $ex) {
|
||||
$sac = new ServerErrorAction($ex->getMessage());
|
||||
$sac->showPage();
|
||||
} else {
|
||||
$action_obj = new $action_class();
|
||||
|
||||
// XXX: find somewhere for this little block to live
|
||||
|
||||
if (common_config('db', 'mirror') && $action_obj->isReadOnly()) {
|
||||
if (is_array(common_config('db', 'mirror'))) {
|
||||
// "load balancing", ha ha
|
||||
$k = array_rand($config['db']['mirror']);
|
||||
|
||||
$mirror = $config['db']['mirror'][$k];
|
||||
} else {
|
||||
$mirror = $config['db']['mirror'];
|
||||
}
|
||||
$config['db']['database'] = $mirror;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($action_obj->prepare($args)) {
|
||||
$action_obj->handle($args);
|
||||
}
|
||||
} catch (ClientException $cex) {
|
||||
$cac = new ClientErrorAction($cex->getMessage(), $cex->getCode());
|
||||
$cac->showPage();
|
||||
} catch (ServerException $sex) { // snort snort guffaw
|
||||
$sac = new ServerErrorAction($sex->getMessage(), $sex->getCode());
|
||||
$sac->showPage();
|
||||
} catch (Exception $ex) {
|
||||
$sac = new ServerErrorAction($ex->getMessage());
|
||||
$sac->showPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
// XXX: cleanup exit() calls or add an exit handler so
|
||||
// this always gets called
|
||||
|
||||
|
24
js/flowplayer-3.0.5.min.js
vendored
Normal file
24
js/flowplayer-3.0.5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
// identica badge -- updated to work with the native API, 12-4-2008
|
||||
// Modified to point to Identi.ca, 2-20-2009 by Zach
|
||||
// copyright Kent Brewster 2008
|
||||
// see http://kentbrewster.com/identica-badge for info
|
||||
( function() {
|
||||
@ -127,7 +128,7 @@
|
||||
var a = document.createElement('A');
|
||||
a.innerHTML = 'get this';
|
||||
a.target = '_blank';
|
||||
a.href = 'http://kentbrewster.com/identica-badge';
|
||||
a.href = 'http://identica/doc/badge';
|
||||
$.s.f.appendChild(a);
|
||||
$.s.appendChild($.s.f);
|
||||
$.f.getUser();
|
||||
|
220
js/jquery.js
vendored
220
js/jquery.js
vendored
@ -1,13 +1,13 @@
|
||||
/*!
|
||||
* jQuery JavaScript Library v1.3
|
||||
* jQuery JavaScript Library v1.3.1
|
||||
* http://jquery.com/
|
||||
*
|
||||
* Copyright (c) 2009 John Resig
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://docs.jquery.com/License
|
||||
*
|
||||
* Date: 2009-01-13 12:50:31 -0500 (Tue, 13 Jan 2009)
|
||||
* Revision: 6104
|
||||
* Date: 2009-01-21 20:42:16 -0500 (Wed, 21 Jan 2009)
|
||||
* Revision: 6158
|
||||
*/
|
||||
(function(){
|
||||
|
||||
@ -60,20 +60,16 @@ jQuery.fn = jQuery.prototype = {
|
||||
else {
|
||||
var elem = document.getElementById( match[3] );
|
||||
|
||||
// Make sure an element was located
|
||||
if ( elem ){
|
||||
// Handle the case where IE and Opera return items
|
||||
// by name instead of ID
|
||||
if ( elem.id != match[3] )
|
||||
return jQuery().find( selector );
|
||||
// Handle the case where IE and Opera return items
|
||||
// by name instead of ID
|
||||
if ( elem && elem.id != match[3] )
|
||||
return jQuery().find( selector );
|
||||
|
||||
// Otherwise, we inject the element directly into the jQuery object
|
||||
var ret = jQuery( elem );
|
||||
ret.context = document;
|
||||
ret.selector = selector;
|
||||
return ret;
|
||||
}
|
||||
selector = [];
|
||||
// Otherwise, we inject the element directly into the jQuery object
|
||||
var ret = jQuery( elem || [] );
|
||||
ret.context = document;
|
||||
ret.selector = selector;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// HANDLE: $(expr, [context])
|
||||
@ -99,7 +95,7 @@ jQuery.fn = jQuery.prototype = {
|
||||
selector: "",
|
||||
|
||||
// The current version of jQuery being used
|
||||
jquery: "1.3",
|
||||
jquery: "1.3.1",
|
||||
|
||||
// The number of elements contained in the matched element set
|
||||
size: function() {
|
||||
@ -634,8 +630,8 @@ jQuery.extend({
|
||||
|
||||
// check if an element is in a (or is an) XML document
|
||||
isXMLDoc: function( elem ) {
|
||||
return elem.documentElement && !elem.body ||
|
||||
elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
|
||||
return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
|
||||
!!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
|
||||
},
|
||||
|
||||
// Evalulates a script in a global context
|
||||
@ -725,7 +721,7 @@ jQuery.extend({
|
||||
|
||||
// internal only, use hasClass("class")
|
||||
has: function( elem, className ) {
|
||||
return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
|
||||
return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
|
||||
}
|
||||
},
|
||||
|
||||
@ -999,9 +995,11 @@ jQuery.extend({
|
||||
var attributeNode = elem.getAttributeNode( "tabIndex" );
|
||||
return attributeNode && attributeNode.specified
|
||||
? attributeNode.value
|
||||
: elem.nodeName.match(/^(a|area|button|input|object|select|textarea)$/i)
|
||||
: elem.nodeName.match(/(button|input|object|select|textarea)/i)
|
||||
? 0
|
||||
: undefined;
|
||||
: elem.nodeName.match(/^(a|area)$/i) && elem.href
|
||||
? 0
|
||||
: undefined;
|
||||
}
|
||||
|
||||
return elem[ name ];
|
||||
@ -1397,14 +1395,14 @@ jQuery.fn.extend({
|
||||
});
|
||||
}
|
||||
});/*!
|
||||
* Sizzle CSS Selector Engine - v0.9.1
|
||||
* Sizzle CSS Selector Engine - v0.9.3
|
||||
* Copyright 2009, The Dojo Foundation
|
||||
* Released under the MIT, BSD, and GPL Licenses.
|
||||
* More information: http://sizzlejs.com/
|
||||
*/
|
||||
(function(){
|
||||
|
||||
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
|
||||
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]+['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
|
||||
done = 0,
|
||||
toString = Object.prototype.toString;
|
||||
|
||||
@ -1433,40 +1431,27 @@ var Sizzle = function(selector, context, results, seed) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( parts.length > 1 && Expr.match.POS.exec( selector ) ) {
|
||||
if ( parts.length > 1 && origPOS.exec( selector ) ) {
|
||||
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
|
||||
var later = "", match;
|
||||
|
||||
// Position selectors must be done after the filter
|
||||
while ( (match = Expr.match.POS.exec( selector )) ) {
|
||||
later += match[0];
|
||||
selector = selector.replace( Expr.match.POS, "" );
|
||||
}
|
||||
|
||||
set = Sizzle.filter( later, Sizzle( /\s$/.test(selector) ? selector + "*" : selector, context ) );
|
||||
set = posProcess( parts[0] + parts[1], context );
|
||||
} else {
|
||||
set = Expr.relative[ parts[0] ] ?
|
||||
[ context ] :
|
||||
Sizzle( parts.shift(), context );
|
||||
|
||||
while ( parts.length ) {
|
||||
var tmpSet = [];
|
||||
|
||||
selector = parts.shift();
|
||||
|
||||
if ( Expr.relative[ selector ] )
|
||||
selector += parts.shift();
|
||||
|
||||
for ( var i = 0, l = set.length; i < l; i++ ) {
|
||||
Sizzle( selector, set[i], tmpSet );
|
||||
}
|
||||
|
||||
set = tmpSet;
|
||||
set = posProcess( selector, set );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var ret = seed ?
|
||||
{ expr: parts.pop(), set: makeArray(seed) } :
|
||||
Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context );
|
||||
Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
|
||||
set = Sizzle.filter( ret.expr, ret.set );
|
||||
|
||||
if ( parts.length > 0 ) {
|
||||
@ -1531,7 +1516,7 @@ Sizzle.matches = function(expr, set){
|
||||
return Sizzle(expr, null, null, set);
|
||||
};
|
||||
|
||||
Sizzle.find = function(expr, context){
|
||||
Sizzle.find = function(expr, context, isXML){
|
||||
var set, match;
|
||||
|
||||
if ( !expr ) {
|
||||
@ -1546,7 +1531,7 @@ Sizzle.find = function(expr, context){
|
||||
|
||||
if ( left.substr( left.length - 1 ) !== "\\" ) {
|
||||
match[1] = (match[1] || "").replace(/\\/g, "");
|
||||
set = Expr.find[ type ]( match, context );
|
||||
set = Expr.find[ type ]( match, context, isXML );
|
||||
if ( set != null ) {
|
||||
expr = expr.replace( Expr.match[ type ], "" );
|
||||
break;
|
||||
@ -1568,7 +1553,7 @@ Sizzle.filter = function(expr, set, inplace, not){
|
||||
while ( expr && set.length ) {
|
||||
for ( var type in Expr.filter ) {
|
||||
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
|
||||
var filter = Expr.filter[ type ], goodArray = null, goodPos = 0, found, item;
|
||||
var filter = Expr.filter[ type ], found, item;
|
||||
anyFound = false;
|
||||
|
||||
if ( curLoop == result ) {
|
||||
@ -1582,26 +1567,13 @@ Sizzle.filter = function(expr, set, inplace, not){
|
||||
anyFound = found = true;
|
||||
} else if ( match === true ) {
|
||||
continue;
|
||||
} else if ( match[0] === true ) {
|
||||
goodArray = [];
|
||||
var last = null, elem;
|
||||
for ( var i = 0; (elem = curLoop[i]) !== undefined; i++ ) {
|
||||
if ( elem && last !== elem ) {
|
||||
goodArray.push( elem );
|
||||
last = elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( match ) {
|
||||
for ( var i = 0; (item = curLoop[i]) !== undefined; i++ ) {
|
||||
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
|
||||
if ( item ) {
|
||||
if ( goodArray && item != goodArray[goodPos] ) {
|
||||
goodPos++;
|
||||
}
|
||||
|
||||
found = filter( item, match, goodPos, goodArray );
|
||||
found = filter( item, match, i, curLoop );
|
||||
var pass = not ^ !!found;
|
||||
|
||||
if ( inplace && found != null ) {
|
||||
@ -1739,14 +1711,16 @@ var Expr = Sizzle.selectors = {
|
||||
}
|
||||
},
|
||||
find: {
|
||||
ID: function(match, context){
|
||||
if ( context.getElementById ) {
|
||||
ID: function(match, context, isXML){
|
||||
if ( typeof context.getElementById !== "undefined" && !isXML ) {
|
||||
var m = context.getElementById(match[1]);
|
||||
return m ? [m] : [];
|
||||
}
|
||||
},
|
||||
NAME: function(match, context){
|
||||
return context.getElementsByName ? context.getElementsByName(match[1]) : null;
|
||||
NAME: function(match, context, isXML){
|
||||
if ( typeof context.getElementsByName !== "undefined" && !isXML ) {
|
||||
return context.getElementsByName(match[1]);
|
||||
}
|
||||
},
|
||||
TAG: function(match, context){
|
||||
return context.getElementsByTagName(match[1]);
|
||||
@ -1756,12 +1730,15 @@ var Expr = Sizzle.selectors = {
|
||||
CLASS: function(match, curLoop, inplace, result, not){
|
||||
match = " " + match[1].replace(/\\/g, "") + " ";
|
||||
|
||||
for ( var i = 0; curLoop[i]; i++ ) {
|
||||
if ( not ^ (" " + curLoop[i].className + " ").indexOf(match) >= 0 ) {
|
||||
if ( !inplace )
|
||||
result.push( curLoop[i] );
|
||||
} else if ( inplace ) {
|
||||
curLoop[i] = false;
|
||||
var elem;
|
||||
for ( var i = 0; (elem = curLoop[i]) != null; i++ ) {
|
||||
if ( elem ) {
|
||||
if ( not ^ (" " + elem.className + " ").indexOf(match) >= 0 ) {
|
||||
if ( !inplace )
|
||||
result.push( elem );
|
||||
} else if ( inplace ) {
|
||||
curLoop[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1771,8 +1748,8 @@ var Expr = Sizzle.selectors = {
|
||||
return match[1].replace(/\\/g, "");
|
||||
},
|
||||
TAG: function(match, curLoop){
|
||||
for ( var i = 0; !curLoop[i]; i++ ){}
|
||||
return isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
|
||||
for ( var i = 0; curLoop[i] === false; i++ ){}
|
||||
return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
|
||||
},
|
||||
CHILD: function(match){
|
||||
if ( match[1] == "nth" ) {
|
||||
@ -1792,7 +1769,7 @@ var Expr = Sizzle.selectors = {
|
||||
return match;
|
||||
},
|
||||
ATTR: function(match){
|
||||
var name = match[1];
|
||||
var name = match[1].replace(/\\/g, "");
|
||||
|
||||
if ( Expr.attrMap[name] ) {
|
||||
match[1] = Expr.attrMap[name];
|
||||
@ -1916,7 +1893,7 @@ var Expr = Sizzle.selectors = {
|
||||
CHILD: function(elem, match){
|
||||
var type = match[1], parent = elem.parentNode;
|
||||
|
||||
var doneName = "child" + parent.childNodes.length;
|
||||
var doneName = match[0];
|
||||
|
||||
if ( parent && (!parent[ doneName ] || !elem.nodeIndex) ) {
|
||||
var count = 1;
|
||||
@ -1985,7 +1962,7 @@ var Expr = Sizzle.selectors = {
|
||||
ATTR: function(elem, match){
|
||||
var result = Expr.attrHandle[ match[1] ] ? Expr.attrHandle[ match[1] ]( elem ) : elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
|
||||
return result == null ?
|
||||
false :
|
||||
type === "!=" :
|
||||
type === "=" ?
|
||||
value === check :
|
||||
type === "*=" ?
|
||||
@ -2014,6 +1991,8 @@ var Expr = Sizzle.selectors = {
|
||||
}
|
||||
};
|
||||
|
||||
var origPOS = Expr.match.POS;
|
||||
|
||||
for ( var type in Expr.match ) {
|
||||
Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
|
||||
}
|
||||
@ -2072,15 +2051,15 @@ try {
|
||||
// The workaround has to do additional checks after a getElementById
|
||||
// Which slows things down for other browsers (hence the branching)
|
||||
if ( !!document.getElementById( id ) ) {
|
||||
Expr.find.ID = function(match, context){
|
||||
if ( context.getElementById ) {
|
||||
Expr.find.ID = function(match, context, isXML){
|
||||
if ( typeof context.getElementById !== "undefined" && !isXML ) {
|
||||
var m = context.getElementById(match[1]);
|
||||
return m ? m.id === match[1] || m.getAttributeNode && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
|
||||
return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
|
||||
}
|
||||
};
|
||||
|
||||
Expr.filter.ID = function(elem, match){
|
||||
var node = elem.getAttributeNode && elem.getAttributeNode("id");
|
||||
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
|
||||
return elem.nodeType === 1 && node && node.nodeValue === match;
|
||||
};
|
||||
}
|
||||
@ -2120,7 +2099,7 @@ try {
|
||||
|
||||
// Check to see if an attribute returns normalized href attributes
|
||||
div.innerHTML = "<a href='#'></a>";
|
||||
if ( div.firstChild.getAttribute("href") !== "#" ) {
|
||||
if ( div.firstChild && div.firstChild.getAttribute("href") !== "#" ) {
|
||||
Expr.attrHandle.href = function(elem){
|
||||
return elem.getAttribute("href", 2);
|
||||
};
|
||||
@ -2128,12 +2107,21 @@ try {
|
||||
})();
|
||||
|
||||
if ( document.querySelectorAll ) (function(){
|
||||
var oldSizzle = Sizzle;
|
||||
var oldSizzle = Sizzle, div = document.createElement("div");
|
||||
div.innerHTML = "<p class='TEST'></p>";
|
||||
|
||||
// Safari can't handle uppercase or unicode characters when
|
||||
// in quirks mode.
|
||||
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sizzle = function(query, context, extra, seed){
|
||||
context = context || document;
|
||||
|
||||
if ( !seed && context.nodeType === 9 ) {
|
||||
// Only use querySelectorAll on non-XML documents
|
||||
// (ID selectors don't work in non-HTML documents)
|
||||
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
|
||||
try {
|
||||
return makeArray( context.querySelectorAll(query), extra );
|
||||
} catch(e){}
|
||||
@ -2148,7 +2136,7 @@ if ( document.querySelectorAll ) (function(){
|
||||
Sizzle.matches = oldSizzle.matches;
|
||||
})();
|
||||
|
||||
if ( document.documentElement.getElementsByClassName ) {
|
||||
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) {
|
||||
Expr.order.splice(1, 0, "CLASS");
|
||||
Expr.find.CLASS = function(match, context) {
|
||||
return context.getElementsByClassName(match[1]);
|
||||
@ -2229,8 +2217,28 @@ var contains = document.compareDocumentPosition ? function(a, b){
|
||||
};
|
||||
|
||||
var isXML = function(elem){
|
||||
return elem.documentElement && !elem.body ||
|
||||
elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
|
||||
return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
|
||||
!!elem.ownerDocument && isXML( elem.ownerDocument );
|
||||
};
|
||||
|
||||
var posProcess = function(selector, context){
|
||||
var tmpSet = [], later = "", match,
|
||||
root = context.nodeType ? [context] : context;
|
||||
|
||||
// Position selectors must be done after the filter
|
||||
// And so must :not(positional) so we move all PSEUDOs to the end
|
||||
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
|
||||
later += match[0];
|
||||
selector = selector.replace( Expr.match.PSEUDO, "" );
|
||||
}
|
||||
|
||||
selector = Expr.relative[selector] ? selector + "*" : selector;
|
||||
|
||||
for ( var i = 0, l = root.length; i < l; i++ ) {
|
||||
Sizzle( selector, root[i], tmpSet );
|
||||
}
|
||||
|
||||
return Sizzle.filter( later, tmpSet );
|
||||
};
|
||||
|
||||
// EXPOSE
|
||||
@ -2681,13 +2689,13 @@ jQuery.Event = function( src ){
|
||||
if( src && src.type ){
|
||||
this.originalEvent = src;
|
||||
this.type = src.type;
|
||||
this.timeStamp = src.timeStamp;
|
||||
// Event type
|
||||
}else
|
||||
this.type = src;
|
||||
|
||||
if( !this.timeStamp )
|
||||
this.timeStamp = now();
|
||||
// timeStamp is buggy for some events on Firefox(#3843)
|
||||
// So we won't rely on the native value
|
||||
this.timeStamp = now();
|
||||
|
||||
// Mark it as fixed
|
||||
this[expando] = true;
|
||||
@ -2876,9 +2884,8 @@ function liveHandler( event ){
|
||||
});
|
||||
|
||||
jQuery.each(elems, function(){
|
||||
if ( !event.isImmediatePropagationStopped() &&
|
||||
this.fn.call(this.elem, event, this.fn.data) === false )
|
||||
stop = false;
|
||||
if ( this.fn.call(this.elem, event, this.fn.data) === false )
|
||||
stop = false;
|
||||
});
|
||||
|
||||
return stop;
|
||||
@ -2942,7 +2949,7 @@ function bindReady(){
|
||||
|
||||
// If IE and not an iframe
|
||||
// continually check to see if the document is ready
|
||||
if ( document.documentElement.doScroll && !window.frameElement ) (function(){
|
||||
if ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){
|
||||
if ( jQuery.isReady ) return;
|
||||
|
||||
try {
|
||||
@ -3477,6 +3484,9 @@ jQuery.extend({
|
||||
// Fire the complete handlers
|
||||
complete();
|
||||
|
||||
if ( isTimeout )
|
||||
xhr.abort();
|
||||
|
||||
// Stop memory leaks
|
||||
if ( s.async )
|
||||
xhr = null;
|
||||
@ -3491,14 +3501,8 @@ jQuery.extend({
|
||||
if ( s.timeout > 0 )
|
||||
setTimeout(function(){
|
||||
// Check to see if the request is still happening
|
||||
if ( xhr ) {
|
||||
if( !requestDone )
|
||||
onreadystatechange( "timeout" );
|
||||
|
||||
// Cancel the request
|
||||
if ( xhr )
|
||||
xhr.abort();
|
||||
}
|
||||
if ( xhr && !requestDone )
|
||||
onreadystatechange( "timeout" );
|
||||
}, s.timeout);
|
||||
}
|
||||
|
||||
@ -3637,6 +3641,7 @@ jQuery.extend({
|
||||
|
||||
});
|
||||
var elemdisplay = {},
|
||||
timerId,
|
||||
fxAttrs = [
|
||||
// height animations
|
||||
[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
|
||||
@ -3859,7 +3864,6 @@ jQuery.extend({
|
||||
},
|
||||
|
||||
timers: [],
|
||||
timerId: null,
|
||||
|
||||
fx: function( elem, options, prop ){
|
||||
this.options = options;
|
||||
@ -3911,10 +3915,8 @@ jQuery.fx.prototype = {
|
||||
|
||||
t.elem = this.elem;
|
||||
|
||||
jQuery.timers.push(t);
|
||||
|
||||
if ( t() && jQuery.timerId == null ) {
|
||||
jQuery.timerId = setInterval(function(){
|
||||
if ( t() && jQuery.timers.push(t) == 1 ) {
|
||||
timerId = setInterval(function(){
|
||||
var timers = jQuery.timers;
|
||||
|
||||
for ( var i = 0; i < timers.length; i++ )
|
||||
@ -3922,8 +3924,7 @@ jQuery.fx.prototype = {
|
||||
timers.splice(i--, 1);
|
||||
|
||||
if ( !timers.length ) {
|
||||
clearInterval( jQuery.timerId );
|
||||
jQuery.timerId = null;
|
||||
clearInterval( timerId );
|
||||
}
|
||||
}, 13);
|
||||
}
|
||||
@ -3989,11 +3990,10 @@ jQuery.fx.prototype = {
|
||||
if ( this.options.hide || this.options.show )
|
||||
for ( var p in this.options.curAnim )
|
||||
jQuery.attr(this.elem.style, p, this.options.orig[p]);
|
||||
}
|
||||
|
||||
if ( done )
|
||||
// Execute the complete function
|
||||
this.options.complete.call( this.elem );
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
@ -4087,7 +4087,7 @@ jQuery.offset = {
|
||||
initialize: function() {
|
||||
if ( this.initialized ) return;
|
||||
var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
|
||||
html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"cellpadding="0"cellspacing="0"><tr><td></td></tr></table>';
|
||||
html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
|
||||
|
||||
rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
|
||||
for ( prop in rules ) container.style[prop] = rules[prop];
|
||||
|
12
js/jquery.min.js
vendored
12
js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
8
js/jquery.simplemodal-1.2.2.pack.js
Normal file
8
js/jquery.simplemodal-1.2.2.pack.js
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* SimpleModal 1.2.2 - jQuery Plugin
|
||||
* http://www.ericmmartin.com/projects/simplemodal/
|
||||
* Copyright (c) 2008 Eric Martin
|
||||
* Dual licensed under the MIT and GPL licenses
|
||||
* Revision: $Id: jquery.simplemodal.js 181 2008-12-16 16:51:44Z emartin24 $
|
||||
*/
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(g($){m f=$.Q.1Q&&1a($.Q.1D)==6&&!10[\'2g\'],1f=$.Q.1Q&&!$.2a,w=[];$.y=g(a,b){I $.y.12.1n(a,b)};$.y.D=g(){$.y.12.D()};$.1P.y=g(a){I $.y.12.1n(3,a)};$.y.1O={V:29,1J:\'r-H\',1B:{},1z:\'r-n\',20:{},1Z:{},v:2t,D:1o,1T:\'<a 2j="2h" 2f="2e"></a>\',X:\'r-D\',l:F,1g:K,1e:F,1d:F,1c:F};$.y.12={7:F,4:{},1n:g(a,b){8(3.4.j){I K}3.7=$.U({},$.y.1O,b);3.v=3.7.v;3.1w=K;8(J a==\'27\'){a=a 25 1A?a:$(a);8(a.1v().1v().23()>0){3.4.T=a.1v();8(!3.7.1g){3.4.21=a.2x(1o)}}}q 8(J a==\'2w\'||J a==\'1r\'){a=$(\'<1q/>\').2s(a)}q{2r(\'2q 2p: 2o j 2l: \'+J a);I K}3.4.j=a.11(\'r-j\').E(3.7.1Z);a=F;3.1S();3.1R();8($.1m(3.7.1d)){3.7.1d.1l(3,[3.4])}I 3},1S:g(){w=3.1k();8(f){3.4.x=$(\'<x 2d="2c:K;"/>\').E($.U(3.7.2b,{1j:\'1i\',V:0,l:\'1h\',A:w[0],z:w[1],v:3.7.v,L:0,B:0})).O(\'u\')}3.4.H=$(\'<1q/>\').1N(\'1M\',3.7.1J).11(\'r-H\').E($.U(3.7.1B,{1j:\'1i\',V:3.7.V/1b,A:w[0],z:w[1],l:\'1h\',B:0,L:0,v:3.7.v+1})).O(\'u\');3.4.n=$(\'<1q/>\').1N(\'1M\',3.7.1z).11(\'r-n\').E($.U(3.7.20,{1j:\'1i\',l:\'1h\',v:3.7.v+2})).1K(3.7.D?$(3.7.1T).11(3.7.X):\'\').O(\'u\');3.19();8(f||1f){3.18()}3.4.n.1K(3.4.j.1I())},1H:g(){m a=3;$(\'.\'+3.7.X).1G(\'1L.r\',g(e){e.28();a.D()});$(10).1G(\'1F.r\',g(){w=a.1k();a.19();8(f||1f){a.18()}q{a.4.x&&a.4.x.E({A:w[0],z:w[1]});a.4.H.E({A:w[0],z:w[1]})}})},1E:g(){$(\'.\'+3.7.X).1C(\'1L.r\');$(10).1C(\'1F.r\')},18:g(){m p=3.7.l;$.26([3.4.x||F,3.4.H,3.4.n],g(i,e){8(e){m a=\'k.u.17\',N=\'k.u.1W\',16=\'k.u.24\',S=\'k.u.1y\',R=\'k.u.1x\',15=\'k.u.22\',1t=\'k.P.17\',1s=\'k.P.1W\',C=\'k.P.1y\',G=\'k.P.1x\',s=e[0].2v;s.l=\'2u\';8(i<2){s.14(\'A\');s.14(\'z\');s.Z(\'A\',\'\'+16+\' > \'+a+\' ? \'+16+\' : \'+a+\' + "o"\');s.Z(\'z\',\'\'+15+\' > \'+N+\' ? \'+15+\' : \'+N+\' + "o"\')}q{m b,W;8(p&&p.1Y==1X){8(p[0]){m c=J p[0]==\'1r\'?p[0].1V():p[0].13(/o/,\'\');b=c.1U(\'%\')==-1?c+\' + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\':1a(c.13(/%/,\'\'))+\' * ((\'+1t+\' || \'+a+\') / 1b) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\'}8(p[1]){m d=J p[1]==\'1r\'?p[1].1V():p[1].13(/o/,\'\');W=d.1U(\'%\')==-1?d+\' + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\':1a(d.13(/%/,\'\'))+\' * ((\'+1s+\' || \'+N+\') / 1b) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}}q{b=\'(\'+1t+\' || \'+a+\') / 2 - (3.2n / 2) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\';W=\'(\'+1s+\' || \'+N+\') / 2 - (3.2m / 2) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}s.14(\'L\');s.14(\'B\');s.Z(\'L\',b);s.Z(\'B\',W)}}})},1k:g(){m a=$(10);m h=$.Q.2k&&$.Q.1D>\'9.5\'&&$.1P.2i<=\'1.2.6\'?k.P[\'17\']:a.A();I[h,a.z()]},19:g(){m a,B,1u=(w[0]/2)-((3.4.n.A()||3.4.j.A())/2),1p=(w[1]/2)-((3.4.n.z()||3.4.j.z())/2);8(3.7.l&&3.7.l.1Y==1X){a=3.7.l[0]||1u;B=3.7.l[1]||1p}q{a=1u;B=1p}3.4.n.E({B:B,L:a})},1R:g(){3.4.x&&3.4.x.Y();8($.1m(3.7.1e)){3.7.1e.1l(3,[3.4])}q{3.4.H.Y();3.4.n.Y();3.4.j.Y()}3.1H()},D:g(){8(!3.4.j){I K}8($.1m(3.7.1c)&&!3.1w){3.1w=1o;3.7.1c.1l(3,[3.4])}q{8(3.4.T){8(3.7.1g){3.4.j.1I().O(3.4.T)}q{3.4.j.M();3.4.21.O(3.4.T)}}q{3.4.j.M()}3.4.n.M();3.4.H.M();3.4.x&&3.4.x.M();3.4={}}3.1E()}}})(1A);',62,158,'|||this|dialog|||opts|if||||||||function|||data|document|position|var|container|px||else|simplemodal|||body|zIndex||iframe|modal|width|height|left|sl|close|css|null|st|overlay|return|typeof|false|top|remove|bcw|appendTo|documentElement|browser|bst|bsl|parentNode|extend|opacity|le|closeClass|show|setExpression|window|addClass|impl|replace|removeExpression|bsw|bsh|clientHeight|fixIE|setPosition|parseInt|100|onClose|onShow|onOpen|ieQuirks|persist|fixed|none|display|getDimensions|apply|isFunction|init|true|vCenter|div|number|cw|ch|hCenter|parent|occb|scrollTop|scrollLeft|containerId|jQuery|overlayCss|unbind|version|unbindEvents|resize|bind|bindEvents|hide|overlayId|append|click|id|attr|defaults|fn|msie|open|create|closeHTML|indexOf|toString|clientWidth|Array|constructor|dataCss|containerCss|orig|scrollWidth|size|scrollHeight|instanceof|each|object|preventDefault|50|boxModel|iframeCss|javascript|src|Close|title|XMLHttpRequest|modalCloseImg|jquery|class|opera|type|offsetWidth|offsetHeight|Unsupported|Error|SimpleModal|alert|html|1000|absolute|style|string|clone'.split('|'),0,{}))
|
9
js/video.js
Normal file
9
js/video.js
Normal file
@ -0,0 +1,9 @@
|
||||
$('document').ready(function() {
|
||||
$('a.media, a.mediamp3').append(' <sup>[PLAY]</sup>');
|
||||
$('a.mediamp3').html('').css('display', 'block').css('width', '224px').css('height','24px').flowplayer('../bin/flowplayer-3.0.5.swf');
|
||||
$('a.media').click(function() {
|
||||
$('<a id="p1i"></a>').attr('href', $(this).attr('href')).flowplayer('../bin/flowplayer-3.0.5.swf').modal({'closeHTML':'<a class="modalCloseImg" title="Close"><img src="x.png" /></a>'});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
147
lib/action.php
147
lib/action.php
@ -151,25 +151,46 @@ class Action extends HTMLOutputter // lawsuit
|
||||
*/
|
||||
function showStylesheets()
|
||||
{
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
foreach (array(6,7) as $ver) {
|
||||
if (file_exists(theme_file('css/ie'.$ver.'.css', 'base'))) {
|
||||
// Yes, IE people should be put in jail.
|
||||
$this->comment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie'.$ver.'.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
if (Event::handle('StartShowStyles', array($this))) {
|
||||
if (Event::handle('StartShowLaconicaStyles', array($this))) {
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/modal.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
if (common_config('site', 'mobile')) {
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
// TODO: "handheld" CSS for other mobile devices
|
||||
'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit
|
||||
}
|
||||
Event::handle('EndShowLaconicaStyles', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowUAStyles', array($this))) {
|
||||
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
foreach (array(6,7) as $ver) {
|
||||
if (file_exists(theme_file('css/ie'.$ver.'.css', 'base'))) {
|
||||
// Yes, IE people should be put in jail.
|
||||
$this->comment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie'.$ver.'.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
}
|
||||
}
|
||||
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
Event::handle('EndShowUAStyles', array($this));
|
||||
}
|
||||
Event::handle('EndShowStyles', array($this));
|
||||
}
|
||||
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
|
||||
'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" /><![endif]');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,6 +208,11 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/jquery.form.js')),
|
||||
' ');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/jquery.simplemodal-1.2.2.pack.js')),
|
||||
' ');
|
||||
|
||||
Event::handle('EndShowJQueryScripts', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||
@ -196,6 +222,17 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
|
||||
' ');
|
||||
// Frame-busting code to avoid clickjacking attacks.
|
||||
$this->element('script', array('type' => 'text/javascript'),
|
||||
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/flowplayer-3.0.5.min.js')),
|
||||
' ');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/video.js')),
|
||||
' ');
|
||||
Event::handle('EndShowLaconicaScripts', array($this));
|
||||
}
|
||||
Event::handle('EndShowScripts', array($this));
|
||||
@ -225,9 +262,19 @@ class Action extends HTMLOutputter // lawsuit
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
|
||||
function showFeeds()
|
||||
{
|
||||
// does nothing by default
|
||||
$feeds = $this->getFeeds();
|
||||
|
||||
if ($feeds) {
|
||||
foreach ($feeds as $feed) {
|
||||
$this->element('link', array('rel' => $feed->rel(),
|
||||
'href' => $feed->url,
|
||||
'type' => $feed->mimeType(),
|
||||
'title' => $feed->title));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,9 +312,15 @@ class Action extends HTMLOutputter // lawsuit
|
||||
{
|
||||
$this->elementStart('body', array('id' => $this->trimmed('action')));
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
$this->showHeader();
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
Event::handle('EndShowHeader', array($this));
|
||||
}
|
||||
$this->showCore();
|
||||
$this->showFooter();
|
||||
if (Event::handle('StartShowFooter', array($this))) {
|
||||
$this->showFooter();
|
||||
Event::handle('EndShowFooter', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('body');
|
||||
}
|
||||
@ -421,8 +474,14 @@ class Action extends HTMLOutputter // lawsuit
|
||||
function showCore()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'core'));
|
||||
$this->showLocalNavBlock();
|
||||
$this->showContentBlock();
|
||||
if (Event::handle('StartShowLocalNavBlock', array($this))) {
|
||||
$this->showLocalNavBlock();
|
||||
Event::handle('EndShowLocalNavBlock', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||
$this->showContentBlock();
|
||||
Event::handle('EndShowContentBlock', array($this));
|
||||
}
|
||||
$this->showAside();
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
@ -524,27 +583,32 @@ class Action extends HTMLOutputter // lawsuit
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
|
||||
function showAside()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'aside_primary',
|
||||
'class' => 'aside'));
|
||||
$this->showExportData();
|
||||
$this->showSections();
|
||||
if (Event::handle('StartShowSections', array($this))) {
|
||||
$this->showSections();
|
||||
Event::handle('EndShowSections', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show export data feeds.
|
||||
*
|
||||
* MAY overload if there are feeds
|
||||
*
|
||||
* @return nothing
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showExportData()
|
||||
{
|
||||
// is there structure to this?
|
||||
// list of (visible!) feed links
|
||||
// can we reuse list of feeds from showFeeds() ?
|
||||
$feeds = $this->getFeeds();
|
||||
if ($feeds) {
|
||||
$fl = new FeedList($this);
|
||||
$fl->show($feeds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -596,6 +660,8 @@ class Action extends HTMLOutputter // lawsuit
|
||||
_('Source'));
|
||||
$this->menuItem(common_local_url('doc', array('title' => 'contact')),
|
||||
_('Contact'));
|
||||
$this->menuItem(common_local_url('doc', array('title' => 'badge')),
|
||||
_('Badge'));
|
||||
Event::handle('EndSecondaryNav', array($this));
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
@ -750,8 +816,10 @@ class Action extends HTMLOutputter // lawsuit
|
||||
if ($if_modified_since) {
|
||||
$ims = strtotime($if_modified_since);
|
||||
if ($lm <= $ims) {
|
||||
if (!$etag ||
|
||||
$this->_hasEtag($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
$if_none_match = $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||
if (!$if_none_match ||
|
||||
!$etag ||
|
||||
$this->_hasEtag($etag, $if_none_match)) {
|
||||
header('HTTP/1.1 304 Not Modified');
|
||||
// Better way to do this?
|
||||
exit(0);
|
||||
@ -769,9 +837,11 @@ class Action extends HTMLOutputter // lawsuit
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
function _hasEtag($etag, $if_none_match)
|
||||
{
|
||||
return ($if_none_match) && in_array($etag, explode(',', $if_none_match));
|
||||
$etags = explode(',', $if_none_match);
|
||||
return in_array($etag, $etags) || in_array('*', $etags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -920,4 +990,17 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of feeds for this action.
|
||||
*
|
||||
* Returns an array of potential feeds for this action.
|
||||
*
|
||||
* @return array Feed object to show in head and links
|
||||
*/
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
class Channel
|
||||
{
|
||||
|
||||
function on($user)
|
||||
{
|
||||
return false;
|
@ -19,7 +19,7 @@
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/classes/Channel.php');
|
||||
require_once(INSTALLDIR.'/lib/channel.php');
|
||||
|
||||
class Command
|
||||
{
|
@ -19,11 +19,10 @@
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/classes/Command.php');
|
||||
require_once INSTALLDIR.'/lib/command.php';
|
||||
|
||||
class CommandInterpreter
|
||||
{
|
||||
|
||||
function handle_command($user, $text)
|
||||
{
|
||||
# XXX: localise
|
@ -106,7 +106,8 @@ $config =
|
||||
array('server' => null),
|
||||
'public' =>
|
||||
array('localonly' => true,
|
||||
'blacklist' => array()),
|
||||
'blacklist' => array(),
|
||||
'autosource' => array()),
|
||||
'theme' =>
|
||||
array('server' => null),
|
||||
'throttle' =>
|
||||
@ -211,6 +212,9 @@ function __autoload($class)
|
||||
require_once(INSTALLDIR.'/classes/' . $class . '.php');
|
||||
} else if (file_exists(INSTALLDIR.'/lib/' . strtolower($class) . '.php')) {
|
||||
require_once(INSTALLDIR.'/lib/' . strtolower($class) . '.php');
|
||||
} else if (mb_substr($class, -6) == 'Action' &&
|
||||
file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php')) {
|
||||
require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php');
|
||||
}
|
||||
}
|
||||
|
||||
|
73
lib/dberroraction.php
Normal file
73
lib/dberroraction.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* DB error action.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Zach Copley <zach@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/servererroraction.php';
|
||||
|
||||
/**
|
||||
* Class for displaying DB Errors
|
||||
*
|
||||
* This only occurs if there's been a DB_DataObject_Error that's
|
||||
* reported through PEAR, so we try to avoid doing anything that connects
|
||||
* to the DB, so we don't trigger it again.
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class DBErrorAction extends ServerErrorAction
|
||||
{
|
||||
function __construct($message='Error', $code=500)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Database error');
|
||||
}
|
||||
|
||||
function getLanguage()
|
||||
{
|
||||
// Don't try to figure out user's language; just show the page
|
||||
return common_config('site', 'language');
|
||||
}
|
||||
|
||||
function showPrimaryNav()
|
||||
{
|
||||
// don't show primary nav
|
||||
}
|
||||
}
|
@ -25,21 +25,6 @@ define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2
|
||||
define("FACEBOOK_NOTICE_PREFIX", 1);
|
||||
define("FACEBOOK_PROMPTED_UPDATE_PREF", 2);
|
||||
|
||||
// Gets all the notices from users with a Facebook link since a given ID
|
||||
function getFacebookNotices($since)
|
||||
{
|
||||
$qry = 'SELECT notice.* ' .
|
||||
'FROM notice ' .
|
||||
'JOIN foreign_link ' .
|
||||
'WHERE notice.profile_id = foreign_link.user_id ' .
|
||||
'AND foreign_link.service = 2';
|
||||
|
||||
// XXX: What should the limit be?
|
||||
//static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) {
|
||||
|
||||
return Notice::getStreamDirect($qry, 0, 1000, 0, 0, null, $since);
|
||||
}
|
||||
|
||||
function getFacebook()
|
||||
{
|
||||
$apikey = common_config('facebook', 'apikey');
|
||||
@ -52,3 +37,97 @@ function updateProfileBox($facebook, $flink, $notice) {
|
||||
$fbaction->updateProfileBox($notice);
|
||||
}
|
||||
|
||||
function isFacebookBound($notice, $flink) {
|
||||
|
||||
// If the user does not want to broadcast to Facebook, move along
|
||||
if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) {
|
||||
common_log(LOG_INFO, "Skipping notice $notice->id " .
|
||||
'because user has FOREIGN_NOTICE_SEND bit off.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = false;
|
||||
|
||||
// If it's not a reply, or if the user WANTS to send @-replies...
|
||||
if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) {
|
||||
|
||||
$success = true;
|
||||
|
||||
// The two condition below are deal breakers:
|
||||
|
||||
// Avoid a loop
|
||||
if ($notice->source == 'Facebook') {
|
||||
common_log(LOG_INFO, "Skipping notice $notice->id because its " .
|
||||
'source is Facebook.');
|
||||
$success = false;
|
||||
}
|
||||
|
||||
$facebook = getFacebook();
|
||||
$fbuid = $flink->foreign_id;
|
||||
|
||||
try {
|
||||
|
||||
// Check to see if the user has given the FB app status update perms
|
||||
$result = $facebook->api_client->
|
||||
users_hasAppPermission('status_update', $fbuid);
|
||||
|
||||
if ($result != 1) {
|
||||
$user = $flink->getUser();
|
||||
$msg = "Can't send notice $notice->id to Facebook " .
|
||||
"because user $user->nickname hasn't given the " .
|
||||
'Facebook app \'status_update\' permission.';
|
||||
common_log(LOG_INFO, $msg);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
} catch(FacebookRestClientException $e){
|
||||
common_log(LOG_ERR, $e->getMessage());
|
||||
$success = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $success;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function facebookBroadcastNotice($notice)
|
||||
{
|
||||
$facebook = getFacebook();
|
||||
$flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE);
|
||||
$fbuid = $flink->foreign_id;
|
||||
|
||||
if (isFacebookBound($notice, $flink)) {
|
||||
|
||||
$status = null;
|
||||
|
||||
// Get the status 'verb' (prefix) the user has set
|
||||
try {
|
||||
$prefix = $facebook->api_client->
|
||||
data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid);
|
||||
|
||||
$status = "$prefix $notice->content";
|
||||
|
||||
} catch(FacebookRestClientException $e) {
|
||||
common_log(LOG_ERR, $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Okay, we're good to go!
|
||||
|
||||
try {
|
||||
$facebook->api_client->users_setStatus($status, $fbuid, false, true);
|
||||
updateProfileBox($facebook, $flink, $notice);
|
||||
} catch(FacebookRestClientException $e) {
|
||||
common_log(LOG_ERR, $e->getMessage());
|
||||
return false;
|
||||
|
||||
// Should we remove flink if this fails?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -86,4 +86,9 @@ class FeaturedUsersSection extends ProfileSection
|
||||
{
|
||||
return 'featured_users';
|
||||
}
|
||||
|
||||
function moreUrl()
|
||||
{
|
||||
return common_local_url('featured');
|
||||
}
|
||||
}
|
||||
|
110
lib/feed.php
Normal file
110
lib/feed.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Data structure for info about syndication feeds (RSS 1.0, RSS 2.0, Atom)
|
||||
*
|
||||
* 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 Feed
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure for feeds
|
||||
*
|
||||
* This structure is a helpful container for shipping around information about syndication feeds.
|
||||
*
|
||||
* @category Feed
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class Feed
|
||||
{
|
||||
const RSS1 = 1;
|
||||
const RSS2 = 2;
|
||||
const ATOM = 3;
|
||||
const FOAF = 4;
|
||||
|
||||
var $type = null;
|
||||
var $url = null;
|
||||
var $title = null;
|
||||
|
||||
function __construct($type, $url, $title)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->url = $url;
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
function mimeType()
|
||||
{
|
||||
switch ($this->type) {
|
||||
case Feed::RSS1:
|
||||
return 'application/rdf+xml';
|
||||
case Feed::RSS2:
|
||||
return 'application/rss+xml';
|
||||
case Feed::ATOM:
|
||||
return 'application/atom+xml';
|
||||
case Feed::FOAF:
|
||||
return 'application/rdf+xml';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function typeName()
|
||||
{
|
||||
switch ($this->type) {
|
||||
case Feed::RSS1:
|
||||
return _('RSS 1.0');
|
||||
case Feed::RSS2:
|
||||
return _('RSS 2.0');
|
||||
case Feed::ATOM:
|
||||
return _('Atom');
|
||||
case Feed::FOAF:
|
||||
return _('FOAF');
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function rel()
|
||||
{
|
||||
switch ($this->type) {
|
||||
case Feed::RSS1:
|
||||
case Feed::RSS2:
|
||||
case Feed::ATOM:
|
||||
return 'alternate';
|
||||
case Feed::FOAF:
|
||||
return 'meta';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -64,8 +64,8 @@ class FeedList extends Widget
|
||||
$this->out->element('h2', null, _('Export data'));
|
||||
$this->out->elementStart('ul', array('class' => 'xoxo'));
|
||||
|
||||
foreach ($feeds as $key => $value) {
|
||||
$this->feedItem($feeds[$key]);
|
||||
foreach ($feeds as $feed) {
|
||||
$this->feedItem($feed);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
@ -74,85 +74,27 @@ class FeedList extends Widget
|
||||
|
||||
function feedItem($feed)
|
||||
{
|
||||
$nickname = $this->action->trimmed('nickname');
|
||||
$classname = null;
|
||||
|
||||
switch($feed['item']) {
|
||||
case 'notices': default:
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "$nickname's ".$feed['version']." notice feed";
|
||||
$feed['textContent'] = "RSS";
|
||||
switch ($feed->type) {
|
||||
case Feed::RSS1:
|
||||
case Feed::RSS2:
|
||||
$classname = 'rss';
|
||||
break;
|
||||
|
||||
case 'allrss':
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = $feed['version']." feed for $nickname and friends";
|
||||
$feed['textContent'] = "RSS";
|
||||
case Feed::ATOM:
|
||||
$classname = 'atom';
|
||||
break;
|
||||
|
||||
case 'repliesrss':
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = $feed['version']." feed for replies to $nickname";
|
||||
$feed['textContent'] = "RSS";
|
||||
break;
|
||||
|
||||
case 'publicrss':
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "Public timeline ".$feed['version']." feed";
|
||||
$feed['textContent'] = "RSS";
|
||||
break;
|
||||
|
||||
case 'publicatom':
|
||||
$feed_classname = "atom";
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "Public timeline ".$feed['version']." feed";
|
||||
$feed['textContent'] = "Atom";
|
||||
break;
|
||||
|
||||
case 'tagrss':
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = $feed['version']." feed for this tag";
|
||||
$feed['textContent'] = "RSS";
|
||||
break;
|
||||
|
||||
case 'favoritedrss':
|
||||
$feed_classname = $feed['type'];
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "Favorited ".$feed['version']." feed";
|
||||
$feed['textContent'] = "RSS";
|
||||
break;
|
||||
|
||||
case 'foaf':
|
||||
$feed_classname = "foaf";
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "$nickname's FOAF file";
|
||||
$feed['textContent'] = "FOAF";
|
||||
break;
|
||||
|
||||
case 'favoritesrss':
|
||||
$feed_classname = "favorites";
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "Feed for favorites of $nickname";
|
||||
$feed['textContent'] = "RSS";
|
||||
break;
|
||||
|
||||
case 'usertimeline':
|
||||
$feed_classname = "atom";
|
||||
$feed_mimetype = "application/".$feed['type']."+xml";
|
||||
$feed_title = "$nickname's ".$feed['version']." notice feed";
|
||||
$feed['textContent'] = "Atom";
|
||||
case Feed::FOAF:
|
||||
$classname = 'foaf';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->element('a', array('href' => $feed['href'],
|
||||
'class' => $feed_classname,
|
||||
'type' => $feed_mimetype,
|
||||
'title' => $feed_title),
|
||||
$feed['textContent']);
|
||||
$this->out->element('a', array('href' => $feed->url,
|
||||
'class' => $classname,
|
||||
'type' => $feed->mimeType(),
|
||||
'title' => $feed->title),
|
||||
$feed->typeName());
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ class GroupList extends Widget
|
||||
if ($this->group->location) {
|
||||
$this->out->elementStart('dl', 'entity_location');
|
||||
$this->out->element('dt', null, _('Location'));
|
||||
$this->out->elementStart('dd', 'location');
|
||||
$this->out->elementStart('dd', 'label');
|
||||
$this->out->raw($this->highlight($this->group->location));
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('dl');
|
||||
@ -151,7 +151,7 @@ class GroupList extends Widget
|
||||
|
||||
# If we're on a list with an owner (subscriptions or subscribers)...
|
||||
|
||||
if ($user && $user->id == $this->owner->id) {
|
||||
if (!empty($user) && !empty($this->owner) && $user->id == $this->owner->id) {
|
||||
$this->showOwnerControls();
|
||||
}
|
||||
|
||||
|
@ -101,9 +101,8 @@ class HTMLOutputter extends XMLOutputter
|
||||
$type = common_negotiate_type($cp, $sp);
|
||||
|
||||
if (!$type) {
|
||||
common_user_error(_('This page is not available in a '.
|
||||
'media type you accept'), 406);
|
||||
exit(0);
|
||||
throw new ClientException(_('This page is not available in a '.
|
||||
'media type you accept'), 406);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,15 +114,19 @@ class HTMLOutputter extends XMLOutputter
|
||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||
|
||||
// FIXME: correct language for interface
|
||||
|
||||
$language = common_language();
|
||||
$language = $this->getLanguage();
|
||||
|
||||
$this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||
'xml:lang' => $language,
|
||||
'lang' => $language));
|
||||
}
|
||||
|
||||
function getLanguage()
|
||||
{
|
||||
// FIXME: correct language for interface
|
||||
return common_language();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends an HTML document
|
||||
*
|
||||
@ -255,7 +258,7 @@ class HTMLOutputter extends XMLOutputter
|
||||
foreach ($content as $value => $option) {
|
||||
if ($value == $selected) {
|
||||
$this->element('option', array('value' => $value,
|
||||
'selected' => $value),
|
||||
'selected' => 'selected'),
|
||||
$option);
|
||||
} else {
|
||||
$this->element('option', array('value' => $value), $option);
|
||||
|
@ -68,17 +68,17 @@ class ImageFile
|
||||
static function fromUpload($param='upload')
|
||||
{
|
||||
switch ($_FILES[$param]['error']) {
|
||||
case UPLOAD_ERR_OK: // success, jump out
|
||||
case UPLOAD_ERR_OK: // success, jump out
|
||||
break;
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'), $this->maxFileSize()));
|
||||
return;
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
@unlink($_FILES[$param]['tmp_name']);
|
||||
throw new Exception(_('Partial upload.'));
|
||||
return;
|
||||
default:
|
||||
default:
|
||||
throw new Exception(_('System error uploading file.'));
|
||||
return;
|
||||
}
|
||||
@ -113,6 +113,23 @@ class ImageFile
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't crop/scale if it isn't necessary
|
||||
if ($size === $this->width
|
||||
&& $size === $this->height
|
||||
&& $x === 0
|
||||
&& $y === 0
|
||||
&& $w === $this->width
|
||||
&& $h === $this->height) {
|
||||
|
||||
$outname = Avatar::filename($this->id,
|
||||
image_type_to_extension($this->type),
|
||||
$size,
|
||||
common_timestamp());
|
||||
$outpath = Avatar::path($outname);
|
||||
@copy($this->filepath, $outpath);
|
||||
return $outname;
|
||||
}
|
||||
|
||||
switch ($this->type) {
|
||||
case IMAGETYPE_GIF:
|
||||
$image_src = imagecreatefromgif($this->filepath);
|
||||
@ -154,9 +171,9 @@ class ImageFile
|
||||
imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $size, $size, $w, $h);
|
||||
|
||||
$outname = Avatar::filename($this->id,
|
||||
image_type_to_extension($this->type),
|
||||
$size,
|
||||
common_timestamp());
|
||||
image_type_to_extension($this->type),
|
||||
$size,
|
||||
common_timestamp());
|
||||
|
||||
$outpath = Avatar::path($outname);
|
||||
|
||||
@ -165,7 +182,7 @@ class ImageFile
|
||||
imagegif($image_dest, $outpath);
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
imagejpeg($image_dest, $outpath);
|
||||
imagejpeg($image_dest, $outpath, 100);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
imagepng($image_dest, $outpath);
|
||||
@ -175,6 +192,9 @@ class ImageFile
|
||||
return;
|
||||
}
|
||||
|
||||
imagedestroy($image_src);
|
||||
imagedestroy($image_dest);
|
||||
|
||||
return $outname;
|
||||
}
|
||||
|
||||
@ -209,12 +229,12 @@ class ImageFile
|
||||
$num = substr($str, 0, -1);
|
||||
|
||||
switch(strtoupper($unit)){
|
||||
case 'G':
|
||||
$num *= 1024;
|
||||
case 'M':
|
||||
$num *= 1024;
|
||||
case 'K':
|
||||
$num *= 1024;
|
||||
case 'G':
|
||||
$num *= 1024;
|
||||
case 'M':
|
||||
$num *= 1024;
|
||||
case 'K':
|
||||
$num *= 1024;
|
||||
}
|
||||
|
||||
return $num;
|
||||
|
@ -114,7 +114,7 @@ function jabber_connect($resource=null)
|
||||
try {
|
||||
$conn->connect(true); // true = persistent connection
|
||||
} catch (XMPPHP_Exception $e) {
|
||||
common_log(LOG_ERROR, $e->getMessage());
|
||||
common_log(LOG_ERR, $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -186,6 +186,11 @@ function jabber_format_entry($profile, $notice)
|
||||
$entry .= "<id>". $notice->uri . "</id>\n";
|
||||
$entry .= "<published>".common_date_w3dtf($notice->created)."</published>\n";
|
||||
$entry .= "<updated>".common_date_w3dtf($notice->modified)."</updated>\n";
|
||||
if ($notice->reply_to) {
|
||||
$replyurl = common_local_url('shownotice',
|
||||
array('notice' => $notice->reply_to));
|
||||
$entry .= "<link rel='related' href='" . $replyurl . "'/>\n";
|
||||
}
|
||||
$entry .= "</entry>\n";
|
||||
|
||||
$html = "\n<html xmlns='http://jabber.org/protocol/xhtml-im'>\n";
|
||||
|
50
lib/mail.php
50
lib/mail.php
@ -573,3 +573,53 @@ function mail_notify_fave($other, $user, $notice)
|
||||
common_init_locale();
|
||||
mail_to_user($other, $subject, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* notify a user that they have received an "attn:" message AKA "@-reply"
|
||||
*
|
||||
* @param User $user The user who recevied the notice
|
||||
* @param Notice $notice The notice that was sent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function mail_notify_attn($user, $notice)
|
||||
{
|
||||
if (!$user->email || !$user->emailnotifyattn) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sender = $notice->getProfile();
|
||||
|
||||
$bestname = $sender->getBestName();
|
||||
|
||||
common_init_locale($user->language);
|
||||
|
||||
$subject = sprintf(_('%s sent a notice to your attention'), $bestname);
|
||||
|
||||
$body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
|
||||
"The notice is here:\n\n".
|
||||
"\t%3\$s\n\n" .
|
||||
"It reads:\n\n".
|
||||
"\t%4\$s\n\n" .
|
||||
"You can reply back here:\n\n".
|
||||
"\t%5\$s\n\n" .
|
||||
"The list of all @-replies for you here:\n\n" .
|
||||
"%6\$s\n\n" .
|
||||
"Faithfully yours,\n" .
|
||||
"%2\$s\n\n" .
|
||||
"P.S. You can turn off these email notifications here: %7\$s\n"),
|
||||
$bestname,
|
||||
common_config('site', 'name'),
|
||||
common_local_url('shownotice',
|
||||
array('notice' => $notice->id)),
|
||||
$notice->content,
|
||||
common_local_url('newnotice',
|
||||
array('replyto' => $sender->nickname)),
|
||||
common_local_url('replies',
|
||||
array('nickname' => $user->nickname)),
|
||||
common_local_url('emailsettings'));
|
||||
|
||||
common_init_locale();
|
||||
mail_to_user($user, $subject, $body);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class NoticeSection extends Section
|
||||
$this->out->elementStart('p', 'entry-content');
|
||||
$this->out->raw($notice->rendered);
|
||||
$this->out->elementEnd('p');
|
||||
if ($notice->value) {
|
||||
if (!empty($notice->value)) {
|
||||
$this->out->elementStart('p');
|
||||
$this->out->text($notice->value);
|
||||
$this->out->elementEnd('p');
|
||||
|
@ -239,7 +239,7 @@ function omb_broadcast_profile($profile)
|
||||
while ($sub->fetch()) {
|
||||
$rp = Remote_profile::staticGet('id', $sub->subscriber);
|
||||
if ($rp) {
|
||||
if (!$updated[$rp->updateprofileurl]) {
|
||||
if (!array_key_exists($rp->updateprofileurl, $updated)) {
|
||||
if (omb_update_profile($profile, $rp, $sub)) {
|
||||
$updated[$rp->updateprofileurl] = true;
|
||||
}
|
||||
@ -295,7 +295,9 @@ function omb_update_profile($profile, $remote_profile, $subscription)
|
||||
|
||||
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
|
||||
|
||||
if ($result->status == 403) { # not authorized, don't send again
|
||||
if (empty($result) || $result) {
|
||||
common_debug("Unable to contact " . $req->get_normalized_http_url());
|
||||
} else if ($result->status == 403) { # not authorized, don't send again
|
||||
common_debug('403 result, deleting subscription', __FILE__);
|
||||
$subscription->delete();
|
||||
return false;
|
||||
|
@ -64,6 +64,9 @@ function oid_set_last($openid_url)
|
||||
|
||||
function oid_get_last()
|
||||
{
|
||||
if (empty($_COOKIE[OPENID_COOKIE_KEY])) {
|
||||
return null;
|
||||
}
|
||||
$openid_url = $_COOKIE[OPENID_COOKIE_KEY];
|
||||
if ($openid_url && strlen($openid_url) > 0) {
|
||||
return $openid_url;
|
||||
|
75
lib/peoplesearchresults.php
Normal file
75
lib/peoplesearchresults.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* People search results class
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Widget
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/profilelist.php';
|
||||
|
||||
/**
|
||||
* People search results class
|
||||
*
|
||||
* Derivative of ProfileList with specialization for highlighting search terms.
|
||||
*
|
||||
* @category Widget
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* @see PeoplesearchAction
|
||||
*/
|
||||
|
||||
class PeopleSearchResults extends ProfileList
|
||||
{
|
||||
var $terms = null;
|
||||
var $pattern = null;
|
||||
|
||||
function __construct($profile, $terms, $action)
|
||||
{
|
||||
parent::__construct($profile, $terms, $action);
|
||||
$this->terms = array_map('preg_quote',
|
||||
array_map('htmlspecialchars', $terms));
|
||||
$this->pattern = '/('.implode('|',$terms).')/i';
|
||||
}
|
||||
|
||||
function highlight($text)
|
||||
{
|
||||
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
define('NOTICES_PER_SECTION', 5);
|
||||
|
||||
/**
|
||||
* Base class for sections showing lists of notices
|
||||
*
|
||||
@ -80,4 +78,9 @@ class PopularNoticeSection extends NoticeSection
|
||||
{
|
||||
return 'popular_notices';
|
||||
}
|
||||
|
||||
function moreUrl()
|
||||
{
|
||||
return common_local_url('favorited');
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,6 @@ if (!defined('LACONICA')) {
|
||||
|
||||
require_once INSTALLDIR.'/lib/widget.php';
|
||||
|
||||
define('PROFILES_PER_PAGE', 20);
|
||||
|
||||
/**
|
||||
* Widget to show a list of profiles
|
||||
*
|
||||
@ -123,7 +121,7 @@ class ProfileList extends Widget
|
||||
if ($this->profile->location) {
|
||||
$this->out->elementStart('dl', 'entity_location');
|
||||
$this->out->element('dt', null, _('Location'));
|
||||
$this->out->elementStart('dd', 'location');
|
||||
$this->out->elementStart('dd', 'label');
|
||||
$this->out->raw($this->highlight($this->profile->location));
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('dl');
|
||||
|
414
lib/router.php
Normal file
414
lib/router.php
Normal file
@ -0,0 +1,414 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* URL routing utilities
|
||||
*
|
||||
* 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 URL
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once 'Net/URL/Mapper.php';
|
||||
|
||||
/**
|
||||
* URL Router
|
||||
*
|
||||
* Cheap wrapper around Net_URL_Mapper
|
||||
*
|
||||
* @category URL
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class Router
|
||||
{
|
||||
var $m = null;
|
||||
static $inst = null;
|
||||
|
||||
static function get()
|
||||
{
|
||||
if (!Router::$inst) {
|
||||
Router::$inst = new Router();
|
||||
}
|
||||
return Router::$inst;
|
||||
}
|
||||
|
||||
function __construct()
|
||||
{
|
||||
if (!$this->m) {
|
||||
$this->m = $this->initialize();
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
$m = Net_URL_Mapper::getInstance();
|
||||
|
||||
// In the "root"
|
||||
|
||||
$m->connect('', array('action' => 'public'));
|
||||
$m->connect('rss', array('action' => 'publicrss'));
|
||||
$m->connect('xrds', array('action' => 'publicxrds'));
|
||||
$m->connect('featuredrss', array('action' => 'featuredrss'));
|
||||
$m->connect('favoritedrss', array('action' => 'favoritedrss'));
|
||||
$m->connect('opensearch/people', array('action' => 'opensearch',
|
||||
'type' => 'people'));
|
||||
$m->connect('opensearch/notice', array('action' => 'opensearch',
|
||||
'type' => 'notice'));
|
||||
|
||||
// docs
|
||||
|
||||
$m->connect('doc/:title', array('action' => 'doc'));
|
||||
|
||||
// facebook
|
||||
|
||||
$m->connect('facebook', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/index.php', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/settings.php', array('action' => 'facebooksettings'));
|
||||
$m->connect('facebook/invite.php', array('action' => 'facebookinvite'));
|
||||
$m->connect('facebook/remove', array('action' => 'facebookremove'));
|
||||
|
||||
// main stuff is repetitive
|
||||
|
||||
$main = array('login', 'logout', 'register', 'subscribe',
|
||||
'unsubscribe', 'confirmaddress', 'recoverpassword',
|
||||
'invite', 'favor', 'disfavor', 'sup',
|
||||
'block');
|
||||
|
||||
foreach ($main as $a) {
|
||||
$m->connect('main/'.$a, array('action' => $a));
|
||||
}
|
||||
|
||||
$m->connect('main/tagother/:id', array('action' => 'tagother'));
|
||||
|
||||
// these take a code
|
||||
|
||||
foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) {
|
||||
$m->connect('main/'.$c.'/:code', array('action' => $c));
|
||||
}
|
||||
|
||||
// exceptional
|
||||
|
||||
$m->connect('main/openid', array('action' => 'openidlogin'));
|
||||
$m->connect('main/remote', array('action' => 'remotesubscribe'));
|
||||
|
||||
// settings
|
||||
|
||||
foreach (array('profile', 'avatar', 'password', 'openid', 'im',
|
||||
'email', 'sms', 'twitter', 'other') as $s) {
|
||||
$m->connect('settings/'.$s, array('action' => $s.'settings'));
|
||||
}
|
||||
|
||||
// search
|
||||
|
||||
foreach (array('group', 'people', 'notice') as $s) {
|
||||
$m->connect('search/'.$s, array('action' => $s.'search'));
|
||||
}
|
||||
|
||||
$m->connect('search/notice/rss', array('action' => 'noticesearchrss'));
|
||||
|
||||
// notice
|
||||
|
||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||
$m->connect('notice/:notice',
|
||||
array('action' => 'shownotice'),
|
||||
array('notice' => '[0-9]+'));
|
||||
$m->connect('notice/delete', array('action' => 'deletenotice'));
|
||||
$m->connect('notice/delete/:notice',
|
||||
array('action' => 'deletenotice'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
||||
$m->connect('message/new', array('action' => 'newmessage'));
|
||||
$m->connect('message/:message',
|
||||
array('action' => 'showmessage'),
|
||||
array('message' => '[0-9]+'));
|
||||
|
||||
$m->connect('user/:id',
|
||||
array('action' => 'userbyid'),
|
||||
array('id' => '[0-9]+'));
|
||||
|
||||
$m->connect('tags/', array('action' => 'publictagcloud'));
|
||||
$m->connect('tag/', array('action' => 'publictagcloud'));
|
||||
$m->connect('tags', array('action' => 'publictagcloud'));
|
||||
$m->connect('tag', array('action' => 'publictagcloud'));
|
||||
$m->connect('tag/:tag/rss',
|
||||
array('action' => 'tagrss'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
$m->connect('tag/:tag',
|
||||
array('action' => 'tag'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('peopletag/:tag',
|
||||
array('action' => 'peopletag'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('featured/', array('action' => 'featured'));
|
||||
$m->connect('featured', array('action' => 'featured'));
|
||||
$m->connect('favorited/', array('action' => 'favorited'));
|
||||
$m->connect('favorited', array('action' => 'favorited'));
|
||||
|
||||
// groups
|
||||
|
||||
$m->connect('group/new', array('action' => 'newgroup'));
|
||||
|
||||
foreach (array('edit', 'join', 'leave') as $v) {
|
||||
$m->connect('group/:nickname/'.$v,
|
||||
array('action' => $v.'group'),
|
||||
array('nickname' => '[a-zA-Z0-9]+'));
|
||||
}
|
||||
|
||||
foreach (array('members', 'logo', 'rss') as $n) {
|
||||
$m->connect('group/:nickname/'.$n,
|
||||
array('action' => 'group'.$n),
|
||||
array('nickname' => '[a-zA-Z0-9]+'));
|
||||
}
|
||||
|
||||
$m->connect('group/:id/id',
|
||||
array('action' => 'groupbyid'),
|
||||
array('id' => '[0-9]+'));
|
||||
|
||||
$m->connect('group/:nickname',
|
||||
array('action' => 'showgroup'),
|
||||
array('nickname' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('group/', array('action' => 'groups'));
|
||||
$m->connect('group', array('action' => 'groups'));
|
||||
$m->connect('groups/', array('action' => 'groups'));
|
||||
$m->connect('groups', array('action' => 'groups'));
|
||||
|
||||
// Twitter-compatible API
|
||||
|
||||
// statuses API
|
||||
|
||||
$m->connect('api/statuses/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses'),
|
||||
array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|friends|followers|featured)(\.(atom|rss|xml|json))?'));
|
||||
|
||||
$m->connect('api/statuses/:method/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses'),
|
||||
array('method' => '(user_timeline|friends_timeline|show|destroy|friends|followers)'));
|
||||
|
||||
// users
|
||||
|
||||
$m->connect('api/users/show/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'users'));
|
||||
|
||||
$m->connect('api/users/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'users'),
|
||||
array('method' => 'show(\.(xml|json|atom|rss))?'));
|
||||
|
||||
// direct messages
|
||||
|
||||
foreach (array('xml', 'json') as $e) {
|
||||
$m->connect('api/direct_messages/new.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'direct_messages',
|
||||
'method' => 'create.'.$e));
|
||||
}
|
||||
|
||||
foreach (array('xml', 'json', 'rss', 'atom') as $e) {
|
||||
$m->connect('api/direct_messages.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'direct_messages',
|
||||
'method' => 'direct_messages.'.$e));
|
||||
}
|
||||
|
||||
foreach (array('xml', 'json', 'rss', 'atom') as $e) {
|
||||
$m->connect('api/direct_message/sent.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'direct_messages',
|
||||
'method' => 'sent.'.$e));
|
||||
}
|
||||
|
||||
$m->connect('api/direct_messages/destroy/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'direct_messages'));
|
||||
|
||||
// friendships
|
||||
|
||||
$m->connect('api/friendships/:method/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'friendships'),
|
||||
array('method' => '(create|destroy)'));
|
||||
|
||||
$m->connect('api/friendships/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'friendships'),
|
||||
array('method' => 'exists(\.(xml|json|rss|atom))'));
|
||||
|
||||
|
||||
// Social graph
|
||||
|
||||
$m->connect('api/friends/ids/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'friendsIDs'));
|
||||
|
||||
foreach (array('xml', 'json') as $e) {
|
||||
$m->connect('api/friends/ids.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'friendsIDs.'.$e));
|
||||
}
|
||||
|
||||
$m->connect('api/followers/ids/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'followersIDs'));
|
||||
|
||||
foreach (array('xml', 'json') as $e) {
|
||||
$m->connect('api/followers/ids.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'followersIDs.'.$e));
|
||||
}
|
||||
|
||||
// account
|
||||
|
||||
$m->connect('api/account/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'account'));
|
||||
|
||||
// favorites
|
||||
|
||||
$m->connect('api/favorites/:method/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'favorites'));
|
||||
|
||||
$m->connect('api/favorites/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'favorites',
|
||||
'method' => 'favorites'));
|
||||
|
||||
foreach (array('xml', 'json', 'rss', 'atom') as $e) {
|
||||
$m->connect('api/favorites.'.$e,
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'favorites',
|
||||
'method' => 'favorites.'.$e));
|
||||
}
|
||||
|
||||
// notifications
|
||||
|
||||
$m->connect('api/notifications/:method/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'favorites'));
|
||||
|
||||
// blocks
|
||||
|
||||
$m->connect('api/blocks/:method/:argument',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'blocks'));
|
||||
|
||||
// help
|
||||
|
||||
$m->connect('api/help/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'help'));
|
||||
|
||||
// laconica
|
||||
|
||||
$m->connect('api/laconica/:method',
|
||||
array('action' => 'api',
|
||||
'apiaction' => 'laconica'));
|
||||
|
||||
// user stuff
|
||||
|
||||
foreach (array('subscriptions', 'subscribers',
|
||||
'nudge', 'xrds', 'all', 'foaf',
|
||||
'replies', 'inbox', 'outbox', 'microsummary') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => $a),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/:tag',
|
||||
array('action' => $a),
|
||||
array('tag' => '[a-zA-Z0-9]+',
|
||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('rss', 'groups') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => 'user'.$a),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('all', 'replies', 'favorites') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/rss',
|
||||
array('action' => $a.'rss'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
$m->connect(':nickname/favorites',
|
||||
array('action' => 'showfavorites'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
||||
$m->connect(':nickname/avatar/:size',
|
||||
array('action' => 'avatarbynickname'),
|
||||
array('size' => '(original|96|48|24)',
|
||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
||||
$m->connect(':nickname',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
||||
return $m;
|
||||
}
|
||||
|
||||
function map($path)
|
||||
{
|
||||
try {
|
||||
$match = $this->m->match($path);
|
||||
} catch (Net_URL_Mapper_InvalidException $e) {
|
||||
common_log(LOG_ERR, "Problem getting route for $path - " .
|
||||
$e->getMessage());
|
||||
$cac = new ClientErrorAction("Page not found.", 404);
|
||||
$cac->showPage();
|
||||
}
|
||||
|
||||
return $match;
|
||||
}
|
||||
|
||||
function build($action, $args=null, $params=null, $fragment=null)
|
||||
{
|
||||
$action_arg = array('action' => $action);
|
||||
|
||||
if ($args) {
|
||||
$args = array_merge($action_arg, $args);
|
||||
} else {
|
||||
$args = $action_arg;
|
||||
}
|
||||
|
||||
return $this->m->generate($args, $params, $fragment);
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ class Rss10Action extends Action
|
||||
|
||||
var $creators = array();
|
||||
var $limit = DEFAULT_RSS_LIMIT;
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -93,6 +94,9 @@ class Rss10Action extends Action
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
// Get the list of notices
|
||||
$this->notices = $this->getNotices();
|
||||
// Parent handling, including cache check
|
||||
parent::handle($args);
|
||||
$this->showRss($this->limit);
|
||||
}
|
||||
@ -258,5 +262,25 @@ class Rss10Action extends Action
|
||||
{
|
||||
$this->elementEnd('rdf:RDF');
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this page last modified?
|
||||
*
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (empty($this->notices)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($this->notices) == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// FIXME: doesn't handle modified profiles, avatars, deleted notices
|
||||
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,10 +79,11 @@ class SearchAction extends Action
|
||||
|
||||
function showTop($arr=null)
|
||||
{
|
||||
$error = null;
|
||||
if ($arr) {
|
||||
$error = $arr[1];
|
||||
}
|
||||
if ($error) {
|
||||
if (!empty($error)) {
|
||||
$this->element('p', 'error', $error);
|
||||
} else {
|
||||
$instr = $this->getInstructions();
|
||||
|
@ -103,6 +103,6 @@ class Section extends Widget
|
||||
|
||||
function moreTitle()
|
||||
{
|
||||
return null;
|
||||
return _('More...');
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
define("TWITTER_SERVICE", 1); // Twitter is foreign_service ID 1
|
||||
|
||||
function get_twitter_data($uri, $screen_name, $password)
|
||||
{
|
||||
|
||||
@ -28,14 +30,13 @@ function get_twitter_data($uri, $screen_name, $password)
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
# CURLOPT_USERAGENT => "identi.ca",
|
||||
CURLOPT_USERAGENT => "Laconica",
|
||||
CURLOPT_CONNECTTIMEOUT => 120,
|
||||
CURLOPT_TIMEOUT => 120,
|
||||
# Twitter is strict about accepting invalid "Expect" headers
|
||||
CURLOPT_HTTPHEADER => array('Expect:')
|
||||
);
|
||||
|
||||
|
||||
$ch = curl_init($uri);
|
||||
curl_setopt_array($ch, $options);
|
||||
$data = curl_exec($ch);
|
||||
@ -95,7 +96,7 @@ function add_twitter_user($twitter_id, $screen_name)
|
||||
$fuser->nickname = $screen_name;
|
||||
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
||||
$fuser->id = $twitter_id;
|
||||
$fuser->service = 1; // Twitter
|
||||
$fuser->service = TWITTER_SERVICE; // Twitter
|
||||
$fuser->created = common_sql_now();
|
||||
$result = $fuser->insert();
|
||||
|
||||
@ -206,3 +207,93 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password)
|
||||
return true;
|
||||
}
|
||||
|
||||
function is_twitter_bound($notice, $flink) {
|
||||
|
||||
// Check to see if notice should go to Twitter
|
||||
if (($flink->noticesync & FOREIGN_NOTICE_SEND)) {
|
||||
|
||||
// If it's not a Twitter-style reply, or if the user WANTS to send replies.
|
||||
if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function broadcast_twitter($notice)
|
||||
{
|
||||
global $config;
|
||||
$success = true;
|
||||
|
||||
$flink = Foreign_link::getByUserID($notice->profile_id,
|
||||
TWITTER_SERVICE);
|
||||
|
||||
// XXX: Not sure WHERE to check whether a notice should go to
|
||||
// Twitter. Should we even put in the queue if it shouldn't? --Zach
|
||||
if (is_twitter_bound($notice, $flink)) {
|
||||
|
||||
$fuser = $flink->getForeignUser();
|
||||
$twitter_user = $fuser->nickname;
|
||||
$twitter_password = $flink->credentials;
|
||||
$uri = 'http://www.twitter.com/statuses/update.json';
|
||||
|
||||
// XXX: Hack to get around PHP cURL's use of @ being a a meta character
|
||||
$statustxt = preg_replace('/^@/', ' @', $notice->content);
|
||||
|
||||
$options = array(
|
||||
CURLOPT_USERPWD => "$twitter_user:$twitter_password",
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS =>
|
||||
array(
|
||||
'status' => $statustxt,
|
||||
'source' => $config['integration']['source']
|
||||
),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_USERAGENT => "Laconica",
|
||||
CURLOPT_CONNECTTIMEOUT => 120, // XXX: How long should this be?
|
||||
CURLOPT_TIMEOUT => 120,
|
||||
|
||||
# Twitter is strict about accepting invalid "Expect" headers
|
||||
CURLOPT_HTTPHEADER => array('Expect:')
|
||||
);
|
||||
|
||||
$ch = curl_init($uri);
|
||||
curl_setopt_array($ch, $options);
|
||||
$data = curl_exec($ch);
|
||||
$errmsg = curl_error($ch);
|
||||
|
||||
if ($errmsg) {
|
||||
common_debug("cURL error: $errmsg - " .
|
||||
"trying to send notice for $twitter_user.",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if (!$data) {
|
||||
common_debug("No data returned by Twitter's " .
|
||||
"API trying to send update for $twitter_user",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
// Twitter should return a status
|
||||
$status = json_decode($data);
|
||||
|
||||
if (!$status->id) {
|
||||
common_debug("Unexpected data returned by Twitter " .
|
||||
" API trying to send update for $twitter_user",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
|
458
lib/util.php
458
lib/util.php
@ -394,32 +394,32 @@ function common_render_text($text)
|
||||
|
||||
function common_replace_urls_callback($text, $callback) {
|
||||
// Start off with a regex
|
||||
$regex = '#
|
||||
(?:
|
||||
(?:
|
||||
(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc)://
|
||||
|
|
||||
(?:mailto|aim|tel):
|
||||
)
|
||||
[^.\s]+\.[^\s]+
|
||||
|
|
||||
(?:[^.\s/:]+\.)+
|
||||
(?:museum|travel|[a-z]{2,4})
|
||||
(?:[:/][^\s]*)?
|
||||
)
|
||||
#ix';
|
||||
$regex = '#'.
|
||||
'(?:'.
|
||||
'(?:'.
|
||||
'(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc)://'.
|
||||
'|'.
|
||||
'(?:mailto|aim|tel):'.
|
||||
')'.
|
||||
'[^.\s]+\.[^\s]+'.
|
||||
'|'.
|
||||
'(?:[^.\s/:]+\.)+'.
|
||||
'(?:museum|travel|[a-z]{2,4})'.
|
||||
'(?:[:/][^\s]*)?'.
|
||||
')'.
|
||||
'#ix';
|
||||
preg_match_all($regex, $text, $matches);
|
||||
|
||||
// Then clean up what the regex left behind
|
||||
$offset = 0;
|
||||
foreach($matches[0] as $url) {
|
||||
$url = htmlspecialchars_decode($url);
|
||||
foreach($matches[0] as $orig_url) {
|
||||
$url = htmlspecialchars_decode($orig_url);
|
||||
|
||||
// Make sure we didn't pick up an email address
|
||||
if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue;
|
||||
|
||||
// Remove trailing punctuation
|
||||
$url = rtrim($url, '.?!,;:\'"`');
|
||||
// Remove surrounding punctuation
|
||||
$url = trim($url, '.?!,;:\'"`([<');
|
||||
|
||||
// Remove surrounding parens and the like
|
||||
preg_match('/[)\]>]+$/', $url, $trailing);
|
||||
@ -446,7 +446,7 @@ function common_replace_urls_callback($text, $callback) {
|
||||
|
||||
// If the first part wasn't cap'd but the last part was, we captured too much
|
||||
if ((!$prev_part && $last_part)) {
|
||||
$url = substr_replace($url, '', mb_strpos($url, '.'.$url_parts[2], 0));
|
||||
$url = mb_substr($url, 0 , mb_strpos($url, '.'.$url_parts['2'], 0));
|
||||
}
|
||||
|
||||
// Capture the new TLD
|
||||
@ -456,6 +456,9 @@ function common_replace_urls_callback($text, $callback) {
|
||||
|
||||
if (!in_array($url_parts[2], $tlds)) continue;
|
||||
|
||||
// Put the url back the way we found it.
|
||||
$url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);
|
||||
|
||||
// Call user specified func
|
||||
$modified_url = $callback($url);
|
||||
|
||||
@ -469,16 +472,25 @@ function common_replace_urls_callback($text, $callback) {
|
||||
}
|
||||
|
||||
function common_linkify($url) {
|
||||
// It comes in special'd, so we unspecial it before passing to the stringifying
|
||||
// functions
|
||||
$ext = pathinfo($url, PATHINFO_EXTENSION);
|
||||
$url = htmlspecialchars_decode($url);
|
||||
$video_ext = array('mp4', 'flv', 'avi', 'mpg', 'mp3', 'ogg');
|
||||
$display = $url;
|
||||
$url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url:$url;
|
||||
$url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url;
|
||||
|
||||
$attrs = array('href' => $url, 'rel' => 'external');
|
||||
|
||||
if (in_array($ext, $video_ext)) {
|
||||
$attrs['class'] = 'media';
|
||||
}
|
||||
|
||||
if ($longurl = common_longurl($url)) {
|
||||
$longurl = htmlentities($longurl, ENT_QUOTES, 'UTF-8');
|
||||
$title = "title=\"$longurl\"";
|
||||
$attrs['title'] = $longurl;
|
||||
}
|
||||
else $title = '';
|
||||
|
||||
return "<a href=\"$url\" $title rel=\"external\">$display</a>";
|
||||
return XMLStringer::estring('a', $attrs, $display);
|
||||
}
|
||||
|
||||
function common_longurl($short_url)
|
||||
@ -579,7 +591,13 @@ function common_tag_link($tag)
|
||||
{
|
||||
$canonical = common_canonical_tag($tag);
|
||||
$url = common_local_url('tag', array('tag' => $canonical));
|
||||
return '<span class="tag"><a href="' . htmlspecialchars($url) . '" rel="tag">' . htmlspecialchars($tag) . '</a></span>';
|
||||
$xs = new XMLStringer();
|
||||
$xs->elementStart('span', 'tag');
|
||||
$xs->element('a', array('href' => $url,
|
||||
'rel' => 'tag'),
|
||||
$tag);
|
||||
$xs->elementEnd('span');
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
function common_canonical_tag($tag)
|
||||
@ -597,7 +615,14 @@ function common_at_link($sender_id, $nickname)
|
||||
$sender = Profile::staticGet($sender_id);
|
||||
$recipient = common_relative_profile($sender, common_canonical_nickname($nickname));
|
||||
if ($recipient) {
|
||||
return '<span class="vcard"><a href="'.htmlspecialchars($recipient->profileurl).'" class="url"><span class="fn nickname">'.$nickname.'</span></a></span>';
|
||||
$xs = new XMLStringer(false);
|
||||
$xs->elementStart('span', 'vcard');
|
||||
$xs->elementStart('a', array('href' => $recipient->profileurl,
|
||||
'class' => 'url'));
|
||||
$xs->element('span', 'fn nickname', $nickname);
|
||||
$xs->elementEnd('a');
|
||||
$xs->elementEnd('span');
|
||||
return $xs->getString();
|
||||
} else {
|
||||
return $nickname;
|
||||
}
|
||||
@ -608,7 +633,14 @@ function common_group_link($sender_id, $nickname)
|
||||
$sender = Profile::staticGet($sender_id);
|
||||
$group = User_group::staticGet('nickname', common_canonical_nickname($nickname));
|
||||
if ($group && $sender->isMember($group)) {
|
||||
return '<span class="vcard"><a href="'.htmlspecialchars($group->permalink()).'" class="url"><span class="fn nickname">'.$nickname.'</span></a></span>';
|
||||
$xs = new XMLStringer();
|
||||
$xs->elementStart('span', 'vcard');
|
||||
$xs->elementStart('a', array('href' => $group->permalink(),
|
||||
'class' => 'url'));
|
||||
$xs->element('span', 'fn nickname', $nickname);
|
||||
$xs->elementEnd('a');
|
||||
$xs->elementEnd('span');
|
||||
return $xs->getString();
|
||||
} else {
|
||||
return $nickname;
|
||||
}
|
||||
@ -625,7 +657,13 @@ function common_at_hash_link($sender_id, $tag)
|
||||
$url = common_local_url('subscriptions',
|
||||
array('nickname' => $user->nickname,
|
||||
'tag' => $tag));
|
||||
return '<span class="tag"><a href="'.htmlspecialchars($url).'" rel="tag">'.$tag.'</a></span>';
|
||||
$xs = new XMLStringer();
|
||||
$xs->elementStart('span', 'tag');
|
||||
$xs->element('a', array('href' => $url,
|
||||
'rel' => $tag),
|
||||
$tag);
|
||||
$xs->elementEnd('span');
|
||||
return $xs->getString();
|
||||
} else {
|
||||
return $tag;
|
||||
}
|
||||
@ -667,277 +705,20 @@ function common_relative_profile($sender, $nickname, $dt=null)
|
||||
return null;
|
||||
}
|
||||
|
||||
function common_local_url($action, $args=null, $fragment=null)
|
||||
function common_local_url($action, $args=null, $params=null, $fragment=null)
|
||||
{
|
||||
$url = null;
|
||||
if (common_config('site','fancy')) {
|
||||
$url = common_fancy_url($action, $args);
|
||||
} else {
|
||||
$url = common_simple_url($action, $args);
|
||||
$r = Router::get();
|
||||
$path = $r->build($action, $args, $params, $fragment);
|
||||
if ($path) {
|
||||
}
|
||||
if (!is_null($fragment)) {
|
||||
$url .= '#'.$fragment;
|
||||
if (common_config('site','fancy')) {
|
||||
$url = common_path(mb_substr($path, 1));
|
||||
} else {
|
||||
$url = common_path('index.php'.$path);
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
function common_fancy_url($action, $args=null)
|
||||
{
|
||||
switch (strtolower($action)) {
|
||||
case 'public':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path('?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path('');
|
||||
}
|
||||
case 'featured':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path('featured?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path('featured');
|
||||
}
|
||||
case 'favorited':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path('favorited?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path('favorited');
|
||||
}
|
||||
case 'publicrss':
|
||||
return common_path('rss');
|
||||
case 'publicatom':
|
||||
return common_path("api/statuses/public_timeline.atom");
|
||||
case 'publicxrds':
|
||||
return common_path('xrds');
|
||||
case 'tagrss':
|
||||
return common_path('tag/' . $args['tag'] . '/rss');
|
||||
case 'featuredrss':
|
||||
return common_path('featuredrss');
|
||||
case 'favoritedrss':
|
||||
return common_path('favoritedrss');
|
||||
case 'opensearch':
|
||||
if ($args && $args['type']) {
|
||||
return common_path('opensearch/'.$args['type']);
|
||||
} else {
|
||||
return common_path('opensearch/people');
|
||||
}
|
||||
case 'doc':
|
||||
return common_path('doc/'.$args['title']);
|
||||
case 'block':
|
||||
case 'login':
|
||||
case 'logout':
|
||||
case 'subscribe':
|
||||
case 'unsubscribe':
|
||||
case 'invite':
|
||||
return common_path('main/'.$action);
|
||||
case 'tagother':
|
||||
return common_path('main/tagother?id='.$args['id']);
|
||||
case 'register':
|
||||
if ($args && $args['code']) {
|
||||
return common_path('main/register/'.$args['code']);
|
||||
} else {
|
||||
return common_path('main/register');
|
||||
}
|
||||
case 'remotesubscribe':
|
||||
if ($args && $args['nickname']) {
|
||||
return common_path('main/remote?nickname=' . $args['nickname']);
|
||||
} else {
|
||||
return common_path('main/remote');
|
||||
}
|
||||
case 'nudge':
|
||||
return common_path($args['nickname'].'/nudge');
|
||||
case 'openidlogin':
|
||||
return common_path('main/openid');
|
||||
case 'profilesettings':
|
||||
return common_path('settings/profile');
|
||||
case 'passwordsettings':
|
||||
return common_path('settings/password');
|
||||
case 'emailsettings':
|
||||
return common_path('settings/email');
|
||||
case 'openidsettings':
|
||||
return common_path('settings/openid');
|
||||
case 'smssettings':
|
||||
return common_path('settings/sms');
|
||||
case 'twittersettings':
|
||||
return common_path('settings/twitter');
|
||||
case 'othersettings':
|
||||
return common_path('settings/other');
|
||||
case 'deleteprofile':
|
||||
return common_path('settings/delete');
|
||||
case 'newnotice':
|
||||
if ($args && $args['replyto']) {
|
||||
return common_path('notice/new?replyto='.$args['replyto']);
|
||||
} else {
|
||||
return common_path('notice/new');
|
||||
}
|
||||
case 'shownotice':
|
||||
return common_path('notice/'.$args['notice']);
|
||||
case 'deletenotice':
|
||||
if ($args && $args['notice']) {
|
||||
return common_path('notice/delete/'.$args['notice']);
|
||||
} else {
|
||||
return common_path('notice/delete');
|
||||
}
|
||||
case 'microsummary':
|
||||
case 'xrds':
|
||||
case 'foaf':
|
||||
return common_path($args['nickname'].'/'.$action);
|
||||
case 'all':
|
||||
case 'replies':
|
||||
case 'inbox':
|
||||
case 'outbox':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path($args['nickname'].'/'.$action.'?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path($args['nickname'].'/'.$action);
|
||||
}
|
||||
case 'subscriptions':
|
||||
case 'subscribers':
|
||||
$nickname = $args['nickname'];
|
||||
unset($args['nickname']);
|
||||
if (isset($args['tag'])) {
|
||||
$tag = $args['tag'];
|
||||
unset($args['tag']);
|
||||
}
|
||||
$params = http_build_query($args);
|
||||
if ($params) {
|
||||
return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '') . '?' . $params);
|
||||
} else {
|
||||
return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : ''));
|
||||
}
|
||||
case 'allrss':
|
||||
return common_path($args['nickname'].'/all/rss');
|
||||
case 'repliesrss':
|
||||
return common_path($args['nickname'].'/replies/rss');
|
||||
case 'userrss':
|
||||
if (isset($args['limit']))
|
||||
return common_path($args['nickname'].'/rss?limit=' . $args['limit']);
|
||||
return common_path($args['nickname'].'/rss');
|
||||
case 'showstream':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path($args['nickname'].'?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path($args['nickname']);
|
||||
}
|
||||
|
||||
case 'usertimeline':
|
||||
return common_path("api/statuses/user_timeline/".$args['nickname'].".atom");
|
||||
case 'confirmaddress':
|
||||
return common_path('main/confirmaddress/'.$args['code']);
|
||||
case 'userbyid':
|
||||
return common_path('user/'.$args['id']);
|
||||
case 'recoverpassword':
|
||||
$path = 'main/recoverpassword';
|
||||
if ($args['code']) {
|
||||
$path .= '/' . $args['code'];
|
||||
}
|
||||
return common_path($path);
|
||||
case 'imsettings':
|
||||
return common_path('settings/im');
|
||||
case 'avatarsettings':
|
||||
return common_path('settings/avatar');
|
||||
case 'groupsearch':
|
||||
return common_path('search/group' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'peoplesearch':
|
||||
return common_path('search/people' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'noticesearch':
|
||||
return common_path('search/notice' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'noticesearchrss':
|
||||
return common_path('search/notice/rss' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'avatarbynickname':
|
||||
return common_path($args['nickname'].'/avatar/'.$args['size']);
|
||||
case 'tag':
|
||||
$path = 'tag/' . $args['tag'];
|
||||
unset($args['tag']);
|
||||
return common_path($path . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'publictagcloud':
|
||||
return common_path('tags');
|
||||
case 'peopletag':
|
||||
$path = 'peopletag/' . $args['tag'];
|
||||
unset($args['tag']);
|
||||
return common_path($path . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'tags':
|
||||
return common_path('tags' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'favor':
|
||||
return common_path('main/favor');
|
||||
case 'disfavor':
|
||||
return common_path('main/disfavor');
|
||||
case 'showfavorites':
|
||||
if ($args && isset($args['page'])) {
|
||||
return common_path($args['nickname'].'/favorites?page=' . $args['page']);
|
||||
} else {
|
||||
return common_path($args['nickname'].'/favorites');
|
||||
}
|
||||
case 'favoritesrss':
|
||||
return common_path($args['nickname'].'/favorites/rss');
|
||||
case 'showmessage':
|
||||
return common_path('message/' . $args['message']);
|
||||
case 'newmessage':
|
||||
return common_path('message/new' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'api':
|
||||
// XXX: do fancy URLs for all the API methods
|
||||
switch (strtolower($args['apiaction'])) {
|
||||
case 'statuses':
|
||||
switch (strtolower($args['method'])) {
|
||||
case 'user_timeline.rss':
|
||||
return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss');
|
||||
case 'user_timeline.atom':
|
||||
return common_path('api/statuses/user_timeline/'.$args['argument'].'.atom');
|
||||
case 'user_timeline.json':
|
||||
return common_path('api/statuses/user_timeline/'.$args['argument'].'.json');
|
||||
case 'user_timeline.xml':
|
||||
return common_path('api/statuses/user_timeline/'.$args['argument'].'.xml');
|
||||
default: return common_simple_url($action, $args);
|
||||
}
|
||||
default: return common_simple_url($action, $args);
|
||||
}
|
||||
case 'sup':
|
||||
if ($args && isset($args['seconds'])) {
|
||||
return common_path('main/sup?seconds='.$args['seconds']);
|
||||
} else {
|
||||
return common_path('main/sup');
|
||||
}
|
||||
case 'newgroup':
|
||||
return common_path('group/new');
|
||||
case 'showgroup':
|
||||
return common_path('group/'.$args['nickname'] . (($args['page']) ? ('?page=' . $args['page']) : ''));
|
||||
case 'editgroup':
|
||||
return common_path('group/'.$args['nickname'].'/edit');
|
||||
case 'joingroup':
|
||||
return common_path('group/'.$args['nickname'].'/join');
|
||||
case 'leavegroup':
|
||||
return common_path('group/'.$args['nickname'].'/leave');
|
||||
case 'groupbyid':
|
||||
return common_path('group/'.$args['id'].'/id');
|
||||
case 'grouprss':
|
||||
return common_path('group/'.$args['nickname'].'/rss');
|
||||
case 'groupmembers':
|
||||
return common_path('group/'.$args['nickname'].'/members' . (($args['page']) ? ('?page=' . $args['page']) : ''));
|
||||
case 'grouplogo':
|
||||
return common_path('group/'.$args['nickname'].'/logo');
|
||||
case 'usergroups':
|
||||
$nickname = $args['nickname'];
|
||||
unset($args['nickname']);
|
||||
return common_path($nickname.'/groups' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
case 'groups':
|
||||
return common_path('group' . (($args) ? ('?' . http_build_query($args)) : ''));
|
||||
default:
|
||||
return common_simple_url($action, $args);
|
||||
}
|
||||
}
|
||||
|
||||
function common_simple_url($action, $args=null)
|
||||
{
|
||||
global $config;
|
||||
/* XXX: pretty URLs */
|
||||
$extra = '';
|
||||
if ($args) {
|
||||
foreach ($args as $key => $value) {
|
||||
$extra .= "&${key}=${value}";
|
||||
}
|
||||
}
|
||||
return common_path("index.php?action=${action}${extra}");
|
||||
}
|
||||
|
||||
function common_path($relative)
|
||||
{
|
||||
global $config;
|
||||
@ -1046,24 +827,6 @@ function common_redirect($url, $code=307)
|
||||
|
||||
function common_broadcast_notice($notice, $remote=false)
|
||||
{
|
||||
|
||||
// Check to see if notice should go to Twitter
|
||||
$flink = Foreign_link::getByUserID($notice->profile_id, 1); // 1 == Twitter
|
||||
if (($flink->noticesync & FOREIGN_NOTICE_SEND) == FOREIGN_NOTICE_SEND) {
|
||||
|
||||
// If it's not a Twitter-style reply, or if the user WANTS to send replies...
|
||||
|
||||
if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
|
||||
(($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) == FOREIGN_NOTICE_SEND_REPLY)) {
|
||||
|
||||
$result = common_twitter_broadcast($notice, $flink);
|
||||
|
||||
if (!$result) {
|
||||
common_debug('Unable to send notice: ' . $notice->id . ' to Twitter.', __FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (common_config('queue', 'enabled')) {
|
||||
// Do it later!
|
||||
return common_enqueue_notice($notice);
|
||||
@ -1072,73 +835,11 @@ function common_broadcast_notice($notice, $remote=false)
|
||||
}
|
||||
}
|
||||
|
||||
function common_twitter_broadcast($notice, $flink)
|
||||
{
|
||||
global $config;
|
||||
$success = true;
|
||||
$fuser = $flink->getForeignUser();
|
||||
$twitter_user = $fuser->nickname;
|
||||
$twitter_password = $flink->credentials;
|
||||
$uri = 'http://www.twitter.com/statuses/update.json';
|
||||
|
||||
// XXX: Hack to get around PHP cURL's use of @ being a a meta character
|
||||
$statustxt = preg_replace('/^@/', ' @', $notice->content);
|
||||
|
||||
$options = array(
|
||||
CURLOPT_USERPWD => "$twitter_user:$twitter_password",
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => array(
|
||||
'status' => $statustxt,
|
||||
'source' => $config['integration']['source']
|
||||
),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_USERAGENT => "Laconica",
|
||||
CURLOPT_CONNECTTIMEOUT => 120, // XXX: Scary!!!! How long should this be?
|
||||
CURLOPT_TIMEOUT => 120,
|
||||
|
||||
# Twitter is strict about accepting invalid "Expect" headers
|
||||
CURLOPT_HTTPHEADER => array('Expect:')
|
||||
);
|
||||
|
||||
$ch = curl_init($uri);
|
||||
curl_setopt_array($ch, $options);
|
||||
$data = curl_exec($ch);
|
||||
$errmsg = curl_error($ch);
|
||||
|
||||
if ($errmsg) {
|
||||
common_debug("cURL error: $errmsg - trying to send notice for $twitter_user.",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if (!$data) {
|
||||
common_debug("No data returned by Twitter's API trying to send update for $twitter_user",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
// Twitter should return a status
|
||||
$status = json_decode($data);
|
||||
|
||||
if (!$status->id) {
|
||||
common_debug("Unexpected data returned by Twitter API trying to send update for $twitter_user",
|
||||
__FILE__);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
// Stick the notice on the queue
|
||||
|
||||
function common_enqueue_notice($notice)
|
||||
{
|
||||
foreach (array('jabber', 'omb', 'sms', 'public') as $transport) {
|
||||
foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook') as $transport) {
|
||||
$qi = new Queue_item();
|
||||
$qi->notice_id = $notice->id;
|
||||
$qi->transport = $transport;
|
||||
@ -1185,6 +886,15 @@ function common_real_broadcast($notice, $remote=false)
|
||||
common_log(LOG_ERR, 'Error in public broadcast for notice ' . $notice->id);
|
||||
}
|
||||
}
|
||||
if ($success) {
|
||||
$success = broadcast_twitter($notice);
|
||||
if (!$success) {
|
||||
common_log(LOG_ERR, 'Error in Twitter broadcast for notice ' . $notice->id);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Do a real-time FB broadcast here?
|
||||
|
||||
// XXX: broadcast notices to other IM
|
||||
return $success;
|
||||
}
|
||||
|
68
lib/xmlstringer.php
Normal file
68
lib/xmlstringer.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Generator for in-memory XML
|
||||
*
|
||||
* 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 Output
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create in-memory XML
|
||||
*
|
||||
* @category Output
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
* @see Action
|
||||
* @see HTMLOutputter
|
||||
*/
|
||||
|
||||
class XMLStringer extends XMLOutputter
|
||||
{
|
||||
function __construct($indent=false)
|
||||
{
|
||||
$this->xw = new XMLWriter();
|
||||
$this->xw->openMemory();
|
||||
$this->xw->setIndent($indent);
|
||||
}
|
||||
|
||||
function getString()
|
||||
{
|
||||
return $this->xw->outputMemory();
|
||||
}
|
||||
|
||||
// utility for quickly creating XML-strings
|
||||
|
||||
static function estring($tag, $attrs=null, $content=null)
|
||||
{
|
||||
$xs = new XMLStringer();
|
||||
$xs->element($tag, $attrs, $content);
|
||||
return $xs->getString();
|
||||
}
|
||||
}
|
144
plugins/BlogspamNetPlugin.php
Normal file
144
plugins/BlogspamNetPlugin.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Plugin to check submitted notices with blogspam.net
|
||||
*
|
||||
* 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 Plugin
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
define('BLOGSPAMNETPLUGIN_VERSION', '0.1');
|
||||
|
||||
/**
|
||||
* Plugin to check submitted notices with blogspam.net
|
||||
*
|
||||
* When new notices are saved, we check their text with blogspam.net (or
|
||||
* a compatible service).
|
||||
*
|
||||
* Blogspam.net is supposed to catch blog comment spam, and I found that
|
||||
* some of its tests (min/max size, bayesian match) gave a lot of false positives.
|
||||
* So, I've turned those tests off by default. This may not get as many
|
||||
* hits, but it's better than nothing.
|
||||
*
|
||||
* @category Plugin
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* @see Event
|
||||
*/
|
||||
|
||||
class BlogspamNetPlugin extends Plugin
|
||||
{
|
||||
var $baseUrl = 'http://test.blogspam.net:8888/';
|
||||
|
||||
function __construct($url=null)
|
||||
{
|
||||
parent::__construct();
|
||||
if ($url) {
|
||||
$this->baseUrl = $url;
|
||||
}
|
||||
}
|
||||
|
||||
function onStartNoticeSave($notice)
|
||||
{
|
||||
$args = $this->testArgs($notice);
|
||||
common_debug("Blogspamnet args = " . print_r($args, TRUE));
|
||||
$request = xmlrpc_encode_request('testComment', array($args));
|
||||
$context = stream_context_create(array('http' => array('method' => "POST",
|
||||
'header' =>
|
||||
"Content-Type: text/xml\r\n".
|
||||
"User-Agent: " . $this->userAgent(),
|
||||
'content' => $request)));
|
||||
$file = file_get_contents($this->baseUrl, false, $context);
|
||||
$response = xmlrpc_decode($file);
|
||||
if (xmlrpc_is_fault($response)) {
|
||||
throw new ServerException("$response[faultString] ($response[faultCode])", 500);
|
||||
} else {
|
||||
common_debug("Blogspamnet results = " . $response);
|
||||
if (preg_match('/^ERROR(:(.*))?$/', $response, $match)) {
|
||||
throw new ServerException(sprintf(_("Error from %s: %s"), $this->baseUrl, $match[2]), 500);
|
||||
} else if (preg_match('/^SPAM(:(.*))?$/', $response, $match)) {
|
||||
throw new ClientException(sprintf(_("Spam checker results: %s"), $match[2]), 400);
|
||||
} else if (preg_match('/^OK$/', $response)) {
|
||||
// don't do anything
|
||||
} else {
|
||||
throw new ServerException(sprintf(_("Unexpected response from %s: %s"), $this->baseUrl, $response), 500);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testArgs($notice)
|
||||
{
|
||||
$args = array();
|
||||
$args['comment'] = $notice->content;
|
||||
$args['ip'] = $this->getClientIP();
|
||||
|
||||
if (isset($_SERVER) && array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
|
||||
$args['agent'] = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
|
||||
$profile = $notice->getProfile();
|
||||
|
||||
if ($profile && $profile->homepage) {
|
||||
$args['link'] = $profile->homepage;
|
||||
}
|
||||
|
||||
if ($profile && $profile->fullname) {
|
||||
$args['name'] = $profile->fullname;
|
||||
} else {
|
||||
$args['name'] = $profile->nickname;
|
||||
}
|
||||
|
||||
$args['site'] = common_root_url();
|
||||
$args['version'] = $this->userAgent();
|
||||
|
||||
$args['options'] = "max-size=140,min-size=0,min-words=0,exclude=bayasian";
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function getClientIP()
|
||||
{
|
||||
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||
// Note: order matters here; use proxy-forwarded stuff first
|
||||
foreach (array('HTTP_X_FORWARDED_FOR', 'CLIENT-IP', 'REMOTE_ADDR') as $k) {
|
||||
if (isset($_SERVER[$k])) {
|
||||
return $_SERVER[$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '127.0.0.1';
|
||||
}
|
||||
|
||||
function userAgent()
|
||||
{
|
||||
return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' Laconica/' . LACONICA_VERSION;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ if (!defined('LACONICA')) {
|
||||
* This plugin will spoot out the correct JavaScript spell to invoke Google Analytics on a page.
|
||||
*
|
||||
* Note that Google Analytics is not compatible with the Franklin Street Statement; consider using
|
||||
* Pikiw (http://www.pikiw.org/) instead!
|
||||
* Piwik (http://www.piwik.org/) instead!
|
||||
*
|
||||
* @category Plugin
|
||||
* @package Laconica
|
||||
|
71
scripts/facebookqueuehandler.php
Executable file
71
scripts/facebookqueuehandler.php
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
# Abort if called from a web server
|
||||
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||
print "This script must be run from the command line\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
define('LACONICA', true);
|
||||
|
||||
require_once(INSTALLDIR . '/lib/common.php');
|
||||
require_once(INSTALLDIR . '/lib/facebookutil.php');
|
||||
require_once(INSTALLDIR . '/lib/queuehandler.php');
|
||||
|
||||
set_error_handler('common_error_handler');
|
||||
|
||||
class FacebookQueueHandler extends QueueHandler
|
||||
{
|
||||
|
||||
function transport()
|
||||
{
|
||||
return 'facebook';
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
$this->log(LOG_INFO, "INITIALIZE");
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle_notice($notice)
|
||||
{
|
||||
return facebookBroadcastNotice($notice);
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ini_set("max_execution_time", "0");
|
||||
ini_set("max_input_time", "0");
|
||||
set_time_limit(0);
|
||||
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
$id = ($argc > 1) ? $argv[1] : null;
|
||||
|
||||
$handler = new FacebookQueueHandler($id);
|
||||
|
||||
$handler->runOnce();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user